21
May

Include only needed classes using asdoc

If you use asdoc and want to include specific packages only, for example get rid of open-source library classes you are using, you can write the following ANT script (taken from this post):

<?xml version="1.0" encoding="UTF-8"?>
<project name="Labstr" default="asdoc" basedir=".">

<!-- File with PC specific properties -->
	<property file="local.properties" />

	<target name="asdoc">
<!-- Put docs into folder named docs in project root -->
		<delete dir="${basedir}/docs"/>
		<mkdir dir="${basedir}/docs"/>

<!-- Get a list of files you don't want to be included in the docs, i.e. all the files except the ones you need. -->
		<fileset id="sources" dir="${basedir}/src">
		 	<exclude name="**/your/package/name/**"/>
		</fileset>

<!-- Convert file names to fully qualified class names. -->
         	<pathconvert property="classes" pathsep=" " refid="sources">
<!-- ChainedMapper executes its child mappers in sequence. -->
        	 	<chainedmapper>
<!-- Basic OR mapper for windows and mac slashes. Removes full path part we don't need. -->
        		 	<mapper>
	        	 		<globmapper from="${basedir}\src\*" to="*" />
	        	 		<globmapper from="${basedir}/src/*" to="*" />
        		 	</mapper>
<!-- Converts file path to class name. -->
        		 	<mapper type="package" from="*.as" to="*" />
        	 	</chainedmapper>
         	</pathconvert>

<!-- Executes asdoc. -->
		<exec executable="${ASDOC}" dir="${basedir}">
			<arg line="-source-path ${basedir}/src
					   -doc-sources ${basedir}/src
					   -exclude-classes ${classes}
					   -output docs"/>
		</exec>
	</target>

</project>

My local.properties content is the following:

FLEX_HOME=e:/work/4.5.0
ASDOC=${FLEX_HOME}/bin/asdoc.exe

Tags: ,

05
May

/tuio/3ASCur – parsing OSC/TUIO in AS3

Meet yet another AS3 OSC/TUIO parser! We have just released it open-source.
Sources can be found on GitHub — https://github.com/InteractiveLab/tuio.3ASCur

Tags: , ,

02
May

NativeWindowInitOptions.owner

Note to self. When you get this error,

ReferenceError: Error #1056: Cannot create property owner on flash.display.NativeWindowInitOptions.

add <swf-version>11</swf-version> into air-config.xml.

Tags: , , , ,

25
Mar

How to build your Flex app for iOS with AIR 2.6

AIR 2.6 brought a lot of great stuff, but one specific feature I just couldn’t pass by — publishing for iOS. Yes, there was this thing called Packager For Iphone, but now it is a part of ADT and is claimed to be much faster.

So, we have Flash Builder Burrito, Flex Hero SDK focused on mobile development and now AIR 2.6. You can see clear vector where Adobe is moving. There are many tutorials for Android platform, but iOS is lacking. So, let’s try to compile a small Flex application for iPad.

Tags: , , , , , , , , , , , , , , , ,

16
Mar

Don’t know what to watch next? Download and watch top ranked TED videos.

Recently I found a great post where the author (using a script) ranked TED videos by the number of times they were mentioned in social services. And since TV series are getting more and more stupid I decided to start watching these videos. I’ve seen many great TED talks in the past and anyway videos people talk about the most shouldn’t be bad. So I decided to download all of them.

One would open that large XLS file from the site and start clicking links. It might seem easier to just watch one video from the list at a time than to write a script which visits URLs and downloads videos. But I wanted to upload all of them to my iPhone and watch/listen to them while on my way to work. So here’s the final script:

require 'rubygems'
require 'nokogiri'
require 'open-uri'
require 'HTTParty'

urls = IO.readlines("data.txt").map {|line| line.chomp}
if !File.exists?("videos")
  Dir.mkdir("videos")
end

urls.each_with_index do |url, count|
  begin
    doc = Nokogiri.parse(open(url).read)
    node = doc.xpath("//dt/a1")
    video = "http://www.ted.com" + node.attribute("href").to_s
    videoName = "videos/(#{count+1})" + url.match(/http:\/\/www.ted.com\/talks\/(.*)\.html/i)[1] + ".mp4"
    puts "Downloading #{url} to #{videoName}"

    File.open( videoName, "w+") do |f|
      f << HTTParty.get( video )
    end
  rescue
    puts "Failed to download #{url}"
  end
end

I uploaded the same script with data for TED videos (with rating >=5) and Gemfile to install required gems to GitHub. Some of the videos don’t have links to video files, so you have to watch them online.

Tags: , ,

11
Mar

Unexpected ByteArray behavior

Yesterday I stumbled upon really unexpected ByteArray behavior with reading Strings containing Null characters or simply speaking characters with ASCII code zero. Here’s the code:

var s:String = "a" + String.fromCharCode( 0 ) + "b" + String.fromCharCode( 0 );
trace( s.length ); // 4
trace( s.charCodeAt(0), s.charCodeAt(1), s.charCodeAt(2), s.charCodeAt(3) ); // 97 0 98 0
var bytes:ByteArray = new ByteArray();
bytes.writeUTF( s );
bytes.writeUTFBytes( s );
trace( "bytes:", bytes.length );
bytes.position = 0;
while ( bytes.bytesAvailable ) {
    trace( "-", bytes.readUnsignedByte() );
}

// 0
// 4
// 97
// 0
// 98
// 0
// 97
// 0
// 98
// 0

bytes.position = 0;
s = bytes.readUTF();
trace( s.length ); // 1
trace( s.charCodeAt(0), s.charCodeAt(1), s.charCodeAt(2), s.charCodeAt(3) ); // 97 NaN NaN NaN
s = bytes.readUTFBytes(4);
trace( s.length ); // 1
trace( s.charCodeAt(0), s.charCodeAt(1), s.charCodeAt(2), s.charCodeAt(3) ); // 97 NaN NaN NaN

Or you can run this at wonderfl.

As you can see ActionScript is perfectly OK with Strings containing \x00. They are even written correctly but couldn’t be read right. I would say that this is unexpected behavior. One can say that in many languages (like C for example) Null characters are used to indicate the end of a string. But here we explicitly write its length into ByteArray. The only logical explanation I have is that this length is used only to read certain amount of bytes not less not more. After that while bytes are traveling from ByteArray to a new String object they are passing some internal representation in Flash Player / AVM2 which indeed is a Null-terminated string. Which crops our string at Null character.

Now I have to store data a bit differently in a more complex way. Being able to dump strings into ByteArrays is essential for me.

Tags: , , , ,

04
Mar

Scala + Processing – an entartaining way to learn a new language

If you’ve read a book about some new technology it doesn’t necessarily mean that you learned or even understood it. Without practice your newly acquired knowledge will vanish soon. That’s why doing exercises from the book you are reading is important.

But all those examples are usually boring. Of course you can start your own pet project to master your skills. Several months ago to learn Scala I started my little command line tool which semi-worked at the end and I gave up on it. So, in a month or so I had to google syntax of “for loop”…

That’s where I decided that I should start writing simple examples for different Scala features that must be fun. Here’s where Processing comes into play. Using it, every novice like me can turn dull exercises into visual installations. And later you can try advanced stuff like fractals, particle systems or data visualisation.

You might be wondering what the hell is Scala. It’s a relatively new and extremely cool programming language. You can read more about it on Wikipedia or on official web site.

I rewrote in Scala and posted to GitHub several cool examples. One of them is on the left picture – famous MSA Fluid Processing sketch.

***

When I first met Scala I fell in love with the language immediately. I looked through a couple of books including Programming in Scala which I recommend to everyone. Even theory alone allowed me to change my perception of programming at the whole. Too bad that my day to day job doesn’t involve Scala in any way. Even the language I use mostly is in many ways different from Scala. No, this language is not Processing.

Processing

I guess now is a good time to introduce Processing because there’s a chance you haven’t heard of it at all. I’m not even talking about that you actually worked with Processing. Of course it’s great if you did.

Anyway, Processing is basically a DSL for Java with a little IDE and a mix of useful libraries. It’s mainly used by so-called Visual Artists to render generative art work. I recommend you to check out Processing channel on Vimeo. There’s really a lot of cool stuff!

Tags: , , , , ,

23
Feb

Cute little Array bug

var a:Array = ["bla"];
a[ uint.MAX_VALUE ] = "bla2";
trace( a.length ); // 0
a.push(1, 2, 3);
trace( a.length ); // 0
trace( a[0] ); // 3
trace( a[ uint.MAX_VALUE ] ); // "bla2"

at wonderfl

don’t ask me how I found it

Tags: ,

22
Aug

In case you need to unlock some files on OS X

Recently I got a major headache with OS X file locks. Apparently, I can do nothing with locked files even being under root. So here comes a handy script which does that recursively. Taken from this site but there was a typo.

#! /bin/bash
#
# Simple file unlocking utility for Mac OS X
#
ARGS=1
E_BADARGS=65

function recursiveUnlock() {
 pushd $1
 for rdir in `ls -A`; do
 if [ -d "${rdir}" ]; then
 recursiveUnlock ${rdir}
 else
 /Developer/Tools/SetFile -a l ${rdir}
 fi
 done
 popd
}

if [ $# -ne "$ARGS" ]
then
 echo "Usage: `basename $0` starting-directory"
 exit $E_BADARGS
fi

recursiveUnlock $1

Call it recursiveUnlock.sh and “chmod” it to 755.

Tags: ,

23
Jun

100x times faster MD5 and more

Update: Get more recent version of the library here.

Update: I updated the zip with LGPL MIT license file. The original author basically says “use wherever you want” which looks like mostly LGPL MIT, right? Yes, haXe was used to create the SWC but I don’t know if we can get the source or not. Anyway I hope you understand from the code below how to use the library.

My dear friend BlooDHounD has recently released an SWC with highly optimized MD5, Base64, CRC32, JPEG, PNG algorithms. Compared to as3corelib we get the following results:

by.blooddy.crypto.MD5.hashBytes: 40
com.adobe.crypto.MD5.hashBytes: 4483

by.blooddy.crypto.Base64.encode: 115
mx.utils.Base64Encoder: 1635

by.blooddy.crypto.Base64.decode: 141
mx.utils.Base64Decoder: 2762

by.blooddy.crypto.image.JPEGEncoder.encode: 447
com.adobe.images.JPGEncoder: 3496

by.blooddy.crypto.image.PNG24Encoder.encode: 538
com.adobe.images.PNGEncoder.encode: 1423

Here’s the benchmark source:

package {

	import by.blooddy.crypto.Base64;
	import by.blooddy.crypto.MD5;
	import by.blooddy.crypto.image.JPEGEncoder;
	import by.blooddy.crypto.image.PNG24Encoder;

	import com.adobe.crypto.MD5;
	import com.adobe.images.JPGEncoder;
	import com.adobe.images.PNGEncoder;

	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.text.TextField;
	import flash.utils.ByteArray;
	import flash.utils.getTimer;

	import mx.utils.Base64Decoder;
	import mx.utils.Base64Encoder;

	[SWF( scriptTimeLimit=&amp;quot;255&amp;quot; )]
	public class test extends Sprite {

		/**
		 * Constructor
		 */
		public function test() {
			super();

			var text:String = '';
			var t:Number;

			// BitmapData for tests
			var bmp:BitmapData = new BitmapData( 1024, 1024, true, 0xFFFF0000 );
			bmp.noise( int( Math.random() * int.MAX_VALUE ), 0, 0xFF, 7, false ); // генерируем шум

			// ByteArray for tests
			var bytes:ByteArray = bmp.getPixels( bmp.rect );

			// MD5 test
			t = getTimer();
			by.blooddy.crypto.MD5.hashBytes( bytes );
			text += '\nby.blooddy.crypto.MD5.hashBytes: ' + ( getTimer() - t ); // 40

			t = getTimer();
			com.adobe.crypto.MD5.hashBytes( bytes );
			text += '\ncom.adobe.crypto.MD5.hashBytes: ' + ( getTimer() - t ); // 4483

			// Base64 encode test
			t = getTimer();
			var s1:String = by.blooddy.crypto.Base64.encode( bytes, true );
			text += '\nby.blooddy.crypto.Base64.encode: ' + ( getTimer() - t ); // 115

			t = getTimer();
			var e:Base64Encoder = new Base64Encoder();
			e.encodeBytes( bytes );
			var s2:String = e.flush();
			text += '\nmx.utils.Base64Encoder: ' + ( getTimer() - t ); // 1635

			// Base64 decode test
			t = getTimer();
			by.blooddy.crypto.Base64.decode( s1 );
			text += '\nby.blooddy.crypto.Base64.decode: ' + ( getTimer() - t ); // 141

			t = getTimer();
			var d:Base64Decoder = new Base64Decoder();
			d.decode( s2 );
			d.flush();
			text += '\nmx.utils.Base64Decoder: ' + ( getTimer() - t ); // 2762

			// JPEG test
			t = getTimer();
			by.blooddy.crypto.image.JPEGEncoder.encode( bmp, 60 );
			text += '\nby.blooddy.crypto.image.JPEGEncoder.encode: ' + ( getTimer() - t ); // 447

			t = getTimer();
			( new com.adobe.images.JPGEncoder( 60 ) ).encode( bmp );
			text += '\ncom.adobe.images.JPGEncoder: ' + ( getTimer() - t ); // 3496

			// PNG test
			t = getTimer();
			by.blooddy.crypto.image.PNG24Encoder.encode( bmp );
			text += '\nby.blooddy.crypto.image.PNG24Encoder.encode: ' + ( getTimer() - t ); // 538

			t = getTimer();
			com.adobe.images.PNGEncoder.encode( bmp );
			text += '\ncom.adobe.images.PNGEncoder.encode: ' + ( getTimer() - t ); // 1423

			var tf:TextField = new TextField();
			tf.autoSize = 'left';
			tf.text = text;
			super.addChild( tf );

		}

	}

}

I know that he is too shy to tell you guys about his results (8
But they are definitely worth sharing.

You can download the SWC here (look up at the update section).

Tags: , , , , , ,