diff --git a/ajax/libs/hashgrid/6/hashgrid.js b/ajax/libs/hashgrid/6/hashgrid.js
new file mode 100644
index 000000000..09f75452b
--- /dev/null
+++ b/ajax/libs/hashgrid/6/hashgrid.js
@@ -0,0 +1,425 @@
+/**
+ * hashgrid (jQuery version)
+ * http://github.com/dotjay/hashgrid
+ * Version 6, 10 Jun 2011
+ * Written by Jon Gibbins at Analog, http://analog.coop/
+ *
+ * Contibutors:
+ * Sean Coates, http://seancoates.com/
+ * Phil Dokas, http://jetless.org/
+ * Andrew Jaswa, http://andrewjaswa.com/
+ */
+
+/**
+ * @license Copyright 2011 Analog Coop Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Usage
+ *
+ * // The basic #grid setup looks like this
+ * var grid = new hashgrid();
+ *
+ * // Or you can set a custom id for your grid, e.g. #mygrid
+ * var grid = new hashgrid("mygrid");
+ *
+ * // But there are a whole bunch of additional options you can set
+ * var grid = new hashgrid({
+ * id: 'mygrid', // id for the grid container
+ * modifierKey: 'alt', // optional 'ctrl', 'alt' or 'shift'
+ * showGridKey: 's', // key to show the grid
+ * holdGridKey: 'enter', // key to hold the grid in place
+ * foregroundKey: 'f', // key to toggle foreground/background
+ * jumpGridsKey: 'd', // key to cycle through the grid classes
+ * numberOfGrids: 2, // number of grid classes used
+ * classPrefix: 'class', // prefix for the grid classes
+ * cookiePrefix: 'mygrid' // prefix for the cookie name
+ * });
+ */
+
+
+/**
+ * Make sure we have the library
+ * TODO: Use an adapter
+ */
+if (typeof jQuery == "undefined") {
+ alert("Hashgrid: jQuery not loaded. Make sure it's linked to your pages.");
+}
+
+
+/**
+ * hashgrid overlay
+ * @constructor
+ */
+var hashgrid = function(set) {
+
+ var options = {
+ id: 'grid', // id for the grid container
+ modifierKey: null, // optional 'ctrl', 'alt' or 'shift'
+ showGridKey: 'g', // key to show the grid
+ holdGridKey: 'h', // key to hold the grid in place
+ foregroundKey: 'f', // key to toggle foreground/background
+ jumpGridsKey: 'j', // key to cycle through the grid classes
+ numberOfGrids: 1, // number of grid classes used
+ classPrefix: 'grid-', // prefix for the grid classes
+ cookiePrefix: 'hashgrid'// prefix for the cookie name
+ },
+ classNumber = 1,
+ gridLines,
+ gridWidth,
+ i,
+ line,
+ lineHeight,
+ numGridLines,
+ overlay,
+ overlayCookie,
+ overlayEl,
+ overlayOn = false,
+ overlayVert,
+ overlayZState = 'B',
+ overlayZBackground = -1,
+ overlayZForeground = 9999,
+ pageHeight,
+ setKey,
+ state,
+ sticky = false,
+ top;
+
+ // Apply options
+ if (typeof set == 'object') {
+ for (setKey in set) {
+ options[setKey] = set[setKey];
+ }
+ }
+ else if (typeof set == 'string') {
+ options.id = set;
+ }
+
+ // Remove any conflicting overlay
+ if ($('#' + options.id).length > 0) {
+ $('#' + options.id).remove();
+ }
+
+ // Create overlay, hidden before adding to DOM
+ overlayEl = $('
');
+ overlayEl
+ .attr('id', options.id)
+ .css({
+ display: 'none',
+ 'pointer-events': 'none'
+ });
+ $("body").prepend(overlayEl);
+ overlay = $('#' + options.id);
+
+ // Unless a custom z-index is set, ensure the overlay will be behind everything
+ if (overlay.css('z-index') == 'auto') overlay.css('z-index', overlayZBackground);
+
+ // Override the default overlay height with the actual page height
+ pageHeight = parseFloat($(document).height());
+ overlay.height(pageHeight);
+
+ // Add the first grid line so that we can measure it
+ overlay.append('');
+
+ // Position off-screen and display to calculate height
+ top = overlay.css("top");
+ overlay.css({
+ top: "-999px",
+ display: "block"
+ });
+
+ // Calculate the number of grid lines needed
+ line = $('#' + options.id + '-horiz');
+ lineHeight = line.outerHeight();
+
+ // Hide and reset top
+ overlay.css({
+ display: "none",
+ top: top
+ });
+
+ // Break on zero line height
+ if (lineHeight <= 0) {
+ return false;
+ }
+
+ // Add the remaining grid lines
+ numGridLines = Math.floor(pageHeight / lineHeight);
+ gridLines = '';
+
+ for (i = numGridLines - 1; i >= 1; i--) {
+ gridLines += '
';
+ }
+ overlay.append(gridLines);
+
+ // vertical grid
+ overlay.append($('
'));
+ overlayVert = overlay.children('.vert-container');
+ gridWidth = overlay.width();
+ overlayVert.css({width: gridWidth, position: 'absolute', top: 0});
+ overlayVert.append('
');
+
+ // 30 is an arbitrarily large number...
+ // can't calculate the margin width properly
+ gridLines = '';
+ for (i = 0; i < 30; i++) {
+ gridLines += '
';
+ }
+ overlayVert.append(gridLines);
+ overlayVert.children()
+ .height(pageHeight)
+ .css({ display: 'inline-block' });
+
+ // Check for saved state
+ overlayCookie = readCookie(options.cookiePrefix + options.id);
+ if (typeof overlayCookie == 'string') {
+ state = overlayCookie.split(',');
+ state[2] = Number(state[2]);
+ if ((typeof state[2] == 'number') && !isNaN(state[2])) {
+ classNumber = state[2].toFixed(0);
+ overlay.addClass(options.classPrefix + classNumber);
+ }
+ if (state[1] == 'F') {
+ overlayZState = 'F';
+ overlay.css('z-index', overlayZForeground);
+ }
+ if (state[0] == '1') {
+ overlayOn = true;
+ sticky = true;
+ showOverlay();
+ }
+ }
+ else {
+ overlay.addClass(options.classPrefix + classNumber);
+ }
+
+ // Keyboard controls
+ $(document).bind('keydown', keydownHandler);
+ $(document).bind('keyup', keyupHandler);
+
+ /**
+ * Helpers
+ */
+
+ function getModifier(e) {
+ if (options.modifierKey == null) return true; // Bypass by default
+ var m = true;
+ switch(options.modifierKey) {
+ case 'ctrl':
+ m = (e.ctrlKey ? e.ctrlKey : false);
+ break;
+
+ case 'alt':
+ m = (e.altKey ? e.altKey : false);
+ break;
+
+ case 'shift':
+ m = (e.shiftKey ? e.shiftKey : false);
+ break;
+ }
+ return m;
+ }
+
+ function getKey(e) {
+ var k = false, c = (e.keyCode ? e.keyCode : e.which);
+ // Handle keywords
+ if (c == 13) k = 'enter';
+ // Handle letters
+ else k = String.fromCharCode(c).toLowerCase();
+ return k;
+ }
+
+ function saveState() {
+ createCookie(options.cookiePrefix + options.id, (sticky ? '1' : '0') + ',' + overlayZState + ',' + classNumber, 1);
+ }
+
+ function showOverlay() {
+ overlay.show();
+ overlayVert.css({width: overlay.width()});
+ // hide any vertical blocks that aren't at the top of the viewport
+ overlayVert.children('.vert').each(function () {
+ $(this).css('display','inline-block');
+ if ($(this).offset().top > 0) {
+ $(this).hide();
+ }
+ });
+ }
+
+ /**
+ * Event handlers
+ */
+
+ function keydownHandler(e) {
+ var k,
+ m,
+ source = e.target.tagName.toLowerCase();
+
+ if ((source == 'input') || (source == 'textarea') || (source == 'select')) {
+ return true;
+ }
+
+ m = getModifier(e);
+ if (!m) {
+ return true;
+ }
+
+ k = getKey(e);
+ if (!k) {
+ return true;
+ }
+
+ switch(k) {
+ case options.showGridKey:
+ if (!overlayOn) {
+ showOverlay();
+ overlayOn = true;
+ }
+ else if (sticky) {
+ overlay.hide();
+ overlayOn = false;
+ sticky = false;
+ saveState();
+ }
+ break;
+ case options.holdGridKey:
+ if (overlayOn && !sticky) {
+ // Turn sticky overlay on
+ sticky = true;
+ saveState();
+ }
+ break;
+ case options.foregroundKey:
+ if (overlayOn) {
+ // Toggle sticky overlay z-index
+ if (overlay.css('z-index') == overlayZForeground) {
+ overlay.css('z-index', overlayZBackground);
+ overlayZState = 'B';
+ }
+ else {
+ overlay.css('z-index', overlayZForeground);
+ overlayZState = 'F';
+ }
+ saveState();
+ }
+ break;
+ case options.jumpGridsKey:
+ if (overlayOn && (options.numberOfGrids > 1)) {
+ // Cycle through the available grids
+ overlay.removeClass(options.classPrefix + classNumber);
+ classNumber++;
+ if (classNumber > options.numberOfGrids) classNumber = 1;
+ overlay.addClass(options.classPrefix + classNumber);
+ showOverlay();
+ if (/webkit/.test( navigator.userAgent.toLowerCase() )) {
+ forceRepaint();
+ }
+ saveState();
+ }
+ break;
+ }
+
+ return true;
+ }
+
+ function keyupHandler(e) {
+ var k,
+ m = getModifier(e);
+
+ if (!m) {
+ return true;
+ }
+
+ k = getKey(e);
+
+ if (k && (k == options.showGridKey) && !sticky) {
+ overlay.hide();
+ overlayOn = false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Cookie functions
+ *
+ * By Peter-Paul Koch:
+ * http://www.quirksmode.org/js/cookies.html
+ */
+ function createCookie(name, value, days) {
+ var date,
+ expires = "";
+
+ if (days) {
+ date = new Date();
+ date.setTime( date.getTime() + (days*24*60*60*1000) );
+ expires = "; expires=" + date.toGMTString();
+ }
+
+ document.cookie = name + "=" + value + expires + "; path=/";
+ }
+
+ function readCookie(name) {
+ var c,
+ ca = document.cookie.split(';'),
+ i = 0,
+ len = ca.length,
+ nameEQ = name + "=";
+
+ for (; i < len; i++) {
+ c = ca[i];
+
+ while (c.charAt(0) == ' ') {
+ c = c.substring(1, c.length);
+ }
+
+ if (c.indexOf(nameEQ) == 0) {
+ return c.substring(nameEQ.length, c.length);
+ }
+ }
+ return null;
+ }
+
+ function eraseCookie(name) {
+ createCookie(name, "", -1);
+ }
+
+ /**
+ * Forces a repaint (because WebKit has issues)
+ * http://www.sitepoint.com/forums/showthread.php?p=4538763
+ * http://www.phpied.com/the-new-game-show-will-it-reflow/
+ */
+ function forceRepaint() {
+ var ss = document.styleSheets[0];
+ try {
+ ss.addRule('.xxxxxx', 'position: relative');
+ ss.removeRule(ss.rules.length - 1);
+ } catch(e) {}
+ }
+
+ return {};
+};
+
+
+/**
+ * You can call hashgrid from your own code, but it's loaded here as
+ * an example for your convenience.
+ */
+$(document).ready(function() {
+
+ var grid = new hashgrid({
+ numberOfGrids: 2
+ });
+
+});
diff --git a/ajax/libs/hashgrid/package.json b/ajax/libs/hashgrid/package.json
new file mode 100644
index 000000000..7e8d24a85
--- /dev/null
+++ b/ajax/libs/hashgrid/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "hashgrid",
+ "filename": "hashgrid.js",
+ "version": "6",
+ "description": "A little tool that inserts a layout grid in web pages, allows you to hold it in place, and toggle between displaying it in the foreground or background.",
+ "homepage": "http://hashgrid.com/",
+ "keywords": [
+ "grid",
+ "layout",
+ "design",
+ "columns"
+ ],
+ "maintainers": [
+ {
+ "name": "Analog Coop",
+ "email": "hello@analog.coop",
+ "web": "http://analog.coop/"
+ }
+ ],
+ "repositories": [
+ {
+ "type": "git",
+ "url": "https://github.com/dotjay/hashgrid"
+ }
+ ]
+}