I’ve been putting a lot of work into Xataface getting it ready for release. There are still some details to take care of, but I think it’s safe to say that this release will be a drastic improvement over any of the previous releases.
All posts by shannah
Logic 8 on Mac OS X Lion Fix
My Dad recently upgraded to Lion only to discover that Logic Pro 8 no longer works on it. When he opened the application it just pops up with message saying that Logic was not compatible with this version of OS X, and promptly quits.
I saw some workarounds on you tube and other sites that involved starting Logic up on the command line by calling the internal binary inside the Logic app package directly – but this “fix” was not clean as it requires the terminal window to stay open and it also allows you to open logic twice or three times by accident and have it running it multiple processes (not a good thing). It also prevented Logic from working nicely with the rest of the OS because you still couldn’t open the app directly the “normal” way.
So I found a fix that will actually allow Logic 8 to work normally on Lion (i.e. you can just open it using the regular application icon and there’s not command line stuff involved).
Steps:
1. Right click (or control-click) the Logic Pro 8 application icon and select “Show Package Contents” from the contextual menu that appears. This will open a folder with the contents of the application package.
2. Open the “Contents” folder.
3. Open the Info.plist file in Text Edit. (You should be able to just double click it). This will open a big XML file with a whole bunch of directives.
4. Look for the text:
<key>LSRequiresCarbon</key>
<true/>
Delete this text.
5. Save the file.
You should now be able to open Logic Pro 8 normally on OS X Lion.
Special Note: That directive says that Logic requires the Carbon libraries to be installed. Carbon is old and it doesn’t look like Logic actually uses it at all – this is just a legacy restriction – I think. That said, it is possible that there are some features that still rely on Carbon to be there and may not work correctly on Lion. I’m sure my dad will let me know if he runs into any problems. So far everything appears to be working properly.
Edit: Apparently updating Lion to 10.7.2 also fixes this issue so you don’t need to perform this workaround.
WWSS (What Would Steve Say?)
I just finished reading the new Walter Isaacson biography of Steve Jobs. It is a good read, especially if you have an interest in Apple, Jobs, or computers in general.
This is a story of two Jobs. One is a self-centered jerk of near mythical proportion; the likes of which I’m certain I’ve never known personally. The other is a goal-driven perfectionist obsessed with design and simplicity, … and perfection. The story of this second Jobs is truly inspiring and it is this Jobs that I will choose to commit to memory.
Jobs had a keen eye for design and he would not allow anything less than the best to earn his stamp of approval. He oversaw all aspects of product development, from the design/development of the raw materials (such as the metal used in the Powerbooks or the glass used in the walls of the Apple Store), to the packaging that the finished product was delivered in. If something wasn’t perfect it was “shit” to him – and he certainly wasn’t polite with his criticisms of imperfections. However when a product did become “perfect” he also wasn’t shy about declaring that it was the “greatest thing ever” to the world.
In my own personal work I have been inspired by the story of Steve Jobs to push myself further towards perfection. I am prone to pragmatism or the “that’s good enough” bug that aids my productivity but sacrifices perfection. I doubt I’ve ever produced anything in my life that would stand the test of Steve Jobs’ criticism – and I suspect that most things would have received the prestigious Steve Jobs certification as “shit”. In the past few days I have found myself asking the question “what would Steve say?” when working on different features and designs for my products. Is there any way that this could be simplified? And I have surprised myself by continually making things better; Probably still “shitty” by Jobs standard, but still getting better.
I really think the world would be a better place if we all had some “ass hole” like Steve Jobs looking over our shoulder declaring “it’s shit, get rid of it!” whenever we were about to turn in a sub-standard piece of work. I think the world is better for Steve and his intense passion for perfection. I think the world is worse for his departure.
Rest in peace, Steve Jobs.
So Steve’s leaving us…. but is he really?
I received my November issue of Mac Life in the mail yesterday. It includes an article on Steve Jobs entitled “Steve’s Gone… Now What?”. It went over some of the Wall Street reaction to his “leaving” and recapped some of the accomplishments and qualifications of his successor, Tim Cook. The article conveyed optimism for Apple’s future and didn’t seem to dwell too much on its founder’s demise. It wasn’t until I reached this second article that I realized that I was reading tragically old news hot off the press:
“So Steve’s leaving us … but is he really?”, the article began.
Hmmm.. Uh yes.. pretty sure he’s really leaving.
Then the next line cleared up the conflict of context:
“What does it mean to switch from being CEO to Chairman of the Board?”
Ah .. that explains it.
Javascript Development with the Xataface Javascript Compiler
Javascript is a wonderful language, but I always felt as if it wasn’t terribly scalable. Not so much in the performance sense, but in the component sense. When working on large projects (like Xataface) Javascript can seem a little too “scripty” to build components in. I’m always fighting between the two conflicting goals of library size and library functionality.
If you build a useful library in Javascript it is usually either comprehensive and large, or small and single-purpose. It is possible to build the library in pieces and just include the parts that you want, but then you end up with a cumbersome set of script includes in your HTML page every time you want to use your library’s functionality. This is error-prone as it is easy to forget which scripts you need to load for any particular function to work.
In server-side languages you don’t have this problem. When you write a script in C, PHP, Python, Java (or any other language), you can just include your dependencies at the top of your file using an import, include, or require statement (syntax depends on the language). Then using your library is as simple as including one file – and all of that file’s dependencies will automatically be imported as well.
To solve this problem, I developed a Javascript compiler as part of Xataface. Some features of this compiler include:
- Compiler directives to process dependencies.
- Javascript Compression – to minimize the footprint.
- Duplicate Dependency tracking (i.e. If multiple scripts all require the same script as a dependency, then the dependency will only be included once).
- Compiler directives to include CSS files.
- Compiler directives to import files as strings.
- Configurable source paths. (i.e. Just like with other languages, you can specify multiple paths where source files will be located).
This doesn’t sound like a lot, but these features really improve the Javascript development experience. It allows me to develop reusable components that can be shared and imported into many different projects without having to deal with the complexities of including script tags in an HTML page, or making sure that the proper CSS files are included. Once you have built a component, it is done. All you need to do in order to use it in your application, is include it using the //require directive.
Let’s look at an example…
All of these features are provided by the Dataface_JavscriptTool class in Xataface. So you begin by obtaining an instance of this, and adding the source path where you want it to look for Javascripts.
import('Dataface/JavascriptTool.php'); $jt = Dataface_JavascriptTool::getInstance(); $jt->addPath('/path/to/javascripts', 'http://www.example.com/url/to/javascripts');
At this point the compiler knows to look in the /path/to/javascripts directory for scripts. But you haven’t told it to include any particular script. That’s our next step:
$jt->import('myscript.js');
If you were write this code inside the context of a Xataface application, your myscript.js file would run because Xataface handles the rest of the rendering at the end of the body of any template extending the Dataface_Main_Template.html template (which is pretty much all templates).
Note that by default the following directories are included in your javascript paths:
– DATAFACE_SITE_PATH/js
– DATAFACE_PATH/modules/XataJax/js
– DATAFACE_PATH/js
So you are able to use any script in those directories without needing to call the addPath() method of the JavscriptTool.
A look at the Javascript
myscript.js:
alert('hello world');
This just pops up an alert. Let’s get to some best practices right away though. The general structure of a script usually goes as follows:
//require <myotherscript.js> (function(){ alert('hello world'); })();
Note the //require statement on the first line. This tells the compiler to include the script myotherscript.js in its place. The compiler will look first in the /path/to/javascripts directory, then in DATAFACE_SITE_URL/js, then in DATAFACE_URL/modules/XataJax/js, then in DATAFACE_URL/js to see if it can find a script by that name. If it cannot find one it will throw an exception with a stacktrace. If it finds it, it will include the contents of the script in place of the require statement.
Example: Requiring jQuery
Xataface comes with lots of libraries included in its source paths. jQuery is one that is used in almost every script:
//require <jquery.packed.js> (function(){ var $ = jQuery; alert('Hello world'); })();
Note that on the first line, we make a reference $ to jQuery. This is because in Xataface jQuery.noConflict() is set so that it doesn’t conflict with other libraries that want to use the $ variable. By declaring it inside our wrapping function(){}, we are able to still use the $ shorthand without polluting the global namespace.
Using jQuery UI
The following example is meant to show why we need to be able to bind CSS with your javascript libraries. We are going to use jQuery UI’s dialog to display our ‘Hello world’ message, and this requires a CSS file in order to look proper:
//require <jquery.packed.js> //require <jquery-ui.min.js> //require-css <jquery-ui/jquery-ui.css> (function(){ var $ = jQuery; var dlg = $('<div>').append('Hello World').appendTo('body'); dlg.dialog(); })();
These examples are just the tip of the iceberg of possibilities that a Javascript compiler brings. More cool examples will be forthcoming as Xataface 2.0’s release nears.
A Week On Android
2 years ago I purchased an HTC Magic which runs on Android. I used if for a day and decided I didn’t like it, so I switched to my wife’s old iPhone 3G instead. I never looked back, until …
Last week my wife’s new iPhone 3G got water poisoning, so I loaned her my iPhone (her old phone). My plan was to dust off the old HTC and try using that instead. After all my needs are quite simple. I read books with the Kindle app, I use email, and I listen to music. The only part that I anticipated difficulty on was the music portion because I had a number of albums that had been purchased from iTunes.
Kindle Block
After charging the phone up a bit I moved onto trying to load the Kindle app. Unfortunately I didn’t see it in the Android marketplace. So I did a Google search to see if I could download it from the web. I found it and downloaded it, but was prompted that it was from an untrusted source and that I needed to turn off some setting in order to be able to install it. After disabling this security setting, I tried to install it… but failed with an error “This app could not be installed on this phone”. No explanation – just failure.
I repeated this procedure on a few different websites before realizing that my version of Android (1.5) was too old to run the software. In fact it was also too old to even work with the Android marketplace on the web.
Upgrade Maze
My next mission was to find out if there were any updates for my phone. So I did some google searches for variations on my phone’s model and my phone carrier which led to an updates page with about 8 or 9 different updates that apparently could be downloaded. There was a date next to each update but it wasn’t clear which update I needed. Did I need them all or did later updates overlap with earlier updates? One of the updates appeared to be an Android 2.1 update but I wasn’t absolutely sure about that. So I downloaded that update – which was only available as an EXE file (i.e. won’t run on a Mac).
So dusted off my Windows laptop and installed the update software. Unfortunately this software said that it couldn’t detect my android phone. After a while I figured out that I needed to also install phone sync application for the computer. Once that was installed, I was able to run the updater program. However the update failed half way through with a non-specific error about my phone not supporting this update.
This led to a period of research where I scoured Google to try to find all the information I could about my phone and updates, and errors with updates. There was a wealth of contradictory information – some reports claimed that the phone could not be updated, other reports claimed that it could. In the end I just went back to the same HTC update page and tried downloading some older updates. I downloaded each update and applied them in order. Most seemed to work – but none of them yet brought my phone up to Android 2.1, which is what was needed to run Kindle.
Once all of the prerequisite updates had been installed correctly, I tried again to install the 2.1 update. But it failed again.
Luckily at this point (with one of the updates I installed) I was able to get the update using a built-in update feature on the phone. So after about 5 hours I had updated my phone to 2.1.
Still No Love
Now, with 2.1 installed I had renewed vigour to get Kindle up and running. I was able to download it, but when I tried to run it, it informed me that I didn’t have enough memory. Apparently the HTC Magic doesn’t have much internal memory, but it has a MicroSD card slot. So I marched over to London Drugs and bought a 16gig card to load into the phone.
This time around, I was able to install Kindle. Phew!
The Easy Part
Android 2.1 is better in every way than its 1.5 ancestor. Importing my contacts from the iPhone and transferring the music turned out to be quite easy.
The Good and The Bad
Most of my gripes (such as lack of features like pinch-zoom) were resolved, leaving the UI to be almost as fluid as the iPhone interface. I do like the multi-tasking ability of it for productivity. I don’t like the multi-tasking ability for battery life.
Turns Out Ben Affleck Survived the War After All
After a few days of Android, we discovered that my wife’s iPhone had recovered from the water poisoning and was ready to resume its duties as her faithful communicator. So I was faced with a dilemma. I had put so much work into reforming the Android phone, and it had come such a long way. It would seem like a betrayal to return to my old phone after all we’d been through.
But it’s just a phone. I’m sure it will understand that no matter how much it tries to look and act like my old phone – it will never be an iPhone.
So I returned to my iPhone this morning and all is well in paradise again.
Footnote: The android really does come close now – but in the end it was the battery life that tipped the scale and convinced me to return to my old phone.
Using a “Silent” Java Applet to Render PDFs in HTML
I have read many obituaries for the Java applet. Once upon a time, in the late 1990’s the applet was king of the internet and hope for the future of rich web-based applications. Its decline and (almost) demise can be attributed to a number of factors, not the least of which is the fact that HTML and Javascript have improved to the point where most of the the functions that used to require an applet can now be performed directly in the web browser without requiring any third-party plugins. Nowadays, you scarcely run across any websites that use applets, and when you do, they generally stick out like a sore thumb. They are generally slow to load, and they almost always pop up with a security dialog asking you to approve their execution based on a signed certificate.
Signed Applets – Full Access or No Access
This clumsy security model is the other reason for the growing irrelevance of applets. An applet can only run in two different modes:
- Run inside the “sandbox”. The applet cannot access any system information from the client computer, cannot access the file system, and cannot make any network connections to any hosts other than where the applet was loaded from.
- Signed Applet – Full access. The applet runs with full permissions of the user. E.g. it can connect to any host, access any client system information, and access the hard drive. This level of access is very risky for the user especially if the applet is just running inside some random webpage that they are trying to open. The applet has the ability to delete the user’s hard drive or copy files from their hard drive without the user even knowing.
Because applet developers are so limited with the sandbox model, most developers end up distributing their applets as signed applets so that they can be run on clients’ computers with full access privileges. This works out great if the client fully trusts the applet developer – but that isn’t the typical client/developer relationship. Most users just click “okay” whenever these types of security dialogs pop up, so it becomes very easy for malicious developers to create trojans for unsuspecting users who browse to their web pages.
Since the proliferation of signed applets across the internet would result in a very dangerous browsing experience for the average internet user, we can be thankful that the web has opted for the applet-less direction that instead makes use of HTML and Javascript – which work inside a secure sandbox. Signed applets are now generally reserved for B2B applications and in-house apps where the client computer has a trusting relationship with the developer.
Unsigned Applets Are Still Safe
All that said, unsigned applets that run inside the applet sandbox are safe for a client to run since they don’t provide any access to the client’s computer. Unsigned applets’ fade from prominence is the natural result of improvements to Javascript and HTML. Javascript/HTML/CSS now have the tools required to create complex user interfaces with rich client interaction. It is no longer necessary to embed a Swing-based user interface inside the browser to give the user a rich experience. Further, it is inconvenient to work with a hybrid of technologies so the developers will often steer clear of applets entirely – opting for pure javascript solutions. For many years, applets were still necessary to accomplish things like drag-and-drop from the desktop (though that required a signed applet), or some more complex user interface widgets, but HTML 5 has introduced most of the tools to do all of these things inside Javascript natively. So the applet has been even further crowded out.
So What Are Applets Useful For Now?
The applet’s relevance may have been eroded down to a few grains of sand, but it turns out that some of those grains still shine like diamonds. Javascript can do many things well, but there are still a few items that Java can bring to the party. For example:
- Javascript doesn’t handle processor intensive operations well. It runs in a single thread so any intensive operations will make the browser hang and possibly even crash. Java, on the other hand, is multi-threaded so it can perform parallel processing in the background and pass results back to the browser in way that doesn’t interfere with the user experience.
- Java provides a rich, almost limitless set of libraries. – Hence you can find a library to do just about anything you need. The provides an alternative to making server-side requests for processing using AJAX. Instead requests can be passed to a “silent” applet that runs on the client computer – saving both network usage and server usage.
The “Silent” Applet
Observing the strengths of Java vs Javascript yields an interesting model for making use of applets in a web page. I call this the “silent” applet because it is designed to be completely transparent to both the Javascript developer, and the user. A silent applet is one that is loaded silently in the web page and does not manifest itself visually in the web page. Rather is runs invisibly along side the web page as a daemon waiting for requests from the web page which it processes and returns to the web page. This is similar to the AJAX model where the client sends background requests to the server, and the server returns a response which the client then processes. With this model, the request is not sent to the server at all. This saves both network and server resources since much more processing can take place on the client.
The silent applet is useful in situations where a significant amount of processing is required so that performing the “calculation” inside javascript is either impossible or would be disruptive to the user experience. This might include rendering a PDF page as an image, generating a complex chart, performing an image, video, or sound transformation, etc….
Example Silent Applet: Web PDF Renderer
I am developing a PDF reporting module for Xataface. I want the UI to allow the user to arrange database fields and content over top of an existing PDF that they upload as a means of creating report templates that can then be rendered as full reports later on. For this I need to be able to display the PDF as a background image in the user’s work space. I also need the user to be able to navigate through the PDF to different pages and to zoom in and out. The current state of Javascript and HTML is such that the rendering of PDFs needs to be relegated to a different system. Either I need to render the PDF pages as images on the server-side, or I need to find a way to do it in the client.
Rendering the PDFs on the server side would require me to install some server-side extensions or applications that can handle PDFs. There are many, but my goal is to keep the server requirements minimal so that it will work inside a standard LAMP install. So my preference is to find a way to render the PDF on the client side. There are various flash and Java applets already that display a PDF inside the browser, however I’m concerned with mixing flash or applets into the UI of my editor as it will likely result in painful, or intermittent conflicts down the road as the technologies choose not to place nicely together. So I decided to create a silent applet for rendering the PDF.
The Web PDF Renderer applet runs as a silent daemon in the background. There is a thin javascript API that can be used to ask the applet to render pages of a PDF at various sizes. When the processing is done, the applet calls a javascript callback to update an <img> tag in the user interface. This allows me to keep the entire user interface in standard HTML and manipulated via the DOM.
Using the Library
One example use of the library is to render the PDF to an HTML <img> tag. The following example creates a new PDFPage wrapper (which creates an img tag), then appends the image to the body of the document, and finally renders the PDF page. The render() method sends a signal to the applet to render the PDF page. When the applet is complete, it sends the data back the PDFPage object which updates the image source with the new data.
// Short reference to PDFPage constructor var PDFPage = xataface.modules.pdfreports.PDFPage; // Create a new page (first page of document) var page = new PDFPage({ width: 800, url: 'test.pdf', page: 0 }); // Append page’s <img < tag to the document body $(‘body’).append(page.el); // Render the page (done asynchronously) page.render();
Inside the Box: The implementation
We need to set up a mechanism for passing messages back and forth from Javascript to the applet and back. For javascript to java communication it is as easy as calling public methods defined on the applet directly. These are exposed and callable in Javascript. For the reverse, we make use JSObject which is available standard as part of the Java plugin. There is quite a bit of information on Java-Javascript communication on Oracle’s website.
We created a global queue that is used to pass the messages:
PDFPage.queue = [];
Note that is is just an empty array at this point.
Calling the render() method will pass a message to the applet – it essentially works as follows (this has been simplified for the example, but gets the point of strategy across):
function PDFPage_render(){ PDFPage.queue.push(this); startDispatch(); }
So render a page involves just two things:
1. We push the PDFPage object onto the message queue so that the applet can access it.
2. We call startDispatch(). This function essentially tells the applet that the queue has been updated so it can start processing.
The startDispatch() function up-close:
function startDispatch(){ var applet = $('applet[name="'+PDFPage.appletID+'"]').get(0); if ( !applet ){ var attributes = { name: PDFPage.appletID, code: "com.xataface.modules.pdfreports.PDFRendererApplet", codebase: PDFPage.codebase, archive: "WebPDFRenderer.jar, commons-codec-1.5.jar, commons-logging-1.1.1.jar, icepdf-core.jar", width: 1, height: 1 }; var parameters = { startDispatch:"PDFPage.startDispatch()", queue:"PDFPage.queue" }; var version = "1.5"; deployJava.runApplet(attributes, parameters, version); } else { try { applet.startDispatch(); } catch (e){ setTimeout(function(){ startDispatch(); }, 1000); } } }
At its core this is just a wrapper around the applet’s startDispatch() method – but it needs to handle some edge cases to load the applet the first time it is called. If the applet hasn’t yet been added to the dom, it adds it and tries to call itself again. If the applet is there but not loaded yet, it waits 1 second and tries again.
The deployJava.run() method is from the standard Java deployment code available here. Notice that we pass 2 parameters to the applet when we load it:
- We pass the javascript path to the queue so that the applet knows where to find its message queue.
- We pass the startDispatch() method call so that the applet is able to call its own startDispatch() method through javascript.
Inside the applet:
The start() method just loads the parameters that we passed, then calls the startDispatch() method for the first time:
public void start(){ queue = (JSObject)JSObject.getWindow(this).eval(this.getParameter("queue")); JSObject.getWindow(this).eval(this.getParameter("startDispatch")); }
The guts can be found in the startDispath() method:
public synchronized void startDispatch(){ if ( running ) return; running = true; Thread dispatcher = new Thread(new Runnable(){ public void run() { while (!stopDispatcher){ try { JSObject next = null; try { next = (JSObject)queue.call("shift", null); } catch (Exception ex){ break; } if ( next == null ) break; String pdfURL = (String)next.getMember("url"); if ( pdfURL == null ) break; PDFRenderer renderer = new PDFRenderer(); URL baseURL = PDFRendererApplet.this.getDocumentBase(); String baseURLStr = baseURL.toString(); int queryPos = baseURLStr.indexOf("?"); if ( queryPos >= 0 ){ baseURLStr = baseURLStr.substring(0, queryPos); } if ( !baseURLStr.endsWith("/") ){ int lastSlashPos = baseURLStr.lastIndexOf("/"); baseURLStr = baseURLStr.substring(0, lastSlashPos+1); } if ( pdfURL.indexOf(":") < 0 ){ if ( pdfURL.indexOf("/") == 0 ){ pdfURL = baseURL.getProtocol()+"://"+baseURL.getHost()+ (baseURL.getPort()>0?(":"+baseURL.getPort()):"")+pdfURL; } else { pdfURL = baseURLStr+pdfURL; } } System.out.println("PDF URL is "+pdfURL); renderer.setPDFURL(new URL(pdfURL)); String req = null; try { req = (String)next.getMember("request"); } catch ( Exception ex){ } if ( "numPages".equals(req) ){ next.call("update", new Object[]{renderer.getNumPages()}); } else { int page = ((Number)next.getMember("page")).intValue(); int width = ((Number)next.getMember("width")).intValue(); renderer.setWidth(width); renderer.setPage(page); BufferedImage img = renderer.getResult(); ByteArrayOutputStream os = new ByteArrayOutputStream(); ImageIO.write(img, "png", os); os.flush(); String encodedImage = new Base64().encodeToString(os.toByteArray()); os.close(); next.call("update", new Object[]{encodedImage}); } //System.out.println(encodedImage); } catch (Exception ex) { //Logger.getLogger(PDFRendererApplet.class.getName()).log(Level.SEVERE, null, ex); ex.printStackTrace(System.out); } } running = false; } }); dispatcher.start();
Edit: In newer versions of Java there are additional security restrictions on network requests when the method call is initiated from Javascript. Therefore is is necessary to wrap the startDispatch() method in an AccessController.doPrivileged() call (Solution found here). To accommodate this I renamed the startDispatch() method as int_startDispatch() and I created a new startDispatch() method as follows:
public synchronized void startDispatch(){ AccessController.doPrivileged( new PrivilegedAction(){ public String run(){ int_startDispatch(); return ""; } } ); }
This ensures that we won’t run into security issues when loading the PDFs.
Basically this spawns a thread the runs a loop. In each iteration, a message is loaded from the queue. It gets the PDF’s URL, and other information about what is being requested. When it is done, it calls the update() method of the original message which is a javascript method. It this method is responsible for adding the image back to the DOM.
JavaFX on Mac, iOS, Android, Windows Phone… Future looking bright
At the recent JavaONE conference in San Francisco, Oracle demonstrated JavaFX running on iOS and Android. While this hasn’t been officially approved by Apple, the proof of concept is also hope for the future of Java. I am heartened by Oracle’s new investment into Java and it looks like the coming years will be exciting ones for Java developers.
Update: It appears that Apple has loosened its restrictions on the technologies that can be used in their iOS app store. Therefore it seems very unlikely that Apple would try to block the use of JavaFX/Java applications in the iOS app store. Even more exciting!!
In addition to these demos, Oracle also announced the release of a JavaFX beta for Mac, and the developer of preview of JDK 7 for Mac – which promises a very bright future for Mac Java development.
Amazon EC2 Micro Instance By Accident
I recently had a problem with my Amazon EC2 server that caused me to have to fire up another fresh instance and transfer the files over. My original server was a “small” instance (which was the smallest available when I first set it up). I mistakenly chose a “micro” instance for the new server thinking that it was just another name for “small”.
3 days of misery ensued.
The server kept on maxing out with high server loads. (The server load average was hovering between 4 and 20 — ideal is around 0.3). However there were no processes that were using high CPU or memory resources according to the top command. With a server load of over 10, the most intensive process was using 0.1% of the CPU – which puzzled me. There was only one reading that appeared to be topping out (other than the load average), and that was %st (Stealth Time) – it was sitting at over 98%st.
Output of Top Command on Micro Instance
After some research I discovered that “Stealth Time” is percent of operations that are made to “wait” for the virtual machine to allow it to continue. This means that there was some throttling going on under the covers. This led me to this excellent review of Amazon EC2’s micro instances where the author describes the exact same experiences with his simple blog.
After converting the instance back to a small instance, all is well again.
Output of Top Command on Small Instance
Date.js – Life-saving Javascript library for date handling
I was faced with having to parse dates that could be in any number of formats. The built-in Javascript Date object is not up to the task. Found Date.js to be just what I needed. It will parse just about anything you can throw at it: