Showing posts with label actionscript. Show all posts
Showing posts with label actionscript. Show all posts

Wednesday, April 22, 2009

ActionScript Quickie: Check for Required Params

You ever need to test that a bunch of variables are not null/empty/true? Here is a quick and dirty way to do it in ActionScript 3.0:

private function validArgs(...args):Boolean{
return args.every(function(arg:Object, ...crap):Boolean {
return arg ? true : false; });
}

Usage:

var firstName:String = ...
var lastName:String = ...
var iq:int = ...
var friends:Array = ...
validArgs(firstName, lastName, iq > 100, friends.length);

Sunday, February 08, 2009

Added Twitter Social Graph APIs

Twitter recently created social graph APIs. You can get the friends or followers of a given user. This information was available in other ways previously, but the new social graph APIs are very convenient they return an array of numeric IDs. So if you want to do things like visualizing the social graph of people or use this to suggest friends, etc. now you've got an easier way to do it. Of course a great way to visualize such data is in Flash. So I added these APIs to TwitterScript. When the TwitterEvent returns, its data property will be the array of numeric IDs.

Thursday, January 15, 2009

Syntax Matters: JavaFX Script

Last night I finished writing an article on JavaFX. It was a lot of fun, and it has convinced me that JavaFX has a strong future. A lot of its promise comes from its syntax. It is easy to get carried away with Rich Media! and Animation! and FPS! but then you forget that JavaFX is a new programming language on the JVM. Here are the highlights of its syntax.

The declarative constructors: When I first started looking at JavaFX, it looked like MXML but in a JSON format. Looks are deceiving. Essentially JavaFX supports name parameters in its constructors. The naming convention is foo : bar, where foo is the name of the parameter and bar is the value. You can put multiple parameters on one line by using a comma to separate, like in most other languages, or you can put each on its own line and eschew the commas. This leads to the JSON-ish syntax. It is probably more accurate to describe it as JavaScript-ish. This becomes even more apparent when you start nesting constructed objects. It really looks a lot like object literals in JavaScript. What is great is that this is not just something you only use for UI elements, like MXML. It is part of the language syntax, so you can use this syntax anywhere you want. Imagine being able to write an MXML expression directly inside a block of ActionScript code...

Speaking of JavaScript: A lot of the syntax of JavaFX looks like JavaScript's more sophisticated cousin, ActionScript 3.0. You use var to declare local variables. You put the type after the variable name, separated with a colon. You use function to define methods. The major difference is using def to denote a constant. In ActionScript, you use const, like you would in C. This is actually kind of bad in my opinion. The def keyword is used in many other languages, like Ruby and Scala, to denote a function. There is no obvious connection between def and a constant. I think they should have used const instead of def. It would have made more sense to do that and maybe use def instead of function.

Functional Programming: A lot of folks are disappointed that closures are not being added to Java, at least not in Java 7. JavaFX does have closures. You can define a var to have a function type and can specify the signature of that function. The syntax is pretty nice. For example, you could do var join:function(String[], String):String to define a variable called join that is a function that takes in an array of strings and a string as input parameters and returns a string. I would like to see this is in ActionScript. JavaFX also has support for list comprehensions. You could do var squares = for (i in [1..100]) { i*i} to get an array of the perfect sqaures up to 10,000. However, JavaFX does not make as much use of closures. You would think that its sequences would have common functional mehtods like filter, map, fold, etc. For filter and map, there are alternatives. For example, let's say you wanted the square of all of the odd integers less than 100. In Scala you would do something like val os = (1 until 100).filter(_ % 2 == 1).map(_^2) . In JavaFX it would be val os = for (x in [1..10][i | i % 2 == 1]){ x*x }. It's a case of syntax over API. The second set of curly braces is like a select clause. I want to like it because it uses mathematics insired symbols.

Other: There are a few other JavaFX syntax bits worth mentioning. First is bind and bound. These are for data binding expressions. These can be very powerful. You can bind variables together, so that the one changes when the other changes. Better is that you can bind to functions and list comprehensions. The other interesting syntax in JavaFX involve the keywords delete and insert. These give LINQ-ish syntax for sequences. In fact if you combine the mathematical style select syntax with insert/delete and with the declarative constructors, you get expressiveness that is pretty on-par with LINQ in my opinion. When you see everything working together, it kind of makes sense but it does seem kind of random at first.

Monday, October 13, 2008

ActionScript Vector Performance

Flash Player 10 is coming out this month. This weekend I went to Adobe's FlashCamp. It was a lot of fun by the way, and a big thank you must go to Dom and the folks at Adobe for a great event. Adobe really treats developers well. Anyways, there are a lot of great new features in Flash Player 10. Other folks will talk about 3-d and text engines and Pixel Bender, etc. but me? I'm excited about Vectors.

If you are like me, then the first time you heard about the new Vector class in ActionScript, you thought it might have something to do with graphics and what not. However, I was overjoyed to learn that it was like the Vector from C++ and Java, i.e. a list-style collection. Like the Vector from the STL and in Java 1.5+, it is parameterized. Even better, you can specify a fixed length for it. In other words, you can say that is a collection that only allows one type of object and that there is fixed number of objects in it. This leads to excellent performance optimizations that are possible, and indeed Adobe has taken advantage of this. Of course I had to test this out for myself.

One of the other nice things about FlashCamp was that they gave us a new build of Flex Builder. This one has support for the new language features supported in Flash 10. To enable the new features, you just change the Flash Player version that you target and voila! I took some benchmark code that I had used for Flash/JS comparisons. Here is the original code:

private function testArray():Number{
var startTime:Date = new Date();
var arrStr:String = null;
var arr:Array = new Array();
var i:int=0;
for (i=0;i<=94;i++){
arr.push(i);
}
for (i=0;i<=arr.length;i++){
arr.push(arr.pop());
arr.sort().reverse();
arr.push(arr.splice(0,1));
}
arrStr = arr.join();
return (new Date()).getTime() - startTime.getTime(); }

And here is the new version that uses a Vector instead of an Array.

private function testVector():Number{
var startTime:Date = new Date();
var v:Vector.<int> = new Vector.<int>();
var arrStr:String = null;
var i:int = 0;
for (i=0;i<=94;i++){
v.push(i);
}
for (i=0;i<=v.length;i++){
v.push(v.pop());
v.sort(comp).reverse();
v.push(v.splice(0,1));
}
arrStr = v.join();
return (new Date()).getTime() - startTime.getTime(); }

Do you like the Vector syntax?

Anyways, back to the results. The Array averaged around 90 ms on my MacBook. The Vector code averaged around 20 ms on my MacBook. 4.5x? Very nice.

One thing I immediately wondered about Vector was if the Flash compiler erased the type. At first glance, there is no reason to do this. It is a different type, so there is no backwards compatibility issue. It does not extend Array, but it is a dynamic class. The documentation states that the push() method does not do type-checking at compile time, but does do this at runtime. This seemed weird, but it would imply that type information is not erased, since it can be checked against at runtime. However, in my testing I could use push() to push any object into any Vector, and had no compile time or runtime errors.

Sunday, October 05, 2008

October Talks

October is going to be a busy month for me. Next weekend I will be at Adobe's FlashCamp. I will be there Friday night and Saturday, and I may do a short session on TwitterScript, the ActionScript API that I maintain. In particular I want to talk about some of the authentication wrinkles present in TwitterScript and its forked brothers.

On October 20, I am speaking at AjaxWorld. I am going to be talking about a subject near and dear to me, Networked Applications. I'll be talking about why you shouldn't waste the power of your servers building HTML strings but why you should instead start using things like jQuery, GWT, or Flex to cash in on the power of your user's computers.

The week after that, I will be on the east coast speaking at EclipseWorld. On Day One, I am doing a day long, introductory workshop on Ruby on Rails. Of course I'll also talk about how Eclipse can help you out. On Day Two, I am doing two talks. One ties in to the previous day's workshop and is about RadRails. The other session is on ... iPhone development. Kind of a strange topic for me. Chris Williams from Aptana was supposed to do both sessions, but couldn't make it. So Aptana asked me to fill in for him. Hopefully they won't wind up regretting that decision!

Tuesday, September 30, 2008

WSDL in ActionScript

One of the advertised features of Adobe's Flex Builder is that it works with web services. Indeed, in any project you can import a WSDL and Flex Builder will generate lots of code for you. The resulting generated code states that the code generator is based on Apache Axis2, and it looks like it. This is mostly a good thing.

This is ok for a single developer or even a small team. Once you get to larger scale development, you usually want to keep code generated artifacts separate for the source code that generated them. Often you never want to check-in generated code. Why? Because then you have two sources of truth: the artifact (WSDL in this case) and the generated code. You don't want to have to keep these things in sync manually, you want your build process to do it. So you don't check in the generated code, and your build system generates it instead.

So ideally the code generation in Flex Builder could be invoked outside of Flex Builder. This may be the case, but so far I have no luck in this. It is certainly not a documented part of the SDK.

I looked for an alternative and found wsdl2as. This looked promising, but did not work out. First, it expects you to send in XML literals when sending SOAP messages. Sure it generates the boilerplate around the core message, but if I wanted to work directly in XML, I would not have bothered with a code generator. It has an option that seems designed to deal with this, but did not. Even worse, it does not handle anything except the simplest WSDLs. The first WSDL I tried with it defined complex types for the input parameter and return type of the web service. This caused wsdl2as to choke, as it expected any type information to be inlined. Sigh.

Tuesday, September 23, 2008

No SharedObjects Allowed

Client side storage by the Flash player (SharedObjects) has several advantages over traditional client side storage, a.k.a. HTTP cookies. From a security standpoint, it is better because the data is never sent over the wire. However the main advantage to most people is that it is bigger, and when it comes to managing data on the client, size definitely matters.

By default you get 100 KB instead of the 4 KB you get with cookies. If your application tries to store 101KB, it won't fail. Instead the user will be prompted to increase the allocated space by a factor of 10, i.e. from 100 KB to 1 MB. Of course you probably don't want the user to ever see this screen. One of the other advantages of SharedObjects is that people don't delete them. People blow away their cookies all too often, but most people would have no idea how to do the same with SharedObjects. The only you would find out would be if you saw the Flash player settings screen, i.e. the interface that appears when a Flash application tries to go over the 100 KB default limit.

So stick to under 100 KB and all is good, right? Not so fast. The settings interface requires that your Flash app is at last 136x213. If it is smaller than that, then what happens? First let's explain what happens when it is big enough to show the settings interface. When you flush data to local storage, a string is returned with a status. Here is typical code for this.


var testSo:SharedObject = SharedObject.getLocal("test", "/", false);
testSo.data.testValue = "test";
var soStatus:String = testSo.flush();
if (soStatus != null){
switch (soStatus){
case SharedObjectFlushStatus.PENDING:
testSo.addEventListener(NetStatusEvent.NET_STATUS, someHandler);
break;
case SharedObjectFlushStatus.FLUSHED:
break;
}
}

There are two possible return values, either "pending" or "flushed." There is no fail. So if you were flushing 101 KB, then you would get a pending return value. Now all you can do is what for an event, or more precisely a NetStatusEvent. This will tell you if the user allowed you to increase the size or not. If not then the NetStatusEvent will come back with a failure code.

If there is not enough space to display the settings interface, then you would think that you would just get an automatic failure, but you don't. Instead you get a "pending" from the return of flush. It's not really pending, since the user can't actually choose to allow it to succeed. It can only fail. But the player pretends this is not the case and that the user denied you request. So you need to still listen for the NetStatusEvent. If you don't catch that event, then it will cause the Flash player to throw an error to the user, and of course you do not want that. Here is a picture of that.


Thursday, September 04, 2008

JavaScript Faster than Flash

This is the last benchmark for awhile. Well, at least for today. I converted the JS benchmarks to ActionScript and tested them. The result were surprising, as JavaScript in Safari 4 and Firefox 3.x edged out Flash:


A few notes. I could not convert all of the tests, as two of them (the DOM and Ajax tests) were predicated on browser specific code. I could have done 'equivalent' functionality in ActionScript, but it did not appropriate for comparison. Otherwise the code was translated as is ... for the most part. I did add static type information where possible. There were also a few APIs (on Date and Array) that had be tweaked slightly. I tested similar changes to the JavaScript. The only test where there was any effect was the Date test. The JavaScript used Date.parse, which does not exist in ActionScript. The Date constructor does the same thing. If I switched to using the Date constructor in JavaScript, it was just slightly slower.

It certainly seems that much of the performance advantage enjoyed by Flash upon arrival of Flash Player 9 has been erased. Flash had a strong advantage still in more mathematical calculations (dates, integer and floating point arithmetic) as well as string manipulation. It did very poorly with arrays and regular expressions. I would guess that as the JITs for JavaScript get better, the string advantages will disappear. Flash will probably maintain an advantage in more mathematical computations, especially given its vector graphics features. Hopefully advances in JavaScript will spurn Flash VM progress.

Notes
1.) Tested on both Flash 9 and 10 RC2 on both OSX and Windows. Negligible performance differences in any of the permutations.
2.) Also tested with Silverlight, but only on Windows. It was slower than everything except IE7. However, that was because it was terribly slow at regular expressions and error handling. It clearly had the best JIT as it was able to reduce some of the tests to 0 after a couple of executions.

Tuesday, September 02, 2008

Firefox 3.1: Bring on the JIT

Web developers everywhere are excited about Firefox 3.1. Part of that is because of CSS improvements, but the big reason is because of TraceMonkey. This a JavaScript engine with a JIT that uses trace trees, a pretty clever technique to turn interpreted JavaScript (read slow) into compiled native (read fast.) JIT is a big part of why VMs like the Java VM and the CLR are very fast, in general much faster than VMs that do not JIT like in Python, Ruby, or (until now) JavaScript. It is why JRuby is faster than Ruby. Thus the prospect of making JavaScript much faster is very exciting.

Recently I had done some micro-benchmarking of JavaScript performance vs. ActionScript/Flash performance. This concentrated on XML parsing only. Now the ActionScript VM is a JIT VM. In fact, Adobe donated it to Mozilla and it is known as Tamarin. It has been Mozilla's intention of using this for JavaScript in Firefox for awhile, as JavaScript is essentially a subset of ActionScript. TraceMonkey is based on Tamarin, but it adds the trace tree algorithm for picking what to JIT. The trace tree approach allows for smaller chunks of code to be JIT'd. For example if you had a large function, like say a single script that runs when the page loads, then with a traditional JIT you either JIT the whole function or not at all. Now what if that function has a loop that runs dozens of times, maybe populating a data table for example. With a trace JIT you can JIT just that one critical loop, but not the whole giant function. So it should be an improvement over Tamarin and thus ActionScript. Of course there is only one way to tell...

So I repeated the same XML parsing tests that I did for Firefox 3.0 and Safari 4 (beta). First, I had to enable JIT in Firefox. One of the links above describes how to do this (open about:config in FF 3.1, look for the jit.content option and set it to true.) I restarted FF 3.1 just to make sure this took effect. I then ran the tests. The results? Not much difference between FF 3.0 and 3.1b+JIT. FF 3.1b+JIT was about 4% faster, which is probably statistically negligible. It was still 6x slower than ActionScript and almost 3x slower than Safari 4.

So what went wrong? Not sure. Here is the code that gets executed in my test:

function load(){
var parser = new DOMParser();
var xml = {};
var start = 0;
var end = 0;
var msg = "";
var results = document.getElementById("result");
var li = document.createElement("li");
initReq();
req.open("GET", "LargeDataSet?size=50", true);
req.setRequestHeader("Connection", "close");
// use a closure for the response handler
req.onreadystatechange = function(){
if (req.readyState == 4 && req.status == 200){
msg = "XML Size=" + req.responseText.length;
start = (new Date()).getTime();
xml = parser.parseFromString(req.responseText, "text/xml");
end = (new Date()).getTime();
msg += " Parsing took: " + (end-start) + " ms";
li.appendChild(document.createTextNode(msg));
results.appendChild(li);
}
};
req.send(null);
}

Pretty simple code. I manually execute it 20 times. It would sure seem like it could be JIT'd. What gets timed is just the parser.parseFromString(...) call, where parser is a DOMParser. Maybe that object cannot be JIT'd? Maybe there is a bug with the JIT that will be resolved in the future? It does seem to suggest that TraceMonkey may not always be the slam dunk everyone expects.

I was surprised by the results. I thought that FF3.1 would be faster than FF3. I didn't think it would be faster than ActionScript in this case, but I thought that it might be close. In many other cases, I expect ActionScript to still be much faster than TraceMonkey. Why? Well there is one other ingredient in VMs like the JVM and CLR that make them fast: static typing. This allows the VM to make a lot of other optimizations that work in combination with JIT'ing. For example, knowing that a particular variable is a number or a string allows the VM to inline references to that variable. This can eliminate branches in logic (if-else statements, where maybe the else is not possible.) The JIT can then take place on the simplified, inlined code, and be about as fast as possible.

If you read about some of the techniques used in TraceMonkey, it tries to do a lot of the above via type inference. So in some cases TraceMonkey and the AVM2 (ActionScript VM) may be able to do the same level of optimizations. In fact, given its tracing approach, TraceMonkey may be able to do better. But I am guessing that there will be a lot of situations where AVM2 will be able to do more optimizations just because of the extra information it has at its disposal in the form of static typing.

Thursday, August 28, 2008

Search Twitter from Flash

I have updated the Twitter ActionScript API. I added support for search. You are probably aware that search is provided by Summize, who was acquired by Twitter. It is pretty obvious that the APIs have not yet been merged!

Twitter's API is all based on Rails ActiveResource ... which is awesome. It turns any resource (often a database table) into a RESTful service. REST is often associated with XML, but Rails (and thus Twitter) supports it as JSON (Twitter supports ATOM and RSS as well) too. For ActionScript, XML is great. Or I should say POX is great and that is what Rails serves up.

The Twitter Search API is different. It supports two formats: ATOM and JSON. No POX. I went with the ATOM format. For JSON, I would have used Adobe's corelib. It works well, but I didn't want to add the weight. Plus, JSON tends to parse much slower in AS3 than XML. That is because AS3 implements E4X. To get E4X to work with ATOM, you have to be mindful of namespaces. For example, here is the code I used to interate over the entries: for each (entryXml in xml.atom::entry). Here the xml variable is the parsed result from search.twitter.com and atom is a Namespace object. Not as pretty as just xml.entry, but oh well.

Sunday, August 24, 2008

Parsing XML on the Client: JavaScrpt vs. ActionScript

Developer: Wow the JavaScript interpreter on Firefox 3 is awesome, but the one on the new Safari is even better. It is a great time to be a JavaScript developer!

Me: It is still a lot slower than ActionScript.

Developer: Oh don't quote me old numbers, the new browsers are so much faster.

Me: Still slower than ActionScript.

Developer: Maybe slower at doing useless things like calculating prime numbers. Who would do that in a browser anyways? The new browsers are fast at doing realistic things.

Me: But still slower than ActionScript.

Developer: Show me some proof on something realistic, like parsing XML coming back from an Ajax call.

Me: [Whips together a servlet for producing huge chunks of XML and some JS and a SWF for calling it and doing a DOM parse.] Alright let's see the results of these tests...

Everything is O(N), as you would expect, and can verify by doing a linear regression of XML document size vs. parse time. Safari 4 is much faster than Firefox 3, the ratio of their slopes (FF3/S4) = 2.95. But they both lose badly to ActionScript 3 (running Flash Player 10, RC2), (FF3/AS3) = 6.36 and (S4/AS3) = 2.16. Maybe IE can do better, should we give it a try?

Developer: Now you are being a jerk.

Monday, June 09, 2008

Gears and Flash

Tonight I launched up Firefox 3, and it informed there was an update to Gears ready to install. I went for it, and sure enough Gears was now working with Firefox 3! I didn't find any official announcement about this, but I didn't let that stop me from finishing an idea I had last week: getting Gears and Flash to work together.

This was not too hard. It is just a matter of using ExternalInterface to create a bridge between the two worlds. I wrote a quick POC, using a simple DB table for storing name/value pairs. I think it would be fun to re-implement the flash.data package that is normally only available in AIR apps...

Here is the JavaScript code:
function dbCall(sql, args){

var db = google.gears.factory.create('beta.database');
var rs = null;
try{

db.open('database-test');
db.execute('create table if not exists little_table (key varchar(20), value varchar(100))');
rs = args ? db.execute(sql, args) : db.execute(sql);
data = [];
while (rs.isValidRow()){

row = {};
for (var i=0;i<rs.fieldCount();i++){

var name = rs.fieldName(i);
row[name] = rs.field(i);
}

data.push(row);
rs.next();
}
return data;
} finally {

rs.close();
}
}


Here is the ActionScript code:
import flash.external.ExternalInterface;


[Bindable]
private var rs:Array = [];

private function load():void{

rs = ExternalInterface.call('dbCall', 'select * from little_table');

}
private function save():void{
var key:String = keyIn.text;
var value:String = valueIn.text;
ExternalInterface.call('dbCall', 'insert into little_table values(?,?)', [key, value]);
keyIn.text = "";
valueIn.text = "";
load();

}
private function clearData():void{
ExternalInterface.call('dbCall', 'delete from little_table');
load();

}


And here is the MXML I used to test it out:
<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="load()">
<mx:DataGrid x="202" y="59" id="grid" dataProvider="{rs}">

<mx:columns>
<mx:DataGridColumn headerText="Key" dataField="key"/>
<mx:DataGridColumn headerText="Value" dataField="value"/>

</mx:columns>
</mx:DataGrid>
<mx:Label x="10" y="251" text="Key"/>

<mx:TextInput x="74" y="249" id="keyIn"/>
<mx:Label x="242" y="251" text="Value"/>

<mx:TextInput x="285" y="249" id="valueIn"/>
<mx:Button x="460" y="249" label="Save" click="save()"/>

<mx:Button x="243" y="298" label="Clear" click="clearData()"/>

</mx:Application>

Tuesday, April 08, 2008

Twitter API in ActionScript

I noticed that the Twitter ActionScript API was a bit out of date to say the least. I had to update it for a small project I was playing around with. I sent a note to al3x about this, and suggested open sourcing the API. He agreed and so here it is.
It needs a lot of work. I basically removed the old authentication scheme, since it relied on setting the Authorization HTTP header and that is no longer allowed starting in Flash Player 9.0.115. This also let me remove a dependency on a third party base 64 encoder. I guess a base64 encoded string that includes your username and password is supposed to be secure :-) I also fixed the loadFriends method, as this now returns users not status messages. I will get the API up to date, but if anyone wants to help out then just send me a note.

Thursday, March 13, 2008

Silverlight Stocks

Ever since details of Silverlight 2.0 came out, I planned on re-doing my stocks app using it. This is an app that I first wrote for a GWT tutorial I did for IBM, and then re-wrote when I learned Flex last year. I wanted to write it in Silverlight last year, but Silverlight was not ready then. Now it is. Here's a picture of it.


This look-and-feel is all defaults. It looks like a web page! It's usually easy to spot Flex apps, but that is not as true with Silverlight. Everything works the same as with the Flex or GWT versions, except the color-coding for stocks that are up or down. I figured out how to define styles with Silverlight (more on that) but could programmatically set the style. Let's take a look at the code. First the UI code.


<UserControl x:Class="SilverStocks.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Enter Symbol "/>
<TextBox x:Name="symbol" Width="100" KeyDown="symbol_KeyDown"/>
<Button Click="Button_Click" Content="Get Info" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Company Name: "/>
<TextBlock x:Name="company"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Price: "/>
<TextBlock x:Name="price" Text="$"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Change: "/>
<TextBlock x:Name="change" Text=""/>
</StackPanel>
</StackPanel>
</UserControl>


Pretty similar to MXML, but distinctive. As with ASP.NET pages, Silverlight puts all code in a code-behind file:


public partial class Page : UserControl
{
const string url = "http://localhost:8080/Stocks/Stocks?symbol=";
public Page()
{
InitializeComponent();
}

private void Button_Click(object sender, RoutedEventArgs e)
{
invokeStockService();
}

private void invokeStockService()
{
string symbol = this.symbol.Text;
WebClient service = new WebClient();
service.DownloadStringCompleted += new DownloadStringCompletedEventHandler(handler);
service.DownloadStringAsync(new Uri(url + symbol));
}

private void handler(object sender, DownloadStringCompletedEventArgs args)
{
if (args.Error == null)
{
this.showInfo(args.Result);
}
}

private void showInfo(string xmlContent)
{
XDocument root = XDocument.Parse(xmlContent);
var stocks = from xml in root.Descendants("stock")
select new Stock
{
Symbol = (string) xml.Element("symbol"),
Company = (string) xml.Element("companyName"),
Price = Decimal.Parse((string)xml.Element("price")),
Change = Decimal.Parse((string)xml.Element("change"))
};
foreach (Stock stock in stocks)
{
this.company.Text = stock.Company;
this.price.Text = stock.Price.ToString();
this.change.Text = stock.Change.ToString();
}
}

private void symbol_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
this.invokeStockService();
}
}
}


Notice that I used the LINQ-XML cleverness, as advocated by Scott Gu. Most dynamic language folks will probably favor ActionScript's E4X over using this lambda-ish query language and a statically defined class. Actually I'm sure I could refactor this to not use the class at all, and just set the text fields during the query.

Finally, the other major difference between the two is the Flex framework's mx:HttpService. This component encapsulates the call to the back-end and provides dynamic binding. There is no handler code in the Flex version because of the binding. Will data source bindings and components like mx:HttpService find their way in to Silverlight?

Thursday, February 28, 2008

Silverlight Slim and Fat Flex

A couple of days ago, I talked about Silverlight 2.0. One of the interesting things to me was that it was how Silverlight RIA-style apps could be a lot smaller than Flex apps. I posted a comment to Scott Guthrie and he was kind enough to post a reply to my question. His reply indicates that for Beta 1, a relatively complex application will be slightly smaller than the same thing in Flex. However, much more of the framework is going to be included with the initial Silverlight download starting in Beta 2, thus giving Siliverlight a huge advantage in terms of app size.

When Adobe announced that the Flex framework could be cached on the Flash player across domains, I wondered why the didn't just included it with the Flash player. I have even bugged Flex evangelist Ted Patrick with this question. His response to me was that they would open themselves up to "DLL hell." In other words, there could be problems with people building their app against Flex framework version X, but a user has an older version installed.

As if this doesn't already happen! Let's not forget that Adobe jumped ActionScript from version 2.0 to 3.0 and thus required Flash player 9 or higher for anything authored using 3.0. This was not just some update in framework, it was the entire programming language being overhauled. It is common to use JavaScript to detect Flash player version and require people to upgrade. It is so common and so part of Flash development, that Adobe distributes the ExpressInstall SWF for doing this as easily as possible. Heck, I usually require users to be on 9.0.28 or higher, since that is the version that fixed some bugs with ExternalInterface.

So back to the Flex framework/DLL hell issue. It would simply require people to check for a certain minimum version of the Flash player (since that would correspond to a version of the Flex framework) and prompt for an upgrade if needed. In other words, it would require something that most folks already do today.

To me the real reason is that it is more economical for Adobe to not include the Flex framework. Ted has a widget he wrote showing over 3.9 billion downloads of Flash player 9. Add an extra 200K to that and you get over 726 TB. That's a lot of bandwidth to pay for. That's a price Microsoft wants to pay, because it would indicate lots of folks with Silverlight installed. Perhaps once that happens, Adobe will reconsider.

Tuesday, February 12, 2008

New Version of JsonViewer: Now Open Source!

I updated the JsonView AIR app I wrote a couple of months ago. It has wound up being pretty useful for some of the folks I work with, hence there have been some bug fixes new features requested. I have also had some folks email me about the source code. So as a result of these two things, not only did I update the app, but I released it as open source via Google Code.

So you can get the latest version here, or you can check out the source code for yourself. I was almost embarrassed to show the source because it so trivial!

Wednesday, February 06, 2008

Setting Custom HTTP Headers in Flash

I needed to set a custom HTTP header in Flash. ActionScript 3 makes this easy, or so I thought. Here was my original prototype code:

import flash.net.navigateToURL;
private function href(url:String):void
{
var req:URLRequest = new URLRequest(url);
var header:URLRequestHeader = new URLRequestHeader("Koostoom", "tmttos");
req.requestHeaders.push(header);
navigateToURL(req);
}

Like I said, this is easy. To verify it was working, I wrote a quick prototype using PHP:

$headers = getallheaders();
foreach ($headers as $name => $value) {
echo "[$name] = $value<br/>\n";
}

I think I copied this out of the PHP manual pretty much. So I tested the above code and everything worked, right? I wouldn't be writing this post if that was the case!

I tried the above in Firefox and Safari. My usual test plan is to make sure it works in those two browsers first, and then deal with IE. In this case it didn't work in either browser. I knew that some HTTP headers were off-limits in Flash, so just for just kicks I tried changing Koostom to Referrer. This should have caused an exception, but of course it didn't. It did nothing.

Finally, I found the answer through experimentation. You have to do an HTTP POST with form data in order to get the custom header sent:

import flash.net.navigateToURL;
private function href(url:String):void
{
var req:URLRequest = new URLRequest(url);
// begin stupid hack
req.method = "POST";
var formVars:URLVariables = new URLVariables();
formVars.blah = "blue";
req.data = formVars;
// end stupid hack
var header:URLRequestHeader = new URLRequestHeader("Koostoom", "tmttos");
req.requestHeaders.push(header);
navigateToURL(req);
}

Now the PHP script showed my Koostoom header...

I don't know if this is a bug with the Flash player, or the browsers. I don't think it is part of the HTTP spec, i.e. I think custom headers are just as valid in an HTTP GET as in an HTTP POST.

Thursday, January 31, 2008

Flash Hacks: Call Arbitrary JavaScript!

In the past I've been annoyed by the lack of HTTP header access in Flash. Turns out there are some hacks you can do to get around it. Let's say you want the URL of the web page that loaded the SWF. This would be the referrer of the HTTP request that loaded the SWF. Flash should provide access to that, but it doesn't because some browsers don't provide it this info. That's ok, you can get to it:
var hostPageUrl:String = ExternalInterface.call("window.location.href.toString");

That's right, you can "call" a JavaScript expression, not just a function defined on the page. Of course the key is that everything in JavaScript (and in ActionScript too) is a function. So any JavaScript expression is a function and thus invokable via ExternalInterface. You can see where this is going! Let's say you want the query string of the host page's URL:
var queryString:String = ExternalInterface.call("window.location.search.toString");

This will give you something like "?param=value&foo=bar..." What about the referrer of that page? 2EZ:
var referrer:String = ExternalInterface.call("document.referrer");
This is a classic case of Too Much Information, really. You are able to execute arbitrary JavaScript, ExternalInterface acts like an eval(). So you can do arbitrary badness like modify the DOM. You can also access cookies (document.cookie).

Of course the key to all of this is script access. The SWF needs to have it. If the SWF is from the same domain as the web page, it gets this by default. If not, then you need to set allowScriptAccess="always". That gives the SWF the keys to the kingdom, if you will. Of course you could use an IFrame for the SWF and sandbox it in.

Friday, January 25, 2008

Cute EcmaScript

The following is a nifty trick that works in JavaScript, but you should be able to tweak it slightly to work in ActionScript as it leverages EcmaScript features.


function Train(){
this.name = "Choo Choo";
this.show = function(){
return this.name;
};
};
var engine = new Train;
engine.name = "Orient Express";
function go(){
alert(engine["show"].call(engine));
}


What is cool is that you can access a function just like any other property of the object. So the go function could take a parameter that would be the name of the function to call on the engine object. It's like reflection, only better.

Thursday, January 10, 2008

Flash and HTTP Headers Redux

A few months ago I wrote about the lack of access to HTTP headers in Flash. I recently came across some other people talking about this. This has caused debate about Flex being able to support REST.

The opinion seems to be that Adobe does not allow this because not all browsers will provide this information to the Flash player. I have not seen a list of what browsers have this limitation, though I will speculate it must be older versions of popular browsers... Some of the evidence of this is that this is provided in AIR. In AIR, it is the runtime itself that makes HTTP requests. In a SWF running in a browser, the runtime relies on the browser. So restrictive browsers could be an issue on a SWF, but never for an AIR app.

Could another reason be security? In particular, cookies are passed back-and-forth via HTTP headers. There are numerous cases of cookies being stolen by malicious JavaScript, which has total access to HTTP headers. Adobe made a lot of significant security improvements between Flash Player 8 and 9. In a world of mashups, are they better off continuing to deny access to HTTP headers?

All of that being said, I recently ran across another case where this causes problems. I had a SWF that could be loaded by two different pages. It needed to show slightly different features depending and have a different look and feel depending on what page it was on. The easiest thing to do would have been for it to "know" what page was loading it by looking at the referrer on the HTTP request that loaded the SWF. This is a header of course, and thus not available. Instead a FlashVar could be passed in to tell the SWF what to show. That's a better way to do it, but required changing the code of the page hosting the SWF, which was not an option. The hack that had to be used was to have to logical copies of the same SWF, foo_A.swf an foo_B.swf. The SWF could then look at its this.loaderInfo.URL to figure out what to show.