Postman Collection to HTML (node script)

If you use the excellent Postman for testing and developing your APIs (and if you don’t yet, please give it a try!) you may find this little node script helpful when generating documentation.

It simply converts your downloaded Postman collection file to HTML (with tables) for inserting into documentation or sharing with a 3rd party developer. The Postman collection is perfect for sharing with developers as it remains close to “live documentation”, but sometimes you need a more readable form.

https://github.com/richardleggett/postman2html

Dynamic Application Cache Manifest for PHP

Earlier today Paulo Fierro uploaded an example of how to do a dynamic application cache manifest for HTML5 web apps using Ruby. A cache manifest is a text file that browsers look for in order to determine which files to store locally on the device, this…

Earlier today Paulo Fierro blogged an example of how to build a dynamic application cache manifest for HTML5 web apps using Ruby.

A cache manifest is a text file that browsers look for in order to determine which files to store locally on the device, this lets you open the site/app offline, great for web apps (on iOS bookmarking a site to the home screen also let’s you specify an icon and removes browser chrome). Creating a cache manifest dynamically means that you don’t have to worry about modifying a text file every time you add or remove a file from the app.

This prompted me to upload my PHP version that works pretty much in the same way. I built it for an iPad web app that needed to run completely offline collecting peoples details at a car show (it later synced data with a server when it found a connection). It’s pretty basic, it just creates an MD5 of all the files in a directory (apart from excluded files, including itself!), so that when one is changed, either the content or the name, the MD5 value changes and that results in the contents of the manifest changing, causing the browser to re-evaluate it.

Below is the dynamic manifest, let’s call it “cache.manifest.php”:


<?php 
	header("Cache-Control: max-age=0, no-cache, no-store, must-revalidate");
	header("Pragma: no-cache");
	header("Expires: Wed, 11 Jan 1984 05:00:00 GMT");
	header('Content-type: text/cache-manifest'); 
	
	$hashes = "";
	
	function printFiles( $path = '.', $level = 0 ){ 
		global $hashes;
	    $ignore = array('.', '..','.htaccess','cache.manifest.php','index.html','submit.php', "video.mp4");  

	    $dh = @opendir( $path ); 

	    while( false !== ( $file = readdir( $dh ) ) ){ 
	        if( !in_array( $file, $ignore ) ){ 
	            if( is_dir( "$path/$file" ) ){ 
	                printFiles( "$path/$file", ($level+1) ); 
	            } else { 
					$hashes .= md5_file("$path/$file");
	                echo $path."/".$file."n";
	            } 
	        } 
	    } 

	    closedir( $dh ); 
	}
?>
CACHE MANIFEST
<?php 
printFiles('.');
// version hash changes automatically when files are modified
echo "#VersionHash: " . md5($hashes) . "n";
?>

NETWORK:
./submit.php
./video.mp4

FALLBACK:
./video.mp4 ./images/offline.jpg
./images/video.jpg ./images/offline.jpg

Remember that cache space is extremely limited. I think it was about 5mb on the iPad first gen. If you need more space you’ll have to use local SQLLite (perhaps storing blobs) and request more DB space from the user.

So you probably don’t want to be including things like video files, you also don’t want to cache the output of dynamic server-side scripts. This is what the NETWORK and FALLBACK portions of the manifest are used for. You can force the browser to only look to the network for certain files, and also provide fallbacks for files it won’t find offline (in the case above, it shows an offline image in place of the video).

To make the browser look for the manifest, you just add the manifest attribute to the HTML tag:

<html manifest="cache.manifest.php">

Now when it comes to actually forcing your client app to check for updates, the following JavaScript should provide some insights. Sorry it’s a bit rough and ready, but it should illustrate how you might invoke an update:


var cacheStatus = getCacheStatus(window.applicationCache.status);
	console.log("App cache status: " + cacheStatus); 
	
	var appCachedHandler = function () {
		console.log("AppCache cached");
		dialog.dialog("close");
	}
	var updateReadyHandler = function() {
		console.log("AppCache update ready");
		
		$("#versionImg").attr("src", src="images/update_available.png");
		$("#versionImg").css("visibility", "visible");
		
		dialog.dialog("close");
			
		if(	!isSyncing && confirm("Update available, update now?") ) {
			window.applicationCache.update();
			window.applicationCache.swapCache();
			window.location.reload(true);
		}
	}
	var downloadingCacheHandler = function() {
		console.log("AppCache downloading...");
		dialog.dialog({modal: true, title: 'Downloading update...'});
			
		$("#versionImg").attr("src", src="images/loading_small.gif");
		$("#versionImg").css("visibility", "visible");
	}
	var cacheErrorHandler = function(obj) {
		console.log("AppCache error " + obj);
		dialog.dialog({modal: true, title: 'Cache error:'+obj});
	}
	window.applicationCache.addEventListener('cached', appCachedHandler, false);
	window.applicationCache.addEventListener('updateready', updateReadyHandler, false);
	window.applicationCache.addEventListener('downloading', downloadingCacheHandler, false);
	window.applicationCache.addEventListener('onerror', cacheErrorHandler, false);

Chrome Web Store: Why Online Apps?

Yesterday Google unveiled the Chrome Web Store. In a nutshell this is an App Store for the Chrome browser and a critical component in the upcoming Chrome OS. The Chrome browser is found on all major desktop operating systems, on the enormous numbers of A…

Yesterday Google unveiled the Chrome Web Store. In a nutshell this is an App Store for the Chrome browser and a critical component in the upcoming Chrome OS. The Chrome browser is found on all major desktop operating systems, on the enormous numbers of Android phones and tablets, and the new TVs and set top boxes from companies like Sony, Logitech and reportedly the biggest of them all, Samsung. Chrome OS is a desktop operating system replacement designed to operate entirely in the cloud, using web technologies, with almost negligible startup times for the instant-on, always connected generation. Chrome touts automatic synchronisation of everything from bookmarks, to auto-fill info and passwords, and preferences.

How do regular people use computers?

I must first apologise for the use of the word “regular” to differentiate users here, but the truth is there are a very small number power users; people that are even remotely interested in how their operating system works and how it can be modified. We manually install software onto a computer because it provides a fast experience, utilising the full power of the machine. The other camp includes everyone else; using Office, the Web (Facebook, webmail), maybe intranet applications at work, and of course shopping and having fun at home. These camps do overlap, but the key point here is the latter camp is the vast majority, and we must always look at technology from their perspective in order to see the bigger shifts.

In a previous post regarding web technologies I proposed that nearly all applications would be web-based within 5 years, I’m an eternal optimist so any numbers I give always need seasoning with a pinch of salt. For a professional programmer or designer this is something really hard to swallow, and the “why a web app store” comments are already proliferating the twitter-sphere. I’m always observing how my group of friends use computers, some have more skill than others, but they rarely install desktop applications any more and would appear to prefer not to have to as they feel comfortable having already learned how to live in browser-land.

The word computer in the heading is a little outdated, it’s already clear to most that computers are, for the most part, being used in the form of mobile phones, tablets and other devices, not laptops and desktops. This is also key, the inevitable decline of the laptop and the desktop, those specialist and indirect machines, from the computing landscape.

Native and offline, the 90% rule

Traditionally we’ve had to install applications to specific operating systems to make use of certain features, certain hardware. One example would be the ability to write files or a database to disk, these might contain a user’s data from several sessions – this feature alone is the decider for a large percentage of mobile apps. Another might be to make use of the graphics card to display massive amounts of 3D polygons for a game. Finally I think notifications are worth mentioning. I’ve had issues with online messengers, twitter clients, apps that are buried in a tab, unable to do more than flash the title bar to let you know *something’s happening!*.

The change that’s occurring is that new web technologies are bringing some of these native-only features to web developers, through HTML5 and Flash, even for the problem of notifications. This means that instead of only being able to produce 50% of the apps you could on desktop, you can now produce 90% and growing.

I like to call this the 90% rule. The added bonus is that the other 10% is typically what our “power users” need, so in effect it’s pretty much 100% of what our “regular” users need. That’s the critical mass required to make the shift away from traditional desktop operating systems, onto something new with many new benefits.

Benefits

There are potential pitfalls and challenges (security, limited connectivity), but also benefits associated with moving entirely to the cloud. I’d like to pick out a few key benefits over traditional computing models.

Backup

Fire, burglary, lost property, batteries a’sploding. In some cases you can lose all your devices in one foul swoop. You backup your computer right? I backup to Timemachine continually, I run a weekly secondary hard-drive backup, I use SVN for all my projects, and I use Dropbox with an encrypted DMG to make sure I always have some important information to hand. Regular computer users do not do this, then inevitably hard drives crash, drinks get spilled, I can’t even begin to count the number of times a non-geek, and even plenty of less paranoid geeks have simply lost everything bar the postage stamp sized photos they uploaded to Facebook. iTunes doesn’t let you re-download music anymore, you really have to back up. This was easier to deal with when people had physical backups, real photos, CDs, real letters, but it’s increasingly becoming an issue.

The immediate win here, admittedly at the cost of a trust relationship, comes from having all your stuff backed up by professionals with backups of their own across the globe. It would take a fairly major worldwide catastrophe before both the server and your local copies were destroyed.

Updates

Probably one of the original reasons apps started moving to web was that you can guarantee your users are all running the same version. From their perspective they don’t have to install anything, and they get updates and bug-fixes with zero effort. No checking for updates and waiting, no updater apps popping up every Wednesday because they changed the kerning in iTunes.

Migration Between Devices

With a great many devices at our disposal; the phones in our pockets, the tablet on the table, the laptop under the sofa, the PC in the back room, the TV in the living room and the watch on our wrist, we have so many overlapping choices in what we use to go online and do things. If each of these runs its own operating system, operates its own App Store, its own way of installing applications and games, having to pay for a copy of an app that only runs on one specific device you may lose or replace, we are simply limiting ourselves.

One of the things a unified web-based operating system does is turn upside-down the notion that you’re going to show someone that photo which is on your INSERT_DEVICE, instead you pick up any device and off you go. Ubiquitous computing, ultimate convenience.

This also makes sense when the inevitable happens, and that new shiny device comes out, you migrate to a new device. The experience on something like an Android phone can be pretty good, should you decide not to switch to another OS. You turn it on, enter your username and password, and all of your settings and apps are immediately re-downloaded. Apple provide a backup mechanism using a cable and desktop/laptop computer running a copy of iTunes (though that doesn’t solve the problem of a house fire where you lose both devices).

Chrome Web Store

Unfortunately Google have done the usual technology-driven thing and put out a rather functional experience for later finessing, rather than launching with a polished user experience as might another user-focused company, but it’s not too bad, certainly better than the Android market even in its present state.

So what do you think to Chrome Web Store and Chrome OS? Comments welcome as always.

ASDoc (via ANT) When Using Conditional Compilation

This relates to using ASDoc to generate documentation for a Flex or AIR project that uses conditional compilation (read more and see tip at end).Conditional Compilation Just for some background, the Flex compiler supports what is known as conditi…

This relates to using ASDoc to generate documentation for a Flex or AIR project that uses conditional compilation (read more and see tip at end).

Conditional Compilation

Just for some background, the Flex compiler supports what is known as conditional compilation. This allows you to set one or more constants via a compiler flag which is then made accessible from anywhere in your code. This may be a boolean, a string, a number and so on. Within your code you can read this value and switch between using certain methods, or execute blocks of code depending on the value it contains.

Continue reading “ASDoc (via ANT) When Using Conditional Compilation”

Google Chrome OS

Google are reportedly planning to release an operating system based on their Chrome runtime/browser. If it was anyone else it would probably warrant no interest. The concept itself is not new, but when you consider the timing, the rise of RIAs, Google’s…

Google are reportedly planning to release an operating system based on their Chrome runtime/browser. If it was anyone else it would probably warrant no interest. The concept itself is not new, but when you consider the timing, the rise of RIAs, Google’s vast offerings and ability to create the future, it deserves a lot more thought.

Update: They have now announced it.
Continue reading “Google Chrome OS”

EncryptedLocalStore processErrorCode() in AIR

I’ve just migrated from an old MacBook Pro to a new one using Apple’s Migration Assistant. I then thought it’d be a great idea to perform some manual cleanup and accidentally deleted a keychain (in KeyChain Access) which was used by an AIR app I am curre…

I’ve just migrated from an old MacBook Pro to a new one using Apple’s Migration Assistant. I then thought it’d be a great idea to perform some manual cleanup and accidentally deleted a keychain (in KeyChain Access) which was used by an AIR app I am currently developing.

After doing this I started getting the following error when running my app, as soon as it accessed EncryptedLocalStore:

Error: general internal error
at flash.data::EncryptedLocalStore$/processErrorCode()
at flash.data::EncryptedLocalStore$/getItem()

To prevent this error you just need to delete the relevant folders in:

~/Library/Application Support/Adobe/AIR/ELS/

Where ~ represents your user folder. I’m not sure what the relevant folder is on Windows, probably something similar involving the user’s Application Data folder, but if someone knows for sure please feel free to paste in the comments.

Bullet Point Characters Incorrect for Word Documents in OpenOffice Mac

Just a very small post here because I had trouble finding a solution myself. Users of OpenOffice for the Mac may experience odd-looking bullet point characters when opening and saving MS Word .doc files. The character looks like a W inside a box.Anyw…

Just a very small post here because I had trouble finding a solution myself. Users of OpenOffice for the Mac may experience odd-looking bullet point characters when opening and saving MS Word .doc files. The character looks like a W inside a box.

Anyway, the problem is due to MS Office not encoding the character correctly when saving the file, but the temporary solution is to use OpenOffice’s Font Replacement feature (see Preferences), to replace “Symbol” with “OpenSymbol”.

Let’s hope there’s some resolution in future, my guess is that the open document formats will just see this issue disappear in time. Here’s a thread that explains the problem, and the solution, in more depth:

http://user.services.openoffice.org/en/forum/viewtopic.php?f=17&t=10846

Filtering Hierachical Data in Flex using ITreeDataDescriptor

This post describes how to filter data for use with any component that displays hierarchical data, such as the Tree, AdvancedDataGrid, or your own custom component. For the purpose of the post I’ll just consider the Tree, but the same technique applies t…

This post describes how to filter data for use with any component that displays hierarchical data, such as the Tree, AdvancedDataGrid, or your own custom component. For the purpose of the post I’ll just consider the Tree, but the same technique applies to the others.

Background

Suppose I have constructed a “Library” of Folder and Leaf nodes and I want to display that in a Tree. Each Folder node has an ArrayCollection called “children” which contains any child Folders and/or Leaf nodes.

So our classes may resemble something like this (I’ve kept things extremely simple for illustration purposes):
Continue reading “Filtering Hierachical Data in Flex using ITreeDataDescriptor”

Loading SWFs into AIR 1.5.X and LoaderInfo.sharedEvents

Today I had a bit of a nightmare with regards to loading SWFs into AIR. Specifically, I am loading my SWFs from somewhere inside app-storage://, and those SWFs use Flash CS4 UI components. These components extend UIComponent which accesses the stage obje…

Today I had a bit of a nightmare with regards to loading SWFs into AIR. Specifically, I am loading my SWFs from somewhere inside app-storage://, and those SWFs use Flash CS4 UI components. These components extend UIComponent which accesses the stage object. When you attempt to load and add this child SWF to the display list of your AIR app, it generates a SecurityErrorEvent which stops things, dead.

The AIR app owns the stage object, there is only one Stage instance, and depending on what security sandbox the content SWF is loaded into, the child SWF is not allowed access to that stage because it could run amok.

The problem is, when you load a SWF file in AIR, it’ll be run in one of 5 security sandboxes, you can trace Security.sandboxType to see which. These range from the full-access “application” sandbox when loading from the un-modifiable app:// directory, to “local-with-file/network” when loading from app-storage://, to the “remote” sandbox when loading from a server. The latter allows you to use Security.allowDomain() and cross-domain policy files to exert some control as you would in web-based Flash. I won’t go into the exact details of all 5 types here, Adobe have a good article on the sandboxes here.

Either way, I needed to load SWFs from app-storage:// as this is where my application downloads content to, and this content may refer to stage, simply by using Flash CS4 UI Components. Unfortunately there doesn’t seem to be a way to use Loader/SWFLoader/Image to load a SWF from this directory and give it the relevant trust; no amount of tweaking LoaderContexts or ApplicationDomains seemed to allow this. The problem is well documented online, but the solution was hard to come by.

It turns out that you can use a URLLoader to load the raw binary data for a SWF, and then use Loader.loadBytes() or SWFLoader.load(bytes) to bypass this restriction. Word of warning: this is NOT recommended unless you have full control over where your SWFs are coming from, you are effectively allowing arbitrary code to be run within your application with full access to the file system etc.

Below I show a code snippet that illustrates the main points, I’m missing out the rest of the class where I define the members, import classes etc as that’s probably quite obvious.


public function TestLoadBytes()
{
  urlLoader = new URLLoader();
  urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
  urlLoader.addEventListener(Event.COMPLETE, urlLoaderCompleteHandler, false, 0, true);
  urlLoader.addEventListener(IOErrorEvent.IO_ERROR, urlLoaderIOErrorHandler, false, 0, true);
  urlLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, urlLoaderHttpStatusHandler, false, 0, true);
  urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, urlLoaderSecurityErrorHandler, false, 0, true);
			
  swfLoader = new Loader();
  swfLoader.contentLoaderInfo.addEventListener(Event.INIT, animLoadCompleteHandler, false, 0, true);

  urlLoader.load(new URLRequest("app-storage://path/to/file.swf"));
}

protected function urlLoaderCompleteHandler(event:Event):void
{
  var lc:LoaderContext = new LoaderContext(false, null);
  lc.allowLoadBytesCodeExecution = true;
			
  swfLoader.loadBytes(urlLoader.data, lc);
}

You may notice here I’m also setting “allowLoadBytesCodeExecution” on the LoaderContext for the URLLoader. This is to enable ActionScript execution in the loaded SWF. Again, I should emphasise the warning, but the only other workaround I’m aware of is to use a HTMLControl to display your loaded SWF which allows you to specify a sandbox and also gives that SWF its own Stage, but I couldn’t face running a load of HTMLControls that for the sake of getting stage access in a child SWF.

If you don’t have 100% control over the SWFs you are loading you can put in place validation checks and measures to increase security. There’s a good discussion of this in the comments over at Ethan Malasky’s blog.

So far I haven’t mentioned how to communicate with our newly loaded SWFs… this is where AIR differs from the web Flash Player. The LoaderInfo class gains a “sharedEvents” EventDispatcher instance, which can be used to dispatch events between the two sandboxes. There’s also a mechanism to call functions between the two (similar to LocalConnection), that can be found in LoaderInfo.parentSandboxBridge and LoaderInfo.childSandboxBridge properties respectively.

Again the docs provide a good rundown, even though they are geared towards using the JavaScript/HTML techniques, the classes and techniques remain the same for AS3/Flash. But here’s a quick sample on how to listen to events using the sharedEvents dispatcher object.

In the parent SWF we listen to the Event.COMPLETE event for a SWFLoader instance:


protected function swfLoaderCompleteHandler(event:Event):void
{
  swfLoader.contentLoaderInfo.sharedEvents.addEventListener(MyEvent.SOME_EVENT, someEventHandler, false, 0, true);			
}

In the SWF being loaded, we dispatch events in a similar way:


function someClickHandler(event:MouseEvent):void
{
  loaderInfo.sharedEvents.dispatchEvent(new MyEvent(MyEvent.SOME_EVENT, "SomeParam", someFuncRef, true));
}

I haven’t covered the use of the parent/childSandbox bridge objects which can be used to directly expose and call methods because you can achieve much the same using this sharedEvents approach in a more decoupled way. For example the Event you are dispatching can contain a “callback” function reference that the parent SWF can call when an asyncronous operation has completed.