{ "id": "89801", "key": "TIMOB-8663", "fields": { "issuetype": { "id": "5", "description": "The sub-task of the issue", "name": "Sub-task", "subtask": true }, "parent": { "id": "89765", "key": "TIMOB-8652", "fields": { "summary": "Core: Create a new Titanium Command Line Interface", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "6", "description": "gh.issue.epic.desc", "name": "Epic", "subtask": false } } }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [ { "id": "13271", "description": "Release 2.1.0", "name": "Release 2.1.0", "archived": false, "released": true, "releaseDate": "2012-06-29" }, { "id": "13277", "name": "Sprint 2012-08", "archived": true, "released": true, "releaseDate": "2012-04-22" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2012-04-17T10:27:06.000+0000", "created": "2012-04-10T15:45:13.000+0000", "priority": { "name": "High", "id": "2" }, "labels": [ "core" ], "versions": [], "issuelinks": [ { "id": "17012", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "outwardIssue": { "id": "91209", "key": "TIMOB-8951", "fields": { "summary": "Core: review javascript code security features for iOS/Android", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "7", "description": "gh.issue.story.desc", "name": "Story", "subtask": false } } } } ], "assignee": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2012-06-15T16:29:04.000+0000", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [ { "id": "10207", "name": "Tooling" } ], "description": "We need to investigate the various JS obfuscation and minification options in the wild and decide on a common approach across platforms. Some obvious contenders:\r\n* Google Closure Compiler\r\n* YUI compressor\r\n\r\nWhen evaluating the various options, we should keep in mind the ability to feed in more data (i.e. an AST or other API heuristics) to further optimize the minification process", "attachment": [], "flagged": false, "summary": "R&D: Evaluate various obfuscation / minification engines for common use across platforms", "creator": { "name": "mculpepper", "key": "mculpepper", "displayName": "Marshall Culpepper", "active": true, "timeZone": "America/Los_Angeles" }, "subtasks": [], "reporter": { "name": "mculpepper", "key": "mculpepper", "displayName": "Marshall Culpepper", "active": true, "timeZone": "America/Los_Angeles" }, "environment": null, "closedSprints": [ { "id": 3, "state": "closed", "name": "Release 3.0.0", "startDate": "2012-09-27T05:26:46.636Z", "endDate": "2012-10-08T20:05:00.000Z", "completeDate": "2012-12-20T17:03:19.403Z" } ], "comment": { "comments": [ { "id": "190506", "author": { "name": "cbarber", "key": "cbarber", "displayName": "Chris Barber", "active": true, "timeZone": "America/Chicago" }, "body": "FWIW, the ultimate goal is mobile web's AST parser will eventually replace closure compiler. Like closure compiler, it will obfuscate through minification. There was no plan to further obfuscate the code as that would probably increase file size. Even if we did some sort of encryption or heavy obfuscation, anybody with Web Inspector or Firebug could pretty much defeat any obfuscation.\r\n\r\nMobile web is capable of \"lazy loading\" code, so you could gain a level of obfuscation by pulling down sensitive data after the page loads, but we're not quite there yet with the tooling require to support this.", "updateAuthor": { "name": "cbarber", "key": "cbarber", "displayName": "Chris Barber", "active": true, "timeZone": "America/Chicago" }, "created": "2012-04-10T15:57:56.000+0000", "updated": "2012-04-10T15:57:56.000+0000" }, { "id": "190607", "author": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Our options so far:\r\n- [Google Closure Compiler|https://developers.google.com/closure/compiler/]\r\n- [YUI Compressor|http://developer.yahoo.com/yui/compressor/]\r\n- [UglifyJS|https://github.com/mishoo/UglifyJS]\r\n- [/packer/|http://dean.edwards.name/packer/] - mine's favorite, but want to be objective :)\r\n- [ShrinkSafe (DOJO compressor)|http://dojotoolkit.org/reference-guide/1.7/util/shrinksafe/index.html]\r\n\r\n- [All-in-one tool (wro4j)|http://code.google.com/p/wro4j/]\r\n\r\nwill go in detail over each one", "updateAuthor": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-04-11T13:25:00.000+0000", "updated": "2012-04-12T16:23:10.000+0000" }, { "id": "190610", "author": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Original Example Code:\r\n{code}\r\nvar win = Titanium.UI.currentWindow;\r\n\r\nvar annotation = Titanium.Map.createAnnotation({\r\n\tlatitude:42.334537,\r\n\tlongitude:-71.170101,\r\n\ttitle:\"Boston College\",\r\n\tsubtitle:'Newton Campus, Chestnut Hill, MA',\r\n\tanimate:true,\r\n\tleftButton:'../images/atlanta.jpg',\r\n\timage:\"../images/boston_college.png\"\r\n});\r\n\r\nvar boston = {latitude:42.334537,longitude:-71.170101,latitudeDelta:0.010, longitudeDelta:0.018};\r\n\r\n//\r\n// CREATE MAP VIEW\r\n//\r\nvar mapview = Titanium.Map.createView({\r\n\tmapType: Titanium.Map.STANDARD_TYPE,\r\n\tregion: boston,\r\n\tanimate:true,\r\n\tregionFit:true,\r\n\tuserLocation:true,\r\n\tannotations:[annotation]\r\n});\r\n\r\n// read in our routes from a comma-separated file\r\nvar f = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory,'examples','route.csv');\r\nvar csv = f.read();\r\nvar points = [];\r\nvar lines = csv.toString().split(\"\\n\");\r\nfor (var c=0;c 1)\r\n\t{\r\n\t\tvar lat = latlong[0];\r\n\t\tvar lon = latlong[1];\r\n\t\tvar entry = {latitude:lat,longitude:lon};\r\n\t\tpoints[c]=entry;\r\n\t}\r\n}\r\n\r\n// route object\r\nvar route = {\r\n\tname:\"boston\",\r\n\tpoints:points,\r\n\tcolor:\"red\",\r\n\twidth:4\r\n};\r\n\r\n// add a route\r\nmapview.addRoute(route);\r\n\r\nwin.add(mapview);\r\n\r\n// when you click the logo, remove the route\r\nannotation.addEventListener('click',function()\r\n{\r\n\tmapview.removeRoute(route);\r\n});\r\n\r\n// map view click event listener\r\nmapview.addEventListener('click',function(evt)\r\n{\r\n\tvar clickSource = evt.clicksource;\r\n\tTi.API.info('mapview click clicksource = ' + clickSource);\r\n});\r\n{code}", "updateAuthor": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-04-11T13:38:28.000+0000", "updated": "2012-04-11T14:25:14.000+0000" }, { "id": "190616", "author": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "body": "h2. [ShrinkSafe|http://dojotoolkit.org/reference-guide/1.7/util/shrinksafe/index.html]\r\nPart of DOJO build toolchain. Java-based, utilizes Rhino to parse code. MPL 1.1 license.\r\nSafe about public variables and APIs. Almost no configuration options.\r\n\r\n{code:title=compressed.js|borderStyle=solid}\r\nvar win=Titanium.UI.currentWindow;\r\nvar annotation=Titanium.Map.createAnnotation({latitude:42.334537,longitude:-71.170101,title:\"Boston College\",subtitle:\"Newton Campus, Chestnut Hill, MA\",animate:true,leftButton:\"../images/atlanta.jpg\",image:\"../images/boston_college.png\"});\r\nvar boston={latitude:42.334537,longitude:-71.170101,latitudeDelta:0.01,longitudeDelta:0.018};\r\nvar mapview=Titanium.Map.createView({mapType:Titanium.Map.STANDARD_TYPE,region:boston,animate:true,regionFit:true,userLocation:true,annotations:[annotation]});\r\nvar f=Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory,\"examples\",\"route.csv\");\r\nvar csv=f.read();\r\nvar points=[];\r\nvar lines=csv.toString().split(\"\\n\");\r\nfor(var c=0;c1){\r\nvar lat=latlong[0];\r\nvar lon=latlong[1];\r\nvar entry={latitude:lat,longitude:lon};\r\npoints[c]=entry;\r\n}\r\n}\r\nvar route={name:\"boston\",points:points,color:\"red\",width:4};\r\nmapview.addRoute(route);\r\nwin.add(mapview);\r\nannotation.addEventListener(\"click\",function(){\r\nmapview.removeRoute(route);\r\n});\r\nmapview.addEventListener(\"click\",function(_1){\r\nvar _2=_1.clicksource;\r\nTi.API.info(\"mapview click clicksource = \"+_2);\r\n});\r\n{code}\r\n\r\nIn order to minimize top level scope variables the whole source code needs to be wrapped into *Immediate function* _(function(){})()_ and then it needs to be stripped of.\r\n{code:title=compressed.js|borderStyle=solid}\r\nvar _1=Titanium.UI.currentWindow;\r\nvar _2=Titanium.Map.createAnnotation({latitude:42.334537,longitude:-71.170101,title:\"Boston College\",subtitle:\"Newton Campus, Chestnut Hill, MA\",animate:true,leftButton:\"../images/atlanta.jpg\",image:\"../images/boston_college.png\"});\r\nvar _3={latitude:42.334537,longitude:-71.170101,latitudeDelta:0.01,longitudeDelta:0.018};\r\nvar _4=Titanium.Map.createView({mapType:Titanium.Map.STANDARD_TYPE,region:_3,animate:true,regionFit:true,userLocation:true,annotations:[_2]});\r\nvar f=Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory,\"examples\",\"route.csv\");\r\nvar _5=f.read();\r\nvar _6=[];\r\nvar _7=_5.toString().split(\"\\n\");\r\nfor(var c=0;c<_7.length;c++){\r\nvar _8=_7[c];\r\nvar _9=_8.split(\",\");\r\nif(_9.length>1){\r\nvar _a=_9[0];\r\nvar _b=_9[1];\r\nvar _c={latitude:_a,longitude:_b};\r\n_6[c]=_c;\r\n}\r\n}\r\nvar _d={name:\"boston\",points:_6,color:\"red\",width:4};\r\n_4.addRoute(_d);\r\n_1.add(_4);\r\n_2.addEventListener(\"click\",function(){\r\n_4.removeRoute(_d);\r\n});\r\n_4.addEventListener(\"click\",function(_e){\r\nvar _f=_e.clicksource;\r\nTi.API.info(\"mapview click clicksource = \"+_f);\r\n});\r\n{code}", "updateAuthor": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-04-11T14:04:20.000+0000", "updated": "2012-04-11T16:20:07.000+0000" }, { "id": "190632", "author": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "body": "h2. [/packer/|http://dean.edwards.name/packer/]\r\n\r\nJavaScript-based. [Source code|http://code.google.com/p/base2/source/browse/trunk/src/apps/packer] available. MIT License.\r\nAnalyses only source code. No AST.\r\nRuns 4 phases: minifier, shrinker, privates encoder, base62 encoder.\r\nThe first 3 phases are pretty ordinary comparing to others.\r\n*The most interesting phase is base62 encoder (0-9A-Za-z) which I think we should adapt regardless of chosen engine*.\r\n\r\n{code:title=compressed.js}\r\neval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('2 o=5.F.G;2 d=5.e.H({g:p.q,h:-r.s,I:\"J K\",L:\\'M N, O P, Q\\',t:6,R:\\'../u/S.T\\',U:\"../u/V.W\"});2 i={g:p.q,h:-r.s,X:0.Y,Z:0.10};2 3=5.e.11({12:5.e.13,14:i,t:6,15:6,16:6,17:[d]});2 f=j.v.18(j.v.19,\\'1a\\',\\'7.k\\');2 k=f.1b();2 8=[];2 l=k.1c().w(\"\\\\n\");1d(2 c=0;c1){2 z=9[0];2 A=9[1];2 B={g:z,h:A};8[c]=B}}2 7={1f:\"i\",8:8,1g:\"1h\",1i:4};3.1j(7);o.1k(3);d.C(\\'m\\',D(){3.1l(7)});3.C(\\'m\\',D(a){2 b=a.E;j.1m.1n(\\'3 m E = \\'+b)});',62,86,'||var|mapview||Titanium|true|route|points|latlong||||annotation|Map||latitude|longitude|boston|Ti|csv|lines|click||win|42|334537|71|170101|animate|images|Filesystem|split|length|line|lat|lon|entry|addEventListener|function|clicksource|UI|currentWindow|createAnnotation|title|Boston|College|subtitle|Newton|Campus|Chestnut|Hill|MA|leftButton|atlanta|jpg|image|boston_college|png|latitudeDelta|010|longitudeDelta|018|createView|mapType|STANDARD_TYPE|region|regionFit|userLocation|annotations|getFile|resourcesDirectory|examples|read|toString|for|if|name|color|red|width|addRoute|add|removeRoute|API|info'.split('|'),0,{}))\r\n{code}", "updateAuthor": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-04-11T14:53:05.000+0000", "updated": "2012-04-11T16:35:42.000+0000" }, { "id": "190640", "author": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "body": "h2. [UglifyJS|https://github.com/mishoo/UglifyJS] (Editor's Choice)\r\n\r\nJavaScript-based. Developed on Node.JS. BSD license.\r\nParses AST tree then does various manipulations on it.\r\nHighly customizable. Supports variable name reserving. Can return AST as output - might be useful for API heuristics.\r\nPerforms a lot of optimizations that could potentially lead to a faster code: simple constant expressions, property access as associated array, IF statements optimizations, joins var declarations etc.\r\n\r\n{code:title=compressed.js}\r\nvar win=Titanium.UI.currentWindow,annotation=Titanium.Map.createAnnotation({latitude:42.334537,longitude:-71.170101,title:\"Boston College\",subtitle:\"Newton Campus, Chestnut Hill, MA\",animate:!0,leftButton:\"../images/atlanta.jpg\",image:\"../images/boston_college.png\"}),boston={latitude:42.334537,longitude:-71.170101,latitudeDelta:.01,longitudeDelta:.018},mapview=Titanium.Map.createView({mapType:Titanium.Map.STANDARD_TYPE,region:boston,animate:!0,regionFit:!0,userLocation:!0,annotations:[annotation]}),f=Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory,\"examples\",\"route.csv\"),csv=f.read(),points=[],lines=csv.toString().split(\"\\n\");for(var c=0;c1){var lat=latlong[0],lon=latlong[1],entry={latitude:lat,longitude:lon};points[c]=entry}}var route={name:\"boston\",points:points,color:\"red\",width:4};mapview.addRoute(route),win.add(mapview),annotation.addEventListener(\"click\",function(){mapview.removeRoute(route)}),mapview.addEventListener(\"click\",function(a){var b=a.clicksource;Ti.API.info(\"mapview click clicksource = \"+b)})\r\n{code}\r\n\r\nHas the same issue with shortening _global_ variables as ShrinkSafe. Use of *Immediate function* is encouraged.\r\n\r\n{code:title=compressed.js}\r\nvar a=Titanium.UI.currentWindow,b=Titanium.Map.createAnnotation({latitude:42.334537,longitude:-71.170101,title:\"Boston College\",subtitle:\"Newton Campus, Chestnut Hill, MA\",animate:!0,leftButton:\"../images/atlanta.jpg\",image:\"../images/boston_college.png\"}),c={latitude:42.334537,longitude:-71.170101,latitudeDelta:.01,longitudeDelta:.018},d=Titanium.Map.createView({mapType:Titanium.Map.STANDARD_TYPE,region:c,animate:!0,regionFit:!0,userLocation:!0,annotations:[b]}),e=Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory,\"examples\",\"route.csv\"),f=e.read(),g=[],h=f.toString().split(\"\\n\");for(var i=0;i1){var l=k[0],m=k[1],n={latitude:l,longitude:m};g[i]=n}}var o={name:\"boston\",points:g,color:\"red\",width:4};d.addRoute(o),a.add(d),b.addEventListener(\"click\",function(){d.removeRoute(o)}),d.addEventListener(\"click\",function(a){var b=a.clicksource;Ti.API.info(\"mapview click clicksource = \"+b)})})()\r\n{code}\r\n", "updateAuthor": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-04-11T16:10:58.000+0000", "updated": "2012-04-11T16:17:27.000+0000" }, { "id": "190648", "author": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "body": "h2. [YUI Compressor|http://developer.yahoo.com/yui/compressor/]\r\n\r\nJava-based, utilizes Rhino to parse code. MPL 1.1/BSD license.\r\nOptional private variables shortening. Pretty much the same as ShrinkSafe.\r\n\r\n{code:title=compressed.js}\r\nvar win=Titanium.UI.currentWindow;var annotation=Titanium.Map.createAnnotation({latitude:42.334537,longitude:-71.170101,title:\"Boston College\",subtitle:\"Newton Campus, Chestnut Hill, MA\",animate:true,leftButton:\"../images/atlanta.jpg\",image:\"../images/boston_college.png\"});var boston={latitude:42.334537,longitude:-71.170101,latitudeDelta:0.01,longitudeDelta:0.018};var mapview=Titanium.Map.createView({mapType:Titanium.Map.STANDARD_TYPE,region:boston,animate:true,regionFit:true,userLocation:true,annotations:[annotation]});var f=Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory,\"examples\",\"route.csv\");var csv=f.read();var points=[];var lines=csv.toString().split(\"\\n\");for(var c=0;c1){var lat=latlong[0];var lon=latlong[1];var entry={latitude:lat,longitude:lon};points[c]=entry}}var route={name:\"boston\",points:points,color:\"red\",width:4};mapview.addRoute(route);win.add(mapview);annotation.addEventListener(\"click\",function(){mapview.removeRoute(route)});mapview.addEventListener(\"click\",function(b){var a=b.clicksource;Ti.API.info(\"mapview click clicksource = \"+a)});\r\n{code}\r\n\r\nWith *Immediate function* trick:\r\n{code:title=compressed.js}\r\nvar h=Titanium.UI.currentWindow;var d=Titanium.Map.createAnnotation({latitude:42.334537,longitude:-71.170101,title:\"Boston College\",subtitle:\"Newton Campus, Chestnut Hill, MA\",animate:true,leftButton:\"../images/atlanta.jpg\",image:\"../images/boston_college.png\"});var b={latitude:42.334537,longitude:-71.170101,latitudeDelta:0.01,longitudeDelta:0.018};var o=Titanium.Map.createView({mapType:Titanium.Map.STANDARD_TYPE,region:b,animate:true,regionFit:true,userLocation:true,annotations:[d]});var i=Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory,\"examples\",\"route.csv\");var g=i.read();var n=[];var q=g.toString().split(\"\\n\");for(var k=0;k1){var j=e[0];var a=e[1];var m={latitude:j,longitude:a};n[k]=m}}var l={name:\"boston\",points:n,color:\"red\",width:4};o.addRoute(l);h.add(o);d.addEventListener(\"click\",function(){o.removeRoute(l)});o.addEventListener(\"click\",function(f){var c=f.clicksource;Ti.API.info(\"mapview click clicksource = \"+c)})\r\n{code}", "updateAuthor": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-04-11T16:34:31.000+0000", "updated": "2012-04-11T16:34:31.000+0000" }, { "id": "190654", "author": { "name": "mstepanov", "key": "mstepanov", "displayName": "Max Stepanov", "active": true, "timeZone": "America/Los_Angeles" }, "body": "h2. [Google Closure Compiler|https://developers.google.com/closure/compiler/]\r\n\r\nJava-based, utilizes Rhino to parse code and build AST. Apache License 2.0\r\nOnly SIMPLE_OPTIMIZATIONS could be applied to source code. ADVANCED_OPTIMIZATIONS involves aggressive renaming which will break app if performed w/o declaring externs (literally _all Titanium APIs_). Also ADVANCED_OPTIMIZATIONS removes _dead code_ like functions defined but never explicitly called. \r\nSee [dangers|https://developers.google.com/closure/compiler/docs/api-tutorial3#dangers] section for the full list of limitations.\r\nCould print AST for analysis.\r\n\r\n{code:title=compressed.js}\r\nfor(var win=Titanium.UI.currentWindow,annotation=Titanium.Map.createAnnotation({latitude:42.334537,longitude:-71.170101,title:\"Boston College\",subtitle:\"Newton Campus, Chestnut Hill, MA\",animate:!0,leftButton:\"../images/atlanta.jpg\",image:\"../images/boston_college.png\"}),boston={latitude:42.334537,longitude:-71.170101,latitudeDelta:0.01,longitudeDelta:0.018},mapview=Titanium.Map.createView({mapType:Titanium.Map.STANDARD_TYPE,region:boston,animate:!0,regionFit:!0,userLocation:!0,annotations:[annotation]}),\r\nf=Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory,\"examples\",\"route.csv\"),csv=f.read(),points=[],lines=csv.toString().split(\"\\n\"),c=0;c