kelvinluck.com

a stroke of luck

Shibuya and Sharify

Yesterday Adobe announced a new service called “Shibuya“. It’s “a monetization service for developers creating AIR applications”. This may sound familiar to anyone who knows Sharify – the service that I launched back in February which “allows you to easily monitize your Adobe® AIR™ application by turning it into a shareware application”.

My thoughts about this echo very closely those of Grant Skinner in his recent post “Thoughts on Adobe Squiggly & Developer Relations“. In one way I am glad that Adobe are stepping up to the plate and providing what I believe (from my own experiences and from the interest in Sharify) is a very useful and necessary service. But in another way I’m concerned that Adobe are competing with the very people they should be trying to empower – the users of their products.

A little history

As mentioned, Sharify was launched in February of this year under the name of shAIR. It received a fair amount of immediate attention – some of it from people inside Adobe and specifically from Robert Christensen, a senior product manager on Adobe AIR:

I wanted to write you a note and let you know that I’m excited about the shAIR framework that you are working on. Application monetization is a critically important area for AIR developers and I suspect quite a few developers will be leveraging your shAIR once you make it available

The only problem was that he felt that our choice of name infringed on the Abode AIR trademark so he asked if we would mind changing it. He acknowledged that this would involve some work for us and offered in exchange to support the launch of the renamed shAIR with blog posts and articles on the Adobe Developer Connection website. This wasn’t the first time Adobe had come down hard on people for using AIR in a domain name – it happened to freshairapps (see discussion here and here). AIRApps.net had an even worse experience wasting $15,000 sponsorship money for an Adobe MAX conference (as described by Edward Mansouri).

We considered our options carefully. Though we believed our choice of name didn’t infringe Adobe’s copyright (or at the very most it was a gray area) it was more important for us to maintain a good relationship with Adobe. Their offer to help with the promotion of our product was worth much more than the hassle of re-branding our (still very young) product. We made the necessary changes and I emailed Rob the news to be greeted by absolute silence. Previously he was replying to my emails within a day of receiving them. Now it took over 6 weeks and a few reminder emails until I got a response – the not very verbose “Confirming receipt of your email”!

My cynical side started to think that perhaps all Rob was interested in was getting me to change the name of the service. The promised help certainly never materialised. Maybe I should have been more proactive in chasing Adobe to promote Sharify but I opted to focus on improving my product. I was a little disheartened by the change in attitude but decided to give them the benefit of the doubt and assumed I could rely on their marketing support once Sharify was out of beta.

And then… Shibuya!

I’ve given the history just to make it clear that there were definitely people at relevant positions within Adobe who are were aware of the Sharify service (in addition to Rob I have also received correspondence from the Senior Product Manager on the Adobe AIR marketplace). It would seem to be at the very least polite to have contacted me before the announcement of Shibuya and told me that Adobe were working on something extremely similar. Instead, the first I heard was when somebody emailed me a link to an article on The Register.

As Grant notes in his post, it is not simply the case that somebody is competing with my product that upsets me. Sharify already has a competitor called Nitro LM which serves a similar purpose, though it is targeted at a different market (“the enterprise”). It is the fact that the competing company is the same company who is responsible for the platform that I am developing on.

I spent time creating a product which enhances Adobe’s platform and enables developers to make money using the platform. I imagine this leading to more developers spending their time creating AIR apps (as there is a potential payback) which would lead to more installs of the runtime which is presumably Adobe’s ultimate aim. By developing and releasing Shibuya Adobe are rendering the time I spent doing that to a large extent wasted. Which doesn’t encourage me to spend time building things to improve the ecosystem around Adobe’s products. It should also be a warning to other developers who are considering this, which can only damage the very ecosystem that Adobe should be trying to protect.

Another problem with Adobe deciding to tackle this problem is that they have the ability to make changes to the runtime itself. It is unclear from the Shibuya announcement whether this has happened in this case but I have logged feature requests with the AIR team for functionality which would have made Sharify more secure and easier to implement. I don’t know if Shibuya uses any features from an as yet unreleased runtime but if so it would seem that Adobe are not only competing with the people they should be helping but are competing with an unfair advantage!

The future

So – is this the end for Sharify? No! Not yet at least. Shibuya is not available yet and doesn’t have a release date that I can find. It seems that once available it will only allow purchasing from within the USA and Canada. And it appears to be tied in to one payment method (using the PayByCash payment provider) while Sharify allows developers to handle payment in any manner they choose. It is also unclear from the prerelease site if Adobe will charge for using Shibuya and if so, how much. And if Adobe have added features to the AIR runtime to help with the development of Shibuya then presumably these features will be available to other developers as well in which case we will be able leverage them to improve the security of Sharify.

However, until we know more about the final form of Shibuya it is hard justify spending additional development time on Sharify. We are committed to ensuring it continues to work for the members of the private beta who are currently using it but there are some exciting improvements in the pipeline which will have to be put on hold until we establish whether implementation would be a waste of time. We will also have to very carefully consider any other projects which might enhance the Flash Platform.

Update: This story was also covered on the register


Error installing plugins in Eclipse on OSX

I’ve run into this problem twice in the last couple of days while downloading and installing new versions of Eclipse and trying out different packages for PHP editing (PDT and Aptana Studio). First time I googled around I couldn’t find a solution and so had to figure it out myself. Second time I thought that maybe I should make a note of my solution as other people might run into it as well.

The problem shows itself with the following error message:

An internal error occurred during: "Computing size".
Incompatible profile file name. Expected format is {timestamp}.profile but was ._1248736262197.profile.

This happens when trying to install a new plugin through the “Check for updates” or “Install New Software” dialog. The problem is because of the hidden ._* files which are created by OS X inside the Eclipse directory. The solution is pretty easy – open up a terminal and:

cd /path/to/your/eclipse/folder
find . -iname '._*' -exec rm -rf {} \;

WARNING – running commands like this on your computer can cause problems. I have run exactly the command above on my machine with no problem but if you manage to break your computer following the above instructions then I take no responsibility! That said, as long as you correctly cd into the Eclipse directory and type/ copy the command correctly then nothing should go wrong!

Hope that helps someone else who runs into the problem!



Google maps for flash marker clustering

I’ve recently been working on a project which makes extensive use of the Google maps API for flash (more about that once it launches). One of the things that was necessary for this project was clustering of markers when they were too close together. To understand what I mean by this click the image below to check out the example:

Google Maps for Flash Clustering Screenshot

As you can see, the capital cities of the world are all displayed on the map as small red dots. I got the list of capital cities from here and converted them to XML for the example – note that some of them (e.g. Rome) appear to be slightly incorrectly positioned. If the cities are too close to each other for the current zoom level then they are clustered into larger red dots with numbers in the middle.

This has of course been done before (e.g. here and here) but the solutions didn’t work for my situation. The first is grid based (rather than distance based) which can give some strange results. And more importantly for my project I needed to use custom markers (for both the individual markers and the clusters) and that didn’t seem possible without changing the actual library code. And with the second solution the markers seem to “jiggle” as you drag the map and I wasn’t sure about whether the license permitted use in a commercial project.

So I found a post from Mika Tuupola. In it he explains the advantage of distance based (as opposed to grid based) clustering algorithms. He then provides some PHP sourcecode to implement distance based clustering.

I started off with a fairly straightforward port of the code from the article but I found that it needed to be optimised quite heavily so that it would work performantly in Flash (especially since it needs to re-calculate the clustering on every zoom change). My final Cluster class looked like this:

package com.kelvinluck.gmaps
{
   import com.google.maps.overlays.Marker;

   import flash.geom.Point;
   import flash.utils.Dictionary;

   /**
    * Distance based clustering solution for google maps markers.
    *
    * <p>Algorithm based on Mika Tuupola's "Introduction to Marker
    * Clustering With Google Maps" adapted for use in a dynamic
    * flash map.</p>
    *
    * @author Kelvin Luck
    * @see http://www.appelsiini.net/2008/11/introduction-to-marker-clustering-with-google-maps
    */

   public class Clusterer
   {
     
      public static const DEFAULT_CLUSTER_RADIUS:int = 25;

      private var _clusters:Array;
      public function get clusters():Array
      {
         if (_invalidated) {
            _clusters = calculateClusters();
            _invalidated = false;
         }
         return _clusters;
      }

      private var _markers:Array;
      public function set markers(value:Array):void
      {
         if (value != _markers) {
            _markers = value;
            _positionedMarkers = [];
            for each (var marker:Marker in value) {
               _positionedMarkers.push(new PositionedMarker(marker));
            }
            _invalidated = true;
         }
      }

      private var _zoom:int;
      public function set zoom(value:int):void
      {
         if (value != _zoom) {
            _zoom = value;
            _invalidated = true;
         }
      }

      private var _clusterRadius:int;
      public function set clusterRadius(value:int):void
      {
         if (value != _clusterRadius) {
            _clusterRadius = value;
            _invalidated = true;
         }
      }

      private var _invalidated:Boolean;
      private var _positionedMarkers:Array;

      public function Clusterer(markers:Array, zoom:int, clusterRadius:int = DEFAULT_CLUSTER_RADIUS)
      {
         this.markers = markers;
         _zoom = zoom;
         _clusterRadius = clusterRadius;
         _invalidated = true;
      }

      private function calculateClusters():Array
      {
         var positionedMarkers:Dictionary = new Dictionary();
         var positionedMarker:PositionedMarker;
         for each (positionedMarker in _positionedMarkers) {
            positionedMarkers[positionedMarker.id] = positionedMarker;
         }
         
         // Rather than taking a sqaure root and dividing by a power of 2 to calculate every distance we
         // do the calculation once here (backwards).
         var compareDistance:Number = Math.pow(_clusterRadius * Math.pow(2, 21 - _zoom), 2);
         
         var clusters:Array = [];
         var cluster:Array;
         var p1:Point;
         var p2:Point;
         var x:int;
         var y:int;
         var compareMarker:PositionedMarker;
         for each (positionedMarker in positionedMarkers) {
            if (positionedMarker == null) {
               continue;
            }
            positionedMarkers[positionedMarker.id] = null;
            cluster = [positionedMarker.marker];
            for each (compareMarker in positionedMarkers) {
               if (compareMarker == null) {
                  continue;
               }
               p1 = positionedMarker.point;
               p2 = compareMarker.point;
               x = p1.x - p2.x;
               y = p1.y - p2.y;
               if (x * x + y * y < compareDistance) {
                  cluster.push(compareMarker.marker);
                  positionedMarkers[compareMarker.id] = null;
               }
            }
            clusters.push(cluster);
         }
         return clusters;
      }
   }
}

import com.google.maps.LatLng;
import com.google.maps.overlays.Marker;

import flash.geom.Point;

internal class PositionedMarker
{

   public static const OFFSET:int = 268435456;
   public static const RADIUS:Number = OFFSET / Math.PI;
   
   // public properties are quicker than getters - speed is important here...
   public var position:LatLng;
   public var point:Point;

   private var _marker:Marker;
   public function get marker():Marker
   {
      return _marker;
   }

   private var _id:int;
   public function get id():int
   {
      return _id;
   }

   private static var globalId:int = 0;

   public function PositionedMarker(marker:Marker)
   {
      _marker = marker;
      _id = globalId++;
      position = marker.getLatLng();
     
      var o:int = OFFSET;
      var r:Number = RADIUS;
      var d:Number = Math.PI / 180;
      var x:int = Math.round(o + r * position.lng() * d);
      var lat:Number = position.lat();
      var y:int = Math.round(o - r * Math.log((1 + Math.sin(lat * d)) / (1 - Math.sin(lat * d))) / 2);
      point = new Point(x, y);
   }
}

You can download the class and the code for the example from it’s github repository. Note that the Clusterer class is all that you need to use – the rest of the classes are just for the sake of the example. I hope it’s useful – if you make anything cool with it then please post in the comments.



jQuery styleswitch – now with toggle!

About three years ago I posted my stylesheet switcher switcher here. It was the first bit of programming I ever did using jQuery. Surprisingly enough it is still one of the most popular posts on my blog and I still get quite frequent questions about it.

One of the most popular questions is “how can you make the styleswitcher toggle between available stylesheets?”. So I just put together a little example of how to do this. While doing it I noticed that the original code wasn’t really that extensible which is probably why people were always asking that question! So I ended up rewriting the code a bit as well as putting together the new example. You can find it all here.



Hello Adobe feeds!

I’ve just found out that my blog is now aggregated on Adobe Feeds. So I thought I would do a quick post to say hello (hello!) and to link to some of my popular or interesting old content:

  • The launch of Sharify – a service to allow developers to easily add shareware features to their AIR applications so that they can sell them
  • jScrollPane - my plugin to allow you to create cross browser custom scrollbars on any HTML element.
  • Some audio programming experiments in Flash Player 10.
  • Some experimental javascript – playing with jQuery and Raphael JS to use javascript for fun and experimentation rather than serious “work”.
  • My jQuery datepicker plugin.
  • My experiments with tweetcoding – seeing what can be made in 140 characters of actionscript.
  • Some experiments with Papervision.
  • Flashr – my old as2 wrapper for the Flickr API.

I hope some of that is interesting to people. Moving forwards, I hope to be making many more posts about Flash, Flex, Javascript, AIR and more. Recently I’ve been programming quite a lot of c sharp .net too and I’ll to write up some of my thoughts about that from the point of view of someone coming from languages like actionscript and javascript. Plus I want to finish the bunch of half done papervision and audio experiments I have sitting around!



Custom 404 error messages with CodeIgniter

CodeIgniter is an “open source PHP web application framework that helps you write kick ass PHP programs”. It’s a nice MVC framework which makes writing PHP bearable by enforcing some organisation and structure on your project. I’ve used it a few times, most recently when I built the Sharify website.

CodeIgniter provides helpful templates for certain error states of your application including a 404 Page not found. And you can edit these templates to suit your needs. Unfortunately these templates are static view code and in an error situation you can’t easily query a database or access most of the functionality of CodeIgniter. This is quite limiting – in my case I couldn’t render my error view into the standard template view I use on the rest of the site. And so I came up with a bit of a hack to make a 404 error behave like any other page request.

I started by creating a method on my default controller (home) called “page_not_found”. Inside this method I generate my error page (by inserting the relevant view into my main template view as I do throughout the rest of the site). Since this is a normal controller method I can interact with any models and views I desire (for example if I needed to grab stuff from the database to build my navigation I could) to produce my output page.

Then I need to override the CI_Exceptions class. So I create the file MY_Exceptions.php inside CI_DIR/application/libraries (where CI_DIR is the path to your codeigniter system folder). Inside that file I override the show_404 method and instead of simply outputting a view I use cURL to request the page I previously set up. I also POST the originally requested URI along with this request which allows me to output it on the generated page if desired.

The code looks like this:

class MY_Exceptions extends CI_Exceptions {
   
   function show_404($page = '')
   {
      $code = '404';
      $text = 'Page not found';
     
      $server_protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : FALSE;
   
      if (substr(php_sapi_name(), 0, 3) == 'cgi')
      {
         header("Status: {$code} {$text}", TRUE);
      }
      elseif ($server_protocol == 'HTTP/1.1' OR $server_protocol == 'HTTP/1.0')
      {
         header($server_protocol." {$code} {$text}", TRUE, $code);
      }
      else
      {
         header("HTTP/1.1 {$code} {$text}", TRUE, $code);
      }
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, 'http://' . $_SERVER['HTTP_HOST'] .'/home/page_not_found/');
      curl_setopt($ch, CURLOPT_HEADER, 0);
      curl_setopt($ch, CURLOPT_POST, 1);
      curl_setopt($ch, CURLOPT_POSTFIELDS, 'originalURL=' . urlencode($_SERVER['REQUEST_URI']));
      curl_ex ec($ch); // WordPress won't let me post the word e x e c - remove the space in the previous code to make it run...
      curl_close($ch);
   }
}

As you can see, I make sure that the correct HTTP header is outputted and then I pass through the page loaded from my “page_not_found” method on my default “home” controller. This means if you visit a non existent page on the Sharify site (like this one) then you get a pretty page which looks like the rest of the site and tries to help you find what you are looking for.

In a perfect world there would be a cleaner way to do this within the CodeIgniter framework but I did some searching when I started building the site and I couldn’t find any clean solutions. There were a couple of other suggestions on the forums but they seemed to involve editing more files which shouldn’t be related to error handling. While I don’t like the hacky nature of the extra curl request I think this solution is relatively simple and clean.



ColorTransform explorer

I recently worked on a project where the client was providing designs for image manipulations which were being done with a ColorTransform in flash. After a couple of bits of feedback along the lines of “…can the blues have more yellows in them at times…” I decided there must be a better way.

So I built the client a tool which allowed them to fiddle with parameters to ColorTransform and send me the numbers. It’s in the same vein as the Flex style explorer but much simpler. So simple in fact that it is hardly worth posting but I was surprised that I couldn’t find something similar on google so I thought I would save someone else the half hour it took to put together…

Click on the picture below to try it out or you can download the source here.



Flex bug quashing

Last weekend I joined in on the first ever Flex Bug Quash. What is a bug quash?

An event where the community comes together with one goal in mind… To quash as many bugs in one day as humanly possible. Don’t just complain, do something about it.

The idea was to allow the commuity to get involved and contribute bug fixes for the Flex framework back to Adobe. This is open source in action! As someone who has spent a fair amount of time cursing the Flex framework and it’s bugs I thought that I should get involved. It also seemed like a good opportunity to network with other Flex developers – although this aspect would have definitely been better if I was close enough to attend in person in Seattle (or one of the other hubs). At least I was in the correct timezone – some developers in Europe, Asia and Australia worked through the night!

After checking out a working copy of the entire 3.x branch of the Flex SDK from the repository I could work on getting my environment set up. The SDK has Flex Builder library projects for the framework.swc, airframework.swc and rpc.swc set up. So I set up a “BugQuash” project and linked it into the framework library project. This means I was basically monkey patching the framework.swc with the latest sourcecode from svn – including any changes I made. This allowed me to easily tackle bugs.

There was a list of bugs on the Adobe bug tracker which were marked as “SDK Community Bug Fix Candidates” – these were bugs which were considered good candidates for the community to tackle. I think this meant that they hadn’t been judged important enough to be placed on an Adobe engineer’s workload and they weren’t considered too hard or dangerous for the community to have a go at. I had a quick flick through the issues on this list and picked the first one which looked like a nice quick and simple fix.

My first bug took a little longer than I expected to fix. While it was quite simple I wanted to make sure that I was doing things correctly and putting my code in the correct places. It’s harder than simply writing code as you have to make sure you think about how any other developer might use (or abuse) the code you write. Once my code was done I generated a patch file – this was easily done with Tortoise SVN. Having signed the relevant legal documents I could then simply attach the patch to the relevant ticket in the bug tracking system.

Once the patch was on the system it needed to be reviewed by a member of the community. Chris Hill kindly volunterred and checked my code and added some extra test cases. Once this was done the bug went into a queue waiting for official Adobe code review. And once that was done my patch was given the go-ahead and committed back to the framework repository. It was very satisfying when my bug was approved and my patch was checked into SVN. I’m genuinely proud that some of my code is in the Flex framework and that I’ve added some useful functionality. And I’m fairly certain that this bug fix will save some cursing for developers when the next point release of the framework comes out!

I then picked up another bug to look at and also successfully submitted a patch for it. As a prize (along with having hopefully helped to make Flex a better place for developers) I get to display this little badge:

Overall I found the event to be very rewarding. More important than the bugs I fixed on the day is the fact that I now feel that I can contribute to the Flex framework. I’m not using Flex too much at the moment but I know that when I was using it day in, day out I would often come up against bugs. And often the fix was simple to implement. But if the fix required monkey patching or otherwise modifying the framework it wouldn’t be allowed in the project (as the project needs to build with a default Flex framework) and I’d end up using an ugly workaround instead.

Now that I know I can submit patches to Adobe and that those patches can be accepted into the framework (obviously dependant on their quality and any side effects) I am much more likely to do so. And if there are a number of similarily empowered developers using Flex day in, day out then we should see a vast reduction in the number of bugs in the Flex framework. So I think that the inaugural flex bug quash was a great success and I look forward to using a more reliable flex framework in the future.



Not my mother’s javascript!

Last week Google launched Chrome Experiments – a set of javascript experiments – to spread the word about their browser, Chrome. One of the major selling points of Chrome (can something free have selling points?) is V8 – it’s new and optimised javascript engine. I guess the idea is that by sponsoring a site of cool experimental stuff they can virally drive people to download and play with their product. And it worked on me! When some of the experiments ran a bit jerkily on my Firefox I decided to download it and give it a go.

Most of the javascript I write is fairly serious with a strong requirement for cross browser compatibility and graceful degradation, but the experiments inspired me. Having recently had some fun with tweetcoding (where you ignore every type of best practise to squeeze “something cool” out of 140 characters of actionscript 3) I felt like trying the same sort of thing with javascript.

For my first attempt I ported my first ever as3 experiment. Click on the image below to try “boingPic” which will split an image of your choice into 100 squares each of which is scared of the mouse (or view it in it’s own window if you want to boing larger images).

boingpic

Then I was reading an interview with Toxi about the creation of Social Collider (one of the chrome experiments). In it he mentioned Raphaël – a javascript library which uses the SVG W3C Recommendation and VML as a base for generating vector graphics.

I decided to check it out and found out that it’s a really great library which gave me the freedom to easily experiment with graphical stuff in javascript. I had loads of fun playing around with it – you can see some of my experiments below. They do appear to run best in Chrome so I’d recommend using that (looks like google’s ploy is working!) or at least Safari (FF doesn’t seem to render the width of paths but webkit does). [Thanks to Dmitri for pointing out the error in my code, it now works in FF too]

  • test3
  • test6
  • test7
  • test8
  • test12
  • test13
  • test17
  • test18
  • test19
  • test20

Most of my experiments were inspired by my previous tweetcoding entries. Feel free to view source on any of them to see how they are done – there is nothing at all complex going on. Big thanks to all of the chrome experiments for getting me to start playing with this and to Raphaël for the vector js goodness – I’m hoping to find more time to do some more complex experiments in the future!



shAIR is now Sharify

Not too long ago I posted about the launch of shAIR – a service which allows developers to easily add shareware functionality to their Adobe AIR applications.

Shortly after the launch we were approached by representatives of Adobe informing us that our choice of name infringed on their trademark. To cut a long story short, while we weren’t convinced that Adobe’s claim was fair, we decided to change the name of the service.

So I take great pleasure in introducing you to Sharify. Check out the website to find out just how easy it is to convert your AIR application into a shareware application. You just need to set up the relevant information on sharify.it and integrate a small swc file. Then you can sell your application to your users and Shairfy will ensure that only people who have purchased a license can use it (after an optional trial period).

The service is still in private beta but if you sign up on the site and include a good description of the application you’ve built or are building then we will be happy to invite you to try it out. What are you waiting for? It’s time to Sharify it!

http://www.sharify.it/