<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6692324655955282410</id><updated>2012-02-16T18:26:24.092-08:00</updated><title type='text'>FlexAmphetamine</title><subtitle type='html'>Useful stuff I've devised and divined in Flash/AS3.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6692324655955282410.post-1038448137407677562</id><published>2011-12-05T23:13:00.001-08:00</published><updated>2011-12-05T23:24:18.616-08:00</updated><title type='text'>Recompress your Flash 11 SWFs with LZMA</title><content type='html'>Flash 11 can load SWFs that have LZMA compression; previously SWF contents were either uncompressed or zlib-compressed.&lt;br /&gt;&lt;br /&gt;Since the mxmlc compiler doesn't yet support this compression, and since it was a PITA to compile&amp;nbsp;Tinic Uro's zlib2lzma on anything but Windows (http://blog.kaourantin.net/?p=124),&amp;nbsp;and since no one else seems to have done it... I wrote a Python script to do the conversion. Woot.&amp;nbsp;It only requires that the input SWF be compiled with &lt;code&gt;-swf-version=13&lt;/code&gt; (or higher). It will fail if you feed it an LZMA-compressed SWF -- feel free to fork me on GitHub and fix that.&lt;br /&gt;&lt;br /&gt;Usage: &lt;code&gt;python swf2lzma.py in.swf out.swf&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Grab the code from: &lt;a href="http://github.com/jspiro/swf2lzma"&gt;http://github.com/jspiro/swf2lzma&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6692324655955282410-1038448137407677562?l=flexamphetamine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/1038448137407677562/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6692324655955282410&amp;postID=1038448137407677562' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/1038448137407677562'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/1038448137407677562'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/2011/12/recompress-your-flash-11-swfs-with-lzma.html' title='Recompress your Flash 11 SWFs with LZMA'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6692324655955282410.post-621033775078902294</id><published>2011-07-19T04:59:00.000-07:00</published><updated>2011-07-19T05:07:35.009-07:00</updated><title type='text'>build decay chronograph</title><content type='html'>After hours of coding and reloading, I constantly forget whether I reloaded a browser tab under development, and otherwise question whether the SWF actually got rebuilt (and am often wrong on both counts).&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-iLMsMKU-I0A/TiVoL0u1iMI/AAAAAAAAALo/crLmT7BRnZE/s1600/buildtime.png" imageanchor="1" style="clear:left; float:left;margin-right:1em; margin-bottom:1em"&gt;&lt;img border="0" height="119" width="46" src="http://4.bp.blogspot.com/-iLMsMKU-I0A/TiVoL0u1iMI/AAAAAAAAALo/crLmT7BRnZE/s400/buildtime.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Enter the &lt;code&gt;BuildDecayChronograph&lt;/code&gt;, an object that shows you how long it's been since a given SWF was last built, and a quick visual indicator from green to red of how &lt;i&gt;fresh&lt;/i&gt; it is (for me, 5 minutes). The only requirement is that the given SWF was compiled with &lt;code&gt;mxmlc&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Usage:&lt;br /&gt;&lt;code&gt;addChild(new BuildDecayChronograph(5*60, 'engine'));&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Download from &lt;a href="https://github.com/jspiro/swf-build-decay-chronograph"&gt;GitHub&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;hr noshade/&gt;This could not have been done without the brilliantly hacky &lt;code&gt;org.igorcosta.hacks.SWF&lt;/code&gt;&lt;br /&gt;&lt;div xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/" about="http://www.igorcosta.org/?p=220"&gt;&lt;span property="dct:title"&gt;Blog Text and Codes&lt;/span&gt; (&lt;a rel="cc:attributionURL" property="cc:attributionName" href="http://www.igorcosta.org"&gt;Igor Costa &lt;/a&gt;) / &lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/3.0/us/"&gt;CC BY-NC-SA 3.0&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6692324655955282410-621033775078902294?l=flexamphetamine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/621033775078902294/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6692324655955282410&amp;postID=621033775078902294' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/621033775078902294'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/621033775078902294'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/2011/07/build-decay-chronograph.html' title='build decay chronograph'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-iLMsMKU-I0A/TiVoL0u1iMI/AAAAAAAAALo/crLmT7BRnZE/s72-c/buildtime.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6692324655955282410.post-3558131474077373089</id><published>2011-07-14T19:00:00.000-07:00</published><updated>2011-07-14T22:53:38.749-07:00</updated><title type='text'>unable to transcode this meaningless error message</title><content type='html'>If you're compiling with &lt;code&gt;mxmlc&lt;/code&gt; on Linux, and you get the 'unable to transcode' error message, and you're transcoding hundreds of files... and you've wasted two days on this (no, I'm not bitter):&lt;br /&gt;&lt;pre&gt;&gt;: ulimit -a&lt;/pre&gt;That may be really small. Like 1024 files. Try compiling again after:&lt;br /&gt;&lt;pre&gt;&gt;: ulimit -n 5000&lt;/pre&gt;Better? &lt;code&gt;mxmlc&lt;/code&gt; swallows the Java IO error #fml &lt;code&gt;&amp;gt;_&amp;lt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6692324655955282410-3558131474077373089?l=flexamphetamine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/3558131474077373089/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6692324655955282410&amp;postID=3558131474077373089' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/3558131474077373089'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/3558131474077373089'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/2011/07/unable-to-transcode-this-meaningless.html' title='unable to transcode this meaningless error message'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6692324655955282410.post-5389116552319240154</id><published>2010-09-30T16:31:00.000-07:00</published><updated>2010-09-30T19:16:02.893-07:00</updated><title type='text'>Tailing Flash</title><content type='html'>&lt;code&gt;&gt;: tail -f /Users/jspiro/Library/Preferences/Macromedia/Flash\ Player/Logs/flashlog.txt&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;How did it never occurred to me to &lt;code&gt;tail&lt;/code&gt; with Flash before? Shameful.&lt;br /&gt;&lt;br /&gt;Though, really, I wish I could control who gets to write to that log, or identify who IS writing to it -- there's so much spam from other running SWFs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6692324655955282410-5389116552319240154?l=flexamphetamine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/5389116552319240154/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6692324655955282410&amp;postID=5389116552319240154' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/5389116552319240154'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/5389116552319240154'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/2010/09/tailing-flash.html' title='Tailing Flash'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6692324655955282410.post-4236503900654368258</id><published>2010-09-17T14:35:00.000-07:00</published><updated>2010-09-30T16:29:19.876-07:00</updated><title type='text'>Dragging's a Drag</title><content type='html'>For reasons that are beyond my comprehension, Flex List components have a property to allow moving of list items, but not one for copying.&lt;br /&gt;&lt;br /&gt;If you allow moving, then you SURELY must also want to allow a poor implementation of copying, whereby your object is deep copied rather than cloned via some interface, putting Objects into your dataProvider rather than whatever class you were using. Also, copying is enabled by holding the control key -- not obvious to me, at least.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;package&lt;br /&gt;{&lt;br /&gt;import mx.events.DragEvent;&lt;br /&gt;import mx.managers.DragManager;&lt;br /&gt;&lt;br /&gt;import spark.components.List;&lt;br /&gt;&lt;br /&gt;/** Disables copy-dragging on List */&lt;br /&gt;public final class NonCopyableList extends List&lt;br /&gt;{&lt;br /&gt; override protected function dragDropHandler(event:DragEvent):void {&lt;br /&gt;  event.ctrlKey = false;&lt;br /&gt;  event.action = DragManager.MOVE;&lt;br /&gt;  super.dragDropHandler(event);&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; override protected function dragOverHandler(event:DragEvent):void {&lt;br /&gt;  event.ctrlKey = false;&lt;br /&gt;  super.dragOverHandler(event);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You're welcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6692324655955282410-4236503900654368258?l=flexamphetamine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/4236503900654368258/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6692324655955282410&amp;postID=4236503900654368258' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/4236503900654368258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/4236503900654368258'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/2010/09/dragging-drags.html' title='Dragging&apos;s a Drag'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6692324655955282410.post-324038277095522251</id><published>2010-07-27T01:52:00.000-07:00</published><updated>2010-07-27T01:52:09.275-07:00</updated><title type='text'>Best Practices when Listening</title><content type='html'>* Try to always use a weak listener, even though it's extra typing. The classes of bugs you are exposed to with strong listeners are mostly running out of memory, taxing the garbage collector, and killing performance as you take memory off the heap -- they creep up and are hard to detect. The classes of bugs with weak listeners are functionally worse -- but easy to detect -- stuff just doesn't work because the listeners got GCed (they are a little less performant too, due to tracking their weak-ness).&lt;br /&gt;&lt;br /&gt;* When writing weak listeners: Make sure that objects you are listening on will not get prematurely garbage collected and are attached to something -- either the class, or some static Singleton.&lt;br /&gt;&lt;br /&gt;* Make sure the object will get garbage collected eventually and write a comment about it.&lt;br /&gt;&lt;br /&gt;* Assume that all weak listeners and objects will never get GC'd and will keep listening forever -- code for this. In other words, explicitly remove listeners when it is IMPERATIVE that you do not receive any more messages, do not rely on setting a parent to null to break the cycle.&lt;br /&gt;&lt;br /&gt;* You DO NOT have to remove weak listeners if it doesn't matter if they continue to receive events until they GC -- e.g. a mouse move handler -- once you've removed the object from the display list, it doesn't matter that this handler MIGHT run. If you code your handlers to guard against runtime errors, then you never have to remove weak listeners. And if the listeners are still receiving after a long while... then you have a memory leak and the object you are listening on is not getting GC'd (see &lt;a href="http://flexamphetamine.blogspot.com/2009/01/detecting-if-reference-gets-garbage.html"&gt;this post&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;* If you are going to skip removing a listener, DOCUMENT IT at the line where you add the listener. If you won't document it, then don't do it.&lt;br /&gt;&lt;br /&gt;* This is tricky stuff, so treat listeners with respect like you would NEW and DELETE in C++. Work them out in your head -- document the hell out of them. They are expensive and cause almost all memory and (many) performance leaks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6692324655955282410-324038277095522251?l=flexamphetamine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/324038277095522251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6692324655955282410&amp;postID=324038277095522251' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/324038277095522251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/324038277095522251'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/2010/07/best-practices-when-listening.html' title='Best Practices when Listening'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6692324655955282410.post-8321790868457896963</id><published>2010-07-27T01:35:00.000-07:00</published><updated>2010-07-27T02:01:24.607-07:00</updated><title type='text'>Random() Performance Tips</title><content type='html'>* Perceived performance is more important than actual performance, and is cheaper to implement. Learn about how to fake speed in progress bars, and never, ever, ever, ever let Flash lock up while doing processing -- break work across frames and do it asynchronously -- keep the UI responsive even if it's modally locked.&lt;br /&gt;&lt;br /&gt;* Initializing variables to null is unnecessary, costly, and distracting (when you're trying to read code -- null or zero unless otherwise specified).&lt;br /&gt;&lt;br /&gt;* Eliminate "this." wherever possible -- this may be outdated, but in the past it produced better bytecode.&lt;br /&gt;&lt;br /&gt;* Don't use coding conveniences like lots and lots of extra variables, WITH blocks, extra "this" statements. They all add space and time in AS3 even though most other languages would compile down equivalent statements to the same thing.&lt;br /&gt;&lt;br /&gt;* Long package and class names get stored in the SWF -- interned strings in the constant pool are a large percentage of SWF size.&lt;br /&gt;&lt;br /&gt;* Keep lazy initialization of datastructures to a minimum (e.g. &lt;code&gt;if (!foo) foo = new Foo()&lt;/code&gt; versus &lt;code&gt;private var foo:Foo = new Foo()&lt;/code&gt;) -- class init and static init code is smaller and only runs once. The only advantages to lazy init are for data structures that are expensive to keep around if not being used, and/or you will null them periodically.&lt;br /&gt;&lt;br /&gt;* Function arguments and local variables are cheapest to use because AS3 doesn't have to search up the scope chain when you access them. Global statics are awesome -- though caching their values locally is best if you're going to reference them a lot. Deep lookups like foo.bar.baz.getterFunction() are expensive if you're going to do a lot of work in baz -- try caching foo.bar.baz first.&lt;br /&gt;&lt;br /&gt;* Anonymous functions: Don't get me started ;) See &lt;a href="http://flexamphetamine.blogspot.com/2009/12/closure-on-closures-terrible-typing-for.html"&gt;this post&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;* If you use Flex, &lt;code&gt;grep -r validateNow&lt;/code&gt; -- and eliminate them unless absolutely necessary. And if you don't remove it, leave a paragraph on why it must be there.&lt;br /&gt;&lt;br /&gt;* Getter functions cost more than  versus get() functions; and they often have hidden side effects. Don't write a getter unless that's all it does, and in constant time.&lt;br /&gt;&lt;br /&gt;* Mark ever variable as const unless you need it to be variable. One day there may be a performance benefit, like finals in Java. But until then, bask in one fewer category of bugs.&lt;br /&gt;&lt;br /&gt;* If you're embedding gobs of XML (damned if I know why you'd need to do this): Pasting the XML into a class as a static XML object offers the best performance and compression. The compile-time processing and optimization is significant versus runtime parsing, type checking, and decompression in a ByteArray (if you compressed it on the wire)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6692324655955282410-8321790868457896963?l=flexamphetamine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/8321790868457896963/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6692324655955282410&amp;postID=8321790868457896963' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/8321790868457896963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/8321790868457896963'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/2010/07/random-performance-tips.html' title='Random() Performance Tips'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6692324655955282410.post-3071145508244000104</id><published>2010-07-27T01:14:00.000-07:00</published><updated>2010-08-02T01:18:21.771-07:00</updated><title type='text'>JITing in the Flash VM</title><content type='html'>Three things that came to mind recently:&lt;br /&gt;&lt;br /&gt;* Constructors should be as short and fast as possible -- don't do any computation in them. The &lt;b&gt;never&lt;/b&gt; JITs the constructor function, it's always fully interpreted. (There are performance tests to show this, though I know it for fact.) If you must do some work in the constructor, or the constructor will get called often (e.g. not a Singleton) -- write a private function to do the work and call it from the constructor.&lt;br /&gt;&lt;br /&gt;* If you are using an Array and indexing it numerically (i.e. not an associative array -- one that uses string indexes), you can improve access speed to the array by hinting as follows:&lt;br /&gt;array[int(idx*2+1)]&lt;br /&gt;Even if idx is already an int, the type coercion sends a hint to the JIT.&lt;br /&gt;&lt;br /&gt;* Finally, not so important, but in tight loops or ones with many iterations: Best practice is to cache the length of an array rather than inlining it: for (var i:int=0; i&lt;fooLength; i++)&lt;br /&gt;&lt;br /&gt;It's been suggested to me that iterating over arrays backwards is faster -- though I suspect that's JIT/platform-dependent. It's confusing as hell, so I'd only suggest doing that if you're already doing something whacked out like dynamic programming =D&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6692324655955282410-3071145508244000104?l=flexamphetamine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/3071145508244000104/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6692324655955282410&amp;postID=3071145508244000104' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/3071145508244000104'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/3071145508244000104'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/2010/07/jiting-in-flash-vm.html' title='JITing in the Flash VM'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6692324655955282410.post-2800634707375580788</id><published>2010-04-08T20:38:00.001-07:00</published><updated>2010-07-27T02:19:23.775-07:00</updated><title type='text'>Printing in AS3</title><content type='html'>Don't.&lt;br /&gt;&lt;br /&gt;---&lt;br /&gt;Okay, so I'm trying to be snarky. But since this blog occasionally attempts to be useful:&lt;br /&gt;&lt;br /&gt;Printing in Flash has always been inconsistent, poorly implemented, and plain broken. As of Flash 10.1, it got some big updates to the point where it's actually useful.&lt;br /&gt;&lt;br /&gt;You still cannot print vectors with transparency -- in which case you're forced to bitmap them first. You still cannot print bitmaps without them looking like shit. You cannot render decent quality bitmaps without using more memory than god.&lt;br /&gt;&lt;br /&gt;But printing now works consistently (even if terribly) across platforms; vector printing really works now; and you can spool pages across frames (meaning a potentially unlimited number of pages, no longer timing out, and being able to show an animation and update progress while it chugs along). I can post code some day -- if there's demand.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6692324655955282410-2800634707375580788?l=flexamphetamine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/2800634707375580788/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6692324655955282410&amp;postID=2800634707375580788' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/2800634707375580788'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/2800634707375580788'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/2010/04/printing-in-as3.html' title='Printing in AS3'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6692324655955282410.post-6172992892522393626</id><published>2010-03-30T21:03:00.000-07:00</published><updated>2010-03-30T21:06:56.586-07:00</updated><title type='text'>Horizontal Mouse Wheel / Swipe Gesture Support in Flash</title><content type='html'>It's possible to detect horizontal scrolling actions from the mouse or MacBook touch pads with a little JavaScript magic. Caveat: This only works on FireFox 3.1+ and Webkit-based browsers (Chrom{e,ium} and Safari). Microsoft still has not extended their events to send horizontal scroll messages*.&lt;br /&gt;&lt;br /&gt;To do this, we're going to inject JS dynamically at runtime. I'm only giving you code snippets, you'll have to tie the logic together yourself.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;First, you'll want to make sure you have a working ExternalInterface and add a callback to handle scroll events coming from JS:&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;if (ExternalInterface.available &amp;&amp; ExternalInterface.objectID != null)&lt;br /&gt;{&lt;br /&gt;    try {&lt;br /&gt;        ExternalInterface.call('eval', 'true;');&lt;br /&gt;        ExternalInterface.addCallback("scrollEvent", onScrollEvent);&lt;br /&gt;    } catch (e:Error){&lt;br /&gt;        // nope!&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Here's your handler:&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;function onScrollEvent(xDelta:Number, yDelta:Number):void&lt;br /&gt;{&lt;br /&gt;    // scroll something in a fancy manner by xDelta and yDelta&lt;br /&gt;    // note: Webkit may give you TWO non-zero values as it allows&lt;br /&gt;    // simultaneous scrolling&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Now we need to drop the JS into a String const:&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;const SCROLL_SCRIPT:String = (&amp;lt;![CDATA[&lt;br /&gt;    function setupScrolling(objectID)&lt;br /&gt;    {&lt;br /&gt;        var flashObject = document.getElementsByName(objectID)[0];&lt;br /&gt;        var eventListenerObject = flashObject;&lt;br /&gt;        var isWebkit = false;&lt;br /&gt;&lt;br /&gt;        if (navigator &amp;&amp; navigator.vendor)&lt;br /&gt;        {&lt;br /&gt;            isWebkit = navigator.vendor.match("Apple") || navigator.vendor.match("Google");&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        // some events will need to point to the containing object tag&lt;br /&gt;        if (isWebkit &amp;&amp; flashObject.parentNode.tagName.toLowerCase() == "object")&lt;br /&gt;        {&lt;br /&gt;            eventListenerObject = flashObject.parentNode;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        var scrollHandler = function(event)&lt;br /&gt;        {&lt;br /&gt;            var xDelta = 0;&lt;br /&gt;            var yDelta = 0;&lt;br /&gt;            &lt;br /&gt;            // IE special case&lt;br /&gt;            if (!event)&lt;br /&gt;                event = window.event;&lt;br /&gt;            &lt;br /&gt;            // IE/Webkit/Opera&lt;br /&gt;            if (event.wheelDelta)&lt;br /&gt;            {&lt;br /&gt;                // horizontal scrolling is supported in Webkit&lt;br /&gt;                if (event.wheelDeltaX)&lt;br /&gt;                {&lt;br /&gt;                    // Webkit can scroll two directions simultaneously&lt;br /&gt;                    xDelta = event.wheelDeltaX;&lt;br /&gt;                    yDelta = event.wheelDeltaY;&lt;br /&gt;                }&lt;br /&gt;                else&lt;br /&gt;                {&lt;br /&gt;                    // fallback to standard scrolling interface&lt;br /&gt;                    yDelta = event.wheelDelta;&lt;br /&gt;                }&lt;br /&gt;    &lt;br /&gt;                // you'll have to play with these,&lt;br /&gt;                // browsers on Windows and OS X handle them differently&lt;br /&gt;                xDelta /= 120;&lt;br /&gt;                yDelta /= 120;&lt;br /&gt;    &lt;br /&gt;                // Opera special case&lt;br /&gt;                if (window.opera)&lt;br /&gt;                {&lt;br /&gt;                    yDelta = -yDelta;&lt;br /&gt;                    // Opera doesn't support hscroll; vscroll is also buggy&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            // Firefox (Mozilla)&lt;br /&gt;            else if (event.detail)&lt;br /&gt;            {&lt;br /&gt;                yDelta = -event.detail/1.5;&lt;br /&gt;                // hscroll supported in FF3.1+&lt;br /&gt;                if (event.axis)&lt;br /&gt;                {&lt;br /&gt;                    if (event.axis == event.HORIZONTAL_AXIS)&lt;br /&gt;                    {&lt;br /&gt;                        // FF can only scroll one dirction at a time&lt;br /&gt;                        xDelta = yDelta;&lt;br /&gt;                        yDelta = 0;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;    &lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                flashObject.scrollEvent(xDelta, yDelta);&lt;br /&gt;            }&lt;br /&gt;            catch(e) {};&lt;br /&gt;&lt;br /&gt;            if (event.preventDefault)&lt;br /&gt;                event.preventDefault();&lt;br /&gt;            event.returnValue = false;            &lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        if (window.addEventListener)&lt;br /&gt;        {&lt;br /&gt;            // not IE&lt;br /&gt;            eventListenerObject.addEventListener('mouseover', function(e)&lt;br /&gt;            {&lt;br /&gt;                if (isWebkit)&lt;br /&gt;                {&lt;br /&gt;                    window.onmousewheel = scrollHandler;&lt;br /&gt;                }&lt;br /&gt;                else&lt;br /&gt;                {&lt;br /&gt;                    window.addEventListener("DOMMouseScroll", scrollHandler, false);&lt;br /&gt;                }&lt;br /&gt;            }, false);&lt;br /&gt;        }&lt;br /&gt;        else&lt;br /&gt;        {&lt;br /&gt;            // IE&lt;br /&gt;            flashObject.onmouseover = function(e)&lt;br /&gt;            {&lt;br /&gt;                document.onmousewheel = scrollHandler;&lt;br /&gt;            };&lt;br /&gt;        }&lt;br /&gt;    }]]&gt;).toString();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Finally, execute it in the browser:&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;ExternalInterface.call("eval", SCROLL_SCRIPT);&lt;br /&gt;ExternalInterface.call("eval", 'setupScrolling( "' + ExternalInterface.objectID + '" );');&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Try it out (click the logo to look at my other documents at Scribd!) -- zoom in as far as you can go:&lt;/b&gt;&lt;br /&gt;&lt;object id="doc_607475650631813" name="doc_607475650631813" height="400" width="400" type="application/x-shockwave-flash" data="http://d1.scribdassets.com/ScribdViewer.swf" style="outline:none;" &gt;  &lt;param name="movie" value="http://d1.scribdassets.com/ScribdViewer.swf"&gt;&lt;param name="wmode" value="opaque"&gt;&lt;param name="bgcolor" value="#ffffff"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;param name="FlashVars" value="document_id=26754978&amp;access_key=key-2ift0zqf2o14ovrp6fqr&amp;page=1&amp;viewMode=list"&gt;&lt;embed id="doc_607475650631813" name="doc_607475650631813" src="http://d1.scribdassets.com/ScribdViewer.swf?document_id=26754978&amp;access_key=key-2ift0zqf2o14ovrp6fqr&amp;page=1&amp;viewMode=list" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="400" width="400" wmode="opaque" bgcolor="#ffffff"&gt;&lt;/embed&gt;  &lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;---&lt;br /&gt;* Poor man's support for IE: Use a modifier key to enable horizontal scrolling. For instance, vertical scrolling works as usual -- and if you want hscroll, hold down CTRL while vscrolling.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6692324655955282410-6172992892522393626?l=flexamphetamine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/6172992892522393626/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6692324655955282410&amp;postID=6172992892522393626' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/6172992892522393626'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/6172992892522393626'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/2010/03/horizontal-mouse-wheel-swipe-gesture.html' title='Horizontal Mouse Wheel / Swipe Gesture Support in Flash'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6692324655955282410.post-1962300327592468784</id><published>2010-02-24T13:30:00.000-08:00</published><updated>2010-02-24T13:30:30.497-08:00</updated><title type='text'>Finding Unused Classes with MXMLC</title><content type='html'>I came up with a quick and dirty method for finding unused AS3 clsses if you compile with MXMLC. The trick is to use a hidden compiler flag that I added while at Adobe: &lt;code&gt;--keep-generated-signatures&lt;/code&gt; (and &lt;code&gt;-incremental&lt;/code&gt; must be on too). This outputs a &lt;code&gt;generated-signatures&lt;/code&gt; directory in your source tree filled with &lt;code&gt;.sig&lt;/code&gt; files (named using the package structure, delimited by underscores: &lt;code&gt;mx_core_Foo.sig&lt;/code&gt;). These are all the AS files that were compiled and/or synthesized in-memory (e.g. from [Embed] metadata) by MXMLC.&lt;br /&gt;&lt;br /&gt;So, now you have a list of AS files that were compiled. Now we need a list of files that we have. &lt;code&gt;cd&lt;/code&gt; to your source directory (if you have more than one, you're on your own):&lt;br /&gt;&lt;code&gt;$ cd src/&lt;br /&gt;$ diff &lt;(find . -name "*.as"|sed 's@\./@@'|sort) &lt;(find generated-signatures -name "*.sig"|sed 's@generated-signatures/@@'|sed 's@_@/@g'|sed 's@\.sig@.as@'|sort)|grep "&lt;"|sed 's@&lt; @@'&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This should give you a list of files that do not have signatures in the compiler, and should be safe to remove.&lt;br /&gt;&lt;br /&gt;&lt;hr/&gt;For the curious: &lt;code&gt;.sig&lt;/code&gt; files are public class signatures -- they are a canonically ordered list of every function, field, import, metadata, etc., that could potentially have a dependency, in either direction, on another class being compiled. One way I used this was for an optimization to determine if a class' dependencies need to be recompiled or not -- if the signature didn't change, they don't. Every AS class gets a signature generated -- on the extremely rare case where a signature can't be generated (due to unforseen syntax or something), a warning is printed with mini-stacktrace to the console -- if you don't see that, you can be sure it's complete.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6692324655955282410-1962300327592468784?l=flexamphetamine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/1962300327592468784/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6692324655955282410&amp;postID=1962300327592468784' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/1962300327592468784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/1962300327592468784'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/2010/02/finding-unused-classes-with-mxmlc.html' title='Finding Unused Classes with MXMLC'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6692324655955282410.post-3435297452022085520</id><published>2009-12-13T23:25:00.000-08:00</published><updated>2010-08-03T23:01:15.642-07:00</updated><title type='text'>Closure on Closures, Terrible Typing, For-Each Failures</title><content type='html'>Here's an old reply I wrote to another blog's wonderings on performance problems in Flash functions, numeric types, and array access. I'm not in the mood to review, rewrite, nor make corrections (e.g. I'm sure I used "function closure" where I meant "activation object" and vice-versa, but not important), but here's the text of my replies (not entirely self-contained, but I recommend reading the original post either way):&lt;br /&gt;&lt;br /&gt;From &lt;a href="http://robert.zubek.net/blog/2008/01/12/actionscript-3-bytecode-performance/#comment-258"&gt;http://robert.zubek.net/blog/2008/01/12/actionscript-3-bytecode-performance/#comment-258&lt;/a&gt;&lt;br /&gt;&lt;blockquote&gt;Anonymous functions/closures have tricky semantics in AS3, which is why you saw such painful numbers.&lt;br /&gt;&lt;br /&gt;AS3 is not block-scoped, so all variable definitions are hoisted to the top-level of their scope — in this case, the function body of the surrounding function, not the anonymous function. This is why you cannot have two for loops with the same ‘var i:Number’ definition — you would get a ‘Duplicate name i’ error.&lt;br /&gt;&lt;br /&gt;So, when you introduce an anonymous function, the cost of *every* variable (within the outer function down to the deepest variable definition) is increased considerably. You have to do a more expensive lookup. This is why the Flex SDK doesn’t use them, ever :)&lt;br /&gt;&lt;br /&gt;Sometimes, you *need* a closure for an event listener… My solution is to create a simple factory function that takes the values you want to close over, and returns a Function object. This doesn’t get around the cost of creating a closure, and it adds the cost of the factory function call, but it isolates the lookup costs to the factory function.&lt;br /&gt;&lt;br /&gt;In small functions, it may be more expensive to use this technique, but I never tested it.&lt;br /&gt;&lt;br /&gt;—&lt;br /&gt;&lt;br /&gt;As for for-each loops: The special form returns values from an array in unspecified order because the backing object is a hashtable (it sometimes begins life as a dense array, but often becomes a hashtable). Assuming that your for(;;) test was iterating over indexes from 0..len-1, each iteration does a hash lookup. We’d like lookup to be O(1) amortized, but there is considerable hidden overhead in doing the lookup.&lt;br /&gt;&lt;br /&gt;The hash function is a quadratic probe, and we have a high load factor (~80%), so a large array has a high probability of collision. To calculate the address, integers indexes must be cast to Number (not terrible, but this is why the Flex SDK uses Number instead of Integer). If you index on a string or the cast fails, we stringify the index, intern it, and use that (!).&lt;br /&gt;&lt;br /&gt;You *might* be able to tell if you have a dense array if the ‘for each’ loop returns items in ascending order, but that’s just a guess. You could try it with a 10 element array versus a 1000 element array, perhaps.&lt;br /&gt;&lt;br /&gt;Player 10 should improve some of the casting costs and differences in performance between numerical types.&lt;br /&gt;&lt;br /&gt;—&lt;br /&gt;&lt;br /&gt;Another gotcha. Though no professional uses them, ‘with’ blocks introduce the same overhead that anonymous functions do, without any of usefulness. [Ed: It was pointed out to me that it's super-useful in graphics code -- true! though given the number of instructions you're likely to give for any non-trivial graphic, you're best off making a variable named g and being explicit about it.] You push the with object onto the scope chain, and then have to search the scope chain for every call within that block.&lt;br /&gt;&lt;br /&gt;Too bad we didn’t implement them the way VB did, where you could tell which statements used the with object because they all started with a “.” (of course, there would be limitations).&lt;br /&gt;&lt;br /&gt;Many equivalent expressions in AS3 are not equivalent in byte size or performance. Many of the convenience mechanisms, like with, are useless because their performance is so poor. I always meant to explore this and actually write posts in my blog, flexamphetamine.&lt;br /&gt;&lt;br /&gt;By the way: Have you tested different kinds of variable accesses? I forget what my results were (two years ago…), but this might have been the order of expense (from least): argument variables (strange, huh?), local variables, class variables. I don’t think I tested statics.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6692324655955282410-3435297452022085520?l=flexamphetamine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/3435297452022085520/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6692324655955282410&amp;postID=3435297452022085520' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/3435297452022085520'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/3435297452022085520'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/2009/12/closure-on-closures-terrible-typing-for.html' title='Closure on Closures, Terrible Typing, For-Each Failures'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6692324655955282410.post-3822579987204935226</id><published>2009-03-26T20:29:00.000-07:00</published><updated>2010-07-27T00:54:44.282-07:00</updated><title type='text'>Alphas Go to Eleven</title><content type='html'>In case you've always wondered why setting alpha to 0.9 doesn't return 0.9 when you read it back...&lt;br /&gt;&lt;br /&gt;Internally, alpha is stored as an integer between 0 and 255, and auto-rounded/converted from the input of [0, 1.0]. This is braindumb design, but a fact of life.&lt;br /&gt;&lt;br /&gt;So if you add 0.1 ten times to an alpha of 0, you get a number less than 1.0, and need to go to eleven (going to eleven is usually a good thing, but in this case it isn't).&lt;br /&gt;&lt;br /&gt;If you are incrementing the alpha by 0.01, the actual alpha will be off more than 20% by the 100th iteration (!).&lt;br /&gt;&lt;br /&gt;So the only way to keep alphas honest is to store the last value you tried to set alpha to, and use that as the input in your code.&lt;br /&gt;&lt;br /&gt;Moral: Don't use the existing value of alpha (ever), always set it and manipulate it from a model.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6692324655955282410-3822579987204935226?l=flexamphetamine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/3822579987204935226/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6692324655955282410&amp;postID=3822579987204935226' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/3822579987204935226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/3822579987204935226'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/2009/03/alpha-and-omegainaccuracy-or-this-goes.html' title='Alphas Go to Eleven'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6692324655955282410.post-616693063847190943</id><published>2009-02-08T15:18:00.000-08:00</published><updated>2009-02-17T20:09:45.960-08:00</updated><title type='text'>Monkeypatching the cached Flex framework RSL</title><content type='html'>I believe I discovered a *consistent* method to monkeypatch the Flex framework with RSLs. I assume you understand what a preloader is, and how to monkeypatch without RSLs -- there is plenty of documentation on both.&lt;br /&gt;&lt;br /&gt;Like the first time you type sudo:&lt;br /&gt;&lt;pre&gt;We trust you have received the usual lecture from the local former Flex SDK dev. It usually boils down to these three things:&lt;br /&gt;    #1) Respect the privacy of other classes.&lt;br /&gt;    #2) Think before you patch.&lt;br /&gt;    #3) With great power comes great responsibility.&lt;/pre&gt;Create an empty preloader class (or add to an existing one) which contains the following, substituting for whatever you're patching.&lt;br /&gt;&lt;pre&gt;    import mx.managers.FocusManager; FocusManager;&lt;/pre&gt;And that'll do it. The class will get preloaded, before the cached framework gets loaded. Simple and obvious now, eh?&lt;br /&gt;&lt;br /&gt;---&lt;br /&gt;Note: If using RSLs, you may see significant code bloat. Classes get loaded in order of dependency -- if the dependency of UIComponent isn't present when it tries to load, it fails.&lt;br /&gt;&lt;br /&gt;So if you are patching high up in the dependency tree, like UIComponent, all the required classes will get compiled into the main SWF, as they are loaded before the RSLs.&lt;br /&gt;&lt;br /&gt;Notably, this is unlike how Java's class loader works.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6692324655955282410-616693063847190943?l=flexamphetamine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/616693063847190943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6692324655955282410&amp;postID=616693063847190943' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/616693063847190943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/616693063847190943'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/2009/02/monkeypatching-cached-flex-framework.html' title='Monkeypatching the cached Flex framework RSL'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6692324655955282410.post-7840198166559430080</id><published>2009-01-08T21:50:00.000-08:00</published><updated>2010-07-27T01:03:53.552-07:00</updated><title type='text'>Heisenberg on Garbage Collection</title><content type='html'>Detecting if a reference gets garbage collected is tricky. In general, you cannot do this because of the Heisenberg Uncertainty Principle -- if you hold a reference, then it cannot get GCd; if you don't hold it, then you cannot check if it got GCd. Until now :)&lt;br /&gt;&lt;br /&gt;Example (try uncommenting the line which nulls our important reference):&lt;br /&gt;&lt;code&gt;&lt;br /&gt;// the object we're curious about&lt;br /&gt;var impReference:Object = new Object();&lt;br /&gt;public function init():void&lt;br /&gt;{&lt;br /&gt;// this code monitors an object for GC, giving it a name.&lt;br /&gt;monitorGC("impReference", impReference);&lt;br /&gt;//impReference = null; // try uncommenting me&lt;br /&gt;&lt;br /&gt;// GC rarely occurs until after code runs, after a frame or so&lt;br /&gt;callLater(function():void&lt;br /&gt;{&lt;br /&gt;// call twice USUALLY makes a GC occur, as does opening&lt;br /&gt;// a LocalConnection to the same name twice in a row&lt;br /&gt;System.gc();&lt;br /&gt;System.gc();&lt;br /&gt;// look at the error console&lt;br /&gt;if (checkIfGCd("impReference"))&lt;br /&gt;trace(name + " got GCd")&lt;br /&gt;});&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// support code&lt;br /&gt;static public function monitorGC(name:String, reference:*):void&lt;br /&gt;{&lt;br /&gt;// this is how we get around Heisenberg, a strong Dictionary holding&lt;br /&gt;// weak dictionaries, each holding a single reference, or no references&lt;br /&gt;(gcReferences[name] = new Dictionary(true))[reference] = true;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static public function checkIfGCd(name:String):Boolean&lt;br /&gt;{&lt;br /&gt;var gotGCd:Boolean = true;&lt;br /&gt;for (var foo:* in gcReferences[name])&lt;br /&gt;gotGCd = false;&lt;br /&gt;return gotGCd;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static private const gcReferences:Dictionary = new Dictionary();&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6692324655955282410-7840198166559430080?l=flexamphetamine.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexamphetamine.blogspot.com/feeds/7840198166559430080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6692324655955282410&amp;postID=7840198166559430080' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/7840198166559430080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6692324655955282410/posts/default/7840198166559430080'/><link rel='alternate' type='text/html' href='http://flexamphetamine.blogspot.com/2009/01/detecting-if-reference-gets-garbage.html' title='Heisenberg on Garbage Collection'/><author><name>Jono Spiro</name><uri>http://www.blogger.com/profile/18049464955638696760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_mQGHKylmpIA/TNHkYetpFZI/AAAAAAAAAI0/3MzqnxXt4RQ/S220/Picture+1+copy.png'/></author><thr:total>0</thr:total></entry></feed>
