Index: frontend/node_modules/dom-converter/LICENSE
===================================================================
--- frontend/node_modules/dom-converter/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/dom-converter/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Aria Minaei
+
+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.
Index: frontend/node_modules/dom-converter/README.md
===================================================================
--- frontend/node_modules/dom-converter/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/dom-converter/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,3 @@
+Converts bare objects to DOM objects, compatible with htmlparser2's DOM objects.
+
+This is useful when you want to work with DOM without having to compose/parse html.
Index: frontend/node_modules/dom-converter/lib/domConverter.js
===================================================================
--- frontend/node_modules/dom-converter/lib/domConverter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/dom-converter/lib/domConverter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,33 @@
+// Generated by CoffeeScript 1.12.7
+var domToMarkup, object, objectToSaneObject, saneObjectToDom, self;
+
+objectToSaneObject = require('./objectToSaneObject');
+
+saneObjectToDom = require('./saneObjectToDom');
+
+domToMarkup = require('./domToMarkup');
+
+object = require('utila').object;
+
+module.exports = self = {
+  objectToDom: function(o) {
+    o = self._object2SaneObject(o);
+    return saneObjectToDom.convert(o);
+  },
+  object2markup: function(o) {
+    var dom;
+    dom = self.objectToDom(o);
+    return domToMarkup.convert(dom);
+  },
+  domToMarkup: function(dom) {
+    return domToMarkup.convert(dom);
+  },
+  _object2SaneObject: function(o) {
+    if (!Array.isArray(o)) {
+      if (!object.isBareObject(o)) {
+        throw Error("toDom() only accepts arrays and bare objects as input");
+      }
+    }
+    return objectToSaneObject.sanitize(o);
+  }
+};
Index: frontend/node_modules/dom-converter/lib/domToMarkup.js
===================================================================
--- frontend/node_modules/dom-converter/lib/domToMarkup.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/dom-converter/lib/domToMarkup.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,2 @@
+// Generated by CoffeeScript 1.12.7
+
Index: frontend/node_modules/dom-converter/lib/objectToSaneObject.js
===================================================================
--- frontend/node_modules/dom-converter/lib/objectToSaneObject.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/dom-converter/lib/objectToSaneObject.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,63 @@
+// Generated by CoffeeScript 1.12.7
+var object, self,
+  hasProp = {}.hasOwnProperty;
+
+object = require('utila').object;
+
+module.exports = self = {
+  sanitize: function(val) {
+    return self._toChildren(val);
+  },
+  _toChildren: function(val) {
+    var ref;
+    if (object.isBareObject(val)) {
+      return self._objectToChildren(val);
+    } else if (Array.isArray(val)) {
+      return self._arrayToChildren(val);
+    } else if (val === null || typeof val === 'undefined') {
+      return [];
+    } else if ((ref = typeof val) === 'string' || ref === 'number') {
+      return [String(val)];
+    } else {
+      throw Error("not a valid child node: `" + val);
+    }
+  },
+  _objectToChildren: function(o) {
+    var a, cur, key, val;
+    a = [];
+    for (key in o) {
+      if (!hasProp.call(o, key)) continue;
+      val = o[key];
+      cur = {};
+      cur[key] = self.sanitize(val);
+      a.push(cur);
+    }
+    return a;
+  },
+  _arrayToChildren: function(a) {
+    var i, len, ret, v;
+    ret = [];
+    for (i = 0, len = a.length; i < len; i++) {
+      v = a[i];
+      ret.push(self._toNode(v));
+    }
+    return ret;
+  },
+  _toNode: function(o) {
+    var key, keys, obj, ref;
+    if ((ref = typeof o) === 'string' || ref === 'number') {
+      return String(o);
+    } else if (object.isBareObject(o)) {
+      keys = Object.keys(o);
+      if (keys.length !== 1) {
+        throw Error("a node must only have one key as tag name");
+      }
+      key = keys[0];
+      obj = {};
+      obj[key] = self._toChildren(o[key]);
+      return obj;
+    } else {
+      throw Error("not a valid node: `" + o + "`");
+    }
+  }
+};
Index: frontend/node_modules/dom-converter/lib/saneObjectToDom.js
===================================================================
--- frontend/node_modules/dom-converter/lib/saneObjectToDom.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/dom-converter/lib/saneObjectToDom.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,114 @@
+// Generated by CoffeeScript 1.12.7
+var self,
+  hasProp = {}.hasOwnProperty;
+
+module.exports = self = {
+  convert: function(obj) {
+    return self._arrayToChildren(obj);
+  },
+  _arrayToChildren: function(a, parent) {
+    var children, j, len, node, prev, v;
+    if (parent == null) {
+      parent = null;
+    }
+    children = [];
+    prev = null;
+    for (j = 0, len = a.length; j < len; j++) {
+      v = a[j];
+      if (typeof v === 'string') {
+        node = self._getTextNodeFor(v);
+      } else {
+        node = self._objectToNode(v, parent);
+        node.prev = null;
+        node.next = null;
+        node.parent = parent;
+        if (prev != null) {
+          node.prev = prev;
+          prev.next = node;
+        }
+        prev = node;
+      }
+      children.push(node);
+    }
+    return children;
+  },
+  _objectToNode: function(o) {
+    var attribs, children, i, k, key, name, node, ref, v, val;
+    i = 0;
+    for (k in o) {
+      if (!hasProp.call(o, k)) continue;
+      v = o[k];
+      if (i > 0) {
+        throw Error("_objectToNode() only accepts an object with one key/value");
+      }
+      key = k;
+      val = v;
+      i++;
+    }
+    node = {};
+    if (typeof key !== 'string') {
+      throw Error("_objectToNode()'s key must be a string of tag name and classes");
+    }
+    if (typeof val === 'string') {
+      children = [self._getTextNodeFor(val)];
+    } else if (Array.isArray(val)) {
+      children = self._arrayToChildren(val, node);
+    } else {
+      inspect(o);
+      throw Error("_objectToNode()'s key's value must only be a string or an array");
+    }
+    node.type = 'tag';
+    ref = self._parseTag(key), name = ref.name, attribs = ref.attribs;
+    node.name = name;
+    node.attribs = attribs;
+    node.children = children;
+    return node;
+  },
+  _getTextNodeFor: function(s) {
+    return {
+      type: 'text',
+      data: s
+    };
+  },
+  _nameRx: /^[a-zA-Z\-\_]{1}[a-zA-Z0-9\-\_]*$/,
+  _parseTag: function(k) {
+    var attribs, classes, cls, id, m, name, parts;
+    if (!k.match(/^[a-zA-Z0-9\#\-\_\.\[\]\"\'\=\,\s]+$/) || k.match(/^[0-9]+/)) {
+      throw Error("cannot parse tag `" + k + "`");
+    }
+    attribs = {};
+    parts = {
+      name: '',
+      attribs: attribs
+    };
+    if (m = k.match(/^([^\.#]+)/)) {
+      name = m[1];
+      if (!name.match(self._nameRx)) {
+        throw Error("tag name `" + name + "` is not valid");
+      }
+      parts.name = name;
+      k = k.substr(name.length, k.length);
+    }
+    if (m = k.match(/^#([a-zA-Z0-9\-]+)/)) {
+      id = m[1];
+      if (!id.match(self._nameRx)) {
+        throw Error("tag id `" + id + "` is not valid");
+      }
+      attribs.id = id;
+      k = k.substr(id.length + 1, k.length);
+    }
+    classes = [];
+    while (m = k.match(/\.([a-zA-Z0-9\-\_]+)/)) {
+      cls = m[1];
+      if (!cls.match(self._nameRx)) {
+        throw Error("tag class `" + cls + "` is not valid");
+      }
+      classes.push(cls);
+      k = k.replace('.' + cls, '');
+    }
+    if (classes.length) {
+      attribs["class"] = classes.join(" ");
+    }
+    return parts;
+  }
+};
Index: frontend/node_modules/dom-converter/package.json
===================================================================
--- frontend/node_modules/dom-converter/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/dom-converter/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,38 @@
+{
+  "name": "dom-converter",
+  "version": "0.2.0",
+  "description": "converts bare objects to DOM objects or xml representations",
+  "main": "lib/domConverter.js",
+  "dependencies": {
+    "utila": "~0.4"
+  },
+  "devDependencies": {
+    "chai": "^1.10.0",
+    "chai-changes": "^1.3.4",
+    "chai-fuzzy": "^1.4.0",
+    "coffee-script": "^1.8.0",
+    "jitter": "^1.3.0",
+    "mocha": "^2.0.1",
+    "mocha-pretty-spec-reporter": "0.1.0-beta.1",
+    "sinon": "^1.12.2",
+    "sinon-chai": "^2.6.0"
+  },
+  "scripts": {
+    "test": "mocha \"test/**/*.coffee\"",
+    "test:watch": "mocha \"test/**/*.coffee\" --watch",
+    "compile": "coffee --bare --compile --output ./lib ./src",
+    "compile:watch": "jitter src lib -b",
+    "watch": "npm run compile:watch & npm run test:watch",
+    "winwatch": "start/b npm run compile:watch & npm run test:watch",
+    "prepublish": "npm run compile"
+  },
+  "author": "Aria Minaei",
+  "license": "MIT",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/AriaMinaei/dom-converter"
+  },
+  "bugs": {
+    "url": "https://github.com/AriaMinaei/dom-converter/issues"
+  }
+}
