Slide 1

Slide 1 text

Android Performance Tips Romain Guy Chet Haase google.com/+RomainGuy google.com/+ChetHaase @romainguy @chethaase

Slide 2

Slide 2 text

Performance Improvements

Slide 3

Slide 3 text

#DV13 #AndroidPerf Lazy Measurement • Introduced in Android 4.4 - targetSdkVersion must be >= 19 • Views cache measured dimensions - Prior to 4.4 only the last measure was cached - In 4.4 all measures are cached until next requestLayout() • Can greatly reduce calls to onMeasure()

Slide 4

Slide 4 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View

Slide 5

Slide 5 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View measure(wSpec1, hSpec1)

Slide 6

Slide 6 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View measure(wSpec1, hSpec1) onMeasure(wSpec1, hSpec1)

Slide 7

Slide 7 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View measure(wSpec1, hSpec1) setDimensions(w1, h1) onMeasure(wSpec1, hSpec1)

Slide 8

Slide 8 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View measure(wSpec2, hSpec2)

Slide 9

Slide 9 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View measure(wSpec2, hSpec2) onMeasure(wSpec2, hSpec2)

Slide 10

Slide 10 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View measure(wSpec2, hSpec2) setDimensions(w2, h2) onMeasure(wSpec2, hSpec2)

Slide 11

Slide 11 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View

Slide 12

Slide 12 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View requestLayout()

Slide 13

Slide 13 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View

Slide 14

Slide 14 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View measure(wSpec1, hSpec1)

Slide 15

Slide 15 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View measure(wSpec1, hSpec1) cached measure: (wSpec1, hSpec1) → (w1, h1)

Slide 16

Slide 16 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View measure(wSpec1, hSpec1) setDimensions(w1, h1) cached measure: (wSpec1, hSpec1) → (w1, h1)

Slide 17

Slide 17 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View measure(wSpec2, hSpec2)

Slide 18

Slide 18 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View measure(wSpec2, hSpec2) onMeasure(wSpec2, hSpec2)

Slide 19

Slide 19 text

#DV13 #AndroidPerf Before 4.4 ViewGroup View View measure(wSpec2, hSpec2) setDimensions(w2, h2) onMeasure(wSpec2, hSpec2)

Slide 20

Slide 20 text

#DV13 #AndroidPerf Single measure cache • Works great in common cases • Breaks with multi-pass layouts - LinearLayout and weight - RelativeLayout - Custom layouts

Slide 21

Slide 21 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View

Slide 22

Slide 22 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec1, hSpec1)

Slide 23

Slide 23 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec1, hSpec1) onMeasure(wSpec1, hSpec1)

Slide 24

Slide 24 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec1, hSpec1) setDimensions(w1, h1) onMeasure(wSpec1, hSpec1)

Slide 25

Slide 25 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec2, hSpec2)

Slide 26

Slide 26 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec2, hSpec2) onMeasure(wSpec2, hSpec2)

Slide 27

Slide 27 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec2, hSpec2) setDimensions(w2, h2) onMeasure(wSpec2, hSpec2)

Slide 28

Slide 28 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View

Slide 29

Slide 29 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec3, hSpec3)

Slide 30

Slide 30 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec3, hSpec3) onMeasure(wSpec3, hSpec3)

Slide 31

Slide 31 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec3, hSpec3) setDimensions(w3, h3) onMeasure(wSpec3, hSpec3)

Slide 32

Slide 32 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec4, hSpec4)

Slide 33

Slide 33 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec4, hSpec4) onMeasure(wSpec4, hSpec4)

Slide 34

Slide 34 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec4, hSpec4) setDimensions(w4, h4) onMeasure(wSpec4, hSpec4)

Slide 35

Slide 35 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View

Slide 36

Slide 36 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View requestLayout()

Slide 37

Slide 37 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View

Slide 38

Slide 38 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec1, hSpec1)

Slide 39

Slide 39 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec1, hSpec1) cached measure: (wSpec3, hSpec3) → (w3, h3)

Slide 40

Slide 40 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec1, hSpec1) onMeasure(wSpec3, hSpec3)

Slide 41

Slide 41 text

#DV13 #AndroidPerf Multi-pass layout ViewGroup View View measure(wSpec1, hSpec1) setDimensions(w1, h1) onMeasure(wSpec3, hSpec3)

Slide 42

Slide 42 text

#DV13 #AndroidPerf Multi-pass layouts • Siblings can cause extra onMeasure() calls • Nested multi-pass layouts can wreck havoc - A leaf View calling requestLayout() can relayout the entire tree! • Solution < 4.4 - Avoid multi-pass layouts - Use fewer Views • Solution >= 4.4 - Framework caches multiple measure pairs - Cache is cleared on requestLayout()

Slide 43

Slide 43 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View

Slide 44

Slide 44 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec1, hSpec1)

Slide 45

Slide 45 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec1, hSpec1) onMeasure(wSpec1, hSpec1)

Slide 46

Slide 46 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec1, hSpec1) setDimensions(w1, h1) onMeasure(wSpec1, hSpec1)

Slide 47

Slide 47 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec2, hSpec2)

Slide 48

Slide 48 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec2, hSpec2) onMeasure(wSpec2, hSpec2)

Slide 49

Slide 49 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec2, hSpec2) setDimensions(w2, h2) onMeasure(wSpec2, hSpec2)

Slide 50

Slide 50 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View

Slide 51

Slide 51 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec3, hSpec3)

Slide 52

Slide 52 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec3, hSpec3) onMeasure(wSpec3, hSpec3)

Slide 53

Slide 53 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec3, hSpec3) setDimensions(w3, h3) onMeasure(wSpec3, hSpec3)

Slide 54

Slide 54 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec4, hSpec4)

Slide 55

Slide 55 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec4, hSpec4) onMeasure(wSpec4, hSpec4)

Slide 56

Slide 56 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec4, hSpec4) setDimensions(w4, h4) onMeasure(wSpec4, hSpec4)

Slide 57

Slide 57 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View

Slide 58

Slide 58 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View requestLayout()

Slide 59

Slide 59 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View

Slide 60

Slide 60 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec1, hSpec1)

Slide 61

Slide 61 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec1, hSpec1) cached measures: (wSpec3, hSpec3) → (w3, h3) (wSpec1, hSpec1) → (w1, h1)

Slide 62

Slide 62 text

#DV13 #AndroidPerf With 4.4 ViewGroup View View measure(wSpec1, hSpec1) setDimensions(w1, h1) cached measures: (wSpec3, hSpec3) → (w3, h3) (wSpec1, hSpec1) → (w1, h1)

Slide 63

Slide 63 text

#DV13 #AndroidPerf Example RelativeLayout LinearLayout LinearLayout RelativeLayout Button TextView TextView TextView TextView RelativeLayout TextView TextView TextView

Slide 64

Slide 64 text

#DV13 #AndroidPerf Example RelativeLayout LinearLayout LinearLayout RelativeLayout Button TextView TextView TextView TextView RelativeLayout TextView TextView TextView requestLayout()

Slide 65

Slide 65 text

#DV13 #AndroidPerf Results targetSdk 18 19 measure time measure count

Slide 66

Slide 66 text

#DV13 #AndroidPerf Results targetSdk 18 19 measure time measure count 6.5ms 72

Slide 67

Slide 67 text

#DV13 #AndroidPerf Results targetSdk 18 19 measure time measure count 6.5ms 0.7ms 72 14

Slide 68

Slide 68 text

#DV13 #AndroidPerf DisplayList Reordering and Merging • Batches similar commands • Minimizes state changes • Minimizes GL operations

Slide 69

Slide 69 text

Save Cancel Maximize compatibility Include metadata

Slide 70

Slide 70 text

No content

Slide 71

Slide 71 text

Include metadata Maximize compatibility Cancel Save Order of drawing commands

Slide 72

Slide 72 text

Include metadata Maximize compatibility Cancel Save 1. Re-ordering

Slide 73

Slide 73 text

Include metadata Maximize compatibility Cancel Save 2. Merging

Slide 74

Slide 74 text

#DV13 #AndroidPerf

Slide 75

Slide 75 text

#DV13 #AndroidPerf Without reordering & merging 48 draw calls

Slide 76

Slide 76 text

#DV13 #AndroidPerf Without reordering & merging 48 draw calls With reordering & merging 18 draw calls

Slide 77

Slide 77 text

#DV13 #AndroidPerf

Slide 78

Slide 78 text

#DV13 #AndroidPerf Without reordering & merging 576 OpenGL driver calls

Slide 79

Slide 79 text

#DV13 #AndroidPerf Without reordering & merging 576 OpenGL driver calls With reordering & merging 216 OpenGL driver calls

Slide 80

Slide 80 text

#DV13 #AndroidPerf Asset Atlas

Slide 81

Slide 81 text

#DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps

Slide 82

Slide 82 text

#DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps Overdraw Window Background 1x

Slide 83

Slide 83 text

#DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps Overdraw Container Background 2x

Slide 84

Slide 84 text

#DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps Overdraw Button Button 2.1x Views

Slide 85

Slide 85 text

#DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps

Slide 86

Slide 86 text

#DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps Overdraw

Slide 87

Slide 87 text

#DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps Overdraw Window Background 0x

Slide 88

Slide 88 text

#DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps Overdraw Container Background 1x

Slide 89

Slide 89 text

#DV13 #AndroidPerf Overdraw Removal • Detects coverage, areas hidden by opaque elements • Avoids drawing them • Eliminates some common overdraw situations • But you should still avoid it in your apps Overdraw Button Button 1.1x Views

Slide 90

Slide 90 text

#DV13 #AndroidPerf Bitmap Reuse • Reuse in 3.0 required Bitmaps of same size/configuration • Bitmaps can now be reconfigured/resized - Can create scratch buffer and load smaller bitmaps into it

Slide 91

Slide 91 text

Performance Tools

Slide 92

Slide 92 text

#DV13 #AndroidPerf Non-Rectangular Clipping Detection

Slide 93

Slide 93 text

#DV13 #AndroidPerf

Slide 94

Slide 94 text

#DV13 #AndroidPerf Overdraw debug

Slide 95

Slide 95 text

#DV13 #AndroidPerf

Slide 96

Slide 96 text

#DV13 #AndroidPerf

Slide 97

Slide 97 text

procstats: UI

Slide 98

Slide 98 text

procstats: command line $ adb shell dumpsys procstats com.google.android.apps.maps COMMITTED STATS FROM 2013-11-05-18-04-58: * com.google.android.apps.maps / u0a60: TOTAL: 1.1% Service: 1.1% (Cached): 99% (98MB-98MB-99MB/96MB-97MB-97MB over 7) Run time Stats: Screen Off / Norm / +1h19m25s22ms Screen On / Norm / +10m43s963ms TOTAL: +1h30m8s985ms Start time: 2013-11-05 18:04:58 Total elapsed time: +5h9m53s44ms (complete) libdvm.so chromeview

Slide 99

Slide 99 text

#DV13 #AndroidPerf GL Tracer

Slide 100

Slide 100 text

#DV13 #AndroidPerf Systrace • Introduced in Jellybean 4.1 • Recent improvements - More framework tags - More categories - Easier to launch - App-level tags

Slide 101

Slide 101 text

#DV13 #AndroidPerf Systrace • Introduced in Jellybean 4.1 • Recent improvements - More framework tags - More categories - Easier to launch - App-level tags Trace.beginSection("someLabel"); // stuff Trace.endSection();

Slide 102

Slide 102 text

#DV13 #AndroidPerf Android Studio System Information

Slide 103

Slide 103 text

#DV13 #AndroidPerf

Slide 104

Slide 104 text

#DV13 #AndroidPerf

Slide 105

Slide 105 text

Performance Tips

Slide 106

Slide 106 text

#DV13 #AndroidPerf Bitmap Reuse mBitmapCache = Bitmap.createBitmap(500, 500, Bitmap.Config.ARGB_8888); mBitmapOptions.inBitmap = mBitmapCache; mBitmapOptions.inSampleSize = 1; Bitmap newBitmap; if (mCheckBox.isChecked()) { newBitmap = BitmapFactory.decodeResource( getResources(), images[index], mBitmapOptions); } else { newBitmap = BitmapFactory.decodeResource( getResources(), images[index]); } mImageView.setImageBitmap(newBitmap);

Slide 107

Slide 107 text

#DV13 #AndroidPerf Atlas • Popular in games, on web sites, etc… - Also called “sprite sheets“ • Can increase performance - Reduce number of OpenGL driver calls - Reduce number of GPU state changes - Better merging of draw calls

Slide 108

Slide 108 text

#DV13 #AndroidPerf Atlas example 10 photos Drawn column by column

Slide 109

Slide 109 text

#DV13 #AndroidPerf Atlas source

Slide 110

Slide 110 text

#DV13 #AndroidPerf Loading the atlas 1/4 • res/raw/atlas.txt • Format: atlas_name ImageName,left,top,right,bottom ImageName,left,top,right,bottom ImageName,left,top,right,bottom

Slide 111

Slide 111 text

#DV13 #AndroidPerf Loading the atlas 2/4 atlas Mountain,1,1,301,201 Gecko,302,1,602,201 Seahorse,603,1,903,201 Camera,904,1,1204,201 Fish,1205,1,1505,201 Plasma,1,202,301,402 Grass,302,202,602,402 Photographer,603,202,903,402 Lights,904,202,1204,402 Flower,1205,202,1505,402

Slide 112

Slide 112 text

#DV13 #AndroidPerf Loading the atlas 3/4 String line = reader.readLine(); Resources res = getContext().getResources(); int atlasId = res.getIdentifier(line, "drawable", getContext().getPackageName()); mAtlas = BitmapFactory.decodeResource(res, atlasId);

Slide 113

Slide 113 text

#DV13 #AndroidPerf Loading the atlas 3/4 String line = reader.readLine(); Resources res = getContext().getResources(); int atlasId = res.getIdentifier(line, "drawable", getContext().getPackageName()); mAtlas = BitmapFactory.decodeResource(res, atlasId);

Slide 114

Slide 114 text

#DV13 #AndroidPerf Loading the atlas 3/4 String line = reader.readLine(); Resources res = getContext().getResources(); int atlasId = res.getIdentifier(line, "drawable", getContext().getPackageName()); mAtlas = BitmapFactory.decodeResource(res, atlasId);

Slide 115

Slide 115 text

#DV13 #AndroidPerf Loading the atlas 4/4 static class Entry { String name; final Rect src = new Rect(); } while ((line = reader.readLine()) != null) { String[] fields = line.split(","); Entry entry = new Entry(); entry.name = fields[0]; entry.src.set(parseInt(fields[1]), parseInt(fields[2]), parseInt(fields[3]), parseInt(fields[4])); mEntries.add(entry); }

Slide 116

Slide 116 text

#DV13 #AndroidPerf Drawing the atlas protected void onDraw(Canvas canvas) { final int count = mEntries.size(); for (int i = 0; i < count; i++) { Entry entry = mEntries.get(i); int x = computeX(entry); int y = computeY(entry); mDst.set(x, y, x + entry.src.width(), y + entry.src.height()); canvas.drawBitmap(mAtlas, entry.src, mDst, null); } }

Slide 117

Slide 117 text

#DV13 #AndroidPerf Drawing the atlas protected void onDraw(Canvas canvas) { final int count = mEntries.size(); for (int i = 0; i < count; i++) { Entry entry = mEntries.get(i); int x = computeX(entry); int y = computeY(entry); mDst.set(x, y, x + entry.src.width(), y + entry.src.height()); canvas.drawBitmap(mAtlas, entry.src, mDst, null); } }

Slide 118

Slide 118 text

#DV13 #AndroidPerf Drawing the atlas protected void onDraw(Canvas canvas) { final int count = mEntries.size(); for (int i = 0; i < count; i++) { Entry entry = mEntries.get(i); int x = computeX(entry); int y = computeY(entry); mDst.set(x, y, x + entry.src.width(), y + entry.src.height()); canvas.drawBitmap(mAtlas, entry.src, mDst, null); } }

Slide 119

Slide 119 text

#DV13 #AndroidPerf Atlas tips 1/2 • 1px transparent border around entries - Allows proper bilinear filtering - For scaling, rotation, perspective, etc. • Watch out for max texture size - Especially at xxhdpi - 2048x2048 is common - 4096x4096 on recent devices

Slide 120

Slide 120 text

#DV13 #AndroidPerf

Slide 121

Slide 121 text

#DV13 #AndroidPerf Atlas tips 2/2 • Disable blending for opaque entries • Use a Paint with the SRC blend mode - mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)) • Store this information in atlas file - Name,left,top,right,bottom,1 // 1=opaque, 0= transparent

Slide 122

Slide 122 text

#DV13 #AndroidPerf Layout • Don’t use multi-pass layouts at the top of the tree - Very expensive • LinearLayout is multi-pass… sometimes - For children with a layout_weight • RelativeLayout is always multi-pass

Slide 123

Slide 123 text

#DV13 #AndroidPerf Tips for LinearLayout • Vertical layouts - Set height to 0dp for children with a weight • Horizontal layouts - Set width to 0dp for children with a weight - And set baselineAligned=”false” on LinearLayout • These tips don’t always apply

Slide 124

Slide 124 text

#DV13 #AndroidPerf Tips for RelativeLayout • Don’t use it

Slide 125

Slide 125 text

#DV13 #AndroidPerf Tips for RelativeLayout • Alright you can use it • But be careful

Slide 126

Slide 126 text

Non-Rectangular Clipping 59 @Override protected void onDraw(Canvas canvas) { // Keep the jellybeans canvas.clipRect(l, t, r, b); // Rotate the jar canvas.rotate(-30.0f, pX, pY); // Draw the jar canvas.drawBitmap(mJellyBeans, x, y, null); }

Slide 127

Slide 127 text

60

Slide 128

Slide 128 text

1. Clip 60

Slide 129

Slide 129 text

2. Rotate 60

Slide 130

Slide 130 text

3. Draw 60

Slide 131

Slide 131 text

60

Slide 132

Slide 132 text

61 @Override protected void onDraw(Canvas canvas) { // Rotate the jar canvas.rotate(-30.0f, pX, pY); // Keep the jellybeans canvas.clipRect(l, t, r, b); // Draw the jar canvas.drawBitmap(mJellyBeans, x, y, null); }

Slide 133

Slide 133 text

62

Slide 134

Slide 134 text

1. Rotate 62

Slide 135

Slide 135 text

2. Clip 62

Slide 136

Slide 136 text

3. Draw 62

Slide 137

Slide 137 text

62

Slide 138

Slide 138 text

Stencil buffer 63

Slide 139

Slide 139 text

Stencil buffer 63

Slide 140

Slide 140 text

#DV13 #AndroidPerf Don’t Update Layers • Avoid invalidating layered views/containers - Don’t change view or child views, remove children, add children, ... view.setLayerType(View.LATER_TYPE_HARDWARE, null); // run animation view.setLayerType(View.LAYER_TYPE_NONE, null); // or view.animate().alpha(0).withLayer();

Slide 141

Slide 141 text

Using the Tools

Slide 142

Slide 142 text

#DV13 #AndroidPerf Systrace • Overall system performance

Slide 143

Slide 143 text

#DV13 #AndroidPerf For More Information • Google I/O talks • Parleys.com talks • Devbytes on YouTube Chet graphics-geek.blogspot.com google.com/+ChetHaase @chethaase Romain: curious-creature.org google.com/+RomainGuy @romainguy