Caps lock breaking keyboard shortcuts handling in Adobe Air

Hello everybody, I’m Florian and currently the newest member of the balsamiq team. So what is my job here? I hunt bugs and add automated tests so once bugs are eradicated we do not run into them again.

Today I would like to discuss an ancient bug. Certain keyboard shortcuts were disabled when caps lock was activated. Instead of saving or exporting your mockups as png nothing happened at all. The bug occured on Windows and Linux even though Windows and Mac are handled in the same way and Linux had its own solution.

So what did we do and what did we do wrong?

At this point I want to dig a bit deeper into technical details of the Flex API of the KeyboardEvent. The KeyboardEvent has several nice public properties which are set on the basis of the keys you press. These are:
• keyCode which is the numeric value of the key pressed
• shiftKey is a Boolean which tells us if shift is pressed, likewise
• altKey for alt
• controlKey for control by Linux and Windows
• commandKey by Mac
• and now the bad bad charCode which is the computed charCode by the all the keys pressed above.

So why is the charCode the baddy? Because it is affected by caps lock on Linux and Windows! So if your key handler works on the basis of the charCode and checks if a key modifier has been pressed you might end up either in a keyboard shortcut which should not be triggered, or with no result at all.

Windows and Mac

For Windows and Mac OS we used the nice NativeMenu from Flex.

We use the NativeMenu and the NativeMenuItems to add all the entries you see in the menu. NativeMenuItem is an entry e.g. “Save As” and in our case it should listen to the key combination "ctrl + shift + s". To create this "Save As" item we use following code sniplet:
var item:NativeMenuItem = new NativeMenuItem(“Save As”);
item.name = “saveas”;
item.keyEquivalent = “S”;
item.mnemonicIndex = 5;

This works great on Windows until we hit caps lock. Before I tell you why I want to refer to a blog post of Brooks Andrus. He added another line to the item above:
item.keyEquivalentModifiers = Keyboard.SHIFT
This meant that he had to have caps lock on to trigger the shortcut.

The reason is the that the NativeMenu and the NativeMenuItems work with the charCode. As we know the charCode is affected by caps lock on Windows. Though it is interesting that the charCode stays unaffected by Mac, so we do not need a special handling here.

Now how do we solve this issue on Windows? The NativeMenu only bubbles the event up if a listener triggers and even if it would still bubble it up the select event has absolutely no knowledge any more of which keys were pressed.

This is how we solved it:
We added a listener in the creation of the menu for a KeyboardEvent.KEY_UP.
And this is the function we call:
protected var _capsLockOn:String;
//Only used on Windows
protected function onKeyUp(p_evt:KeyboardEvent = null):void
{
trace("onKeyUp "+Keyboard.capsLock);
var newCapsLock:String = (Keyboard.capsLock) ? "ON" : "OFF"
if (_capsLockOn == null || newCapsLock != _capsLockOn) {
_capsLockOn = newCapsLock;
Application.application.stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
if (_capsLockOn == "ON") {
Application.application.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
}
}
}

In onKeyDown we again handle all the events that should have been handled in the NativeMenu.

Linux

For Linux we wrote our own menu. We designed it as we wanted, added all the items and added event listeners to handle keyboard events for specific item. The event handler worked with the charCode.

So for Linux the solution is straightforward. Instead of mapping just to the charCode we map to the lower case of the charCode and check if shift is pressed. It would probably be even better to map to the keyCode and the key modifiers.

So the mystery is solved why caps lock disables shortcuts. We have learned our lesson here.

I hope this helps a lot of you to solve the problem of shortcut issues vanishing when caps lock is pressed.

(P.S. If anybody knows how to simulate a keyboard event so the NativeMenu triggers please share this information with me. I want to add some Unit Tests for this. (Yes, I know that is no longer unit level!))

What are the steps to do a Balsamiq Mockups release?

We do a lot of releases at Balsamiq.

After all the code is in and all the devs and testers give the build the go ahead, what are the steps to get the new release out the door?

In this video you see Peldi going through the steps for this release.

The video is sped up 2x, and only minimally edited. Grab a cup of coffee, go full screen, sit back and enjoy! :)

If you see something we could improve, let us know in the comments below, we're all ears! :)

Music credits: songs by "The Bird and The Bee", from their excellent "Ray Guns Are Not Just the Future" album.

Zero-downtime server updates with HTTPS, Tomcat, Nginx and Amazon Load Balancer (ELB)

Hi all,
it is strange for me to write in a tech blog not directly related to coding but you know, you never stop learning here at Balsamiq.

I will describe our recent experience setting up a load balancer with SSL on Amazon Web Services. Our goal was to achieve zero down time during upgrades for the server running our internal back-office webapp. We wanted also to redirect all http traffic to https to enforce encryption. It was not trivial, but Peldi and Luis did a great work!!

One of our webapp tasks is to listen to incoming transactions posted by our online seller and store them in our database. It's based on grails and is running on an Amazon EC2 instance. Every day we develop and release little new features and is quite a problem when we upgrade our server because incoming transactions will be lost while it is down for maintenance...

Initial setup

 

We needed a solution that makes upgrading our webapp simple and reduces downtime to zero! We wanted also to keep the ability to redirect http traffic to https like in our single server setup.
So, let's go for it using Amazon Services!

ELB setup

The first step is to setup an Amazon Elastic Load Balancer. Really easy using the Amazon Management Console. We want our load balancer to receive all incoming traffic on ports 80 and 443 and to simply forward it to the same ports on our instances, like this:

Since the load balancer will handle SSL, we had to provide a certificate. If you already uploaded your certificate to Amazon, it will appear in a drop down list for you to choose, alternatively you will have to paste the certificate and the key issued by your certificate authority in the corresponding text boxes. Do not forget (like I did!!) to add also the chain certificate. Note that if you want to modify the certificate after your ELB has been created you can use command line tools like described here (we used a certificate issued by godaddy with no problems).

Next step is to configure the heath check for your instances so that the load balancer will know which ones are down and where to safely route its traffic. We used a check on port 44 HTTP (remember SSL is managed by the load balancer!) of each EC2 instance.

Amazon provides out of the box a fancy public DNS name for your load balancer but you will certainly want to use your own sober domain name. To do this you should create a CNAME record for the LoadBalancer DNS name as specified by Amazon docs. For more information about CNAME records, see the CNAME Record Wikipedia article.

Ok, now we have a simple load balancer but we have no instances yet!

EC2 instances setup

In our idea each instance should run a servlet container with our grails application and should listen for incoming connections on ports 80 and 443. Connections on port 80 should be redirected to 443 to enforce encryption through the load balancer. We started from a standard Ubuntu 10 image and customized if for our purposes.

We used a divde et impera thecnique here, thanks to a brilliant idea of Luis!
We had 2 different tasks:

  • Running a webapp
  • Doing some proxying/url rewriting stuff

So we used two different pieces of software on the same machine, each doing its own best: Tomcat would have handled our application and Nginx would have acted as our proxy. Installing both products was straightforward.

Tomcat configuration was really nice and easy. Since Tomcat only purpose was to run our webapp we just put a simple connector for http on port 8080 in the configuration file server.xml with no encryption and no redirects:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
URIEncoding="UTF-8" />
Then we just set our webapp as the ROOT one. Here the Tomcat reference to do that.

Nginx configuration was a little trickier. We created a virtual host config file under nginx folder /etc/nginx/sites-available and created a link to it inside the folder /etc/nginx/sites-enabled. The file contains Nginx directives for url rewriting and redirecting. Detailed info on virtual hosts can be found on Nginx wiki.

The configuration file uses two server statements, the first looks like this:
server {
  server_name  localhost;
  access_log  /var/log/nginx/website.redirector.access.log;
  location / {
    rewrite ^ https://public.website.com permanent;
  }
}

This basically says to nginx to listen on port 80 for any location request (/) and redirect clients to https://public.website.com that is the main website using https protocol. Now all http connections will be redirected to the home page using https!

You can alternatively use this location line to redirect to the same page requested, always forcing https.
location / {
  rewrite ^ https://public.website.com$uri permanent;
}

Ok, now we just need to create the last server statement:
server {
  listen   443; ## listen for ipv4
  listen   [::]:443 default ipv6only=on; ## listen for ipv6
  server_name  localhost;
  access_log  /var/log/nginx/website.access.log;
  location / {
    proxy_pass      http://127.0.0.1:8080;
  }
}

This is needed for handling connections on port 443. Connections incoming on this port are unencrypted because the load balancer handles the SSL certificate and decryption. We want these connections to be passed on to our tomcat server listening on the same machine on port 8080, so we set the proxy pass value to http://127.0.0.1:8080.

Done! Connections on port 443 are decrypted by our load balancer, passed on port 443 of our instance to Nginx that forwards them to Tomcat running on port 8080!

It remains just a little issue to take care of...
Our webapp is totally ignorant about our complex-but-beautiful-2stages-proxy-configuration, so when it sends a redirect to the client browser it will use a  location containing an address of the kind: http://127.0.0.1:8080 !!!
Nginx to the rescue! We can add a rule to our configuration to take care of all that messy redirects. This is the final config that translates the redirects from http://127.0.0.1:8080 to our pretty  https://public.website.com
server {
  listen   443; ## listen for ipv4
  listen   [::]:443 default ipv6only=on; ## listen for ipv6
  server_name  localhost;
  access_log  /var/log/nginx/website.access.log;
  location / {
    proxy_pass      http://127.0.0.1:8080;
    proxy_redirect http://127.0.0.1:8080 https://public.website.com;
  }
}

Now our setup is finally ok!

Final setup

Automatic updates: the icing on the cake

Last thing we did is to add some automation to our instance. We created a startup job that executes the following tasks:

  1. Download the last build of our webapp from our build server and put it into the Tomcat war folder
  2. Start Tomcat so that it will deploy the new war as the ROOT webapp and start listening on port 8080
  3. Start Nginx that will serve requests on ports 80 and 443 as per our configuration

After this last piece of configuration we crated an AMI out of our instance.

Each time we want to update our server we simply launch a new instance and add it to the load balancer. As soon as it recognizes the instance as "in service" we just stop the old one... voilà our webapp was updated with zero downtime! :)

Nearly automatic updates

 

I hope this will help someone out there, or at least give some ideas on how to approach similar problems.
Ciao!

Paolo

Prepping for Growth

Hi everyone, I hope you all had a great spring/Easter break.

If you've been following our company/product blog, you know that we have a few big features coming up: myBalsamiq, the components feature and a new skin for Mockups. Each of these features has the potential for increasing our customer base substantially, so we need to be ready for it.

We took advantage of the downtime last week to migrate our website, blogs and source code to a more scalable, modern and reliable infrastructure. Oh, and it's must faster too! :)

It was a pretty big effort, so we thought we'd share what we did and how we got to this point, in the hope that it will help you if you're just starting out.

A bit of History

The chart above maps the 4 transitions that took us to this point.

When I was first starting up my good friends and advisers Michael Fitzpatrick and Chris Tennant generously offered to lend me space on one of their servers. They run ConnectSolutions, a very cool company which offers top-notch real-time communication solutions (you should DEFINITELY check them out, they're awesome), so they had server-space available. Their typical slices had 4Gb of hard drive space, which I thought was plenty!

I installed Drupal (for the website), WordPress (for the blog), Perforce (for source-code repository) and CruiseControl (for continous integration, i.e. turning the source code into the applications you download from our site). I also installed MySQL so that Drupal and WordPress could save their data in it.

For the videos on the website I just used YouTube at this point, adding Vimeo briefly (I liked their UI, but their Terms of Service are incredibly un-business friendly).

The first migration: moving the build machine

Right around the time when Marco joined last year, we decided to move the build machine to its own server. Compiling our many different products is a CPU-intensive operation, and that's not a good thing if that same computer has to be serving your web pages at the same time.

On top of that Perforce, which is free for up to two clients (one on the build machine and one on my laptop), was way too expensive for us, so we switched to Subversion. It behaved much like Perforce with a centralized repository of code and check-in/check-out model, plus was mature enough to have great GUI clients like Versions, so we went with it.

For the new server we chose to get "a slice" (a virtual piece of a server) on Slicehost, which we had heard about due to their great customer service.

One added benefit of the move was that from then on our code was backed up daily automatically (I had not set up backups on the Windows server because I was using my laptop as backup...I know, not good, but such is life). Slicehost makes it incredibly easy to turn on backups, it's a "set it and forget it" kind of thing.

Regarding hosting video, because I was unhappy with Vimeo, I wrote a simple FLV player and started hosting some videos myself. This gave me more control but meant more work, and those video files take up a lot of hard drive space (remember, I only had 4Gb to work with, which by now started to feel pretty small).

Our Little Company Grows

With Luis and Mike rounding out the team at the beginning of the year, we decided to each have a blog so that we could share our experiences with you better and hopefully get your feedback along the way.

The only drawback of having five different blogs means that we needed to manage 5 different WordPress installations, each needing to be backed up and updated regularely. Plus we needed to have a single theme to share, each with its separate sidebar. Anyways, a lot of maintenance work.

I asked Mike to take all of that on, but after a lovely chat with one of my heroes at SXSW I have come to realize that outsourcing this maintenance work would be the best way for us to do.

Another side-effect of having Luis and Mike joining full-time is that we now have more people committing code and working on different features at the same time. Luis encouraged to look at Bazaar and Hudson and gave us a demo in person when he came down to Bologna last month. Slowly but surely, I came around.

What happened last week

Right before SXSW, our old web server was straining under the load, so the night before I left for Austin I got another slice and prepped it all up (firewall, ssh, apache, mysql). BTW, I love it how things that seem so scary and hard the first time you do them can become so painless after you do them a few times.

At SXSW I met one of my heroes and he told me his new startup was basically a managed WordPress service on steroids, so I thought, why not migrate our blogs to their service at the same time?

And "while we were at it" (the 5 most expensive words in any remodeling), why not make the move from SVN to Bazaar and from CruiseControl to Hudson?

I figured if we're going to break everything, let's just do it all at once and get it over with?

Well, it was a tough week, but it's over. I bet there will be broken links to fix in the next few days, but so far, I'm really happy we made the move.

Our builds are much more streamlined, easier to manage and MUCH, much faster (we only build the skin's SWF once instead of 8 different times, for starters). Hudson's web interface is very usable, and the software  tells us the build is ready via Instant Messenger, which is kind-of cute.

The website feels VERY fast to me, I guess having some hard drive and more ram really makes a big difference, who knew! :)

As I was going through the 50 web pages that make up our website (I'm not counting the blogs), I also moved our videos to Brightcove, which we're also very happy with so far.

As for Bazaar, it's awesome. The ability to have your own local branches is really liberating. Just the fact of not having to fear branches as a concept any more is worth the move. I started a feature, didn't like where it was going, so I parked it in a branch. Marco is working on components, on its own branch, while I can continue to fix bugs and do weekly releases. Mike is redoing the CSS of myBalsamiq, in his own branch. I pull his changes once in a while, but Luis doesn't have to. So cool

The people at the WordPress hosting company, which I cannot mention yet, are giving us tremendous support, making managing 5 different blogs much, much easier. They back up everything (which, if you remember, I still hadn't done more than once or twice manually), and they'll be able to handle any load we can throw at them. I'll blog more about them when they go live.

So, we're set up for our next phase. I can sleep better at night knowing that everything we do is backed up (a first! shame on me!), knowing that we are running as lean and efficiently as we can, and knowing that we have room to grow.

Onward!

Video: A first look at Bazaar

· Posted by peldi in Videos · 7 Comments

Hi there. So Luis came to our office in Bologna for a couple of days, which was great.

We took the opportunity to take a look at Bazaar, the source-control system used by Ubuntu, mySQL, GNome.

Luis likes it more than Git, and we've been using SVN all this time, which I hear is "the old way" of working.

Anyways, we thought we'd record the session to share it with you...who knows, it may be useful if you're like me and still don't "get" these new ways of sharing your code...

Warning: the video is unedited and 48 minutes long.

In the end, I wasn't totally convinced but I'm willing to give it a try. We'll port our myBalsamiq code-base to Bazaar after our next beta refresh release and see how it feels.

What do you think? Will we ever go back to SVN?

Peldi

Better Adobe AIR Beta 2 Package for Ubuntu 64-bit Jaunty

UPDATE:  Package for AIR 2.5.0.  Remember you still need to follow the instructions below and your mileage may vary !!!

adobeair_2.5.0.16600balsamiq1.deb

We ran into a number of issues with installing Adobe AIR Beta 2 on our hosting infrastructure for myBalsamiq.com last week, so I wanted to share a trick I found that made the process a lot smoother and that hopefully is not too big of a hack while we wait for real 64-bit debian packages from Adobe.

So first of all a note of warning, the debian package that you can download here does not constitute a way to install a 64-bit package for Adobe AIR!  Adobe has announced an official 64-bit distribution but at least as concerns beta 2, we are still talking about using workarounds to get a 32-bit AIR to run on a 64-bit distribution through downloading and installing the appropriate 32-bit dependencies.

Our use case for installing Adobe AIR on some of our servers is a simple feature that was missing from previous myBalsamiq beta releases.  What happens is that when you upload a BMML file to a myBalsamiq project we call Balsamiq Mockups Desktop through the command line interface and produce a PNG of the uploaded mockup using the export command.  This allows us to create a new myBalsamiq Mockup page for the upload complete with a mockup image without having to launch the Mockups editor first.

Now Adobe has a very detailed procedure that is important to get acquainted with to install Adobe AIR 2 on 64-bit Ubuntu 9.04 because you still have to go through it, at least up to the step where it asks you to run AdobeAirInstaller.bin (which didn't work for us at all). Actually, I found there was no need to extract libs from the two debs (steps 4 & 5) as everything was setup right by the ia32_libs package.  I also did have to run an extra getlibs to grab libxstl1.1 as follows

sudo getlibs -l libxslt.so.1

Now  once the official deb package installed, because of a current bug in apt referenced here on Launchpad and here on the debian bug tracker, installing an AIR app through the AIR App Installer would work, but would create a broken package for the app rendering apt unusable for further installations.

So...  now for the big hack which allowed us to both install Adobe AIR using a deb package and not break apt.  What I did was use the following steps to extract, amend, and repackage the official Adobe AIR deb package to produce a patched version that lies to apt by saying its a 64-bit package!

First I extracted the deb package contents and debian meta-data into a folder:

dpkg-deb -x adobeair-2.0.0.11670.deb adobeair-2.0.0.11670balsamiq1
dpkg-deb -e adobeair-2.0.0.11670.deb adobeair-2.0.0.11670balsamiq1/DEBIAN

Then I updated the DEBIAN/control file switching the i386 architecture to amd64 and the version to 2.0.0.11670balsamiq1.

I then rebuilt the package using:

dpkg -b adobeair-2.0.0.11670balsamiq1

which produced the adobeair-2.0.0.11670balsamiq1.deb package which you can download here.

Here's a trace of installing it on one of our machines where you can see that aptitude picks up the presence of the adobe air package (which won't work if you use the official one)

luis@mockupshq:~$ sudo dpkg -i adobeair-2.0.0.11670balsamiq1.deb
Selecting previously deselected package adobeair.
(Reading database ... 63964 files and directories currently installed.)
Unpacking adobeair (from adobeair-2.0.0.11670balsamiq1.deb) ...

Running 32-bit AIR on 64-bit systems has not been fully tested. However, 32-bit AIR is expected to run on 64-bit systems if they have the required 32-bit libraries and packages installed.
 The following links describe how to install or update AIR 2.0 on 64-bit versions of Ubuntu 9.04, Fedora 11 and OpenSuse 11.1.
 Installing Adobe AIR 2.0 on 64-bit Linux visit http://kb2.adobe.com/cps/521/cpsid_52132.html
 Updating to Adobe AIR 2.0 on 64-bit Linux visit http://kb2.adobe.com/cps/521/cpsid_52132.html
Setting up adobeair (2.0.0.11670balsamiq1) ...

luis@mockupshq:~$ aptitude show adobeair
Package: adobeair
New: yes
State: installed
Automatically installed: no
Version: 2.0.0.11670balsamiq1
Priority: extra
Section: Development
Maintainer: Adobe Systems, Incorporated
Uncompressed Size: 44.9M
Depends: libgtk2.0-0 (>= 2.4), libxslt1.1, libxml2
PreDepends: lzma
Conflicts: adobeair1.0
Description: Adobe AIR

Now remember, your mileage with our deb is not guaranteed (although I actually also use this package on my laptop which is running karmic 64-bit)! So please don't get angry if something terrible happens with your installation, but I do encourage you to post your experience with it in the comments here, especially if something bad happens so that others may avoid going through your misery.

Oh and if you're interested in our myBalsamiq webapp, then definitely check out Peldi's awesome sneak peak screencast on the company blog.

Error creating AIR file: Could not BER decode the CRL.

Today, out of the blue, our Mockups for Desktop build started failing with the cryptic error above.

A Google search didn't turn up much, while a Bing search returned this seemingly abandoned Flex bug (#FB-16236).

Signs pointed to an issue with our code signing certificate. I contacted the TC TrustCenter support (who issued the cert) via phone, which was totally useless. The guy didn't even ask what happened, he just opened a ticket and 6 hours later I haven't heard back.

Until we get this fixed we cannot ship updates to Mockups, so you can imagine how I felt all afternoon.

I posted on the Adobe Air pre-release forums but heard nothing there either.

I did eventually find a solution though: I went here: http://www.chosensecurity.com/adobe-air-certificates and since the links on the page were broken I reluctantly clicked on "Chat Now", at least to tell them about their broken websites.

To my surprise, the person that answered my chat was extremely knowledgeable and was able to tell me exactly what the deal was.

So I'm sharing it now for those of you in the future who hit this rare issue. Do not panic, your pain is temporary.

So here's the deal: when you sign your Air application with a certificate, it turns out that adt goes out to the interwebs and checks a Certificate Revocation List, i.e. a server that keeps a list of expired or blocked certificates.

Makes sense, except that today ChosenSecurity/TC TrustCenter has had an outage of some sorts that took down their CRL server. They're working on it, and it should all go back to normal tomorrow.

In the meantime, a workaround is to DISCONNECT FROM THE INTERNET and sign your application then. In this case adt falls back to a cached version of the CRL, et voila'! I tried it and it works.

Hurray!

This reminds me of something my "Distributed Systems" professor taught us back in college: "a rigorous, well accepted definition of a distributed system is one in which someone, somewhere, does something...which prevents you from getting your work done".

Yup, check! :)

Peldi

People from the future: If this article helped you, put a w00t in the comments! :)

Once in a Lifetime

As a young man, I was fond of listening to a lot to Talking Heads, so although the song describes a character dealing with their mid-life crisis (of which I believe mine are (mostly) over), I felt no other title to this introductory post would best describe my feelings: I am overwhelmed by joining Peldi and the gang at Balsamiq to do what I believe will be some of the most fulfilling work to come in some twenty years in challenging startup environments.  The reason is that if Balsamiq with its good humour prides itself on "adding flavor", the pun is not innocent in the sense that it takes the right combination of ingredients, process and intention (or vision) to bring a product like Balsamiq Mockups to the desktops and wikis of so many satisfied customers.

Entrepreneurship being above all a human endeavor, clearly the ingredients are there !  Not only is our small distributed team a joy to work with, but our  partners and customers provide a rich foundation for improvement and building the future through conversations taking place all around the clock whether they concern our products or are simply encouragements do do even better.  Our processes are agile and ruthlessly focused on bringing  value to our customers through new features, enhancements, bug fixes, and usability improvements.  Release cycles are short and feedback is only a tweet or a post on our community site at GetSatisfaction away.  Finally, it only takes briefly studying Balsamiq's track record to understand that on top of all of this rich substrate of ingredients on which to build a successful business, we have in our founder Peldi, the rare quality of non compromising leadership based on values.

Now I know all of this through experience because among other business activities, I have been working with Peldi and Marco in stealth mode all of this past year on our our webapp project MyBalsamiq.  So I am thrilled to be able from now on to focus all of my time on MyBalsamiq and bring the product out the door so that our customers old and new will be in the position use  Mockups online with their customers and co-workers. Thank you Peldi for making this possible !

Finally, please note that this is a brand new blog at Balsamiq!  The Balsamiq Tech Blog will be a place for us to engage technical discussions focused on the tools, technology and processes that we use to build our products such as FlexGrails or agile software development.  This will also be the place for us to talk about the modules we release as open source. Hopefully all of this will be helpful to our customers and beyond, and the benefits of learning and improving software development skills with our readers will be mutual.