Wednesday, June 29, 2005


General Updates

Well, I've been busy over the last couple of days, mostly working on getting the GPLFlash Wiki populated with some base-line information. I've also filled in the final sections of my knowledge management paper; feedback on this paper would be welcome :).

Also, I'm probably going to be out of touch for the next 5 days — going to visit relatives tomorrow, and then I'll be attending a four-day LAN party directly afterwards. I'll see what I can do between rounds at the party, but communication is likely to be sporadic; don't count on anything ;).

Saturday, June 25, 2005


MoinMoin: The Tentative Winner

So, now that I've tinkered around with it a bit, it looks like MoinMoin could come out as being the wiki that powers GPLFlash. Briefly, here are the pros and cons of the system:

If anything else springs to mind, I'll be sure to update this post. In the mean time, I'm probably going to go about re-installing MoinMoin and setting up the site for a test pilot.

Friday, June 24, 2005


So Many Wikis, So Little Time

Well, I've been installing and uninstalling wikis like crazy over the last couple of days, along with the assistance of Thomas. For future reference, here are the systems that we've tested, and why we've rejected each:

Currently, I've got MoinMoin installed. It was a bit of a pain to set up, but now that it is installed, it looks like it may actually have real user support (!). I wouldn't have thought that such a basic feature — logging in — would be so hard to find. I'll continue tinkering with MoinMoin and see if it's all-around adequate for our needs.

Update: Other wikis that were rejected:

Thursday, June 23, 2005


GPLFlash and Knowledge Management

Well, I decided to start putting a little more work into the knowledge management paper I'm doing for school, and I'm almost finished with it. I've decided to put the work in progress (PDF) up for anyone who's interested — if anyone would like to comment on it, please feel free.

Wednesday, June 22, 2005


More Rotten Fruit

ArgoUML can't differentiate between classes with the same name but in different namespaces. Hello, guys; remind me what the whole point of namespaces is? ArgoUML also has a UI that is so painful to use, I almost want to slam my computer to the floor in frustration. Drag-and-drop works, but only some of the time in some cases; click-to-edit works, but sometimes the changes take and sometimes they don't; while working, internal parts of the program seem to crash and can only be fixed by a restart… the thing feels like it's taking lessons from a younger M$. I swear I have never been this angry at a program before — and it takes a lot to get me angry, especially at a computer.

I think that the most frustrating thing is that the program seems like it could be vastly useful if the UI weren't so bad… and the software weren't so buggy… and the model elements interacted in an intuitive fashion… and it could import XMI right… I don't know how, through all these flaws, it manages to seem useful, but it does pull it off, and it's utterly infuriating. Unless you want to bash your head against the wall, do not use this software.

So, here's the make/break list for the software I've tried thus far:

So, I'm bust for tools. I think I'll go back to Umbrello, since it's pretty close, and very simple to use… it just has crappy code gen. But I think I can live with that *sigh*. Can anyone else recommend a good tool?

Tuesday, June 21, 2005


Rotten Fruit

So, I got through a good chunk of design in Umbrello, only to realize that it doesn't have any concept of a const member function (i.e., a "query" stereotype method). I'm a very const-aware person, and the lack of this feature makes the whole tool utterly worthless to me. What's even more aggravating is that I can't open the XMI file in ArgoUML. So much for interoperability… I'm currently hand-copying the information over to ArgoUML (which does handle the query stereotype), and I'll post that XMI file when I've finished. If you haven't noticed, I'm keeping the design link on the "links" list; the last updated time will help you figure out if you have the newest version or not.

Monday, June 20, 2005


Fruits of Labor

Well, I've found a diagram editor that I really like, and it spits out files that seem to be standardized/portable (XMI). So, I've gotten some very rough (and by no means complete) gplflash models done, at long last. You can read the files with Umbrello, or with other tools that can read XMI (like ArgoUML, or Gaphor)

I've also tarballed my current SWFIO concept, which at the moment provides access to only the SWF primitives.

Update: I forgot to mention that feedback is requested; sending in diffs and ideas would be much appreciated!

Friday, June 17, 2005


Coming Attractions

I've retargeted my school project to incorporate GPLFlash2 — that way, I'm really only working on one project, and getting real work done with the project (instead of just fake academic-land "work"). It will be a small (fewer than 15 pages) report on Knowledge Management, and how the GPLFlash project could greatly benefit from it. I'll make it available as an sxw and a PDF as soon as I've finished it.


SWF Rendering: Part 1

Now that I have the basics down, I've started to take a deeper look into SWF overall, in order to get a better feeling of where I'm going and what design decisions need to be made along the way. As part of this process, I've decided to write a set of articles explaining how the SWF rendering process works. This will serve three purposes:

In this article, we'll go over SWF interpretation up to and including definition tags. The next article will be dedicated to the interpretation of non-ActionScript control tags, and possibly the visual model that the SWF format should be interpreted with.

Step 1: Decoding Tags

Before anything else can happen, the data from the file must be parsed into data structures in memory. There are three major parts to this on the file wide scale:

  1. Header extraction
  2. Decompression (dependent on header)
  3. Tag extraction

"Tag extraction" is a bit vague, however; the RecordHeader data structure means that we could extract all of the tags simply by pulling the appropriate number of bytes out of the stream and store them in a character array. This wouldn't be very useful, however, since we still wouldn't know what information is trying to be conveyed by the file. Thus, we have a little more to do on the per record scale (header included):

  1. Know what type of record we're extracting
  2. Know the SWF primitives (their type, order and meaning) that make up the record
  3. Extract each primitive to a corresponding, size-compatible, in-memory variable.

Once we can extract tags in a meaningful manner, we have enough infrastructure to start processing them. Because SWF is a streamable format, we don't need to have the whole file before we start working.

Step 2: Definitions and The Dictionary

As definition tags are discovered, they are then added to the "dictionary." This is a static repository for all of the objects with definition tags (called "characters"). Other tags (called control tags) generally refer to one or more tags in the dictionary, applying transforms in a cumulative filtering (or "delta based") fashion. This makes implementing the dictionary straightforward, as all it has to do is allow new characters to be added, and report the values of existing characters.

Thursday, June 16, 2005


SWFIO: Layer 0 Completed

Well, I've just got my lowest-level I/O code working. It now both writes and reads the integral SWF data types (UI8, UI16, UI32, UB, SI8, SI16, SI32, SB), and the hard bits (that is, the bitfield operators) pass a suite of tests that is thorough enough to make me comfortable that the code works. The only thing I can think of that I'm missing is a mechanism to quickly pull out a very large quantity of data (such as an embedded JPEG or MP3), but I figure that's a feature I can add later if I really need it.

The next thing up is layer 0.5, or the "fixed point" data type. After that will be the first substantial layer — layer 1, the structure layer. I'm eager to get to that point, and start getting the structures out of the way. I think it will be very easy going, since the nasty part (interfacing with the data stream at a bit-wise level) is done.

Some other misc. stuff does need to get done to the layer 0 code before it's really "completed" — specifically, I need to add logging and create better unit tests for the non-bitfield operators. There exist tests for all of the operators at the moment, but the tests for the aligned accesses are wimpy (since the code implementing them is almost laughably trivial). Ah well.

Monday, June 13, 2005


Better Design Through Layering

Well, I finished the lowest level of my SWF I/O code (well, technically there's no I yet), and have been taking the time to think about what I'm doing and why I'm doing it. The nice thing about writing parsing code is that it's fairly straightforward, and you can be pretty much guaranteed that you'll need it later; thus, you can start hacking it up first (to handle that "gotta code" urge), and simultaneously contemplate what to do next.

Someone asked me the other day what I thought the design flaws were in the current GPLFlash2 implementation, and I didn't give them a good answer. I've been thinking about it, and have started to define exactly what it is that I don't like about the current design. The major things that I think are missing are the use of modularization and layering.

As an example, the Swf_decoder class does absolutely everything for decoding SWF. In fact, it knows every data struct and every class (!) that could be stored in the SWF. Furthermore, it knows the exact order and type of data that needs to be pulled out of the SWF — the objects don't read themselves in, the Swf_decode object encapsulates (IMHO, inappropriately) all of the knowledge of all of the tags. This "everything at once" approach is difficult to test, difficult to maintain, and difficult to get consistent and predictable quality out of.

I propose a design that takes a much more modularized and layered approach to the problem. Instead of having one great big monolith that tries to do everything, I envision building up a system that depends on discreet services. The layers move from data to presentation in a gradient, fanning out as it moves closer to the "end result" that the user sees.

The first bit that I'm working on is the "bitstream" reader and writer. This is the absolute lowest layer, and acts as the most general interface to an SWF file. It provides only the functions needed to read and write the integral SWF data blocks: unsigned integers (little endian; 8, 16 and 32 bits), signed integers (little endian; 8, 16 and 32 bits), unsigned bitfields (big endian; 1-31 bits long), and signed bitfields (big endian; 1-31 [2-32 with sign] bits long). The other data types (fixed point integer and bitfield) can be derived from the types already included. In truth, we need only provide "integer" functionality without sign (sign is unimportant, and simply a matter of interpretation), but for the sake of consistency, I've provided calls for both signed and unsigned integers. Since handling of signed bitfields is different than that of unsigned bitfields, both functions are necessary.

This interface is the absolute bare minimum needed to interpret the contents of an SWF file. By choosing a very tight set of functionality, we can ensure better quality — every one of these functions has a set of unit tests, as well as an integration test to ensure that they play nice together. This is an application of the "do one thing and do it well" principle — the SWF stream wrapper doesn't need to know or care about tags or non-primitive data structures; all it needs to know are the primitives.

Now, I've been talking about layering, but so far I've discussed only one component. Well, the SWF stream wrapper is the lowest layer in the system I'm envisioning. Everything else is built on top of it, so it's absolutely critical that it provides rock-solid functionality. Because it's so small, we are much more able to build it up to the level of stability that an entire system can depend on. The very next layer is also thin: it's the set of structures that emulate the "missing" core types (fixed-point numbers). This layer need only know about the SWF bitstream wrapper, and doesn't care about anything else. The next layer up will be the data structures. They don't need to know about one another — they just need to know how to read themselves out of a SWF stream wrapper, using the fixed-point classes if needed.

As you can see, we're slowly building our way up. We now have the very core types, the fixed-point types, and the data structures (Rectangle, RGB, RGBA, Matrix, etc.), all of whom know how to use the lower layers to construct themselves. There is no interrelation between things at the same layer, so bugs are isolated — the bug either exists in the class itself, or in subset of objects that it uses from the layer below it(1).

Moving up one more layer, we finally get to tags. The tags, like the structures, will know how to read themselves in off the stream — nothing fancy in the tag classes themselves, they just use the lower layers to fill in their data when constructed with a SWF stream wrapper, or when asked to extract() themselves from a SWF stream.

The alert readers in the crowd will probably be asking at this point, "But Quandary, how will we know what tag to read off the stream? If the tags read themselves in, they won't know until it's too late if their object type is at the start of the stream!" Well, to put it shortly, the tags themselves don't actually care. In fact, the tags don't even need to have a variable field for their ID (it can be a static const), because they aren't going to read the ID off the stream. It's not the job of the tag to know if it's next up on the stream — that's someone else's job (we'll come back to this later).

So, now we've got three layers (and one mini-layer), with each class in each layer being nice, compact, focused, and (mostly) isolated from all of the other classes in its layer. All this infrastructure doesn't do much, though — actually, all of these "layers" are really sub-layers of the overall system's data layer. The data layer's responsibility is to read data in from a provided input stream and put it into objects that the rest of the system can understand and use in other operations. Having a solid data layer that can stand independent of the system is a crucial aspect for reusability — it is difficult to re-use data layers if they take actions for or make assumptions about other parts of the system.

So, getting back to the "how can a tag read itself in?" issue. That problem starts moving out of the pure data realm and starts treading into the realm of behavior, or the application logic layer. The problem is still in the data layer, because the SWF specification tells us how the file is structured and how it must be read in order to make sense. However, the bit that actually makes decisions about how to decode the stream uses the tags — it is not a part of the tags. I've settled on using a "class factory" pattern to solve the discreet problem of reading a tag in from the stream. Given that we know a tag is at the start of the stream (and there will be a process that knows when this is the case; we haven't discussed it yet) we can have a RecordHeader read itself off the stream (and hey, it'll even automagically handle long versus short record types! The joys of encapsulation). We can then pass that RecordHeader to the TagFactory function(2), which will use the tag type in the record header as an index into an array of function pointers. Each entry in the array will point to a static "create" function, to which we can pass an SWF stream wrapper (and tag length) to and get back an appropriate tag. In the cases where we cannot decode the tag, the corresponding table entry will point to the create function of the generic tag class. This will eat the unknown tag off the stream so that file processing can continue.

So, we've worked further and further up the chain, and this is all starting to look like a nice bottom-up design. We now have a mechanism to create tags from the SWF stream wrapper, so all that's left is the top-level controlling class that provides all the glitzy "look, it's a parser!" feel. This top-level class will be pretty straightforward: take a filename or an existing stream, create the stream (in the former case), wrap the stream with the SWF wrapper, tell the header to read itself in, check for validity, then go into a loop of reading RecordHeaders, passing them to the TagFactory, and getting back nice, pretty tags. And for anyone who's thinking "Hey! You glossed over compressed SWFs!" — yes, you're right, I did.

So, let's take the opportunity to extend the system. What happens when we have a compressed SWF file? Well, the data stream starts off uncompressed, then switches to compressed. So, all we have to do is modify the SWF wrapper class to have a new method (like decompress()) that instantiates a lower layer wrapper class — one that does on-the-fly ZLib decompression — passes that lower layer wrapper the current stream, and then replaces the current stream with the ZLib-wrapped stream. From that point on, everything is exactly the same as it was before. In fact, we don't even need to implement this functionality directly in the SWF wrapper class — the high-level control class can just toss out the SWF wrapper, re-wrap the stream in a ZLib wrapper stream, and create a new SWF wrapper class to wrap the ZLib wrapped stream.

1: This is somewhat of an oversimplification; because the classes share a common data store (the SWF stream), a bug (reading/writing too much or not enough data to the stream) can cause later reads and writes to not return the expected results.

2: Note that it would be an (understandable and common) error to make the TagFactory function a method on, say, the Tag class. Tag should not have to know each and every class that derives from it. The whole point of derived classes is that the parent has no clue what's being implemented under it — any class that could benefit from inheriting the data and behaviors that the parent provides should be free to do so without having to notify the parent. TagFactory is a domain (if not an application) specific tool that works with and around tags — it is not part of a tag (in much the same way an emergency dispatcher is not a policeman or firefighter).

Saturday, June 11, 2005


Taking a Break to Work

I'm going to be offline working on a school-related project for the next week or so. Hopefully I'll be able to get it out of the way in that time so I can get back to working on GPLFlash (which, quite frankly, is where I'd rather be spending my time). Anyhow, if anyone is wondering where I went to, there's the answer.


Software Components

While I'm on the subject of design, it might be nice to think about what subsystems we can build gplflash on top of. So, I've come up with a short list of software that the project could benefit from using:


This is a library that provides logging functionality, with a decent level of control. Rationale for using it:


This is a library that provides a unit testing framework, complete with test runners for automated testing. Rationale for using it:


This is a tool that parses several languages, locates embedded documentation and converts it into a variety of different output formats. Rationale for using it:


This library provides vector graphics operations, allowing a program to draw vectors to multiple back-end devices. Rationale for using it:

Friday, June 10, 2005


Proposed Architecture

Here's a first pass at an overall architecture.

Five packages, SWFIO, ActionScript, Static Flash, SWF Engine, and Renderer. Static Flash depends on SWF I/O, ActionScript depends on Static Flash, and Renderer depends on SWF Engine. Both Static Flash and ActionScript represent implementations of an SWF Engine.


The SWF I/O library will provide a wrapper around normal istream/ostream classes, a la iswfstream and oswfstream. These wrappers will allow integral SWF data types to be read in from and written out to a stream. The primary functionality will be the automatic handling of both endianness and bitfield extraction/alignment.

SWF Engine interface

The SWF Engine series of interfaces can be implemented by a library in order to export a view of SWF data to a post-processor. The interface allows the post-processor to call back with events in-between frames, for interactivity.

The post-process interface will provide read/write access to all of the SWF within the implementing package. This will allow for dynamic behavior, as well as the potential for extensions. ActionScript, for example, would utilize this, but other active filters could be created as well.

Static Flash

An implementation of the SWF Engine set of interfaces. The Static Flash model will interpret all of the static tags and directives in the order they occur in the SWF stream. ActionScript tags will not be interpreted.


Another SWF Engine implementation. Hooks into the Static Flash model using the post-processing interface, interprets any ActionScript that exists, and makes changes to the content as necessary.


Uses the post-processing interface of an SWF Engine to access the final frame to be rendered. This package handles all the details needed to present audio and visuals to the user, as well as collect events and pass them back to the SWF Engine.

More comments


The 63-Bit Nightmare: Continued

Update:Ignore this post. 5 bits has a range of 0-31. I can't count.

Well, after going through a double-check, it looks like 63-bit bitfields don't get handled properly by the official Flash player (a la "no movie loaded"). So, can we just mark any bitfield longer than 32 bits as erroneous? Well, let's craft a 34-bit bitfield into a SWF and see:


This test file ran with no problems; perhaps putting a simple BackgroundColor tag would help to show if it's really working, or "working by accident." Note that 34 bits were chosen so that the bitfield took up an extra line. If we didn't do this, there would be a chance that we could get a false positive — the data could get read as a truncated 32-bit set of fields, and the extra data at the end thrown away as padding. Using 34-bits, we guarantee that the bitfield is longer than a 32-bit set of fields would be, so the player can't ignore our data.

And here's a 32-bit bitfield file, just for comparison:


As expected, this file runs with no problems. So… back to square one. It looks like we might not be able to outright ignore the values greater than 32, but we also can't handle values at the top-end of 63 bits, either. Sigh. I'll continue working on my swfio library*, and see if I can't get it built up enough to start generating some of these files for me, instead of having to hand-craft these tests.

*I'm using this as a tool to help me learn the format, and force me to think about all the nuances. It was in writing this that I discovered this particular issue.

Thursday, June 09, 2005


SWF and the 63-Bit Nightmare

Update:Ignore this post. 5 bits has a range of 0-31. I can't count.

Update:It appears as though the Macromedia player does choke on the file. The first right-click on the movie works, but subsequent right-clicks don't. This is the case for both the 64- and 63-bit versions of the file.

Part of the SWF format are things called "bitfields" — bit-aligned strings of 1s and 0s. Now, these are used to save space; no need to use 32 bits to encode something when 26 will do, right? The length of each bitfield is determined by a control bitfield of a fixed size (5 bits); a single control field usually determines the length of several bitfields that come after it. Now, here comes the issue: the SWF spec only specifically mentions sizes up to 32 bits for non-bitfield types, and explicitly pegs ONE bitfield type (fixed-point) as 32-bits. But, with a 5 bit control field... well, we can specify a bitfield to be up to 63 bits long.

So, we're left wondering, "Gee, are control values greater than 32 just invalid? Or are there a slew of other rules that we need to know?" Unfortunately, Macromedia's Flash player loaded a hand-crafted SWF that contained 63-bit bitfields in it, and didn't report any errors. So, it appears that these values are valid to the extent that the official player doesn't segfault when reading them — unlike the SWFToolkit tools, which crashed and burned when fed the file.

Here is the hex stream representation of my test file, if anyone else wants to take a shot at it:


Update:note that the above code is not the original code of the post (which used 64-bit bitfields instead of 63); the above movie does NOT play back in Macromedia's player.

The above translates into the following:

Non-Compressed Flash, Version 7
File Size:47 bytes
Frame Count:0

I'd really appreciate if anyone with official Macromedia tools could try and open that file, and see what kind of stats it gives back. Again, the official player doesn't seem to choke on the file, but I don't know if it's actually picking the size up or not — it's just not crashing.

Sunday, June 05, 2005


My Kingdom for a Test

Well, by far the biggest problem I can see so far is the lack of a nice, standard suite of tests. I've gone through the mailing list and seen several E-mails now that go something like the following:

Hey the flash animation at <URL> doesn't work…


The example at <URL> works now…

There are no tests checked into CVS, though. This is bad for lots of reasons — it means that we don't have a controlled way of figuring out exactly what works versus what doesn't. It also means that regressions can much more easily slip in.

An ideal solution would be to create automated tests, though this could be a bit difficult. The main problem is that telling when "it works" versus when "it doesn't work" is somewhat qualitative: a person can look and see, yes that's a spinning cube on the screen, and tell that that's what they're supposed to see. Software, however, has to use a machine-readable "expected output" in order to compare the test output with. I'll have to dig into the architecture a bit, but I think that it could be done.


The first bit to test would be the parser. We'd need a way to specify (in a file) the SWF we want to read, and the contents that the Decoder object should have once that SWF is read in. Any discrepancies between the two indicates that either our parser code has a bug, or we mis-represented the contents of the Decoder object (who tests the tests? ;) ).


The next stage is to test the interpreter. For this, we need a way to specify (again, in a file) the SWF and the set of events (in order) that we expect to occur. Eventually, we would also need a way to specify user events and expected responses, to validate interactive elements. To implement the testing, we would pass the validated Decoder object (from the prior step) through to the interpreter (or Engine), and the Engine, in turn, would be plugged into a dummy executor -- that is, something that claims to present the information to the user, but really records the actions requested of it. The executor's output would then be compared to the expected output, and any discrepancies would show us where interpretation errors (or test-creation errors) are.


This is almost certainly infeasible to test automatically. The execution portion talks to external drivers that generate output for the user to consume; testing that this output is in-line with expectations would be difficult for many reasons, not least of which is the fact that different implementations (of, e.g., OpenGL) could produce slightly different (but still correct) output. We're approaching the analog border, and so, user testing is likely going to have to come in at this point.

Good First Steps

A good start would be to plan out what parts of the code should be tested, and write up some SWFs that specifically target the bits we want. An excellent way to do this would be to use a tool such as swfc from the swftools, or SSWF. An even better tool for this job would be one that allows full, direct control of the SWF, similar to flasm, but for all of Flash — not just the ActionScript.


Flash and GPLFlash: a 40,000-kilometer overview

All right; I've gotten my brain mostly wrapped around the parts of this project. As such I've written up a little crash course. If anyone sees any discrepancies, feel free to point them out to me! So, without further ado, enjoy the article.

Flash, SWF, and what it all means

Flash is a platform, with a set of features defining things that you can do. SWF is the format that embodies that platform, containing the discreet instructions on what to do. To have a "Flash player," you need a piece of software that can read in an arbitrary (but valid) SWF file, and correctly interpret and execute all of the contained commands. This translates into knowing the syntax (reading), knowing the semantics (interpreting), and having an engine that can express the interpretation to the user (execution).

Moving forward in Flash versions, the SWF format is added to. That is, if the Foo command was in v1, it will be in v2. Therefore, the syntax part of a Flash reader needs only to be extended when preparing it to read a newer version of Flash. Furthermore, the facilities needed to accurately convey the information to the user are also only added to — displaying things, playing audio, getting clicks, and so on. The only thing that seems to require changing (as opposed to extension), is the interpretation layer. Though the command Foo may carry across from one version to another (with all of its file-encoded structure intact), the behavior may not be the same. For the sake of argument, we'll take a fictitious command, CreateWhatsit, and say that in v1, it creates a picture and displays it on-screen. In v2, the behavior could change so that the picture is created, but not put on-screen until an explicit command is given to do so.

Information sources

The information needed to decode and interpret SWF is available from the friendly folks at the SSWF project. They have a link to their own SWF documentation (said to be from the apparently defunct openswf project), as well as a direct link to Macromedia's version of the document (which bypasses the document's licensing page) on the right-hand list of links.

Where is the project?

I've just taken a preliminary look at what the flashplayer program can do, and poked through a little code. I have by no means done an exhaustive audit; I'm just going to be commenting on the bits and pieces I've seen thus far.

The decoder seems to be done (though I'm tempted to rip it apart, and possibly re-write it depending on what I see); interpretation and execution appear to be the main focus of what needs to get done. Several ActionScript bits aren't interpreted yet, and we may or may not have all of the infrastructure in place to execute all of the functionality encapsulated in the Flash platform.

Saturday, June 04, 2005


Scribblings of a madman...

Well, here I go, leaping into GPLFlash2, with absolutely no clue as to any of its aspects. Manipulating vectors, calculating colors, OpenGL; animations and graphics in general are completely foreign to me.

But, I've dealt with Foamy having out-of-sync audio for too long now, and I'm irritated enough to do something about it. The fact that the FSF has made GPLFlash a priority has just spurred me further.

All right, so, the game plan for me is as follows:

  1. get information about Flash as a whole; understand how it works
  2. figure out and document what currently exists in the GPLFlash2 source
  3. do any re-designing that comes to light
  4. hack on the code like the crazed maniac I am

I already have a good start on the first bullet, but that post will have to wait until after I finish tying up enough loose ends in "real life" to devote real time to the project. Things will be sorted out in the next two weeks (at most)... after that, look out world.

Note: I have been told by someone who recently downloaded the SWF specification that Macromedia has added a restrictive license to the end of the document. Because of this, newcomers will not be able to get a copy of the spec and still be able to contribute to GPLFlash's development. Since other developers (such as myself) already have access to the specification without the license, this should not pose a major problem in the short term. Please bear with us, and do not seek out or use this specification in conjunction with the GPLFlash project.