Tuesday, 20 October 2009

robotLegs meets as3-signals?

The flash event model is a bit... sucky.

Robert Penner wrote these 3 blog posts which summarise the limitations:

He's been working on an alternative known as as3-signals, which you'll find on git-hub.

Essentially signals seem to provide the following enhancements: (correct me if I'm wrong here)
  1. A type based rather than string based registration for an event.
  2. Compile time checking that you only register for relevant signals. If SomeClass doesn't have a .clicked signal then you won't be able to listen for it.
  3. Centralised and handy functions for removing all listeners from an event.
  4. The ability to add a listener for one time only (and have it automatically removed).
  5. Useful runtime errors (if you use 'addOnce' after you've already used 'add' or the reverse you get a sensible error).
  6. The option to prioritise listeners - enforcing a calling order.
I'm currently working on this modularised rebuild of an existing piece of complex software. Inter-module communication is the thing I'm thinking about most.

I've also been checking out the interesting stuff over at robotlegs - a DI driven framework which looks light and really focussed... except that Flash CS4 won't let you use the metadata required, so it seems to be Flex only for now.

However, it has a nice command and event mapping model - allowing for type checking, 'one shot only' and so on.

So... I'm considering the benefits of a hybrid. Of creating a command mapped version of as3-signals.

Questions:
1) How to replicate the nice compile time checking that Signals provides while also supporting the decoupling of the modules via the centralised command map - so you can't register for an event that will never exist.

2) Where to put the events? Which package? Do they need to reside in a centralised area?

3) Is this a complete waste of time? Does the command map already provide sufficient decoupling? Should I simply use signals within a module and the command map between modules?

4) Could a module create a new signal 'channel' dynamically, or does that make no sense at all?

Questions... questions...

Wednesday, 16 September 2009

A framework for Modular AIR Applications

I've finished building a framework for securely loading signed, packaged swfs into the application sandbox at runtime, while leaving others in the non-application sandbox and rejecting modules without matched signatures.


The framework fairly neatly packages the whole process.

The origin of the signature testing process is the Adobe article here, where you can also download a compiled code swc of the necessary flex-only classes if you're working in Flash.

The air application I've built as proof-of-principle achieves the following:
  • Modules with matching signatures are loaded to the app sandbox (if requested).
  • Modules without matching signatures requesting app sandbox loading are rejected.
  • Modules can also be loaded to the non-application sandbox.

It demonstrates:
  • That app sandbox loaded modules can write to the file system (they put a directory on your desktop).
  • That non-app sandbox loaded modules are prevented from writing to the file system.
  • That both app and non-app sandbox loaded modules can pass library assets to the main application to be added to the display list.

It has a lot of user feedback / developer feedback built in. In the absence of the ability to trace in the air application itself I'm listening for this feedback and displaying it in a textarea in the main application.

Currently the information about what to load and how to load it, and where to find the .zip assets on a server to install modules, is all contained in moduleData.xml inside the applicationFlasAndCode folder. When you start the application you must browse to this file.

To use the framework:
  1. Use ModuleXMLLoader to load an xml document containing your module information.
  2. This creates a strongly typed iterator: ModuleDescriptionIterator.
  3. Instantiate ModuleChainLoader, passing it that iterator.
  4. Listen for the ModuleEvent.MODULE_LOADING_COMPLETE event.
  5. Ask the moduleChainLoader to startLoadingModules().
  6. When you handle the loading complete event, run getModuleDictionary().
  7. Access your modules from the ModuleDictionary using getModule() and getSandboxedModule(). You pass the module's unique name to those functions. They pass back the required module.

Any questions at all, post them here or email me.


How secure is secure?

I'm building an enterprise training application. It already exists in AIR, but we're moving to a modular system because our users don't have the permissions required to run the automatic updates.

Secure, for me, is secure enough not to be the preferred target for a malicious attack. Nothing is impossible, but I want to make it sufficiently difficult / tedious that anyone intending to cause trouble looks elsewhere to do it.


Notes:

In my own final application the xml will be a secure data stream coming from a server.

If you want to keep my xml structure you can use the ModuleXMLLoader class as is, but I've kept it as a separate stage in the process so that you can make changes to this.


Some possible gotchas to avoid:
  • The example module flas have classes which extend ITestableModule. You'll need to point flash to the com folder in order for this interface to be found.
  • Remember that flash keeps signing with the last certificate you used. So when creating good and bad modules, and compiling the app itself, keep an eye on which certificate you're using.
  • Module .air packages need to be renamed .zip
  • You cannot test secure loading in the flash test player. You have to create the application .air file, install it and run it to test it.
  • Don't forget to grab that SignatureUtils.swc from the Adobe link.

Tuesday, 1 September 2009

Creating modular applications in Adobe AIR

Identity is on hold at the moment, work still being too hectic. I'm hoping to really get down to it next year - I've got 3 O'Reilly books on the way out by March next year, and they're eating all my time.

In the meantime, the main work project I've got going on is a nice fit with what Identity needs to achieve in terms of modularity. It's an e-learning app, already running successfully as an Air application, but we're rebuilding it to achieve the following:

1) Dynamically built modular environment. Other than the AIR shell itself, all the functionality will be loaded by the app at runtime. This allows for non-admin updates, and for user A and user B to have different logging systems / quiz engine etc.

2) Reskinned at runtime. Different departments and sub companies of the corporate client can have a different look and feel, maybe even a different screen size requirement.

I've already grappled with the Air security sandbox stuff within this app. The lessons themselves are dynamically loaded and using sandbox bridge for communication. The current quiz apps are also decoupled, and only simple data is passing around - mostly I'm using strings of xml for more structured data requirements.

I've been playing with the two variations of loading content into flash:

A) The light side: use a normal loader, put your downloaded content into a sandbox where it can only access other content via the safe and secure bridge.

B) The dark side: read the file into a ByteArray and use loadBytes() with allowLoadBytesCodeExecution = true on the loader context, to give your loaded content the run of the place... including the fileSystem.

The pros and cons of breaking the Air security model

The light side:

Events
Events must be passed using loaderInfo.sharedEvents. Only built-in events keep their type, but that's ok. The actual Event.type property is just a plain string anyway, so you can still make use of a custom event for compile time checking to avoid typos, as the Air shell doesn't care that it didn't know what MyCustomEvent.DOG_BARKED was - it just sees "dogBarked". On the down side you can't pass useful extra data with your custom events.

Security
You can use sensible functions like storeAsset(assetPath:String) to pull in things and read / write to the file system, rather than opening up your user's computer for an attack by rogue dynamically loaded modules.

Loading grandchildren
Loading a grandchild asset such as a png or jpg seems to be possible using loadBytes() with code execution set to false. You have to pass the byteArray as a normal array, reconstruct it to be a byteArray, and then load the content in the child module. I've only part tested this. More to follow. And it's pretty gross as a process.

Decoupling logic and events is ok
Modularising the logic of the application doesn't actually seem to be too hard. The code was pretty nicely decoupled already, and we think we can reduce inter-module communication to a combination of vanilla events and xml (passed as string). We'd use the Air shell as a postman to deliver messages from one module to another. There would be an unnerving amount of dynamic stuff which isn't checkable at compile time, but it's doable.

Major hurdle: providing skin assets at runtime
I simply can't find any way to load the actual graphics for the modules at runtime. All I want is to load a specific (dynamically selected) swf with a bunch of MCs in the library, and to be able to do stuff like "new LoginButtonUpSkin()" and whack the requested graphic into the right place. I guess we could export all of our graphics as pngs and use the loadBytes() trick to feed them to the individual modules, but how grim is that?

The other option would be to compile variations on the modules themselves, with different look and feel. "MainMenuGreen.swf" "MainMenuBlue.swf". That feels like a huge pain in the ass when it comes to creating new skins. The designers would need access to the code library, they always ring me up wondering how to link their files to the com folder... you can see the potential headaches I'm sure...

The dark side:

Events: Module to module event traffic is possible. Events don't lose their typing when passing from module to module.

Security: This is dangerous stuff. But all my modules are coming from a trusted server and there's a technique for verifying signatures. Basically any module that wants to be loaded into the application sandbox using the loadBytes() method would have to be an Air app in itself. Then that air package gets loaded and ripped open, the signature verified and the module loaded or rejected. I've no doubt that it's not failsafe.

Will adobe continue to provide this work-around?
The adobe official documentation on working securely with untrusted content end with the following fear-inducing statement:

Note: In a future release of Adobe AIR, this API may change. When that occurs, you may need to recompile content that uses theallowLoadBytesCodeExecution property of the LoaderContext class.

A future release WHEN? What? And will I need to recompile content even if it's happily running. Will Air 2.0 break my 1.5 application if I've used this? Presumably Adobe would provide a better work around for achieving this, but my client doesn't want to do a thousand admin-requiring reinstalls... which is why we're going to use a module based system in the first place...

At the moment I'm still testing, still lurching from favouring one side to the other. More to follow as it unfolds. Hopefully I can save someone the three days of googling and testing I've just been through.

Wednesday, 17 September 2008

TextMate for Flash, Actionscript 3 and asdoc

The Flash IDE sucks. I never quite manage to feel at home in the eclipse interface and Flex whines about my Flash components when I try to compile documentation. Powerflasher looks good but resides within eclipse, and FlashDevelop is PC only.

I love TextMate, and I wanted to sort out my workflow so I could edit .as files in TextMate, compile in Flash and also create asdoc documentation for all my code. I read up online and followed a few people's instructions but found I was still a mile away from what I needed. Having worked through those issues, here's a step-by-step guide to getting to a coherent code-document-compile set up with TextMate and Flash.

Note: The paths to put stuff are a good guide, you can alter them if you like later. Create any folders that don't already exist as you go. HD is a substitute for whatever you've named your main Hard Drive. I found that on one of my computers the folder HD/Developer/ was heavily restricted and I had to change the permissions and then apply to enclosed items to give myself write access.

1) Install the Flex 3 SDK (free)

Download from : http://opensource.adobe.com/wiki/display/flexsdk/Download+Flex+3

I downloaded the latest milestone build of the Adobe Flex SDK (not the open source version) but there are also nightly build s available, and stable interim builds too.

Put this folder in : HD/Developer/SDKs/ and then rename the folder to be called Flex.




2) Download and install TextMate (free trial, then $50)

You can get the application file at : http://macromates.com/

A 30 day trial is available, but I'm sure you'll want to buy it. The best $50 I've ever spent on software.


3) Get the TextMate bundles for Actionscript 3, Ant and Flex

You can download the zip files of zipped stable builds from the side bar of creator Simon Gregory's blog: http://blog.simongregory.com/10/textmate-actionscript-3-and-flex-bundles/

The zips are in the right hand column under "Bundles".

To install these, just double click the .tmbundle file once it has unzipped. Textmate will install them in the right place and the file will disappear from your downloads folder.


4) Copy the Flash components .swc files to your SDKs folder

Within HD/Developer/SDKs/ create a folder called AS3.

Copy the Applications/Adobe Flash CS3/Configuration/Components/ folder into this /SDKs/AS3/ folder.



5) Set up your TextMate project.

I keep all my AS3 classes in one top level folder, which also then contains my asdoc building stuff and my docs folder once the documentation is created. You may want to do something different - so feel free to tweak this once you're all set up.

So - my top level folder is /as3_classes/ (this name is not used anywhere so you can call it whatever you like), and it contains my top level packages - com, uk.

Within this folder you should also create the subfolders /asdoc_ant/, /fl/ and /docs/.

In order to be able to work with files which refer to flash components, you need to fill this /fl/ folder with all the fl. package classes.

You'll find these in Applications/Adobe Flash CS3/Configuration/.

There are 4 sets to copy, all of which need to go into that single /fl/ folder in your top level folder. There are two sets of video package files, make sure you add one to the other and don't just overwrite the first. Be certain to copy and not just move these files or your Flash App will go crazy.

Within the /Configuration/ folder above, the 4 fl folders are at:

- /ActionScript 3.0/Classes/
- /Component Source/ActionScript 3.0/FLVPlayback/
- /Component Source/ActionScript 3.0/FLVPlaybackCaptioning/
- /Component Source/ActionScript 3.0/User Interface/

Once you've got them all you should have a list of subfolders like the image on the left.

Now, to create your project, within TextMate do File > New Project. Simply drag your top level folder (the one I called as3_classes, which contains your packages, docs, fl and asdoc_ant) to the folder pane where it says "Drag Files and Folders Here".


6) Create your build.xml file


Within /asdoc_ant/ create a new xml file called build.xml. Paste the following into it:
<project name="asdoc" default="asdocs">
<target name="asdocs">

<!-- Clean out the contents of the doc directory, without deleting "docs" -->
<delete includeemptydirs="true">
<fileset dir="../docs/" includes="**/*" />
</delete>

<exec executable='/Developer/SDKs/Flex/bin/asdoc' failonerror="false">
<arg line='-library-path /Developer/SDKs/Flex/frameworks/libs'/>
<arg line='-library-path /Developer/SDKs/Flex/frameworks/libs/air'/>
<arg line='-library-path /Developer/SDKs/AS3/Components'/>
<arg line='-library-path /Developer/SDKs/Flex/frameworks/locale/en_US'/>

<!-- these classes are required in your source files in order to use the flash components, but
we really don't want to have to error check and create documentation for them -->
<arg line='-exclude-classes fl.accessibility.AccImpl fl.accessibility.ButtonAccImpl fl.accessibility.CheckBoxAccImpl fl.accessibility.ComboBoxAccImpl fl.accessibility.DataGridAccImpl fl.accessibility.LabelButtonAccImpl fl.accessibility.ListAccImpl fl.accessibility.RadioButtonAccImpl fl.accessibility.SelectableListAccImpl fl.accessibility.TileListAccImpl fl.accessibility.UIComponentAccImpl fl.containers.BaseScrollPane fl.containers.ScrollPane fl.containers.UILoader fl.controls.BaseButton fl.controls.Button fl.controls.ButtonLabelPlacement fl.controls.CheckBox fl.controls.ColorPicker fl.controls.ComboBox fl.controls.DataGrid fl.controls.dataGridClasses.DataGridCellEditor fl.controls.dataGridClasses.DataGridColumn fl.controls.dataGridClasses.HeaderRenderer fl.controls.Label fl.controls.LabelButton fl.controls.List fl.controls.listClasses.CellRenderer fl.controls.listClasses.ICellRenderer fl.controls.listClasses.ImageCell fl.controls.listClasses.ListData fl.controls.listClasses.TileListData fl.controls.NumericStepper fl.controls.ProgressBar fl.controls.progressBarClasses.IndeterminateBar fl.controls.ProgressBarDirection fl.controls.ProgressBarMode fl.controls.RadioButton fl.controls.RadioButtonGroup fl.controls.ScrollBar fl.controls.ScrollBarDirection fl.controls.ScrollPolicy fl.controls.SelectableList fl.controls.Slider fl.controls.SliderDirection fl.controls.TextArea fl.controls.TextInput fl.controls.TileList fl.controls.UIScrollBar fl.core.InvalidationType fl.core.UIComponent fl.data.DataProvider fl.data.SimpleCollectionItem fl.data.TileListCollectionItem fl.events.ColorPickerEvent fl.events.ComponentEvent fl.events.DataChangeEvent fl.events.DataChangeType fl.events.DataGridEvent fl.events.DataGridEventReason fl.events.InteractionInputType fl.events.ListEvent fl.events.ScrollEvent fl.events.SliderEvent fl.events.SliderEventClickTarget fl.lang.Locale fl.livepreview.LivePreviewParent fl.managers.FocusManager fl.managers.IFocusManager fl.managers.IFocusManagerComponent fl.managers.IFocusManagerGroup fl.managers.StyleManager fl.motion.Animator fl.motion.BezierEase fl.motion.BezierSegment fl.motion.Color fl.motion.CustomEase fl.motion.easing.Back fl.motion.easing.Bounce fl.motion.easing.Circular fl.motion.easing.Cubic fl.motion.easing.Elastic fl.motion.easing.Exponential fl.motion.easing.Linear fl.motion.easing.Quadratic fl.motion.easing.Quartic fl.motion.easing.Quintic fl.motion.easing.Sine fl.motion.FunctionEase fl.motion.ITween fl.motion.Keyframe fl.motion.MatrixTransformer fl.motion.Motion fl.motion.MotionEvent fl.motion.RotateDirection fl.motion.SimpleEase fl.motion.Source fl.motion.Tweenables fl.transitions.Blinds fl.transitions.easing.Back fl.transitions.easing.Bounce fl.transitions.easing.Elastic fl.transitions.easing.None fl.transitions.easing.Regular fl.transitions.easing.Strong fl.transitions.Fade fl.transitions.Fly fl.transitions.Iris fl.transitions.Photo fl.transitions.PixelDissolve fl.transitions.Rotate fl.transitions.Squeeze fl.transitions.Transition fl.transitions.TransitionManager fl.transitions.Tween fl.transitions.TweenEvent fl.transitions.Wipe fl.transitions.Zoom fl.video.AutoLayoutEvent fl.video.ComponentVersion fl.video.ConnectClient fl.video.ConnectClientNative fl.video.ControlData fl.video.CuePointManager fl.video.CuePointType fl.video.FLVPlayback fl.video.flvplayback_internal fl.video.FPADManager fl.video.INCManager fl.video.IVPEvent fl.video.LayoutEvent fl.video.MetadataEvent fl.video.NCManager fl.video.NCManagerNative fl.video.ParseResults fl.video.QueuedCommand fl.video.ReconnectClient fl.video.SkinErrorEvent fl.video.SMILManager fl.video.SoundEvent fl.video.UIManager fl.video.VideoAlign fl.video.VideoError fl.video.VideoEvent fl.video.VideoPlayer fl.video.VideoPlayerClient fl.video.VideoPlayerState fl.video.VideoProgressEvent fl.video.VideoScaleMode fl.video.VideoState'/>
<!-- the source of your code to generate docs for - I'm only doing my com folder -->
<arg line='-doc-sources ../com'/>
<!-- where the documentation ends up -->
<arg line='-output ../docs'/>
<arg line='-templates-path /Developer/SDKs/Flex/asdoc/templates'/>
<!-- where to look for top level packages - eg the fl package -->
<arg line='-source-path ../'/>
<!-- edit this to include your own footer -->
<arg line='-footer newloop'/>
</exec>
</target>
</project>
Thanks to many other bloggers I've borrowed sections of that xml from, it was hugely appreciated when I was struggling to get my own version set up.

If you've set up exactly as I've described above then you shouldn't need to edit that file. If you've used other locations then you'll need to edit your file paths to match. It doesn't like paths with spaces in.

You'll notice that the list of excluded classes is pretty long and basically contains all the flash component and base classes, so that you're not compiling documentation on those.


7) Do your FIRST (of many) test documentation build.


These next steps are basically a cycle of building, failing, fixing something, building and failing a bit better and so on until you finally have documentation.

With the build.xml file open in TextMate, press Apple-B to build, or go to bundles > ant > Build.



Most likely you will a list of over 100 errors. It seems to stop and fail at around 115 or so. This doesn't mean that you only have 115, but that it has given up.

Weirdly it then also says "BUILD SUCCESSFUL". This is nonsense - your build did not work. Don't panic, that's totally normal. Some of those errors can be reduced by changing the flex config settings to be less strict. Personally I worked with the least strict config possible until I knew that I could build SOME documentation. Then I reintroduced the strictness and debugged as I went.

To alter the strictness of your flex config open

HD/Developer/SDKs/Flex/frameworks/flex-config.xml in TextMate.

Set the following:
<show-actionscript-warnings>false</show-actionscript-warnings>

<strict>false</strict>
Save the flex-config.xml file.

Build again. Fail again. See the next step for tips for debugging.


8) Fixing your code to get rid of those errors ...

This was a long process, but the types of errors in my classes that I had to sort out may help you on your way:

a) If you have errors like "Error: Type was not found or was not a compile-time constant: TextInput." where you recognise that the type not found is a flash component then check that you've definitely put the flash component swc files in your SDKs folder and the fl files in your top level directory.

b) Historical stuff related to old unit tests / files not now required. Mostly I just binned those. They gave me errors like "Interface not properly implemented" - which is true as I had stopped developing those test files and continued with the interface.

c) Flash Library issues - eg "24 Error: Type was not found or was not a compile-time constant: TestClip.
[exec]
[exec] private var testArea:TestClip;"

Where TestClip was a movieclip inside the library of a Fla, exported with the name "TestClip". You know when the flash IDE says "Don't worry, I'll create this class at runtime ... " well, that's no good for ASDocs.

As tedious as it was, my only option was to create actual classes for all those linked in MCs. And of course I then need to go back to the Fla files and change the export linkage of those symbols in the library to match the final class path. Dull. There may be a way around this but I wasn't able to find one.

d) Issues with 3rd Party frameworks such as Yahoo astra components.

I consistently got the following error:

/Volumes/loopShop/as3_classes/com/yahoo/astra/animation/Animation.as(85): col: 21 Error: Type was not found or was not a compile-time constant: Animation.
[exec]
[exec] var oldAnimation:Animation = Animation.targetsToAnimation[target];

In the end I just dumped from my library the Animation class and everything that depended upon it. Which was OK as I wasn't actually using it. If you are using it then you might have to approach yahoo for a solution - they have their own documentation which must be coping with this error, so perhaps they can help.

e) Issues with Adobe Flash components / core classes.

The only one I found was:

[exec] /Volumes/loopShop/as3_classes/fl/core/UIComponent.as(968): col: 63 Error: Parameter initializer unknown or is not a compile-time constant.
[exec]
[exec] public function invalidate(property:String=InvalidationType.ALL,callLater:Boolean=true):void {

It basically didn't like the use of the InvalidationType.ALL constant. Instead I changed it to "all", which is the value from the InvalidationType class, and it works ok.

You should be able to work through the errors you get, removing classes that are causing problems and aren't needed, fixing pathing issues (I had a few classes where I'd moved them outside their original package accidentally) and creating real class paths for classes which were previously created by flash at runtime.

With any luck your error numbers are reducing, and eventually you get the prize - it generates some documentation in your /docs/ folder!


9) Reinstate some of the compiler strictness

Next you can switch your flex-config back to show warnings:

<show-actionscript-warnings>true</show-actionscript-warnings>
there are a bunch of different things you can warn about, but the really interesting one is this (nearer the bottom):

<warn-no-type-decl>true</warn-no-type-decl>
This one was a real eye opener to me. I had no idea how often I created a variable without specifying a type. I remember probably 90% of the time, but those 10% are a real liability. It created a huge list for me to fix but I think it was worth it as now I can fix them as I go, simply by running my asdoc build before I finish for the day and spotting them regularly.

If you use automatic stage variable declaration in flash then you'll be unable to switch back to strict mode. It will freak out about you using this.myTextField in the middle of a class when myTextField isn't declared as a variable at the top.

So, you need to use:
<strict>false</strict>
If you don't have a bunch of legacy stuff with stage variables being used without being found then you can switch back to strict = true.

When I finally got my docs to compile (a wonderful moment) the ant build also threw a ton of warnings about fl package files that were being excluded and that it couldn't find them. I know I should care about this, but it hasn't caused me any problems so far. My guess is that these are entries in the excluded classes which don't have a corresponding .swc file, but if you've got a better idea let me know.

I have quite a large code library and it takes about four minutes to build my documentation.


10) Edit the ActionScript 3 bundle to use apple-enter to compile your Fla


TextMate top menu > Bundles > Bundle Editor

Unfold the ActionScript 3 bundle on the left.

Click the + button and select "New Command". I called mine "Test in Flash".


Save > All Files in Project
Commands :
echo "document.testMovie();" > /tmp/fc.jsfl
open /tmp/fc.jsfl -a "Applications/Adobe Flash CS3/Adobe Flash CS3.app"
Input > None
Output > Discard
Activation > Key Equivalent (I made mine apple-enter as that's my reflex)
Scope Selector: leave blank

To compile a fla you need to have the fla open in flash. Then from TextMate just press your activation key (apple-enter is mine) and it switches to flash and does the deed.

You can also edit the bundle editor to suit your own for loop style etc. The tab completion stuff is fab.

---

You're all set (hopefully).

Let me know if you have any questions, good luck!

Friday, 5 September 2008

Quick update

Eek! I've been so slack at keeping this updated. Apologies. My housemate / work partner broke her ankle a few weeks back and life is slightly more complex than usual until she has the use of that leg again - hence no time to really devote to Identity. 

Photo evidence is available on my personal house-blog if you're into that sort of thing.

Life resumes (hopefully) on the 25th September when the cast comes off and simple tasks such as carrying a cup of tea to the place where she wants to drink it become possible again.

Wednesday, 16 July 2008

Still here, and loving TextMate for AS3

Just a quick note to say that I haven't abandoned Identity and / or fallen under a bus.

The book I'm writing at the moment is in the final intense stages, so spare time is non-existent.

I'll try to reply today to anyone who has emailed me and not heard back. 

As an aside - last week I finally completed configuring TextMate to edit all my AS3 projects, and use ant to produce asdocs. I'm mostly working in Flash rather than Flex so it took a bit of wiggling to get the fl. package stuff to stop complaining.

Clearly if you're on Windows then you've got the option of FlashDevelop, but on Mac I've tried Flex, Eclipse with Powerflasher FDT, jEdit, coda (which I'm still using for everything except AS3) and of course the good ol' Flash IDE, but I've finally settled on TextMate and I'm really happy with it.

I'd been using TextMate as a 'power editor' to do extensive find / replace type tasks when refactoring for a while, but had come across multiple problems that stopped me from switching to it for all my AS3 and asdocs.

I'll post a complete run down of how I've finally got it set up next week. Google code group and this blog should be active again from the end of next week onwards. 

 

Saturday, 21 June 2008

Aviary invites

I've got 5 aviary invites to give away.

Let me know if you're interested.