├── empty_project ├── debug.keystore.pass.txt ├── main │ └── main.collection ├── debug.keystore ├── input │ └── game.input_binding ├── manifest.private.der ├── manifest.public.der ├── .gitignore └── game.project ├── size.png ├── bob_size.png ├── bundle_size.png ├── editor_size.png ├── engine_size.png ├── size_small.png ├── legacy_engine_size.png ├── legacy_engine_size_stripped.png ├── .gitignore ├── .github └── workflows │ └── check_size.yaml ├── README.md ├── bob_report.csv ├── index.html ├── editor_report.csv ├── size-analyzer ├── index.html ├── README.md ├── css │ └── style.css ├── js │ └── csv-parser.js └── analysis_index.json ├── css └── dashboard.css ├── bundle_report.csv ├── engine_report.csv ├── legacy_engine_report.csv ├── check_size.py ├── releases.json └── js └── dashboard.js /empty_project/debug.keystore.pass.txt: -------------------------------------------------------------------------------- 1 | android -------------------------------------------------------------------------------- /empty_project/main/main.collection: -------------------------------------------------------------------------------- 1 | name: "main" 2 | scale_along_z: 0 3 | -------------------------------------------------------------------------------- /size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/build-size/HEAD/size.png -------------------------------------------------------------------------------- /bob_size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/build-size/HEAD/bob_size.png -------------------------------------------------------------------------------- /bundle_size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/build-size/HEAD/bundle_size.png -------------------------------------------------------------------------------- /editor_size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/build-size/HEAD/editor_size.png -------------------------------------------------------------------------------- /engine_size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/build-size/HEAD/engine_size.png -------------------------------------------------------------------------------- /size_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/build-size/HEAD/size_small.png -------------------------------------------------------------------------------- /legacy_engine_size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/build-size/HEAD/legacy_engine_size.png -------------------------------------------------------------------------------- /empty_project/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/build-size/HEAD/empty_project/debug.keystore -------------------------------------------------------------------------------- /empty_project/input/game.input_binding: -------------------------------------------------------------------------------- 1 | mouse_trigger { 2 | input: MOUSE_BUTTON_1 3 | action: "touch" 4 | } 5 | -------------------------------------------------------------------------------- /legacy_engine_size_stripped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/build-size/HEAD/legacy_engine_size_stripped.png -------------------------------------------------------------------------------- /empty_project/manifest.private.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/build-size/HEAD/empty_project/manifest.private.der -------------------------------------------------------------------------------- /empty_project/manifest.public.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/build-size/HEAD/empty_project/manifest.public.der -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bob*.jar 2 | bundle_output 3 | 4 | # Allow our bob.jar analysis folder and its CSV files 5 | !size-analyzer/bob.jar/ 6 | !size-analyzer/bob.jar/*.csv -------------------------------------------------------------------------------- /empty_project/.gitignore: -------------------------------------------------------------------------------- 1 | /.internal 2 | /build 3 | .externalToolBuilders 4 | .DS_Store 5 | Thumbs.db 6 | .lock-wscript 7 | *.pyc 8 | .project 9 | .cproject 10 | builtins -------------------------------------------------------------------------------- /empty_project/game.project: -------------------------------------------------------------------------------- 1 | [bootstrap] 2 | main_collection = /main/main.collectionc 3 | 4 | [script] 5 | shared_state = 1 6 | 7 | [display] 8 | width = 960 9 | height = 640 10 | 11 | [android] 12 | input_method = HiddenInputField -------------------------------------------------------------------------------- /.github/workflows/check_size.yaml: -------------------------------------------------------------------------------- 1 | name: Check engine size 2 | 3 | on: 4 | push: 5 | schedule: 6 | - cron: 0 2 * * * 7 | jobs: 8 | check_size: 9 | runs-on: macOS-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v3 13 | 14 | - name: Setup Python 15 | uses: actions/setup-python@v4 16 | with: 17 | python-version: '3.10' 18 | 19 | - name: Setup Java 20 | uses: actions/setup-java@v3 21 | with: 22 | java-version: '21.0.5+11.0.LTS' 23 | distribution: 'temurin' 24 | 25 | - name: Install Python dependencies 26 | run: | 27 | python -m pip install -U pip 28 | python -m pip install -U matplotlib 29 | 30 | - name: Install bloaty (for analyze_builds.py) 31 | run: | 32 | # Install bloaty using Homebrew (macOS) 33 | brew install bloaty 34 | 35 | - name: Check size 36 | run: | 37 | python check_size.py 38 | 39 | - name: Run detailed analysis 40 | run: | 41 | python analyze_builds.py 42 | 43 | - name: Check github token 44 | id: checktoken 45 | shell: bash 46 | env: 47 | SERVICES_GITHUB_TOKEN: ${{ secrets.SERVICES_GITHUB_TOKEN }} 48 | run: | 49 | if [ "${SERVICES_GITHUB_TOKEN}" == "" ]; then 50 | # echo "::set-output name=token_exists::false" 51 | echo "token_exists=false" >> $GITHUB_OUTPUT 52 | echo "token_exists::false" 53 | else 54 | # echo "::set-output name=token_exists::true" 55 | echo "token_exists=true" >> $GITHUB_OUTPUT 56 | echo "token_exists::true" 57 | fi 58 | 59 | - name: Commit changes 60 | if: ${{ steps.checktoken.outputs.token_exists == 'true' }} 61 | shell: bash 62 | env: 63 | SERVICES_GITHUB_TOKEN: ${{ secrets.SERVICES_GITHUB_TOKEN }} 64 | run: | 65 | git add -A 66 | git commit -m "Generated new size report and graph [skip ci]" bundle_size.png engine_size.png engine_report.csv bob_size.png bob_report.csv editor_size.png editor_report.csv bundle_report.csv releases.json size-analyzer/ 67 | git push "https://${SERVICES_GITHUB_TOKEN}@github.com/defold/build-size.git" HEAD 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Buils Status](https://github.com/defold/build-size/actions/workflows/check_size.yaml/badge.svg)](https://github.com/defold/build-size/actions/workflows/check_size.yaml) 2 | 3 | # Defold engine and application bundle size plot 4 | This project will plot the size of the Defold engine (aka dmengine) as well as the size of a complete Defold game bundle for all supported platforms and versions. 5 | 6 | **Live Dashboard**: https://defold.com/build-size 7 | **Interactive Size Analyzer**: https://defold.com/build-size/size-analyzer/ 8 | 9 | ## Bundle size 10 | The bundle size is measured as: 11 | 12 | * Android - Size of .aab file containing one CPU architecture 13 | * iOS - Size of .ipa file 14 | * macOS - Size of .app file 15 | * Windows - Size of zip archive with engine, required library files and game archive 16 | * Linux - Size of zip archive with engine, required library files and game archive 17 | * HTML5 - Size of zip archive with either .wasm or .asm.js engine, required library files and game archive 18 | 19 | ![Bundle size per platform and version](./bundle_size.png) 20 | 21 | 22 | ## Engine size 23 | This is the size of a release version of the Defold engine executable/library: 24 | 25 | ![Engine size per platform and version](./engine_size.png) 26 | 27 | ## Editor size 28 | This is the size of the release versions of the Defold editor (including bob.jar): 29 | 30 | ![Editor size per platform and version](./editor_size.png) 31 | 32 | ## Bob size 33 | This is the size of a release version of the our command line build interface (bob.jar): 34 | 35 | ![bob.jar size per platform and version](./bob_size.png) 36 | 37 | 38 | ## Deprecated graphs 39 | Graph of versions stripped of debug symbols: 40 | 41 | ![Size per platform and version](./legacy_engine_size_stripped.png) 42 | 43 | History of versions: 44 | 45 | ![History of size per platform and version](./legacy_engine_size.png) 46 | 47 | NOTE: In both of the deprecated graphs above the measurements show the size of the .apk file for Android and for all other platforms the size of the engine itself. 48 | 49 | # Requirements 50 | If you wish to run this script locally you need to have the following things installed: 51 | 52 | * Python 3 (developed with 3.10.5) 53 | * Java 11.0.* 54 | * [matlibplot](http://matplotlib.org/) (Install with `python3 -m pip install matplotlib`) 55 | 56 | # Usage 57 | Run [check_size.py](check_size.py): 58 | 59 | python3 check_size.py 60 | 61 | It will generate these files: 62 | * [releases.json](releases.json) 63 | * [engine_report.csv](engine_report.csv) 64 | * [bundle_report.csv](bundle_report.csv) 65 | * [bob_report.csv](bob_report.csv) 66 | * [editor_report.csv](editor_report.csv) 67 | * [engine_size.png](engine_size.png) 68 | * [bundle_size.png](bundle_size.png) 69 | * [bob_size.png](bob_size.png) 70 | * [editor_size.png](editor_size.png) 71 | 72 | 73 | To include a new version of dmengine in the report you need to [add an entry in the releases list in releases.json](https://github.com/defold/build-size/blob/master/releases.json). The sha1 of the version you wish to add can be seen at [d.defold.com](d.defold.com). 74 | 75 | The project will automatically generate new graphs and report files when a file in the project is changed. 76 | -------------------------------------------------------------------------------- /bob_report.csv: -------------------------------------------------------------------------------- 1 | VERSION,x86_64-macos 2 | 1.2.38,0 3 | 1.2.39,0 4 | 1.2.40,0 5 | 1.2.41,0 6 | 1.2.42,0 7 | 1.2.43,0 8 | 1.2.44,0 9 | 1.2.45,0 10 | 1.2.46,0 11 | 1.2.47,0 12 | 1.2.48,0 13 | 1.2.49,0 14 | 1.2.50,0 15 | 1.2.51,0 16 | 1.2.52,0 17 | 1.2.53,0 18 | 1.2.54,0 19 | 1.2.55,0 20 | 1.2.56,0 21 | 1.2.57,0 22 | 1.2.58,0 23 | 1.2.59,0 24 | 1.2.60,0 25 | 1.2.61,0 26 | 1.2.62,0 27 | 1.2.63,0 28 | 1.2.64,0 29 | 1.2.65,0 30 | 1.2.66,0 31 | 1.2.67,0 32 | 1.2.68,0 33 | 1.2.69,0 34 | 1.2.70,0 35 | 1.2.71,0 36 | 1.2.72,0 37 | 1.2.73,0 38 | 1.2.74,0 39 | 1.2.75,0 40 | 1.2.76,0 41 | 1.2.77,0 42 | 1.2.78,0 43 | 1.2.79,0 44 | 1.2.80,0 45 | 1.2.81,0 46 | 1.2.82,0 47 | 1.2.83,0 48 | 1.2.84,0 49 | 1.2.85,0 50 | 1.2.86,0 51 | 1.2.87,0 52 | 1.2.88,0 53 | 1.2.89,0 54 | 1.2.90,0 55 | 1.2.91,0 56 | 1.2.92,0 57 | 1.2.93,0 58 | 1.2.94,0 59 | 1.2.95,0 60 | 1.2.96,0 61 | 1.2.97,0 62 | 1.2.98,0 63 | 1.2.99,0 64 | 1.2.100,0 65 | 1.2.101,0 66 | 1.2.102,0 67 | 1.2.103,0 68 | 1.2.104,0 69 | 1.2.105,0 70 | 1.2.106,0 71 | 1.2.107,0 72 | 1.2.108,0 73 | 1.2.109,0 74 | 1.2.110,0 75 | 1.2.111,0 76 | 1.2.112,0 77 | 1.2.113,0 78 | 1.2.114,0 79 | 1.2.115,0 80 | 1.2.116,0 81 | 1.2.117,0 82 | 1.2.118,0 83 | 1.2.119,0 84 | 1.2.120,0 85 | 1.2.121,0 86 | 1.2.122,0 87 | 1.2.123,0 88 | 1.2.124,0 89 | 1.2.125,0 90 | 1.2.126,0 91 | 1.2.127,0 92 | 1.2.128,0 93 | 1.2.129,0 94 | 1.2.130,0 95 | 1.2.131,0 96 | 1.2.132,0 97 | 1.2.133,0 98 | 1.2.134,0 99 | 1.2.135,0 100 | 1.2.136,0 101 | 1.2.137,0 102 | 1.2.138,0 103 | 1.2.139,0 104 | 1.2.140,0 105 | 1.2.141,0 106 | 1.2.142,0 107 | 1.2.143,0 108 | 1.2.144,0 109 | 1.2.145,0 110 | 1.2.146,0 111 | 1.2.147,0 112 | 1.2.148,0 113 | 1.2.149,0 114 | 1.2.150,0 115 | 1.2.151,0 116 | 1.2.152,0 117 | 1.2.153,0 118 | 1.2.154,0 119 | 1.2.155,0 120 | 1.2.156,0 121 | 1.2.157,0 122 | 1.2.158,0 123 | 1.2.159,0 124 | 1.2.160,0 125 | 1.2.161,0 126 | 1.2.162,0 127 | 1.2.163,0 128 | 1.2.164,0 129 | 1.2.165,0 130 | 1.2.166,107064052 131 | 1.2.167,107078765 132 | 1.2.168,107086636 133 | 1.2.169,107288572 134 | 1.2.170,135803529 135 | 1.2.171,135803529 136 | 1.2.172,135597602 137 | 1.2.173,133654536 138 | 1.2.174,133654536 139 | 1.2.175,134616479 140 | 1.2.176,134652129 141 | 1.2.177,134678844 142 | 1.2.178,134678844 143 | 1.2.179,134096242 144 | 1.2.180,134096242 145 | 1.2.181,135181408 146 | 1.2.182,132069097 147 | 1.2.183,131915149 148 | 1.2.184,131933875 149 | 1.2.185,134226201 150 | 1.2.186,134257274 151 | 1.2.187,134273270 152 | 1.2.188,133923330 153 | 1.2.189,134043599 154 | 1.2.190,132934472 155 | 1.2.191,132706312 156 | 1.2.192,132750708 157 | 1.3.0,130366147 158 | 1.3.1,130514885 159 | 1.3.2,131498227 160 | 1.3.3,131498227 161 | 1.3.4,131435613 162 | 1.3.5,134420551 163 | 1.3.6,132902440 164 | 1.3.7,133802830 165 | 1.4.0,133513289 166 | 1.4.1,136543267 167 | 1.4.2,136741886 168 | 1.4.3,141953878 169 | 1.4.4,147706730 170 | 1.4.5,147133218 171 | 1.4.6,144314016 172 | 1.4.7,139058992 173 | 1.4.8,139761626 174 | 1.5.0,142383446 175 | 1.6.0,142291689 176 | 1.6.1,151056273 177 | 1.6.2,152415095 178 | 1.6.3,142057068 179 | 1.6.4,142391490 180 | 1.7.0,142750407 181 | 1.8.0,143038403 182 | 1.8.1,143132178 183 | 1.9.0,144051552 184 | 1.9.1,144870024 185 | 1.9.2,144734030 186 | 1.9.3,145048368 187 | 1.9.4,156849600 188 | 1.9.5,159571915 189 | 1.9.6,154545456 190 | 1.9.7,165631787 191 | 1.9.8,177701000 192 | 1.10.0,183379180 193 | 1.10.1,183232147 194 | 1.10.2,187512556 195 | 1.10.3,187524563 196 | 1.10.4,191077485 197 | 1.11.0,191070974 198 | 1.11.1,191344503 199 | 1.11.2,191406260 200 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Defold Component Size Dashboard 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |

Defold Component Size Dashboard

15 |

Track the size evolution of Defold components across versions and platforms

16 |
17 | 18 | 19 |
20 |
21 |

Bundle Size

22 |

Compiled game bundle sizes across platforms

23 |
24 | 25 | 28 |
29 |
30 |
31 |
32 |
33 |
34 | 35 | 36 |
37 |
38 |

Engine Size

39 |

Engine binary sizes across platforms

40 |
41 | 42 | 45 |
46 |
47 |
48 |
49 |
50 |
51 | 52 | 53 |
54 |
55 |

Editor Size

56 |

Editor application sizes across desktop platforms

57 |
58 | 59 | 62 |
63 |
64 |
65 |
66 |
67 |
68 | 69 | 70 |
71 |
72 |

Bob.jar Size

73 |

Build tool (bob.jar) size evolution

74 |
75 | 76 | 79 |
80 |
81 |
82 |
83 |
84 |
85 | 86 | 89 |
90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /editor_report.csv: -------------------------------------------------------------------------------- 1 | VERSION,x86_64-macos,x86_64-win32,x86_64-linux,arm64-macos 2 | 1.2.38,0,0,0,0 3 | 1.2.39,0,0,0,0 4 | 1.2.40,0,0,0,0 5 | 1.2.41,0,0,0,0 6 | 1.2.42,0,0,0,0 7 | 1.2.43,0,0,0,0 8 | 1.2.44,0,0,0,0 9 | 1.2.45,0,0,0,0 10 | 1.2.46,0,0,0,0 11 | 1.2.47,0,0,0,0 12 | 1.2.48,0,0,0,0 13 | 1.2.49,0,0,0,0 14 | 1.2.50,0,0,0,0 15 | 1.2.51,0,0,0,0 16 | 1.2.52,0,0,0,0 17 | 1.2.53,0,0,0,0 18 | 1.2.54,0,0,0,0 19 | 1.2.55,0,0,0,0 20 | 1.2.56,0,0,0,0 21 | 1.2.57,0,0,0,0 22 | 1.2.58,0,0,0,0 23 | 1.2.59,0,0,0,0 24 | 1.2.60,0,0,0,0 25 | 1.2.61,0,0,0,0 26 | 1.2.62,0,0,0,0 27 | 1.2.63,0,0,0,0 28 | 1.2.64,0,0,0,0 29 | 1.2.65,0,0,0,0 30 | 1.2.66,0,0,0,0 31 | 1.2.67,0,0,0,0 32 | 1.2.68,0,0,0,0 33 | 1.2.69,0,0,0,0 34 | 1.2.70,0,0,0,0 35 | 1.2.71,0,0,0,0 36 | 1.2.72,0,0,0,0 37 | 1.2.73,0,0,0,0 38 | 1.2.74,0,0,0,0 39 | 1.2.75,0,0,0,0 40 | 1.2.76,0,0,0,0 41 | 1.2.77,0,0,0,0 42 | 1.2.78,0,0,0,0 43 | 1.2.79,0,0,0,0 44 | 1.2.80,0,0,0,0 45 | 1.2.81,0,0,0,0 46 | 1.2.82,0,0,0,0 47 | 1.2.83,0,0,0,0 48 | 1.2.84,0,0,0,0 49 | 1.2.85,0,0,0,0 50 | 1.2.86,0,0,0,0 51 | 1.2.87,0,0,0,0 52 | 1.2.88,0,0,0,0 53 | 1.2.89,0,0,0,0 54 | 1.2.90,0,0,0,0 55 | 1.2.91,0,0,0,0 56 | 1.2.92,0,0,0,0 57 | 1.2.93,0,0,0,0 58 | 1.2.94,0,0,0,0 59 | 1.2.95,0,0,0,0 60 | 1.2.96,0,0,0,0 61 | 1.2.97,0,0,0,0 62 | 1.2.98,0,0,0,0 63 | 1.2.99,0,0,0,0 64 | 1.2.100,0,0,0,0 65 | 1.2.101,0,0,0,0 66 | 1.2.102,0,0,0,0 67 | 1.2.103,0,0,0,0 68 | 1.2.104,0,0,0,0 69 | 1.2.105,0,0,0,0 70 | 1.2.106,0,0,0,0 71 | 1.2.107,0,0,0,0 72 | 1.2.108,0,0,0,0 73 | 1.2.109,0,0,0,0 74 | 1.2.110,0,0,0,0 75 | 1.2.111,0,0,0,0 76 | 1.2.112,0,0,0,0 77 | 1.2.113,0,0,0,0 78 | 1.2.114,0,0,0,0 79 | 1.2.115,0,0,0,0 80 | 1.2.116,0,0,0,0 81 | 1.2.117,0,0,0,0 82 | 1.2.118,0,0,0,0 83 | 1.2.119,0,0,0,0 84 | 1.2.120,0,0,0,0 85 | 1.2.121,0,0,0,0 86 | 1.2.122,0,0,0,0 87 | 1.2.123,0,0,0,0 88 | 1.2.124,0,0,0,0 89 | 1.2.125,0,0,0,0 90 | 1.2.126,0,0,0,0 91 | 1.2.127,0,0,0,0 92 | 1.2.128,0,0,0,0 93 | 1.2.129,0,0,0,0 94 | 1.2.130,0,0,0,0 95 | 1.2.131,0,0,0,0 96 | 1.2.132,0,0,0,0 97 | 1.2.133,0,0,0,0 98 | 1.2.134,0,0,0,0 99 | 1.2.135,0,0,0,0 100 | 1.2.136,0,0,0,0 101 | 1.2.137,0,0,0,0 102 | 1.2.138,0,0,0,0 103 | 1.2.139,0,0,0,0 104 | 1.2.140,0,0,0,0 105 | 1.2.141,0,0,0,0 106 | 1.2.142,0,0,0,0 107 | 1.2.143,0,0,0,0 108 | 1.2.144,0,0,0,0 109 | 1.2.145,0,0,0,0 110 | 1.2.146,0,0,0,0 111 | 1.2.147,0,0,0,0 112 | 1.2.148,0,0,0,0 113 | 1.2.149,0,0,0,0 114 | 1.2.150,0,0,0,0 115 | 1.2.151,0,0,0,0 116 | 1.2.152,0,0,0,0 117 | 1.2.153,0,0,0,0 118 | 1.2.154,0,0,0,0 119 | 1.2.155,0,0,0,0 120 | 1.2.156,0,0,0,0 121 | 1.2.157,0,0,0,0 122 | 1.2.158,0,0,0,0 123 | 1.2.159,0,0,0,0 124 | 1.2.160,0,0,0,0 125 | 1.2.161,0,0,0,0 126 | 1.2.162,0,0,0,0 127 | 1.2.163,0,0,0,0 128 | 1.2.164,0,0,0,0 129 | 1.2.165,0,0,0,0 130 | 1.2.166,0,379211064,389782411,0 131 | 1.2.167,0,379233953,389806827,0 132 | 1.2.168,0,379247672,389820694,0 133 | 1.2.169,0,380250261,390854804,0 134 | 1.2.170,0,412104755,422618946,0 135 | 1.2.171,0,401842184,411750125,0 136 | 1.2.172,0,0,0,0 137 | 1.2.173,0,0,0,0 138 | 1.2.174,0,0,0,0 139 | 1.2.175,0,0,0,0 140 | 1.2.176,0,0,0,0 141 | 1.2.177,0,0,0,0 142 | 1.2.178,0,0,0,0 143 | 1.2.179,0,0,0,0 144 | 1.2.180,0,0,0,0 145 | 1.2.181,0,0,0,0 146 | 1.2.182,0,0,0,0 147 | 1.2.183,0,0,0,0 148 | 1.2.184,0,0,0,0 149 | 1.2.185,0,0,0,0 150 | 1.2.186,0,0,0,0 151 | 1.2.187,0,0,0,0 152 | 1.2.188,0,0,0,0 153 | 1.2.189,0,0,0,0 154 | 1.2.190,0,0,0,0 155 | 1.2.191,0,0,0,0 156 | 1.2.192,0,0,0,0 157 | 1.3.0,0,316587682,338349627,0 158 | 1.3.1,0,316938412,338701661,0 159 | 1.3.2,0,317929250,339693745,0 160 | 1.3.3,0,317929250,339693745,0 161 | 1.3.4,0,318865565,339246852,0 162 | 1.3.5,0,323399058,343681626,0 163 | 1.3.6,303920706,321976637,340424381,0 164 | 1.3.7,305512193,323659539,342069010,0 165 | 1.4.0,305704738,323415393,342046616,0 166 | 1.4.1,307442628,324990713,344815491,0 167 | 1.4.2,308844936,326502655,346331519,0 168 | 1.4.3,316487202,334328425,354158743,0 169 | 1.4.4,323940699,341762218,362593296,0 170 | 1.4.5,323505007,341407857,362239249,0 171 | 1.4.6,322872935,340695080,361990391,0 172 | 1.4.7,313592701,331450127,352746060,0 173 | 1.4.8,321992664,338251921,359643789,0 174 | 1.5.0,323375881,339339291,360742127,0 175 | 1.6.0,326986435,342744545,364207283,322581235 176 | 1.6.1,329405868,345323223,366736428,324936588 177 | 1.6.2,341084631,357483783,378523379,336171010 178 | 1.6.3,284665893,314023606,327550968,279489806 179 | 1.6.4,285094101,314690233,328378010,280206542 180 | 1.7.0,286264978,316252303,330627235,281533058 181 | 1.8.0,286516272,316722528,331062379,281639814 182 | 1.8.1,286856457,317066151,331522121,282217944 183 | 1.9.0,290008330,320997519,335119054,285241511 184 | 1.9.1,289404334,319961498,333862018,284642589 185 | 1.9.2,289316408,319791807,334100465,284519056 186 | 1.9.3,289622265,319994077,334255632,284708557 187 | 1.9.4,294665171,321761411,340243289,289312132 188 | 1.9.5,295075340,324640203,340518295,289633164 189 | 1.9.6,289570634,317850371,338526561,284317044 190 | 1.9.7,293365947,321755493,342283378,287955756 191 | 1.9.8,302517379,330869938,351385189,297200704 192 | 1.10.0,311274497,337796561,358415550,305636552 193 | 1.10.1,312700687,339344070,359475837,306903177 194 | 1.10.2,316313579,342956899,363072780,310436058 195 | 1.10.3,316291760,342991970,363212413,310706411 196 | 1.10.4,320350389,347038675,367398635,314697924 197 | 1.11.0,286014686,315139633,325208355,282740444 198 | 1.11.1,273229693,301547529,311445735,269977379 199 | 1.11.2,280441321,309384771,319429553,277216011 200 | -------------------------------------------------------------------------------- /size-analyzer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Defold Size Analyzer 7 | 8 | 9 | 10 | 11 |
12 |
13 |

Defold Size Analyzer

14 |

Analyze Defold component sizes across versions using interactive bar histograms

15 |
16 | 17 |
18 |
19 | 20 | 22 |
23 | 24 |
25 | 26 | 28 |
29 | 30 |
31 | 32 | 34 |
35 | 36 | 37 | 38 |
39 | 40 | 41 |
42 | 43 | 56 | 57 | 58 | 59 | 60 |
61 | 62 |
63 |

Select platform and versions to begin comparison

64 |
65 | 66 |
67 |
68 | 69 | 70 |
71 |
72 | 73 |
74 |

Legend

75 |
76 |
77 |
78 | Size decreased (Left Side) 79 |
80 |
81 |
82 | Size increased (Right Side) 83 |
84 |
85 |

86 | Shows cumulative change from the selected baseline version to the compare version.
87 | Use tabs above to switch between File Size and VM Size metrics.
88 | Click any file bar to see its detailed evolution timeline across all intermediate versions. 89 |

90 |
91 | 92 |
93 |
94 |
95 |
Version 1
96 |
97 | Cumulative Size Changes - Click bars for timeline, hover for details 98 |
99 |
Version 2
100 |
101 |
102 |
103 |
104 | 105 |
106 |

Comparison Details

107 |
108 | 109 |
110 |

File Changes

111 |
112 | 113 | 119 | 120 | 121 |
122 |
123 |
124 |
125 |
126 | 127 |
128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /css/dashboard.css: -------------------------------------------------------------------------------- 1 | /* Dashboard-specific styles */ 2 | 3 | /* Chart sections */ 4 | .chart-section { 5 | margin-bottom: 3rem; 6 | padding: 1.5rem; 7 | background: #fff; 8 | border-radius: 12px; 9 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 10 | border: 1px solid #e1e8ed; 11 | } 12 | 13 | .chart-header { 14 | margin-bottom: 1.5rem; 15 | border-bottom: 2px solid #f8f9fa; 16 | padding-bottom: 1rem; 17 | } 18 | 19 | .chart-header h2 { 20 | margin: 0 0 0.5rem 0; 21 | color: #2c3e50; 22 | font-size: 1.8rem; 23 | font-weight: 600; 24 | line-height: 1.2; 25 | } 26 | 27 | .chart-header p { 28 | margin: 0 0 1rem 0; 29 | color: #666; 30 | font-size: 1rem; 31 | line-height: 1.4; 32 | } 33 | 34 | /* Version controls */ 35 | .version-control { 36 | margin-top: 1rem; 37 | display: flex; 38 | align-items: center; 39 | gap: 0.5rem; 40 | } 41 | 42 | .version-control label { 43 | font-size: 0.9rem; 44 | color: #555; 45 | font-weight: 500; 46 | } 47 | 48 | .version-control select { 49 | padding: 0.5rem 0.75rem; 50 | border: 1px solid #ddd; 51 | border-radius: 4px; 52 | background: white; 53 | font-size: 0.9rem; 54 | color: #333; 55 | cursor: pointer; 56 | transition: border-color 0.2s ease; 57 | } 58 | 59 | .version-control select:hover { 60 | border-color: #3498db; 61 | } 62 | 63 | .version-control select:focus { 64 | outline: none; 65 | border-color: #3498db; 66 | box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2); 67 | } 68 | 69 | 70 | /* Chart containers */ 71 | .chart-container { 72 | min-height: 800px; 73 | background: #fafbfc; 74 | border-radius: 8px; 75 | padding: 1rem; 76 | } 77 | 78 | .chart-container > div { 79 | width: 100% !important; 80 | height: 800px !important; 81 | } 82 | 83 | /* Footer */ 84 | footer { 85 | margin-top: 3rem; 86 | padding: 2rem 0; 87 | text-align: center; 88 | border-top: 1px solid #e1e8ed; 89 | } 90 | 91 | footer a { 92 | color: #3498db; 93 | text-decoration: none; 94 | font-weight: 500; 95 | font-size: 1.1rem; 96 | padding: 0.75rem 1.5rem; 97 | border: 2px solid #3498db; 98 | border-radius: 6px; 99 | transition: all 0.2s ease; 100 | display: inline-block; 101 | } 102 | 103 | footer a:hover { 104 | background: #3498db; 105 | color: white; 106 | transform: translateY(-1px); 107 | box-shadow: 0 4px 12px rgba(52, 152, 219, 0.3); 108 | } 109 | 110 | /* Loading states */ 111 | .loading { 112 | display: flex; 113 | align-items: center; 114 | justify-content: center; 115 | height: 800px; 116 | color: #666; 117 | font-size: 1.1rem; 118 | } 119 | 120 | .loading::before { 121 | content: ''; 122 | width: 20px; 123 | height: 20px; 124 | border: 2px solid #ddd; 125 | border-top: 2px solid #3498db; 126 | border-radius: 50%; 127 | animation: spin 1s linear infinite; 128 | margin-right: 0.75rem; 129 | } 130 | 131 | @keyframes spin { 132 | to { transform: rotate(360deg); } 133 | } 134 | 135 | /* Error states */ 136 | .error { 137 | display: flex; 138 | align-items: center; 139 | justify-content: center; 140 | height: 800px; 141 | color: #e74c3c; 142 | font-size: 1.1rem; 143 | background: #fdf2f2; 144 | border-radius: 6px; 145 | border: 1px solid #fadbd8; 146 | } 147 | 148 | /* Responsive design */ 149 | @media (max-width: 768px) { 150 | .container { 151 | padding: 1rem; 152 | } 153 | 154 | .chart-section { 155 | margin-bottom: 2rem; 156 | padding: 1rem; 157 | } 158 | 159 | .chart-header { 160 | margin-bottom: 1rem; 161 | padding-bottom: 0.75rem; 162 | } 163 | 164 | .chart-header h2 { 165 | font-size: 1.4rem; 166 | margin-bottom: 0.75rem; 167 | } 168 | 169 | .chart-header p { 170 | font-size: 0.9rem; 171 | margin-bottom: 0.75rem; 172 | } 173 | 174 | .version-control { 175 | margin-top: 0.75rem; 176 | flex-direction: column; 177 | align-items: flex-start; 178 | gap: 0.5rem; 179 | } 180 | 181 | .version-control label { 182 | font-size: 0.85rem; 183 | } 184 | 185 | .version-control select { 186 | width: 100%; 187 | max-width: 250px; 188 | padding: 0.6rem 0.75rem; 189 | } 190 | 191 | .chart-container { 192 | min-height: 500px; 193 | padding: 0.5rem; 194 | margin-top: 1rem; 195 | } 196 | 197 | .chart-container > div { 198 | height: 500px !important; 199 | } 200 | 201 | header h1 { 202 | font-size: 1.8rem; 203 | } 204 | 205 | header p { 206 | font-size: 0.9rem; 207 | } 208 | } 209 | 210 | @media (max-width: 480px) { 211 | .container { 212 | padding: 0.75rem; 213 | } 214 | 215 | .chart-section { 216 | margin-bottom: 1.5rem; 217 | padding: 0.75rem; 218 | } 219 | 220 | .chart-header h2 { 221 | font-size: 1.25rem; 222 | margin-bottom: 0.5rem; 223 | } 224 | 225 | .chart-header p { 226 | font-size: 0.85rem; 227 | margin-bottom: 0.5rem; 228 | } 229 | 230 | .version-control { 231 | margin-top: 0.5rem; 232 | } 233 | 234 | .version-control label { 235 | font-size: 0.8rem; 236 | } 237 | 238 | .version-control select { 239 | max-width: 100%; 240 | font-size: 0.85rem; 241 | padding: 0.5rem 0.6rem; 242 | } 243 | 244 | .chart-container { 245 | min-height: 400px; 246 | padding: 0.25rem; 247 | } 248 | 249 | .chart-container > div { 250 | height: 400px !important; 251 | } 252 | 253 | header h1 { 254 | font-size: 1.5rem; 255 | } 256 | 257 | header p { 258 | font-size: 0.85rem; 259 | } 260 | 261 | footer a { 262 | font-size: 1rem; 263 | padding: 0.6rem 1.2rem; 264 | } 265 | } 266 | 267 | /* Platform-specific colors for consistency */ 268 | .platform-arm64-ios { color: #e74c3c; } 269 | .platform-arm64-android { color: #3498db; } 270 | .platform-armv7-android { color: #9b59b6; } 271 | .platform-x86_64-macos { color: #2ecc71; } 272 | .platform-js-web { color: #f39c12; } 273 | .platform-wasm-web { color: #e67e22; } 274 | .platform-x86_64-linux { color: #34495e; } 275 | .platform-x86-win32 { color: #16a085; } 276 | .platform-x86_64-win32 { color: #27ae60; } 277 | .platform-arm64-macos { color: #8e44ad; } 278 | 279 | /* Ensure Plotly tooltips remain readable with classic styling */ 280 | .plotly .hovertext { 281 | background: #FFFFDD !important; 282 | color: black !important; 283 | border: 1px solid #333 !important; 284 | } 285 | 286 | .plotly .hovertext text { 287 | fill: black !important; 288 | } 289 | 290 | /* Override any colorful tooltip backgrounds */ 291 | g.hovertext { 292 | background: #FFFFDD !important; 293 | } 294 | 295 | g.hovertext rect { 296 | fill: #FFFFDD !important; 297 | stroke: #333 !important; 298 | } 299 | 300 | g.hovertext text { 301 | fill: black !important; 302 | } -------------------------------------------------------------------------------- /bundle_report.csv: -------------------------------------------------------------------------------- 1 | VERSION,arm64-ios,arm64-android,armv7-android,x86_64-macos,js-web,wasm-web,x86_64-linux,x86-win32,x86_64-win32,arm64-macos 2 | 1.2.38,0,0,0,0,0,0,0,0,0,0 3 | 1.2.39,0,0,0,0,0,0,0,0,0,0 4 | 1.2.40,0,0,0,0,0,0,0,0,0,0 5 | 1.2.41,0,0,0,0,0,0,0,0,0,0 6 | 1.2.42,0,0,0,0,0,0,0,0,0,0 7 | 1.2.43,0,0,0,0,0,0,0,0,0,0 8 | 1.2.44,0,0,0,0,0,0,0,0,0,0 9 | 1.2.45,0,0,0,0,0,0,0,0,0,0 10 | 1.2.46,0,0,0,0,0,0,0,0,0,0 11 | 1.2.47,0,0,0,0,0,0,0,0,0,0 12 | 1.2.48,0,0,0,0,0,0,0,0,0,0 13 | 1.2.49,0,0,0,0,0,0,0,0,0,0 14 | 1.2.50,0,0,0,0,0,0,0,0,0,0 15 | 1.2.51,0,0,0,0,0,0,0,0,0,0 16 | 1.2.52,0,0,0,0,0,0,0,0,0,0 17 | 1.2.53,0,0,0,0,0,0,0,0,0,0 18 | 1.2.54,0,0,0,0,0,0,0,0,0,0 19 | 1.2.55,0,0,0,0,0,0,0,0,0,0 20 | 1.2.56,0,0,0,0,0,0,0,0,0,0 21 | 1.2.57,0,0,0,0,0,0,0,0,0,0 22 | 1.2.58,0,0,0,0,0,0,0,0,0,0 23 | 1.2.59,0,0,0,0,0,0,0,0,0,0 24 | 1.2.60,0,0,0,0,0,0,0,0,0,0 25 | 1.2.61,0,0,0,0,0,0,0,0,0,0 26 | 1.2.62,0,0,0,0,0,0,0,0,0,0 27 | 1.2.63,0,0,0,0,0,0,0,0,0,0 28 | 1.2.64,0,0,0,0,0,0,0,0,0,0 29 | 1.2.65,0,0,0,0,0,0,0,0,0,0 30 | 1.2.66,0,0,0,0,0,0,0,0,0,0 31 | 1.2.67,0,0,0,0,0,0,0,0,0,0 32 | 1.2.68,0,0,0,0,0,0,0,0,0,0 33 | 1.2.69,0,0,0,0,0,0,0,0,0,0 34 | 1.2.70,0,0,0,0,0,0,0,0,0,0 35 | 1.2.71,0,0,0,0,0,0,0,0,0,0 36 | 1.2.72,0,0,0,0,0,0,0,0,0,0 37 | 1.2.73,0,0,0,0,0,0,0,0,0,0 38 | 1.2.74,0,0,0,0,0,0,0,0,0,0 39 | 1.2.75,0,0,0,0,0,0,0,0,0,0 40 | 1.2.76,0,0,0,0,0,0,0,0,0,0 41 | 1.2.77,0,0,0,0,0,0,0,0,0,0 42 | 1.2.78,0,0,0,0,0,0,0,0,0,0 43 | 1.2.79,0,0,0,0,0,0,0,0,0,0 44 | 1.2.80,0,0,0,0,0,0,0,0,0,0 45 | 1.2.81,0,0,0,0,0,0,0,0,0,0 46 | 1.2.82,0,0,0,0,0,0,0,0,0,0 47 | 1.2.83,0,0,0,0,0,0,0,0,0,0 48 | 1.2.84,0,0,0,0,0,0,0,0,0,0 49 | 1.2.85,0,0,0,0,0,0,0,0,0,0 50 | 1.2.86,0,0,0,0,0,0,0,0,0,0 51 | 1.2.87,0,0,0,0,0,0,0,0,0,0 52 | 1.2.88,0,0,0,0,0,0,0,0,0,0 53 | 1.2.89,0,0,0,0,0,0,0,0,0,0 54 | 1.2.90,0,0,0,0,0,0,0,0,0,0 55 | 1.2.91,0,0,0,0,0,0,0,0,0,0 56 | 1.2.92,0,0,0,0,0,0,0,0,0,0 57 | 1.2.93,0,0,0,0,0,0,0,0,0,0 58 | 1.2.94,0,0,0,0,0,0,0,0,0,0 59 | 1.2.95,0,0,0,0,0,0,0,0,0,0 60 | 1.2.96,0,0,0,0,0,0,0,0,0,0 61 | 1.2.97,0,0,0,0,0,0,0,0,0,0 62 | 1.2.98,0,0,0,0,0,0,0,0,0,0 63 | 1.2.99,0,0,0,0,0,0,0,0,0,0 64 | 1.2.100,0,0,0,0,0,0,0,0,0,0 65 | 1.2.101,0,0,0,0,0,0,0,0,0,0 66 | 1.2.102,0,0,0,0,0,0,0,0,0,0 67 | 1.2.103,0,0,0,0,0,0,0,0,0,0 68 | 1.2.104,0,0,0,0,0,0,0,0,0,0 69 | 1.2.105,0,0,0,0,0,0,0,0,0,0 70 | 1.2.106,0,0,0,0,0,0,0,0,0,0 71 | 1.2.107,0,0,0,0,0,0,0,0,0,0 72 | 1.2.108,0,0,0,0,0,0,0,0,0,0 73 | 1.2.109,0,0,0,0,0,0,0,0,0,0 74 | 1.2.110,0,0,0,0,0,0,0,0,0,0 75 | 1.2.111,0,0,0,0,0,0,0,0,0,0 76 | 1.2.112,0,0,0,0,0,0,0,0,0,0 77 | 1.2.113,0,0,0,0,0,0,0,0,0,0 78 | 1.2.114,0,0,0,0,0,0,0,0,0,0 79 | 1.2.115,0,0,0,0,0,0,0,0,0,0 80 | 1.2.116,0,0,0,0,0,0,0,0,0,0 81 | 1.2.117,0,0,0,0,0,0,0,0,0,0 82 | 1.2.118,0,0,0,0,0,0,0,0,0,0 83 | 1.2.119,0,0,0,0,0,0,0,0,0,0 84 | 1.2.120,0,0,0,0,0,0,0,0,0,0 85 | 1.2.121,0,0,0,0,0,0,0,0,0,0 86 | 1.2.122,0,0,0,0,0,0,0,0,0,0 87 | 1.2.123,0,0,0,0,0,0,0,0,0,0 88 | 1.2.124,0,0,0,0,0,0,0,0,0,0 89 | 1.2.125,0,0,0,0,0,0,0,0,0,0 90 | 1.2.126,0,0,0,0,0,0,0,0,0,0 91 | 1.2.127,0,0,0,0,0,0,0,0,0,0 92 | 1.2.128,0,0,0,0,0,0,0,0,0,0 93 | 1.2.129,0,0,0,0,0,0,0,0,0,0 94 | 1.2.130,0,0,0,0,0,0,0,0,0,0 95 | 1.2.131,0,0,0,0,0,0,0,0,0,0 96 | 1.2.132,0,0,0,0,0,0,0,0,0,0 97 | 1.2.133,0,0,0,0,0,0,0,0,0,0 98 | 1.2.134,0,0,0,0,0,0,0,0,0,0 99 | 1.2.135,0,0,0,0,0,0,0,0,0,0 100 | 1.2.136,0,0,0,0,0,0,0,0,0,0 101 | 1.2.137,0,0,0,0,0,0,0,0,0,0 102 | 1.2.138,0,0,0,0,0,0,0,0,0,0 103 | 1.2.139,0,0,0,0,0,0,0,0,0,0 104 | 1.2.140,0,0,0,0,0,0,0,0,0,0 105 | 1.2.141,0,0,0,0,0,0,0,0,0,0 106 | 1.2.142,0,0,0,0,0,0,0,0,0,0 107 | 1.2.143,0,0,0,0,0,0,0,0,0,0 108 | 1.2.144,0,0,0,0,0,0,0,0,0,0 109 | 1.2.145,0,0,0,0,0,0,0,0,0,0 110 | 1.2.146,0,0,0,0,0,0,0,0,0,0 111 | 1.2.147,0,0,0,0,0,0,0,0,0,0 112 | 1.2.148,0,0,0,0,0,0,0,0,0,0 113 | 1.2.149,0,0,0,0,0,0,0,0,0,0 114 | 1.2.150,0,0,0,0,0,0,0,0,0,0 115 | 1.2.151,0,0,0,0,0,0,0,0,0,0 116 | 1.2.152,0,0,0,0,0,0,0,0,0,0 117 | 1.2.153,0,0,0,0,0,0,0,0,0,0 118 | 1.2.154,0,0,0,0,0,0,0,0,0,0 119 | 1.2.155,0,0,0,0,0,0,0,0,0,0 120 | 1.2.156,0,0,0,0,0,0,0,0,0,0 121 | 1.2.157,0,0,0,0,0,0,0,0,0,0 122 | 1.2.158,0,0,0,0,0,0,0,0,0,0 123 | 1.2.159,0,0,0,0,0,0,0,0,0,0 124 | 1.2.160,0,0,0,0,0,0,0,0,0,0 125 | 1.2.161,0,0,0,0,0,0,0,0,0,0 126 | 1.2.162,0,0,0,0,0,0,0,0,0,0 127 | 1.2.163,0,0,0,0,0,0,0,0,0,0 128 | 1.2.164,0,0,0,0,0,0,0,0,0,0 129 | 1.2.165,0,0,0,0,0,0,0,0,0,0 130 | 1.2.166,0,0,0,4903042,2135157,2135156,2279276,2278882,2640013,0 131 | 1.2.167,0,0,0,4903195,2135613,2135614,2279761,2279380,2640468,0 132 | 1.2.168,0,0,0,4903229,2136856,2136856,2280112,2279798,2640920,0 133 | 1.2.169,0,0,0,4953181,2168338,2168338,2297914,2280313,2640715,0 134 | 1.2.170,0,0,0,4867450,2487049,2487048,2267170,2394652,2779963,0 135 | 1.2.171,0,0,0,4867450,2487049,2487048,2267170,2394652,2779963,0 136 | 1.2.172,0,0,0,4855284,2488697,2488697,2218831,2395577,2781188,0 137 | 1.2.173,0,1672536,1615194,3976115,2495531,2495532,1841827,2198735,2562808,0 138 | 1.2.174,0,1672529,1615185,4000635,2495531,2495530,1841763,2198784,2562755,0 139 | 1.2.175,0,1713489,1660240,4099506,2545905,2545905,1884656,2239733,2610053,0 140 | 1.2.176,0,1713496,1660241,4099498,2548117,2548117,1885522,2240821,2612642,0 141 | 1.2.177,0,1717591,1660246,4099498,2548392,2548391,1885603,2241100,2612616,0 142 | 1.2.178,0,1717591,1660246,4099498,2548392,2548391,1885603,2241100,2612616,0 143 | 1.2.179,0,1717589,1664346,4099605,2201171,2201171,1890197,2244298,2616297,0 144 | 1.2.180,0,1705295,1660243,3952173,2219824,2219824,1849027,2228458,2595066,0 145 | 1.2.181,0,1709398,1664337,3952293,3477357,3477357,1853922,2233274,2600308,0 146 | 1.2.182,0,1680727,1635676,3902621,2227058,2227059,1824983,2203302,2562387,0 147 | 1.2.183,0,1684815,1643862,3919069,2224087,2224087,1827518,2202140,2558347,0 148 | 1.2.184,0,1688911,1643856,3902738,2225591,2225589,1828497,2202471,2559595,0 149 | 1.2.185,0,1701201,1660243,3936135,2226683,2226683,1840156,2231271,2590955,0 150 | 1.2.186,0,1701192,1664339,3936138,2228367,2228367,1841365,2232798,2592023,0 151 | 1.2.187,0,1701199,1664348,3936138,2229301,2229302,1841612,2232901,2592234,0 152 | 1.2.188,0,1693007,1652054,3903202,2211340,2211340,1832963,2222563,2579291,0 153 | 1.2.189,0,1697102,1656151,3919762,2217192,2217192,1837336,2227505,2586530,0 154 | 1.2.190,0,1697105,1660252,3936217,2222184,2222184,1839453,2232894,2588874,0 155 | 1.2.191,0,1701207,1664337,3936337,2226956,2226955,1839068,2236151,2592502,0 156 | 1.2.192,0,1705288,1664339,3936400,2229571,2229571,1840895,2239236,2594820,0 157 | 1.3.0,1311415,1701201,1664339,3936292,2226882,2226882,1839416,2251344,2611718,0 158 | 1.3.1,1325539,1709400,1668433,3936608,2232602,2232602,1843884,2256104,2616751,0 159 | 1.3.2,1325721,1709391,1668435,3936616,2232959,2232959,1844075,2256226,2617231,0 160 | 1.3.3,1325721,1709391,1668435,3936616,2232959,2232959,1844075,2256226,2617231,0 161 | 1.3.4,1308359,1688918,1643864,3903803,2209528,2209528,1820900,2227513,2583570,0 162 | 1.3.5,1310633,1717596,1680739,4003480,2215907,2215907,1872079,2234894,2622010,0 163 | 1.3.6,1310633,1725791,1688919,4003480,2226145,2226145,1886697,2274835,2662573,0 164 | 1.3.7,1305877,1733979,1693015,4053138,2237375,2237375,1889606,2279130,2670770,0 165 | 1.4.0,1295418,1725782,1684833,4020387,2223981,2223981,1881450,2257772,2643957,0 166 | 1.4.1,1298827,1729886,1688920,4036932,2231360,2231360,1886200,2263148,2649248,0 167 | 1.4.2,1306701,1738079,1697123,4053364,2241220,2241220,1894791,2271528,2661271,0 168 | 1.4.3,1309689,1746261,1713504,4069884,2247205,2247206,1898977,2276062,2666082,0 169 | 1.4.4,1314949,1750314,1721644,3578569,2260640,2260640,1905247,2295685,2689260,0 170 | 1.4.5,1313123,1733930,1701164,3578631,2256360,2256360,1885803,2275965,2667344,0 171 | 1.4.6,1317318,1738026,1709356,3595103,2268666,2268667,1890666,2281471,2672954,0 172 | 1.4.7,1320502,1746218,1721644,3595119,2271732,2271732,1892687,2283840,2675117,3208519 173 | 1.4.8,1329218,1754410,1733932,3611875,1344415,964545,1902172,2293442,2687490,3225067 174 | 1.5.0,1339199,1766698,1750316,3644874,1355133,971917,1915733,2312242,2712942,3258386 175 | 1.6.0,1317645,1746218,1729836,3628981,1351567,968334,1895454,2292419,2694193,3258861 176 | 1.6.1,1319012,1750314,1733932,3629485,1346642,962396,1897939,2297380,2699303,3259373 177 | 1.6.2,1321164,1754410,1733932,3647229,1347477,962770,1902112,2317662,2727354,3260717 178 | 1.6.3,1326119,1758506,1742124,3647353,1354332,967108,1908050,2324926,2738152,3277329 179 | 1.6.4,1344908,1778986,1758508,3697041,1374597,981042,1929574,2346697,2763469,3310945 180 | 1.7.0,1351159,1787178,1770796,3713521,1383795,986440,1937267,2356314,2775164,3327537 181 | 1.8.0,1344643,1799466,1783084,3697201,1414710,1033877,1948337,2367135,2789744,3312897 182 | 1.8.1,1346975,1803562,1787180,3697377,1418640,1037326,1952160,2370898,2795117,3313065 183 | 1.9.0,1357163,1815850,1799468,3845113,1425926,1041757,1961881,2380784,2805620,3474337 184 | 1.9.1,1361782,1819946,1803564,3852977,1429217,1043971,1964855,2382964,2808789,3490545 185 | 1.9.2,1375761,1832234,1815852,3849693,1434086,1047536,1975042,2427588,2857904,3491141 186 | 1.9.3,1377701,1832234,1815852,3849745,1435504,1048396,1976636,2428057,2858941,3491209 187 | 1.9.4,1396325,1852714,1840428,3903801,1442770,1047320,1998650,2453272,2888976,3525049 188 | 1.9.5,1395866,1856810,1840428,3908023,1444022,1048360,2000146,2454121,2890311,3525175 189 | 1.9.6,1402198,1856810,1840428,3904559,1449431,1052964,1996883,2209294,2638902,3525799 190 | 1.9.7,1389380,1865002,1852716,3888208,1459741,1060663,2153418,2226936,2656842,3407008 191 | 1.9.8,1396550,1873194,1860908,3904719,1469982,1066779,2162410,2232197,2666100,3423639 192 | 1.10.0,1406427,1885482,1873196,8071281,1474534,1070766,2171665,2244439,2686095,7167705 193 | 1.10.1,1465240,1942826,1930540,8145227,1539076,1127986,2235780,2306343,2746970,7233955 194 | 1.10.2,1475975,1955114,1946924,8174086,1546044,1135634,2251940,2317467,2762661,7250686 195 | 1.10.3,1475848,1959210,1951020,8178224,1546867,1136488,2253383,2317877,2763540,7250704 196 | 1.10.4,1470349,1958461,1944910,8190808,1547335,1140535,2270469,2332502,2775529,7250984 197 | 1.11.0,1470584,1957303,1944706,8186976,1546237,1139066,2269918,2331525,2775088,7251272 198 | 1.11.1,1476645,1966325,1957364,8203539,1551912,1144325,2277888,2340230,2784035,7267932 199 | 1.11.2,1478187,1969202,1960879,8207703,1553921,1145773,2281888,2342655,2786691,7284471 200 | -------------------------------------------------------------------------------- /engine_report.csv: -------------------------------------------------------------------------------- 1 | VERSION,arm64-ios,arm64-android,armv7-android,x86_64-macos,js-web,wasm-web,x86_64-linux,x86-win32,x86_64-win32,arm64-macos 2 | 1.2.38,0,0,0,0,0,0,0,0,0,0 3 | 1.2.39,0,0,0,0,0,0,0,0,0,0 4 | 1.2.40,0,0,0,0,0,0,0,0,0,0 5 | 1.2.41,0,0,0,0,0,0,0,0,0,0 6 | 1.2.42,0,0,0,0,0,0,0,0,0,0 7 | 1.2.43,0,0,0,0,0,0,0,0,0,0 8 | 1.2.44,0,0,0,0,0,0,0,0,0,0 9 | 1.2.45,0,0,0,0,0,0,0,0,0,0 10 | 1.2.46,0,0,0,0,0,0,0,0,0,0 11 | 1.2.47,0,0,0,0,0,0,0,0,0,0 12 | 1.2.48,0,0,0,0,0,0,0,0,0,0 13 | 1.2.49,0,0,0,0,0,0,0,0,0,0 14 | 1.2.50,0,0,0,0,0,0,0,0,0,0 15 | 1.2.51,0,0,0,0,0,0,0,0,0,0 16 | 1.2.52,0,0,0,0,0,0,0,0,0,0 17 | 1.2.53,0,0,0,0,0,0,0,0,0,0 18 | 1.2.54,0,0,0,0,0,0,0,0,0,0 19 | 1.2.55,0,0,0,0,0,0,0,0,0,0 20 | 1.2.56,0,0,0,0,0,0,0,0,0,0 21 | 1.2.57,0,0,0,0,0,0,0,0,0,0 22 | 1.2.58,0,0,0,0,0,0,0,0,0,0 23 | 1.2.59,0,0,0,0,0,0,0,0,0,0 24 | 1.2.60,0,0,0,0,0,0,0,0,0,0 25 | 1.2.61,0,0,0,0,0,0,0,0,0,0 26 | 1.2.62,0,0,0,0,0,0,0,0,0,0 27 | 1.2.63,0,0,0,0,0,0,0,0,0,0 28 | 1.2.64,0,0,0,0,0,0,0,0,0,0 29 | 1.2.65,0,0,0,0,0,0,0,0,0,0 30 | 1.2.66,0,0,0,0,0,0,0,0,0,0 31 | 1.2.67,0,0,0,0,0,0,0,0,0,0 32 | 1.2.68,0,0,0,0,0,0,0,0,0,0 33 | 1.2.69,0,0,0,0,0,0,0,0,0,0 34 | 1.2.70,0,0,0,0,0,0,0,0,0,0 35 | 1.2.71,0,0,0,0,0,0,0,0,0,0 36 | 1.2.72,0,0,0,0,0,0,0,0,0,0 37 | 1.2.73,0,0,0,0,0,0,0,0,0,0 38 | 1.2.74,0,0,0,0,0,0,0,0,0,0 39 | 1.2.75,0,0,0,0,0,0,0,0,0,0 40 | 1.2.76,0,0,0,0,0,0,0,0,0,0 41 | 1.2.77,0,0,0,0,0,0,0,0,0,0 42 | 1.2.78,0,0,0,0,0,0,0,0,0,0 43 | 1.2.79,0,0,0,0,0,0,0,0,0,0 44 | 1.2.80,0,0,0,0,0,0,0,0,0,0 45 | 1.2.81,0,0,0,0,0,0,0,0,0,0 46 | 1.2.82,0,0,0,0,0,0,0,0,0,0 47 | 1.2.83,0,0,0,0,0,0,0,0,0,0 48 | 1.2.84,0,0,0,0,0,0,0,0,0,0 49 | 1.2.85,0,0,0,0,0,0,0,0,0,0 50 | 1.2.86,0,0,0,0,0,0,0,0,0,0 51 | 1.2.87,0,0,0,0,0,0,0,0,0,0 52 | 1.2.88,0,0,0,0,0,0,0,0,0,0 53 | 1.2.89,0,0,0,0,0,0,0,0,0,0 54 | 1.2.90,0,0,0,0,0,0,0,0,0,0 55 | 1.2.91,0,0,0,0,0,0,0,0,0,0 56 | 1.2.92,0,0,0,0,0,0,0,0,0,0 57 | 1.2.93,0,0,0,0,0,0,0,0,0,0 58 | 1.2.94,0,0,0,0,0,0,0,0,0,0 59 | 1.2.95,0,0,0,0,0,0,0,0,0,0 60 | 1.2.96,0,0,0,0,0,0,0,0,0,0 61 | 1.2.97,0,0,0,0,0,0,0,0,0,0 62 | 1.2.98,0,0,0,0,0,0,0,0,0,0 63 | 1.2.99,0,0,0,0,0,0,0,0,0,0 64 | 1.2.100,0,0,0,0,0,0,0,0,0,0 65 | 1.2.101,0,0,0,0,0,0,0,0,0,0 66 | 1.2.102,0,0,0,0,0,0,0,0,0,0 67 | 1.2.103,0,0,0,0,0,0,0,0,0,0 68 | 1.2.104,0,0,0,0,0,0,0,0,0,0 69 | 1.2.105,0,0,0,0,0,0,0,0,0,0 70 | 1.2.106,0,0,0,0,0,0,0,0,0,0 71 | 1.2.107,0,0,0,0,0,0,0,0,0,0 72 | 1.2.108,0,0,0,0,0,0,0,0,0,0 73 | 1.2.109,0,0,0,0,0,0,0,0,0,0 74 | 1.2.110,0,0,0,0,0,0,0,0,0,0 75 | 1.2.111,0,0,0,0,0,0,0,0,0,0 76 | 1.2.112,0,0,0,0,0,0,0,0,0,0 77 | 1.2.113,0,0,0,0,0,0,0,0,0,0 78 | 1.2.114,0,0,0,0,0,0,0,0,0,0 79 | 1.2.115,0,0,0,0,0,0,0,0,0,0 80 | 1.2.116,0,0,0,0,0,0,0,0,0,0 81 | 1.2.117,0,0,0,0,0,0,0,0,0,0 82 | 1.2.118,0,0,0,0,0,0,0,0,0,0 83 | 1.2.119,0,0,0,0,0,0,0,0,0,0 84 | 1.2.120,0,0,0,0,0,0,0,0,0,0 85 | 1.2.121,0,0,0,0,0,0,0,0,0,0 86 | 1.2.122,0,0,0,0,0,0,0,0,0,0 87 | 1.2.123,0,0,0,0,0,0,0,0,0,0 88 | 1.2.124,0,0,0,0,0,0,0,0,0,0 89 | 1.2.125,0,0,0,0,0,0,0,0,0,0 90 | 1.2.126,0,0,0,0,0,0,0,0,0,0 91 | 1.2.127,0,0,0,0,0,0,0,0,0,0 92 | 1.2.128,0,0,0,0,0,0,0,0,0,0 93 | 1.2.129,0,0,0,0,0,0,0,0,0,0 94 | 1.2.130,0,0,0,0,0,0,0,0,0,0 95 | 1.2.131,0,0,0,0,0,0,0,0,0,0 96 | 1.2.132,0,0,0,0,0,0,0,0,0,0 97 | 1.2.133,0,0,0,0,0,0,0,0,0,0 98 | 1.2.134,0,0,0,0,0,0,0,0,0,0 99 | 1.2.135,0,0,0,0,0,0,0,0,0,0 100 | 1.2.136,0,0,0,0,0,0,0,0,0,0 101 | 1.2.137,0,0,0,0,0,0,0,0,0,0 102 | 1.2.138,0,0,0,0,0,0,0,0,0,0 103 | 1.2.139,0,0,0,0,0,0,0,0,0,0 104 | 1.2.140,0,0,0,0,0,0,0,0,0,0 105 | 1.2.141,0,0,0,0,0,0,0,0,0,0 106 | 1.2.142,0,0,0,0,0,0,0,0,0,0 107 | 1.2.143,0,0,0,0,0,0,0,0,0,0 108 | 1.2.144,0,0,0,0,0,0,0,0,0,0 109 | 1.2.145,0,0,0,0,0,0,0,0,0,0 110 | 1.2.146,0,0,0,0,0,0,0,0,0,0 111 | 1.2.147,0,0,0,0,0,0,0,0,0,0 112 | 1.2.148,0,0,0,0,0,0,0,0,0,0 113 | 1.2.149,0,0,0,0,0,0,0,0,0,0 114 | 1.2.150,0,0,0,0,0,0,0,0,0,0 115 | 1.2.151,0,0,0,0,0,0,0,0,0,0 116 | 1.2.152,0,0,0,0,0,0,0,0,0,0 117 | 1.2.153,0,0,0,0,0,0,0,0,0,0 118 | 1.2.154,0,0,0,0,0,0,0,0,0,0 119 | 1.2.155,0,0,0,0,0,0,0,0,0,0 120 | 1.2.156,0,0,0,0,0,0,0,0,0,0 121 | 1.2.157,0,0,0,0,0,0,0,0,0,0 122 | 1.2.158,0,0,0,0,0,0,0,0,0,0 123 | 1.2.159,0,0,0,0,0,0,0,0,0,0 124 | 1.2.160,0,0,0,0,0,0,0,0,0,0 125 | 1.2.161,0,0,0,0,0,0,0,0,0,0 126 | 1.2.162,0,0,0,0,0,0,0,0,0,0 127 | 1.2.163,0,0,0,0,0,0,0,0,0,0 128 | 1.2.164,0,0,0,0,0,0,0,0,0,0 129 | 1.2.165,0,0,0,0,0,0,0,0,0,0 130 | 1.2.166,2700168,3661544,3185048,4891172,4835755,2286395,5167560,5381632,6499840,0 131 | 1.2.167,2700184,3657632,3185144,4891188,4836689,2287332,5171848,5383680,6502400,0 132 | 1.2.168,2700184,3669920,3185144,4891188,4837918,2287888,5171848,5383168,6501376,0 133 | 1.2.169,2733488,3699696,3226680,4940932,4936683,2340041,5222440,5398528,6533120,0 134 | 1.2.170,2689520,3511296,3128384,4855172,7765741,2105327,5124024,5713920,6893568,0 135 | 1.2.171,2689520,3511296,3128384,4855172,7765741,2105327,5124024,5713920,6893568,0 136 | 1.2.172,2620432,3511288,3128364,4842868,7776508,2106805,4895928,5717504,6895104,0 137 | 1.2.173,2586136,3457880,3075028,3963408,7800581,2114245,3871648,5089280,6170624,0 138 | 1.2.174,2586132,3466072,3075028,3987904,7800441,2114250,3871648,5089280,6170624,0 139 | 1.2.175,2635492,3548216,3165252,4086760,7940338,2155920,3953824,5184512,6282240,0 140 | 1.2.176,2635492,3548216,3169348,4086752,7950699,2158372,3957920,5186560,6288896,0 141 | 1.2.177,2635492,3556408,3169348,4086752,7951095,2158464,3957920,5187072,6288896,0 142 | 1.2.178,2635492,3556408,3169348,4086752,7951095,2158464,3957920,5187072,6288896,0 143 | 1.2.179,2635532,3548216,3177540,4086840,4499044,2159059,3966112,5194240,6297600,0 144 | 1.2.180,2553404,3492512,3130052,3939384,4523023,2184641,3839616,5094400,6171136,0 145 | 1.2.181,2553460,3508896,3138244,3939504,4523023,3117419,3851904,5105664,6184448,0 146 | 1.2.182,2520080,3451544,3089084,3889832,4538185,2192835,3798632,5040128,6098432,0 147 | 1.2.183,2536296,3488408,3097276,3906144,4531672,2182293,3802720,5034496,6082048,0 148 | 1.2.184,2536312,3464184,3097628,3889784,4533137,2182616,3803072,5033472,6082048,0 149 | 1.2.185,2553000,3464144,3118032,3923176,4535548,2183817,3823616,5097472,6158848,0 150 | 1.2.186,2553000,3484680,3122160,3923184,4539647,2186237,3827744,5100032,6161920,0 151 | 1.2.187,2553000,3472392,3122160,3923184,4540474,2186724,3827744,5100544,6163456,0 152 | 1.2.188,2536536,3452096,3097680,3890248,4495274,2164996,3799264,5072384,6126080,0 153 | 1.2.189,2536952,3464728,3106064,3906808,4505080,2170497,3811936,5086208,6141952,0 154 | 1.2.190,2536968,3460632,3110160,3923224,4515600,2175511,3816032,5105152,6152192,0 155 | 1.2.191,2553568,3468904,3118392,3923344,4525468,2180643,3820120,5113856,6162944,0 156 | 1.2.192,2553584,3481200,3122488,3923384,4531041,2183249,3824216,5121536,6170624,0 157 | 1.3.0,2553472,3463344,3113496,3923272,4523948,2178435,3818616,5339648,6533120,0 158 | 1.3.1,2619992,3483864,3121720,3923312,4539555,2186567,3830968,5348864,6545920,0 159 | 1.3.2,2619992,3475680,3121728,3923320,4540390,2186884,3830968,5349376,6546432,0 160 | 1.3.3,2619992,3475680,3121728,3923320,4540390,2186884,3830968,5349376,6546432,0 161 | 1.3.4,2586800,3431496,3072544,3890304,4502203,2162204,3790840,5282304,6478336,0 162 | 1.3.5,2587056,3505600,3146440,3990376,4513615,2167120,3889560,5302272,6630400,0 163 | 1.3.6,2587192,3514312,3163040,4023480,4530569,2177882,3918752,5700096,7033856,0 164 | 1.3.7,2587208,3530152,3175056,4039976,4556679,2189135,3926368,5705216,7054336,0 165 | 1.4.0,2570952,3526080,3154592,4007192,4531531,2176479,3914112,5467648,6663680,0 166 | 1.4.1,2587416,3534440,3162928,4023720,4542916,2182191,3922496,5485568,6680064,0 167 | 1.4.2,2603848,3550880,3179352,4040152,4562341,2193278,3938912,5506560,6709760,0 168 | 1.4.3,2603984,3520336,3129468,4056672,4573881,2199084,3947232,5516288,6723584,0 169 | 1.4.4,2620448,3536264,3144340,3565296,4602216,2213157,3959776,5563392,6782464,0 170 | 1.4.5,2604248,3521984,3127068,3565320,4588181,2204783,3945440,5540352,6760448,0 171 | 1.4.6,2620720,3533600,3142524,3581792,4615856,2215713,3953600,5554688,6774784,0 172 | 1.4.7,2620736,3554528,3170044,3581808,4621966,2219383,3959360,5560832,6781440,3195208 173 | 1.4.8,2637368,3579624,3195652,3598496,4663546,2238056,3981568,5588480,6820864,3211688 174 | 1.5.0,2670192,3610568,3227628,3631456,4714611,2261946,4014464,5641216,6891520,3244968 175 | 1.6.0,2637464,3579800,3196772,3615536,4738984,2251218,3986176,5606400,6861824,3245416 176 | 1.6.1,2653904,3585600,3204132,3616040,4713017,2253176,3990688,5622272,6876160,3245928 177 | 1.6.2,2653912,3592608,3209772,3632488,4714458,2253654,3998944,5708800,7001088,3245976 178 | 1.6.3,2653992,3598360,3217076,3632592,4733592,2261293,4009024,5725696,7024128,3262568 179 | 1.6.4,2687376,3644880,3281540,3682280,4810218,2300750,4055712,5785600,7108608,3296184 180 | 1.7.0,2703800,3660120,3301492,3698792,4842740,2316340,4076432,5815296,7149568,3312808 181 | 1.8.0,2720216,3693496,3334396,3680920,4959985,2332458,4105808,5848064,7191040,3296616 182 | 1.8.1,2736656,3702408,3342892,3680976,4974831,2339221,4110000,5857280,7203840,3296664 183 | 1.9.0,2769904,3732904,3371972,3828688,4999074,2351713,4135008,5880320,7234560,3457912 184 | 1.9.1,2770248,3742768,3379924,3836552,5011281,2357939,4148352,5888000,7245312,3474120 185 | 1.9.2,2852704,3762072,3403204,3833248,5033064,2371299,4169040,6092800,7476224,3474696 186 | 1.9.3,2852736,3764568,3406692,3833280,5039346,2374239,4173144,6093824,7476736,3474744 187 | 1.9.4,2886280,3814912,3455588,3887336,5020648,2399700,4219736,6159360,7556608,3508584 188 | 1.9.5,2886416,3816832,3457772,3891432,5023084,2400982,4219832,6160384,7559680,3508584 189 | 1.9.6,2886600,3819952,3460888,3887520,5036492,2408422,4236360,6171136,7565312,3508760 190 | 1.9.7,2785520,3841824,3483256,3871008,5062847,2421742,4779512,6206976,7614464,3389800 191 | 1.9.8,2802072,3858256,3498536,3887496,5098038,2437616,4796448,6228480,7645184,3406408 192 | 1.10.0,2818464,3875480,3528840,8054200,5118085,2447038,4820344,6256640,7703040,7150616 193 | 1.10.1,2884008,3942344,3597128,8127936,5210254,2515889,4898168,6348800,7793664,7216664 194 | 1.10.2,2900496,3970736,3632600,8156760,5235836,2529364,4935096,6372864,7826432,7233352 195 | 1.10.3,2900496,3972608,3634756,8160872,5238851,2530740,4935064,6373888,7828480,7233352 196 | 1.10.4,2884208,3980152,3604580,8173400,5226192,2528224,4951992,6375936,7769600,7233576 197 | 1.11.0,2884376,3980328,3604052,8169280,5220798,2525713,4947928,6372864,7768576,7233576 198 | 1.11.1,2900864,4002776,3632140,8185824,5243653,2536605,4961408,6396416,7802368,7250216 199 | 1.11.2,2917472,4009176,3639596,8189976,5249004,2539758,4973760,6404608,7811072,7266744 200 | -------------------------------------------------------------------------------- /legacy_engine_report.csv: -------------------------------------------------------------------------------- 1 | VERSION,arm64-darwin,armv7-android,armv7-darwin,darwin,js-web,wasm-web,linux,win32,x86_64-darwin,x86_64-linux,armv7-android,arm64-android 2 | 1.2.38,0,8264241,3627640,6230456,0,0,11582686,4840448,0,0,8264015,0 3 | 1.2.39,0,8395828,3687012,6336376,0,0,11871119,4893184,0,0,8395541,0 4 | 1.2.40,0,8400795,3690676,6346424,0,0,11884882,4897792,0,0,8400751,0 5 | 1.2.41,0,8465000,2890588,5630788,4741940,0,11195843,3952128,0,0,8464966,0 6 | 1.2.42,0,8467106,2891588,5635364,4779111,0,11203845,3951616,0,0,8467410,0 7 | 1.2.43,0,8637793,3000732,5781920,4976103,0,11366192,4042240,0,0,8638017,0 8 | 1.2.44,0,8637572,2998712,5780228,4975658,0,11362816,4037632,0,0,8637927,0 9 | 1.2.45,0,8647159,2998176,5790668,4978854,0,11390842,4042240,0,0,8647210,0 10 | 1.2.46,0,8580419,3164812,6035624,5042747,0,11516745,4151296,0,0,8579926,0 11 | 1.2.47,0,8581891,3166324,6041800,5044154,0,11523823,4151296,0,0,8581596,0 12 | 1.2.48,0,8620182,3173824,6095256,5077204,0,11628180,4183552,0,0,8619978,0 13 | 1.2.49,0,8705847,3286272,6218856,5073830,0,11784794,4177408,0,0,8706017,0 14 | 1.2.50,0,8847534,3464332,6218856,5074316,0,11788910,4177408,0,0,8847775,0 15 | 1.2.51,0,8885113,3491320,6253816,5110949,0,11879990,4200448,0,0,8884235,0 16 | 1.2.52,3841456,8890685,3494840,6261312,5115637,0,12184720,4201984,6452612,0,8890381,0 17 | 1.2.53,3842288,8917579,3495612,6281520,5137497,0,12226299,4209152,6469504,0,8916816,0 18 | 1.2.54,3844568,8924202,3497760,6283140,5138083,0,12230071,4214784,6475352,0,8923985,0 19 | 1.2.55,3849224,8932722,3501912,6282488,5118105,0,12250954,4214272,6471320,11785005,8932629,0 20 | 1.2.56,3867776,8938057,3503924,6289900,5129502,0,12268525,4219392,6479032,11805794,8937821,0 21 | 1.2.57,3897756,8998738,3535308,6360972,5169628,0,12393316,4246528,6557896,11932379,8998832,0 22 | 1.2.58,3928360,9058886,3565488,6410228,5209732,0,12499062,4269568,6608756,12031327,9059206,0 23 | 1.2.59,4034432,9129205,3688080,6529668,5527032,0,12632164,4406272,6728052,12160822,9128484,0 24 | 1.2.60,4053024,9142560,3690104,6530096,5526576,0,12636699,4412928,6733108,12165813,9142434,0 25 | 1.2.61,4051060,9147694,3688236,6532644,5528104,0,12633412,4408320,6730972,12166626,9147412,0 26 | 1.2.62,4053680,9150329,3707088,6535344,5530786,0,12643742,4415488,6737980,12172756,9150136,0 27 | 1.2.63,4092028,9180199,3727760,6535404,5536078,0,12645909,4418048,6739636,12174819,9180218,0 28 | 1.2.64,4122160,9270507,3756812,6578668,5577412,0,12753141,4437504,6780140,12279783,9270068,0 29 | 1.2.65,4137856,9276824,3756124,6585284,5583056,0,12762576,4435456,6788180,12294166,9276274,0 30 | 1.2.66,4156932,9313255,3774868,6609984,5651367,0,12794119,4460544,6810244,12323909,9313322,0 31 | 1.2.67,4156480,9315969,3774432,6610916,5651899,0,12795122,4461056,6815484,12325060,9315813,0 32 | 1.2.68,4160616,9318556,3778260,6614384,5651421,0,12803250,4468736,6819244,12337050,9318389,0 33 | 1.2.69,4146736,9312675,3747756,6588832,5556383,0,12772158,4428288,6789532,12306166,9312474,0 34 | 1.2.70,4149788,9441884,3766960,6591108,5557593,0,12782657,4434432,6795908,12312345,9442058,0 35 | 1.2.71,4160448,9444279,3785552,6567752,5563290,0,12783939,4438016,6736636,12317231,9443719,0 36 | 1.2.72,4150304,9455437,3775408,6557924,5567357,0,12777577,4435456,6726852,12308361,9455715,0 37 | 1.2.73,4161808,9469804,3785880,6570684,5577915,0,12792437,4440064,6740068,12322653,9469938,0 38 | 1.2.74,4161808,9469576,3785884,6570688,5578110,0,12792523,4440576,6741396,12322741,9469640,0 39 | 1.2.75,4186156,9578605,3809408,6579260,4981475,0,12812620,4450816,6750572,12345274,9578825,0 40 | 1.2.76,4120872,9551356,3744200,6573372,4836182,0,12723664,4389376,6754676,12240828,9551638,0 41 | 1.2.77,4122632,9551040,3745864,6574968,4836372,0,12726544,4394496,6756204,12243716,9551307,0 42 | 1.2.78,4123492,9556710,3746624,6580648,4841157,0,12730616,4398592,6762084,12253844,9556645,0 43 | 1.2.79,4123564,9560673,3746712,6576552,4845826,0,12731148,4399616,6762084,12254356,9560115,0 44 | 1.2.80,4123728,9563363,3746872,6581104,4851276,0,12736204,4418560,6764988,12259524,9563547,0 45 | 1.2.81,4306816,9937734,3922872,6961724,5136790,0,13100283,4715520,7173092,13024402,9937481,0 46 | 1.2.82,4323188,9936706,3922772,4964644,15227607,0,16605019,4140032,4889732,23237567,9936361,0 47 | 1.2.83,4324808,9979804,3924256,4975052,5202393,0,16697699,4147712,4904044,23337019,9979863,0 48 | 1.2.84,4369616,10035897,3951616,4980708,5212214,0,16705681,4150272,4905996,23346226,10035388,0 49 | 1.2.85,4370316,10037544,3952260,4980704,5215095,0,16705597,4151296,4910124,23345986,10037178,0 50 | 1.2.86,4373936,10056013,3955548,4979096,5215795,0,16703440,4151296,4913836,23337284,10056312,0 51 | 1.2.87,4332136,10061048,3954512,4977416,5222295,0,16723270,4155904,4944912,23353441,10060735,0 52 | 1.2.88,4343184,10125698,3981556,4997676,5238402,0,16877552,4165120,4966264,23492800,10125489,0 53 | 1.2.89,4368064,10185665,3989476,5018688,5267245,0,17015361,4180992,4996408,23633113,10186110,0 54 | 1.2.90,4369344,10191207,3990568,5019124,5269728,0,17021160,4184576,4997524,23640327,10190560,0 55 | 1.2.91,4369476,10192646,4007076,5020372,5269955,0,17022230,4185600,5001804,23642565,10192020,0 56 | 1.2.92,4419512,10261027,4023224,5055288,5321548,0,17177572,4207104,5030108,23807084,10260779,0 57 | 1.2.93,4424412,10274248,4044068,5068268,5336737,0,17217462,4216832,5043660,23865522,10273738,0 58 | 1.2.94,4448576,10371218,4051664,5099452,5366001,0,17476304,4239872,5075668,24206229,10371026,0 59 | 1.2.95,4448576,10371215,4051664,5098828,5366006,0,17476304,4239872,5077364,24206229,10371041,0 60 | 1.2.96,4448576,10371230,4051672,5099880,5365603,0,17481550,4658176,5075996,24206223,10371020,0 61 | 1.2.97,4510716,10500039,4112428,5174380,5436716,0,17755701,4699648,5164308,24533402,10500031,0 62 | 1.2.98,4511032,10502025,4112724,5175772,5438159,0,17761616,4700672,5163844,24541721,10501600,0 63 | 1.2.99,4544112,10532027,4145784,5208664,5532180,0,17794476,4733952,5197956,24580405,10531884,0 64 | 1.2.100,4564716,10550800,4149504,5220412,5556516,0,17838351,4746752,5204832,24631698,10550346,0 65 | 1.2.101,4565888,10556431,4150608,5225628,5559629,0,17844978,4749312,5207520,24645313,10556525,0 66 | 1.2.102,4569968,10550295,4170828,5232276,5565303,0,17840169,4741120,5224756,24655149,10550272,0 67 | 1.2.103,4570044,10556063,4170868,5238296,5567155,0,17856543,4742144,5223084,24675811,10556067,0 68 | 1.2.104,4569040,10552320,4169432,5237248,5563691,0,17830010,4743168,5226140,24618246,10552194,0 69 | 1.2.105,4573120,10565873,4173112,5245032,5571977,0,17861003,4747264,5233228,24655184,10565445,0 70 | 1.2.106,4573076,10573081,4172964,5248228,5572487,0,17877036,4751872,5236948,24682698,10572848,0 71 | 1.2.107,4596800,10602255,4180028,5267740,5587197,0,17949257,4764672,5261332,24768311,10602047,0 72 | 1.2.108,4586104,10606615,4217116,5168172,5589043,0,17953597,4766720,5241968,24774857,10605946,0 73 | 1.2.109,4593516,10643796,4240648,5192728,5621526,0,18048218,4785664,5267152,24909393,10643797,0 74 | 1.2.110,4593668,10641698,4240744,5192344,5618984,0,18026881,4784640,5270856,24907237,10641895,0 75 | 1.2.111,4593656,10641304,4240772,5196648,5620874,0,18026968,4783616,5271040,24903632,10640967,0 76 | 1.2.112,4594344,10645267,4241376,5197264,5624559,0,18024993,4785664,5271744,24920076,10645001,0 77 | 1.2.113,4594348,10653588,4257764,5205460,5655014,0,18033262,4795392,5279936,24927970,10653214,0 78 | 1.2.114,4594536,10656129,4257936,5206092,5655991,0,19373644,4850176,5284744,24936543,10655417,0 79 | 1.2.115,4639340,10713063,4269040,5238044,5734014,0,19432188,5090304,5643964,24758200,10712330,0 80 | 1.2.116,4639764,10717082,4269420,5238584,5737247,0,19440944,5091328,5644564,24762280,10716746,0 81 | 1.2.117,4397832,10436689,4012464,4985404,5016012,0,18958508,4809216,5389228,24203792,10721035,0 82 | 1.2.118,4400056,10446556,4014540,4991816,5022263,0,18979516,4813312,5391788,24229184,10730716,0 83 | 1.2.119,4407468,10451192,4021220,4998004,5039179,0,19013148,4823552,5406820,24273768,10734190,0 84 | 1.2.120,4431516,10481003,4061388,5032676,5100417,0,19041372,4862464,5447872,24345856,10754899,0 85 | 1.2.121,4431696,10480499,4061536,5030548,5090477,0,19056208,4859392,5444056,24349448,10754481,0 86 | 1.2.122,4431828,10481112,4061648,5030656,5091861,0,19058300,4860416,5444232,24353784,10756223,0 87 | 1.2.123,4414964,10486302,4061636,5067396,5092579,0,19065300,4860928,5439536,24360272,10759587,0 88 | 1.2.124,4415324,10490976,4061952,5072000,5095949,0,19068528,4861952,5440104,24363304,10764889,0 89 | 1.2.125,4411860,10491277,4060260,5072492,5096742,0,19070004,4862464,5436752,24364456,10766327,0 90 | 1.2.126,4419880,10503991,4068712,5090848,5099803,0,19117476,4866048,5456224,24413928,10778423,0 91 | 1.2.127,4374464,10494029,4037964,5053432,4969919,0,19065428,4818432,5415176,24350904,10824655,0 92 | 1.2.128,4396052,10504754,4040536,5064460,4977067,0,19087296,4825600,5421416,24378184,10836056,0 93 | 1.2.129,4398216,10850193,4044760,5071856,4983368,0,19115904,4831232,5433344,24412288,11186862,0 94 | 1.2.130,4401840,10876136,4049572,5085572,5000582,0,19169428,4839424,5447528,24485440,11212621,0 95 | 1.2.131,4402040,10878544,4049772,5086084,5002172,0,19176952,4840448,5452576,24489560,11215151,0 96 | 1.2.132,4250288,10770595,3852308,4833976,5002214,0,19213216,4840448,5194284,24615064,11109362,0 97 | 1.2.133,4222880,10766669,3810240,4794576,4988784,0,19191700,4848640,5158364,24597992,11105602,0 98 | 1.2.134,4187956,10210631,3827880,4794544,5135612,0,15138400,4786176,5109648,19131024,10547381,0 99 | 1.2.135,4187960,10215667,3827884,4797008,5138227,0,15147084,4786688,5113776,19136136,10550772,0 100 | 1.2.136,4217168,13716416,3871116,4783984,5129445,0,15135676,4783616,5095584,19117640,14052664,0 101 | 1.2.137,4217364,13719736,3871292,0,5133516,0,15140916,4785664,5095784,19123520,14056092,0 102 | 1.2.138,4235380,13725998,3873052,0,5152452,0,15161028,4794368,5106496,19149872,14063179,0 103 | 1.2.139,4157072,13588745,3812324,0,4509371,0,14848700,4725248,4999968,18769144,13928279,0 104 | 1.2.140,4157072,13589280,3812324,0,4509531,0,14849036,4725248,4999968,18769192,13928615,0 105 | 1.2.141,4155152,13579954,3810604,0,4511122,2044857,14880796,4726272,5004800,18809608,13919339,0 106 | 1.2.142,4155368,13569629,3811940,0,4508009,2072237,14853048,4725248,5010888,18776440,13909316,0 107 | 1.2.143,4157916,13573817,3813152,0,4510650,2074281,14856236,4725760,5012192,18780008,13912154,0 108 | 1.2.144,4174688,13798679,3813524,0,4522266,2080727,14867268,4732928,5016920,18792704,14190754,0 109 | 1.2.145,4192936,13828119,3831752,0,4548196,2095589,15281952,4988416,5732288,19361072,14217724,0 110 | 1.2.146,4236432,13842874,3874212,0,4568598,2112308,0,5029888,5789064,19522600,14234333,0 111 | 1.2.147,4280980,13863720,3889584,0,4586079,2121248,0,5036032,5836320,19565120,14260217,0 112 | 1.2.148,4315968,13850133,3923184,0,4456904,2111782,0,5042688,5872208,19502504,14322310,0 113 | 1.2.149,2714136,13949944,2491860,0,4473530,2119371,0,5052928,4303952,4408704,14422910,0 114 | 1.2.150,2714152,13961401,2491828,0,4472686,2118739,0,5052928,4304112,4412960,14432644,0 115 | 1.2.151,2714192,13965207,2491988,0,4483955,2125447,0,5057536,4308216,4413120,14436789,0 116 | 1.2.152,2963576,13974807,2508684,0,4484085,2125524,0,5105152,4362392,4736976,14447417,0 117 | 1.2.153,2998188,0,2543268,0,4484884,2126105,0,5166592,4418196,4802664,14503494,15336225 118 | 1.2.154,2998196,0,2543276,0,4484884,2126105,0,5167104,4418204,4802664,14503442,15234145 119 | 1.2.155,2484160,0,2126644,0,4454545,2109217,0,5142528,4418220,4802664,4488935,4711873 120 | 1.2.156,2517304,0,2159980,0,4577972,2160399,0,5151232,4434700,4814952,4493928,4719570 121 | 1.2.157,2533704,0,2160008,0,4586788,2163321,0,5153792,4439512,4819176,4495473,4721146 122 | 1.2.158,2533704,0,2160008,0,4587229,2163538,0,5153792,4439512,4819176,4495731,4721442 123 | 1.2.159,2550088,0,2160008,0,4587071,2163497,0,5175296,4451800,4835944,4495880,4721556 124 | 1.2.160,2533052,0,2159368,0,4588789,2163959,0,5149696,4451768,4840040,4153781,4378796 125 | 1.2.161,2533076,0,2159392,0,4589473,2165223,0,5157376,4455896,4844168,4191436,4284660 126 | 1.2.162,2648756,0,2258708,0,4810892,2285557,0,5334528,4633400,5021096,2000178,2101232 127 | 1.2.163,2631060,0,2241060,0,4807563,2274866,0,5341696,4629368,5015624,1923140,2022404 128 | 1.2.164,2631060,0,2241060,0,4807563,2274866,0,5341696,4629368,5015624,1923140,2022404 129 | 1.2.165,2700120,0,2306292,0,4821690,2279469,0,5369856,4878836,5019624,1929653,2027408 130 | 1.2.166,2700168,0,2306448,0,4835755,2286395,0,5381632,4891172,5167560,1934481,2032164 131 | 1.2.167,2700184,0,2306460,0,4836406,2287127,0,5382144,4891188,5171848,1934445,2032042 132 | 1.2.168,2700184,0,2306460,0,4837918,2287888,0,5383168,4891188,5171848,1935121,2032654 133 | 1.2.169,2733488,0,2340612,0,4936683,2340041,0,5398528,4940932,5222440,1951089,2047758 134 | 1.2.170,2689520,0,2250124,0,7765741,2105327,0,5713920,4855172,5124024,1917094,2000034 135 | 1.2.171,2620424,0,2168528,0,7764627,2104537,0,5713920,4842860,4895960,1917584,1999970 136 | 1.2.172,2620432,0,2168532,0,7776508,2106805,0,5717504,4842868,4895928,1918382,2001135 137 | 1.2.173,2586136,0,2134168,0,7800581,2114245,0,5089280,3963408,3871648,1888174,1970273 138 | 1.2.174,2586132,0,2134184,0,7800441,2114250,0,5089280,3987904,3871648,1888305,1970653 139 | 1.2.175,2635492,0,2167180,0,7940338,2155920,0,5184512,4086760,3953824,1936409,2015817 140 | 1.2.176,2635492,0,2183572,0,7950699,2158372,0,5186560,4086752,3957920,1938829,2017040 141 | 1.2.177,2635492,0,2183572,0,7951095,2158464,0,5187072,4086752,3957920,1939007,2016975 142 | 1.2.178,2635492,0,2183572,0,7951095,2158464,0,5187072,4086752,3957920,1939007,2016975 143 | 1.2.179,2635532,0,2183688,0,4499044,2159059,0,5194240,4086840,3966112,1946796,2024053 144 | 1.2.180,2553404,0,2084712,0,4523023,2184641,0,5094400,3939384,3839616,2026223,2092974 145 | 1.2.181,2553460,0,2101088,0,20958953,3117419,0,5105664,3939504,3851904,2029827,2096437 146 | 1.2.182,2520080,0,2067780,0,4538185,2192835,0,5040128,3889832,3798632,2003631,2070426 147 | 1.2.183,2536296,0,2067620,0,4531672,2182293,0,5034496,3906144,3802720,2008956,2073433 148 | 1.2.184,2536312,0,2067484,0,4533137,2182616,0,5033472,3889784,3803072,2009458,2074156 149 | 1.2.185,2553000,0,2084184,0,4535548,2183817,0,5097472,3923176,3823616,2029228,2087818 150 | 1.2.186,2553000,0,2084188,0,4539647,2186237,0,5100032,3923184,3827744,2030585,2089356 151 | 1.2.187,2553000,0,2084196,0,4540474,2186724,0,5100544,3923184,3827744,2030768,2089775 152 | 1.2.188,2536536,0,2067692,0,4495274,2164996,0,5072384,3890248,3799264,2020282,2079668 153 | 1.2.189,2536952,0,2084520,0,4505080,2170497,0,5086208,3906808,3811936,2023388,2083257 154 | -------------------------------------------------------------------------------- /size-analyzer/README.md: -------------------------------------------------------------------------------- 1 | # Defold Size Analyzer 2 | 3 | A comprehensive tool for analyzing and comparing Defold component sizes across versions. The analyzer supports both native engine binaries and Java tooling (bob.jar) analysis with interactive visualizations and dashboard overview. 4 | 5 | ## Overview 6 | 7 | The Defold Size Analyzer consists of three main components: 8 | 1. **Data Collection Pipeline** - Automated analysis and CSV generation 9 | 2. **Dashboard** - High-level overview with size evolution charts 10 | 3. **Size Analyzer** - Detailed comparison and analysis tools 11 | 12 | --- 13 | 14 | ## Data Collection Pipeline 15 | 16 | ### 1. Analysis Script (`analyze_builds.py`) 17 | 18 | The Python script automates the download and analysis of Defold components across versions. 19 | 20 | #### Supported Platforms: 21 | - **Native Binaries**: `arm64-android`, `armv7-android`, `arm64-ios`, `x86_64-macos`, `arm64-macos` (libdmengine_release.so) 22 | - **Java Tooling**: `bob.jar` (editor/build tools) 23 | - **Editor Applications**: `editor-win32`, `editor-x86_64-linux`, `editor-x86_64-macos`, `editor-arm64-macos` (complete editor packages) 24 | 25 | #### Data Sources: 26 | - Downloads components from Defold's archive: `http://d.defold.com/archive/{sha1}/` 27 | - Uses `releases.json` to determine available versions and SHA1 hashes 28 | - Processes versions from 1.9.0 onwards 29 | 30 | #### Analysis Methods: 31 | 32 | **Native Binary Analysis (using Bloaty)** 33 | ```bash 34 | bloaty -d compileunits --demangle=full -n 0 binary.so --csv 35 | ``` 36 | - **Tool**: [Google Bloaty](https://github.com/google/bloaty) - Binary size analysis tool 37 | - **Documentation**: [Bloaty Usage Guide](https://github.com/google/bloaty/blob/main/doc/using.md) 38 | - **Output**: `compileunits,vmsize,filesize` 39 | - **vmsize**: Virtual memory size (loaded into memory) 40 | - **filesize**: File size on disk 41 | - **compileunits**: Source file/compilation unit names 42 | 43 | **JAR Analysis (using Python zipfile)** 44 | ```python 45 | with zipfile.ZipFile(jar_path, 'r') as zf: 46 | for info in zf.infolist(): 47 | # Extract: filename, compressed_size, uncompressed_size 48 | ``` 49 | - **Output**: `filename,compressed,uncompressed` 50 | - **compressed**: Size of entry in JAR (compressed) 51 | - **uncompressed**: Original size of entry 52 | - **filename**: Path within JAR file 53 | 54 | **Editor Analysis (Combined Approach)** 55 | ```python 56 | # Combines JAR analysis, JDK grouping, and file analysis 57 | # - JAR contents analyzed individually with compression ratios 58 | # - JDK folder grouped as single "JDK" entity 59 | # - Other files analyzed individually (compressed == uncompressed) 60 | # - Library grouping applied to reduce complexity 61 | ``` 62 | - **Output**: `filename,compressed,uncompressed` 63 | - **compressed**: Compressed size (for JARs) or file size (for other files) 64 | - **uncompressed**: Uncompressed size (for JARs) or file size (for other files) 65 | - **filename**: File path or grouped library name (e.g., `com/ibm/*.*`, `JDK`) 66 | 67 | #### Generated Files: 68 | ``` 69 | size-analyzer/ 70 | ├── analysis_index.json # Platform and version metadata 71 | ├── arm64-android/ # Native binary analysis 72 | │ ├── 1.9.0.csv 73 | │ ├── 1.9.1.csv 74 | │ └── ... 75 | ├── bob.jar/ # Java tooling analysis 76 | │ ├── 1.9.0.csv 77 | │ ├── 1.9.1.csv 78 | │ └── ... 79 | └── editor-*/ # Editor analysis (all platforms) 80 | ├── 1.10.3.csv 81 | ├── 1.10.4.csv 82 | └── ... 83 | ``` 84 | 85 | #### Running Analysis: 86 | ```bash 87 | # Full analysis (all platforms, all versions) 88 | python3 analyze_builds.py 89 | 90 | # Test mode (single platform, latest version only) 91 | python3 analyze_builds.py --test editor # Test editor analysis 92 | python3 analyze_builds.py --test bob # Test bob.jar analysis 93 | python3 analyze_builds.py --test ios # Test iOS engine analysis 94 | ``` 95 | 96 | The script will: 97 | 1. Read `releases.json` for version information 98 | 2. Download and analyze each component for each version 99 | 3. Generate CSV files with size data 100 | 4. Apply library grouping for editor analysis (reduces ~76,000 entries to ~5,500) 101 | 5. Update `analysis_index.json` with available platforms/versions 102 | 6. Clean up temporary downloaded files 103 | 104 | --- 105 | 106 | ## Dashboard 107 | 108 | ### 1. Overview Charts 109 | 110 | The dashboard provides a high-level view of component size evolution across versions: 111 | 112 | **Features:** 113 | - **Bundle Size Chart**: Game bundle sizes across all supported platforms 114 | - **Engine Size Chart**: Engine binary sizes across platforms 115 | - **Editor Size Chart**: Editor application sizes (desktop platforms) 116 | - **Bob.jar Size Chart**: Build tool size evolution (macOS only) 117 | 118 | **Interactive Elements:** 119 | - **Version Dropdowns**: Select starting version for each chart 120 | - **Legend Controls**: 121 | - Click legend items to toggle platforms on/off 122 | - Alt+click legend items to isolate single platform 123 | - **Chart Navigation**: Click any data point to open detailed analysis 124 | 125 | ### 2. Cross-Navigation 126 | 127 | **Dashboard → Size Analyzer Integration:** 128 | - Click any dot on dashboard charts to open size-analyzer 129 | - Automatically selects the correct platform 130 | - Pre-fills "from" version (previous) and "to" version (clicked) 131 | - Opens in new tab for seamless workflow 132 | 133 | **Supported Platforms:** 134 | - `arm64-ios`, `arm64-android`, `armv7-android` 135 | - `x86_64-macos`, `x86_64-linux`, `x86-win32`, `x86_64-win32`, `arm64-macos` 136 | - `js-web`, `wasm-web` 137 | - `bob.jar` (special handling for build tools) 138 | - `editor-*` platforms (automatic mapping from dashboard to size-analyzer) 139 | 140 | **Files:** 141 | - `index.html` - Dashboard interface 142 | - `js/dashboard.js` - Chart rendering and interaction logic 143 | - `css/dashboard.css` - Dashboard-specific styling 144 | 145 | --- 146 | 147 | ## Size Analyzer (Detailed View) 148 | 149 | ### 1. Architecture 150 | 151 | The viewer is a client-side web application with no server dependencies: 152 | 153 | **Technologies:** 154 | - **Vanilla JavaScript** - No frameworks, pure ES6+ 155 | - **Plotly.js** - Interactive chart rendering 156 | - **CSS3** - Modern responsive styling 157 | - **Fetch API** - CSV data loading 158 | 159 | **Files:** 160 | - `index.html` - Main application interface 161 | - `js/app.js` - Main application logic and state management 162 | - `js/csv-parser.js` - CSV loading and data processing 163 | - `js/plotly-histogram.js` - Chart rendering and interactions 164 | - `css/style.css` - Visual styling and responsive design 165 | 166 | ### 2. Data-Driven Design 167 | 168 | #### Dynamic Platform Detection: 169 | The viewer automatically adapts to any CSV structure by reading headers: 170 | 171 | **arm64-android format:** 172 | ```csv 173 | compileunits,vmsize,filesize 174 | src/dlib/array.cpp,2048,4096 175 | ``` 176 | 177 | **bob.jar format:** 178 | ```csv 179 | filename,compressed,uncompressed 180 | lib/android.jar,10299057,13989417 181 | ``` 182 | 183 | **editor format (with library grouping):** 184 | ```csv 185 | filename,compressed,uncompressed 186 | jfxwebkit.dll,31852784,83512832 187 | JDK,58083658,58083658 188 | com/ibm/*.*,11528031,27028277 189 | com/sun/*.*,8886096,21765809 190 | clojure/*.*,6990823,15500531 191 | ``` 192 | 193 | #### Tab Generation: 194 | Tabs are automatically created based on available metrics: 195 | - **Native Binary**: "File Size" and "VM Size" tabs 196 | - **JAR Files**: "Compressed" and "Uncompressed" tabs 197 | - **Future Formats**: Automatically supported by reading CSV headers 198 | 199 | ### 3. Core Features 200 | 201 | #### Version Selection Logic: 202 | - **Baseline Dropdown**: All versions except the latest (prevents impossible comparisons) 203 | - **Compare Dropdown**: Only versions newer than selected baseline 204 | - **Smart Defaults**: Automatically selects (latest-1) vs (latest) on load 205 | - **Preservation**: Maintains selections when switching platforms if versions exist 206 | 207 | #### Interactive Visualization: 208 | - **Horizontal Bar Charts**: Files sorted by change magnitude 209 | - **Color Coding**: Red (increased), Green (decreased) with metric-specific colors 210 | - **Threshold Filtering**: Dynamic range based on actual data 211 | - **Timeline Modal**: Click any bar to see version-by-version evolution 212 | - **Pan Navigation**: Charts support panning but prevent zoom in/out for consistent scale 213 | - **External Titles**: Chart titles displayed outside Plotly area for better mobile experience 214 | - **Enhanced Hover Areas**: Full-row hover detection with subtle gray overlays for easier interaction 215 | - **Cursor-Following Tooltips**: Tooltips positioned near cursor with Plotly-style yellow background 216 | - **File Name Tooltips**: Hover over long file names (chart y-axis or table) to see full paths 217 | 218 | #### Data Processing Pipeline: 219 | ```javascript 220 | 1. CSV Loading → CSVParser.loadCSV() 221 | 2. Header Detection → getMetricsFromHeaders() 222 | 3. Tab Creation → createDynamicTabs() 223 | 4. Data Processing → processDataByMetric() 224 | 5. Visualization → PlotlyHistogramChart.render() 225 | ``` 226 | 227 | ### 4. Advanced Features 228 | 229 | #### Debug Section Filtering (Android): 230 | - Automatically detects Android platforms 231 | - Shows checkbox to hide debug-only sections 232 | - Filters sections like `.debug_str`, `.symtab`, etc. 233 | - Includes informational modal explaining debug sections 234 | 235 | #### Platform-Specific Adaptations: 236 | - **File Path Normalization**: Handles `../src/` vs `src/` inconsistencies 237 | - **Dynamic Filename Columns**: `compileunits` vs `filename` 238 | - **Metric-Specific Colors**: Different colors for different metrics 239 | - **Timeline Data**: Adapts to platform-specific CSV formats 240 | 241 | #### Performance Optimizations: 242 | - **CSV Caching**: Prevents redundant network requests 243 | - **Lazy Loading**: Only loads data when needed 244 | - **Efficient Filtering**: Client-side processing with smart algorithms 245 | - **Responsive UI**: Smooth interactions even with large datasets 246 | - **Chart Optimization**: Fixed axis ranges prevent expensive zoom calculations 247 | - **Mobile Performance**: Reduced chart complexity and disabled zoom for better touch performance 248 | 249 | ### 5. User Interface 250 | 251 | #### Main Interface: 252 | 1. **Platform Selection**: Choose between arm64-android, bob.jar, etc. 253 | 2. **Version Selection**: Smart dropdowns with validation 254 | 3. **Metric Tabs**: Dynamic tabs based on available data 255 | 4. **Threshold Control**: Filter by change magnitude 256 | 5. **Chart Info**: Dynamic title showing comparison details above chart 257 | 6. **Chart Visualization**: Interactive horizontal bar chart with pan-only navigation 258 | 7. **Data Table**: Detailed file list with filtering options 259 | 260 | #### Timeline Modal: 261 | - **Triggered**: Click any bar in the main chart 262 | - **Content**: Line chart showing file evolution across all intermediate versions 263 | - **Data**: Cumulative view from baseline to compare version 264 | - **Interaction**: Hover for details, responsive design 265 | 266 | #### URL Parameter Support: 267 | - **Cross-navigation**: Supports platform, from, and to version parameters 268 | - **Deep linking**: `size-analyzer/?platform=arm64-android&from=1.10.3&to=1.10.4` 269 | - **Dashboard integration**: Automatically applied when navigating from dashboard 270 | 271 | #### Responsive Design: 272 | - **Desktop**: Full-featured interface with side-by-side layouts and standard chart margins 273 | - **Tablet**: Stacked layouts with touch-friendly controls and adjusted chart spacing 274 | - **Mobile**: Simplified interface with collapsible sections and mobile-optimized chart layouts 275 | - **Dynamic Layout**: Charts automatically adjust margins and title positioning based on screen width 276 | - **Touch-Friendly**: Disabled zoom gestures to prevent accidental UI disruption on mobile devices 277 | 278 | --- 279 | 280 | ## Recent Improvements 281 | 282 | ### Editor Analysis Integration (v20): 283 | - **Complete Editor Analysis**: Added support for analyzing Defold editor packages across all platforms 284 | - **Combined Analysis Approach**: JAR contents + individual files + JDK grouping in unified CSV format 285 | - **Intelligent Library Grouping**: Reduced editor analysis from ~76,000 entries to ~5,500 (92% reduction) 286 | - **Test Mode**: Added `--test` flag for quick single-platform validation during development 287 | - **Dashboard Integration**: Automatic platform name mapping from dashboard to size-analyzer URLs 288 | 289 | ### Enhanced User Experience (v20): 290 | - **Full-Row Hover Detection**: Click/hover anywhere across chart rows, not just thin bars 291 | - **Cursor-Following Tooltips**: Tooltips now position near cursor instead of fixed right-side placement 292 | - **File Name Tooltips**: Hover over truncated file names (y-axis labels and table) to see complete paths 293 | - **Smart Tooltip Styling**: Maintained Plotly-style yellow background with dynamic width adaptation 294 | - **Subtle Visual Cues**: Light gray overlay bars indicate hoverable areas without interfering with data 295 | 296 | ### Mobile & Touch Optimization (v19): 297 | - **Responsive Chart Titles**: Moved chart titles outside Plotly area to prevent mobile overlap with modebar 298 | - **Zoom Restrictions**: Disabled zoom in/out to maintain consistent scale and prevent accidental gestures 299 | - **Touch Navigation**: Enabled pan-only interaction for better mobile experience 300 | - **Dynamic Margins**: Charts automatically adjust spacing based on screen width (≤768px detection) 301 | - **Simplified Controls**: Streamlined arrow labels ("← smaller" / "bigger →") for mobile readability 302 | 303 | ### Error Handling & Stability: 304 | - **Version Parsing**: Fixed `version.split is not a function` error in timeline modal 305 | - **Type Safety**: Added string conversion safeguards for version processing 306 | - **Data Validation**: Improved handling of analysis_index.json structure changes 307 | - **Cross-Platform URL Mapping**: Automatic conversion between dashboard platform keys and size-analyzer directories 308 | 309 | --- 310 | 311 | ## Usage Examples 312 | 313 | ### Dashboard Workflow: 314 | 1. Open dashboard (`index.html`) for overview of all components 315 | 2. Use version dropdowns to focus on specific time ranges 316 | 3. Use legend controls to filter platforms: 317 | - Click to toggle platform visibility 318 | - Alt+click to show only one platform 319 | 4. Click any data point to dive into detailed analysis 320 | 5. Size analyzer opens with pre-selected comparison 321 | 322 | ### Comparing Engine Sizes: 323 | 1. Select "arm64-android" platform (or navigate from dashboard) 324 | 2. Choose baseline version (e.g., 1.10.3) 325 | 3. Choose compare version (e.g., 1.10.4) 326 | 4. Switch between "File Size" and "VM Size" tabs 327 | 5. Adjust threshold to focus on significant changes 328 | 6. Click bars to see detailed timeline evolution 329 | 330 | ### Analyzing JAR Components: 331 | 1. Select "bob.jar" platform 332 | 2. Choose version range for comparison 333 | 3. Switch between "Compressed" and "Uncompressed" tabs 334 | 4. Identify which JAR entries contribute most to size changes 335 | 5. Use timeline view to understand growth patterns 336 | 337 | ### Analyzing Editor Components: 338 | 1. Select any "editor-*" platform (win32, linux, macos) 339 | 2. Choose version range for comparison (editor analysis starts from 1.10.3) 340 | 3. Switch between "Compressed" and "Uncompressed" tabs 341 | 4. Analyze grouped libraries (com/ibm/*.*, com/sun/*.*, etc.) and individual components 342 | 5. Compare JDK overhead vs application code vs bundled libraries 343 | 6. Use hover tooltips to see full component names for grouped entries 344 | 345 | ### Debug Analysis (Android): 346 | 1. Select arm64-android platform 347 | 2. Check "Hide debug sections" to focus on runtime code 348 | 3. Click info button to understand debug section types 349 | 4. Compare with/without debug sections to understand overhead 350 | 351 | --- 352 | 353 | ## Technical Details 354 | 355 | ### CSV Format Requirements: 356 | - **First column**: Must be filename/path (any name containing "filename" or "compileunits") 357 | - **Other columns**: Numeric size metrics (any names) 358 | - **Headers**: Used to generate tab names automatically 359 | - **Encoding**: UTF-8 with proper CSV escaping 360 | 361 | ### Browser Compatibility: 362 | - **Modern browsers**: Chrome 80+, Firefox 75+, Safari 13+, Edge 80+ 363 | - **Features used**: ES6 modules, Fetch API, CSS Grid, Flexbox, window.innerWidth detection 364 | - **Mobile browsers**: iOS Safari 13+, Android Chrome 80+, mobile-optimized interactions 365 | - **No IE support**: Uses modern JavaScript features and responsive design 366 | 367 | ### Performance Characteristics: 368 | - **Data loading**: ~100ms per CSV file (cached after first load) 369 | - **Processing**: <50ms for datasets up to 10,000 files 370 | - **Rendering**: <200ms for charts with 1,000+ bars 371 | - **Memory usage**: ~5MB for typical datasets 372 | 373 | ### Extensibility: 374 | The tool is designed to handle new platforms automatically: 375 | 1. Add CSV files in new platform directory 376 | 2. Update `analysis_index.json` with platform info 377 | 3. Add platform to dashboard CSV reports (bundle_report.csv, engine_report.csv, etc.) 378 | 4. Dashboard and size analyzer automatically detect and support new format 379 | 5. No code changes required for new metrics or platforms 380 | 381 | ### Cross-Navigation: 382 | **URL Parameter Flow:** 383 | ``` 384 | Dashboard Click → Generate URL → Open Size Analyzer → Parse Parameters → Apply Selection 385 | ``` 386 | 387 | **Data Flow:** 388 | ``` 389 | CSV Reports → Dashboard Charts → User Click → URL Generation → Size Analyzer → Detailed Analysis 390 | ``` 391 | 392 | **Supported URL Parameters:** 393 | - `platform`: Platform key (e.g., arm64-android, bob.jar) 394 | - `from`: Baseline version for comparison 395 | - `to`: Target version for comparison -------------------------------------------------------------------------------- /size-analyzer/css/style.css: -------------------------------------------------------------------------------- 1 | /* Reset and base styles */ 2 | * { 3 | margin: 0; 4 | padding: 0; 5 | box-sizing: border-box; 6 | } 7 | 8 | body { 9 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; 10 | line-height: 1.6; 11 | color: #333; 12 | background-color: #f5f5f5; 13 | } 14 | 15 | .container { 16 | max-width: 1400px; 17 | margin: 0 auto; 18 | padding: 20px; 19 | } 20 | 21 | /* Header */ 22 | header { 23 | text-align: center; 24 | margin-bottom: 30px; 25 | } 26 | 27 | header h1 { 28 | color: #2c3e50; 29 | margin-bottom: 10px; 30 | font-size: 2.5em; 31 | font-weight: 300; 32 | } 33 | 34 | header p { 35 | color: #666; 36 | font-size: 1.1em; 37 | } 38 | 39 | /* Controls */ 40 | .controls { 41 | background: white; 42 | padding: 25px; 43 | border-radius: 8px; 44 | box-shadow: 0 2px 10px rgba(0,0,0,0.1); 45 | margin-bottom: 20px; 46 | display: grid; 47 | grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); 48 | gap: 20px; 49 | align-items: end; 50 | position: relative; 51 | z-index: 100; 52 | } 53 | 54 | .control-group { 55 | display: flex; 56 | flex-direction: column; 57 | } 58 | 59 | .control-group label { 60 | margin-bottom: 5px; 61 | font-weight: 500; 62 | color: #555; 63 | } 64 | 65 | .control-group select, 66 | .control-group button { 67 | padding: 8px 12px; 68 | border: 2px solid #ddd; 69 | border-radius: 4px; 70 | font-size: 14px; 71 | background: white; 72 | transition: border-color 0.2s, box-shadow 0.2s; 73 | } 74 | 75 | .control-group select:focus, 76 | .control-group button:focus { 77 | outline: none; 78 | border-color: #3498db; 79 | box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1); 80 | } 81 | 82 | .control-group select:disabled { 83 | background-color: #f8f9fa; 84 | color: #6c757d; 85 | } 86 | 87 | .checkbox-group { 88 | display: flex; 89 | gap: 15px; 90 | flex-wrap: wrap; 91 | } 92 | 93 | .checkbox-label { 94 | display: flex; 95 | align-items: center; 96 | gap: 5px; 97 | cursor: pointer; 98 | font-weight: normal !important; 99 | } 100 | 101 | .checkbox-label input[type="checkbox"] { 102 | margin: 0; 103 | } 104 | 105 | button.info-button { 106 | background: none; 107 | border: none; 108 | color: #666; 109 | cursor: pointer; 110 | padding: 2px; 111 | margin-left: 6px; 112 | border-radius: 50%; 113 | width: 20px; 114 | height: 20px; 115 | display: inline-flex; 116 | align-items: center; 117 | justify-content: center; 118 | transition: all 0.2s; 119 | vertical-align: middle; 120 | } 121 | 122 | button.info-button:hover { 123 | background: #e9ecef; 124 | color: #495057; 125 | } 126 | 127 | button.info-button svg { 128 | width: 14px; 129 | height: 14px; 130 | fill: currentColor; 131 | } 132 | 133 | button { 134 | background: #3498db; 135 | color: white; 136 | border: none; 137 | cursor: pointer; 138 | font-weight: 500; 139 | transition: background-color 0.2s; 140 | } 141 | 142 | button:hover:not(:disabled) { 143 | background: #2980b9; 144 | } 145 | 146 | button:disabled { 147 | background: #bdc3c7; 148 | cursor: not-allowed; 149 | } 150 | 151 | /* Slider styles */ 152 | .slider { 153 | width: 100%; 154 | height: 5px; 155 | border-radius: 5px; 156 | background: #ddd; 157 | outline: none; 158 | opacity: 0.7; 159 | transition: opacity 0.2s; 160 | -webkit-appearance: none; 161 | } 162 | 163 | .slider:hover { 164 | opacity: 1; 165 | } 166 | 167 | .slider::-webkit-slider-thumb { 168 | -webkit-appearance: none; 169 | appearance: none; 170 | width: 20px; 171 | height: 20px; 172 | border-radius: 50%; 173 | background: #3498db; 174 | cursor: pointer; 175 | } 176 | 177 | .slider::-moz-range-thumb { 178 | width: 20px; 179 | height: 20px; 180 | border-radius: 50%; 181 | background: #3498db; 182 | cursor: pointer; 183 | border: none; 184 | } 185 | 186 | /* Table filters */ 187 | .table-filters { 188 | display: grid; 189 | grid-template-columns: 2fr 1fr 1fr 1fr; 190 | gap: 10px; 191 | margin-bottom: 20px; 192 | padding: 15px; 193 | background: #f8f9fa; 194 | border-radius: 4px; 195 | } 196 | 197 | .table-filters input, 198 | .table-filters select { 199 | padding: 8px 12px; 200 | border: 1px solid #ddd; 201 | border-radius: 4px; 202 | font-size: 14px; 203 | } 204 | 205 | .file-list-section h4 { 206 | margin-bottom: 15px; 207 | color: #2c3e50; 208 | } 209 | 210 | /* Status */ 211 | .status { 212 | background: #e8f4fd; 213 | border: 1px solid #bee5eb; 214 | color: #0c5460; 215 | padding: 15px; 216 | border-radius: 4px; 217 | margin-bottom: 20px; 218 | text-align: center; 219 | } 220 | 221 | /* Tabs */ 222 | .tabs { 223 | margin-bottom: 20px; 224 | } 225 | 226 | .tab-buttons { 227 | display: flex; 228 | background: white; 229 | border-radius: 8px; 230 | box-shadow: 0 2px 10px rgba(0,0,0,0.1); 231 | overflow: hidden; 232 | } 233 | 234 | .tab-button { 235 | flex: 1; 236 | padding: 15px 20px; 237 | background: #f8f9fa; 238 | border: none; 239 | cursor: pointer; 240 | font-size: 16px; 241 | font-weight: 500; 242 | color: #666; 243 | transition: all 0.2s; 244 | border-right: 1px solid #dee2e6; 245 | } 246 | 247 | .tab-button:last-child { 248 | border-right: none; 249 | } 250 | 251 | .tab-button:hover { 252 | background: #e9ecef; 253 | color: #495057; 254 | } 255 | 256 | .tab-button.active { 257 | background: #3498db; 258 | color: white; 259 | } 260 | 261 | .tab-button.active:hover { 262 | background: #2980b9; 263 | } 264 | 265 | .status.error { 266 | background: #f8d7da; 267 | border-color: #f5c6cb; 268 | color: #721c24; 269 | } 270 | 271 | .status.success { 272 | background: #d4edda; 273 | border-color: #c3e6cb; 274 | color: #155724; 275 | } 276 | 277 | /* Legend */ 278 | .legend { 279 | background: white; 280 | padding: 20px; 281 | border-radius: 8px; 282 | box-shadow: 0 2px 10px rgba(0,0,0,0.1); 283 | margin-bottom: 20px; 284 | } 285 | 286 | .legend h3 { 287 | margin-bottom: 15px; 288 | color: #2c3e50; 289 | } 290 | 291 | .legend-items { 292 | display: flex; 293 | gap: 25px; 294 | flex-wrap: wrap; 295 | } 296 | 297 | .legend-item { 298 | display: flex; 299 | align-items: center; 300 | gap: 8px; 301 | } 302 | 303 | .legend-color { 304 | width: 20px; 305 | height: 20px; 306 | border-radius: 3px; 307 | } 308 | 309 | .legend-color.unchanged { 310 | background: #95a5a6; 311 | } 312 | 313 | .legend-color.decreased { 314 | background: #27ae60; 315 | } 316 | 317 | .legend-color.increased { 318 | background: #e74c3c; 319 | } 320 | 321 | /* Visualization */ 322 | .visualization { 323 | background: white; 324 | border-radius: 8px; 325 | box-shadow: 0 2px 10px rgba(0,0,0,0.1); 326 | margin-bottom: 20px; 327 | overflow: hidden; 328 | } 329 | 330 | .chart-container { 331 | position: relative; 332 | min-height: 600px; 333 | z-index: 1; 334 | } 335 | 336 | #metric-chart { 337 | max-height: 800px; 338 | overflow-y: auto; 339 | overflow-x: auto; 340 | position: relative; 341 | z-index: 1; 342 | margin-top: -10px; 343 | padding-top: 15px; 344 | } 345 | 346 | .chart-header { 347 | display: flex; 348 | justify-content: space-between; 349 | align-items: center; 350 | padding: 20px 40px 10px; 351 | background: #f8f9fa; 352 | border-bottom: 1px solid #dee2e6; 353 | position: relative; 354 | z-index: 50; 355 | } 356 | 357 | .version-label { 358 | font-weight: 600; 359 | color: #495057; 360 | font-size: 1.1em; 361 | } 362 | 363 | .chart-controls { 364 | display: flex; 365 | gap: 8px; 366 | align-items: center; 367 | position: relative; 368 | z-index: 200; 369 | } 370 | 371 | .chart-info { 372 | color: #666; 373 | font-size: 14px; 374 | font-style: italic; 375 | } 376 | 377 | 378 | /* Interactive elements */ 379 | .chart-container .node rect { 380 | transition: stroke-width 0.2s; 381 | } 382 | 383 | .chart-container .node:hover rect { 384 | stroke-width: 2px; 385 | } 386 | 387 | .chart-container .link { 388 | transition: stroke-opacity 0.2s; 389 | } 390 | 391 | .chart-container .link:hover { 392 | stroke-opacity: 1 !important; 393 | } 394 | 395 | /* Details */ 396 | .details { 397 | background: white; 398 | padding: 25px; 399 | border-radius: 8px; 400 | box-shadow: 0 2px 10px rgba(0,0,0,0.1); 401 | } 402 | 403 | .details h3 { 404 | margin-bottom: 20px; 405 | color: #2c3e50; 406 | } 407 | 408 | .summary { 409 | margin-bottom: 20px; 410 | padding: 15px; 411 | background: #f8f9fa; 412 | border-radius: 4px; 413 | } 414 | 415 | .summary-item { 416 | display: flex; 417 | justify-content: space-between; 418 | margin-bottom: 8px; 419 | } 420 | 421 | .summary-item:last-child { 422 | margin-bottom: 0; 423 | } 424 | 425 | .file-list { 426 | max-height: 800px; 427 | overflow-y: auto; 428 | position: relative; 429 | z-index: 1; 430 | } 431 | 432 | .file-list-header { 433 | display: flex; 434 | justify-content: space-between; 435 | align-items: center; 436 | padding: 12px 10px; 437 | background-color: #f8f9fa; 438 | border: 1px solid #dee2e6; 439 | border-bottom: 2px solid #adb5bd; 440 | font-weight: 600; 441 | color: #495057; 442 | position: sticky; 443 | top: 0; 444 | z-index: 10; 445 | } 446 | 447 | .file-name-header { 448 | flex: 1; 449 | font-family: 'Courier New', monospace; 450 | font-size: 0.9em; 451 | } 452 | 453 | .file-sizes-header { 454 | display: flex; 455 | gap: 15px; 456 | align-items: center; 457 | font-size: 0.9em; 458 | } 459 | 460 | .size-value-header, 461 | .size-change-header { 462 | min-width: 80px; 463 | text-align: center; 464 | font-size: 0.85em; 465 | } 466 | 467 | .file-item { 468 | display: flex; 469 | justify-content: space-between; 470 | align-items: center; 471 | padding: 10px; 472 | border-bottom: 1px solid #eee; 473 | transition: background-color 0.2s; 474 | } 475 | 476 | .file-item:hover { 477 | background-color: #f8f9fa; 478 | } 479 | 480 | .file-item:last-child { 481 | border-bottom: none; 482 | } 483 | 484 | .file-name { 485 | flex: 1; 486 | font-family: 'Courier New', monospace; 487 | font-size: 0.9em; 488 | word-break: break-all; 489 | } 490 | 491 | .file-name-tooltip { 492 | cursor: help; 493 | } 494 | 495 | .file-sizes { 496 | display: flex; 497 | gap: 15px; 498 | align-items: center; 499 | font-size: 0.9em; 500 | } 501 | 502 | .size-value { 503 | min-width: 80px; 504 | text-align: right; 505 | } 506 | 507 | .size-change { 508 | min-width: 60px; 509 | text-align: right; 510 | font-weight: 500; 511 | } 512 | 513 | .size-change.positive { 514 | color: #e74c3c; 515 | } 516 | 517 | .size-change.negative { 518 | color: #27ae60; 519 | } 520 | 521 | .size-change.neutral { 522 | color: #95a5a6; 523 | } 524 | 525 | /* Sortable headers */ 526 | .sortable-header { 527 | cursor: pointer; 528 | user-select: none; 529 | position: relative; 530 | transition: background-color 0.2s ease, color 0.2s ease; 531 | } 532 | 533 | .sortable-header:hover { 534 | background-color: #e9ecef; 535 | color: #495057; 536 | } 537 | 538 | .sortable-header:active { 539 | background-color: #dee2e6; 540 | } 541 | 542 | /* Sort direction indicators */ 543 | .sortable-header::after { 544 | content: ''; 545 | opacity: 0.3; 546 | margin-left: 0.5em; 547 | } 548 | 549 | .sortable-header:hover::after { 550 | opacity: 0.6; 551 | } 552 | 553 | /* Ensure Plotly tooltips remain readable with classic styling */ 554 | .plotly .hovertext { 555 | background: #FFFFDD !important; 556 | color: black !important; 557 | border: 1px solid #333 !important; 558 | } 559 | 560 | .plotly .hovertext text { 561 | fill: black !important; 562 | } 563 | 564 | /* Override any colorful tooltip backgrounds */ 565 | g.hovertext { 566 | background: #FFFFDD !important; 567 | } 568 | 569 | g.hovertext rect { 570 | fill: #FFFFDD !important; 571 | stroke: #333 !important; 572 | } 573 | 574 | g.hovertext text { 575 | fill: black !important; 576 | } 577 | 578 | /* Safari scrollbar fixes */ 579 | .file-list::-webkit-scrollbar { 580 | width: 8px; 581 | } 582 | 583 | .file-list::-webkit-scrollbar-track { 584 | background: #f1f1f1; 585 | border-radius: 4px; 586 | } 587 | 588 | .file-list::-webkit-scrollbar-thumb { 589 | background: #c1c1c1; 590 | border-radius: 4px; 591 | } 592 | 593 | .file-list::-webkit-scrollbar-thumb:hover { 594 | background: #a8a8a8; 595 | } 596 | 597 | #metric-chart::-webkit-scrollbar { 598 | width: 8px; 599 | height: 8px; 600 | } 601 | 602 | #metric-chart::-webkit-scrollbar-track { 603 | background: #f1f1f1; 604 | border-radius: 4px; 605 | } 606 | 607 | #metric-chart::-webkit-scrollbar-thumb { 608 | background: #c1c1c1; 609 | border-radius: 4px; 610 | } 611 | 612 | #metric-chart::-webkit-scrollbar-thumb:hover { 613 | background: #a8a8a8; 614 | } 615 | 616 | /* Ensure scrollable areas have proper isolation */ 617 | .file-list, #metric-chart { 618 | isolation: isolate; 619 | } 620 | 621 | /* Plotly modebar (chart controls) fixes - keep on right with spacing from scrollbar */ 622 | .modebar { 623 | position: absolute !important; 624 | right: 20px !important; 625 | top: 10px !important; 626 | z-index: 300 !important; 627 | } 628 | 629 | .modebar-group { 630 | position: relative !important; 631 | z-index: 300 !important; 632 | } 633 | 634 | .modebar-btn { 635 | z-index: 300 !important; 636 | } 637 | 638 | /* Prevent scrollbars from covering Plotly controls */ 639 | .plotly > div { 640 | position: relative; 641 | } 642 | 643 | .plotly .modebar-container { 644 | position: relative !important; 645 | z-index: 300 !important; 646 | } 647 | 648 | /* Tooltip */ 649 | .tooltip { 650 | position: absolute; 651 | background: rgba(0, 0, 0, 0.9); 652 | color: white; 653 | padding: 10px; 654 | border-radius: 4px; 655 | font-size: 12px; 656 | pointer-events: none; 657 | z-index: 1000; 658 | opacity: 0; 659 | transition: opacity 0.2s; 660 | max-width: 300px; 661 | line-height: 1.4; 662 | } 663 | 664 | .tooltip.visible { 665 | opacity: 1; 666 | } 667 | 668 | /* Responsive design */ 669 | @media (max-width: 768px) { 670 | .controls { 671 | grid-template-columns: 1fr; 672 | } 673 | 674 | .legend-items { 675 | flex-direction: column; 676 | gap: 10px; 677 | } 678 | 679 | .chart-header { 680 | padding: 15px 20px 10px; 681 | } 682 | 683 | .file-sizes { 684 | flex-direction: column; 685 | gap: 5px; 686 | align-items: flex-end; 687 | } 688 | } 689 | 690 | /* Loading state */ 691 | .loading { 692 | text-align: center; 693 | padding: 40px; 694 | color: #666; 695 | } 696 | 697 | .loading::after { 698 | content: ''; 699 | display: inline-block; 700 | width: 20px; 701 | height: 20px; 702 | border: 2px solid #ddd; 703 | border-top: 2px solid #3498db; 704 | border-radius: 50%; 705 | animation: spin 1s linear infinite; 706 | margin-left: 10px; 707 | } 708 | 709 | @keyframes spin { 710 | 0% { transform: rotate(0deg); } 711 | 100% { transform: rotate(360deg); } 712 | } 713 | 714 | /* Timeline Modal Styles */ 715 | .timeline-modal-backdrop { 716 | position: fixed; 717 | top: 0; 718 | left: 0; 719 | width: 100%; 720 | height: 100%; 721 | background: rgba(0, 0, 0, 0.5); 722 | z-index: 10000; 723 | display: flex; 724 | align-items: center; 725 | justify-content: center; 726 | animation: fadeIn 0.2s ease-out; 727 | } 728 | 729 | @keyframes fadeIn { 730 | from { opacity: 0; } 731 | to { opacity: 1; } 732 | } 733 | 734 | .timeline-modal { 735 | background: white; 736 | border-radius: 12px; 737 | box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2); 738 | width: 90%; 739 | max-width: 900px; 740 | max-height: 90vh; 741 | overflow: hidden; 742 | animation: slideIn 0.3s ease-out; 743 | } 744 | 745 | @keyframes slideIn { 746 | from { 747 | opacity: 0; 748 | transform: scale(0.95) translateY(-20px); 749 | } 750 | to { 751 | opacity: 1; 752 | transform: scale(1) translateY(0); 753 | } 754 | } 755 | 756 | .timeline-modal-header { 757 | padding: 25px 30px 20px; 758 | border-bottom: 1px solid #e1e5e9; 759 | background: #f8f9fa; 760 | position: relative; 761 | } 762 | 763 | .timeline-modal-header h3 { 764 | margin: 0 0 10px 0; 765 | color: #2c3e50; 766 | font-size: 1.4em; 767 | font-weight: 600; 768 | word-break: break-all; 769 | padding-right: 40px; 770 | } 771 | 772 | .timeline-modal-summary { 773 | color: #666; 774 | font-size: 14px; 775 | } 776 | 777 | .timeline-modal-close { 778 | position: absolute; 779 | top: 20px; 780 | right: 25px; 781 | background: none; 782 | border: none; 783 | font-size: 24px; 784 | color: #999; 785 | cursor: pointer; 786 | width: 30px; 787 | height: 30px; 788 | display: flex; 789 | align-items: center; 790 | justify-content: center; 791 | border-radius: 50%; 792 | transition: all 0.2s; 793 | } 794 | 795 | .timeline-modal-close:hover { 796 | background: #f0f0f0; 797 | color: #666; 798 | } 799 | 800 | .timeline-modal-body { 801 | padding: 25px 30px 30px; 802 | max-height: calc(90vh - 120px); 803 | overflow-y: auto; 804 | } 805 | 806 | .timeline-loading { 807 | display: flex; 808 | flex-direction: column; 809 | align-items: center; 810 | padding: 40px 20px; 811 | color: #666; 812 | } 813 | 814 | .loading-spinner { 815 | width: 32px; 816 | height: 32px; 817 | border: 3px solid #f0f0f0; 818 | border-top: 3px solid #3498db; 819 | border-radius: 50%; 820 | animation: spin 1s linear infinite; 821 | margin-bottom: 15px; 822 | } 823 | 824 | .timeline-loading p { 825 | margin: 0; 826 | font-size: 16px; 827 | } 828 | 829 | /* Responsive Design */ 830 | @media (max-width: 768px) { 831 | .timeline-modal { 832 | width: 95%; 833 | margin: 20px; 834 | max-height: calc(100vh - 40px); 835 | } 836 | 837 | .timeline-modal-header { 838 | padding: 20px; 839 | } 840 | 841 | .timeline-modal-header h3 { 842 | font-size: 1.2em; 843 | padding-right: 35px; 844 | } 845 | 846 | .timeline-modal-close { 847 | top: 15px; 848 | right: 15px; 849 | font-size: 20px; 850 | width: 26px; 851 | height: 26px; 852 | } 853 | 854 | .timeline-modal-body { 855 | padding: 20px; 856 | } 857 | } 858 | 859 | @media (max-width: 480px) { 860 | .timeline-modal { 861 | width: 100%; 862 | height: 100%; 863 | max-height: 100vh; 864 | border-radius: 0; 865 | margin: 0; 866 | } 867 | 868 | .timeline-modal-header h3 { 869 | font-size: 1.1em; 870 | line-height: 1.3; 871 | } 872 | } -------------------------------------------------------------------------------- /check_size.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import sys 4 | import subprocess 5 | import tempfile 6 | import urllib 7 | import urllib.request 8 | import datetime 9 | import itertools 10 | import json 11 | import shutil 12 | import csv 13 | import zipfile 14 | import matplotlib 15 | matplotlib.use('Agg') 16 | 17 | from matplotlib import pyplot 18 | from collections import OrderedDict 19 | 20 | 21 | # https://matplotlib.org/stable/api/markers_api.html 22 | markers = '.o8s+xD*pP<<>' 23 | 24 | # old list containing architectures we no longer use 25 | # also a mix of engines and archives (apk vs engine binary) 26 | legacy_engines = [ 27 | {"platform": "arm64-darwin", "filename": "dmengine_release"}, 28 | {"platform": "armv7-android", "filename": "dmengine_release.apk"}, # added in 1.2.153 29 | {"platform": "armv7-darwin", "filename": "dmengine_release"}, 30 | {"platform": "darwin", "filename": "dmengine_release"}, 31 | {"platform": "js-web", "filename": "dmengine_release.js"}, 32 | {"platform": "wasm-web", "filename": "dmengine_release.wasm"}, # added in 1.2.141 33 | {"platform": "linux", "filename": "dmengine_release"}, 34 | {"platform": "win32", "filename": "dmengine_release.exe"}, 35 | {"platform": "x86_64-darwin", "filename": "dmengine_release"}, 36 | {"platform": "x86_64-linux", "filename": "dmengine_release"}, 37 | {"platform": "armv7-android", "filename": "dmengine.apk"}, 38 | {"platform": "arm64-android", "filename": "dmengine.apk"}, 39 | ] 40 | 41 | engines = [ 42 | {"platform": "arm64-ios", "filename": "dmengine_release"}, 43 | {"platform": "arm64-android", "filename": "libdmengine_release.so"}, 44 | {"platform": "armv7-android", "filename": "libdmengine_release.so"}, 45 | {"platform": "x86_64-macos", "filename": "dmengine_release"}, 46 | {"platform": "arm64-macos", "filename": "dmengine_release"}, 47 | {"platform": "js-web", "filename": "dmengine_release.js"}, 48 | {"platform": "wasm-web", "filename": "dmengine_release.wasm"}, 49 | {"platform": "x86_64-linux", "filename": "dmengine_release"}, 50 | {"platform": "x86-win32", "filename": "dmengine_release.exe"}, 51 | {"platform": "x86_64-win32", "filename": "dmengine_release.exe"}, 52 | ] 53 | 54 | bundles = [ 55 | {"platform": "arm64-ios", "filename": "notused"}, 56 | {"platform": "arm64-android", "filename": "notused"}, 57 | {"platform": "armv7-android", "filename": "notused"}, 58 | {"platform": "x86_64-macos", "filename": "notused"}, 59 | {"platform": "arm64-macos", "filename": "notused"}, 60 | {"platform": "js-web", "filename": "notused"}, 61 | {"platform": "wasm-web", "filename": "notused"}, 62 | {"platform": "x86_64-linux", "filename": "notused"}, 63 | {"platform": "x86-win32", "filename": "notused"}, 64 | {"platform": "x86_64-win32", "filename": "notused"}, 65 | ] 66 | 67 | # each platform is the same size (it's the same bundle) 68 | bob_files = [ 69 | {"platform": "x86_64-macos", "filename": "bob.jar"}, 70 | ] 71 | 72 | editor_files = [ 73 | {"platform": "x86_64-macos", "filename": "Defold-x86_64-macos.dmg"}, 74 | {"platform": "arm64-macos", "filename": "Defold-arm64-macos.dmg"}, 75 | {"platform": "x86_64-win32", "filename": "Defold-x86_64-win32.zip"}, 76 | {"platform": "x86_64-linux", "filename": "Defold-x86_64-linux.zip"}, 77 | ] 78 | #editor2/Defold-x86_64-macos.dmg 79 | 80 | def get_host(): 81 | if sys.platform == 'linux2': 82 | return 'linux' 83 | elif sys.platform == 'win32': 84 | return 'windows' 85 | elif sys.platform == 'darwin': 86 | return 'macos' 87 | raise "Unknown platform" 88 | 89 | def download_bob(sha1): 90 | bob_path = 'bob_{}.jar'.format(sha1) 91 | if not os.path.exists(bob_path): 92 | print("Downloading bob version {} to {}".format(sha1, bob_path)) 93 | url = "http://d.defold.com/archive/stable/" + sha1 + "/bob/bob.jar" 94 | urllib.request.urlretrieve(url, bob_path) 95 | return bob_path 96 | 97 | def get_size_from_url(sha1, path): 98 | url = "http://d.defold.com/archive/" + sha1 + "/" + path 99 | try: 100 | d = urllib.request.urlopen(url) 101 | if d.getcode() == 200: 102 | return d.info()['Content-Length'] 103 | except urllib.error.HTTPError as e: 104 | if e.code == 404: 105 | print(e.code, "Url doesn't exist:", url) 106 | return 0 107 | 108 | def get_engine_size_from_aws(sha1, platform, filename): 109 | if platform == "x86-win32": 110 | platform = "win32" 111 | path = "engine/{}/stripped/{}" 112 | print("Gettings size of {} for platform {} with sha1 {} from AWS".format(filename, platform, sha1)) 113 | path = path.format(platform, filename) 114 | size = get_size_from_url(sha1, path) 115 | if size == 0: 116 | path = "engine/{}/{}" 117 | path = path.format(platform, filename) 118 | size = get_size_from_url(sha1, path) 119 | if size == 0: 120 | path = "engine/{}/{}".format(platform, filename) 121 | size = get_size_from_url(sha1, path) 122 | return size 123 | 124 | def get_bob_size_from_aws(sha1, platform, filename): 125 | print("Gettings size of {} for platform {} with sha1 {} from AWS".format(filename, platform, sha1)) 126 | path = "bob/{}".format(filename) 127 | size = get_size_from_url(sha1, path) 128 | return size 129 | 130 | def get_editor_size_from_aws(sha1, platform, filename): 131 | print("Gettings size of {} for platform {} with sha1 {} from AWS".format(filename, platform, sha1)) 132 | path = "editor-alpha/editor2/{}".format(filename) 133 | size = get_size_from_url(sha1, path) 134 | return size 135 | 136 | def extract_from_bob(bob_path, filename): 137 | bob_zip = zipfile.ZipFile(bob_path) 138 | bob_info = bob_zip.getinfo(filename) 139 | return bob_zip.extract(bob_info) 140 | 141 | def get_engine_size_from_bob(sha1, platform, filename): 142 | print("Gettings size of {} for platform {} with sha1 {} from Bob".format(filename, platform, sha1)) 143 | try: 144 | bob_path = download_bob(sha1) 145 | engine_path = 'libexec/{}/{}'.format(platform, filename) 146 | extracted_engine = extract_from_bob(bob_path, engine_path) 147 | return os.path.getsize(extracted_engine) 148 | except Exception as e: 149 | print(e) 150 | return 0 151 | 152 | def get_engine_size(sha1, platform, filename): 153 | # Try to get the engine size from Bob 154 | size = get_engine_size_from_bob(sha1, platform, filename) 155 | if size > 0: 156 | return size 157 | 158 | # Fall back to getting the engine size from AWS 159 | size = get_engine_size_from_aws(sha1, platform, filename) 160 | return size 161 | 162 | def get_zipped_size(path): 163 | tmp = tempfile.NamedTemporaryFile("wb") 164 | z = zipfile.ZipFile(tmp, "w", zipfile.ZIP_DEFLATED) 165 | for root, dirs, files in os.walk(path): 166 | for file in files: 167 | z.write(os.path.join(root, file)) 168 | print("write " + os.path.join(root, file)) 169 | z.close() 170 | return os.path.getsize(tmp.name) 171 | 172 | def get_folder_size(path): 173 | size = 0 174 | for root, dirs, files in os.walk(path): 175 | for file in files: 176 | size = size + os.path.getsize(os.path.join(root, file)) 177 | return size 178 | 179 | def get_bundle_size_from_bob(sha1, platform, _): 180 | print("Gettings size of bundle for platform {} with sha1 {} using Bob".format(platform, sha1)) 181 | if os.path.exists("bundle_output"): 182 | shutil.rmtree("bundle_output") 183 | os.mkdir("bundle_output") 184 | 185 | try: 186 | bob_path = download_bob(sha1) 187 | bob_filename = os.path.basename(bob_path) 188 | shutil.copy(bob_path, os.path.join("empty_project", "bob.jar")) 189 | args = [] 190 | args.append("java") 191 | args.append("-jar") 192 | args.append("bob.jar") 193 | args.append("--archive") 194 | if platform in ("armv7-android", "arm64-android"): 195 | args.append("--platform=armv7-android") 196 | args.append("--architectures=" + platform) 197 | args.append("--bundle-format="+"aab") 198 | elif platform in ("wasm-web", "js-web"): 199 | args.append("--platform=js-web") 200 | args.append("--architectures=" + platform) 201 | elif platform in ("x86_64-macos", "arm64-macos"): 202 | args.append("--platform=x86_64-macos") 203 | args.append("--architectures=" + platform) 204 | else: 205 | args.append("--platform=" + platform) 206 | args.append("--variant=release") 207 | args.append("--strip-executable") 208 | args.append("--bundle-output=../bundle_output") 209 | args.extend(["clean", "build", "bundle"]) 210 | 211 | subprocess.call(args,cwd="empty_project") 212 | 213 | if platform in ("armv7-android", "arm64-android"): 214 | return os.path.getsize("bundle_output/unnamed/unnamed.aab") 215 | elif platform in ("arm64-ios","x86_64-ios","arm64-darwin"): 216 | return os.path.getsize("bundle_output/unnamed.ipa") 217 | elif platform in ("x86_64-macos", "x86_64-darwin", "arm64-macos"): 218 | return get_folder_size("bundle_output/unnamed.app") 219 | elif platform in ("x86_64-win32", "x86-win32"): 220 | return get_zipped_size("bundle_output") 221 | elif platform in ("x86_64-linux",): 222 | return get_zipped_size("bundle_output") 223 | elif platform in ("wasm-web", "js-web"): 224 | return get_zipped_size("bundle_output") 225 | else: 226 | raise Exception("Unknown platform {}". format(platform)) 227 | except Exception as e: 228 | print(e) 229 | return 0 230 | 231 | 232 | def get_latest_version(): 233 | url = "http://d.defold.com/stable/info.json" 234 | response = urllib.request.urlopen(url) 235 | if response.getcode() == 200: 236 | return json.loads(response.read()) 237 | return {} 238 | 239 | def read_releases(path): 240 | with open(path, 'rb') as f: 241 | d = json.loads(f.read()) 242 | return d 243 | return {} 244 | 245 | def version_to_number(version): 246 | tokens = version.split('.') 247 | ints = list(map(int, tokens)) 248 | n = ints[0] * 100000 + ints[1] * 1000 + ints[2] 249 | return n 250 | 251 | 252 | def number_to_version(number): 253 | major = number // 100000 254 | number -= major * 100000 255 | middle = number // 1000 256 | number -= middle * 1000 #minor 257 | return "%d.%d.%d" % (major, middle, number) 258 | 259 | 260 | def print_report(report): 261 | 262 | """ 263 | { 264 | 'version' = ['1.3.3', '1.3.4', '1.3.5'], 265 | 'arm64-ios' = { 266 | '1.3.4' = 123456, 267 | '1.3.5' = 123789, 268 | } 269 | 'x86_64-macos' = { 270 | ... 271 | } 272 | ... 273 | } 274 | """ 275 | print("report:") 276 | for key, data in report.items(): 277 | if key == 'version': 278 | print(" version:") 279 | for version in data: 280 | print(" ", version) 281 | continue 282 | platform = key 283 | print(" platform:", platform) 284 | for version, size in data.items(): 285 | print(" ", version, ":", size) 286 | 287 | def read_report(path): 288 | #format: 289 | #VERSION,arm64-ios,arm64-android,armv7-android,x86_64-macos,js-web,wasm-web,x86_64-linux,x86-win32,x86_64-win32 290 | #1.2.38,0,0,0,0,0,0,0,0,0,0,0,0,0 291 | #1.2.39,0,0,0,0,0,0,0,0,0,0,0,0,0 292 | lines = [] 293 | with open(path, 'r') as f: 294 | reader = csv.reader(f) 295 | for row in reader: 296 | lines.append(row) 297 | 298 | header = lines[0] 299 | platforms = header[1:] 300 | assert(header[0] == 'VERSION') 301 | 302 | report = OrderedDict() 303 | report['version'] = [] 304 | for line in lines[1:]: 305 | version = line[0] 306 | report['version'].append(version) 307 | 308 | if len(line) != len(header): 309 | print("%s:" % path, "Mismatching number of cells in line", line) 310 | continue 311 | 312 | # loop over each platform 313 | for i, platform in enumerate(header): 314 | if i == 0: 315 | continue 316 | 317 | if not platform in report: 318 | report[platform] = OrderedDict() 319 | 320 | size = line[i] 321 | if size == '0': 322 | continue 323 | report[platform][version] = size 324 | 325 | return report 326 | 327 | def sort_versions(versions): 328 | version_numbers = list(map(lambda x: version_to_number(x), versions)) 329 | return list(map(lambda x: number_to_version(x), sorted(version_numbers))) 330 | 331 | def write_report(path, report): 332 | #format: 333 | #VERSION,arm64-ios,arm64-android,armv7-android,x86_64-macos,js-web,wasm-web,x86_64-linux,x86-win32,x86_64-win32 334 | #1.2.38,0,0,0,0,0,0,0,0,0,0,0,0,0 335 | #1.2.39,0,0,0,0,0,0,0,0,0,0,0,0,0 336 | 337 | versions = sort_versions(report['version']) 338 | 339 | platforms = [x for x in report.keys() if x != 'version'] 340 | 341 | lines = [] 342 | lines.append(['VERSION']+platforms) # header 343 | 344 | for version in versions: 345 | row = [version] 346 | for platform in platforms: 347 | platform_data = report[platform] 348 | size = platform_data.get(version, 0) # the size (int) or n/a (0) 349 | row.append(size) 350 | 351 | lines.append(row) 352 | 353 | with open(path, 'w') as f: 354 | writer = csv.writer(f) 355 | for line in lines: 356 | writer.writerow(line) 357 | 358 | print("Wrote {}".format(path)) 359 | 360 | 361 | def create_report(report_filename, releases, report_platforms, fn): 362 | print("Creating {}".format(report_filename)) 363 | 364 | report = read_report(report_filename) 365 | 366 | # Remove old platforms 367 | supported_platforms = list(map(lambda x: x['platform'], report_platforms)) 368 | delete_keys = [] 369 | for key,_ in report.items(): 370 | if key == 'version': 371 | continue 372 | if key not in supported_platforms: 373 | print("Removed old platform", key) 374 | delete_keys.append(key) 375 | for key in delete_keys: 376 | del report[key] 377 | 378 | # Add new platforms 379 | for platform in supported_platforms: 380 | if not platform in report: 381 | report[platform] = OrderedDict() 382 | 383 | 384 | # go through the releases one by one and either use existing size data 385 | # or download and get the size data 386 | for release in releases: 387 | version = release["version"] 388 | sha1 = release["sha1"] 389 | 390 | if version in report['version']: 391 | print(f" Version {version} already exists") 392 | continue # we already had the report for this version 393 | 394 | report['version'].append(version) 395 | print("Found new version {} - Getting size".format(version)) 396 | 397 | for report_platform in report_platforms: 398 | platform = report_platform["platform"] 399 | filename = report_platform["filename"] 400 | print(f" Making report for {platform}...") 401 | size = fn(sha1, platform, filename) 402 | print(f" Resported size: {platform} {size}") 403 | report[platform][version] = size 404 | 405 | write_report(report_filename, report) 406 | print("Creating {} - ok".format(report_filename)) 407 | 408 | def parse_version(version_str): 409 | return tuple(map(int, version_str.split('.'))) # make it into a tuple 410 | 411 | def create_graph(report_filename, out, from_version=None): 412 | print("Creating {}".format(out)) 413 | with open(report_filename, 'r') as f: 414 | data = list(csv.reader(f)) 415 | 416 | # only keep the versions starting with from_version and above 417 | if from_version is not None: 418 | from_version = parse_version(from_version) 419 | new_data = [] 420 | for line in data: 421 | if 'VERSION' in line[0]: 422 | new_data.append(line) 423 | continue 424 | version = parse_version(line[0]) 425 | #if new_version(version, from_version): 426 | if version >= from_version: 427 | new_data.append(line) 428 | data = new_data 429 | 430 | # get all versions, ignore column headers 431 | versions = [i[0] for i in data[1::]] 432 | xaxis_version = range(0, len(versions)) 433 | 434 | mb = 1024 * 1024 435 | 436 | fig, ax = pyplot.subplots(figsize=(20, 10)) 437 | pyplot.xticks(xaxis_version, versions, rotation=270) 438 | max_ysize = 0 439 | min_ysize = 10000 * mb 440 | assert(len(markers) >= (len(data[0])-1)) # we need unique markers for each platform 441 | 442 | for engine, marker in zip(range(1, len(data[0])), markers): 443 | # convert from string to int 444 | # find the max y size 445 | yaxis_size = [] 446 | for num in list([i[engine] for i in data[1::]]): 447 | num = int(num) 448 | max_ysize = max(max_ysize, num) 449 | min_ysize = min(min_ysize, num) 450 | yaxis_size.append(num) 451 | ax.plot(xaxis_version, yaxis_size, label=data[0][engine], marker=marker) 452 | 453 | # make sure the plot fills out the area (easier to see nuances) 454 | ax.set_ylim(bottom=min_ysize) 455 | ax.set_xlim(left=0., right=xaxis_version[-1]) 456 | 457 | max_mb = int( (max_ysize+mb/2) // mb ) 458 | min_mb = int( (min_ysize+mb/2) // mb ) 459 | step = 1 460 | if max_mb - min_mb > 200: 461 | step = 10 462 | locs = [i * mb for i in range(min_mb, max_mb+1, step)] 463 | 464 | # create horizontal lines, to make it easier to track sizes 465 | for y in range(min_mb*mb, max_mb*mb, mb*step): 466 | ax.axhline(y, alpha=0.1) 467 | 468 | pyplot.yticks(locs, map(lambda x: "%d mb" % (x // mb), locs)) 469 | pyplot.ylabel('SIZE') 470 | pyplot.xlabel('VERSION') 471 | # add timestamp to top-left corner of graph 472 | pyplot.annotate(str(datetime.datetime.now()), xy=(0.02, 0.95), xycoords='axes fraction') 473 | 474 | # create legend 475 | legend = ax.legend(loc='upper left', bbox_to_anchor=(0.02, 0.94)) 476 | frame = legend.get_frame() 477 | frame.set_facecolor('0.90') 478 | 479 | fig.savefig(out, format='png', bbox_extra_artists=(legend,), bbox_inches='tight', pad_inches=1) 480 | print("Creating {} - ok".format(out)) 481 | 482 | 483 | def check_for_updates(latest_release, releases): 484 | # Is the release already present? 485 | for release in releases['releases']: 486 | if latest_release['version'] == release['version']: 487 | return False 488 | return True 489 | 490 | 491 | # latest_release = { "version": "1.3.3", "sha1": "287c945fab310c324493e08b191ee1b1538ef973"} 492 | latest_release = get_latest_version() 493 | 494 | releases = read_releases('releases.json') 495 | 496 | if check_for_updates(latest_release, releases): 497 | print("Found new release {}".format(latest_release)) 498 | releases['releases'].append(latest_release) 499 | 500 | # update the releases on disc 501 | with open('releases_new.json', 'w') as f: 502 | json.dump(releases, f, indent=4, separators=(',', ': ')) 503 | # if everything went right, move the temp file 504 | shutil.move('releases_new.json', 'releases.json') 505 | 506 | 507 | # update reports (if releases are missing from a report file) 508 | print("Creating reports") 509 | # create_report("legacy_engine_report.csv", releases['releases'], engines, get_engine_size_from_aws) 510 | create_report("engine_report.csv", releases['releases'], engines, get_engine_size) 511 | create_report("bundle_report.csv", releases['releases'], bundles, get_bundle_size_from_bob) 512 | create_report("bob_report.csv", releases['releases'], bob_files, get_bob_size_from_aws) 513 | create_report("editor_report.csv", releases['releases'], editor_files, get_editor_size_from_aws) 514 | 515 | 516 | # create graphs based on the different reports 517 | print("Creating graphs") 518 | # create_graph("legacy_engine_report.csv", out='legacy_engine_size.png') 519 | # create_graph("legacy_engine_report.csv", out='legacy_engine_size_stripped.png', from_version='1.2.155') # from 1.2.155, we have stripped versions available for all platforms 520 | create_graph("engine_report.csv", out='engine_size.png', from_version='1.2.166') 521 | create_graph("bundle_report.csv", out='bundle_size.png', from_version='1.2.166') 522 | create_graph("bob_report.csv", out='bob_size.png', from_version='1.2.166') 523 | create_graph("editor_report.csv", out='editor_size.png', from_version='1.3.6') 524 | -------------------------------------------------------------------------------- /size-analyzer/js/csv-parser.js: -------------------------------------------------------------------------------- 1 | // CSV Parser and Data Processing Module 2 | 3 | class CSVParser { 4 | // Cache for loaded CSV data to avoid repeated requests 5 | static csvCache = new Map(); 6 | 7 | static async parseCSV(text) { 8 | const lines = text.trim().split('\n'); 9 | const headers = lines[0].split(','); 10 | const data = []; 11 | 12 | for (let i = 1; i < lines.length; i++) { 13 | const values = this.parseCSVLine(lines[i]); 14 | if (values.length === headers.length) { 15 | const row = {}; 16 | headers.forEach((header, index) => { 17 | row[header.trim()] = values[index].trim(); 18 | }); 19 | data.push(row); 20 | } 21 | } 22 | 23 | return data; 24 | } 25 | 26 | static getMetricsFromHeaders(headers) { 27 | // Get metrics from CSV headers, excluding the filename column 28 | const filenameColumns = ['compileunits', 'filename', 'symbol_group_name']; 29 | return headers 30 | .map(h => h.trim()) 31 | .filter(header => !filenameColumns.includes(header.toLowerCase())); 32 | } 33 | 34 | static getFilenameColumn(headers) { 35 | // Find the filename column 36 | const filenameColumns = ['compileunits', 'filename', 'symbol_group_name']; 37 | return headers 38 | .map(h => h.trim()) 39 | .find(header => filenameColumns.includes(header.toLowerCase())) || headers[0]; 40 | } 41 | 42 | static parseCSVLine(line) { 43 | const result = []; 44 | let current = ''; 45 | let inQuotes = false; 46 | 47 | for (let i = 0; i < line.length; i++) { 48 | const char = line[i]; 49 | 50 | if (char === '"') { 51 | inQuotes = !inQuotes; 52 | } else if (char === ',' && !inQuotes) { 53 | result.push(current); 54 | current = ''; 55 | } else { 56 | current += char; 57 | } 58 | } 59 | 60 | result.push(current); 61 | return result; 62 | } 63 | 64 | static async loadCSV(url) { 65 | // Check cache first 66 | if (this.csvCache.has(url)) { 67 | return this.csvCache.get(url); 68 | } 69 | 70 | try { 71 | const response = await fetch(url); 72 | if (!response.ok) { 73 | throw new Error(`HTTP error! status: ${response.status}`); 74 | } 75 | const text = await response.text(); 76 | const data = await this.parseCSV(text); 77 | 78 | // Cache the parsed data 79 | this.csvCache.set(url, data); 80 | return data; 81 | } catch (error) { 82 | console.error('Error loading CSV:', url, error); 83 | throw error; 84 | } 85 | } 86 | 87 | static clearCache() { 88 | this.csvCache.clear(); 89 | } 90 | } 91 | 92 | class DataProcessor { 93 | static normalizeFilePath(filePath) { 94 | if (!filePath) return filePath; 95 | 96 | // Remove leading ../ and ./ prefixes 97 | let normalized = filePath.replace(/^(\.\.\/)+/, '').replace(/^\.\//, ''); 98 | 99 | // Handle cases where the path might start with different variations 100 | // Also remove any leading / if present 101 | normalized = normalized.replace(/^\/+/, ''); 102 | 103 | return normalized; 104 | } 105 | 106 | static parseVersion(version) { 107 | // Ensure version is a string 108 | const versionStr = typeof version === 'string' ? version : String(version); 109 | return versionStr.split('.').map(Number); 110 | } 111 | 112 | static compareVersions(v1, v2) { 113 | const a = this.parseVersion(v1); 114 | const b = this.parseVersion(v2); 115 | 116 | for (let i = 0; i < Math.max(a.length, b.length); i++) { 117 | const numA = a[i] || 0; 118 | const numB = b[i] || 0; 119 | if (numA !== numB) { 120 | return numA - numB; 121 | } 122 | } 123 | return 0; 124 | } 125 | 126 | static getVersionsInRange(allVersions, startVersion, endVersion) { 127 | return allVersions 128 | .filter(version => { 129 | return this.compareVersions(version, startVersion) >= 0 && 130 | this.compareVersions(version, endVersion) <= 0; 131 | }) 132 | .sort(this.compareVersions.bind(this)); 133 | } 134 | 135 | static async getFileTimeline(fileName, platform, startVersion, endVersion, metricType) { 136 | // Get analysis index to determine available versions 137 | const analysisResponse = await fetch('analysis_index.json'); 138 | const analysisIndex = await analysisResponse.json(); 139 | const allVersionObjects = analysisIndex.platforms[platform].versions; 140 | 141 | // Extract just the version strings from the objects 142 | const allVersions = allVersionObjects.map(v => v.version); 143 | 144 | // Get versions in range 145 | const versionsInRange = this.getVersionsInRange(allVersions, startVersion, endVersion); 146 | 147 | const timeline = []; 148 | let filenameColumn = 'compileunits'; // default 149 | 150 | // Load data for each version 151 | for (const version of versionsInRange) { 152 | try { 153 | const csvData = await CSVParser.loadCSV(`${platform}/${version}.csv`); 154 | 155 | // Detect filename column from first version's data 156 | if (csvData.length > 0 && filenameColumn === 'compileunits') { 157 | const headers = Object.keys(csvData[0]); 158 | filenameColumn = CSVParser.getFilenameColumn(headers); 159 | } 160 | 161 | // Find the file in this version's data 162 | const normalizedFileName = DataProcessor.normalizeFilePath(fileName); 163 | const fileRow = csvData.find(row => 164 | DataProcessor.normalizeFilePath(row[filenameColumn]) === normalizedFileName 165 | ); 166 | 167 | const size = fileRow ? (parseInt(fileRow[metricType]) || 0) : 0; 168 | 169 | timeline.push({ 170 | version: version, 171 | size: size, 172 | exists: !!fileRow 173 | }); 174 | 175 | } catch (error) { 176 | console.warn(`Failed to load data for version ${version}:`, error); 177 | // Add zero size for missing versions 178 | timeline.push({ 179 | version: version, 180 | size: 0, 181 | exists: false 182 | }); 183 | } 184 | } 185 | 186 | return timeline; 187 | } 188 | 189 | static processDataByMetric(data1, data2, metricType, changeThreshold = 50, filenameColumn = 'compileunits') { 190 | // Process data for a specific metric (dynamic based on CSV headers) 191 | 192 | const data1Map = new Map(); 193 | const data2Map = new Map(); 194 | 195 | // Process first dataset 196 | data1.forEach((row, index) => { 197 | const compileUnit = this.normalizeFilePath(row[filenameColumn]); 198 | const metricValue = parseInt(row[metricType]) || 0; 199 | 200 | data1Map.set(compileUnit, { 201 | size: metricValue, 202 | compileUnit, 203 | originalPath: row[filenameColumn] 204 | }); 205 | }); 206 | 207 | // Process second dataset 208 | data2.forEach(row => { 209 | const compileUnit = this.normalizeFilePath(row[filenameColumn]); 210 | const metricValue = parseInt(row[metricType]) || 0; 211 | 212 | data2Map.set(compileUnit, { 213 | size: metricValue, 214 | compileUnit, 215 | originalPath: row[filenameColumn] 216 | }); 217 | }); 218 | 219 | // Detect file moves before processing comparisons 220 | const moveDetection = this.detectFileMoves(data1Map, data2Map); 221 | const { mergedData1, mergedData2 } = moveDetection; 222 | 223 | // Compare and create comparison data using merged data (after move detection) 224 | const comparisons = []; 225 | const allKeys = new Set([...mergedData1.keys(), ...mergedData2.keys()]); 226 | 227 | allKeys.forEach(compileUnit => { 228 | const item1 = mergedData1.get(compileUnit); 229 | const item2 = mergedData2.get(compileUnit); 230 | 231 | const size1 = item1 ? item1.size : 0; 232 | const size2 = item2 ? item2.size : 0; 233 | const difference = size2 - size1; 234 | const percentChange = size1 > 0 ? ((difference / size1) * 100) : (size2 > 0 ? 100 : 0); 235 | 236 | let changeType = 'unchanged'; 237 | if (Math.abs(difference) > changeThreshold) { 238 | changeType = difference > 0 ? 'increased' : 'decreased'; 239 | } 240 | 241 | // Add move detection info if applicable 242 | const moveInfo = item1?.moveInfo || item2?.moveInfo; 243 | 244 | comparisons.push({ 245 | compileUnit, 246 | size1, 247 | size2, 248 | difference, 249 | percentChange, 250 | changeType, 251 | metricType, 252 | ...(moveInfo && { 253 | isMoved: true, 254 | moveInfo: moveInfo, 255 | displayName: moveInfo.displayName 256 | }) 257 | }); 258 | }); 259 | 260 | // Sort by absolute difference (largest changes first) 261 | comparisons.sort((a, b) => Math.abs(b.difference) - Math.abs(a.difference)); 262 | 263 | 264 | return comparisons; 265 | } 266 | 267 | static detectFileMoves(data1Map, data2Map) { 268 | // Algorithm to detect file moves by comparing basenames and sizes 269 | // Returns merged data maps where moves are consolidated as single entities 270 | 271 | const mergedData1 = new Map(data1Map); 272 | const mergedData2 = new Map(data2Map); 273 | const moveInfo = new Map(); 274 | 275 | // Get files that are only in data1 (potentially moved out) 276 | const onlyInData1 = []; 277 | for (const [key, value] of data1Map) { 278 | if (!data2Map.has(key)) { 279 | onlyInData1.push({ key, value }); 280 | } 281 | } 282 | 283 | // Get files that are only in data2 (potentially moved in) 284 | const onlyInData2 = []; 285 | for (const [key, value] of data2Map) { 286 | if (!data1Map.has(key)) { 287 | onlyInData2.push({ key, value }); 288 | } 289 | } 290 | 291 | // Try to match files by basename and similar size 292 | const matchedMoves = []; 293 | 294 | for (const item1 of onlyInData1) { 295 | const basename1 = this.getBasename(item1.key); 296 | const size1 = item1.value.size; 297 | 298 | for (const item2 of onlyInData2) { 299 | const basename2 = this.getBasename(item2.key); 300 | const size2 = item2.value.size; 301 | 302 | // Check if basenames match and sizes are similar (within 10% tolerance) 303 | if (basename1 === basename2 && this.sizesAreSimilar(size1, size2)) { 304 | matchedMoves.push({ 305 | oldKey: item1.key, 306 | newKey: item2.key, 307 | oldValue: item1.value, 308 | newValue: item2.value, 309 | basename: basename1 310 | }); 311 | break; // Move to next item1 after finding a match 312 | } 313 | } 314 | } 315 | 316 | // Process matched moves 317 | for (const move of matchedMoves) { 318 | // Use the new path as the canonical key 319 | const canonicalKey = move.newKey; 320 | 321 | // Create move info 322 | const moveDetails = { 323 | oldPath: move.oldValue.originalPath, 324 | newPath: move.newValue.originalPath, 325 | displayName: `${move.basename} (moved from ${this.getDirectoryPath(move.oldKey)} to ${this.getDirectoryPath(move.newKey)})` 326 | }; 327 | 328 | // Remove the individual entries 329 | mergedData1.delete(move.oldKey); 330 | mergedData2.delete(move.newKey); 331 | 332 | // Add the moved file with combined info 333 | mergedData1.set(canonicalKey, { 334 | ...move.oldValue, 335 | moveInfo: moveDetails 336 | }); 337 | 338 | mergedData2.set(canonicalKey, { 339 | ...move.newValue, 340 | moveInfo: moveDetails 341 | }); 342 | } 343 | 344 | return { mergedData1, mergedData2, moveInfo: matchedMoves }; 345 | } 346 | 347 | static getBasename(filePath) { 348 | // Extract the basename (filename without directory path) 349 | const parts = filePath.split('/'); 350 | return parts[parts.length - 1]; 351 | } 352 | 353 | static getDirectoryPath(filePath) { 354 | // Extract the directory path (everything except the basename) 355 | const parts = filePath.split('/'); 356 | return parts.slice(0, -1).join('/') || '/'; 357 | } 358 | 359 | static sizesAreSimilar(size1, size2, tolerance = 0.1) { 360 | // Check if sizes are similar within tolerance percentage 361 | if (size1 === 0 && size2 === 0) return true; 362 | if (size1 === 0 || size2 === 0) return false; 363 | 364 | const diff = Math.abs(size1 - size2); 365 | const average = (size1 + size2) / 2; 366 | return (diff / average) <= tolerance; 367 | } 368 | 369 | static processData(data1, data2, includeVMSize = true, includeFileSize = true, changeThreshold = 50) { 370 | // Create maps for fast lookup 371 | const data1Map = new Map(); 372 | const data2Map = new Map(); 373 | 374 | // Process first dataset 375 | data1.forEach(row => { 376 | const compileUnit = this.normalizeFilePath(row.compileunits); 377 | const vmsize = parseInt(row.vmsize) || 0; 378 | const filesize = parseInt(row.filesize) || 0; 379 | 380 | let totalSize = 0; 381 | if (includeVMSize) totalSize += vmsize; 382 | if (includeFileSize) totalSize += filesize; 383 | 384 | data1Map.set(compileUnit, { 385 | vmsize, 386 | filesize, 387 | totalSize, 388 | compileUnit 389 | }); 390 | }); 391 | 392 | // Process second dataset 393 | data2.forEach(row => { 394 | const compileUnit = this.normalizeFilePath(row.compileunits); 395 | const vmsize = parseInt(row.vmsize) || 0; 396 | const filesize = parseInt(row.filesize) || 0; 397 | 398 | let totalSize = 0; 399 | if (includeVMSize) totalSize += vmsize; 400 | if (includeFileSize) totalSize += filesize; 401 | 402 | data2Map.set(compileUnit, { 403 | vmsize, 404 | filesize, 405 | totalSize, 406 | compileUnit 407 | }); 408 | }); 409 | 410 | // Compare and create comparison data 411 | const comparisons = []; 412 | const allKeys = new Set([...data1Map.keys(), ...data2Map.keys()]); 413 | 414 | allKeys.forEach(compileUnit => { 415 | const item1 = data1Map.get(compileUnit); 416 | const item2 = data2Map.get(compileUnit); 417 | 418 | const size1 = item1 ? item1.totalSize : 0; 419 | const size2 = item2 ? item2.totalSize : 0; 420 | const difference = size2 - size1; 421 | const percentChange = size1 > 0 ? ((difference / size1) * 100) : (size2 > 0 ? 100 : 0); 422 | 423 | let changeType = 'unchanged'; 424 | if (Math.abs(difference) > changeThreshold) { 425 | changeType = difference > 0 ? 'increased' : 'decreased'; 426 | } 427 | 428 | comparisons.push({ 429 | compileUnit, 430 | size1, 431 | size2, 432 | difference, 433 | percentChange, 434 | changeType, 435 | vmsize1: item1 ? item1.vmsize : 0, 436 | filesize1: item1 ? item1.filesize : 0, 437 | vmsize2: item2 ? item2.vmsize : 0, 438 | filesize2: item2 ? item2.filesize : 0 439 | }); 440 | }); 441 | 442 | // Sort by absolute difference (largest changes first) 443 | comparisons.sort((a, b) => Math.abs(b.difference) - Math.abs(a.difference)); 444 | 445 | return comparisons; 446 | } 447 | 448 | static generateSummary(comparisons) { 449 | const summary = { 450 | totalFiles: comparisons.length, 451 | unchanged: 0, 452 | increased: 0, 453 | decreased: 0, 454 | totalSizeChange: 0, 455 | largestIncrease: null, 456 | largestDecrease: null 457 | }; 458 | 459 | comparisons.forEach(comp => { 460 | summary.totalSizeChange += comp.difference; 461 | 462 | switch (comp.changeType) { 463 | case 'unchanged': 464 | summary.unchanged++; 465 | break; 466 | case 'increased': 467 | summary.increased++; 468 | if (!summary.largestIncrease || comp.difference > summary.largestIncrease.difference) { 469 | summary.largestIncrease = comp; 470 | } 471 | break; 472 | case 'decreased': 473 | summary.decreased++; 474 | if (!summary.largestDecrease || comp.difference < summary.largestDecrease.difference) { 475 | summary.largestDecrease = comp; 476 | } 477 | break; 478 | } 479 | }); 480 | 481 | return summary; 482 | } 483 | 484 | static formatBytes(bytes) { 485 | if (bytes === 0) return '0 B'; 486 | 487 | const k = 1024; 488 | const sizes = ['B', 'KB', 'MB', 'GB']; 489 | const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(k)); 490 | 491 | return (bytes / Math.pow(k, i)).toFixed(1) + ' ' + sizes[i]; 492 | } 493 | 494 | static formatNumber(num) { 495 | return num.toLocaleString(); 496 | } 497 | 498 | static formatPercentage(percent) { 499 | return (percent >= 0 ? '+' : '') + percent.toFixed(1) + '%'; 500 | } 501 | 502 | static prepareForVisualization(comparisons, hideUnchanged = false) { 503 | let filteredComparisons = comparisons; 504 | 505 | if (hideUnchanged) { 506 | filteredComparisons = comparisons.filter(comp => comp.changeType !== 'unchanged'); 507 | } 508 | 509 | // Group by change type for better visualization 510 | const groups = { 511 | unchanged: filteredComparisons.filter(comp => comp.changeType === 'unchanged'), 512 | decreased: filteredComparisons.filter(comp => comp.changeType === 'decreased'), 513 | increased: filteredComparisons.filter(comp => comp.changeType === 'increased') 514 | }; 515 | 516 | return { 517 | all: filteredComparisons, 518 | groups: groups, 519 | maxSize: Math.max(...filteredComparisons.map(comp => Math.max(comp.size1, comp.size2))) 520 | }; 521 | } 522 | } -------------------------------------------------------------------------------- /size-analyzer/analysis_index.json: -------------------------------------------------------------------------------- 1 | { 2 | "platforms": { 3 | "arm64-android": { 4 | "versions": [ 5 | { 6 | "version": "1.9.0", 7 | "sha1": "d6882f432beca85d460ec42497888157c356d058" 8 | }, 9 | { 10 | "version": "1.9.1", 11 | "sha1": "3be87d89fd5a93a63f527351fbedb84f8a875812" 12 | }, 13 | { 14 | "version": "1.9.2", 15 | "sha1": "3251ca82359cf238a1074e383281e3126547d50b" 16 | }, 17 | { 18 | "version": "1.9.3", 19 | "sha1": "e4aaff11f49c941fde1dd93883cf69c6b8abebe4" 20 | }, 21 | { 22 | "version": "1.9.4", 23 | "sha1": "512763fd375633fd67197225e61fe90a5929166b" 24 | }, 25 | { 26 | "version": "1.9.5", 27 | "sha1": "87b6907759f7b8dff830d54b2250b8d721bde291" 28 | }, 29 | { 30 | "version": "1.9.6", 31 | "sha1": "4035511f1e258a47b77798a2005c024609ed2c67" 32 | }, 33 | { 34 | "version": "1.9.7", 35 | "sha1": "a1ae95286a1b2677ed3fda6785816e76df4ee8a2" 36 | }, 37 | { 38 | "version": "1.9.8", 39 | "sha1": "a9247e38b24ba1c1ed5913c4049d9a4083a314a7" 40 | }, 41 | { 42 | "version": "1.10.0", 43 | "sha1": "591eb496d52f4140bc2c7de547131f1b9408b9b4" 44 | }, 45 | { 46 | "version": "1.10.1", 47 | "sha1": "2783cc609cd52bc5ac92ec9e35b9b854f5f07882" 48 | }, 49 | { 50 | "version": "1.10.2", 51 | "sha1": "f56fcca509a9fa5350bf55f18d8c6087295a8cef" 52 | }, 53 | { 54 | "version": "1.10.3", 55 | "sha1": "1c76521bb8b08c63ef619aa8a5ab563dddf7b3cf" 56 | }, 57 | { 58 | "version": "1.10.4", 59 | "sha1": "1aafd0a262ff40214ed7f51302d92fa587c607ef" 60 | }, 61 | { 62 | "version": "1.11.0", 63 | "sha1": "7c81792859a6da7f7401c0ac37a4cc83bb500ff6" 64 | }, 65 | { 66 | "version": "1.11.1", 67 | "sha1": "1ba9e1aa422166864c3267f03f5110144b745c1e" 68 | }, 69 | { 70 | "version": "1.11.2", 71 | "sha1": "a6d86c0083f00ee6c3709478ff3b33deff5e6d19" 72 | } 73 | ] 74 | }, 75 | "armv7-android": { 76 | "versions": [ 77 | { 78 | "version": "1.9.0", 79 | "sha1": "d6882f432beca85d460ec42497888157c356d058" 80 | }, 81 | { 82 | "version": "1.9.1", 83 | "sha1": "3be87d89fd5a93a63f527351fbedb84f8a875812" 84 | }, 85 | { 86 | "version": "1.9.2", 87 | "sha1": "3251ca82359cf238a1074e383281e3126547d50b" 88 | }, 89 | { 90 | "version": "1.9.3", 91 | "sha1": "e4aaff11f49c941fde1dd93883cf69c6b8abebe4" 92 | }, 93 | { 94 | "version": "1.9.4", 95 | "sha1": "512763fd375633fd67197225e61fe90a5929166b" 96 | }, 97 | { 98 | "version": "1.9.5", 99 | "sha1": "87b6907759f7b8dff830d54b2250b8d721bde291" 100 | }, 101 | { 102 | "version": "1.9.6", 103 | "sha1": "4035511f1e258a47b77798a2005c024609ed2c67" 104 | }, 105 | { 106 | "version": "1.9.7", 107 | "sha1": "a1ae95286a1b2677ed3fda6785816e76df4ee8a2" 108 | }, 109 | { 110 | "version": "1.9.8", 111 | "sha1": "a9247e38b24ba1c1ed5913c4049d9a4083a314a7" 112 | }, 113 | { 114 | "version": "1.10.0", 115 | "sha1": "591eb496d52f4140bc2c7de547131f1b9408b9b4" 116 | }, 117 | { 118 | "version": "1.10.1", 119 | "sha1": "2783cc609cd52bc5ac92ec9e35b9b854f5f07882" 120 | }, 121 | { 122 | "version": "1.10.2", 123 | "sha1": "f56fcca509a9fa5350bf55f18d8c6087295a8cef" 124 | }, 125 | { 126 | "version": "1.10.3", 127 | "sha1": "1c76521bb8b08c63ef619aa8a5ab563dddf7b3cf" 128 | }, 129 | { 130 | "version": "1.10.4", 131 | "sha1": "1aafd0a262ff40214ed7f51302d92fa587c607ef" 132 | }, 133 | { 134 | "version": "1.11.0", 135 | "sha1": "7c81792859a6da7f7401c0ac37a4cc83bb500ff6" 136 | }, 137 | { 138 | "version": "1.11.1", 139 | "sha1": "1ba9e1aa422166864c3267f03f5110144b745c1e" 140 | }, 141 | { 142 | "version": "1.11.2", 143 | "sha1": "a6d86c0083f00ee6c3709478ff3b33deff5e6d19" 144 | } 145 | ] 146 | }, 147 | "arm64-ios": { 148 | "versions": [ 149 | { 150 | "version": "1.9.0", 151 | "sha1": "d6882f432beca85d460ec42497888157c356d058" 152 | }, 153 | { 154 | "version": "1.9.1", 155 | "sha1": "3be87d89fd5a93a63f527351fbedb84f8a875812" 156 | }, 157 | { 158 | "version": "1.9.2", 159 | "sha1": "3251ca82359cf238a1074e383281e3126547d50b" 160 | }, 161 | { 162 | "version": "1.9.3", 163 | "sha1": "e4aaff11f49c941fde1dd93883cf69c6b8abebe4" 164 | }, 165 | { 166 | "version": "1.9.4", 167 | "sha1": "512763fd375633fd67197225e61fe90a5929166b" 168 | }, 169 | { 170 | "version": "1.9.5", 171 | "sha1": "87b6907759f7b8dff830d54b2250b8d721bde291" 172 | }, 173 | { 174 | "version": "1.9.6", 175 | "sha1": "4035511f1e258a47b77798a2005c024609ed2c67" 176 | }, 177 | { 178 | "version": "1.9.7", 179 | "sha1": "a1ae95286a1b2677ed3fda6785816e76df4ee8a2" 180 | }, 181 | { 182 | "version": "1.9.8", 183 | "sha1": "a9247e38b24ba1c1ed5913c4049d9a4083a314a7" 184 | }, 185 | { 186 | "version": "1.10.0", 187 | "sha1": "591eb496d52f4140bc2c7de547131f1b9408b9b4" 188 | }, 189 | { 190 | "version": "1.10.1", 191 | "sha1": "2783cc609cd52bc5ac92ec9e35b9b854f5f07882" 192 | }, 193 | { 194 | "version": "1.10.2", 195 | "sha1": "f56fcca509a9fa5350bf55f18d8c6087295a8cef" 196 | }, 197 | { 198 | "version": "1.10.3", 199 | "sha1": "1c76521bb8b08c63ef619aa8a5ab563dddf7b3cf" 200 | }, 201 | { 202 | "version": "1.10.4", 203 | "sha1": "1aafd0a262ff40214ed7f51302d92fa587c607ef" 204 | }, 205 | { 206 | "version": "1.11.0", 207 | "sha1": "7c81792859a6da7f7401c0ac37a4cc83bb500ff6" 208 | }, 209 | { 210 | "version": "1.11.1", 211 | "sha1": "1ba9e1aa422166864c3267f03f5110144b745c1e" 212 | }, 213 | { 214 | "version": "1.11.2", 215 | "sha1": "a6d86c0083f00ee6c3709478ff3b33deff5e6d19" 216 | } 217 | ] 218 | }, 219 | "x86_64-macos": { 220 | "versions": [ 221 | { 222 | "version": "1.9.0", 223 | "sha1": "d6882f432beca85d460ec42497888157c356d058" 224 | }, 225 | { 226 | "version": "1.9.1", 227 | "sha1": "3be87d89fd5a93a63f527351fbedb84f8a875812" 228 | }, 229 | { 230 | "version": "1.9.2", 231 | "sha1": "3251ca82359cf238a1074e383281e3126547d50b" 232 | }, 233 | { 234 | "version": "1.9.3", 235 | "sha1": "e4aaff11f49c941fde1dd93883cf69c6b8abebe4" 236 | }, 237 | { 238 | "version": "1.9.4", 239 | "sha1": "512763fd375633fd67197225e61fe90a5929166b" 240 | }, 241 | { 242 | "version": "1.9.5", 243 | "sha1": "87b6907759f7b8dff830d54b2250b8d721bde291" 244 | }, 245 | { 246 | "version": "1.9.6", 247 | "sha1": "4035511f1e258a47b77798a2005c024609ed2c67" 248 | }, 249 | { 250 | "version": "1.9.7", 251 | "sha1": "a1ae95286a1b2677ed3fda6785816e76df4ee8a2" 252 | }, 253 | { 254 | "version": "1.9.8", 255 | "sha1": "a9247e38b24ba1c1ed5913c4049d9a4083a314a7" 256 | }, 257 | { 258 | "version": "1.10.0", 259 | "sha1": "591eb496d52f4140bc2c7de547131f1b9408b9b4" 260 | }, 261 | { 262 | "version": "1.10.1", 263 | "sha1": "2783cc609cd52bc5ac92ec9e35b9b854f5f07882" 264 | }, 265 | { 266 | "version": "1.10.2", 267 | "sha1": "f56fcca509a9fa5350bf55f18d8c6087295a8cef" 268 | }, 269 | { 270 | "version": "1.10.3", 271 | "sha1": "1c76521bb8b08c63ef619aa8a5ab563dddf7b3cf" 272 | }, 273 | { 274 | "version": "1.10.4", 275 | "sha1": "1aafd0a262ff40214ed7f51302d92fa587c607ef" 276 | }, 277 | { 278 | "version": "1.11.0", 279 | "sha1": "7c81792859a6da7f7401c0ac37a4cc83bb500ff6" 280 | }, 281 | { 282 | "version": "1.11.1", 283 | "sha1": "1ba9e1aa422166864c3267f03f5110144b745c1e" 284 | }, 285 | { 286 | "version": "1.11.2", 287 | "sha1": "a6d86c0083f00ee6c3709478ff3b33deff5e6d19" 288 | } 289 | ] 290 | }, 291 | "arm64-macos": { 292 | "versions": [ 293 | { 294 | "version": "1.9.0", 295 | "sha1": "d6882f432beca85d460ec42497888157c356d058" 296 | }, 297 | { 298 | "version": "1.9.1", 299 | "sha1": "3be87d89fd5a93a63f527351fbedb84f8a875812" 300 | }, 301 | { 302 | "version": "1.9.2", 303 | "sha1": "3251ca82359cf238a1074e383281e3126547d50b" 304 | }, 305 | { 306 | "version": "1.9.3", 307 | "sha1": "e4aaff11f49c941fde1dd93883cf69c6b8abebe4" 308 | }, 309 | { 310 | "version": "1.9.4", 311 | "sha1": "512763fd375633fd67197225e61fe90a5929166b" 312 | }, 313 | { 314 | "version": "1.9.5", 315 | "sha1": "87b6907759f7b8dff830d54b2250b8d721bde291" 316 | }, 317 | { 318 | "version": "1.9.6", 319 | "sha1": "4035511f1e258a47b77798a2005c024609ed2c67" 320 | }, 321 | { 322 | "version": "1.9.7", 323 | "sha1": "a1ae95286a1b2677ed3fda6785816e76df4ee8a2" 324 | }, 325 | { 326 | "version": "1.9.8", 327 | "sha1": "a9247e38b24ba1c1ed5913c4049d9a4083a314a7" 328 | }, 329 | { 330 | "version": "1.10.0", 331 | "sha1": "591eb496d52f4140bc2c7de547131f1b9408b9b4" 332 | }, 333 | { 334 | "version": "1.10.1", 335 | "sha1": "2783cc609cd52bc5ac92ec9e35b9b854f5f07882" 336 | }, 337 | { 338 | "version": "1.10.2", 339 | "sha1": "f56fcca509a9fa5350bf55f18d8c6087295a8cef" 340 | }, 341 | { 342 | "version": "1.10.3", 343 | "sha1": "1c76521bb8b08c63ef619aa8a5ab563dddf7b3cf" 344 | }, 345 | { 346 | "version": "1.10.4", 347 | "sha1": "1aafd0a262ff40214ed7f51302d92fa587c607ef" 348 | }, 349 | { 350 | "version": "1.11.0", 351 | "sha1": "7c81792859a6da7f7401c0ac37a4cc83bb500ff6" 352 | }, 353 | { 354 | "version": "1.11.1", 355 | "sha1": "1ba9e1aa422166864c3267f03f5110144b745c1e" 356 | }, 357 | { 358 | "version": "1.11.2", 359 | "sha1": "a6d86c0083f00ee6c3709478ff3b33deff5e6d19" 360 | } 361 | ] 362 | }, 363 | "bob.jar": { 364 | "versions": [ 365 | { 366 | "version": "1.9.0", 367 | "sha1": "d6882f432beca85d460ec42497888157c356d058" 368 | }, 369 | { 370 | "version": "1.9.1", 371 | "sha1": "3be87d89fd5a93a63f527351fbedb84f8a875812" 372 | }, 373 | { 374 | "version": "1.9.2", 375 | "sha1": "3251ca82359cf238a1074e383281e3126547d50b" 376 | }, 377 | { 378 | "version": "1.9.3", 379 | "sha1": "e4aaff11f49c941fde1dd93883cf69c6b8abebe4" 380 | }, 381 | { 382 | "version": "1.9.4", 383 | "sha1": "512763fd375633fd67197225e61fe90a5929166b" 384 | }, 385 | { 386 | "version": "1.9.5", 387 | "sha1": "87b6907759f7b8dff830d54b2250b8d721bde291" 388 | }, 389 | { 390 | "version": "1.9.6", 391 | "sha1": "4035511f1e258a47b77798a2005c024609ed2c67" 392 | }, 393 | { 394 | "version": "1.9.7", 395 | "sha1": "a1ae95286a1b2677ed3fda6785816e76df4ee8a2" 396 | }, 397 | { 398 | "version": "1.9.8", 399 | "sha1": "a9247e38b24ba1c1ed5913c4049d9a4083a314a7" 400 | }, 401 | { 402 | "version": "1.10.0", 403 | "sha1": "591eb496d52f4140bc2c7de547131f1b9408b9b4" 404 | }, 405 | { 406 | "version": "1.10.1", 407 | "sha1": "2783cc609cd52bc5ac92ec9e35b9b854f5f07882" 408 | }, 409 | { 410 | "version": "1.10.2", 411 | "sha1": "f56fcca509a9fa5350bf55f18d8c6087295a8cef" 412 | }, 413 | { 414 | "version": "1.10.3", 415 | "sha1": "1c76521bb8b08c63ef619aa8a5ab563dddf7b3cf" 416 | }, 417 | { 418 | "version": "1.10.4", 419 | "sha1": "1aafd0a262ff40214ed7f51302d92fa587c607ef" 420 | }, 421 | { 422 | "version": "1.11.0", 423 | "sha1": "7c81792859a6da7f7401c0ac37a4cc83bb500ff6" 424 | }, 425 | { 426 | "version": "1.11.1", 427 | "sha1": "1ba9e1aa422166864c3267f03f5110144b745c1e" 428 | }, 429 | { 430 | "version": "1.11.2", 431 | "sha1": "a6d86c0083f00ee6c3709478ff3b33deff5e6d19" 432 | } 433 | ] 434 | }, 435 | "editor-win32": { 436 | "versions": [ 437 | { 438 | "version": "1.9.0", 439 | "sha1": "d6882f432beca85d460ec42497888157c356d058" 440 | }, 441 | { 442 | "version": "1.9.1", 443 | "sha1": "3be87d89fd5a93a63f527351fbedb84f8a875812" 444 | }, 445 | { 446 | "version": "1.9.2", 447 | "sha1": "3251ca82359cf238a1074e383281e3126547d50b" 448 | }, 449 | { 450 | "version": "1.9.3", 451 | "sha1": "e4aaff11f49c941fde1dd93883cf69c6b8abebe4" 452 | }, 453 | { 454 | "version": "1.9.4", 455 | "sha1": "512763fd375633fd67197225e61fe90a5929166b" 456 | }, 457 | { 458 | "version": "1.9.5", 459 | "sha1": "87b6907759f7b8dff830d54b2250b8d721bde291" 460 | }, 461 | { 462 | "version": "1.9.6", 463 | "sha1": "4035511f1e258a47b77798a2005c024609ed2c67" 464 | }, 465 | { 466 | "version": "1.9.7", 467 | "sha1": "a1ae95286a1b2677ed3fda6785816e76df4ee8a2" 468 | }, 469 | { 470 | "version": "1.9.8", 471 | "sha1": "a9247e38b24ba1c1ed5913c4049d9a4083a314a7" 472 | }, 473 | { 474 | "version": "1.10.0", 475 | "sha1": "591eb496d52f4140bc2c7de547131f1b9408b9b4" 476 | }, 477 | { 478 | "version": "1.10.1", 479 | "sha1": "2783cc609cd52bc5ac92ec9e35b9b854f5f07882" 480 | }, 481 | { 482 | "version": "1.10.2", 483 | "sha1": "f56fcca509a9fa5350bf55f18d8c6087295a8cef" 484 | }, 485 | { 486 | "version": "1.10.3", 487 | "sha1": "1c76521bb8b08c63ef619aa8a5ab563dddf7b3cf" 488 | }, 489 | { 490 | "version": "1.10.4", 491 | "sha1": "1aafd0a262ff40214ed7f51302d92fa587c607ef" 492 | }, 493 | { 494 | "version": "1.11.0", 495 | "sha1": "7c81792859a6da7f7401c0ac37a4cc83bb500ff6" 496 | }, 497 | { 498 | "version": "1.11.1", 499 | "sha1": "1ba9e1aa422166864c3267f03f5110144b745c1e" 500 | }, 501 | { 502 | "version": "1.11.2", 503 | "sha1": "a6d86c0083f00ee6c3709478ff3b33deff5e6d19" 504 | } 505 | ] 506 | }, 507 | "editor-x86_64-linux": { 508 | "versions": [ 509 | { 510 | "version": "1.9.0", 511 | "sha1": "d6882f432beca85d460ec42497888157c356d058" 512 | }, 513 | { 514 | "version": "1.9.1", 515 | "sha1": "3be87d89fd5a93a63f527351fbedb84f8a875812" 516 | }, 517 | { 518 | "version": "1.9.2", 519 | "sha1": "3251ca82359cf238a1074e383281e3126547d50b" 520 | }, 521 | { 522 | "version": "1.9.3", 523 | "sha1": "e4aaff11f49c941fde1dd93883cf69c6b8abebe4" 524 | }, 525 | { 526 | "version": "1.9.4", 527 | "sha1": "512763fd375633fd67197225e61fe90a5929166b" 528 | }, 529 | { 530 | "version": "1.9.5", 531 | "sha1": "87b6907759f7b8dff830d54b2250b8d721bde291" 532 | }, 533 | { 534 | "version": "1.9.6", 535 | "sha1": "4035511f1e258a47b77798a2005c024609ed2c67" 536 | }, 537 | { 538 | "version": "1.9.7", 539 | "sha1": "a1ae95286a1b2677ed3fda6785816e76df4ee8a2" 540 | }, 541 | { 542 | "version": "1.9.8", 543 | "sha1": "a9247e38b24ba1c1ed5913c4049d9a4083a314a7" 544 | }, 545 | { 546 | "version": "1.10.0", 547 | "sha1": "591eb496d52f4140bc2c7de547131f1b9408b9b4" 548 | }, 549 | { 550 | "version": "1.10.1", 551 | "sha1": "2783cc609cd52bc5ac92ec9e35b9b854f5f07882" 552 | }, 553 | { 554 | "version": "1.10.2", 555 | "sha1": "f56fcca509a9fa5350bf55f18d8c6087295a8cef" 556 | }, 557 | { 558 | "version": "1.10.3", 559 | "sha1": "1c76521bb8b08c63ef619aa8a5ab563dddf7b3cf" 560 | }, 561 | { 562 | "version": "1.10.4", 563 | "sha1": "1aafd0a262ff40214ed7f51302d92fa587c607ef" 564 | }, 565 | { 566 | "version": "1.11.0", 567 | "sha1": "7c81792859a6da7f7401c0ac37a4cc83bb500ff6" 568 | }, 569 | { 570 | "version": "1.11.1", 571 | "sha1": "1ba9e1aa422166864c3267f03f5110144b745c1e" 572 | }, 573 | { 574 | "version": "1.11.2", 575 | "sha1": "a6d86c0083f00ee6c3709478ff3b33deff5e6d19" 576 | } 577 | ] 578 | }, 579 | "editor-x86_64-macos": { 580 | "versions": [ 581 | { 582 | "version": "1.9.0", 583 | "sha1": "d6882f432beca85d460ec42497888157c356d058" 584 | }, 585 | { 586 | "version": "1.9.1", 587 | "sha1": "3be87d89fd5a93a63f527351fbedb84f8a875812" 588 | }, 589 | { 590 | "version": "1.9.2", 591 | "sha1": "3251ca82359cf238a1074e383281e3126547d50b" 592 | }, 593 | { 594 | "version": "1.9.3", 595 | "sha1": "e4aaff11f49c941fde1dd93883cf69c6b8abebe4" 596 | }, 597 | { 598 | "version": "1.9.4", 599 | "sha1": "512763fd375633fd67197225e61fe90a5929166b" 600 | }, 601 | { 602 | "version": "1.9.5", 603 | "sha1": "87b6907759f7b8dff830d54b2250b8d721bde291" 604 | }, 605 | { 606 | "version": "1.9.6", 607 | "sha1": "4035511f1e258a47b77798a2005c024609ed2c67" 608 | }, 609 | { 610 | "version": "1.9.7", 611 | "sha1": "a1ae95286a1b2677ed3fda6785816e76df4ee8a2" 612 | }, 613 | { 614 | "version": "1.9.8", 615 | "sha1": "a9247e38b24ba1c1ed5913c4049d9a4083a314a7" 616 | }, 617 | { 618 | "version": "1.10.0", 619 | "sha1": "591eb496d52f4140bc2c7de547131f1b9408b9b4" 620 | }, 621 | { 622 | "version": "1.10.1", 623 | "sha1": "2783cc609cd52bc5ac92ec9e35b9b854f5f07882" 624 | }, 625 | { 626 | "version": "1.10.2", 627 | "sha1": "f56fcca509a9fa5350bf55f18d8c6087295a8cef" 628 | }, 629 | { 630 | "version": "1.10.3", 631 | "sha1": "1c76521bb8b08c63ef619aa8a5ab563dddf7b3cf" 632 | }, 633 | { 634 | "version": "1.10.4", 635 | "sha1": "1aafd0a262ff40214ed7f51302d92fa587c607ef" 636 | }, 637 | { 638 | "version": "1.11.0", 639 | "sha1": "7c81792859a6da7f7401c0ac37a4cc83bb500ff6" 640 | }, 641 | { 642 | "version": "1.11.1", 643 | "sha1": "1ba9e1aa422166864c3267f03f5110144b745c1e" 644 | }, 645 | { 646 | "version": "1.11.2", 647 | "sha1": "a6d86c0083f00ee6c3709478ff3b33deff5e6d19" 648 | } 649 | ] 650 | }, 651 | "editor-arm64-macos": { 652 | "versions": [ 653 | { 654 | "version": "1.9.0", 655 | "sha1": "d6882f432beca85d460ec42497888157c356d058" 656 | }, 657 | { 658 | "version": "1.9.1", 659 | "sha1": "3be87d89fd5a93a63f527351fbedb84f8a875812" 660 | }, 661 | { 662 | "version": "1.9.2", 663 | "sha1": "3251ca82359cf238a1074e383281e3126547d50b" 664 | }, 665 | { 666 | "version": "1.9.3", 667 | "sha1": "e4aaff11f49c941fde1dd93883cf69c6b8abebe4" 668 | }, 669 | { 670 | "version": "1.9.4", 671 | "sha1": "512763fd375633fd67197225e61fe90a5929166b" 672 | }, 673 | { 674 | "version": "1.9.5", 675 | "sha1": "87b6907759f7b8dff830d54b2250b8d721bde291" 676 | }, 677 | { 678 | "version": "1.9.6", 679 | "sha1": "4035511f1e258a47b77798a2005c024609ed2c67" 680 | }, 681 | { 682 | "version": "1.9.7", 683 | "sha1": "a1ae95286a1b2677ed3fda6785816e76df4ee8a2" 684 | }, 685 | { 686 | "version": "1.9.8", 687 | "sha1": "a9247e38b24ba1c1ed5913c4049d9a4083a314a7" 688 | }, 689 | { 690 | "version": "1.10.0", 691 | "sha1": "591eb496d52f4140bc2c7de547131f1b9408b9b4" 692 | }, 693 | { 694 | "version": "1.10.1", 695 | "sha1": "2783cc609cd52bc5ac92ec9e35b9b854f5f07882" 696 | }, 697 | { 698 | "version": "1.10.2", 699 | "sha1": "f56fcca509a9fa5350bf55f18d8c6087295a8cef" 700 | }, 701 | { 702 | "version": "1.10.3", 703 | "sha1": "1c76521bb8b08c63ef619aa8a5ab563dddf7b3cf" 704 | }, 705 | { 706 | "version": "1.10.4", 707 | "sha1": "1aafd0a262ff40214ed7f51302d92fa587c607ef" 708 | }, 709 | { 710 | "version": "1.11.0", 711 | "sha1": "7c81792859a6da7f7401c0ac37a4cc83bb500ff6" 712 | }, 713 | { 714 | "version": "1.11.1", 715 | "sha1": "1ba9e1aa422166864c3267f03f5110144b745c1e" 716 | }, 717 | { 718 | "version": "1.11.2", 719 | "sha1": "a6d86c0083f00ee6c3709478ff3b33deff5e6d19" 720 | } 721 | ] 722 | } 723 | } 724 | } -------------------------------------------------------------------------------- /releases.json: -------------------------------------------------------------------------------- 1 | { 2 | "releases": [ 3 | { 4 | "version": "1.2.38", 5 | "sha1": "d0fdb9c5fc1ac46debbbc39e8ac572b6fa7652f7" 6 | }, 7 | { 8 | "version": "1.2.39", 9 | "sha1": "4c263ff84c19de1f6304e9c2cf756bf572009d38" 10 | }, 11 | { 12 | "version": "1.2.40", 13 | "sha1": "b8b46b391ee60a5762024931f92d7cf90650b0dc" 14 | }, 15 | { 16 | "version": "1.2.41", 17 | "sha1": "95d50f8ef9f04617a6498f6412dac3aab960dc6e" 18 | }, 19 | { 20 | "version": "1.2.42", 21 | "sha1": "b10ae21d0ef877e91fc91c89d39399d6a8a56caf" 22 | }, 23 | { 24 | "version": "1.2.43", 25 | "sha1": "a10a45eba9544958b7d64d4dbe90cf8e3eabcf0e" 26 | }, 27 | { 28 | "version": "1.2.44", 29 | "sha1": "30d355de2d97ef54fabaa53938a52963dec8f88c" 30 | }, 31 | { 32 | "version": "1.2.45", 33 | "sha1": "4a5a22d288d6bc2806a4a79d2162124f94059b9f" 34 | }, 35 | { 36 | "version": "1.2.46", 37 | "sha1": "af94d38e4bc8fa29f807025f07b25d6c2d38efe0" 38 | }, 39 | { 40 | "version": "1.2.47", 41 | "sha1": "445d9ce11e76531c6a3823743617b2937aa2bc8a" 42 | }, 43 | { 44 | "version": "1.2.48", 45 | "sha1": "4886ef433cd87a45ca5a447af8bc568e4409bd52" 46 | }, 47 | { 48 | "version": "1.2.49", 49 | "sha1": "84a19985eb2912d17bb571d61473c5d6be66c9b1" 50 | }, 51 | { 52 | "version": "1.2.50", 53 | "sha1": "44be13348c6547916506d18c763ac96665e21f65" 54 | }, 55 | { 56 | "version": "1.2.51", 57 | "sha1": "9dcd71c92feb7bbc8bcb00e24c29a6f86d76e97a" 58 | }, 59 | { 60 | "version": "1.2.52", 61 | "sha1": "1b7762c5433a293fb7181eb8347f776f35ea8e09" 62 | }, 63 | { 64 | "version": "1.2.53", 65 | "sha1": "a1b8f3d533e7f8713fdee217badce2d1acdc71c2" 66 | }, 67 | { 68 | "version": "1.2.54", 69 | "sha1": "d9baebe87893f1d220660773a3e7ae8932e6f5a9" 70 | }, 71 | { 72 | "version": "1.2.55", 73 | "sha1": "ed97ba8447a25c71eeed7b690497ae5a3c42f9a7" 74 | }, 75 | { 76 | "version": "1.2.56", 77 | "sha1": "c263328a62ce78fcc86941c680670e1f20e6ce98" 78 | }, 79 | { 80 | "version": "1.2.57", 81 | "sha1": "2b680b3ec7af8a84401ad584d8bc47a246f82947" 82 | }, 83 | { 84 | "version": "1.2.58", 85 | "sha1": "3ffc1a4f07ca69d5d47ff11e510fff4d7993e5b3" 86 | }, 87 | { 88 | "version": "1.2.59", 89 | "sha1": "c85517d64288d5d9f2d3bad146dd192687a6b493" 90 | }, 91 | { 92 | "version": "1.2.60", 93 | "sha1": "f0b34f3292b01184a461f928fcee5aceae741e23" 94 | }, 95 | { 96 | "version": "1.2.61", 97 | "sha1": "bfa38969ef225100fb5d9a1c43414d882f17f09a" 98 | }, 99 | { 100 | "version": "1.2.62", 101 | "sha1": "36f9c452d9ba2ffb14dfbd91b96b963f17ad1a01" 102 | }, 103 | { 104 | "version": "1.2.63", 105 | "sha1": "7053e150cb4412f3bc7af11562e27ac292e1e408" 106 | }, 107 | { 108 | "version": "1.2.64", 109 | "sha1": "1a026deefcdb40e8251606a1c20ec665e277dcd9" 110 | }, 111 | { 112 | "version": "1.2.65", 113 | "sha1": "39f180d1fc4ee616bd9e29a321bd58845317a939" 114 | }, 115 | { 116 | "version": "1.2.66", 117 | "sha1": "b8e108961099b9b70ff82476bed03f6d6606ef4f" 118 | }, 119 | { 120 | "version": "1.2.67", 121 | "sha1": "dd97a77bb97cde6a6a83f2dd25c3884751e9511f" 122 | }, 123 | { 124 | "version": "1.2.68", 125 | "sha1": "dd13311deab181d63775c04be935656fdcbdd7cf" 126 | }, 127 | { 128 | "version": "1.2.69", 129 | "sha1": "18ac5ddf4e9737833068d6e9f8a9e0230f281b68" 130 | }, 131 | { 132 | "version": "1.2.70", 133 | "sha1": "864eba8ab0257ac795c9593334c79f4b3cbbbbb6" 134 | }, 135 | { 136 | "version": "1.2.71", 137 | "sha1": "00c6dbb2506e5b567adec6e6b591e2684914e419" 138 | }, 139 | { 140 | "version": "1.2.72", 141 | "sha1": "181f1cd0d18716abc26524eb83444ec3b1c3455e" 142 | }, 143 | { 144 | "version": "1.2.73", 145 | "sha1": "181bfb10b315d75960210b4b19d13379a154a518" 146 | }, 147 | { 148 | "version": "1.2.74", 149 | "sha1": "5d0293aa4206f0ad6b15c6c373dd85cc24a96454" 150 | }, 151 | { 152 | "version": "1.2.75", 153 | "sha1": "0929102a19fd1c3d3b655a6fd4120fcc59d96ec2" 154 | }, 155 | { 156 | "version": "1.2.76", 157 | "sha1": "85b4c750f5994f7e97460c7395f365c24e2fe215" 158 | }, 159 | { 160 | "version": "1.2.77", 161 | "sha1": "86c9c6e78e532440b82c8400f328730b0d72448e" 162 | }, 163 | { 164 | "version": "1.2.78", 165 | "sha1": "6b5b6a73cc16d52f2e935bd03c305b6722b73772" 166 | }, 167 | { 168 | "version": "1.2.79", 169 | "sha1": "683677d7d655e9c7aa3328ce9c72dd126391447d" 170 | }, 171 | { 172 | "version": "1.2.80", 173 | "sha1": "c7176baed6df55d32c3286ce27c84e1fe45406c4" 174 | }, 175 | { 176 | "version": "1.2.81", 177 | "sha1": "e8e0c7d8d49d99fa51b90887e8cc5d31d7fbcf6d" 178 | }, 179 | { 180 | "version": "1.2.82", 181 | "sha1": "5fb9dca1a7303e505c95c53c18a29d69418cb6d3" 182 | }, 183 | { 184 | "version": "1.2.83", 185 | "sha1": "1f14af3d6d66b328bdcc4b537e5f109c3f4014b9" 186 | }, 187 | { 188 | "version": "1.2.84", 189 | "sha1": "5eb478decad6398828e764ed07ba582c9423bd0b" 190 | }, 191 | { 192 | "version": "1.2.85", 193 | "sha1": "69b592ceb2ff974584085b6877506a6ddc14c157" 194 | }, 195 | { 196 | "version": "1.2.86", 197 | "sha1": "ae263d1a84869f9f7e8d453f86f4591a76bf0564" 198 | }, 199 | { 200 | "version": "1.2.87", 201 | "sha1": "ad5e4d8464435e6b8a51645b6590e6014a454c86" 202 | }, 203 | { 204 | "version": "1.2.88", 205 | "sha1": "0a5b3b315212623e0f09ae240702234aa1808992" 206 | }, 207 | { 208 | "version": "1.2.89", 209 | "sha1": "5ca3dd134cc960c35ecefe12f6dc81a48f212d40" 210 | }, 211 | { 212 | "version": "1.2.90", 213 | "sha1": "5d25bd72acaca1a4bd97038168f8369d370b3645" 214 | }, 215 | { 216 | "version": "1.2.91", 217 | "sha1": "618f38b65e8b867ea81c3ef892bb2b2b8cc959ce" 218 | }, 219 | { 220 | "version": "1.2.92", 221 | "sha1": "619820e3e9df9f588981e816bf77232a05a59eaf" 222 | }, 223 | { 224 | "version": "1.2.93", 225 | "sha1": "f2c010d1fcfe5c619bfcea890feb84d46ef5f47a" 226 | }, 227 | { 228 | "version": "1.2.94", 229 | "sha1": "a9ec217c3e4b486c07a86c935b0cc805b6680480" 230 | }, 231 | { 232 | "version": "1.2.95", 233 | "sha1": "7ca47a7f7aa0e4809e31ab2274fd1693a1fc5a7e" 234 | }, 235 | { 236 | "version": "1.2.96", 237 | "sha1": "0060183cce2e29dbd09c85ece83cbb72068ee050" 238 | }, 239 | { 240 | "version": "1.2.97", 241 | "sha1": "8e1d5f8a8a0e1734c9e873ec72b56bea53f25d87" 242 | }, 243 | { 244 | "version": "1.2.98", 245 | "sha1": "735ff76c8b1f93b3126ff223cd234d7ceb5b886d" 246 | }, 247 | { 248 | "version": "1.2.99", 249 | "sha1": "0d7f8b51658bee90cb38f3d651b3ba072394afed" 250 | }, 251 | { 252 | "version": "1.2.100", 253 | "sha1": "1afccdb2cd42ca3bc7612a0496dfa6d434a8ebf9" 254 | }, 255 | { 256 | "version": "1.2.101", 257 | "sha1": "1e53d81a6306962b64381195f081d442d033ead1" 258 | }, 259 | { 260 | "version": "1.2.102", 261 | "sha1": "d530758af74c2800d0898c591cc7188cc4515476" 262 | }, 263 | { 264 | "version": "1.2.103", 265 | "sha1": "d126b0348d27c684d020e0bd43fde0a2771746f0" 266 | }, 267 | { 268 | "version": "1.2.104", 269 | "sha1": "298b7ce75a1386a26124061dbccfa822df9bc982" 270 | }, 271 | { 272 | "version": "1.2.105", 273 | "sha1": "a285bcf69ac6de9d1cab399768b74968c80cd864" 274 | }, 275 | { 276 | "version": "1.2.106", 277 | "sha1": "dc92d10b96eaa8c0b3e527c76fecb22186d7cd60" 278 | }, 279 | { 280 | "version": "1.2.107", 281 | "sha1": "597b94fc8d88b8f24264d54a59851951d04eae5c" 282 | }, 283 | { 284 | "version": "1.2.108", 285 | "sha1": "8c2083883fdf321a3fa2aa1a1a5d319a82635c10" 286 | }, 287 | { 288 | "version": "1.2.109", 289 | "sha1": "d1aad61476af35638fb6201574c7cc9869733aa6" 290 | }, 291 | { 292 | "version": "1.2.110", 293 | "sha1": "de8a2aeb1843f573c81ab89c07c0ffb5f1c12e58" 294 | }, 295 | { 296 | "version": "1.2.111", 297 | "sha1": "7ba1ba8d65588009458c7f389307d1943d25a683" 298 | }, 299 | { 300 | "version": "1.2.112", 301 | "sha1": "0dde28ca92551934cf34137e33d029cce19b2447" 302 | }, 303 | { 304 | "version": "1.2.113", 305 | "sha1": "e0ad6b7ed96333a156d95855641664f4b76fd0f6" 306 | }, 307 | { 308 | "version": "1.2.114", 309 | "sha1": "5de6a24af5821865121237c3f77f8a42c8a044e2" 310 | }, 311 | { 312 | "version": "1.2.115", 313 | "sha1": "57fb5f1ad5df59262aa415f298f97694debc991c" 314 | }, 315 | { 316 | "version": "1.2.116", 317 | "sha1": "33da4aa91761d531471f364ef1693c2acec16de7" 318 | }, 319 | { 320 | "version": "1.2.117", 321 | "sha1": "4ac025d15c25a9e0dbf14140d2e5d443c2edfdc4" 322 | }, 323 | { 324 | "version": "1.2.118", 325 | "sha1": "0faa10db6bb28907d67358ad5810f3962437f3fd" 326 | }, 327 | { 328 | "version": "1.2.119", 329 | "sha1": "2406775912d235d2579cfe723ab4dbcea2ca77ca" 330 | }, 331 | { 332 | "version": "1.2.120", 333 | "sha1": "c70ad190898e790f8284e8dab0e31c9090476be9" 334 | }, 335 | { 336 | "version": "1.2.121", 337 | "sha1": "9988355914f63362a4292c4827639f0187275e70" 338 | }, 339 | { 340 | "version": "1.2.122", 341 | "sha1": "fce7921da858a71876773c75920b74310ca7ac1f" 342 | }, 343 | { 344 | "version": "1.2.123", 345 | "sha1": "46d8b7e63d7e0f0f4acd545c46d25ca2b227a806" 346 | }, 347 | { 348 | "version": "1.2.124", 349 | "sha1": "e3f2a48e6495946eb8aede3c843471bb037976aa" 350 | }, 351 | { 352 | "version": "1.2.125", 353 | "sha1": "f9995611e4d5befaa75d6b6d7becdd52823e01eb" 354 | }, 355 | { 356 | "version": "1.2.126", 357 | "sha1": "32ba5eaa128e4b54113fb36eb4b9eff33d8582b3" 358 | }, 359 | { 360 | "version": "1.2.127", 361 | "sha1": "c129eafe38a95a1a69eec93679790cd29ab6c0a6" 362 | }, 363 | { 364 | "version": "1.2.128", 365 | "sha1": "477e0e1034b76a6f9e07fb5ead5dc10adcd2ba6d" 366 | }, 367 | { 368 | "version": "1.2.129", 369 | "sha1": "30b201abdb7224683a3b3de2a02b22946dbbd427" 370 | }, 371 | { 372 | "version": "1.2.130", 373 | "sha1": "3abf70ee10dfb24e43529ff2e7ffbf1905ef5c19" 374 | }, 375 | { 376 | "version": "1.2.131", 377 | "sha1": "091e7e02ce492d3c4e493324b9db57d40df69e95" 378 | }, 379 | { 380 | "version": "1.2.132", 381 | "sha1": "09410355c1baf7e474e46cbc2d252f67f673e1dc" 382 | }, 383 | { 384 | "version": "1.2.133", 385 | "sha1": "7b2c2c019d6fa106f78e2e98cd3009a21d4095aa" 386 | }, 387 | { 388 | "version": "1.2.134", 389 | "sha1": "b2ef3a19802728e76adf84d51d02e11d636791a3" 390 | }, 391 | { 392 | "version": "1.2.135", 393 | "sha1": "1b90c9a905d634b766b467e3536458b9210ec812" 394 | }, 395 | { 396 | "version": "1.2.136", 397 | "sha1": "883d660f9894e0d2bcc7f5895c1eaab1153e98b6" 398 | }, 399 | { 400 | "version": "1.2.137", 401 | "sha1": "936eee90249fcf505f8dbe5b215db5d165221cca" 402 | }, 403 | { 404 | "version": "1.2.138", 405 | "sha1": "cd250cdbbace72ce374bf44ad8302739e69f65ec" 406 | }, 407 | { 408 | "version": "1.2.139", 409 | "sha1": "eedf9a7f2aa650143bb7169bf7e209cba80ef527" 410 | }, 411 | { 412 | "version": "1.2.140", 413 | "sha1": "2fc8ff32c9fa3a16c8f4ce44eba8351c054b33dd" 414 | }, 415 | { 416 | "version": "1.2.141", 417 | "sha1": "738e2ebc3cba56027fa00ca27706019bb772871c" 418 | }, 419 | { 420 | "version": "1.2.142", 421 | "sha1": "6230c40dfa051a311aa4005c19097574e062374d" 422 | }, 423 | { 424 | "version": "1.2.143", 425 | "sha1": "d13de133800e52aeda921e270d1d7340d5ac6684" 426 | }, 427 | { 428 | "version": "1.2.144", 429 | "sha1": "8def4b50c9aa049670e698d7dff3dc00d77e42d5" 430 | }, 431 | { 432 | "version": "1.2.145", 433 | "sha1": "9f376d88408bad9088a4187d4f874ae4767a0185" 434 | }, 435 | { 436 | "version": "1.2.146", 437 | "sha1": "851fbeb469987908d2b785fa3964003acc919394" 438 | }, 439 | { 440 | "version": "1.2.147", 441 | "sha1": "5f1c6286a8bb1cfd8505517c1734f6d0666bf5df" 442 | }, 443 | { 444 | "version": "1.2.148", 445 | "sha1": "47c9f8e03623ca3ac511b5a55e6cfcc7e51ce340" 446 | }, 447 | { 448 | "version": "1.2.149", 449 | "sha1": "34bb9603dfcb145c74fbb4f36f4146acea4c4252" 450 | }, 451 | { 452 | "version": "1.2.150", 453 | "sha1": "e79cdece4f5c8498302b3b00591808e3dc5a1827" 454 | }, 455 | { 456 | "version": "1.2.151", 457 | "sha1": "e05232d70b8a6d8c69fcfe968f01b876090ffa06" 458 | }, 459 | { 460 | "version": "1.2.152", 461 | "sha1": "11b1e7662dd68172fca551c52cba248eea16a364" 462 | }, 463 | { 464 | "version": "1.2.153", 465 | "sha1": "89a2b88bceb3b17682f301b2212764ea16761f4c" 466 | }, 467 | { 468 | "version": "1.2.154", 469 | "sha1": "2a329c6cc44abfec727e985898d428d6860f658a" 470 | }, 471 | { 472 | "version": "1.2.155", 473 | "sha1": "838cecd7a26c932e6be73421d98e51ba12f1d462" 474 | }, 475 | { 476 | "version": "1.2.156", 477 | "sha1": "67b68f1e1ac26a3385fb511cdce520fe52387bb0" 478 | }, 479 | { 480 | "version": "1.2.157", 481 | "sha1": "d7042d5368c338ed5d66b6dff9c60a20924385ac" 482 | }, 483 | { 484 | "version": "1.2.158", 485 | "sha1": "3d63d0509cc828c9555afc149cccfea0f7f83c97" 486 | }, 487 | { 488 | "version": "1.2.159", 489 | "sha1": "f7d0a1ba6940e42c7f7e1c208ba484c3c34a135d" 490 | }, 491 | { 492 | "version": "1.2.160", 493 | "sha1": "1a8e53ae9c38a09b742d38dffc6a9f2efdbe6e97" 494 | }, 495 | { 496 | "version": "1.2.161", 497 | "sha1": "45635ad26f85009c52905724e242cc92dd252146" 498 | }, 499 | { 500 | "version": "1.2.162", 501 | "sha1": "e07f3bb9e8c970eceda8dce8efd5905fd67fa720" 502 | }, 503 | { 504 | "version": "1.2.163", 505 | "sha1": "13261949f45c333806c8aac8bd5b08124ca2810f" 506 | }, 507 | { 508 | "version": "1.2.164", 509 | "sha1": "13261949f45c333806c8aac8bd5b08124ca2810f" 510 | }, 511 | { 512 | "version": "1.2.165", 513 | "sha1": "2be2687cbb670c2dbe9cf2e99577bc3338561778" 514 | }, 515 | { 516 | "version": "1.2.166", 517 | "sha1": "5295afb3878441fb12f497df8831148525dcfb10" 518 | }, 519 | { 520 | "version": "1.2.167", 521 | "sha1": "96f7a5e4f617d5f6f4645f30a3e6ff656689435d" 522 | }, 523 | { 524 | "version": "1.2.168", 525 | "sha1": "e22f6d2f81e7c53ebcbfefe703ff22ce5da252c0" 526 | }, 527 | { 528 | "version": "1.2.169", 529 | "sha1": "4ebe7a1d548eae2398717ed46f9d7d1b103d5503" 530 | }, 531 | { 532 | "version": "1.2.170", 533 | "sha1": "5791ee6d96b87e50eee5acd70abaa4026fefef28" 534 | }, 535 | { 536 | "version": "1.2.171", 537 | "sha1": "29b8e598b0bce19b274327c5d9711f78b3bd0c22" 538 | }, 539 | { 540 | "version": "1.2.172", 541 | "sha1": "dedf1ed10d96c92df6e361f5494531c79af4c1cf" 542 | }, 543 | { 544 | "version": "1.2.173", 545 | "sha1": "fe2b689302e79b7cf8c0bc7d934f23587b268c8a" 546 | }, 547 | { 548 | "version": "1.2.174", 549 | "sha1": "8f3e864464062e1b35c207521dc65dfd77899cdf" 550 | }, 551 | { 552 | "version": "1.2.175", 553 | "sha1": "e41438cca6cc1550d4a0131b8fc3858c2a4097f1" 554 | }, 555 | { 556 | "version": "1.2.176", 557 | "sha1": "7107bc8781535e83cbb30734b32d6b32a3039cd0" 558 | }, 559 | { 560 | "version": "1.2.177", 561 | "sha1": "28a2c96432d6329caa4d845967ba76ffcc2fc773" 562 | }, 563 | { 564 | "version": "1.2.178", 565 | "sha1": "d1948ec5629c0f7fe037d199b043391f2929fc58" 566 | }, 567 | { 568 | "version": "1.2.179", 569 | "sha1": "af6a29c2a1e2545e2d033790089c606ac9f0bb7a" 570 | }, 571 | { 572 | "version": "1.2.180", 573 | "sha1": "99c844bd84d5718189de7beb23ea801ddf72778e" 574 | }, 575 | { 576 | "version": "1.2.181", 577 | "sha1": "ff5b94e432eb58dabdb8e367bed9acc5e99e129b" 578 | }, 579 | { 580 | "version": "1.2.182", 581 | "sha1": "1a2776dac6a868eed1a35e41acb0c71a7e17948f" 582 | }, 583 | { 584 | "version": "1.2.183", 585 | "sha1": "7e7ab0f78048390f41d187fb60d1553297a67e5f" 586 | }, 587 | { 588 | "version": "1.2.184", 589 | "sha1": "1f5712609c345f870b691a85d611d4825d22a718" 590 | }, 591 | { 592 | "version": "1.2.185", 593 | "sha1": "0a8d3e879724132afb18d47e0040c2034be07504" 594 | }, 595 | { 596 | "version": "1.2.186", 597 | "sha1": "1f748d5b0a84e8b5c58bf747e4c48d153ef77a52" 598 | }, 599 | { 600 | "version": "1.2.187", 601 | "sha1": "581c6439ae93755a8a6bcf58732c39c724fa193c" 602 | }, 603 | { 604 | "version": "1.2.188", 605 | "sha1": "6bfeea3b13d7b8920483ea2cba9c181a8650b84d" 606 | }, 607 | { 608 | "version": "1.2.189", 609 | "sha1": "794112e7e21be5d00f1cc70bb891b80ded986c6f" 610 | }, 611 | { 612 | "version": "1.2.190", 613 | "sha1": "d31d6397a72178541a5ef6e7ef2bed090d828f58" 614 | }, 615 | { 616 | "version": "1.2.191", 617 | "sha1": "d393bae6a361f86cf2263ab312c9b3cea45253ab" 618 | }, 619 | { 620 | "version": "1.2.192", 621 | "sha1": "84a9c89dfd5a2c3818c01e7c6777169272d9390b" 622 | }, 623 | { 624 | "version": "1.3.0", 625 | "sha1": "0e77ba11ac957ee01878bbde2e6ac0c9fae6dc01" 626 | }, 627 | { 628 | "version": "1.3.1", 629 | "sha1": "06bc078e490fd7d94ec01e38abac989f6cc351a5" 630 | }, 631 | { 632 | "version": "1.3.2", 633 | "sha1": "287c945fab310c324493e08b191ee1b1538ef973" 634 | }, 635 | { 636 | "version": "1.3.3", 637 | "sha1": "287c945fab310c324493e08b191ee1b1538ef973" 638 | }, 639 | { 640 | "version": "1.3.4", 641 | "sha1": "80b1b73fd9cdbd4682c2583403fddfbaf0919107" 642 | }, 643 | { 644 | "version": "1.3.5", 645 | "sha1": "28eafea5a8bfedfddc621a7cd00b39f25bd34922" 646 | }, 647 | { 648 | "version": "1.3.6", 649 | "sha1": "905234d8da2e642f1075c73aaa1bfb72e49199e3" 650 | }, 651 | { 652 | "version": "1.3.7", 653 | "sha1": "f0ad06a2f1fbf0e9cbddbf96162a75bc006d84bb" 654 | }, 655 | { 656 | "version": "1.4.0", 657 | "sha1": "9c44c4a9b6cbc9d0cb66b7027b7c984bf364a568" 658 | }, 659 | { 660 | "version": "1.4.1", 661 | "sha1": "8f96e450ddfb006a99aa134fdd373cace3760571" 662 | }, 663 | { 664 | "version": "1.4.2", 665 | "sha1": "8cd3a634b13f4db51a37607bf32bf3a3b362c8e6" 666 | }, 667 | { 668 | "version": "1.4.3", 669 | "sha1": "8eaab6b1281ce492163428e0e7b2e0fa247a0a93" 670 | }, 671 | { 672 | "version": "1.4.4", 673 | "sha1": "f5e114aaebe25c5242db5f0066af2f5189c09f99" 674 | }, 675 | { 676 | "version": "1.4.5", 677 | "sha1": "3dbbf1dbebd3a8146f6a917d101882a61f56afdc" 678 | }, 679 | { 680 | "version": "1.4.6", 681 | "sha1": "cb8b34230bd42a5e0b68c12441657f06485562a6" 682 | }, 683 | { 684 | "version": "1.4.7", 685 | "sha1": "7a608d3ce6ed895d484956c1e76110ed8b78422a" 686 | }, 687 | { 688 | "version": "1.4.8", 689 | "sha1": "504de7800fa81847bfc2e26a21973899db9dd747" 690 | }, 691 | { 692 | "version": "1.5.0", 693 | "sha1": "57b34efdf44a922acc6f21d285b207029b53927d" 694 | }, 695 | { 696 | "version": "1.6.0", 697 | "sha1": "981353ef7ba544d3074cefdbfe275b541b7038aa" 698 | }, 699 | { 700 | "version": "1.6.1", 701 | "sha1": "27bbea23f00cfb65707cb096fbe82ba7b78723f6" 702 | }, 703 | { 704 | "version": "1.6.2", 705 | "sha1": "708bbcc6985d4cf3719829603972a39895a03a07" 706 | }, 707 | { 708 | "version": "1.6.3", 709 | "sha1": "0d35fc89aabab0456ef2ee7572f0571314b97121" 710 | }, 711 | { 712 | "version": "1.6.4", 713 | "sha1": "4689e4033ebfc982176b92545900302d0fcb03b3" 714 | }, 715 | { 716 | "version": "1.7.0", 717 | "sha1": "bf4dc66ab5fbbafd4294d32c2797c08b630c0be5" 718 | }, 719 | { 720 | "version": "1.8.0", 721 | "sha1": "ef07c036b8f7d34f4b1d7fcc355ce46a92d2dcc8" 722 | }, 723 | { 724 | "version": "1.8.1", 725 | "sha1": "fd1ad4c17bfdcd890ea7176f2672c35102384419" 726 | }, 727 | { 728 | "version": "1.9.0", 729 | "sha1": "d6882f432beca85d460ec42497888157c356d058" 730 | }, 731 | { 732 | "version": "1.9.1", 733 | "sha1": "3be87d89fd5a93a63f527351fbedb84f8a875812" 734 | }, 735 | { 736 | "version": "1.9.2", 737 | "sha1": "3251ca82359cf238a1074e383281e3126547d50b" 738 | }, 739 | { 740 | "version": "1.9.3", 741 | "sha1": "e4aaff11f49c941fde1dd93883cf69c6b8abebe4" 742 | }, 743 | { 744 | "version": "1.9.4", 745 | "sha1": "512763fd375633fd67197225e61fe90a5929166b" 746 | }, 747 | { 748 | "version": "1.9.5", 749 | "sha1": "87b6907759f7b8dff830d54b2250b8d721bde291" 750 | }, 751 | { 752 | "version": "1.9.6", 753 | "sha1": "4035511f1e258a47b77798a2005c024609ed2c67" 754 | }, 755 | { 756 | "version": "1.9.7", 757 | "sha1": "a1ae95286a1b2677ed3fda6785816e76df4ee8a2" 758 | }, 759 | { 760 | "version": "1.9.8", 761 | "sha1": "a9247e38b24ba1c1ed5913c4049d9a4083a314a7" 762 | }, 763 | { 764 | "version": "1.10.0", 765 | "sha1": "591eb496d52f4140bc2c7de547131f1b9408b9b4" 766 | }, 767 | { 768 | "version": "1.10.1", 769 | "sha1": "2783cc609cd52bc5ac92ec9e35b9b854f5f07882" 770 | }, 771 | { 772 | "version": "1.10.2", 773 | "sha1": "f56fcca509a9fa5350bf55f18d8c6087295a8cef" 774 | }, 775 | { 776 | "version": "1.10.3", 777 | "sha1": "1c76521bb8b08c63ef619aa8a5ab563dddf7b3cf" 778 | }, 779 | { 780 | "version": "1.10.4", 781 | "sha1": "1aafd0a262ff40214ed7f51302d92fa587c607ef" 782 | }, 783 | { 784 | "version": "1.11.0", 785 | "sha1": "7c81792859a6da7f7401c0ac37a4cc83bb500ff6" 786 | }, 787 | { 788 | "version": "1.11.1", 789 | "sha1": "1ba9e1aa422166864c3267f03f5110144b745c1e" 790 | }, 791 | { 792 | "version": "1.11.2", 793 | "sha1": "a6d86c0083f00ee6c3709478ff3b33deff5e6d19" 794 | } 795 | ] 796 | } -------------------------------------------------------------------------------- /js/dashboard.js: -------------------------------------------------------------------------------- 1 | // Defold Component Size Dashboard 2 | 3 | class DefoldDashboard { 4 | constructor() { 5 | this.csvCache = new Map(); 6 | this.charts = new Map(); 7 | this.chartConfigs = new Map(); // Store chart configurations 8 | this.platformColors = { 9 | 'arm64-ios': '#e74c3c', 10 | 'arm64-android': '#3498db', 11 | 'armv7-android': '#9b59b6', 12 | 'x86_64-macos': '#2ecc71', 13 | 'js-web': '#f39c12', 14 | 'wasm-web': '#e67e22', 15 | 'x86_64-linux': '#34495e', 16 | 'x86-win32': '#16a085', 17 | 'x86_64-win32': '#27ae60', 18 | 'arm64-macos': '#8e44ad' 19 | }; 20 | 21 | this.init(); 22 | 23 | // Add window resize listener to handle responsive layout changes 24 | window.addEventListener('resize', () => { 25 | this.handleResize(); 26 | }); 27 | } 28 | 29 | async init() { 30 | try { 31 | // Load all CSV files 32 | await this.loadAllData(); 33 | 34 | // Create all charts 35 | this.createBundleChart(); 36 | this.createEngineChart(); 37 | this.createEditorChart(); 38 | this.createBobChart(); 39 | 40 | // Setup version dropdowns and event listeners 41 | this.setupVersionDropdowns(); 42 | 43 | console.log('Dashboard loaded successfully'); 44 | 45 | } catch (error) { 46 | console.error('Error initializing dashboard:', error); 47 | this.showError('Failed to load dashboard data'); 48 | } 49 | } 50 | 51 | async loadAllData() { 52 | const files = ['bundle_report.csv', 'engine_report.csv', 'editor_report.csv', 'bob_report.csv']; 53 | 54 | for (const file of files) { 55 | await this.loadCSV(file); 56 | } 57 | } 58 | 59 | async loadCSV(filename) { 60 | if (this.csvCache.has(filename)) { 61 | return this.csvCache.get(filename); 62 | } 63 | 64 | try { 65 | const response = await fetch(filename); 66 | if (!response.ok) { 67 | throw new Error(`HTTP error! status: ${response.status}`); 68 | } 69 | 70 | const text = await response.text(); 71 | const data = this.parseCSV(text); 72 | 73 | // Filter out rows with all zeros 74 | const filteredData = data.filter(row => { 75 | const values = Object.values(row); 76 | return values.some(value => value !== 'VERSION' && parseFloat(value) > 0); 77 | }); 78 | 79 | this.csvCache.set(filename, filteredData); 80 | return filteredData; 81 | 82 | } catch (error) { 83 | console.error(`Error loading ${filename}:`, error); 84 | throw error; 85 | } 86 | } 87 | 88 | parseCSV(text) { 89 | const lines = text.trim().split('\n'); 90 | const headers = lines[0].split(',').map(h => h.trim()); 91 | const data = []; 92 | 93 | for (let i = 1; i < lines.length; i++) { 94 | const values = lines[i].split(',').map(v => v.trim()); 95 | if (values.length === headers.length) { 96 | const row = {}; 97 | headers.forEach((header, index) => { 98 | row[header] = values[index]; 99 | }); 100 | data.push(row); 101 | } 102 | } 103 | 104 | return data; 105 | } 106 | 107 | compareVersions(v1, v2) { 108 | const a = v1.split('.').map(Number); 109 | const b = v2.split('.').map(Number); 110 | 111 | for (let i = 0; i < Math.max(a.length, b.length); i++) { 112 | const numA = a[i] || 0; 113 | const numB = b[i] || 0; 114 | if (numA !== numB) { 115 | return numA - numB; 116 | } 117 | } 118 | return 0; 119 | } 120 | 121 | filterDataFromVersion(data, startVersion) { 122 | return data.filter(row => { 123 | const version = row.VERSION; 124 | return this.compareVersions(version, startVersion) >= 0; 125 | }); 126 | } 127 | 128 | calculateDefaultVersion(csvFile, minimumVersion) { 129 | const rawData = this.csvCache.get(csvFile); 130 | if (!rawData) return minimumVersion; 131 | 132 | // Get all versions with data (non-zero values) 133 | const versions = rawData 134 | .filter(row => { 135 | const values = Object.values(row); 136 | return values.some(value => value !== 'VERSION' && parseFloat(value) > 0); 137 | }) 138 | .map(row => row.VERSION); 139 | 140 | // Sort versions 141 | versions.sort(this.compareVersions.bind(this)); 142 | 143 | // Filter to only include versions >= minimum allowed 144 | const validVersions = versions.filter(version => 145 | this.compareVersions(version, minimumVersion) >= 0 146 | ); 147 | 148 | // If we have more than 20 versions, start from the 20th from the end 149 | if (validVersions.length > 20) { 150 | const startIndex = validVersions.length - 20; 151 | return validVersions[startIndex]; 152 | } 153 | 154 | // If we have 20 or fewer versions, start from the minimum 155 | return minimumVersion; 156 | } 157 | 158 | formatBytes(bytes) { 159 | if (bytes === 0) return '0 B'; 160 | 161 | const k = 1024; 162 | const sizes = ['B', 'KB', 'MB', 'GB']; 163 | const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(k)); 164 | 165 | return (bytes / Math.pow(k, i)).toFixed(1) + ' ' + sizes[i]; 166 | } 167 | 168 | createBundleChart() { 169 | const rawData = this.csvCache.get('bundle_report.csv'); 170 | const platforms = ['arm64-ios', 'arm64-android', 'armv7-android', 'x86_64-macos', 'js-web', 'wasm-web', 'x86_64-linux', 'x86-win32', 'x86_64-win32', 'arm64-macos']; 171 | 172 | // Calculate default version (last 20 versions) 173 | const defaultVersion = this.calculateDefaultVersion('bundle_report.csv', '1.2.166'); 174 | 175 | // Store chart config 176 | this.chartConfigs.set('bundle-chart', { 177 | csvFile: 'bundle_report.csv', 178 | platforms: platforms, 179 | title: 'Bundle Size Evolution', 180 | defaultVersion: defaultVersion, 181 | selectId: 'bundle-version-select' 182 | }); 183 | 184 | const data = this.filterDataFromVersion(rawData, defaultVersion); 185 | this.createChart('bundle-chart', data, platforms, 'Bundle Size Evolution'); 186 | } 187 | 188 | createEngineChart() { 189 | const rawData = this.csvCache.get('engine_report.csv'); 190 | const platforms = ['arm64-ios', 'arm64-android', 'armv7-android', 'x86_64-macos', 'js-web', 'wasm-web', 'x86_64-linux', 'x86-win32', 'x86_64-win32', 'arm64-macos']; 191 | 192 | // Calculate default version (last 20 versions) 193 | const defaultVersion = this.calculateDefaultVersion('engine_report.csv', '1.2.166'); 194 | 195 | // Store chart config 196 | this.chartConfigs.set('engine-chart', { 197 | csvFile: 'engine_report.csv', 198 | platforms: platforms, 199 | title: 'Engine Size Evolution', 200 | defaultVersion: defaultVersion, 201 | selectId: 'engine-version-select' 202 | }); 203 | 204 | const data = this.filterDataFromVersion(rawData, defaultVersion); 205 | this.createChart('engine-chart', data, platforms, 'Engine Size Evolution'); 206 | } 207 | 208 | createEditorChart() { 209 | const rawData = this.csvCache.get('editor_report.csv'); 210 | const platforms = ['x86_64-macos', 'x86_64-win32', 'x86_64-linux', 'arm64-macos']; 211 | 212 | // Calculate default version (last 20 versions) 213 | const defaultVersion = this.calculateDefaultVersion('editor_report.csv', '1.3.6'); 214 | 215 | // Store chart config 216 | this.chartConfigs.set('editor-chart', { 217 | csvFile: 'editor_report.csv', 218 | platforms: platforms, 219 | title: 'Editor Size Evolution', 220 | defaultVersion: defaultVersion, 221 | selectId: 'editor-version-select' 222 | }); 223 | 224 | const data = this.filterDataFromVersion(rawData, defaultVersion); 225 | this.createChart('editor-chart', data, platforms, 'Editor Size Evolution'); 226 | } 227 | 228 | createBobChart() { 229 | const rawData = this.csvCache.get('bob_report.csv'); 230 | const platforms = ['x86_64-macos']; 231 | 232 | // Calculate default version (last 20 versions) 233 | const defaultVersion = this.calculateDefaultVersion('bob_report.csv', '1.2.166'); 234 | 235 | // Store chart config 236 | this.chartConfigs.set('bob-chart', { 237 | csvFile: 'bob_report.csv', 238 | platforms: platforms, 239 | title: 'Bob.jar Size Evolution', 240 | defaultVersion: defaultVersion, 241 | selectId: 'bob-version-select' 242 | }); 243 | 244 | const data = this.filterDataFromVersion(rawData, defaultVersion); 245 | this.createChart('bob-chart', data, platforms, 'Bob.jar Size Evolution', false); // No legend for Bob chart 246 | } 247 | 248 | createChart(containerId, data, platforms, title, showLegend = true) { 249 | const container = document.getElementById(containerId); 250 | 251 | if (!data || data.length === 0) { 252 | container.innerHTML = '
No data available
'; 253 | return; 254 | } 255 | 256 | // Show loading state 257 | container.innerHTML = '
Loading chart...
'; 258 | 259 | const traces = []; 260 | const versions = data.map(row => row.VERSION); 261 | 262 | platforms.forEach(platform => { 263 | const sizes = data.map(row => { 264 | const size = parseFloat(row[platform]) || 0; 265 | return size; 266 | }); 267 | 268 | // Only include platforms that have some data 269 | const hasData = sizes.some(size => size > 0); 270 | if (!hasData) return; 271 | 272 | traces.push({ 273 | x: versions, 274 | y: sizes, 275 | type: 'scatter', 276 | mode: 'lines+markers', 277 | name: this.formatPlatformName(platform), 278 | line: { 279 | color: this.platformColors[platform] || '#666', 280 | width: 2 281 | }, 282 | marker: { 283 | size: 4, 284 | color: this.platformColors[platform] || '#666' 285 | }, 286 | hovertemplate: `%{fullData.name}
Version: %{x}
Size: %{text}
Bytes: %{y:,.0f}`, 287 | text: sizes.map(size => this.formatBytes(size)), 288 | hoverlabel: { 289 | bgcolor: '#FFFFDD', 290 | bordercolor: '#333', 291 | font: { color: '#000', size: 12 } 292 | } 293 | }); 294 | }); 295 | 296 | // Check if we're on mobile/tablet (768px or less) 297 | const isMobile = window.innerWidth <= 768; 298 | 299 | const layout = { 300 | title: { 301 | text: title, 302 | font: { size: 16, color: '#2c3e50' }, 303 | y: isMobile ? 0.92 : 0.95, 304 | yanchor: 'top' 305 | }, 306 | xaxis: { 307 | title: 'Version', 308 | tickangle: -45, 309 | gridcolor: '#f0f0f0' 310 | }, 311 | yaxis: { 312 | title: 'Size', 313 | tickformat: '.2s', 314 | gridcolor: '#f0f0f0' 315 | }, 316 | margin: { 317 | l: 80, 318 | r: 50, 319 | t: isMobile ? 100 : 60, 320 | b: showLegend ? 100 : 60 321 | }, 322 | paper_bgcolor: 'white', 323 | plot_bgcolor: 'white', 324 | showlegend: showLegend, 325 | legend: showLegend ? { 326 | orientation: 'h', 327 | x: 0, 328 | y: -0.25, 329 | xanchor: 'left', 330 | bgcolor: 'rgba(255,255,255,0.8)', 331 | bordercolor: '#ddd', 332 | borderwidth: 1, 333 | font: { size: 12 } 334 | } : {}, 335 | hovermode: 'closest' 336 | }; 337 | 338 | const config = { 339 | displayModeBar: true, 340 | modeBarButtonsToRemove: ['select2d', 'lasso2d'], 341 | displaylogo: false, 342 | responsive: true 343 | }; 344 | 345 | // Clear loading spinner before creating chart 346 | container.innerHTML = ''; 347 | 348 | Plotly.newPlot(containerId, traces, layout, config); 349 | this.charts.set(containerId, { traces, layout, config, platforms }); 350 | 351 | // Add click handler to open size-analyzer with selected version 352 | document.getElementById(containerId).on('plotly_click', (data) => { 353 | this.handleChartClick(data, platforms, containerId); 354 | }); 355 | 356 | // Add legend click handler for Alt+click to show only selected platform 357 | if (showLegend) { 358 | document.getElementById(containerId).on('plotly_legendclick', (data) => { 359 | return this.handleLegendClick(data, containerId); 360 | }); 361 | 362 | // Add legend usage info 363 | this.addLegendInfo(containerId); 364 | } 365 | } 366 | 367 | addLegendInfo(containerId) { 368 | const container = document.getElementById(containerId); 369 | const chartContainer = container.closest('.chart-section'); 370 | 371 | if (chartContainer) { 372 | // Check if info already exists 373 | const existingInfo = chartContainer.querySelector('.legend-info'); 374 | if (!existingInfo) { 375 | const infoDiv = document.createElement('div'); 376 | infoDiv.className = 'legend-info'; 377 | infoDiv.style.cssText = ` 378 | font-style: italic; 379 | font-size: 9px; 380 | color: #999; 381 | text-align: right; 382 | margin-top: 2px; 383 | line-height: 1; 384 | `; 385 | infoDiv.textContent = 'Legend: click to toggle, Alt+click to isolate'; 386 | 387 | // Add after the chart container 388 | const chartDiv = chartContainer.querySelector('.chart-container'); 389 | if (chartDiv) { 390 | chartDiv.insertAdjacentElement('afterend', infoDiv); 391 | } else { 392 | container.insertAdjacentElement('afterend', infoDiv); 393 | } 394 | } 395 | } 396 | } 397 | 398 | handleChartClick(data, platforms, containerId) { 399 | if (data.points && data.points.length > 0) { 400 | const point = data.points[0]; 401 | const clickedVersion = point.x; // Version from X-axis 402 | const platformName = point.fullData.name; // Platform name from trace 403 | 404 | // Find the actual platform key from the formatted name 405 | let platformKey = this.findPlatformKey(platformName, platforms); 406 | 407 | // Special case: if this is the Bob chart, use 'bob.jar' as platform 408 | if (containerId === 'bob-chart') { 409 | platformKey = 'bob.jar'; 410 | } 411 | 412 | // Special case: if this is the Editor chart, map to editor platform names 413 | if (containerId === 'editor-chart') { 414 | const editorPlatformMap = { 415 | 'x86_64-win32': 'editor-win32', 416 | 'x86_64-linux': 'editor-x86_64-linux', 417 | 'x86_64-macos': 'editor-x86_64-macos', 418 | 'arm64-macos': 'editor-arm64-macos' 419 | }; 420 | platformKey = editorPlatformMap[platformKey] || platformKey; 421 | } 422 | 423 | if (platformKey && clickedVersion) { 424 | // Get all available versions for this platform to find the previous version 425 | const allVersions = this.getAllVersionsForPlatform(platformKey, containerId); 426 | const versionIndex = allVersions.indexOf(clickedVersion); 427 | 428 | if (versionIndex > 0) { 429 | const fromVersion = allVersions[versionIndex - 1]; 430 | const toVersion = clickedVersion; 431 | 432 | // Open size-analyzer with URL parameters 433 | const url = `size-analyzer/?platform=${platformKey}&from=${fromVersion}&to=${toVersion}`; 434 | window.open(url, '_blank'); 435 | } else { 436 | alert('Cannot compare: This is the first version in the dataset.'); 437 | } 438 | } 439 | } 440 | } 441 | 442 | handleLegendClick(data, containerId) { 443 | // Check if Alt key is pressed 444 | if (data.event && data.event.altKey) { 445 | // Alt+click: show only the clicked trace, hide all others 446 | const clickedTraceIndex = data.curveNumber; 447 | const currentChart = this.charts.get(containerId); 448 | 449 | if (currentChart) { 450 | const update = { 451 | visible: currentChart.traces.map((trace, index) => 452 | index === clickedTraceIndex ? true : 'legendonly' 453 | ) 454 | }; 455 | 456 | Plotly.restyle(containerId, update); 457 | } 458 | 459 | // Return false to prevent default legend click behavior 460 | return false; 461 | } 462 | 463 | // Return true to allow default legend click behavior (normal toggle) 464 | return true; 465 | } 466 | 467 | findPlatformKey(platformName, platforms) { 468 | // Convert formatted platform name back to platform key 469 | const reverseNameMap = { 470 | 'ARM64 iOS': 'arm64-ios', 471 | 'ARM64 Android': 'arm64-android', 472 | 'ARMv7 Android': 'armv7-android', 473 | 'x86_64 macOS': 'x86_64-macos', 474 | 'JS Web': 'js-web', 475 | 'WASM Web': 'wasm-web', 476 | 'x86_64 Linux': 'x86_64-linux', 477 | 'x86 Win32': 'x86-win32', 478 | 'x86_64 Win32': 'x86_64-win32', 479 | 'ARM64 macOS': 'arm64-macos' 480 | }; 481 | 482 | return reverseNameMap[platformName] || platforms.find(p => 483 | this.formatPlatformName(p) === platformName 484 | ); 485 | } 486 | 487 | getAllVersionsForPlatform(platformKey, containerId = null) { 488 | // Get all available versions from the raw CSV data 489 | let csvFile; 490 | 491 | // Special case: if this is the Bob chart or platform is bob.jar, use bob_report.csv 492 | if (containerId === 'bob-chart' || platformKey === 'bob.jar') { 493 | csvFile = 'bob_report.csv'; 494 | } else { 495 | csvFile = this.getCsvFileForPlatform(platformKey); 496 | } 497 | 498 | const rawData = this.csvCache.get(csvFile); 499 | 500 | if (rawData) { 501 | return rawData.map(row => row.VERSION).filter(v => v); 502 | } 503 | 504 | return []; 505 | } 506 | 507 | getCsvFileForPlatform(platformKey) { 508 | // Map platform to CSV file based on chart context 509 | // For desktop platforms, prefer editor_report.csv, except for bob chart 510 | if (['x86_64-macos', 'x86_64-win32', 'x86_64-linux', 'arm64-macos'].includes(platformKey)) { 511 | return 'editor_report.csv'; 512 | } else { 513 | // For mobile/web platforms, use bundle_report.csv (or engine_report.csv as fallback) 514 | return this.csvCache.has('bundle_report.csv') ? 'bundle_report.csv' : 'engine_report.csv'; 515 | } 516 | } 517 | 518 | formatPlatformName(platform) { 519 | const names = { 520 | 'arm64-ios': 'ARM64 iOS', 521 | 'arm64-android': 'ARM64 Android', 522 | 'armv7-android': 'ARMv7 Android', 523 | 'x86_64-macos': 'x86_64 macOS', 524 | 'js-web': 'JS Web', 525 | 'wasm-web': 'WASM Web', 526 | 'x86_64-linux': 'x86_64 Linux', 527 | 'x86-win32': 'x86 Win32', 528 | 'x86_64-win32': 'x86_64 Win32', 529 | 'arm64-macos': 'ARM64 macOS' 530 | }; 531 | return names[platform] || platform; 532 | } 533 | 534 | setupVersionDropdowns() { 535 | // Setup dropdowns for each chart 536 | this.chartConfigs.forEach((config, chartId) => { 537 | this.populateVersionDropdown(config.selectId, config.csvFile, config.defaultVersion); 538 | 539 | // Add event listener for version changes 540 | const select = document.getElementById(config.selectId); 541 | select.addEventListener('change', () => { 542 | this.onVersionChange(chartId, select.value); 543 | }); 544 | }); 545 | } 546 | 547 | populateVersionDropdown(selectId, csvFile, defaultVersion) { 548 | const select = document.getElementById(selectId); 549 | const rawData = this.csvCache.get(csvFile); 550 | 551 | if (!rawData) return; 552 | 553 | // Define minimum allowed versions for each chart type 554 | const minimumVersions = { 555 | 'bundle_report.csv': '1.2.166', 556 | 'engine_report.csv': '1.2.166', 557 | 'editor_report.csv': '1.3.6', 558 | 'bob_report.csv': '1.2.166' 559 | }; 560 | 561 | const minimumVersion = minimumVersions[csvFile]; 562 | 563 | // Get all versions with data (non-zero values) 564 | const versions = rawData 565 | .filter(row => { 566 | const values = Object.values(row); 567 | return values.some(value => value !== 'VERSION' && parseFloat(value) > 0); 568 | }) 569 | .map(row => row.VERSION); 570 | 571 | // Sort versions 572 | versions.sort(this.compareVersions.bind(this)); 573 | 574 | // Filter versions to only include those >= minimum allowed version 575 | const validVersions = versions.filter(version => 576 | this.compareVersions(version, minimumVersion) >= 0 577 | ); 578 | 579 | // Get maximum versions for selection range (last available - 3) 580 | const maxVersionIndex = Math.max(0, validVersions.length - 4); 581 | const selectableVersions = validVersions.slice(0, maxVersionIndex + 1); 582 | 583 | // Clear and populate dropdown 584 | select.innerHTML = ''; 585 | 586 | selectableVersions.forEach(version => { 587 | const option = document.createElement('option'); 588 | option.value = version; 589 | option.textContent = version; 590 | if (version === defaultVersion) { 591 | option.selected = true; 592 | } 593 | select.appendChild(option); 594 | }); 595 | } 596 | 597 | onVersionChange(chartId, selectedVersion) { 598 | if (!selectedVersion) return; 599 | 600 | const config = this.chartConfigs.get(chartId); 601 | if (!config) return; 602 | 603 | const rawData = this.csvCache.get(config.csvFile); 604 | const filteredData = this.filterDataFromVersion(rawData, selectedVersion); 605 | 606 | // Update the chart 607 | this.updateChartWithData(chartId, filteredData, config.platforms, config.title); 608 | } 609 | 610 | updateChartWithData(chartId, data, platforms, title) { 611 | const container = document.getElementById(chartId); 612 | const chartData = this.charts.get(chartId); 613 | 614 | if (!data || !chartData) return; 615 | 616 | const traces = []; 617 | const versions = data.map(row => row.VERSION); 618 | 619 | platforms.forEach(platform => { 620 | const sizes = data.map(row => { 621 | const size = parseFloat(row[platform]) || 0; 622 | return size; 623 | }); 624 | 625 | // Only include platforms that have some data 626 | const hasData = sizes.some(size => size > 0); 627 | if (!hasData) return; 628 | 629 | traces.push({ 630 | x: versions, 631 | y: sizes, 632 | type: 'scatter', 633 | mode: 'lines+markers', 634 | name: this.formatPlatformName(platform), 635 | line: { 636 | color: this.platformColors[platform] || '#666', 637 | width: 2 638 | }, 639 | marker: { 640 | size: 4, 641 | color: this.platformColors[platform] || '#666' 642 | }, 643 | hovertemplate: `%{fullData.name}
Version: %{x}
Size: %{text}
Bytes: %{y:,.0f}`, 644 | text: sizes.map(size => this.formatBytes(size)), 645 | hoverlabel: { 646 | bgcolor: '#FFFFDD', 647 | bordercolor: '#333', 648 | font: { color: '#000', size: 12 } 649 | } 650 | }); 651 | }); 652 | 653 | Plotly.react(chartId, traces, chartData.layout, chartData.config); 654 | } 655 | 656 | handleResize() { 657 | // Debounce resize events 658 | clearTimeout(this.resizeTimeout); 659 | this.resizeTimeout = setTimeout(() => { 660 | // Update all charts with responsive layout 661 | this.chartConfigs.forEach((config, chartId) => { 662 | const chartData = this.charts.get(chartId); 663 | if (chartData) { 664 | const isMobile = window.innerWidth <= 768; 665 | const updatedLayout = { 666 | ...chartData.layout, 667 | title: { 668 | ...chartData.layout.title, 669 | y: isMobile ? 0.92 : 0.95 670 | }, 671 | margin: { 672 | ...chartData.layout.margin, 673 | t: isMobile ? 100 : 60 674 | } 675 | }; 676 | 677 | Plotly.relayout(chartId, updatedLayout); 678 | this.charts.set(chartId, { ...chartData, layout: updatedLayout }); 679 | } 680 | }); 681 | }, 250); // 250ms debounce 682 | } 683 | 684 | showError(message) { 685 | const sections = document.querySelectorAll('.chart-section .chart-container'); 686 | sections.forEach(section => { 687 | section.innerHTML = `
${message}
`; 688 | }); 689 | } 690 | } 691 | 692 | // Initialize dashboard when page loads 693 | document.addEventListener('DOMContentLoaded', () => { 694 | window.defoldDashboard = new DefoldDashboard(); 695 | }); --------------------------------------------------------------------------------