diff --git a/static/third/lazyload/HISTORY b/static/third/lazyload/HISTORY
new file mode 100644
index 0000000000..8955c4a701
--- /dev/null
+++ b/static/third/lazyload/HISTORY
@@ -0,0 +1,68 @@
+LazyLoad Changelog
+================================================================================
+
+Version 2.0.3 (2011-07-05)
+ * Fixed a bug caused by an unwanted Closure Compiler optimization that broke
+ CSS load completion detection in Gecko when using the minified version of
+ LazyLoad. [Allex Wang]
+ * Fixed a race condition in which a URL could be removed from the "pending"
+ queue if it finished loading before other URLs in the same batch had been
+ added to the queue, resulting in the queue's length changing unexpectedly
+ during iteration. [Klaas Neirinck]
+
+Version 2.0.2 (2011-04-17)
+ * Added support for reliable detection of CSS load completion in Gecko
+ browsers based on a technique described by Zach Leatherman at
+ .
+ * Fixed a bug that prevented CSS load completion from being detected in WebKit
+ when there were no other stylesheets on the page. [Klaas Neirinck]
+ * Fixed a bug that could prevent CSS callbacks from being called in IE.
+
+Version 2.0.1 (2011-03-05)
+ * Added support for async=false. This ensures that parallel script loading
+ still works in Firefox 4 while preserving execution order. For more info,
+ see .
+ * Stylesheet load completion is now detected reliably in WebKit by polling
+ document.styleSheets for changes. Thanks to Jonathan Cook for suggesting
+ this solution.
+ * Dynamically created script and link nodes are now given a "lazyload" class
+ so they can be identified later.
+ * The charset for dynamically created script and link nodes is set to "utf-8".
+
+Version 2.0.0 (2009-08-06)
+ * Added support for CSS. Caveat: Gecko and WebKit don't support the onload
+ event for link nodes, so the CSS callback will fire almost immediately in
+ those browsers.
+ * When an array of URLs is specified, the resources will be loaded in parallel
+ in browsers that support it. Currently, all browsers support loading CSS in
+ parallel, but only Gecko and Opera support parallel scripts while preserving
+ execution order.
+ * The load() method has been replaced by css() and js() methods for loading
+ CSS and JS, respectively.
+ * The loadOnce() method has been removed, since it wasn't terribly useful.
+ * Improved reliability in all supported browsers.
+
+Version 1.0.4 (2008-07-24)
+ * Improved reliability with all supported browsers.
+ * Reduced the minified size to 1751 bytes (a whopping 67 bytes smaller than
+ version 1.0.3).
+ * Fixed a bug that caused the load completion callback to fire immediately in
+ Safari 3.x.
+ * Fixed a bug that caused the load completion callback to fail to fire in
+ Internet Explorer if the script was loaded from the cache.
+
+Version 1.0.3 (2007-06-18)
+ * Added "force" parameter to the loadOnce() method to force execution of the
+ callback even when all specified scripts have already been loaded.
+
+Version 1.0.2 (2007-06-02)
+ * Improved browser detection.
+ * Switched to NaturalDocs for source documentation.
+
+Version 1.0.1 (2007-05-30)
+ * Fixed potential race condition when load() is called multiple times in
+ succession.
+ * Refactored to reduce complexity.
+
+Version 1.0.0 (2007-05-29)
+ * First release.
diff --git a/static/third/lazyload/LICENSE b/static/third/lazyload/LICENSE
new file mode 100644
index 0000000000..cf4690b1cb
--- /dev/null
+++ b/static/third/lazyload/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2011 Ryan Grove
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the 'Software'), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/static/third/lazyload/README.md b/static/third/lazyload/README.md
new file mode 100644
index 0000000000..bc98a61c7c
--- /dev/null
+++ b/static/third/lazyload/README.md
@@ -0,0 +1,97 @@
+LazyLoad
+========
+
+LazyLoad is a tiny (only 966 bytes minified and gzipped), dependency-free
+JavaScript utility that makes it super easy to load external JavaScript and CSS
+files on demand.
+
+Whenever possible, LazyLoad will automatically load resources in parallel while
+ensuring execution order when you specify an array of URLs to load. In browsers
+that don't preserve the execution order of asynchronously-loaded scripts,
+LazyLoad will safely load the scripts sequentially.
+
+Use LazyLoad when you need a small, fast, safe dynamic JS or CSS loader, but
+don't need the overhead of dependency management or other extra functionality
+that larger script loaders provide.
+
+Downloads
+---------
+
+ * [lazyload.js](https://github.com/rgrove/lazyload/raw/master/lazyload.js) (full source)
+
+Usage
+-----
+
+Using LazyLoad is simple. Just call the appropriate method -- `css()` to load
+CSS, `js()` to load JavaScript -- and pass in a URL or array of URLs to load.
+You can also provide a callback function if you'd like to be notified when the
+resources have finished loading, as well as an argument to pass to the callback
+and a context in which to execute the callback.
+
+```js
+// Load a single JavaScript file and execute a callback when it finishes.
+LazyLoad.js('http://example.com/foo.js', function () {
+ alert('foo.js has been loaded');
+});
+
+// Load multiple JS files and execute a callback when they've all finished.
+LazyLoad.js(['foo.js', 'bar.js', 'baz.js'], function () {
+ alert('all files have been loaded');
+});
+
+// Load a CSS file and pass an argument to the callback function.
+LazyLoad.css('foo.css', function (arg) {
+ alert(arg);
+}, 'foo.css has been loaded');
+
+// Load a CSS file and execute the callback in a different scope.
+LazyLoad.css('foo.css', function () {
+ alert(this.foo); // displays 'bar'
+}, null, {foo: 'bar'});
+```
+
+Supported Browsers
+------------------
+
+ * Firefox 2+
+ * Google Chrome
+ * Internet Explorer 6+
+ * Opera 9+
+ * Safari 3+
+ * Mobile Safari
+ * Android
+
+Other browsers may work, but haven't been tested. It's a safe bet that anything
+based on a recent version of Gecko or WebKit will probably work.
+
+Caveats
+-------
+
+All browsers support parallel loading of CSS. However, only Firefox and Opera
+currently support parallel script loading while preserving execution order. To
+ensure that scripts are always executed in the correct order, LazyLoad will load
+all scripts sequentially in browsers other than Firefox and Opera. Hopefully
+other browsers will improve their parallel script loading behavior soon.
+
+License
+-------
+
+Copyright (c) 2011 Ryan Grove (ryan@wonko.com).
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the 'Software'), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/static/third/lazyload/lazyload.js b/static/third/lazyload/lazyload.js
new file mode 100644
index 0000000000..3985f30973
--- /dev/null
+++ b/static/third/lazyload/lazyload.js
@@ -0,0 +1,390 @@
+/*jslint browser: true, eqeqeq: true, bitwise: true, newcap: true, immed: true, regexp: false */
+
+/**
+LazyLoad makes it easy and painless to lazily load one or more external
+JavaScript or CSS files on demand either during or after the rendering of a web
+page.
+
+Supported browsers include Firefox 2+, IE6+, Safari 3+ (including Mobile
+Safari), Google Chrome, and Opera 9+. Other browsers may or may not work and
+are not officially supported.
+
+Visit https://github.com/rgrove/lazyload/ for more info.
+
+Copyright (c) 2011 Ryan Grove
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the 'Software'), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+@module lazyload
+@class LazyLoad
+@static
+*/
+
+LazyLoad = (function (doc) {
+ // -- Private Variables ------------------------------------------------------
+
+ // User agent and feature test information.
+ var env,
+
+ // Reference to the element (populated lazily).
+ head,
+
+ // Requests currently in progress, if any.
+ pending = {},
+
+ // Number of times we've polled to check whether a pending stylesheet has
+ // finished loading. If this gets too high, we're probably stalled.
+ pollCount = 0,
+
+ // Queued requests.
+ queue = {css: [], js: []},
+
+ // Reference to the browser's list of stylesheets.
+ styleSheets = doc.styleSheets;
+
+ // -- Private Methods --------------------------------------------------------
+
+ /**
+ Creates and returns an HTML element with the specified name and attributes.
+
+ @method createNode
+ @param {String} name element name
+ @param {Object} attrs name/value mapping of element attributes
+ @return {HTMLElement}
+ @private
+ */
+ function createNode(name, attrs) {
+ var node = doc.createElement(name), attr;
+
+ for (attr in attrs) {
+ if (attrs.hasOwnProperty(attr)) {
+ node.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return node;
+ }
+
+ /**
+ Called when the current pending resource of the specified type has finished
+ loading. Executes the associated callback (if any) and loads the next
+ resource in the queue.
+
+ @method finish
+ @param {String} type resource type ('css' or 'js')
+ @private
+ */
+ function finish(type) {
+ var p = pending[type],
+ callback,
+ urls;
+
+ if (p) {
+ callback = p.callback;
+ urls = p.urls;
+
+ urls.shift();
+ pollCount = 0;
+
+ // If this is the last of the pending URLs, execute the callback and
+ // start the next request in the queue (if any).
+ if (!urls.length) {
+ callback && callback.call(p.context, p.obj);
+ pending[type] = null;
+ queue[type].length && load(type);
+ }
+ }
+ }
+
+ /**
+ Populates the env variable with user agent and feature test
+ information.
+
+ @method getEnv
+ @private
+ */
+ function getEnv() {
+ var ua = navigator.userAgent;
+
+ env = {
+ // True if this browser supports disabling async mode on dynamically
+ // created script nodes. See
+ // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
+ async: doc.createElement('script').async === true
+ };
+
+ (env.webkit = /AppleWebKit\//.test(ua))
+ || (env.ie = /MSIE|Trident/.test(ua))
+ || (env.opera = /Opera/.test(ua))
+ || (env.gecko = /Gecko\//.test(ua))
+ || (env.unknown = true);
+ }
+
+ /**
+ Loads the specified resources, or the next resource of the specified type
+ in the queue if no resources are specified. If a resource of the specified
+ type is already being loaded, the new request will be queued until the
+ first request has been finished.
+
+ When an array of resource URLs is specified, those URLs will be loaded in
+ parallel if it is possible to do so while preserving execution order. All
+ browsers support parallel loading of CSS, but only Firefox and Opera
+ support parallel loading of scripts. In other browsers, scripts will be
+ queued and loaded one at a time to ensure correct execution order.
+
+ @method load
+ @param {String} type resource type ('css' or 'js')
+ @param {String|Array} urls (optional) URL or array of URLs to load
+ @param {Function} callback (optional) callback function to execute when the
+ resource is loaded
+ @param {Object} obj (optional) object to pass to the callback function
+ @param {Object} context (optional) if provided, the callback function will
+ be executed in this object's context
+ @private
+ */
+ function load(type, urls, callback, obj, context) {
+ var _finish = function () { finish(type); },
+ isCSS = type === 'css',
+ nodes = [],
+ i, len, node, p, pendingUrls, url;
+
+ env || getEnv();
+
+ if (urls) {
+ // If urls is a string, wrap it in an array. Otherwise assume it's an
+ // array and create a copy of it so modifications won't be made to the
+ // original.
+ urls = typeof urls === 'string' ? [urls] : urls.concat();
+
+ // Create a request object for each URL. If multiple URLs are specified,
+ // the callback will only be executed after all URLs have been loaded.
+ //
+ // Sadly, Firefox and Opera are the only browsers capable of loading
+ // scripts in parallel while preserving execution order. In all other
+ // browsers, scripts must be loaded sequentially.
+ //
+ // All browsers respect CSS specificity based on the order of the link
+ // elements in the DOM, regardless of the order in which the stylesheets
+ // are actually downloaded.
+ if (isCSS || env.async || env.gecko || env.opera) {
+ // Load in parallel.
+ queue[type].push({
+ urls : urls,
+ callback: callback,
+ obj : obj,
+ context : context
+ });
+ } else {
+ // Load sequentially.
+ for (i = 0, len = urls.length; i < len; ++i) {
+ queue[type].push({
+ urls : [urls[i]],
+ callback: i === len - 1 ? callback : null, // callback is only added to the last URL
+ obj : obj,
+ context : context
+ });
+ }
+ }
+ }
+
+ // If a previous load request of this type is currently in progress, we'll
+ // wait our turn. Otherwise, grab the next item in the queue.
+ if (pending[type] || !(p = pending[type] = queue[type].shift())) {
+ return;
+ }
+
+ head || (head = doc.head || doc.getElementsByTagName('head')[0]);
+ pendingUrls = p.urls;
+
+ for (i = 0, len = pendingUrls.length; i < len; ++i) {
+ url = pendingUrls[i];
+
+ if (isCSS) {
+ node = env.gecko ? createNode('style') : createNode('link', {
+ href: url,
+ rel : 'stylesheet'
+ });
+ } else {
+ node = createNode('script', {src: url});
+ node.async = false;
+ }
+
+ node.className = 'lazyload';
+ node.setAttribute('charset', 'utf-8');
+
+ if (env.ie && !isCSS && 'onreadystatechange' in node && !('draggable' in node)) {
+ node.onreadystatechange = function () {
+ if (/loaded|complete/.test(node.readyState)) {
+ node.onreadystatechange = null;
+ _finish();
+ }
+ };
+ } else if (isCSS && (env.gecko || env.webkit)) {
+ // Gecko and WebKit don't support the onload event on link nodes.
+ if (env.webkit) {
+ // In WebKit, we can poll for changes to document.styleSheets to
+ // figure out when stylesheets have loaded.
+ p.urls[i] = node.href; // resolve relative URLs (or polling won't work)
+ pollWebKit();
+ } else {
+ // In Gecko, we can import the requested URL into a