Quality Reads

Friday, August 03, 2007

The Cross-Over Point AKA FU Money

Hackzine has a great post on money management. They discuss the often sought after (little talked about) situation known as FU Money. The point where you earn more in interest on your investments than you spend in living expenses. Its a really simple concept that most people don't think about until they're old and gray (Hackzine begs to differ).

I've come up with a new response to "What's fueling this whole Web 2.0 frenzy?" FU Money, obviously!

Have a great weekend.

Cheers,
Todd

CF8 Logos...


Rey Bango just posted a bunch of CF8 logos. If you're working on a ColdFusion 8 powered project (I know I am), then you may want to snag one of these. I'm hoping to have some info on my *hush* *hush* AIR derby project by Monday.

Cheers,
Todd

Saturday, July 28, 2007

Ning :: Full Source Access

API's are great from a security standpoint but creativity takes a backseat in the process. What happens when you come up with an idea/concept that the original developer never thought of? With a standard web service, nothing. With Ning, you can write your own API .

http://www.ning.com/help/faq-developers.html

Perhaps I'm blurring the truth a little bit. Ning doesn't really provide an "API" like other web applications, they've created an application layer that ANY community user can edit. Their API is exposed via PHP, a very untraditional approach to open development that begs the question: if Ning can do it, why can't you? or me? or Google?

If you could provide all your company's information/resources in a system like Ning, would you?

Thursday, July 26, 2007

Drag & Drop in AIR

I just ran into a great article by Alastair outlining the use of Native Drag & Drop functionality in AIR (w/ a little RoR mixin). The documentation for Native D&D is very spotty, there are more mistakes then anything else. So, if you haven't learned the hard way yet, let me make your life a little easier: http://blog.vixiom.com/2007/06/29/merb-on-air-drag-and-drop-multiple-file-upload/

Here's a simple test application you can use to get started:

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init(event)">

<mx:Script>
<![CDATA[
import mx.events.DragEvent;
import flash.desktop.DragManager;
import flash.desktop.DragActions;
import flash.events.NativeDragEvent;
import flash.desktop.TransferableFormats;
import flash.filesystem.File;

private function init(e:Event):void
{
//add the event handlers
this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, onEnter);
dropPanel.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, onDrop);
}

public function onEnter(event:NativeDragEvent):void
{
//Check to see if the drag item is the right format
if(event.transferable.hasFormat(TransferableFormats.FILE_LIST_FORMAT))
{
DragManager.acceptDragDrop(dropPanel);
}
}

public function onDrop(event:NativeDragEvent):void{
trace("dropped");
// Cast the drag & drop data as an array
var files:Array = event.clipboard.dataForFormat(flash.desktop.ClipboardFormats.FILE_LIST_FORMAT) as Array;
for each (var f:File in files)
{
// check out the file URL
trace(f.url);
}
}
]]>
</mx:Script>

<mx:Panel id="dropPanel"
top="10"
left="10"
height="100"
width="100"
title="Drop Files Here"
backgroundColor="#FFF">


</mx:Panel>

</mx:WindowedApplication>



Also worth a read: http://coenraets.org/blog/2007/06/air-to-desktop-drag-and-drop-two-simple-utility-classes/

I'll let you know why I'm reading up on D&D in a couple days :)

Cheers,
Todd

***Updated for AIR Beta 2***

Sunday, July 22, 2007

CT-CFUG Presentation

Just a quick heads up. JB and I are giving a presentation on Adobe AIR at the Connecticut ColdFusion User Group on Tuesday night (July 24th, 2007). If you're in the area and up on technology, you might want to think about stopping in for our jam session. I hear there's going to be some free Adobe swag in it.

Cheers,
Todd

Thursday, July 19, 2007

Nokia Didn't See This Use Case Coming

Adam Prestin pointed me to this crazy picture earlier today and I had to re-post it.

No this phone wasn't modded out by some MAKE afficionado. Its actually a terrorist/insurgent/{insert political spin here} bomb timer from Iraqi, apparently a very common one too.

Its a good thing they missed the call.

(Thanks Adam)

Bubblemark Animation Test Confirms It

Alexey Gavrilov compiled a nice set of performance tests for all the major RIA development platforms (Flex, Silverlight, JavaFX, AJAX). Flex (aka Flash) performed like a champ in the browser arena, which isn't horribly surprising considering how long its been around. Both Flex & Actionscript are up to, or on the way to, version 3.0 and Flash is rocking numero nine. I do have to admit that I'm impressed by Microsoft's progress on Silverlight. After the Flex 2.0 release, they must have recognized the enterprise level development capabilities that Flex brought to the table and jumped right on the issue. If they had taken a look at the crazy flash apps Pier was doing back in 2001, they might have foreseen this RIA trend long in advance.

Here are a couple surprises:
  • JavaFX is 4.4 times slower than Flash.
  • Firefox + Silverlight (CLR) — 99 fps
  • Flex and AIR peform at the same speed (as I previous reported)
While it looks like Silverlight is going to be a strong contender from a performance standpoint, I'm going to hold my opinion until they release the first non-Windows version.

Check out the complete results here.

PS- I also enjoyed reading Alexey's initial experiences w/ Flex. I distinctly remember dealing with each one of the issues he mentioned. Good times.

Thursday, July 12, 2007

There's an Advanced DataGrid!?!

I guess in all the excitement surrounding Adobe AIR, I missed out on a huge feature available in Flex 3, the Advanced DataGrid.


If you're working w/ alot of data in your Flex/AIR applications like I am, you need to check this component out. It may just save your life/sanity.

Here are some of the main features:
  • Multi-column sorting
  • Tree View (basically a tree component mashed into a DataGrid)
  • Cell Formatting
  • Summary Collections (allows you to perform a calcuation on the DataGrid columns and output a result)
  • Column Grouping
Seriously, half the work I'm doing right now could be handled with this component. Check out some of the details here or the Flex 3 docs here. This is the type of great stuff I expect from the Flex team. Now if we could only get the CS3-to-Flex skinning integration to work properly everything would be brilliant.

Cheers,
Todd

Tuesday, July 10, 2007

Performance in AIR


If you're like me, you might have thought that Adobe AIR (formerly Apollo) would provide a more powerful computing platform for desktop RIA development. Well, you'd be wrong. After running a number of performance tests ranging from long-running financial calculations to CPU intensive UI effects, AIR and Flex executed at approximately the same speed (~2% in favor of Flex -- insignificant).

While I must profess a little disappointment, I don't think its a huge downside of the platform since Flash provides so many other core competencies. However, you need to take it into account whenever you are about to perform a lengthy IO operation. The user interface will freeze up when saving/generating multiple files. At Pier, we've been popping up a modal window just prior to all IO ops to keep the user from trying to interact w/ the UI during the freeze.

My suggestion is take the time to setup you IO framework so you don't have to code a custom modal on every operation.

Cheers,
Todd

Saturday, June 30, 2007

Execution Times in Apollo vs. Flash

I just wrapped up a 12hrs. coding session at work. We're creating an application that provides ROI (return on investment) calculations to prospective technology clients. Its standard practice these days to sell software based on value even though selling on features is a heck of a lot more fun, which is where the ROI calc. comes in handy.

Behind the calculator's UI, there are a plethora of events being generated to update the key benefits used by the buyer. As we've continued to work on larger calculators (more benefits), the processing time in AIR has lagged even when the Flex seems to run unhindered. So tonight I did a little testing to see how significant the difference was, I was shocked to learn that AIR executed the same functions as the Flex application at a speed ~ 54% slower. The "native" application is running slower?!? Even more bizarre, the execution time goes back to normal when I load a secondary SWF inside the AIR application to handle the calculations. Very weird and disheartening to say the least. I don't have the tests at home otherwise I'd post them but if anyone has a reason for this discrepancy. Do tell.

You can expect the source for my tests tomorrow. Until then, you might want to think about creating a wrapper for calling functions w/in a SWFLoader. Here's a useful article about how to make calls from the child app. to the parent.

Cheers,
Todd

Thursday, June 21, 2007

Living in Boston...

I guess I haven't taken the time to make mention of my new job (or write a post for that matter). I packed up my bags about a week ago and made the long haul up to Boston, actually it was three short hauls. Besides the psycho that yelled at me for "borrowing" her parking space while I moved my furniture into my apartment, everyone I've met has been great. A trend I'm sure can't last forever but I'm enjoying it for now.


My new company, Pier Inc., creates Rich Internet Applications using Flash (Flex, AIR). We've got an impressive list of Fortune five clients and skunkworks to boot! I've got to get back to work for now but you can expect some great Flex/AIR tutorials to follow.

Cheers,
Todd

Thursday, June 07, 2007

Managing Markers in Google Maps



I just spent the last four hours trying to coerce Firefox into properly displaying 600 markers on Google Maps (using GMarkerManager). In the end, I came up with the same response "too much recursion", FF's words not mine.

My original process was to create the map, so users have something to look at, then make an XHR call for all the markers I wanted to place on it. Logical, I thought at the time. For some reason, making the XHR call after the map is instantiated seems to freeze up my computer (dual-core Mac). A very bad sign considering the average user doesn't have the power setup that I do. I tweaked a couple functions to improve performance but nothing seemed to work.

Then I found this web page (and demo) which provides a VERY simple solution. Load the data up front then initialize the map. Presto, GMarkerManager kicks in and everything works perfectly. If you don't feel this answer is satisfying...I hear you. Frankly, it doesn't sit well with me either but it works and the load time isn't horrible.

Hopefully, someone will see this post and avoid getting brutalized like I did.

Cheers,
Todd

Wednesday, June 06, 2007

Is Google Expanding Too Quickly?

I want to say no. Really.
I want to believe that Google is the company of the future. Nimble, smart, and opportunistic. Shifting resources on a dime to push whatever technology is on the horizon.
Then I get a reality check:
You'll notice something strange in the top left corner of the page. Yep, thats some Javascript for their Google Analytics account. Upon further inspection, I discovered they forgot the closing script tag. Pretty sloppy. I'm not saying I haven't thrown pages up before they were ready or that I don't make mistakes. But come on. Someone should have QC'ed the page and noticed that.
I guess the future isn't today.

Friday, June 01, 2007

Updated: Custom Event System for Prototype

After using my original Event System for a little while I realize that I structured the original Classes all wrong. For some reason, I though it was a good idea to pass the event dispatching responsibilities off on the Event object itself. Bad idea. So I updated the code, all 2K of it.

Here's the update:


/**
* @author toddcullen
*/
CustomEvent = {};
CustomEvent.Events = {};
CustomEvent.Events.Base = Class.create();
CustomEvent.Events.Base.prototype = {
initialize : function(){
this.type = "CustomEvent.Events.Base";
}
}
CustomEvent.EventController = Class.create();
CustomEvent.EventController.prototype = {
initialize: function(){
this.listeners = $A([]);
},
addEventListener: function(n, f){
this.listeners.push({name: n, callback: f});
},
removeEventListener: function(n, f){
this.listeners = this.listeners.without({name: n, callback: f});
},
dispatchEvent: function(n, e){
for(var x=0; x<this.listeners.length; x++){
if(this.listeners[x].name == n){
this.listeners[x].callback(e);
}
}
}
}
var EventController = new CustomEvent.EventController();


You can create any type of Event you'd like. Its just an object you pass from the event target to the listener. Here's an example usage where I created a DataEvent Event Class:


/*
* Data Event
*/
CustomEvent.Events.DataEvent = Class.create();
CustomEvent.Events.DataEvent.prototype = {
initialize : function(data){
this.type = "CustomEvent.Events.DataEvent";
this.data = $H(data);
}
};

Event.observe(window, "load", function(){
EventController.addEventListener("BasicEvent", testListener);
EventController.addEventListener("DataEvent", testListener);

Event.observe('basic', 'click', dispatchBasic);
Event.observe('data', 'click', dispatchData);
});

function dispatchBasic(){
var event = new CustomEvent.Events.Base();
EventController.dispatchEvent("BasicEvent", event);
}
function dispatchData(){
var event = new CustomEvent.Events.DataEvent({info : 'HELLO WORLD!'});
EventController.dispatchEvent("DataEvent", event);
}
function testListener(event){
alert("event type:"+event.type);
if(event.type == "CustomEvent.Events.DataEvent"){
alert('event data: ' + event.data.inspect());
}
}


The HTML is simply an anchor with an id of "data" and an anchor with an idea of "basic". This system is really useful for an HTML UI that has to be flexible. Minimize/eliminates the need for objects to know about each other. They only need to "know" about the EventController.

Snag the full demo here.

Cheers,
Todd

Apollo/Gears Integration

Check out this press release on Apollo/Gears integration.

Gotta run!

Seriously, I have to leave this time.

Gears is Great for Bandwidth

Real quick post, I'm on my way into the office.

Most people are aware of the growing bandwidth issue facing ISP's. With high def videos and full scale web applications, people are using more bandwidth today per capita than every before.

Enter Google Gears, reduce the amount of bandwidth needed for large scale web apps by downloading it once and serving the static files locally.

Brilliant!

::I'm working on a versioning system right now, so applications will know when to update themselves to the latest version::(Its apart of the API)

Wednesday, May 30, 2007

Google Closing Web-Desktop Gap

Right on the heels of my post concerning "Universal Search", Google just announced a new project bringing the web and the desktop closer together. Google Gears is a development platform where online applications can be made available offline or provide additional processing power to an online application. One of the major limitation of javascript is its single threaded processing. If you have a resource intensive operations occurring on a web page, the UI will often freeze until the operation is complete. Obviously, users don't understand what's going on in the bowels of the application so this can create a significant development barrier. Google Gears provides an API to hand off the resource intensive operation so the UI doesn't freeze up and users are none the wiser.

Here are the three main features of Google Gears (straight from Google):
LocalServer LocalServer
Cache and serve application resources (HTML, JavaScript, images, etc.) locally
Database Database
Store data locally in a fully-searchable relational database
WorkerPool WorkerPool
Make your web applications more responsive by performing resource-intensive operations asynchronously

From my brief inspection of the API, this makes me rethink my whole opinion of Apollo. You can develop one website with hooks into Gears that gracefully degrades if its not installed. With the Flex/AJAX bridge, you could even have a Flex website that communicates with the Database and WorkerPool. Whoa. Pretty sweet.

I'll post some more thoughts, once I get some time to digest the idea.

-Todd

Search in a Foreign Language


I happened upon this hidden gem in Google Translate. I know Google just announced their "Universal Search" concept but I hadn't actually noticed any new features to back up the claim. That is, until I ran into the aforementioned page.

As you can see from the screenshots, you can specify your native language and the language you want the results selected from.

Based on my search for "Silverlight" in Japanese, I'm not sure how relevant the results are yet. Here are a couple quick questions I've got running around:
  1. What's the time line to integrate this feature into Google search classic (or iGoogle)?
  2. What's the purpose behind serving both the translated and original version on the search page? If I'm using a translator, I obviously don't know the language very well. In what situation would I need the original next to the translated version? Besides learning the language.
  3. What type of search requires specifying a foreign language? Perhaps as someone English speaking, I am not Google's target audience for "Universal Search".
Like all things Google, Universal Search is still in Beta.

Cheers,
Todd

Thursday, May 24, 2007

OOP in Javascript

Ran across this great article by Ray Djajadinata (Microsoft Developer). Its a shame this wasn't around when I first started getting into advanced Javascript development two years ago. Could've saved me hours of trial and error.

If you still don't fully grok OO Javascript, check out the section explaining how prototyping works. Great stuff.

Cheers,
Todd

Tuesday, May 22, 2007

Prototype Custom Event System

Perhaps I have a little Flex envy but the DOM event model is woefully ill-suited to handle dynamic single page applications. To remedy the situation, I've written an extension for Prototype to provide a Custom Event messaging system. Its designed to work as a mediator between your AJAX controller and services. The concept works something like this:
  1. A user clicks a button (or interacts with any UI component) and a DOM event is triggered. Typically captured using Event.observe.
  2. The controller receives the DOM event, checks the state of the application, and gathers any data required by the model.
  3. Then using the Custom Event framework, a Custom Event is broadcasted with all the data the Model needs to perform its actions.
  4. The Model receives the Custom Event, processes its service call (or data storage etc.), and then uses its own Custom Event to broadcast data back to the controller.
  5. The controller then updates the view accordingly.

Custom Events are not a replacement for the Event object. Its really meant to aid in the loose coupling of the Model from the Controller in your client side code. Now that you've heard my spiel. Here's the code:



CustomEvent = {};
CustomEvent.Events = {};
CustomEvent.Events.Base = Class.create();
CustomEvent.Events.Base.prototype = {
initialize: function(){
this.listeners = new Array();
},
addEventListener: function(f){
this.listeners.push(f);
},
removeEventListener: function(f){
this.listeners = this.listeners.without(f);
},
dispatchEvent: function(n, d){
var data = this.setupData(d);
this.listeners.each(function(l){
l({name : n}, data);
});
},
setupData: function(d){
return $H(d);
}
}
CustomEvent.EventController = Class.create();
CustomEvent.EventController.prototype = {
initialize: function(){
this.events = new Hash();
},
create: function(n, t){
var args = arguments[2]?arguments[2]:null;
this.events[n] = new Event.CustomEvent[t](args);
},
addEventListener: function(n, f){
this.events[n].addEventListener(f);
},
removeEventListener: function(n, f){
this.events[n].removeEventListener(f);
},
dispatchEvent: function(){
var n = arguments[0];
var d = arguments[1] ? arguments[1] : {};
this.events[n].dispatchEvent(n, d);
},
destroy: function(n){
this.events.remove(n);
}
}
var EventController = new CustomEvent.EventController();


Here's how you would use it.


EventController.create("test", "Base");
EventController.addEventListener("test", myTest);

function myTest(evt){
alert('Event Name: '+evt.name);
}


Base is just the Basic custom event. Extend it to specify a unique data structure. Trigger the event with the following code:


EventController.dispatchEvent("test");


I still need to tweak the code little bit but so far its been very useful. Hope this helps someone else out.

Cheers,
Todd