October 28, 2011

Memory leaks in AS3

A short comment on memory leaks in AS3. In many cases, memory leaks are no problems in AS3, since most Flash content is not very complex and swf files are often reloaded (e.g. if they are only part of an html page, such as a banner). In some cases, such as when you create a Flash application or when an entire site is built in Flash or Flex, then memory leaks could build up to very high levels.

In order to monitor memory usage you can call System.totalMemory:

trace(System.totalMemory);

The most common reason why memory leaks occur is that we add event listeners with strong references to objects, which prevents those objects from being garbage collected. As a best practice to prevent this, you should always use weak references when creating event listeners:

label.addEventListener(MouseEvent.Click, handleMouseClick, false, 0, true);
instead of

label.addEventListener(MouseEvent.Click, handleMouseClick);
Grant Skinner discusses the importance of weak references and resource management in more detail on his blog.

October 27, 2011

Parsing dates in AS3


Trying to parse dates from strings in AS3 is not always straight forward.

From today's lesson we learn that the Date.parse method returns a Number, not and int, and this number can be used to create a Date object using the Date() constructor. However, the Date may not contain any dash "-", which is commonly used in some local Date formats, since that would produce "Invalid Date".

This is how it's done:

function convertDate(value:String):Date
{
  return new Date(Date.parse(value));
}

trace(convertDate("2011-10-27 15:12:00")); // OUTPUT: Invalid Date
trace(convertDate("2011 10 27 15:12:00")); // OUTPUT: Invalid Date
trace(convertDate("2011/10/27 15:12:00")); // OUTPUT: Thu Oct 27 15:12:00 GMT+0200 2011


If you receive string values using dashes "-", this can easily be fixed by replacing them with "/".

value = value.split("-").join("/");

Another pitfall is to use an int instead of a Number:

var date:Date = new Date();
var intValue:int = Date.parse(date);    // intValue = 1166693128      (incorrect)
var numValue:Number = Date.parse(date); // numValue = 1319721653000   (correct)

For more information about accepted date formats and generally about the Date object, see:

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Date.html#parse%28%29

October 26, 2011


How to install Mac OS 9 on a iMac with OS X


If you, for any reason, want to install Mac OS 9, but do not have any compatible hardware to install on, then you could use a new Mac and install OS 9 in an emulator environment.

For this purpose we have chosen the SheepShaver emulation software, which can be downloaded as a binary from Macupdate.com (see http://www.macupdate.com/app/mac/20615/sheepshaver). Alternatively, you could choose Basilisk II, which is an open source alternative software.

Prerequisites

Following our example, you need:
  • A running Mac OS 9 computer
  • Internet access
  • A target Mac OS X computer
  • An OS installation disc for Mac OS 9

Download SheepShaver Emulator

Download the SheepShaver (we tried version 2.3) from above link and extract the content into a new folder. In order to run the SheepShaver we need to find a suitable Mac OS ROM file, which is not very easy. When found, the Mac OS ROM file shall be copied into the SheepShaver folder. Until then, the software will not run.

Finding the Mac OS ROM file

The Mac OS ROM file is located in the System Folder in an installed Mac OS 9 or on the system installation disc. We tried different Mac OS 9 files, from already installed systems and from the system installation discs and recovery discs. We even tried Mac OS 8 versions, but none of the Mac OS ROM files were accepted. Also, the Mac OS ROM file would not be available anywhere on the internet for downloading, since Apple software license does not allow any distribution of the file.

However, there is a workaround, and it worked for us!
You can download a Mac OS ROM Update, following the instructions from the SheepShaver help, located at: http://www.open.ou.nl/hsp/Engels/SheepShaver_Help/rom_file_how_to.html.

Make sure you download the file on a running Mac OS 9, since you need to mount the smi-file (self-mounting image) and doing it on Mac OS X in our case converted the files to PC-files, and extracting the Mac OS ROM failed.

Step 2. Mounting the Mac OS ROM Update image
After downloading the Update smi, double click on it to extract the Mac OS ROM Update 1.0.smi file. You can double click on the new file to mount the image, after which it will appear on the desktop as an image called Mac OS ROM Update.

Step 3. Download the TomeViewer.
TomeViewer is a software for Mac OS 9 which is used to extract files from installation packages, called Tome archive. TomeViewer can be downloaded from Tucows here: http://www.tucows.com/preview/207002. We tried version 1.3d3, which worked fine.

The TomeViewer comes as a StuffIt (.sit) file, which can be extracted by doubleclicking.

Step 4. Extracting the Mac OS ROM file
Run the TomeViewer application and open the mounted image on the desktop from the File menu. A window will be opened and the Mac OS ROM file will appear. From the Archive menu, you can choose Expand to extract the file to a location of your choice. Then copy this file to the Mac OS X computer to the SheepShaver folder.

The file that worked for us is 1,945,746 bytes.

Step 5. Setting up the virtual Mac OS 9 computer
The first step when running the SheepShaver emulator is to set up a harddrive, memory, etc. All this is well described in the Setup Documentation, so we will not cover it here.

When the emulated computer first boots, then it will not find any harddrive, but you can access the preferences on the menu. Using the dialog you can set up the harddrive and all other hardware settings. In order to close the program you need to press ctrl + escape.

Now insert the OS installation disc and start SheepShaver emulator. The emulator will boot using the OS disc and you can format the harddrive (choose extended file system) and install the operating system. In case you have a hardware specific OS installation disc you need to extract the OS files manually.

Insert a system restore disc and locate the OS image file in the configuration folder. Double click on the image file to extract the files to the desktop. Now copy the files to your newly formatted harddrive and the Mac OS 9 should be up and running.

Restart the Mac OS 9 and eject the installation disc, and you are hopefully done!





October 25, 2011

Downloading and parsing external content through Javascript and VBScript

In this first post we share a method to download and parse a remote http page using the XMLHttpRequest object available in Javascript.

Background
If you want to get some information from a different web site, you could let the browser download that page and then parse it for the desired content.

Suggested procedure
1. Create an XMLHttpRequest object using a browser independent method.
2. Remove or replace all html tags that could cause the browser to run scripts, load external content, or behave in any unwanted way.
3. Request the target page and insert the returned content in a hidded iframe
4. Parse the iframe DOM and look for wanted content.
5. Process and reformat the extracted content.

1. Creating the XMLHttpRequest object
The following javascript function first tries to create the object for Internet Explorer using conditional compiling (See http://www.javascriptkit.com/javatutors/conditionalcompile.shtml).
If above does not work and XMLHttpRequest class (see http://www.w3schools.com/xml/xml_http.asp) is defined, then that will be used.

function createXmlHttp() {
    var xmlhttp=false;
    /*@cc_on @*/
    /*@if (@_jscript_version >= 5)
    // Through conditional compilation we can handle old Internet Explorer versions
    // and security blocked creation of the XMLHTTP object.
   
    try {
        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
        try {
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (E) {
            xmlhttp = false;
        }
    }
    @end @*/
    if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
        try {
            xmlhttp = new XMLHttpRequest();
        } catch (e) {
            xmlhttp=false;
        }
    }
    if (!xmlhttp && window.createRequest) {
        try {
            xmlhttp = window.createRequest();
        } catch (e) {
            xmlhttp=false;
        }
    }
    return xmlhttp;
}

2. Making content safe
Since we are going to insert the code in a hidden iframe, we don't want the browser to load any scripts or other active content.
Since VBScript is very easy to use for string manipulation (RegEx could be used, but is less straight forward), we could create a VBScript Function to do the work for us.

    <script language="vbscript">
        Function Safe(txt)
            Dim tags
            txt = Replace(txt, "<link", "<safelink")
            txt = Replace(txt, "</link>", "</safelink>")
            txt = Replace(txt, "<script", "<safescript")
            txt = Replace(txt, "</scr" & "ipt>", "</safescript>")
            txt = Replace(txt, "<iframe", "<safeframe")
            txt = Replace(txt, "</iframe>", "</safeframe>")
            txt = Replace(txt, "<img", "<safeimg")
            txt = Replace(txt, "</img>", "</safeimg>")
           
            Safe = txt
        End Function
    </script>

This way any <script> tag will be renamed to <safescript> and therefore it will not behave like an ordinary script tag.

3. Request the target page

This part is quite straight forward. For more information see http://www.w3schools.com/xml/xml_http.asp.

xmlhttp = createXmlHttp();
xmlhttp.open("GET", url, true);
xmlhttp.onreadystatechange = handleHttpResult;
xmlhttp.send(null);

function handleHttpResult() {
    if (xmlhttp.readyState == 4) {
        parseResponse(xmlhttp.responseText);
    }
}

4. Parsing the IFRAME DOM

First it is convenient to have two helper functions, function $() and function $$() to retrieve DOM objects, either from the main document DOM or from the IFRAME DOM.

function $(id) {
    return document.getElementById(id);
}
function $$(id) {
    return loadedDoc.getElementById(id);
}


function parseResponse(txt) {
    txt = safe(txt); // make the content safe according to above
    loadedDoc = $("iframe").contentWindow.document;
    loadedDoc.close();
    loadedDoc.write(" "); // clear iframe document
    loadedDoc.writeln(txt); // insert content into iframe document
   
    // Below an example of parsing. This of course needs to be adapted to every context.
    if ($$("interesting-content-tag") == null)
    {
        alert("NO RESULT FOUND");
        return;
    }
    var list = $$("interesting-content-tag").childNodes;
    var tag;
    for (var i = 0; i < list.length - 1; i++)
    {
        if (list[i].getElementsByTagName("p")[0].className == "title") // if current tag contains a tag <p class="title">
        {
            tag = list[i].getElementsByTagName("ul")[0].childNodes[0]; // then retrieve the first <li> child of the first <ul> tag.
            alert("Found tag: " + tag.innerHTML);                      // alert the user.
        }
    }
    if (tag == null) alert("No tag found");
}



Blog started

In this blog we will comment on topics related to our main business, with main focus on programming concepts.

/Sfynx Team