New QLog release
hi folks,
I recently became aware of a couple of features I really needed in QLog so I finally sat down to implement them.
Because I am currently working on an application which consits of several modules, each with it's own logger, the view of all the modules log messages in one window became quite cumbersome to read. So I wanted to see the logs of the modules each in a seperate tab to be able to better distinguish between them. Today I finally implemented this feature and QLog is now capable of creating different tabs for each logger connection. Thanks to the new tabs the information is far better structured and reading logs from different modules is now quite convenient.
Sometimes it's handy to save the logs to a file. That could be for instance to be able to compare the logs later, or simply to send them to someone else. This can now easily be done through QLog's new save file feature, which renders a html file for the currently opened log tab.
I also discovered and fixed a bug which occurred only with the flash player versions 9,0,124,0 or above, because these and future flash player versions need the server to send a socket policy file to the client in order to establish a connection. read more
Well, that's it. You can download the latest QLog release here.
Hopefully fsteeg will add the new features to his eclipse plugin version of QLog soon.
splinkresource 0.1.0 framework released
splinkresource aims to ease the workflow with resources in actionscript3 multilanguage applications. It supervises the processing of resources by loading and registring display assets, fonts and class libraries. During resource loadtime it offers detailed information on the load progress of the currently loading resource but also on the overall resource load progress. Moreover it provides conventient access to the processed resources within your application.
In particular splinkresource simplifies the development of actionscript 3 multilanguage applications by offering the concept of localized resourcebundles. Each resourcebundle contains information on and references to resources availible within the context of a locale. So the framework loads and provides only the resources needed for the specified locale. If your need to switch to another locale during runtime, you just pass the new locale to the framework and let it process the corresponding resourcebundle. Upon completion you have access to resources within the context of the new locale.
Of course splinkresource integrates well into the splinklibrary queue system. For instance you can add splinkresource easily into your application bootstrapping.
Because I believe in examples
The rough workflow with splinkresource is to:
- create an xml file based on the resourcebundles.dtd shipped with splinkresource. The file might look like:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE resourcebundles SYSTEM "resourcebundles.dtd"> <!-- Sample xml Note that id values MUST BE UNIQUE --> <!-- defaultLocale is the locale which is loaded by default --> <resourcebundles defaultLocale="de_DE"> <!-- For multilanguage applications define a resourcebundle for each locale --> <!-- locale defines the locale for the resourcebundle package --> <resourcebundle locale="de_DE"> <!-- path is the path to the asset files, relative from your applications root directory --> <assets path="assets/"> <!-- id is the assets id src is the assets source register defines a subclass of org.quui.resource.AssetRegister in which the assets are specified --> <asset id="sample assets" src="assets.swf" register="sample.SampleAssetRegister" filesize="16375" /> </assets> <!-- path is the path to the font files, relative from your applications root directory --> <fonts path="fonts/"> <!-- id is the name of the font type is the identifier which you use within your application to access a FontData object src (optional) the fonts source isSystemFont (optional) default value is false xOffset,yOffset (optional) enables to define a x/y offset for a specific font type sizeOffset (optional) enables to define a size offset for a specific font type --> <font id="Futura LT Condensed Bold" type="headline" src="futura_western.swf" filesize="26908" /> <font id="Arial" type="text" src="arial_western.swf" filesize="104710" /> <font id="Verdana" type="system" isSystemFont="true" xOffset="5" yOffset="5" sizeOffset="-3" filesize="0" /> </fonts> <!-- path is the path to the library swf files, relative from your applications root directory a quick way to get a library swf is to generate an swc (which in fact is a zip archive) and extract the swf within. To gain autocompletion for dynamically loaded class swfs: as fdt user you can add the swc as "runtime shared code" in your "fdt sourcefolder" tab or as flex user add the swc to the "flex build path" and switch the "default link type" for your swc from "merged into code" to "runtime shared library". These steps cause the compiler not to compile the code into your swf (because the code will be loaded during application runtime), but enable the editor to use the swc for autocompletion --> <libraries path="library/"> <!-- id is the librarys id src is the librarys source --> <library id="de.polygonal.as3ds" src="as3ds.swf" filesize="43654" /> </libraries> </resourcebundle> <resourcebundle locale="en_US"> <assets path="assets/"> <asset id="assetA" src="assetA.swf" register="DefaultAssetRegister" filesize="0" /> <asset id="assetB" src="assetB.swf" register="DefaultAssetRegister" filesize="0" /> </assets> <fonts path="fonts/"> <font id="Futura LT Condensed Bold" type="headline" src="futura_western.swf" xOffset="3" yOffset="3" sizeOffset="2" filesize="26908" /> <font id="Arial" type="text" src="arial_western.swf" sizeOffset="-2" filesize="104710" /> <font id="Verdana" type="system" isSystemFont="true" filesize="0" /> </fonts> </resourcebundle> </resourcebundles>
- use the org.splink.ant.filesizeinjectortask.jar ant task and integrate it into the build process. Have a look at the sample build file:
<?xml version="1.0" encoding="UTF-8"?> <!-- @author Max Kugland --> <project name="org.splink.resource.sample" default="build_sample" basedir="../"> <property file="build/build_${user.name}.properties" /> <!-- project folders --> <property name="dependencies" value="${basedir}/dependencies" /> <property name="build" value="${basedir}/build" /> <property name="sample" value="${basedir}/sample" /> <property name="xml" value="${basedir}/xml" /> <property name="source" value="${basedir}/src" /> <taskdef name="sizeinjector" classname="org.splink.ant.SizeInjectorTask" classpath="${basedir}/build/org.splink.ant.filesizeinjectortask.jar" /> <target name="inject" description="Inject file sizes into the resources xml file"> <sizeinjector file="${resourcefile}" resourcebasedir="sample" /> </target> <target name="build_sample_assets"> <exec executable="${flex.mxmlc}"> <arg line="-default-size 1 1" /> <arg line="-default-frame-rate=30" /> <arg line="-library-path '${flex3libsdir}'" /> <arg line="-default-background-color=0xffffff" /> <arg line="-source-path ${source}" /> <arg line="-output ${sample}/assets/assets.swf" /> <arg line="${source}/sample/SampleAssetRegister.as" /> </exec> </target> <target name="build_sample" depends="build_sample_assets, inject"> <exec executable="${flex.mxmlc}"> <arg value="-debug=true" /> <arg line="-library-path '${flex3libsdir}'" /> <arg line="-library-path '${org_splink_library}'" /> <arg line="-external-library-path+='${basedir}/${as3ds}'" /> <arg line="-default-size 640 480" /> <arg line="-default-frame-rate=30" /> <arg line="-default-background-color=0xffffff" /> <arg line="-sp ${source}" /> <arg line="-o ${sample}/sample.swf" /> <arg line="${source}/sample/SampleApplication.as" /> </exec> </target> </project>
- invoke splinkresource from within your application code, register a few listeners and let it do the work. splinkresource processes your resourcebundles.xml file, loads the neccessary resources for the given locale into the given ApplicationDomain and registres the the loaded resources. Meanwhile it provides you with infomation about the loading progress and upon processing completion you can access the resources within the given ApplicationDomain through the singleton class ResourceProvider.
package sample { imports... public class SampleApplication extends Sprite { public function SampleApplication() { // pass the path to the resourcebundles.xml, also pass the locale // for which to load resources, also register for various events var processor:ResourcebundleProcessor = new ResourcebundleProcessor("../xml/resourcebundles.xml", "de_DE"); processor.register(QueueEvent.ON_ERROR, onProcessError); processor.register(QueueEvent.ON_COMPLETE, onProcessComplete); processor.register(ResourcebundleProcessorProgressEvent.PROGRESS, onProgress); processor.start(); } /** * Invoked when the resource loading progresses, as you can see you * get provided with a lot * of information on the load progress */ private function onProgress( e:ResourcebundleProcessorProgressEvent):void { var progress:ResourceProgress = e.getResourceProgress(); var br:String = "\r\n"; trace(progress.getId()+" "+progress.getCurrentItem() + " / " + progress.getTotalItems() + br); trace( Math.round(progress.getCurrentItemBytes() / 1024) + "kb / " + Math.round(progress.getCurrentItemTotalBytes() / 1024) + "kb " + progress.getCurrentItemPercent() + "%"+br); trace( Math.round(progress.getTotalLoadedBytes() / 1024) + "kb / " + Math.round(progress.getTotalBytes() / 1024) + " kb " + progress.getTotalPercent() + "%"+br); } /** * Invoked when an error occurs */ private function onProcessError(e:QueueEvent):void { trace(e.getErrorMessage()); } /** * Invoked when the ResourcebundleProcessor completed its * processing */ private function onProcessComplete(e:QueueEvent):void { e.getSource().finalize(); testAssets(); testFonts(); } /** * Renders one of the assets defined in resourcebundles.xml to * the screen * Note that you can access assets trough the * ResourceProvider.getInstance().getAssetClassById method */ private function testAssets():void { var SplinkAssetClazz:Class = ResourceProvider.getInstance().getAssetClassById( SampleAssetRegister.SPLINK_ASSET); addChild(new SplinkAssetClazz()); } /** * Renders some fonts defined in resourcebundles.xml to * the screen */ private function testFonts():void { var fontData:FontData = ResourceProvider.getInstance().getFontDataByType("headline"); var textFormat:TextFormat = new TextFormat(); textFormat.size = 20; textFormat.font = fontData.getId(); var textField:TextField = new TextField(); textField.defaultTextFormat = textFormat; textField.autoSize = TextFieldAutoSize.LEFT; textField.htmlText = fontData.getId(); if(fontData.getIsSystemFont() != true) textField.embedFonts = true; textField.x = 0; textField.y = height + 20; addChild(textField); } } }
Note that there is a quickstart sample included in the release so you can easily start trying splinkresource.
You can download splinkresource here
AsBeanGen - Generate value objects for DTD driven XML files
AsBeanGen is a class generator application written in java which generates as3 data bean classes from DTD files. Overall it shortens development time a lot, because it rids you of spending a considerable amount of time on writing data bean classes.
Instead AsBeanGen can generate hunderts of classes in less than a second for you and as an added bonus it doesn't just generate the bean classes, but also the classes which transform the content of an XML file (implementing the DTD) to data bean objects. So finally you just have to write two lines of code yourself to get a strongly typed object representation of an XML file.
If you never heard of DTD (Document Type Definition), I suggest you to read this.
As DTD doesn't support type information natively, you also have to annotate the DTD files through simple comments to add the neccessary type information, otherwise AsBeanGen uses 'Object' as the standard type.
To give you a more specific idea how it is used, let's jump straight into an example:
This is the annotatd DTD file
<?xml version="1.0" encoding="UTF-8"?> <!ELEMENT test (size,fonts+) > <!-- Sets the types for the properties of the SizeData class TYPE size.width=int TYPE size.height=int --> <!ELEMENT size EMPTY > <!ATTLIST size width CDATA #REQUIRED height CDATA #REQUIRED > <!-- Sets the types for the properties of the FontsData class TYPE fonts.path=String Generates 'getFontDataById(id:String):FontData' method into FontsData class GENERATE font.id Generates 'getFontDataByName(name:String):FontData' method into FontsData class GENERATE font.name --> <!ELEMENT fonts (font+) > <!ATTLIST fonts path CDATA #REQUIRED > <!-- Sets the types for the properties of the FontData class TYPE font.id=String TYPE font.type=String TYPE font.name=String TYPE font.src=String TYPE font.systemfont=Boolean --> <!ELEMENT font EMPTY > <!ATTLIST font id CDATA #REQUIRED type CDATA #REQUIRED name CDATA #REQUIRED src CDATA #REQUIRED systemfont (true|false) #IMPLIED >
This is an xml file based on the DTD
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE test SYSTEM "test.dtd"> <test> <size height="100" width="100"/> <fonts path="fonts/"> <font id="foo" name="Arial" src="arial.swf" type="text"/> <font id="foo2" name="Arial2" src="arial2.swf" type="text2"/> </fonts> </test>
This is the generated FontsData bean class
package data.test { /** * Class generated by AsBeanGen * http://www.splink.org */ import data.test.fonts.FontData; public class FontsData { private var _path : String; private var _fontData : Array; public function FontsData() { } public function getPath() : String { return _path; } public function setPath(value:String) : void { _path = value; } public function getFontDataById(id:String) : FontData { var data:FontData; var r:FontData = null; for (var i:int=0; i<_fontData.length; i++) { data = _fontData[i]; if(data.getId() == id) { r = data; break; } } return r; } public function getFontDataByName(name:String) : FontData { var data:FontData; var r:FontData = null; for (var i:int=0; i<_fontData.length; i++) { data = _fontData[i]; if(data.getName() == name) { r = data; break; } } return r; } /** * @return an array of FontData objects */ public function getFontDataArray() : Array { return _fontData; } /** * @param an array of FontData objects */ public function setFontDataArray(value:Array) : void { _fontData = value; } } }
This is the generated FontsDataReader class for the FontsData bean class
package data.test { /** * Class generated by AsBeanGen * http://www.splink.org */ import data.test.FontsData; import data.test.fonts.FontDataReader; public class FontsDataReader { private var _xml : XML; public function FontsDataReader(xml:XML) { _xml = xml; } public function read() : FontsData { var fontsData:FontsData = new FontsData(); fontsData.setPath(_xml.@path); fontsData.setFontDataArray(readFontData()); return fontsData; } private function readFontData() : Array { var rAr:Array = []; for each(var xml:XML in _xml['font']) { var reader:FontDataReader = new FontDataReader(xml); rAr.push(reader.read()); } return rAr; } } }
This is what the generated structure looks like:
This is how to use the generated classes in your application:
// TestDataReader is the root reader and expects the loaded xml file // as a parameter. var reader:TestDataReader = new TestDataReader(xml); // TestDataReader's read method returns the root object of the // generated tree, filled with values from the given xml. var data:TestData = reader.read();
AsBeanGen can be used as a commandline application (usage shown below), or, if you are eclipse user you can add it as an 'External Tool' which proves to be very convenient (at least to me).
java -jar AsBeanGen.jar test.DTD C:\your\project\src de.your.package.name.test
Note that the "test" in the package name is the name of the DTD file.
How to add AsBeanGen as an 'External Tool' in Eclipse
1) Open your annotated DTD file
2) Open the 'External Tools'

3) Create a 'New Launch Configuration'
4) Fill the form (see screenshot)

4) After configuring AsBeanGen, you will want it to appear in the External Tools favorites. Switch to the 'Common' tab and check 'External Tools' within the 'Display in favorites menu' box.
5) Press 'Apply' button

Now you should be able to launch AsBeanGen from the 'External Tools Favorites Bar'. Just make sure that the DTD from which you wish to generate the actionscript classes is opened and focused.
QLog + splinklibrary Logging
QLog is a java application which simply displays log messages. It enables to apply a filter to these messages so you can seek for a specific log or just display log messages which apply to the filter.
Because QLog is in fact a socket server it is also possible to display logs sent from an application which runs on a remote server. (This can be very handy). The greatest feature in my opionion is that messages sent to QLog can be equipped with a color for each kind of message (that is trace,info,debug,warn,error,fatal,...), so the messages look well arranged.

In the whole QLog is a lot like powerflashers superb SocketOutputServer SOS but in contrast to SOS it is platform independent, it also runs on Mac Os X or Linux. (I developed it because i wanted to migrate to Ubuntu and I simply couldnt live without something like SOS)
QLog also integrates very well with the logging framework from splinklibrary. The splinklibrary logging framework comes with various ILogOutput implementations, so you can configure to which output destinations your logs are sent.
splinklibrary supports TraceOutput, FirebugOutput, SosOutput and QLogOutput out of the box. So you dont need to worry about any low level socket implementation details if you use QLog with splinklibrary.
One very useful feature of the sprinklibrary logging system is that if you run your application within the flash debug player, it adds the class- and methodname where the log originated from and if compiled with the -debug=true flag also the line number.
/** The Logger is configured once in a project. Each class which wants to log simply needs to add something like: private static const _logger:ILogger = LoggerProvider.getLogger("default", TheClassName); */ private function configureLogger():void { var factory:ILoggerFactory = new LoggerFactory(); /** It's possible to set various logger factories, so each one needs its own id */ factory.setId("default"); /** Logs within the specified range are sent to the log outputs */ factory.setRange(new LogRange(LogLevel.TRACE, LogLevel.FATAL)); /** DefaultOutputFormatter is used to format the log messages You can easily write and use your own IOutputFormatter */ factory.setOuputFormatter(new DefaultOutputFormatter()); /** Use different output strategies, here QLog and trace splinklibrary offers QLog, SOS, trace and Firebug LogOutput implementations. If you need something else, just implement the ILogOutput interface */ factory.addLogOutput(new QLogOutput()); factory.addLogOutput(new TraceOutput()); LoggerProvider.addLoggerFactory(factory); /** Get a Logger and log something */ _logger = LoggerProvider.getLogger("default", SampleApplicationClass); _logger.log(LogLevel.INFO, "Info"); _logger.log(LogLevel.DEBUG, "Debug"); _logger.log(LogLevel.ERROR, "Error"); }
Of course it should be quite simple to use Qlog with other Logging frameworks, or just to write a simple class to use it. splinklibararys QLogOutput should give a good impression how to do it.
Currently there is a stable QLog standalone version
Thanks to Fabian there is also a Eclipse Plugin version (very alpha) Update site: http://quui.com/update-site/
Here is a simple log4j appender class which enables to use QLog with the apache log4j framework for java.
splinklibrary 0.1.0 relased
Today I released my actionscript 3 code library. It is the basic toolkit which I use in my as3 projects.
The splinklibrary core features are:
- event distribution
- queues
- reflection
- logging (log4j style)
- tweening (queue based)
- loading (queue based)
If you want to have a closer look at it check out the API docs
splinklibrary is hosted at google code. You can check it out from the google code svn here: http://splinklibrary.googlecode.com/svn/trunk/
AS2 EventDistributor
Yes, I know, this is pretty old stuff, from the time before as3. Nevertheless I want to share my actionscript 2 event system for the unlucky fellows which still have to work with actionscript 2. If you know the as3 event system you will notice that EventDistributor is a lot like it, which should help to grasp quickly how to use it.
Originally I built EventDistributor to overcome the shortcomings of the way events were handled in as2. In as2 there were a couple of event systems, most well known probably the mx.EventDispatcher. Neither of these event systems could satisfy my needs, so I came up with my own solution for event distribution.
EventDistributor in contrast to the mx.EventDispatcher does not rely on static methods, it is glued to the class which needs to distribute events.
Therefore it is destroyed when the class utilizing it is destroyed. This is quite convenient, because if you destroy the class which fires events, every listener which is currently attached to it is removed too, so there is no need to write stuff like myEventDispatcher.removeListener("onSomeEvent", eventTargetFunction) over and over again.
mx.EventDispatcher is accessed trough static methods and therefore stores listeners in a static member array, which means that if you forget to remove a listener it will live on forever, which is pretty bad.
Furthermore EventDistributor encourages the usage of constants like Event.ON_COMPLETE rather then Strings like "onComplete" and is therefore much more error resistent.
EventDistributor provides all neccessary information for removing eventListeners with every distributed event. So you do not need to save function variables as class members to be able to remove listeners - you can remove them immediately after catching the event or remove all listeners by finalizing the class which makes use of the distributor.
EventDistributor distributes typed events, not generic objects like mx.EventDispatcher does. Because the events are typed you dont get into trouble when bubbeling events trough an application; Because EventDistributor encourages to create custom events by extending the Event base class or implementing the IEvent interface you always know about your events at compile time.
Well after the theory its time to have a look at how it is actually used:
/** * The class which makes use of EventDistributor to distribute events **/ class DistributingClass implements IDistributor { private var _eventDistributor:EventDistributor; private var _targetMC:MovieClip; public function DistributingClass(targetMC:MovieClip) { _targetMC=targetMC; _eventDistributor=new EventDistributor(); _eventDistributor.initialize(this); _targetMC.onRelease=Delegate.create(this,distribute); } private function distribute():Void { // ReleaseEvent extends Event or implements IEvent distributeEvent(new ReleaseEvent(ReleaseEvent.ON_RELEASE, "event_ID")); } private function addEventListener(type:String,func:Function){}:Void private function removeEventListener(type:String,func:Function){}:Void private function distributeEvent(eventObject:IEvent){}:Void }
/** * A custom event class which is distributed by DistributingClass **/ class ReleaseEvent extends Event { public static var ON_RELEASE : String="onRelease"; private var _id:String; public function ReleaseEvent(type:String,id:String) { super(type); _id=id; } public function getId():String { return _id; } }
/** * A class which listens for ReleaseEvent objects distributed by * DistributingClass **/ class Listener { private var _distributingClass:IDistributor; public function Listener(distributingClass:IDistributor) { _distributingClass = distributingClass _distributingClass.addEventListener(ReleaseEvent.ON_RELEASE, Delegate.create(this, onRelease); } private function onRelease(event:ReleaseEvent,listener:EventListener) :Void { // in the case you want to unsubscribe immediately after the // event is caught: _distributingClass.removeEventListener(ReleaseEvent.ON_RELEASE, listener.getFunction()); trace("event caught: "+event.getId(); } public function finalize():Void { // in the case you want to destroy the class distributing events and // automatically remove all listeners _distributingClass.finalize(); } }
DuDe
Recently I discovered an interesting tool called DuDe. The author Richard Wettel describes DuDe as a 'text-based, language-independent code duplication (code clones) detector, gravitating around the concept of duplication chain.'

It is pretty simple to use; you start the jar, select a projects source folder and select the algorithm you want DuDe to use. Upon completion you can browse the results and learn which parts of your code could do with some optimizations.
I guess there are much more powerful tools for specific languages like java, but what makes DuDe shine brightly in my opinion is that it is language independent. So it works very well for actionscript source code or any other plain text files.
Hello world!
Yes, i am a bit late, but finally I did it. After so many years of pondering whether to start a blog and 'go public' or not, I decided to just do it. So here it is: my brand new blog. Hope you will enjoy it.
