Try clean-css.
authorXhmikosR <xhmikosr@users.sourceforge.net>
Tue, 18 Mar 2014 15:14:55 +0000 (17:14 +0200)
committerXhmikosR <xhmikosr@users.sourceforge.net>
Wed, 19 Mar 2014 05:50:39 +0000 (07:50 +0200)
README.md
cleancss-browser.js [new file with mode: 0644]
csso.js [deleted file]
dist/htmlminifier.js
dist/htmlminifier.min.js
index.html
package.json
src/htmlminifier.js
tests/index.html

index 3a0d9cb..ef69346 100644 (file)
--- a/README.md
+++ b/README.md
@@ -47,10 +47,10 @@ npm install html-minifier
 | `removeOptionalTags`           | [Remove unrequired tags](http://perfectionkills.com/experimenting-with-html-minifier/#remove_optional_tags)                                                 | `false` |
 | `removeEmptyElements`          | [Remove all elements with empty contents](http://perfectionkills.com/experimenting-with-html-minifier/#remove_empty_elements)                               | `false` |
 | `lint`                         | [Toggle linting](http://perfectionkills.com/experimenting-with-html-minifier/#validate_input_through_html_lint)                                             | `false` |
-| `keepClosingSlash`             | Keep the trailing slash on singleton elements                               | `false` |
-| `caseSensitive`             | Treat attributes in case sensitive manner (useful for SVG; e.g. viewBox)                               | `false` |
-| `minifyJS`             | Minify Javascript in script elements (uses [UglifyJS](https://github.com/mishoo/UglifyJS2))                               | `false` |
-| `minifyCSS`            | Minify CSS in style elements (uses [CSSO](https://github.com/css/csso))                               | `false` |
+| `keepClosingSlash`             | Keep the trailing slash on singleton elements                                                                                                               | `false` |
+| `caseSensitive`                | Treat attributes in case sensitive manner (useful for SVG; e.g. viewBox)                                                                                    | `false` |
+| `minifyJS`                     | Minify Javascript in script elements (uses [UglifyJS](https://github.com/mishoo/UglifyJS2))                                                                 | `false` |
+| `minifyCSS`                    | Minify CSS in style elements (uses [clean-css](https://github.com/GoalSmashers/clean-css))                                                                  | `false` |
 
 
 [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/kangax/html-minifier/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
diff --git a/cleancss-browser.js b/cleancss-browser.js
new file mode 100644 (file)
index 0000000..3117519
--- /dev/null
@@ -0,0 +1,9992 @@
+!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.CleanCSS=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
+module.exports = _dereq_('./lib/clean');
+
+},{"./lib/clean":2}],2:[function(_dereq_,module,exports){
+(function (process,Buffer){
+/**
+ * Clean-css - https://github.com/GoalSmashers/clean-css
+ * Released under the terms of MIT license
+ *
+ * Copyright (C) 2011-2014 GoalSmashers.com
+ */
+
+/* jshint latedef: false */
+
+var ColorShortener = _dereq_('./colors/shortener');
+var ColorHSLToHex = _dereq_('./colors/hsl-to-hex');
+var ColorRGBToHex = _dereq_('./colors/rgb-to-hex');
+var ColorLongToShortHex = _dereq_('./colors/long-to-short-hex');
+
+var ImportInliner = _dereq_('./imports/inliner');
+var UrlRebase = _dereq_('./images/url-rebase');
+var EmptyRemoval = _dereq_('./selectors/empty-removal');
+
+var CommentsProcessor = _dereq_('./text/comments');
+var ExpressionsProcessor = _dereq_('./text/expressions');
+var FreeTextProcessor = _dereq_('./text/free');
+var UrlsProcessor = _dereq_('./text/urls');
+var NameQuotesProcessor = _dereq_('./text/name-quotes');
+
+var SelectorsOptimizer = _dereq_('./selectors/optimizer');
+
+var CleanCSS = module.exports = function CleanCSS(options) {
+  options = options || {};
+
+  // back compat
+  if (!(this instanceof CleanCSS))
+    return new CleanCSS(options);
+
+  options.keepBreaks = options.keepBreaks || false;
+
+  //active by default
+  if (undefined === options.processImport)
+    options.processImport = true;
+
+  this.options = options;
+  this.stats = {};
+  this.context = {
+    errors: [],
+    warnings: [],
+    debug: options.debug
+  };
+  this.errors = this.context.errors;
+  this.warnings = this.context.warnings;
+  this.lineBreak = process.platform == 'win32' ? '\r\n' : '\n';
+};
+
+CleanCSS.prototype.minify = function(data, callback) {
+  var options = this.options;
+
+  if (Buffer.isBuffer(data))
+    data = data.toString();
+
+  if (options.processImport) {
+    // inline all imports
+    var self = this;
+    var runner = callback ?
+      process.nextTick :
+      function(callback) { return callback(); };
+
+    return runner(function() {
+      return new ImportInliner(self.context, options.inliner).process(data, {
+        localOnly: !callback,
+        root: options.root || process.cwd(),
+        relativeTo: options.relativeTo,
+        whenDone: function(data) {
+          return minify.call(self, data, callback);
+        }
+      });
+    });
+  } else {
+    return minify.call(this, data, callback);
+  }
+};
+
+var minify = function(data, callback) {
+  var startedAt;
+  var stats = this.stats;
+  var options = this.options;
+  var context = this.context;
+  var lineBreak = this.lineBreak;
+
+  var commentsProcessor = new CommentsProcessor(
+    'keepSpecialComments' in options ? options.keepSpecialComments : '*',
+    options.keepBreaks,
+    lineBreak
+  );
+  var expressionsProcessor = new ExpressionsProcessor();
+  var freeTextProcessor = new FreeTextProcessor();
+  var urlsProcessor = new UrlsProcessor();
+  var nameQuotesProcessor = new NameQuotesProcessor();
+
+  if (options.debug) {
+    this.startedAt = process.hrtime();
+    this.stats.originalSize = data.length;
+  }
+
+  var replace = function() {
+    if (typeof arguments[0] == 'function')
+      arguments[0]();
+    else
+      data = data.replace.apply(data, arguments);
+  };
+
+  // replace function
+  if (options.benchmark) {
+    var originalReplace = replace;
+    replace = function(pattern, replacement) {
+      var name = typeof pattern == 'function' ?
+        /function (\w+)\(/.exec(pattern.toString())[1] :
+        pattern;
+
+      var start = process.hrtime();
+      originalReplace(pattern, replacement);
+
+      var itTook = process.hrtime(start);
+      console.log('%d ms: ' + name, 1000 * itTook[0] + itTook[1] / 1000000);
+    };
+  }
+
+  if (options.debug) {
+    startedAt = process.hrtime();
+    stats.originalSize = data.length;
+  }
+
+  replace(function escapeComments() {
+    data = commentsProcessor.escape(data);
+  });
+
+  // replace all escaped line breaks
+  replace(/\\(\r\n|\n)/gm, '');
+
+  // strip parentheses in urls if possible (no spaces inside)
+  replace(/url\((['"])([^\)]+)['"]\)/g, function(match, quote, url) {
+    var unsafeDataURI = url.indexOf('data:') === 0 && url.match(/data:\w+\/[^;]+;base64,/) === null;
+    if (url.match(/[ \t]/g) !== null || unsafeDataURI)
+      return 'url(' + quote + url + quote + ')';
+    else
+      return 'url(' + url + ')';
+  });
+
+  // strip parentheses in animation & font names
+  replace(function removeQuotes() {
+    data = nameQuotesProcessor.process(data);
+  });
+
+  // strip parentheses in @keyframes
+  replace(/@(\-moz\-|\-o\-|\-webkit\-)?keyframes ([^{]+)/g, function(match, prefix, name) {
+    prefix = prefix || '';
+    return '@' + prefix + 'keyframes ' + (name.indexOf(' ') > -1 ? name : name.replace(/['"]/g, ''));
+  });
+
+  // IE shorter filters, but only if single (IE 7 issue)
+  replace(/progid:DXImageTransform\.Microsoft\.(Alpha|Chroma)(\([^\)]+\))([;}'"])/g, function(match, filter, args, suffix) {
+    return filter.toLowerCase() + args + suffix;
+  });
+
+  replace(function escapeExpressions() {
+    data = expressionsProcessor.escape(data);
+  });
+
+  // strip parentheses in attribute values
+  replace(/\[([^\]]+)\]/g, function(match, content) {
+    var eqIndex = content.indexOf('=');
+    var singleQuoteIndex = content.indexOf('\'');
+    var doubleQuoteIndex = content.indexOf('"');
+    if (eqIndex < 0 && singleQuoteIndex < 0 && doubleQuoteIndex < 0)
+      return match;
+    if (singleQuoteIndex === 0 || doubleQuoteIndex === 0)
+      return match;
+
+    var key = content.substring(0, eqIndex);
+    var value = content.substring(eqIndex + 1, content.length);
+
+    if (/^['"](?:[a-zA-Z][a-zA-Z\d\-_]+)['"]$/.test(value))
+      return '[' + key + '=' + value.substring(1, value.length - 1) + ']';
+    else
+      return match;
+  });
+
+  replace(function escapeFreeText() {
+    data = freeTextProcessor.escape(data);
+  });
+
+  replace(function escapeUrls() {
+    data = urlsProcessor.escape(data);
+  });
+
+  // whitespace inside attribute selectors brackets
+  replace(/\[([^\]]+)\]/g, function(match) {
+    return match.replace(/\s/g, '');
+  });
+
+  // line breaks
+  replace(/[\r]?\n/g, ' ');
+
+  // multiple whitespace
+  replace(/[\t ]+/g, ' ');
+
+  // multiple semicolons (with optional whitespace)
+  replace(/;[ ]?;+/g, ';');
+
+  // multiple line breaks to one
+  replace(/ (?:\r\n|\n)/g, lineBreak);
+  replace(/(?:\r\n|\n)+/g, lineBreak);
+
+  // remove spaces around selectors
+  replace(/ ([+~>]) /g, '$1');
+
+  // remove extra spaces inside content
+  replace(/([!\(\{\}:;=,\n]) /g, '$1');
+  replace(/ ([!\)\{\};=,\n])/g, '$1');
+  replace(/(?:\r\n|\n)\}/g, '}');
+  replace(/([\{;,])(?:\r\n|\n)/g, '$1');
+  replace(/ :([^\{\};]+)([;}])/g, ':$1$2');
+
+  // restore spaces inside IE filters (IE 7 issue)
+  replace(/progid:[^(]+\(([^\)]+)/g, function(match) {
+    return match.replace(/,/g, ', ');
+  });
+
+  // trailing semicolons
+  replace(/;\}/g, '}');
+
+  replace(function hsl2Hex() {
+    data = new ColorHSLToHex(data).process();
+  });
+
+  replace(function rgb2Hex() {
+    data = new ColorRGBToHex(data).process();
+  });
+
+  replace(function longToShortHex() {
+    data = new ColorLongToShortHex(data).process();
+  });
+
+  replace(function shortenColors() {
+    data = new ColorShortener(data).process();
+  });
+
+  // replace font weight with numerical value
+  replace(/(font\-weight|font):(normal|bold)([ ;\}!])(\w*)/g, function(match, property, weight, suffix, next) {
+    if (suffix == ' ' && next.length > 0 && !/[.\d]/.test(next))
+      return match;
+
+    if (weight == 'normal')
+      return property + ':400' + suffix + next;
+    else if (weight == 'bold')
+      return property + ':700' + suffix + next;
+    else
+      return match;
+  });
+
+  // minus zero to zero
+  // repeated twice on purpose as if not it doesn't process rgba(-0,-0,-0,-0) correctly
+  var zerosRegexp = /(\s|:|,|\()\-0([^\.])/g;
+  replace(zerosRegexp, '$10$2');
+  replace(zerosRegexp, '$10$2');
+
+  // zero(s) + value to value
+  replace(/(\s|:|,)0+([1-9])/g, '$1$2');
+
+  // round pixels to 2nd decimal place
+  replace(/\.(\d{3,})px/g, function(match, decimalPlaces) {
+    return '.' + Math.round(parseFloat('.' + decimalPlaces) * 100) + 'px';
+  });
+
+  // .0 to 0
+  replace(/(\D)\.0+(,|\}|\))/g, '$10$2');
+
+  // fraction zeros removal
+  replace(/\.([1-9]*)0+(\D)/g, function(match, nonZeroPart, suffix) {
+    return (nonZeroPart.length > 0 ? '.' : '') + nonZeroPart + suffix;
+  });
+
+  // zero + unit to zero
+  var units = ['px', 'em', 'ex', 'cm', 'mm', 'in', 'pt', 'pc', '%'];
+  if (['ie7', 'ie8'].indexOf(options.compatibility) == -1)
+    units.push('rem');
+
+  replace(new RegExp('(\\s|:|,)\\-?0(?:' + units.join('|') + ')', 'g'), '$1' + '0');
+  replace(new RegExp('(\\s|:|,)\\-?(\\d)\\.(\\D)', 'g'), '$1$2$3');
+  replace(new RegExp('rect\\(0(?:' + units.join('|') + ')', 'g'), 'rect(0');
+
+  // restore % in rgb/rgba and hsl/hsla
+  replace(/(rgb|rgba|hsl|hsla)\(([^\)]+)\)/g, function(match, colorFunction, colorDef) {
+    var tokens = colorDef.split(',');
+    var applies = colorFunction == 'hsl' || colorFunction == 'hsla' || tokens[0].indexOf('%') > -1;
+    if (!applies)
+      return match;
+
+    if (tokens[1].indexOf('%') == -1)
+      tokens[1] += '%';
+    if (tokens[2].indexOf('%') == -1)
+      tokens[2] += '%';
+    return colorFunction + '(' + tokens.join(',') + ')';
+  });
+
+  // none to 0
+  replace(/outline:none/g, 'outline:0');
+
+  // background:none to background:0 0
+  replace(/background:(?:none|transparent)([;}])/g, 'background:0 0$1');
+
+  // multiple zeros into one
+  replace(/box-shadow:0 0 0( 0)?([^\.])/g, 'box-shadow:0 0$2');
+  replace(/:0 0 0 0([^\.])/g, ':0$1');
+  replace(/([: ,=\-])0\.(\d)/g, '$1.$2');
+
+  // restore rect(...) zeros syntax for 4 zeros
+  replace(/rect\(\s?0(\s|,)0[ ,]0[ ,]0\s?\)/g, 'rect(0$10$10$10)');
+
+  // remove universal selector when not needed (*#id, *.class etc)
+  replace(/\*([\.#:\[])/g, '$1');
+
+  // Restore spaces inside calc back
+  replace(/calc\([^\}]+\}/g, function(match) {
+    return match.replace(/\+/g, ' + ');
+  });
+
+  // remove space after (rgba|hsla) declaration - see #165
+  replace(/(rgba|hsla)\(([^\)]+)\) /g, '$1($2)');
+
+  if (options.noAdvanced) {
+    if (options.keepBreaks)
+      replace(/\}/g, '}' + lineBreak);
+  } else {
+    replace(function optimizeSelectors() {
+      data = new SelectorsOptimizer(data, context, {
+        keepBreaks: options.keepBreaks,
+        lineBreak: lineBreak,
+        compatibility: options.compatibility
+      }).process();
+    });
+  }
+
+  replace(function restoreUrls() {
+    data = urlsProcessor.restore(data);
+  });
+  replace(function rebaseUrls() {
+    data = options.noRebase ? data : new UrlRebase(options, context).process(data);
+  });
+  replace(function restoreFreeText() {
+    data = freeTextProcessor.restore(data);
+  });
+  replace(function restoreComments() {
+    data = commentsProcessor.restore(data);
+  });
+  replace(function restoreExpressions() {
+    data = expressionsProcessor.restore(data);
+  });
+
+  // move first charset to the beginning
+  replace(function moveCharset() {
+    // get first charset in stylesheet
+    var match = data.match(/@charset [^;]+;/);
+    var firstCharset = match ? match[0] : null;
+    if (!firstCharset)
+      return;
+
+    // reattach first charset and remove all subsequent
+    data = firstCharset +
+      (options.keepBreaks ? lineBreak : '') +
+      data.replace(new RegExp('@charset [^;]+;(' + lineBreak + ')?', 'g'), '').trim();
+  });
+
+  if (options.noAdvanced) {
+    replace(function removeEmptySelectors() {
+      data = new EmptyRemoval(data).process();
+    });
+  }
+
+  // trim spaces at beginning and end
+  data = data.trim();
+
+  if (options.debug) {
+    var elapsed = process.hrtime(startedAt);
+    stats.timeSpent = ~~(elapsed[0] * 1e3 + elapsed[1] / 1e6);
+    stats.efficiency = 1 - data.length / stats.originalSize;
+    stats.minifiedSize = data.length;
+  }
+
+  return callback ?
+    callback.call(this, this.context.errors.length > 0 ? this.context.errors : null, data) :
+    data;
+};
+
+}).call(this,_dereq_("C:\\Users\\xmr\\Desktop\\clean-css\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"),_dereq_("buffer").Buffer)
+},{"./colors/hsl-to-hex":3,"./colors/long-to-short-hex":4,"./colors/rgb-to-hex":5,"./colors/shortener":6,"./images/url-rebase":7,"./imports/inliner":9,"./selectors/empty-removal":17,"./selectors/optimizer":18,"./text/comments":20,"./text/expressions":22,"./text/free":23,"./text/name-quotes":24,"./text/urls":26,"C:\\Users\\xmr\\Desktop\\clean-css\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":38,"buffer":28}],3:[function(_dereq_,module,exports){
+module.exports = function HSLToHex(data) {
+  // HSL to RGB converter. Both methods adapted from:
+  // http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
+  var hslToRgb = function(h, s, l) {
+    var r, g, b;
+
+    // normalize hue orientation b/w 0 and 360 degrees
+    h = h % 360;
+    if (h < 0)
+      h += 360;
+    h = ~~h / 360;
+
+    if (s < 0)
+      s = 0;
+    else if (s > 100)
+      s = 100;
+    s = ~~s / 100;
+
+    if (l < 0)
+      l = 0;
+    else if (l > 100)
+      l = 100;
+    l = ~~l / 100;
+
+    if (s === 0) {
+      r = g = b = l; // achromatic
+    } else {
+      var q = l < 0.5 ?
+        l * (1 + s) :
+        l + s - l * s;
+      var p = 2 * l - q;
+      r = hueToRgb(p, q, h + 1/3);
+      g = hueToRgb(p, q, h);
+      b = hueToRgb(p, q, h - 1/3);
+    }
+
+    return [~~(r * 255), ~~(g * 255), ~~(b * 255)];
+  };
+
+  var hueToRgb = function(p, q, t) {
+    if (t < 0) t += 1;
+    if (t > 1) t -= 1;
+    if (t < 1/6) return p + (q - p) * 6 * t;
+    if (t < 1/2) return q;
+    if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
+    return p;
+  };
+
+  return {
+    process: function() {
+      return data.replace(/hsl\((-?\d+),(-?\d+)%?,(-?\d+)%?\)/g, function(match, hue, saturation, lightness) {
+        var asRgb = hslToRgb(hue, saturation, lightness);
+        var redAsHex = asRgb[0].toString(16);
+        var greenAsHex = asRgb[1].toString(16);
+        var blueAsHex = asRgb[2].toString(16);
+
+        return '#' +
+          ((redAsHex.length == 1 ? '0' : '') + redAsHex) +
+          ((greenAsHex.length == 1 ? '0' : '') + greenAsHex) +
+          ((blueAsHex.length == 1 ? '0' : '') + blueAsHex);
+      });
+    }
+  };
+};
+
+},{}],4:[function(_dereq_,module,exports){
+module.exports = function LongToShortHex(data) {
+  return {
+    process: function() {
+      return data.replace(/([,: \(])#([0-9a-f]{6})/gi, function(match, prefix, color) {
+        if (color[0] == color[1] && color[2] == color[3] && color[4] == color[5])
+          return prefix + '#' + color[0] + color[2] + color[4];
+        else
+          return prefix + '#' + color;
+      });
+    }
+  };
+};
+
+},{}],5:[function(_dereq_,module,exports){
+module.exports = function RGBToHex(data) {
+  return {
+    process: function() {
+      return data.replace(/rgb\((\-?\d+),(\-?\d+),(\-?\d+)\)/g, function(match, red, green, blue) {
+        red = Math.max(0, Math.min(~~red, 255));
+        green = Math.max(0, Math.min(~~green, 255));
+        blue = Math.max(0, Math.min(~~blue, 255));
+
+        // Credit: Asen  http://jsbin.com/UPUmaGOc/2/edit?js,console
+        return '#' + ('00000' + (red << 16 | green << 8 | blue).toString(16)).slice(-6);
+      });
+    }
+  };
+};
+
+},{}],6:[function(_dereq_,module,exports){
+module.exports = function Shortener(data) {
+  var COLORS = {
+    aliceblue: '#f0f8ff',
+    antiquewhite: '#faebd7',
+    aqua: '#0ff',
+    aquamarine: '#7fffd4',
+    azure: '#f0ffff',
+    beige: '#f5f5dc',
+    bisque: '#ffe4c4',
+    black: '#000',
+    blanchedalmond: '#ffebcd',
+    blue: '#00f',
+    blueviolet: '#8a2be2',
+    brown: '#a52a2a',
+    burlywood: '#deb887',
+    cadetblue: '#5f9ea0',
+    chartreuse: '#7fff00',
+    chocolate: '#d2691e',
+    coral: '#ff7f50',
+    cornflowerblue: '#6495ed',
+    cornsilk: '#fff8dc',
+    crimson: '#dc143c',
+    cyan: '#0ff',
+    darkblue: '#00008b',
+    darkcyan: '#008b8b',
+    darkgoldenrod: '#b8860b',
+    darkgray: '#a9a9a9',
+    darkgreen: '#006400',
+    darkkhaki: '#bdb76b',
+    darkmagenta: '#8b008b',
+    darkolivegreen: '#556b2f',
+    darkorange: '#ff8c00',
+    darkorchid: '#9932cc',
+    darkred: '#8b0000',
+    darksalmon: '#e9967a',
+    darkseagreen: '#8fbc8f',
+    darkslateblue: '#483d8b',
+    darkslategray: '#2f4f4f',
+    darkturquoise: '#00ced1',
+    darkviolet: '#9400d3',
+    deeppink: '#ff1493',
+    deepskyblue: '#00bfff',
+    dimgray: '#696969',
+    dodgerblue: '#1e90ff',
+    firebrick: '#b22222',
+    floralwhite: '#fffaf0',
+    forestgreen: '#228b22',
+    fuchsia: '#f0f',
+    gainsboro: '#dcdcdc',
+    ghostwhite: '#f8f8ff',
+    gold: '#ffd700',
+    goldenrod: '#daa520',
+    gray: '#808080',
+    green: '#008000',
+    greenyellow: '#adff2f',
+    honeydew: '#f0fff0',
+    hotpink: '#ff69b4',
+    indianred: '#cd5c5c',
+    indigo: '#4b0082',
+    ivory: '#fffff0',
+    khaki: '#f0e68c',
+    lavender: '#e6e6fa',
+    lavenderblush: '#fff0f5',
+    lawngreen: '#7cfc00',
+    lemonchiffon: '#fffacd',
+    lightblue: '#add8e6',
+    lightcoral: '#f08080',
+    lightcyan: '#e0ffff',
+    lightgoldenrodyellow: '#fafad2',
+    lightgray: '#d3d3d3',
+    lightgreen: '#90ee90',
+    lightpink: '#ffb6c1',
+    lightsalmon: '#ffa07a',
+    lightseagreen: '#20b2aa',
+    lightskyblue: '#87cefa',
+    lightslategray: '#778899',
+    lightsteelblue: '#b0c4de',
+    lightyellow: '#ffffe0',
+    lime: '#0f0',
+    limegreen: '#32cd32',
+    linen: '#faf0e6',
+    magenta: '#ff00ff',
+    maroon: '#800000',
+    mediumaquamarine: '#66cdaa',
+    mediumblue: '#0000cd',
+    mediumorchid: '#ba55d3',
+    mediumpurple: '#9370db',
+    mediumseagreen: '#3cb371',
+    mediumslateblue: '#7b68ee',
+    mediumspringgreen: '#00fa9a',
+    mediumturquoise: '#48d1cc',
+    mediumvioletred: '#c71585',
+    midnightblue: '#191970',
+    mintcream: '#f5fffa',
+    mistyrose: '#ffe4e1',
+    moccasin: '#ffe4b5',
+    navajowhite: '#ffdead',
+    navy: '#000080',
+    oldlace: '#fdf5e6',
+    olive: '#808000',
+    olivedrab: '#6b8e23',
+    orange: '#ffa500',
+    orangered: '#ff4500',
+    orchid: '#da70d6',
+    palegoldenrod: '#eee8aa',
+    palegreen: '#98fb98',
+    paleturquoise: '#afeeee',
+    palevioletred: '#db7093',
+    papayawhip: '#ffefd5',
+    peachpuff: '#ffdab9',
+    peru: '#cd853f',
+    pink: '#ffc0cb',
+    plum: '#dda0dd',
+    powderblue: '#b0e0e6',
+    purple: '#800080',
+    red: '#f00',
+    rosybrown: '#bc8f8f',
+    royalblue: '#4169e1',
+    saddlebrown: '#8b4513',
+    salmon: '#fa8072',
+    sandybrown: '#f4a460',
+    seagreen: '#2e8b57',
+    seashell: '#fff5ee',
+    sienna: '#a0522d',
+    silver: '#c0c0c0',
+    skyblue: '#87ceeb',
+    slateblue: '#6a5acd',
+    slategray: '#708090',
+    snow: '#fffafa',
+    springgreen: '#00ff7f',
+    steelblue: '#4682b4',
+    tan: '#d2b48c',
+    teal: '#008080',
+    thistle: '#d8bfd8',
+    tomato: '#ff6347',
+    turquoise: '#40e0d0',
+    violet: '#ee82ee',
+    wheat: '#f5deb3',
+    white: '#fff',
+    whitesmoke: '#f5f5f5',
+    yellow: '#ff0',
+    yellowgreen: '#9acd32'
+  };
+
+  var toHex = {};
+  var toName = {};
+
+  for (var name in COLORS) {
+    var color = COLORS[name];
+    if (name.length < color.length)
+      toName[color] = name;
+    else
+      toHex[name] = color;
+  }
+
+  return {
+    toHex: toHex,
+    toName: toName,
+
+    // replace color name with hex values if shorter (or the other way around)
+    process: function() {
+      [toHex, toName].forEach(function(conversion) {
+        var pattern = '(' + Object.keys(conversion).join('|') + ')';
+        var colorSwitcher = function(match, prefix, colorValue, suffix) {
+          return prefix + conversion[colorValue.toLowerCase()] + suffix;
+        };
+        data = data.replace(new RegExp('([ :,\\(])' + pattern + '([;\\}!\\) ])', 'ig'), colorSwitcher);
+        data = data.replace(new RegExp('(,)' + pattern + '(,)', 'ig'), colorSwitcher);
+      });
+
+      return data;
+    }
+  };
+};
+
+},{}],7:[function(_dereq_,module,exports){
+var path = _dereq_('path');
+
+var UrlRewriter = _dereq_('./url-rewriter');
+
+module.exports = function UrlRebase(options, context) {
+  var process = function(data) {
+    var rebaseOpts = {
+      absolute: !!options.root,
+      relative: !options.root && !!options.target,
+      fromBase: options.relativeTo
+    };
+
+    if (!rebaseOpts.absolute && !rebaseOpts.relative)
+      return data;
+
+    if (rebaseOpts.absolute && !!options.target)
+      context.warnings.push('Both \'root\' and output file given so rebasing URLs as absolute paths');
+
+    if (rebaseOpts.absolute)
+      rebaseOpts.toBase = path.resolve(options.root);
+
+    if (rebaseOpts.relative)
+      rebaseOpts.toBase = path.resolve(path.dirname(options.target));
+
+    if (!rebaseOpts.fromBase || !rebaseOpts.toBase)
+      return data;
+
+    return UrlRewriter.process(data, rebaseOpts);
+  };
+
+  return { process: process };
+};
+
+},{"./url-rewriter":8,"path":39}],8:[function(_dereq_,module,exports){
+(function (process){
+var path = _dereq_('path');
+var url = _dereq_('url');
+
+module.exports = {
+  process: function(data, options) {
+    var tempData = [];
+    var nextStart = 0;
+    var nextEnd = 0;
+    var cursor = 0;
+
+    for (; nextEnd < data.length;) {
+      nextStart = data.indexOf('url(', nextEnd);
+      if (nextStart == -1)
+        break;
+
+      nextEnd = data.indexOf(')', nextStart + 4);
+      if (nextEnd == -1)
+        break;
+
+      tempData.push(data.substring(cursor, nextStart));
+      var url = data.substring(nextStart + 4, nextEnd).replace(/['"]/g, '');
+      tempData.push('url(' + this._rebased(url, options) + ')');
+      cursor = nextEnd + 1;
+    }
+
+    return tempData.length > 0 ?
+      tempData.join('') + data.substring(cursor, data.length) :
+      data;
+  },
+
+  _rebased: function(resource, options) {
+    var specialUrl = resource[0] == '/' ||
+      resource.substring(resource.length - 4) == '.css' ||
+      resource.indexOf('data:') === 0 ||
+      /^https?:\/\//.exec(resource) !== null ||
+      /__\w+__/.exec(resource) !== null;
+    var rebased;
+
+    if (specialUrl)
+      return resource;
+
+    if (/https?:\/\//.test(options.toBase))
+      return url.resolve(options.toBase, resource);
+
+    if (options.absolute) {
+      rebased = path
+        .resolve(path.join(options.fromBase, resource))
+        .replace(options.toBase, '');
+    } else {
+      rebased = path.relative(options.toBase, path.join(options.fromBase, resource));
+    }
+
+    return process.platform == 'win32' ?
+      rebased.replace(/\\/g, '/') :
+      rebased;
+  }
+};
+
+}).call(this,_dereq_("C:\\Users\\xmr\\Desktop\\clean-css\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"))
+},{"C:\\Users\\xmr\\Desktop\\clean-css\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":38,"path":39,"url":52}],9:[function(_dereq_,module,exports){
+var fs = _dereq_('fs');
+var path = _dereq_('path');
+var http = _dereq_('http');
+var https = _dereq_('https');
+var url = _dereq_('url');
+
+var UrlRewriter = _dereq_('../images/url-rewriter');
+
+var merge = function(source1, source2) {
+  var target = {};
+  for (var key1 in source1)
+    target[key1] = source1[key1];
+  for (var key2 in source2)
+    target[key2] = source2[key2];
+
+  return target;
+};
+
+module.exports = function Inliner(context, options) {
+  var defaultOptions = {
+    timeout: 5000,
+    request: {}
+  };
+  var inlinerOptions = merge(defaultOptions, options || {});
+
+  var process = function(data, options) {
+    options._shared = options._shared || {
+      done: [],
+      left: []
+    };
+    var shared = options._shared;
+
+    var nextStart = 0;
+    var nextEnd = 0;
+    var cursor = 0;
+    var isComment = commentScanner(data);
+    var afterContent = contentScanner(data);
+
+    options.relativeTo = options.relativeTo || options.root;
+    options._baseRelativeTo = options._baseRelativeTo || options.relativeTo;
+    options.visited = options.visited || [];
+
+    for (; nextEnd < data.length;) {
+      nextStart = data.indexOf('@import', cursor);
+      if (nextStart == -1)
+        break;
+
+      if (isComment(nextStart)) {
+        cursor = nextStart + 1;
+        continue;
+      }
+
+      nextEnd = data.indexOf(';', nextStart);
+      if (nextEnd == -1) {
+        cursor = data.length;
+        data = '';
+        break;
+      }
+
+      shared.done.push(data.substring(cursor, nextStart));
+      shared.left.unshift([data.substring(nextEnd + 1), options]);
+
+      return afterContent(nextStart) ?
+        processNext(options) :
+        inline(data, nextStart, nextEnd, options);
+    }
+
+    // no @import matched in current data
+    shared.done.push(data);
+    return processNext(options);
+  };
+
+  var processNext = function(options) {
+    if (options._shared.left.length > 0)
+      return process.apply(null, options._shared.left.shift());
+    else
+      return options.whenDone(options._shared.done.join(''));
+  };
+
+  var commentScanner = function(data) {
+    var commentRegex = /(\/\*(?!\*\/)[\s\S]*?\*\/)/;
+    var lastStartIndex = 0;
+    var lastEndIndex = 0;
+    var noComments = false;
+
+    // test whether an index is located within a comment
+    var scanner = function(idx) {
+      var comment;
+      var localStartIndex = 0;
+      var localEndIndex = 0;
+      var globalStartIndex = 0;
+      var globalEndIndex = 0;
+
+      // return if we know there are no more comments
+      if (noComments)
+        return false;
+
+      // idx can be still within last matched comment (many @import statements inside one comment)
+      if (idx > lastStartIndex && idx < lastEndIndex)
+        return true;
+
+      comment = data.match(commentRegex);
+
+      if (!comment) {
+        noComments = true;
+        return false;
+      }
+
+      // get the indexes relative to the current data chunk
+      lastStartIndex = localStartIndex = comment.index;
+      localEndIndex = localStartIndex + comment[0].length;
+
+      // calculate the indexes relative to the full original data
+      globalEndIndex = localEndIndex + lastEndIndex;
+      globalStartIndex = globalEndIndex - comment[0].length;
+
+      // chop off data up to and including current comment block
+      data = data.substring(localEndIndex);
+      lastEndIndex = globalEndIndex;
+
+      // re-run scan if comment ended before the idx
+      if (globalEndIndex < idx)
+        return scanner(idx);
+
+      return globalEndIndex > idx && idx > globalStartIndex;
+    };
+
+    return scanner;
+  };
+
+  var contentScanner = function(data) {
+    var isComment = commentScanner(data);
+    var firstContentIdx = -1;
+    while (true) {
+      firstContentIdx = data.indexOf('{', firstContentIdx + 1);
+      if (firstContentIdx == -1 || !isComment(firstContentIdx))
+        break;
+    }
+
+    return function(idx) {
+      return firstContentIdx > -1 ?
+        idx > firstContentIdx :
+        false;
+    };
+  };
+
+  var inline = function(data, nextStart, nextEnd, options) {
+    var importDeclaration = data
+      .substring(data.indexOf(' ', nextStart) + 1, nextEnd)
+      .trim();
+
+    var viaUrl = importDeclaration.indexOf('url(') === 0;
+    var urlStartsAt = viaUrl ? 4 : 0;
+    var isQuoted = /^['"]/.exec(importDeclaration.substring(urlStartsAt, urlStartsAt + 2));
+    var urlEndsAt = isQuoted ?
+      importDeclaration.indexOf(isQuoted[0], urlStartsAt + 1) :
+      importDeclaration.split(' ')[0].length;
+
+    var importedFile = importDeclaration
+      .substring(urlStartsAt, urlEndsAt)
+      .replace(/['"]/g, '')
+      .replace(/\)$/, '')
+      .trim();
+
+    var mediaQuery = importDeclaration
+      .substring(urlEndsAt + 1)
+      .replace(/^\)/, '')
+      .trim();
+
+    var isRemote = options.isRemote ||
+      /^(http|https):\/\//.test(importedFile) ||
+      /^\/\//.test(importedFile);
+
+    if (options.localOnly && isRemote) {
+      context.warnings.push('Ignoring remote @import declaration of "' + importedFile + '" as no callback given.');
+      restoreImport(importedFile, mediaQuery, options);
+
+      return processNext(options);
+    }
+
+    var method = isRemote ? inlineRemoteResource : inlineLocalResource;
+    return method(importedFile, mediaQuery, options);
+  };
+
+  var inlineRemoteResource = function(importedFile, mediaQuery, options) {
+    var importedUrl = /^https?:\/\//.test(importedFile) ?
+      importedFile :
+      url.resolve(options.relativeTo, importedFile);
+
+    if (importedUrl.indexOf('//') === 0)
+      importedUrl = 'http:' + importedUrl;
+
+    if (options.visited.indexOf(importedUrl) > -1)
+      return processNext(options);
+
+
+    if (context.debug)
+      console.error('Inlining remote stylesheet: ' + importedUrl);
+
+    options.visited.push(importedUrl);
+
+    var get = importedUrl.indexOf('http://') === 0 ?
+      http.get :
+      https.get;
+
+    var timedOut = false;
+    var handleError = function(message) {
+      context.errors.push('Broken @import declaration of "' + importedUrl + '" - ' + message);
+      restoreImport(importedUrl, mediaQuery, options);
+
+      processNext(options);
+    };
+    var requestOptions = merge(url.parse(importedUrl), inlinerOptions.request);
+
+    get(requestOptions, function(res) {
+      if (res.statusCode < 200 || res.statusCode > 399) {
+        return handleError('error ' + res.statusCode);
+      } else if (res.statusCode > 299) {
+        var movedUrl = url.resolve(importedUrl, res.headers.location);
+        return inlineRemoteResource(movedUrl, mediaQuery, options);
+      }
+
+      var chunks = [];
+      var parsedUrl = url.parse(importedUrl);
+      res.on('data', function(chunk) {
+        chunks.push(chunk.toString());
+      });
+      res.on('end', function() {
+        var importedData = chunks.join('');
+        importedData = UrlRewriter.process(importedData, { toBase: importedUrl });
+
+        if (mediaQuery.length > 0)
+          importedData = '@media ' + mediaQuery + '{' + importedData + '}';
+
+        process(importedData, {
+          isRemote: true,
+          relativeTo: parsedUrl.protocol + '//' + parsedUrl.host,
+          _shared: options._shared,
+          whenDone: options.whenDone,
+          visited: options.visited
+        });
+      });
+    })
+    .on('error', function(res) {
+      handleError(res.message);
+    })
+    .on('timeout', function() {
+      // FIX: node 0.8 fires this event twice
+      if (timedOut)
+        return;
+
+      handleError('timeout');
+      timedOut = true;
+    })
+    .setTimeout(inlinerOptions.timeout);
+  };
+
+  var inlineLocalResource = function(importedFile, mediaQuery, options) {
+    var relativeTo = importedFile[0] == '/' ?
+      options.root :
+      options.relativeTo;
+
+    var fullPath = path.resolve(path.join(relativeTo, importedFile));
+
+    if (!fs.existsSync(fullPath) || !fs.statSync(fullPath).isFile()) {
+      context.errors.push('Broken @import declaration of "' + importedFile + '"');
+      return processNext(options);
+    }
+
+    if (options.visited.indexOf(fullPath) > -1)
+      return processNext(options);
+
+
+    if (context.debug)
+      console.error('Inlining local stylesheet: ' + fullPath);
+
+    options.visited.push(fullPath);
+
+    var importedData = fs.readFileSync(fullPath, 'utf8');
+    var importRelativeTo = path.dirname(fullPath);
+    importedData = UrlRewriter.process(importedData, {
+      relative: true,
+      fromBase: importRelativeTo,
+      toBase: options._baseRelativeTo
+    });
+
+    if (mediaQuery.length > 0)
+      importedData = '@media ' + mediaQuery + '{' + importedData + '}';
+
+    return process(importedData, {
+      root: options.root,
+      relativeTo: importRelativeTo,
+      _baseRelativeTo: options._baseRelativeTo,
+      _shared: options._shared,
+      visited: options.visited,
+      whenDone: options.whenDone,
+      localOnly: options.localOnly
+    });
+  };
+
+  var restoreImport = function(importedUrl, mediaQuery, options) {
+    var restoredImport = '@import url(' + importedUrl + ')' + (mediaQuery.length > 0 ? ' ' + mediaQuery : '') + ';';
+    options._shared.done.push(restoredImport);
+  };
+
+  // Inlines all imports taking care of repetitions, unknown files, and circular dependencies
+  return { process: process };
+};
+
+},{"../images/url-rewriter":8,"fs":27,"http":32,"https":36,"path":39,"url":52}],10:[function(_dereq_,module,exports){
+
+var processableInfo = _dereq_('./processable');
+var overrideCompactor = _dereq_('./override-compactor');
+var shorthandCompactor = _dereq_('./shorthand-compactor');
+
+module.exports = function Optimizer(compatibility) {
+  var overridable = {
+    'animation-delay': ['animation'],
+    'animation-direction': ['animation'],
+    'animation-duration': ['animation'],
+    'animation-fill-mode': ['animation'],
+    'animation-iteration-count': ['animation'],
+    'animation-name': ['animation'],
+    'animation-play-state': ['animation'],
+    'animation-timing-function': ['animation'],
+    '-moz-animation-delay': ['-moz-animation'],
+    '-moz-animation-direction': ['-moz-animation'],
+    '-moz-animation-duration': ['-moz-animation'],
+    '-moz-animation-fill-mode': ['-moz-animation'],
+    '-moz-animation-iteration-count': ['-moz-animation'],
+    '-moz-animation-name': ['-moz-animation'],
+    '-moz-animation-play-state': ['-moz-animation'],
+    '-moz-animation-timing-function': ['-moz-animation'],
+    '-o-animation-delay': ['-o-animation'],
+    '-o-animation-direction': ['-o-animation'],
+    '-o-animation-duration': ['-o-animation'],
+    '-o-animation-fill-mode': ['-o-animation'],
+    '-o-animation-iteration-count': ['-o-animation'],
+    '-o-animation-name': ['-o-animation'],
+    '-o-animation-play-state': ['-o-animation'],
+    '-o-animation-timing-function': ['-o-animation'],
+    '-webkit-animation-delay': ['-webkit-animation'],
+    '-webkit-animation-direction': ['-webkit-animation'],
+    '-webkit-animation-duration': ['-webkit-animation'],
+    '-webkit-animation-fill-mode': ['-webkit-animation'],
+    '-webkit-animation-iteration-count': ['-webkit-animation'],
+    '-webkit-animation-name': ['-webkit-animation'],
+    '-webkit-animation-play-state': ['-webkit-animation'],
+    '-webkit-animation-timing-function': ['-webkit-animation'],
+    'background-attachment': ['background'],
+    'background-clip': ['background'],
+    'background-color': ['background'],
+    'background-image': ['background'],
+    'background-origin': ['background'],
+    'background-position': ['background'],
+    'background-repeat': ['background'],
+    'background-size': ['background'],
+    'border-color': ['border'],
+    'border-style': ['border'],
+    'border-width': ['border'],
+    'border-bottom': ['border'],
+    'border-bottom-color': ['border-bottom', 'border-color', 'border'],
+    'border-bottom-style': ['border-bottom', 'border-style', 'border'],
+    'border-bottom-width': ['border-bottom', 'border-width', 'border'],
+    'border-left': ['border'],
+    'border-left-color': ['border-left', 'border-color', 'border'],
+    'border-left-style': ['border-left', 'border-style', 'border'],
+    'border-left-width': ['border-left', 'border-width', 'border'],
+    'border-right': ['border'],
+    'border-right-color': ['border-right', 'border-color', 'border'],
+    'border-right-style': ['border-right', 'border-style', 'border'],
+    'border-right-width': ['border-right', 'border-width', 'border'],
+    'border-top': ['border'],
+    'border-top-color': ['border-top', 'border-color', 'border'],
+    'border-top-style': ['border-top', 'border-style', 'border'],
+    'border-top-width': ['border-top', 'border-width', 'border'],
+    'font-family': ['font'],
+    'font-size': ['font'],
+    'font-style': ['font'],
+    'font-variant': ['font'],
+    'font-weight': ['font'],
+    'list-style-image': ['list'],
+    'list-style-position': ['list'],
+    'list-style-type': ['list'],
+    'margin-bottom': ['margin'],
+    'margin-left': ['margin'],
+    'margin-right': ['margin'],
+    'margin-top': ['margin'],
+    'outline-color': ['outline'],
+    'outline-style': ['outline'],
+    'outline-width': ['outline'],
+    'padding-bottom': ['padding'],
+    'padding-left': ['padding'],
+    'padding-right': ['padding'],
+    'padding-top': ['padding'],
+    'transition-delay': ['transition'],
+    'transition-duration': ['transition'],
+    'transition-property': ['transition'],
+    'transition-timing-function': ['transition'],
+    '-moz-transition-delay': ['-moz-transition'],
+    '-moz-transition-duration': ['-moz-transition'],
+    '-moz-transition-property': ['-moz-transition'],
+    '-moz-transition-timing-function': ['-moz-transition'],
+    '-o-transition-delay': ['-o-transition'],
+    '-o-transition-duration': ['-o-transition'],
+    '-o-transition-property': ['-o-transition'],
+    '-o-transition-timing-function': ['-o-transition'],
+    '-webkit-transition-delay': ['-webkit-transition'],
+    '-webkit-transition-duration': ['-webkit-transition'],
+    '-webkit-transition-property': ['-webkit-transition'],
+    '-webkit-transition-timing-function': ['-webkit-transition']
+  };
+
+  var IE_BACKSLASH_HACK = '\\9';
+
+  var overrides = {};
+  for (var granular in overridable) {
+    for (var i = 0; i < overridable[granular].length; i++) {
+      var coarse = overridable[granular][i];
+      var list = overrides[coarse];
+
+      if (list)
+        list.push(granular);
+      else
+        overrides[coarse] = [granular];
+    }
+  }
+
+  var tokenize = function(body) {
+    var tokens = body.split(';');
+    var keyValues = [];
+
+    if (tokens.length === 0 || (tokens.length == 1 && tokens[0].indexOf(IE_BACKSLASH_HACK) == -1))
+      return;
+
+    for (var i = 0, l = tokens.length; i < l; i++) {
+      var token = tokens[i];
+      if (token === '')
+        continue;
+
+      var firstColon = token.indexOf(':');
+      keyValues.push([
+        token.substring(0, firstColon),
+        token.substring(firstColon + 1),
+        token.indexOf('!important') > -1,
+        token.indexOf(IE_BACKSLASH_HACK, firstColon + 1) > 0
+      ]);
+    }
+
+    return keyValues;
+  };
+
+  var optimize = function(tokens, allowAdjacent) {
+    var merged = [];
+    var properties = [];
+    var lastProperty = null;
+    var rescanTrigger = {};
+
+    var removeOverridenBy = function(property, isImportant) {
+      var overrided = overrides[property];
+      for (var i = 0, l = overrided.length; i < l; i++) {
+        for (var j = 0; j < properties.length; j++) {
+          if (properties[j] != overrided[i] || (merged[j][2] && !isImportant))
+            continue;
+
+          merged.splice(j, 1);
+          properties.splice(j, 1);
+          j -= 1;
+        }
+      }
+    };
+
+    var mergeablePosition = function(position) {
+      if (allowAdjacent === false || allowAdjacent === true)
+        return allowAdjacent;
+
+      return allowAdjacent.indexOf(position) > -1;
+    };
+
+    tokensLoop:
+    for (var i = 0, l = tokens.length; i < l; i++) {
+      var token = tokens[i];
+      var property = token[0];
+      var isImportant = token[2];
+      var isIEHack = token[3];
+      var _property = (property == '-ms-filter' || property == 'filter') ?
+        (lastProperty == 'background' || lastProperty == 'background-image' ? lastProperty : property) :
+        property;
+      var toOverridePosition = 0;
+
+      if (!compatibility && isIEHack)
+        continue;
+
+      // comment is necessary - we assume that if two properties are one after another
+      // then it is intentional way of redefining property which may not be widely supported
+      // e.g. a{display:inline-block;display:-moz-inline-box}
+      // however if `mergeablePosition` yields true then the rule does not apply
+      // (e.g merging two adjacent selectors: `a{display:block}a{display:block}`)
+      if (_property != lastProperty || mergeablePosition(i)) {
+        while (true) {
+          toOverridePosition = properties.indexOf(_property, toOverridePosition);
+          if (toOverridePosition == -1)
+            break;
+
+          var lastToken = merged[toOverridePosition];
+          var wasImportant = lastToken[2];
+          var wasIEHack = lastToken[3];
+
+          if (wasImportant && !isImportant)
+            continue tokensLoop;
+
+          if (compatibility && !wasIEHack && isIEHack)
+            break;
+
+          merged.splice(toOverridePosition, 1);
+          properties.splice(toOverridePosition, 1);
+        }
+      }
+
+      merged.push(token);
+      properties.push(_property);
+
+      // certain properties (see values of `overridable`) should trigger removal of
+      // more granular properties (see keys of `overridable`)
+      if (rescanTrigger[_property])
+        removeOverridenBy(_property, isImportant);
+
+      // add rescan triggers - if certain property appears later in the list a rescan needs
+      // to be triggered, e.g 'border-top' triggers a rescan after 'border-top-width' and
+      // 'border-top-color' as they can be removed
+      for (var j = 0, list = overridable[_property] || [], m = list.length; j < m; j++)
+        rescanTrigger[list[j]] = true;
+
+      lastProperty = _property;
+    }
+
+    return merged;
+  };
+
+  var rebuild = function(tokens) {
+    var flat = [];
+
+
+    for (var i = 0, l = tokens.length; i < l; i++) {
+      flat.push(tokens[i][0] + ':' + tokens[i][1]);
+    }
+
+    return flat.join(';');
+  };
+
+  var compact = function (input) {
+    var processable = processableInfo.processable;
+    var Token = processableInfo.Token;
+
+    var tokens = Token.tokenize(input);
+
+    tokens = overrideCompactor.compactOverrides(tokens, processable);
+    tokens = shorthandCompactor.compactShorthands(tokens, false, processable, Token);
+    tokens = shorthandCompactor.compactShorthands(tokens, true, processable, Token);
+
+    return Token.detokenize(tokens);
+  };
+
+  return {
+    process: function(body, allowAdjacent, skipCompacting) {
+      var result = body;
+
+      var tokens = tokenize(body);
+      if (tokens) {
+        var optimized = optimize(tokens, allowAdjacent);
+        result = rebuild(optimized);
+      }
+
+      if (!skipCompacting) {
+        result = compact(result);
+      }
+
+      return result;
+    }
+  };
+};
+
+},{"./override-compactor":11,"./processable":12,"./shorthand-compactor":14}],11:[function(_dereq_,module,exports){
+
+// Compacts the given tokens according to their ability to override each other.
+
+module.exports = (function () {
+  // Default override function: only allow overrides when the two values are the same
+  var sameValue = function (val1, val2) {
+    return val1 === val2;
+  };
+
+  var compactOverrides = function (tokens, processable) {
+    var result, can, token, t, i, ii, oldResult, matchingComponent;
+
+    // Used when searching for a component that matches token
+    var nameMatchFilter1 = function (x) {
+      return x.prop === token.prop;
+    };
+    // Used when searching for a component that matches t
+    var nameMatchFilter2 = function (x) {
+      return x.prop === t.prop;
+    };
+
+    // Go from the end and always take what the current token can't override as the new result set
+    // NOTE: can't cache result.length here because it will change with every iteration
+    for (result = tokens, i = 0; (ii = result.length - 1 - i) >= 0; i++) {
+      token = result[ii];
+      can = (processable[token.prop] && processable[token.prop].canOverride) || sameValue;
+      oldResult = result;
+      result = [];
+
+      // Special flag which indicates that the current token should be removed
+      var removeSelf = false;
+      var oldResultLength = oldResult.length;
+
+      for (var iii = 0; iii < oldResultLength; iii++) {
+        t = oldResult[iii];
+
+        // A token can't override itself (checked by reference, not by value)
+        // NOTE: except when we explicitly tell it to remove itself
+        if (t === token && !removeSelf) {
+          result.push(t);
+          continue;
+        }
+
+        // Only an important token can even try to override tokens that come after it
+        if (iii > ii && !token.isImportant) {
+          result.push(t);
+          continue;
+        }
+
+        // A nonimportant token can never override an important one
+        if (t.isImportant && !token.isImportant) {
+          result.push(t);
+          continue;
+        }
+
+        if (token.isShorthand && !t.isShorthand && t.isComponentOf(token)) {
+          // token (a shorthand) is trying to override t (a component)
+
+          // Find the matching component in the shorthand
+          matchingComponent = token.components.filter(nameMatchFilter2)[0];
+          can = (processable[t.prop] && processable[t.prop].canOverride) || sameValue;
+          if (!can(t.value, matchingComponent.value)) {
+            // The shorthand can't override the component
+            result.push(t);
+          }
+        } else if (t.isShorthand && !token.isShorthand && token.isComponentOf(t)) {
+          // token (a component) is trying to override a component of t (a shorthand)
+
+          // Find the matching component in the shorthand
+          matchingComponent = t.components.filter(nameMatchFilter1)[0];
+          if (can(matchingComponent.value, token.value)) {
+            // The component can override the matching component in the shorthand
+
+            if (!token.isImportant) {
+              // The overriding component is non-important which means we can simply include it into the shorthand
+              // NOTE: stuff that can't really be included, like inherit, is taken care of at the final step, not here
+              matchingComponent.value = token.value;
+              // We use the special flag to get rid of the component
+              removeSelf = true;
+            } else {
+              // The overriding component is important; sadly we can't get rid of it,
+              // but we can still mark the matching component in the shorthand as irrelevant
+              matchingComponent.isIrrelevant = true;
+            }
+            t.isDirty = true;
+          }
+          result.push(t);
+        } else if (token.isShorthand && t.isShorthand && token.prop === t.prop) {
+          // token is a shorthand and is trying to override another instance of the same shorthand
+
+          // Can only override other shorthand when each of its components can override each of the other's components
+          for (var iiii = 0; iiii < t.components.length; iiii++) {
+            can = (processable[t.components[iiii].prop] && processable[t.components[iiii].prop].canOverride) || sameValue;
+            if (!can(t.components[iiii].value, token.components[iiii].value)) {
+              result.push(t);
+              break;
+            }
+          }
+        } else if (t.prop !== token.prop || !can(t.value, token.value)) {
+          // in every other case, use the override mechanism
+          result.push(t);
+        }
+      }
+      if (removeSelf) {
+        i--;
+      }
+    }
+
+    return result;
+  };
+
+  return {
+    compactOverrides: compactOverrides
+  };
+
+})();
+
+},{}],12:[function(_dereq_,module,exports){
+
+// Contains the interpretation of CSS properties, as used by the property optimizer
+
+
+module.exports = (function () {
+
+  var tokenModule = _dereq_('./token');
+  var validator = _dereq_('./validator');
+
+  // Functions that decide what value can override what.
+  // The main purpose is to disallow removing CSS fallbacks.
+  // A separate implementation is needed for every different kind of CSS property.
+  // -----
+  // The generic idea is that properties that have wider browser support are 'more understandable'
+  // than others and that 'less understandable' values can't override more understandable ones.
+  var canOverride = {
+    // Use when two tokens of the same property can always be merged
+    always: function () {
+      // NOTE: We could have (val1, val2) parameters here but jshint complains because we don't use them
+      return true;
+    },
+    // Use when two tokens of the same property can only be merged if they have the same value
+    sameValue: function(val1, val2) {
+      return val1 === val2;
+    },
+    sameFunctionOrValue: function(val1, val2) {
+      // Functions with the same name can override each other
+      if (validator.areSameFunction(val1, val2)) {
+        return true;
+      }
+
+      return val1 === val2;
+    },
+    // Use for properties containing CSS units (margin-top, padding-left, etc.)
+    unit: function(val1, val2) {
+      // The idea here is that 'more understandable' values override 'less understandable' values, but not vice versa
+      // Understandability: (unit without functions) > (same functions | standard functions) > anything else
+      // NOTE: there is no point in having different vendor-specific functions override each other or standard functions,
+      //       or having standard functions override vendor-specific functions, but standard functions can override each other
+      // NOTE: vendor-specific property values are not taken into consideration here at the moment
+
+      if (validator.isValidUnitWithoutFunction(val2))
+        return true;
+      if (validator.isValidUnitWithoutFunction(val1))
+        return false;
+
+      // Standard non-vendor-prefixed functions can override each other
+      if (validator.isValidFunctionWithoutVendorPrefix(val2) && validator.isValidFunctionWithoutVendorPrefix(val1)) {
+        return true;
+      }
+
+      // Functions with the same name can override each other; same values can override each other
+      return canOverride.sameFunctionOrValue(val1, val2);
+    },
+    // Use for color properties (color, background-color, border-color, etc.)
+    color: function(val1, val2) {
+      // The idea here is that 'more understandable' values override 'less understandable' values, but not vice versa
+      // Understandability: (hex | named) > (rgba | hsla) > (same function name) > anything else
+      // NOTE: at this point rgb and hsl are replaced by hex values by clean-css
+
+      // (hex | named)
+      if (validator.isValidNamedColor(val2) || validator.isValidHexColor(val2))
+        return true;
+      if (validator.isValidNamedColor(val1) || validator.isValidHexColor(val1))
+        return false;
+
+      // (rgba|hsla)
+      if (validator.isValidRgbaColor(val2) || validator.isValidHslColor(val2) || validator.isValidHslaColor(val2))
+        return true;
+      if (validator.isValidRgbaColor(val1) || validator.isValidHslColor(val1) || validator.isValidHslaColor(val1))
+        return false;
+
+      // Functions with the same name can override each other; same values can override each other
+      return canOverride.sameFunctionOrValue(val1, val2);
+    },
+    // Use for background-image
+    backgroundImage: function(val1, val2) {
+      // The idea here is that 'more understandable' values override 'less understandable' values, but not vice versa
+      // Understandability: (none | url | inherit) > (same function) > (same value)
+
+      // (none | url)
+      if (val2 === 'none' || val2 === 'inherit' || validator.isValidUrl(val2))
+        return true;
+      if (val1 === 'none' || val1 === 'inherit' || validator.isValidUrl(val1))
+        return false;
+
+      // Functions with the same name can override each other; same values can override each other
+      return canOverride.sameFunctionOrValue(val1, val2);
+    }
+  };
+  canOverride = Object.freeze(canOverride);
+
+  // Functions for breaking up shorthands to components
+  var breakUp = {};
+  breakUp.takeCareOfFourValues = function (splitfunc) {
+    return function (token) {
+      var descriptor = processable[token.prop];
+      var result = [];
+      var splitval = splitfunc(token.value);
+
+      if (splitval.length === 0 || (splitval.length < descriptor.components.length && descriptor.components.length > 4)) {
+        // This token is malformed and we have no idea how to fix it. So let's just keep it intact
+        return [token];
+      }
+
+      // Fix those that we do know how to fix
+      if (splitval.length < descriptor.components.length && splitval.length < 2) {
+        // foo{margin:1px} -> foo{margin:1px 1px}
+        splitval[1] = splitval[0];
+      }
+      if (splitval.length < descriptor.components.length && splitval.length < 3) {
+        // foo{margin:1px 2px} -> foo{margin:1px 2px 1px}
+        splitval[2] = splitval[0];
+      }
+      if (splitval.length < descriptor.components.length && splitval.length < 4) {
+        // foo{margin:1px 2px 3px} -> foo{margin:1px 2px 3px 2px}
+        splitval[3] = splitval[1];
+      }
+
+      // Now break it up to its components
+      for (var i = 0; i < descriptor.components.length; i++) {
+        var t = new Token(descriptor.components[i], splitval[i], token.isImportant);
+        result.push(t);
+      }
+
+      return result;
+    };
+  };
+  // Use this for properties with 4 unit values (like margin or padding)
+  // NOTE: it handles shorter forms of these properties too (like, only 1, 2, or 3 units)
+  breakUp.fourUnits = breakUp.takeCareOfFourValues(function (val) {
+    return val.match(new RegExp(validator.cssUnitAnyRegexStr, 'gi'));
+  });
+  // Use this when you simply want to break up four values along spaces
+  breakUp.fourBySpaces = breakUp.takeCareOfFourValues(function (val) {
+    return val.split(' ').filter(function (v) { return v; });
+  });
+  // Use this for non-length values that can also contain functions
+  breakUp.fourBySpacesOrFunctions = breakUp.takeCareOfFourValues(function (val) {
+    var result = [];
+    var curr = '';
+    var parenthesisLevel = 0;
+    var valLength = val.length;
+
+    for (var i = 0; i < valLength; i++) {
+      var c = val[i];
+      curr += c;
+
+      if (c === '(') {
+        parenthesisLevel++;
+      } else if (c === ')') {
+        parenthesisLevel--;
+        if (parenthesisLevel === 0) {
+          result.push(curr.trim());
+          curr = '';
+        }
+      } else if (c === ' ' && parenthesisLevel === 0) {
+        result.push(curr.trim());
+        curr = '';
+      }
+    }
+
+    if (curr) {
+      result.push(curr.trim());
+      curr = '';
+    }
+
+    return result;
+  });
+  // Breaks up a background property value
+  breakUp.background = function (token) {
+    // Default values
+    var result = Token.makeDefaults(['background-color', 'background-image', 'background-repeat', 'background-position', 'background-attachment'], token.isImportant);
+    var color = result[0], image = result[1], repeat = result[2], position = result[3], attachment = result[4];
+
+    // Take care of inherit
+    if (token.value === 'inherit') {
+      // NOTE: 'inherit' is not a valid value for background-attachment so there we'll leave the default value
+      color.value = image.value =  repeat.value = position.value = attachment.value = 'inherit';
+      return result;
+    }
+
+    // Break the background up into parts
+    var parts = token.value.split(' ');
+    if (parts.length === 0)
+      return result;
+
+    // The trick here is that we start going through the parts from the end, then stop after background repeat,
+    // then start from the from the beginning until we find a valid color value. What remains will be treated as background-image.
+
+    var currentIndex = parts.length - 1;
+    var current = parts[currentIndex];
+    // Attachment
+    if (validator.isValidBackgroundAttachment(current)) {
+      // Found attachment
+      attachment.value = current;
+      currentIndex--;
+      current = parts[currentIndex];
+    }
+    // Position
+    var pos = parts[currentIndex - 1] + ' ' + parts[currentIndex];
+    if (currentIndex >= 1 && validator.isValidBackgroundPosition(pos)) {
+      // Found position (containing two parts)
+      position.value = pos;
+      currentIndex -= 2;
+      current = parts[currentIndex];
+    } else if (currentIndex >= 0 && validator.isValidBackgroundPosition(current)) {
+      // Found position (containing just one part)
+      position.value = current;
+      currentIndex--;
+      current = parts[currentIndex];
+    }
+    // Repeat
+    if (currentIndex >= 0 && validator.isValidBackgroundRepeat(current)) {
+      // Found repeat
+      repeat.value = current;
+      currentIndex--;
+      current = parts[currentIndex];
+    }
+    // Color
+    var fromBeginning = 0;
+    if (validator.isValidColor(parts[0])) {
+      // Found color
+      color.value = parts[0];
+      fromBeginning = 1;
+    }
+    // Image
+    image.value = (parts.splice(fromBeginning, currentIndex - fromBeginning + 1).join(' ')) || 'none';
+
+    return result;
+  };
+  // Breaks up a list-style property value
+  breakUp.listStyle = function (token) {
+    // Default values
+    var result = Token.makeDefaults(['list-style-type', 'list-style-position', 'list-style-image'], token.isImportant);
+    var type = result[0], position = result[1], image = result[2];
+
+    if (token.value === 'inherit') {
+      type.value = position.value = image.value = 'inherit';
+      return result;
+    }
+
+    var parts = token.value.split(' ');
+    var ci = 0;
+
+    // Type
+    if (ci < parts.length && validator.isValidListStyleType(parts[ci])) {
+      type.value = parts[ci];
+      ci++;
+    }
+    // Position
+    if (ci < parts.length && validator.isValidListStylePosition(parts[ci])) {
+      position.value = parts[ci];
+      ci++;
+    }
+    // Image
+    if (ci < parts.length) {
+      image.value = parts.splice(ci, parts.length - ci + 1).join(' ');
+    }
+
+    return result;
+  };
+  // Breaks up outline
+  breakUp.outline = function (token) {
+    // Default values
+    var result = Token.makeDefaults(['outline-color', 'outline-style', 'outline-width'], token.isImportant);
+    var color = result[0], style = result[1], width = result[2];
+
+    // Take care of inherit
+    if (token.value === 'inherit' || token.value === 'inherit inherit inherit') {
+      color.value = style.value = width.value = 'inherit';
+      return result;
+    }
+
+    // NOTE: usually users don't follow the required order of parts in this shorthand,
+    // so we'll try to parse it caring as little about order as possible
+
+    var parts = token.value.split(' '), w;
+
+    if (parts.length === 0) {
+      return result;
+    }
+
+    if (parts.length >= 1) {
+      // Try to find outline-width, excluding inherit because that can be anything
+      w = parts.filter(function(p) { return p !== 'inherit' && validator.isValidOutlineWidth(p); });
+      if (w.length) {
+        width.value = w[0];
+        parts.splice(parts.indexOf(w[0]), 1);
+      }
+    }
+    if (parts.length >= 1) {
+      // Try to find outline-style, excluding inherit because that can be anything
+      w = parts.filter(function(p) { return p !== 'inherit' && validator.isValidOutlineStyle(p); });
+      if (w.length) {
+        style.value = w[0];
+        parts.splice(parts.indexOf(w[0]), 1);
+      }
+    }
+    if (parts.length >= 1) {
+      // Find outline-color but this time can catch inherit
+      w = parts.filter(function(p) { return validator.isValidOutlineColor(p); });
+      if (w.length) {
+        color.value = w[0];
+        parts.splice(parts.indexOf(w[0]), 1);
+      }
+    }
+
+    return result;
+  };
+
+  // Contains functions that can put together shorthands from their components
+  // NOTE: correct order of tokens is assumed inside these functions!
+  var putTogether = {
+    // Use this for properties which have four unit values (margin, padding, etc.)
+    // NOTE: optimizes to shorter forms too (that only specify 1, 2, or 3 values)
+    fourUnits: function (prop, tokens, isImportant) {
+      // See about irrelevant tokens
+      // NOTE: This will enable some crazy optimalizations for us.
+      if (tokens[0].isIrrelevant)
+        tokens[0].value = tokens[2].value;
+      if (tokens[2].isIrrelevant)
+        tokens[2].value = tokens[0].value;
+      if (tokens[1].isIrrelevant)
+        tokens[1].value = tokens[3].value;
+      if (tokens[3].isIrrelevant)
+        tokens[3].value = tokens[1].value;
+
+      if (tokens[0].isIrrelevant && tokens[2].isIrrelevant) {
+        if (tokens[1].value === tokens[3].value)
+          tokens[0].value = tokens[2].value = tokens[1].value;
+        else
+          tokens[0].value = tokens[2].value = '0';
+      }
+      if (tokens[1].isIrrelevant && tokens[3].isIrrelevant) {
+        if (tokens[0].value === tokens[2].value)
+          tokens[1].value = tokens[3].value = tokens[0].value;
+        else
+          tokens[1].value = tokens[3].value = '0';
+      }
+
+      var result = new Token(prop, tokens[0].value, isImportant);
+      result.granularValues = [];
+      result.granularValues[tokens[0].prop] = tokens[0].value;
+      result.granularValues[tokens[1].prop] = tokens[1].value;
+      result.granularValues[tokens[2].prop] = tokens[2].value;
+      result.granularValues[tokens[3].prop] = tokens[3].value;
+
+      // If all of them are irrelevant
+      if (tokens[0].isIrrelevant && tokens[1].isIrrelevant && tokens[2].isIrrelevant && tokens[3].isIrrelevant) {
+        result.value = processable[prop].shortestValue || processable[prop].defaultValue;
+        return result;
+      }
+
+      // 1-value short form: all four components are equal
+      if (tokens[0].value === tokens[1].value && tokens[0].value === tokens[2].value && tokens[0].value === tokens[3].value) {
+        return result;
+      }
+      result.value += ' ' + tokens[1].value;
+      // 2-value short form: first and third; second and fourth values are equal
+      if (tokens[0].value === tokens[2].value && tokens[1].value === tokens[3].value) {
+        return result;
+      }
+      result.value += ' ' + tokens[2].value;
+      // 3-value short form: second and fourth values are equal
+      if (tokens[1].value === tokens[3].value) {
+        return result;
+      }
+      // 4-value form (none of the above optimalizations could be accomplished)
+      result.value += ' ' + tokens[3].value;
+      return result;
+    },
+    // Puts together the components by spaces and omits default values (this is the case for most shorthands)
+    bySpacesOmitDefaults: function (prop, tokens, isImportant) {
+      var result = new Token(prop, '', isImportant);
+      // Get irrelevant tokens
+      var irrelevantTokens = tokens.filter(function (t) { return t.isIrrelevant; });
+
+      // If every token is irrelevant, return shortest possible value, fallback to default value
+      if (irrelevantTokens.length === tokens.length) {
+        result.isIrrelevant = true;
+        result.value = processable[prop].shortestValue || processable[prop].defaultValue;
+        return result;
+      }
+
+      // This will be the value of the shorthand if all the components are default
+      var valueIfAllDefault = processable[prop].defaultValue;
+
+      // Go through all tokens and concatenate their values as necessary
+      for (var i = 0; i < tokens.length; i++) {
+        var token = tokens[i];
+
+        // Set granular value so that other parts of the code can use this for optimalization opportunities
+        result.granularValues = result.granularValues || { };
+        result.granularValues[token.prop] = token.value;
+
+        // Use irrelevant tokens for optimalization opportunity
+        if (token.isIrrelevant) {
+          // Get shortest possible value, fallback to default value
+          var tokenShortest = processable[token.prop].shortestValue || processable[token.prop].defaultValue;
+          // If the shortest possible value of this token is shorter than the default value of the shorthand, use it instead
+          if (tokenShortest.length < valueIfAllDefault.length) {
+            valueIfAllDefault = tokenShortest;
+          }
+        }
+
+        // Omit default / irrelevant value
+        if (token.isIrrelevant || (processable[token.prop] && processable[token.prop].defaultValue === token.value)) {
+          continue;
+        }
+
+        result.value += ' ' + token.value;
+      }
+
+      result.value = result.value.trim();
+      if (!result.value) {
+        result.value = valueIfAllDefault;
+      }
+
+      return result;
+    },
+    // Handles the cases when some or all the fine-grained properties are set to inherit
+    takeCareOfInherit: function (innerFunc) {
+      return function (prop, tokens, isImportant) {
+        // Filter out the inheriting and non-inheriting tokens in one iteration
+        var inheritingTokens = [];
+        var nonInheritingTokens = [];
+        var result2Shorthandable = [];
+        var i;
+        for (i = 0; i < tokens.length; i++) {
+          if (tokens[i].value === 'inherit') {
+            inheritingTokens.push(tokens[i]);
+
+            // Indicate that this property is irrelevant and its value can safely be set to anything else
+            var r2s = new Token(tokens[i].prop, tokens[i].isImportant);
+            r2s.isIrrelevant = true;
+            result2Shorthandable.push(r2s);
+          } else {
+            nonInheritingTokens.push(tokens[i]);
+            result2Shorthandable.push(tokens[i]);
+          }
+        }
+
+        if (nonInheritingTokens.length === 0) {
+          // When all the tokens are 'inherit'
+          return new Token(prop, 'inherit', isImportant);
+        } else if (inheritingTokens.length > 0) {
+          // When some (but not all) of the tokens are 'inherit'
+
+          // Result 1. Shorthand just the inherit values and have it overridden with the non-inheriting ones
+          var result1 = [new Token(prop, 'inherit', isImportant)].concat(nonInheritingTokens);
+
+          // Result 2. Shorthand every non-inherit value and then have it overridden with the inheriting ones
+          var result2 = [innerFunc(prop, result2Shorthandable, isImportant)].concat(inheritingTokens);
+
+          // Return whichever is shorter
+          var dl1 = Token.getDetokenizedLength(result1);
+          var dl2 = Token.getDetokenizedLength(result2);
+
+          return dl1 < dl2 ? result1 : result2;
+        } else {
+          // When none of tokens are 'inherit'
+          return innerFunc(prop, tokens, isImportant);
+        }
+      };
+    }
+  };
+
+  // Properties to process
+  // Extend this object in order to add support for more properties in the optimizer.
+  //
+  // Each key in this object represents a CSS property and should be an object.
+  // Such an object contains properties that describe how the represented CSS property should be handled.
+  // Possible options:
+  //
+  // * components: array (Only specify for shorthand properties.)
+  //   Contains the names of the granular properties this shorthand compacts.
+  //
+  // * canOverride: function (Default is canOverride.sameValue - meaning that they'll only be merged if they have the same value.)
+  //   Returns whether two tokens of this property can be merged with each other.
+  //   This property has no meaning for shorthands.
+  //
+  // * defaultValue: string
+  //   Specifies the default value of the property according to the CSS standard.
+  //   For shorthand, this is used when every component is set to its default value, therefore it should be the shortest possible default value of all the components.
+  //
+  // * shortestValue: string
+  //   Specifies the shortest possible value the property can possibly have.
+  //   (Falls back to defaultValue if unspecified.)
+  //
+  // * breakUp: function (Only specify for shorthand properties.)
+  //   Breaks the shorthand up to its components.
+  //
+  // * putTogether: function (Only specify for shorthand properties.)
+  //   Puts the shorthand together from its components.
+  //
+  var processable = {
+    'color': {
+      canOverride: canOverride.color,
+      defaultValue: 'transparent',
+      shortestValue: 'red'
+    },
+    // background ------------------------------------------------------------------------------
+    'background': {
+      components: [
+        'background-color',
+        'background-image',
+        'background-repeat',
+        'background-position',
+        'background-attachment'
+      ],
+      breakUp: breakUp.background,
+      putTogether: putTogether.takeCareOfInherit(putTogether.bySpacesOmitDefaults),
+      defaultValue: '0 0',
+      shortestValue: '0'
+    },
+    'background-color': {
+      canOverride: canOverride.color,
+      defaultValue: 'transparent',
+      shortestValue: 'red'
+    },
+    'background-image': {
+      canOverride: canOverride.backgroundImage,
+      defaultValue: 'none'
+    },
+    'background-repeat': {
+      canOverride: canOverride.always,
+      defaultValue: 'repeat'
+    },
+    'background-position': {
+      canOverride: canOverride.always,
+      defaultValue: '0 0',
+      shortestValue: '0'
+    },
+    'background-attachment': {
+      canOverride: canOverride.always,
+      defaultValue: 'scroll'
+    },
+    // list-style ------------------------------------------------------------------------------
+    'list-style': {
+      components: [
+        'list-style-type',
+        'list-style-position',
+        'list-style-image'
+      ],
+      canOverride: canOverride.always,
+      breakUp: breakUp.listStyle,
+      putTogether: putTogether.takeCareOfInherit(putTogether.bySpacesOmitDefaults),
+      defaultValue: 'outside', // can't use 'disc' because that'd override default 'decimal' for <ol>
+      shortestValue: 'none'
+    },
+    'list-style-type' : {
+      canOverride: canOverride.always,
+      shortestValue: 'none',
+      defaultValue: '__hack'
+      // NOTE: we can't tell the real default value here, it's 'disc' for <ul> and 'decimal' for <ol>
+      //       -- this is a hack, but it doesn't matter because this value will be either overridden or it will disappear at the final step anyway
+    },
+    'list-style-position' : {
+      canOverride: canOverride.always,
+      defaultValue: 'outside',
+      shortestValue: 'inside'
+    },
+    'list-style-image' : {
+      canOverride: canOverride.always,
+      defaultValue: 'none'
+    },
+    // outline ------------------------------------------------------------------------------
+    'outline': {
+      components: [
+        'outline-color',
+        'outline-style',
+        'outline-width'
+      ],
+      breakUp: breakUp.outline,
+      putTogether: putTogether.takeCareOfInherit(putTogether.bySpacesOmitDefaults),
+      defaultValue: '0'
+    },
+    'outline-color': {
+      canOverride: canOverride.color,
+      defaultValue: 'invert',
+      shortestValue: 'red'
+    },
+    'outline-style': {
+      canOverride: canOverride.always,
+      defaultValue: 'none'
+    },
+    'outline-width': {
+      canOverride: canOverride.unit,
+      defaultValue: 'medium',
+      shortestValue: '0'
+    }
+  };
+
+  var addFourValueShorthand = function (prop, components, breakup, puttogether, canoverride, defaultValue, shortestValue) {
+    processable[prop] = {
+      components: components,
+      breakUp: breakup || breakUp.fourUnits,
+      putTogether: puttogether || putTogether.takeCareOfInherit(putTogether.fourUnits),
+      defaultValue: defaultValue || '0',
+      shortestValue: shortestValue
+    };
+    for (var i = 0; i < components.length; i++) {
+      processable[components[i]] = {
+        canOverride: canoverride || canOverride.unit,
+        defaultValue: defaultValue || '0',
+        shortestValue: shortestValue
+      };
+    }
+  };
+
+  addFourValueShorthand('border-radius', [
+    'border-top-left-radius',
+    'border-top-right-radius',
+    'border-bottom-right-radius',
+    'border-bottom-left-radius'
+  ]);
+
+  addFourValueShorthand('-moz-border-radius', [
+    '-moz-border-top-left-radius',
+    '-moz-border-top-right-radius',
+    '-moz-border-bottom-right-radius',
+    '-moz-border-bottom-left-radius'
+  ]);
+
+  addFourValueShorthand('-webkit-border-radius', [
+    '-webkit-border-top-left-radius',
+    '-webkit-border-top-right-radius',
+    '-webkit-border-bottom-right-radius',
+    '-webkit-border-bottom-left-radius'
+  ]);
+
+  addFourValueShorthand('-o-border-radius', [
+    '-o-border-top-left-radius',
+    '-o-border-top-right-radius',
+    '-o-border-bottom-right-radius',
+    '-o-border-bottom-left-radius'
+  ]);
+
+  addFourValueShorthand('border-color', [
+    'border-top-color',
+    'border-right-color',
+    'border-bottom-color',
+    'border-left-color'
+  ], breakUp.fourBySpacesOrFunctions, null, canOverride.color, 'currentColor', 'red');
+
+  addFourValueShorthand('border-style', [
+    'border-top-style',
+    'border-right-style',
+    'border-bottom-style',
+    'border-left-style'
+  ], breakUp.fourBySpaces, null, canOverride.always, 'none');
+
+  addFourValueShorthand('border-width', [
+    'border-top-width',
+    'border-right-width',
+    'border-bottom-width',
+    'border-left-width'
+  ], null, null, null, 'medium', '0');
+
+  addFourValueShorthand('padding', [
+    'padding-top',
+    'padding-right',
+    'padding-bottom',
+    'padding-left'
+  ]);
+
+  addFourValueShorthand('margin', [
+    'margin-top',
+    'margin-right',
+    'margin-bottom',
+    'margin-left'
+  ]);
+
+  // Set some stuff iteratively
+  for (var proc in processable) {
+    if (!processable.hasOwnProperty(proc))
+      continue;
+
+    var currDesc = processable[proc];
+
+    if (!(currDesc.components instanceof Array) || currDesc.components.length === 0)
+      continue;
+
+    currDesc.isShorthand = true;
+
+    for (var cI = 0; cI < currDesc.components.length; cI++) {
+      if (!processable[currDesc.components[cI]]) {
+        throw new Error('"' + currDesc.components[cI] + '" is defined as a component of "' + proc + '" but isn\'t defined in processable.');
+      }
+      processable[currDesc.components[cI]].componentOf = proc;
+    }
+  }
+
+  var Token = tokenModule.createTokenPrototype(processable);
+
+  return {
+    processable: processable,
+    Token: Token
+  };
+})();
+
+},{"./token":15,"./validator":16}],13:[function(_dereq_,module,exports){
+(function() {
+  var OPEN_BRACE = '{';
+  var SEMICOLON = ';';
+  var COLON = ':';
+
+  var PropertyScanner = function PropertyScanner(data) {
+    this.data = data;
+  };
+
+  PropertyScanner.prototype.nextAt = function(cursor) {
+    var lastColon = this.data.lastIndexOf(COLON, cursor);
+    var lastOpenBrace = this.data.lastIndexOf(OPEN_BRACE, cursor);
+    var lastSemicolon = this.data.lastIndexOf(SEMICOLON, cursor);
+    var startAt = Math.max(lastOpenBrace, lastSemicolon);
+
+    return this.data.substring(startAt + 1, lastColon).trim();
+  };
+
+  module.exports = PropertyScanner;
+})();
+
+},{}],14:[function(_dereq_,module,exports){
+
+// Compacts the tokens by transforming properties into their shorthand notations when possible
+
+module.exports = (function () {
+  var isHackValue = function (t) { return t.value === '__hack'; };
+
+  var compactShorthands = function(tokens, isImportant, processable, Token) {
+    // Contains the components found so far, grouped by shorthand name
+    var componentsSoFar = { };
+
+    // Initializes a prop in componentsSoFar
+    var initSoFar = function (shprop, last, clearAll) {
+      var found = {};
+      var shorthandPosition;
+
+      if (!clearAll && componentsSoFar[shprop]) {
+        for (var i = 0; i < processable[shprop].components.length; i++) {
+          var prop = processable[shprop].components[i];
+          found[prop] = [];
+
+          if (!(componentsSoFar[shprop].found[prop]))
+            continue;
+
+          for (var ii = 0; ii < componentsSoFar[shprop].found[prop].length; ii++) {
+            var comp = componentsSoFar[shprop].found[prop][ii];
+
+            if (comp.isMarkedForDeletion)
+              continue;
+
+            found[prop].push(comp);
+
+            if (comp.position && (!shorthandPosition || comp.position < shorthandPosition))
+              shorthandPosition = comp.position;
+          }
+        }
+      }
+      componentsSoFar[shprop] = {
+        lastShorthand: last,
+        found: found,
+        shorthandPosition: shorthandPosition
+      };
+    };
+
+    // Adds a component to componentsSoFar
+    var addComponentSoFar = function (token, index) {
+      var shprop = processable[token.prop].componentOf;
+      if (!componentsSoFar[shprop])
+        initSoFar(shprop);
+      if (!componentsSoFar[shprop].found[token.prop])
+        componentsSoFar[shprop].found[token.prop] = [];
+
+      // Add the newfound component to componentsSoFar
+      componentsSoFar[shprop].found[token.prop].push(token);
+
+      if (!componentsSoFar[shprop].shorthandPosition && index) {
+        // If the haven't decided on where the shorthand should go, put it in the place of this component
+        componentsSoFar[shprop].shorthandPosition = index;
+      }
+    };
+
+    // Tries to compact a prop in componentsSoFar
+    var compactSoFar = function (prop) {
+      var i;
+
+      // Check basics
+      if (!componentsSoFar[prop] || !componentsSoFar[prop].found)
+        return false;
+
+      // Find components for the shorthand
+      var components = [];
+      var realComponents = [];
+      for (i = 0; i < processable[prop].components.length; i++) {
+        // Get property name
+        var pp = processable[prop].components[i];
+
+        if (componentsSoFar[prop].found[pp] && componentsSoFar[prop].found[pp].length) {
+          // We really found it
+          var foundRealComp = componentsSoFar[prop].found[pp][0];
+          components.push(foundRealComp);
+          if (foundRealComp.isReal !== false) {
+            realComponents.push(foundRealComp);
+          }
+        } else if (componentsSoFar[prop].lastShorthand) {
+          // It's defined in the previous shorthand
+          var c = componentsSoFar[prop].lastShorthand.components[i].clone(isImportant);
+          components.push(c);
+        } else {
+          // Couldn't find this component at all
+          return false;
+        }
+      }
+
+      if (realComponents.length === 0) {
+        // Couldn't find enough components, sorry
+        return false;
+      }
+
+      if (realComponents.length === processable[prop].components.length) {
+        // When all the components are from real values, only allow shorthanding if their understandability allows it
+        // This is the case when every component can override their default values, or when all of them use the same function
+
+        var canOverrideDefault = true;
+        var functionNameMatches = true;
+        var functionName;
+
+        for (var ci = 0; ci < realComponents.length; ci++) {
+          var rc = realComponents[ci];
+
+          if (!processable[rc.prop].canOverride(processable[rc.prop].defaultValue, rc.value)) {
+            canOverrideDefault = false;
+          }
+          var iop = rc.value.indexOf('(');
+          if (iop >= 0) {
+            var otherFunctionName = rc.value.substring(0, iop);
+            if (functionName)
+              functionNameMatches = functionNameMatches && otherFunctionName === functionName;
+            else
+              functionName = otherFunctionName;
+          }
+        }
+
+        if (!canOverrideDefault || !functionNameMatches)
+          return false;
+      }
+
+      // Compact the components into a shorthand
+      var compacted = processable[prop].putTogether(prop, components, isImportant);
+      if (!(compacted instanceof Array)) {
+        compacted = [compacted];
+      }
+
+      var compactedLength = Token.getDetokenizedLength(compacted);
+      var authenticLength = Token.getDetokenizedLength(realComponents);
+
+      if (realComponents.length === processable[prop].components.length || compactedLength < authenticLength || components.some(isHackValue)) {
+        compacted[0].isShorthand = true;
+        compacted[0].components = processable[prop].breakUp(compacted[0]);
+
+        // Mark the granular components for deletion
+        for (i = 0; i < realComponents.length; i++) {
+          realComponents[i].isMarkedForDeletion = true;
+        }
+
+        // Mark the position of the new shorthand
+        tokens[componentsSoFar[prop].shorthandPosition].replaceWith = compacted;
+
+        // Reinitialize the thing for further compacting
+        initSoFar(prop, compacted[0]);
+        for (i = 1; i < compacted.length; i++) {
+          addComponentSoFar(compacted[i]);
+        }
+
+        // Yes, we can keep the new shorthand!
+        return true;
+      }
+
+      return false;
+    };
+
+    // Tries to compact all properties currently in componentsSoFar
+    var compactAllSoFar = function () {
+      for (var i in componentsSoFar) {
+        if (componentsSoFar.hasOwnProperty(i)) {
+          while (compactSoFar(i)) { }
+        }
+      }
+    };
+
+    var i, token;
+
+    // Go through each token and collect components for each shorthand as we go on
+    for (i = 0; i < tokens.length; i++) {
+      token = tokens[i];
+      if (token.isMarkedForDeletion) {
+        continue;
+      }
+      if (!processable[token.prop]) {
+        // We don't know what it is, move on
+        continue;
+      }
+      if (processable[token.prop].isShorthand) {
+        // Found an instance of a full shorthand
+        // NOTE: we should NOT mix together tokens that come before and after the shorthands
+
+        if (token.isImportant === isImportant || (token.isImportant && !isImportant)) {
+          // Try to compact what we've found so far
+          while (compactSoFar(token.prop)) { }
+          // Reset
+          initSoFar(token.prop, token, true);
+        }
+
+        // TODO: when the old optimizer is removed, take care of this corner case:
+        //   div{background-color:#111;background-image:url(aaa);background:linear-gradient(aaa);background-repeat:no-repeat;background-position:1px 2px;background-attachment:scroll}
+        //   -> should not be shorthanded / minified at all because the result wouldn't be equivalent to the original in any browser
+      } else if (processable[token.prop].componentOf) {
+        // Found a component of a shorthand
+        if (token.isImportant === isImportant) {
+          // Same importantness
+          token.position = i;
+          addComponentSoFar(token, i);
+        } else if (!isImportant && token.isImportant) {
+          // Use importants for optimalization opportunities
+          // https://github.com/GoalSmashers/clean-css/issues/184
+          var importantTrickComp = new Token(token.prop, token.value, isImportant);
+          importantTrickComp.isIrrelevant = true;
+          importantTrickComp.isReal = false;
+          addComponentSoFar(importantTrickComp);
+        }
+      } else {
+        // This is not a shorthand and not a component, don't care about it
+        continue;
+      }
+    }
+
+    // Perform all possible compactions
+    compactAllSoFar();
+
+    // Process the results - throw away stuff marked for deletion, insert compacted things, etc.
+    var result = [];
+    for (i = 0; i < tokens.length; i++) {
+      token = tokens[i];
+
+      if (token.replaceWith) {
+        for (var ii = 0; ii < token.replaceWith.length; ii++) {
+          result.push(token.replaceWith[ii]);
+        }
+      }
+      if (!token.isMarkedForDeletion) {
+        result.push(token);
+      }
+
+      token.isMarkedForDeletion = false;
+      token.replaceWith = null;
+    }
+
+    return result;
+  };
+
+  return {
+    compactShorthands: compactShorthands
+  };
+
+})();
+
+},{}],15:[function(_dereq_,module,exports){
+
+// Helper for tokenizing the contents of a CSS selector block
+
+module.exports = (function() {
+  var createTokenPrototype = function (processable) {
+    var important = '!important';
+
+    // Constructor for tokens
+    function Token (prop, p2, p3) {
+      this.prop = prop;
+      if (typeof(p2) === 'string') {
+        this.value = p2;
+        this.isImportant = p3;
+      }
+      else {
+        this.value = processable[prop].defaultValue;
+        this.isImportant = p2;
+      }
+    }
+
+    Token.prototype.prop = null;
+    Token.prototype.value = null;
+    Token.prototype.granularValues = null;
+    Token.prototype.components = null;
+    Token.prototype.position = null;
+    Token.prototype.isImportant = false;
+    Token.prototype.isDirty = false;
+    Token.prototype.isShorthand = false;
+    Token.prototype.isIrrelevant = false;
+    Token.prototype.isReal = true;
+    Token.prototype.isMarkedForDeletion = false;
+
+    // Tells if this token is a component of the other one
+    Token.prototype.isComponentOf = function (other) {
+      if (!processable[this.prop] || !processable[other.prop])
+        return false;
+      if (!(processable[other.prop].components instanceof Array) || !processable[other.prop].components.length)
+        return false;
+
+      return processable[other.prop].components.indexOf(this.prop) >= 0;
+    };
+
+    // Clones a token
+    Token.prototype.clone = function (isImportant) {
+      var token = new Token(this.prop, this.value, (typeof(isImportant) !== 'undefined' ? isImportant : this.isImportant));
+      return token;
+    };
+
+    // Creates an irrelevant token with the same prop
+    Token.prototype.cloneIrrelevant = function (isImportant) {
+      var token = Token.makeDefault(this.prop, (typeof(isImportant) !== 'undefined' ? isImportant : this.isImportant));
+      token.isIrrelevant = true;
+      return token;
+    };
+
+    // Creates an array of property tokens with their default values
+    Token.makeDefaults = function (props, important) {
+      return props.map(function(prop) {
+        return new Token(prop, important);
+      });
+    };
+
+    // Parses one CSS property declaration into a token
+    Token.tokenizeOne = function (fullProp) {
+      // Find first colon
+      var colonPos = fullProp.indexOf(':');
+
+      if (colonPos < 0) {
+        // This property doesn't have a colon, it's invalid. Let's keep it intact anyway.
+        return new Token('', fullProp);
+      }
+
+      // Parse parts of the property
+      var prop = fullProp.substr(0, colonPos).trim();
+      var value = fullProp.substr(colonPos + 1).trim();
+      var isImportant = false;
+      var importantPos = value.indexOf(important);
+
+      // Check if the property is important
+      if (importantPos >= 1 && importantPos === value.length - important.length) {
+        value = value.substr(0, importantPos).trim();
+        isImportant = true;
+      }
+
+      // Return result
+      var result = new Token(prop, value, isImportant);
+
+      // If this is a shorthand, break up its values
+      // NOTE: we need to do this for all shorthands because otherwise we couldn't remove default values from them
+      if (processable[prop] && processable[prop].isShorthand) {
+        result.isShorthand = true;
+        result.components = processable[prop].breakUp(result);
+        result.isDirty = true;
+      }
+
+      return result;
+    };
+
+    // Breaks up a string of CSS property declarations into tokens so that they can be handled more easily
+    Token.tokenize = function (input) {
+      // Split the input by semicolons and parse the parts
+      var tokens = input.split(';').map(Token.tokenizeOne);
+      return tokens;
+    };
+
+    // Transforms tokens back into CSS properties
+    Token.detokenize = function (tokens) {
+      // If by mistake the input is not an array, make it an array
+      if (!(tokens instanceof Array)) {
+        tokens = [tokens];
+      }
+
+      // This step takes care of putting together the components of shorthands
+      // NOTE: this is necessary to do for every shorthand, otherwise we couldn't remove their default values
+      for (var i = 0; i < tokens.length; i++) {
+        var t = tokens[i];
+        if (t.isShorthand && t.isDirty) {
+          var news = processable[t.prop].putTogether(t.prop, t.components, t.isImportant);
+          Array.prototype.splice.apply(tokens, [i, 1].concat(news));
+          t.isDirty = false;
+          i--;
+        }
+      }
+
+      // And now, simply map every token into its string representation and concat them with a semicolon
+      var str = tokens.map(function(token) {
+        var result = '';
+
+        // NOTE: malformed tokens will not have a 'prop' property
+        if (token.prop) {
+          result += token.prop + ':';
+        }
+        if (token.value) {
+          result += token.value;
+        }
+        if (token.isImportant) {
+          result += important;
+        }
+
+        return result;
+      }).join(';');
+
+      return str;
+    };
+
+    // Gets the final (detokenized) length of the given tokens
+    Token.getDetokenizedLength = function (tokens) {
+      // If by mistake the input is not an array, make it an array
+      if (!(tokens instanceof Array)) {
+        tokens = [tokens];
+      }
+
+      var result = 0;
+
+      // This step takes care of putting together the components of shorthands
+      // NOTE: this is necessary to do for every shorthand, otherwise we couldn't remove their default values
+      for (var i = 0; i < tokens.length; i++) {
+        var t = tokens[i];
+        if (t.isShorthand && t.isDirty) {
+          var news = processable[t.prop].putTogether(t.prop, t.components, t.isImportant);
+          Array.prototype.splice.apply(tokens, [i, 1].concat(news));
+          t.isDirty = false;
+          i--;
+          continue;
+        }
+
+        if (t.prop) {
+          result += t.prop.length + 1;
+        }
+        if (t.value) {
+          result += t.value.length;
+        }
+        if (t.isImportant) {
+          result += important.length;
+        }
+      }
+
+      return result;
+    };
+
+    return Token;
+  };
+
+  return {
+    createTokenPrototype: createTokenPrototype
+  };
+
+})();
+
+},{}],16:[function(_dereq_,module,exports){
+
+// Validates various CSS property values
+
+module.exports = (function () {
+  // Regexes used for stuff
+  var cssUnitRegexStr = '(\\-?\\.?\\d+\\.?\\d*(px|%|em|rem|in|cm|mm|ex|pt|pc|)|auto|inherit)';
+  var cssFunctionNoVendorRegexStr = '[A-Z]+(\\-|[A-Z]|[0-9])+\\(([A-Z]|[0-9]|\\ |\\,|\\#|\\+|\\-|\\%|\\.)*\\)';
+  var cssFunctionVendorRegexStr = '\\-(\\-|[A-Z]|[0-9])+\\(([A-Z]|[0-9]|\\ |\\,|\\#|\\+|\\-|\\%|\\.)*\\)';
+  var cssFunctionAnyRegexStr = '(' + cssFunctionNoVendorRegexStr + '|' + cssFunctionVendorRegexStr + ')';
+  var cssUnitAnyRegexStr = '(' + cssUnitRegexStr + '|' + cssFunctionNoVendorRegexStr + '|' + cssFunctionVendorRegexStr + ')';
+
+  var backgroundRepeatKeywords = ['repeat', 'no-repeat', 'repeat-x', 'repeat-y', 'inherit'];
+  var backgroundAttachmentKeywords = ['inherit', 'scroll', 'fixed', 'local'];
+  var backgroundPositionKeywords = ['center', 'top', 'bottom', 'left', 'right'];
+  var listStyleTypeKeywords = ['armenian', 'circle', 'cjk-ideographic', 'decimal', 'decimal-leading-zero', 'disc', 'georgian', 'hebrew', 'hiragana', 'hiragana-iroha', 'inherit', 'katakana', 'katakana-iroha', 'lower-alpha', 'lower-greek', 'lower-latin', 'lower-roman', 'none', 'square', 'upper-alpha', 'upper-latin', 'upper-roman'];
+  var listStylePositionKeywords = ['inside', 'outside', 'inherit'];
+  var outlineStyleKeywords = ['inherit', 'hidden', 'none', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset'];
+  var outlineWidthKeywords = ['thin', 'thick', 'medium', 'inherit'];
+
+  var validator = {
+    isValidHexColor: function (s) {
+      return (s.length === 4 || s.length === 7) && s[0] === '#';
+    },
+    isValidRgbaColor: function (s) {
+      s = s.split(' ').join('');
+      return s.length > 0 && s.indexOf('rgba(') === 0 && s.indexOf(')') === s.length - 1;
+    },
+    isValidHslaColor: function (s) {
+      s = s.split(' ').join('');
+      return s.length > 0 && s.indexOf('hsla(') === 0 && s.indexOf(')') === s.length - 1;
+    },
+    isValidNamedColor: function (s) {
+      // We don't really check if it's a valid color value, but allow any letters in it
+      return s !== 'auto' && (s === 'transparent' || s === 'inherit' || /^[a-zA-Z]+$/.test(s));
+    },
+    isValidColor: function (s) {
+      return validator.isValidNamedColor(s) || validator.isValidHexColor(s) || validator.isValidRgbaColor(s) || validator.isValidHslaColor(s);
+    },
+    isValidUrl: function (s) {
+      // NOTE: at this point all URLs are replaced with placeholders by clean-css, so we check for those placeholders
+      return s.indexOf('__ESCAPED_URL_CLEAN_CSS') === 0;
+    },
+    isValidUnit: function (s) {
+      return new RegExp('^' + cssUnitAnyRegexStr + '$', 'gi').test(s);
+    },
+    isValidUnitWithoutFunction: function (s) {
+      return new RegExp('^' + cssUnitRegexStr + '$', 'gi').test(s);
+    },
+    isValidFunctionWithoutVendorPrefix: function (s) {
+      return new RegExp('^' + cssFunctionNoVendorRegexStr + '$', 'gi').test(s);
+    },
+    isValidFunctionWithVendorPrefix: function (s) {
+      return new RegExp('^' + cssFunctionVendorRegexStr + '$', 'gi').test(s);
+    },
+    isValidFunction: function (s) {
+      return new RegExp('^' + cssFunctionAnyRegexStr + '$', 'gi').test(s);
+    },
+    isValidBackgroundRepeat: function (s) {
+      return backgroundRepeatKeywords.indexOf(s) >= 0;
+    },
+    isValidBackgroundAttachment: function (s) {
+      return backgroundAttachmentKeywords.indexOf(s) >= 0;
+    },
+    isValidBackgroundPositionPart: function (s) {
+      if (backgroundPositionKeywords.indexOf(s) >= 0)
+        return true;
+
+      return new RegExp('^' + cssUnitRegexStr + '$', 'gi').test(s);
+    },
+    isValidBackgroundPosition: function (s) {
+      if (s === 'inherit')
+        return true;
+
+      return s.split(' ').filter(function (p) {
+        return p !== '';
+      }).every(function(p) {
+        return validator.isValidBackgroundPositionPart(p);
+      });
+    },
+    isValidListStyleType: function (s) {
+      return listStyleTypeKeywords.indexOf(s) >= 0;
+    },
+    isValidListStylePosition: function (s) {
+      return listStylePositionKeywords.indexOf(s) >= 0;
+    },
+    isValidOutlineColor: function (s) {
+      return s === 'invert' || validator.isValidColor(s) || validator.isValidVendorPrefixedValue(s);
+    },
+    isValidOutlineStyle: function (s) {
+      return outlineStyleKeywords.indexOf(s) >= 0;
+    },
+    isValidOutlineWidth: function (s) {
+      return validator.isValidUnit(s) || outlineWidthKeywords.indexOf(s) >= 0;
+    },
+    isValidVendorPrefixedValue: function (s) {
+      return /^-([A-Za-z0-9]|-)*$/gi.test(s);
+    },
+    areSameFunction: function (a, b) {
+      if (!validator.isValidFunction(a) || !validator.isValidFunction(b)) {
+        return false;
+      }
+      var f1name = a.substring(0, a.indexOf('('));
+      var f2name = b.substring(0, b.indexOf('('));
+
+      return f1name === f2name;
+    }
+  };
+
+  validator.cssUnitRegexStr = cssUnitRegexStr;
+  validator.cssFunctionNoVendorRegexStr = cssFunctionNoVendorRegexStr;
+  validator.cssFunctionVendorRegexStr = cssFunctionVendorRegexStr;
+  validator.cssFunctionAnyRegexStr = cssFunctionAnyRegexStr;
+  validator.cssUnitAnyRegexStr = cssUnitAnyRegexStr;
+
+  return validator;
+})();
+
+},{}],17:[function(_dereq_,module,exports){
+module.exports = function EmptyRemoval(data) {
+  var stripEmpty = function(cssData) {
+    var tempData = [];
+    var nextEmpty = 0;
+    var cursor = 0;
+
+    for (; nextEmpty < cssData.length;) {
+      nextEmpty = cssData.indexOf('{}', cursor);
+      if (nextEmpty == -1)
+        break;
+
+      var startsAt = nextEmpty - 1;
+      while (cssData[startsAt] && cssData[startsAt] != '}' && cssData[startsAt] != '{' && cssData[startsAt] != ';')
+        startsAt--;
+
+      tempData.push(cssData.substring(cursor, startsAt + 1));
+      cursor = nextEmpty + 2;
+    }
+
+    return tempData.length > 0 ?
+      stripEmpty(tempData.join('') + cssData.substring(cursor, cssData.length)) :
+      cssData;
+  };
+
+  return {
+    process: function() {
+      return stripEmpty(data);
+    }
+  };
+};
+
+},{}],18:[function(_dereq_,module,exports){
+var Tokenizer = _dereq_('./tokenizer');
+var PropertyOptimizer = _dereq_('../properties/optimizer');
+
+module.exports = function Optimizer(data, context, options) {
+  var specialSelectors = {
+    '*': /\-(moz|ms|o|webkit)\-/,
+    'ie8': /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:root|:nth|:first\-of|:last|:only|:empty|:target|:checked|::selection|:enabled|:disabled|:not)/,
+    'ie7': /(\-moz\-|\-ms\-|\-o\-|\-webkit\-|:focus|:before|:after|:root|:nth|:first\-of|:last|:only|:empty|:target|:checked|::selection|:enabled|:disabled|:not)/
+  };
+
+  var minificationsMade = [];
+
+  var propertyOptimizer = new PropertyOptimizer(options.compatibility);
+
+  var cleanUpSelector = function(selectors) {
+    if (selectors.indexOf(',') == -1)
+      return selectors;
+
+    var plain = [];
+    var cursor = 0;
+    var lastComma = 0;
+    var noBrackets = selectors.indexOf('(') == -1;
+    var withinBrackets = function(idx) {
+      if (noBrackets)
+        return false;
+
+      var previousOpening = selectors.lastIndexOf('(', idx);
+      var previousClosing = selectors.lastIndexOf(')', idx);
+
+      if (previousOpening == -1)
+        return false;
+      if (previousClosing > 0 && previousClosing < idx)
+        return false;
+
+      return true;
+    };
+
+    while (true) {
+      var nextComma = selectors.indexOf(',', cursor + 1);
+      var selector;
+
+      if (nextComma === -1) {
+        nextComma = selectors.length;
+      } else if (withinBrackets(nextComma)) {
+        cursor = nextComma + 1;
+        continue;
+      }
+      selector = selectors.substring(lastComma, nextComma);
+      lastComma = cursor = nextComma + 1;
+
+      if (plain.indexOf(selector) == -1)
+        plain.push(selector);
+
+      if (nextComma === selectors.length)
+        break;
+    }
+
+    return plain.sort().join(',');
+  };
+
+  var isSpecial = function(selector) {
+    return specialSelectors[options.compatibility || '*'].test(selector);
+  };
+
+  var removeDuplicates = function(tokens) {
+    var matched = {};
+    var forRemoval = [];
+
+    for (var i = 0, l = tokens.length; i < l; i++) {
+      var token = tokens[i];
+      if (typeof token == 'string' || token.block)
+        continue;
+
+      var id = token.body + '@' + token.selector;
+      var alreadyMatched = matched[id];
+
+      if (alreadyMatched) {
+        forRemoval.push(alreadyMatched[0]);
+        alreadyMatched.unshift(i);
+      } else {
+        matched[id] = [i];
+      }
+    }
+
+    forRemoval = forRemoval.sort(function(a, b) {
+      return a > b ? 1 : -1;
+    });
+
+    for (var j = 0, n = forRemoval.length; j < n; j++) {
+      tokens.splice(forRemoval[j] - j, 1);
+    }
+
+    minificationsMade.unshift(forRemoval.length > 0);
+  };
+
+  var mergeAdjacent = function(tokens) {
+    var forRemoval = [];
+    var lastToken = { selector: null, body: null };
+
+    for (var i = 0, l = tokens.length; i < l; i++) {
+      var token = tokens[i];
+
+      if (typeof token == 'string' || token.block)
+        continue;
+
+      if (token.selector == lastToken.selector) {
+        var joinAt = [lastToken.body.split(';').length];
+        lastToken.body = propertyOptimizer.process(lastToken.body + ';' + token.body, joinAt);
+        forRemoval.push(i);
+      } else if (token.body == lastToken.body && !isSpecial(token.selector) && !isSpecial(lastToken.selector)) {
+        lastToken.selector = cleanUpSelector(lastToken.selector + ',' + token.selector);
+        forRemoval.push(i);
+      } else {
+        lastToken = token;
+      }
+    }
+
+    for (var j = 0, m = forRemoval.length; j < m; j++) {
+      tokens.splice(forRemoval[j] - j, 1);
+    }
+
+    minificationsMade.unshift(forRemoval.length > 0);
+  };
+
+  var reduceNonAdjacent = function(tokens) {
+    var candidates = {};
+    var moreThanOnce = [];
+
+    for (var i = tokens.length - 1; i >= 0; i--) {
+      var token = tokens[i];
+
+      if (typeof token == 'string' || token.block)
+        continue;
+
+      var complexSelector = token.selector;
+      var selectors = complexSelector.indexOf(',') > -1 && !isSpecial(complexSelector) ?
+        complexSelector.split(',').concat(complexSelector) : // simplification, as :not() can have commas too
+        [complexSelector];
+
+      for (var j = 0, m = selectors.length; j < m; j++) {
+        var selector = selectors[j];
+
+        if (!candidates[selector])
+          candidates[selector] = [];
+        else
+          moreThanOnce.push(selector);
+
+        candidates[selector].push({
+          where: i,
+          partial: selector != complexSelector
+        });
+      }
+    }
+
+    var reducedInSimple = _reduceSimpleNonAdjacentCases(tokens, moreThanOnce, candidates);
+    var reducedInComplex = _reduceComplexNonAdjacentCases(tokens, candidates);
+
+    minificationsMade.unshift(reducedInSimple || reducedInComplex);
+  };
+
+  var _reduceSimpleNonAdjacentCases = function(tokens, matches, positions) {
+    var reduced = false;
+
+    for (var i = 0, l = matches.length; i < l; i++) {
+      var selector = matches[i];
+      var data = positions[selector];
+
+      if (data.length < 2)
+        continue;
+
+      /* jshint loopfunc: true */
+      _reduceSelector(tokens, selector, data, {
+        filterOut: function(idx, bodies) {
+          return data[idx].partial && bodies.length === 0;
+        },
+        callback: function(token, newBody, processedCount, tokenIdx) {
+          if (!data[processedCount - tokenIdx - 1].partial) {
+            token.body = newBody.join(';');
+            reduced = true;
+          }
+        }
+      });
+    }
+
+    return reduced;
+  };
+
+  var _reduceComplexNonAdjacentCases = function(tokens, positions) {
+    var reduced = false;
+
+    allSelectors:
+    for (var complexSelector in positions) {
+      if (complexSelector.indexOf(',') == -1) // simplification, as :not() can have commas too
+        continue;
+
+      var intoPosition = positions[complexSelector].pop().where;
+      var intoToken = tokens[intoPosition];
+
+      var selectors = isSpecial(complexSelector) ?
+        [complexSelector] :
+        complexSelector.split(',');
+      var reducedBodies = [];
+
+      for (var j = 0, m = selectors.length; j < m; j++) {
+        var selector = selectors[j];
+        var data = positions[selector];
+
+        if (data.length < 2)
+          continue allSelectors;
+
+        /* jshint loopfunc: true */
+        _reduceSelector(tokens, selector, data, {
+          filterOut: function(idx) {
+            return data[idx].where < intoPosition;
+          },
+          callback: function(token, newBody, processedCount, tokenIdx) {
+            if (tokenIdx === 0)
+              reducedBodies.push(newBody.join(';'));
+          }
+        });
+
+        if (reducedBodies[reducedBodies.length - 1] != reducedBodies[0])
+          continue allSelectors;
+      }
+
+      intoToken.body = reducedBodies[0];
+      reduced = true;
+    }
+
+    return reduced;
+  };
+
+  var _reduceSelector = function(tokens, selector, data, options) {
+    var bodies = [];
+    var joinsAt = [];
+    var processedTokens = [];
+
+    for (var j = data.length - 1, m = 0; j >= 0; j--) {
+      if (options.filterOut(j, bodies))
+        continue;
+
+      var where = data[j].where;
+      var token = tokens[where];
+      var body = token.body;
+      bodies.push(body);
+      processedTokens.push(where);
+    }
+
+    for (j = 0, m = bodies.length; j < m; j++) {
+      if (bodies[j].length > 0)
+        joinsAt.push((joinsAt[j - 1] || 0) + bodies[j].split(';').length);
+    }
+
+    var optimizedBody = propertyOptimizer.process(bodies.join(';'), joinsAt, true);
+    var optimizedProperties = optimizedBody.split(';');
+
+    var processedCount = processedTokens.length;
+    var propertyIdx = optimizedProperties.length - 1;
+    var tokenIdx = processedCount - 1;
+
+    while (tokenIdx >= 0) {
+      if ((tokenIdx === 0 || bodies[tokenIdx].indexOf(optimizedProperties[propertyIdx]) > -1) && propertyIdx > -1) {
+        propertyIdx--;
+        continue;
+      }
+
+      var newBody = optimizedProperties.splice(propertyIdx + 1);
+      options.callback(tokens[processedTokens[tokenIdx]], newBody, processedCount, tokenIdx);
+
+      tokenIdx--;
+    }
+  };
+
+  var optimize = function(tokens) {
+    var noChanges = function() {
+      return minificationsMade.length > 4 &&
+        minificationsMade[0] === false &&
+        minificationsMade[1] === false;
+    };
+
+    tokens = Array.isArray(tokens) ? tokens : [tokens];
+    for (var i = 0, l = tokens.length; i < l; i++) {
+      var token = tokens[i];
+
+      if (token.selector) {
+        token.selector = cleanUpSelector(token.selector);
+        token.body = propertyOptimizer.process(token.body, false);
+      } else if (token.block) {
+        optimize(token.body);
+      }
+    }
+
+    // Run until 2 last operations do not yield any changes
+    minificationsMade = [];
+    while (true) {
+      if (noChanges())
+        break;
+      removeDuplicates(tokens);
+
+      if (noChanges())
+        break;
+      mergeAdjacent(tokens);
+
+      if (noChanges())
+        break;
+      reduceNonAdjacent(tokens);
+    }
+  };
+
+  var rebuild = function(tokens) {
+    var rebuilt = [];
+
+    tokens = Array.isArray(tokens) ? tokens : [tokens];
+    for (var i = 0, l = tokens.length; i < l; i++) {
+      var token = tokens[i];
+
+      if (typeof token == 'string') {
+        rebuilt.push(token);
+        continue;
+      }
+
+      var name = token.block || token.selector;
+      var body = token.block ? rebuild(token.body) : token.body;
+
+      if (body.length > 0)
+        rebuilt.push(name + '{' + body + '}');
+    }
+
+    return rebuilt.join(options.keepBreaks ? options.lineBreak : '');
+  };
+
+  return {
+    process: function() {
+      var tokenized = new Tokenizer(data, context).process();
+      optimize(tokenized);
+      return rebuild(tokenized);
+    }
+  };
+};
+
+},{"../properties/optimizer":10,"./tokenizer":19}],19:[function(_dereq_,module,exports){
+/* jshint latedef: false */
+
+module.exports = function Tokenizer(data, minifyContext) {
+  var chunker = new Chunker(data, 128);
+  var chunk = chunker.next();
+  var flatBlock = /^@(font\-face|page|\-ms\-viewport|\-o\-viewport|viewport)/;
+
+  var whatsNext = function(context) {
+    var cursor = context.cursor;
+    var mode = context.mode;
+    var closest;
+
+    if (chunk.length == context.cursor) {
+      if (chunker.isEmpty())
+        return null;
+
+      chunk = chunker.next();
+      context.cursor = 0;
+    }
+
+    if (mode == 'body') {
+      closest = chunk.indexOf('}', cursor);
+      return closest > -1 ?
+        [closest, 'bodyEnd'] :
+        null;
+    }
+
+    var nextSpecial = chunk.indexOf('@', context.cursor);
+    var nextEscape = mode == 'top' ? chunk.indexOf('__ESCAPED_COMMENT_CLEAN_CSS', context.cursor) : -1;
+    var nextBodyStart = chunk.indexOf('{', context.cursor);
+    var nextBodyEnd = chunk.indexOf('}', context.cursor);
+
+    closest = nextSpecial;
+    if (closest == -1 || (nextEscape > -1 && nextEscape < closest))
+      closest = nextEscape;
+    if (closest == -1 || (nextBodyStart > -1 && nextBodyStart < closest))
+      closest = nextBodyStart;
+    if (closest == -1 || (nextBodyEnd > -1 && nextBodyEnd < closest))
+      closest = nextBodyEnd;
+
+    if (closest == -1)
+      return;
+    if (nextEscape === closest)
+      return [closest, 'escape'];
+    if (nextBodyStart === closest)
+      return [closest, 'bodyStart'];
+    if (nextBodyEnd === closest)
+      return [closest, 'bodyEnd'];
+    if (nextSpecial === closest)
+      return [closest, 'special'];
+  };
+
+  var tokenize = function(context) {
+    var tokenized = [];
+
+    context = context || { cursor: 0, mode: 'top' };
+
+    while (true) {
+      var next = whatsNext(context);
+      if (!next) {
+        var whatsLeft = chunk.substring(context.cursor);
+        if (whatsLeft.length > 0) {
+          tokenized.push(whatsLeft);
+          context.cursor += whatsLeft.length;
+        }
+        break;
+      }
+
+      var nextSpecial = next[0];
+      var what = next[1];
+      var nextEnd;
+      var oldMode;
+
+      if (what == 'special') {
+        var fragment = chunk.substring(nextSpecial, context.cursor + '@font-face'.length + 1);
+        var isSingle = fragment.indexOf('@import') === 0 || fragment.indexOf('@charset') === 0;
+        if (isSingle) {
+          nextEnd = chunk.indexOf(';', nextSpecial + 1);
+          tokenized.push(chunk.substring(context.cursor, nextEnd + 1));
+
+          context.cursor = nextEnd + 1;
+        } else {
+          nextEnd = chunk.indexOf('{', nextSpecial + 1);
+          var block = chunk.substring(context.cursor, nextEnd).trim();
+
+          var isFlat = flatBlock.test(block);
+          oldMode = context.mode;
+          context.cursor = nextEnd + 1;
+          context.mode = isFlat ? 'body' : 'block';
+          var specialBody = tokenize(context);
+          context.mode = oldMode;
+
+          tokenized.push({ block: block, body: specialBody });
+        }
+      } else if (what == 'escape') {
+        nextEnd = chunk.indexOf('__', nextSpecial + 1);
+        var escaped = chunk.substring(context.cursor, nextEnd + 2);
+        tokenized.push(escaped);
+
+        context.cursor = nextEnd + 2;
+      } else if (what == 'bodyStart') {
+        var selector = chunk.substring(context.cursor, nextSpecial).trim();
+
+        oldMode = context.mode;
+        context.cursor = nextSpecial + 1;
+        context.mode = 'body';
+        var body = tokenize(context);
+        context.mode = oldMode;
+
+        tokenized.push({ selector: selector, body: body });
+      } else if (what == 'bodyEnd') {
+        // extra closing brace at the top level can be safely ignored
+        if (context.mode == 'top') {
+          var at = context.cursor;
+          var warning = chunk[context.cursor] == '}' ?
+            'Unexpected \'}\' in \'' + chunk.substring(at - 20, at + 20) + '\'. Ignoring.' :
+            'Unexpected content: \'' + chunk.substring(at, nextSpecial + 1) + '\'. Ignoring.';
+
+          minifyContext.warnings.push(warning);
+          context.cursor = nextSpecial + 1;
+          continue;
+        }
+
+        if (context.mode != 'block')
+          tokenized = chunk.substring(context.cursor, nextSpecial);
+
+        context.cursor = nextSpecial + 1;
+
+        break;
+      }
+    }
+
+    return tokenized;
+  };
+
+  return {
+    process: function() {
+      return tokenize();
+    }
+  };
+};
+
+// Divides `data` into chunks of `chunkSize` for faster processing
+var Chunker = function(data, chunkSize) {
+  var chunks = [];
+  for (var cursor = 0, dataSize = data.length; cursor < dataSize;) {
+    var nextCursor = cursor + chunkSize > dataSize ?
+      dataSize - 1 :
+      cursor + chunkSize;
+
+    if (data[nextCursor] != '}')
+      nextCursor = data.indexOf('}', nextCursor);
+    if (nextCursor == -1)
+      nextCursor = data.length - 1;
+
+    chunks.push(data.substring(cursor, nextCursor + 1));
+    cursor = nextCursor + 1;
+  }
+
+  return {
+    isEmpty: function() {
+      return chunks.length === 0;
+    },
+
+    next: function() {
+      return chunks.shift() || '';
+    }
+  };
+};
+
+},{}],20:[function(_dereq_,module,exports){
+var EscapeStore = _dereq_('./escape-store');
+
+module.exports = function Comments(keepSpecialComments, keepBreaks, lineBreak) {
+  var comments = new EscapeStore('COMMENT');
+
+  return {
+    // Strip special comments (/*! ... */) by replacing them by a special marker
+    // for further restoring. Plain comments are removed. It's done by scanning data using
+    // String#indexOf scanning instead of regexps to speed up the process.
+    escape: function(data) {
+      var tempData = [];
+      var nextStart = 0;
+      var nextEnd = 0;
+      var cursor = 0;
+
+      for (; nextEnd < data.length;) {
+        nextStart = data.indexOf('/*', cursor);
+        nextEnd = data.indexOf('*/', nextStart + 2);
+        if (nextStart == -1 || nextEnd == -1)
+          break;
+
+        tempData.push(data.substring(cursor, nextStart));
+        if (data[nextStart + 2] == '!') {
+          // in case of special comments, replace them with a placeholder
+          var comment = data.substring(nextStart, nextEnd + 2);
+          var placeholder = comments.store(comment);
+          tempData.push(placeholder);
+        }
+        cursor = nextEnd + 2;
+      }
+
+      return tempData.length > 0 ?
+        tempData.join('') + data.substring(cursor, data.length) :
+        data;
+    },
+
+    restore: function(data) {
+      var restored = 0;
+      var breakSuffix = keepBreaks ? lineBreak : '';
+
+      return data.replace(new RegExp(comments.placeholderPattern + '(' + lineBreak + '| )?', 'g'), function(match, placeholder) {
+        restored++;
+
+        switch (keepSpecialComments) {
+          case '*':
+            return comments.restore(placeholder) + breakSuffix;
+          case 1:
+          case '1':
+            return restored == 1 ?
+              comments.restore(placeholder) + breakSuffix :
+              '';
+          case 0:
+          case '0':
+            return '';
+        }
+      });
+    }
+  };
+};
+
+},{"./escape-store":21}],21:[function(_dereq_,module,exports){
+module.exports = function EscapeStore(placeholderRoot) {
+  placeholderRoot = 'ESCAPED_' + placeholderRoot + '_CLEAN_CSS';
+
+  var placeholderToData = {};
+  var dataToPlaceholder = {};
+  var count = 0;
+  var nextPlaceholder = function() {
+    return '__' + placeholderRoot + (count++) + '__';
+  };
+  var pattern = '(__' + placeholderRoot + '\\d{1,}__)';
+
+  return {
+    placeholderPattern: pattern,
+
+    placeholderRegExp: new RegExp(pattern, 'g'),
+
+    store: function(data) {
+      var placeholder = dataToPlaceholder[data];
+      if (!placeholder) {
+        placeholder = nextPlaceholder();
+        placeholderToData[placeholder] = data;
+        dataToPlaceholder[data] = placeholder;
+      }
+
+      return placeholder;
+    },
+
+    restore: function(placeholder) {
+      return placeholderToData[placeholder];
+    }
+  };
+};
+
+},{}],22:[function(_dereq_,module,exports){
+var EscapeStore = _dereq_('./escape-store');
+
+module.exports = function Expressions() {
+  var expressions = new EscapeStore('EXPRESSION');
+
+  var findEnd = function(data, start) {
+    var end = start + 'expression'.length;
+    var level = 0;
+    var quoted = false;
+
+    while (true) {
+      var next = data[end++];
+
+      if (quoted) {
+        quoted = next != '\'' && next != '"';
+      } else {
+        quoted = next == '\'' || next == '"';
+
+        if (next == '(')
+          level++;
+        if (next == ')')
+          level--;
+        if (next == '}' && level == 1) {
+          end--;
+          level--;
+        }
+      }
+
+      if (level === 0 || !next)
+        break;
+    }
+
+    return end;
+  };
+
+  return {
+    // Escapes expressions by replacing them by a special
+    // marker for further restoring. It's done via string scanning
+    // instead of regexps to speed up the process.
+    escape: function(data) {
+      var nextStart = 0;
+      var nextEnd = 0;
+      var cursor = 0;
+      var tempData = [];
+
+      for (; nextEnd < data.length;) {
+        nextStart = data.indexOf('expression(', nextEnd);
+        if (nextStart == -1)
+          break;
+
+        nextEnd = findEnd(data, nextStart);
+
+        var expression = data.substring(nextStart, nextEnd);
+        var placeholder = expressions.store(expression);
+        tempData.push(data.substring(cursor, nextStart));
+        tempData.push(placeholder);
+        cursor = nextEnd;
+      }
+
+      return tempData.length > 0 ?
+        tempData.join('') + data.substring(cursor, data.length) :
+        data;
+    },
+
+    restore: function(data) {
+      return data.replace(expressions.placeholderRegExp, expressions.restore);
+    }
+  };
+};
+
+},{"./escape-store":21}],23:[function(_dereq_,module,exports){
+(function() {
+  var EscapeStore = _dereq_('./escape-store');
+  var QuoteScanner = _dereq_('./quote-scanner');
+
+  var Free = function Free() {
+    this.matches = new EscapeStore('FREE_TEXT');
+  };
+
+  // Strip content tags by replacing them by the a special
+  // marker for further restoring. It's done via string scanning
+  // instead of regexps to speed up the process.
+  Free.prototype.escape = function(data) {
+    var self = this;
+
+    return new QuoteScanner(data).each(function(match, store) {
+      var placeholder = self.matches.store(match);
+      store.push(placeholder);
+    });
+  };
+
+  Free.prototype.restore = function(data) {
+    return data.replace(this.matches.placeholderRegExp, this.matches.restore);
+  };
+
+  module.exports = Free;
+})();
+
+},{"./escape-store":21,"./quote-scanner":25}],24:[function(_dereq_,module,exports){
+(function() {
+  var QuoteScanner = _dereq_('./quote-scanner');
+  var PropertyScanner = _dereq_('../properties/scanner');
+
+  var NameQuotes = function NameQuotes() {};
+
+  var STRIPPABLE = /^['"][a-zA-Z][a-zA-Z\d\-_]+['"]$/;
+
+  var properties = [
+    'animation',
+    '-moz-animation',
+    '-o-animation',
+    '-webkit-animation',
+    'animation-name',
+    '-moz-animation-name',
+    '-o-animation-name',
+    '-webkit-animation-name',
+    'font',
+    'font-family'
+  ];
+
+  NameQuotes.prototype.process = function(data) {
+    var scanner = new PropertyScanner(data);
+
+    return new QuoteScanner(data).each(function(match, store, cursor) {
+      var lastProperty = scanner.nextAt(cursor);
+      if (properties.indexOf(lastProperty) > -1) {
+        if (STRIPPABLE.test(match))
+          match = match.substring(1, match.length - 1);
+      }
+
+      store.push(match);
+    });
+  };
+
+  module.exports = NameQuotes;
+})();
+
+},{"../properties/scanner":13,"./quote-scanner":25}],25:[function(_dereq_,module,exports){
+(function() {
+  var QuoteScanner = function QuoteScanner(data) {
+    this.data = data;
+  };
+
+  var findNonEscapedEnd = function(data, matched, start) {
+    var end = start;
+    while (true) {
+      end = data.indexOf(matched, end);
+
+      if (end > -1 && data[end - 1] == '\\') {
+        end += 1;
+        continue;
+      } else {
+        break;
+      }
+    }
+
+    return end;
+  };
+
+  QuoteScanner.prototype.each = function(callback) {
+    var data = this.data;
+    var tempData = [];
+    var nextStart = 0;
+    var nextEnd = 0;
+    var cursor = 0;
+    var matchedMark = null;
+    var singleMark = '\'';
+    var doubleMark = '"';
+    var dataLength = data.length;
+
+    for (; nextEnd < data.length;) {
+      var nextStartSingle = data.indexOf(singleMark, nextEnd + 1);
+      var nextStartDouble = data.indexOf(doubleMark, nextEnd + 1);
+
+      if (nextStartSingle == -1)
+        nextStartSingle = dataLength;
+      if (nextStartDouble == -1)
+        nextStartDouble = dataLength;
+
+      if (nextStartSingle < nextStartDouble) {
+        nextStart = nextStartSingle;
+        matchedMark = singleMark;
+      } else {
+        nextStart = nextStartDouble;
+        matchedMark = doubleMark;
+      }
+
+      if (nextStart == -1)
+        break;
+
+      nextEnd = findNonEscapedEnd(data, matchedMark, nextStart + 1);
+      if (nextEnd == -1)
+        break;
+
+      var text = data.substring(nextStart, nextEnd + 1);
+      tempData.push(data.substring(cursor, nextStart));
+      callback(text, tempData, nextStart);
+
+      cursor = nextEnd + 1;
+    }
+
+    return tempData.length > 0 ?
+      tempData.join('') + data.substring(cursor, data.length) :
+      data;
+  };
+
+  module.exports = QuoteScanner;
+})();
+
+},{}],26:[function(_dereq_,module,exports){
+var EscapeStore = _dereq_('./escape-store');
+
+module.exports = function Urls() {
+  var urls = new EscapeStore('URL');
+
+  return {
+    // Strip urls by replacing them by a special
+    // marker for further restoring. It's done via string scanning
+    // instead of regexps to speed up the process.
+    escape: function(data) {
+      var nextStart = 0;
+      var nextEnd = 0;
+      var cursor = 0;
+      var tempData = [];
+
+      for (; nextEnd < data.length;) {
+        nextStart = data.indexOf('url(', nextEnd);
+        if (nextStart == -1)
+          break;
+
+        nextEnd = data.indexOf(')', nextStart);
+
+        var url = data.substring(nextStart, nextEnd + 1);
+        var placeholder = urls.store(url);
+        tempData.push(data.substring(cursor, nextStart));
+        tempData.push(placeholder);
+        cursor = nextEnd + 1;
+      }
+
+      return tempData.length > 0 ?
+        tempData.join('') + data.substring(cursor, data.length) :
+        data;
+    },
+
+    restore: function(data) {
+      return data.replace(urls.placeholderRegExp, function(placeholder) {
+        return urls.restore(placeholder).replace(/\s/g, '');
+      });
+    }
+  };
+};
+
+},{"./escape-store":21}],27:[function(_dereq_,module,exports){
+
+},{}],28:[function(_dereq_,module,exports){
+/**
+ * The buffer module from node.js, for the browser.
+ *
+ * Author:   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
+ * License:  MIT
+ *
+ * `npm install buffer`
+ */
+
+var base64 = _dereq_('base64-js')
+var ieee754 = _dereq_('ieee754')
+
+exports.Buffer = Buffer
+exports.SlowBuffer = Buffer
+exports.INSPECT_MAX_BYTES = 50
+Buffer.poolSize = 8192
+
+/**
+ * If `Buffer._useTypedArrays`:
+ *   === true    Use Uint8Array implementation (fastest)
+ *   === false   Use Object implementation (compatible down to IE6)
+ */
+Buffer._useTypedArrays = (function () {
+   // Detect if browser supports Typed Arrays. Supported browsers are IE 10+,
+   // Firefox 4+, Chrome 7+, Safari 5.1+, Opera 11.6+, iOS 4.2+.
+  if (typeof Uint8Array !== 'function' || typeof ArrayBuffer !== 'function')
+    return false
+
+  // Does the browser support adding properties to `Uint8Array` instances? If
+  // not, then that's the same as no `Uint8Array` support. We need to be able to
+  // add all the node Buffer API methods.
+  // Bug in Firefox 4-29, now fixed: https://bugzilla.mozilla.org/show_bug.cgi?id=695438
+  try {
+    var arr = new Uint8Array(0)
+    arr.foo = function () { return 42 }
+    return 42 === arr.foo() &&
+        typeof arr.subarray === 'function' // Chrome 9-10 lack `subarray`
+  } catch (e) {
+    return false
+  }
+})()
+
+/**
+ * Class: Buffer
+ * =============
+ *
+ * The Buffer constructor returns instances of `Uint8Array` that are augmented
+ * with function properties for all the node `Buffer` API functions. We use
+ * `Uint8Array` so that square bracket notation works as expected -- it returns
+ * a single octet.
+ *
+ * By augmenting the instances, we can avoid modifying the `Uint8Array`
+ * prototype.
+ */
+function Buffer (subject, encoding, noZero) {
+  if (!(this instanceof Buffer))
+    return new Buffer(subject, encoding, noZero)
+
+  var type = typeof subject
+
+  // Workaround: node's base64 implementation allows for non-padded strings
+  // while base64-js does not.
+  if (encoding === 'base64' && type === 'string') {
+    subject = stringtrim(subject)
+    while (subject.length % 4 !== 0) {
+      subject = subject + '='
+    }
+  }
+
+  // Find the length
+  var length
+  if (type === 'number')
+    length = coerce(subject)
+  else if (type === 'string')
+    length = Buffer.byteLength(subject, encoding)
+  else if (type === 'object')
+    length = coerce(subject.length) // Assume object is an array
+  else
+    throw new Error('First argument needs to be a number, array or string.')
+
+  var buf
+  if (Buffer._useTypedArrays) {
+    // Preferred: Return an augmented `Uint8Array` instance for best performance
+    buf = augment(new Uint8Array(length))
+  } else {
+    // Fallback: Return THIS instance of Buffer (created by `new`)
+    buf = this
+    buf.length = length
+    buf._isBuffer = true
+  }
+
+  var i
+  if (Buffer._useTypedArrays && typeof Uint8Array === 'function' &&
+      subject instanceof Uint8Array) {
+    // Speed optimization -- use set if we're copying from a Uint8Array
+    buf._set(subject)
+  } else if (isArrayish(subject)) {
+    // Treat array-ish objects as a byte array
+    for (i = 0; i < length; i++) {
+      if (Buffer.isBuffer(subject))
+        buf[i] = subject.readUInt8(i)
+      else
+        buf[i] = subject[i]
+    }
+  } else if (type === 'string') {
+    buf.write(subject, 0, encoding)
+  } else if (type === 'number' && !Buffer._useTypedArrays && !noZero) {
+    for (i = 0; i < length; i++) {
+      buf[i] = 0
+    }
+  }
+
+  return buf
+}
+
+// STATIC METHODS
+// ==============
+
+Buffer.isEncoding = function (encoding) {
+  switch (String(encoding).toLowerCase()) {
+    case 'hex':
+    case 'utf8':
+    case 'utf-8':
+    case 'ascii':
+    case 'binary':
+    case 'base64':
+    case 'raw':
+    case 'ucs2':
+    case 'ucs-2':
+    case 'utf16le':
+    case 'utf-16le':
+      return true
+    default:
+      return false
+  }
+}
+
+Buffer.isBuffer = function (b) {
+  return !!(b !== null && b !== undefined && b._isBuffer)
+}
+
+Buffer.byteLength = function (str, encoding) {
+  var ret
+  str = str + ''
+  switch (encoding || 'utf8') {
+    case 'hex':
+      ret = str.length / 2
+      break
+    case 'utf8':
+    case 'utf-8':
+      ret = utf8ToBytes(str).length
+      break
+    case 'ascii':
+    case 'binary':
+    case 'raw':
+      ret = str.length
+      break
+    case 'base64':
+      ret = base64ToBytes(str).length
+      break
+    case 'ucs2':
+    case 'ucs-2':
+    case 'utf16le':
+    case 'utf-16le':
+      ret = str.length * 2
+      break
+    default:
+      throw new Error('Unknown encoding')
+  }
+  return ret
+}
+
+Buffer.concat = function (list, totalLength) {
+  assert(isArray(list), 'Usage: Buffer.concat(list, [totalLength])\n' +
+      'list should be an Array.')
+
+  if (list.length === 0) {
+    return new Buffer(0)
+  } else if (list.length === 1) {
+    return list[0]
+  }
+
+  var i
+  if (typeof totalLength !== 'number') {
+    totalLength = 0
+    for (i = 0; i < list.length; i++) {
+      totalLength += list[i].length
+    }
+  }
+
+  var buf = new Buffer(totalLength)
+  var pos = 0
+  for (i = 0; i < list.length; i++) {
+    var item = list[i]
+    item.copy(buf, pos)
+    pos += item.length
+  }
+  return buf
+}
+
+// BUFFER INSTANCE METHODS
+// =======================
+
+function _hexWrite (buf, string, offset, length) {
+  offset = Number(offset) || 0
+  var remaining = buf.length - offset
+  if (!length) {
+    length = remaining
+  } else {
+    length = Number(length)
+    if (length > remaining) {
+      length = remaining
+    }
+  }
+
+  // must be an even number of digits
+  var strLen = string.length
+  assert(strLen % 2 === 0, 'Invalid hex string')
+
+  if (length > strLen / 2) {
+    length = strLen / 2
+  }
+  for (var i = 0; i < length; i++) {
+    var byte = parseInt(string.substr(i * 2, 2), 16)
+    assert(!isNaN(byte), 'Invalid hex string')
+    buf[offset + i] = byte
+  }
+  Buffer._charsWritten = i * 2
+  return i
+}
+
+function _utf8Write (buf, string, offset, length) {
+  var charsWritten = Buffer._charsWritten =
+    blitBuffer(utf8ToBytes(string), buf, offset, length)
+  return charsWritten
+}
+
+function _asciiWrite (buf, string, offset, length) {
+  var charsWritten = Buffer._charsWritten =
+    blitBuffer(asciiToBytes(string), buf, offset, length)
+  return charsWritten
+}
+
+function _binaryWrite (buf, string, offset, length) {
+  return _asciiWrite(buf, string, offset, length)
+}
+
+function _base64Write (buf, string, offset, length) {
+  var charsWritten = Buffer._charsWritten =
+    blitBuffer(base64ToBytes(string), buf, offset, length)
+  return charsWritten
+}
+
+function _utf16leWrite (buf, string, offset, length) {
+  var charsWritten = Buffer._charsWritten =
+    blitBuffer(utf16leToBytes(string), buf, offset, length)
+  return charsWritten
+}
+
+Buffer.prototype.write = function (string, offset, length, encoding) {
+  // Support both (string, offset, length, encoding)
+  // and the legacy (string, encoding, offset, length)
+  if (isFinite(offset)) {
+    if (!isFinite(length)) {
+      encoding = length
+      length = undefined
+    }
+  } else {  // legacy
+    var swap = encoding
+    encoding = offset
+    offset = length
+    length = swap
+  }
+
+  offset = Number(offset) || 0
+  var remaining = this.length - offset
+  if (!length) {
+    length = remaining
+  } else {
+    length = Number(length)
+    if (length > remaining) {
+      length = remaining
+    }
+  }
+  encoding = String(encoding || 'utf8').toLowerCase()
+
+  var ret
+  switch (encoding) {
+    case 'hex':
+      ret = _hexWrite(this, string, offset, length)
+      break
+    case 'utf8':
+    case 'utf-8':
+      ret = _utf8Write(this, string, offset, length)
+      break
+    case 'ascii':
+      ret = _asciiWrite(this, string, offset, length)
+      break
+    case 'binary':
+      ret = _binaryWrite(this, string, offset, length)
+      break
+    case 'base64':
+      ret = _base64Write(this, string, offset, length)
+      break
+    case 'ucs2':
+    case 'ucs-2':
+    case 'utf16le':
+    case 'utf-16le':
+      ret = _utf16leWrite(this, string, offset, length)
+      break
+    default:
+      throw new Error('Unknown encoding')
+  }
+  return ret
+}
+
+Buffer.prototype.toString = function (encoding, start, end) {
+  var self = this
+
+  encoding = String(encoding || 'utf8').toLowerCase()
+  start = Number(start) || 0
+  end = (end !== undefined)
+    ? Number(end)
+    : end = self.length
+
+  // Fastpath empty strings
+  if (end === start)
+    return ''
+
+  var ret
+  switch (encoding) {
+    case 'hex':
+      ret = _hexSlice(self, start, end)
+      break
+    case 'utf8':
+    case 'utf-8':
+      ret = _utf8Slice(self, start, end)
+      break
+    case 'ascii':
+      ret = _asciiSlice(self, start, end)
+      break
+    case 'binary':
+      ret = _binarySlice(self, start, end)
+      break
+    case 'base64':
+      ret = _base64Slice(self, start, end)
+      break
+    case 'ucs2':
+    case 'ucs-2':
+    case 'utf16le':
+    case 'utf-16le':
+      ret = _utf16leSlice(self, start, end)
+      break
+    default:
+      throw new Error('Unknown encoding')
+  }
+  return ret
+}
+
+Buffer.prototype.toJSON = function () {
+  return {
+    type: 'Buffer',
+    data: Array.prototype.slice.call(this._arr || this, 0)
+  }
+}
+
+// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
+Buffer.prototype.copy = function (target, target_start, start, end) {
+  var source = this
+
+  if (!start) start = 0
+  if (!end && end !== 0) end = this.length
+  if (!target_start) target_start = 0
+
+  // Copy 0 bytes; we're done
+  if (end === start) return
+  if (target.length === 0 || source.length === 0) return
+
+  // Fatal error conditions
+  assert(end >= start, 'sourceEnd < sourceStart')
+  assert(target_start >= 0 && target_start < target.length,
+      'targetStart out of bounds')
+  assert(start >= 0 && start < source.length, 'sourceStart out of bounds')
+  assert(end >= 0 && end <= source.length, 'sourceEnd out of bounds')
+
+  // Are we oob?
+  if (end > this.length)
+    end = this.length
+  if (target.length - target_start < end - start)
+    end = target.length - target_start + start
+
+  // copy!
+  for (var i = 0; i < end - start; i++)
+    target[i + target_start] = this[i + start]
+}
+
+function _base64Slice (buf, start, end) {
+  if (start === 0 && end === buf.length) {
+    return base64.fromByteArray(buf)
+  } else {
+    return base64.fromByteArray(buf.slice(start, end))
+  }
+}
+
+function _utf8Slice (buf, start, end) {
+  var res = ''
+  var tmp = ''
+  end = Math.min(buf.length, end)
+
+  for (var i = start; i < end; i++) {
+    if (buf[i] <= 0x7F) {
+      res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i])
+      tmp = ''
+    } else {
+      tmp += '%' + buf[i].toString(16)
+    }
+  }
+
+  return res + decodeUtf8Char(tmp)
+}
+
+function _asciiSlice (buf, start, end) {
+  var ret = ''
+  end = Math.min(buf.length, end)
+
+  for (var i = start; i < end; i++)
+    ret += String.fromCharCode(buf[i])
+  return ret
+}
+
+function _binarySlice (buf, start, end) {
+  return _asciiSlice(buf, start, end)
+}
+
+function _hexSlice (buf, start, end) {
+  var len = buf.length
+
+  if (!start || start < 0) start = 0
+  if (!end || end < 0 || end > len) end = len
+
+  var out = ''
+  for (var i = start; i < end; i++) {
+    out += toHex(buf[i])
+  }
+  return out
+}
+
+function _utf16leSlice (buf, start, end) {
+  var bytes = buf.slice(start, end)
+  var res = ''
+  for (var i = 0; i < bytes.length; i += 2) {
+    res += String.fromCharCode(bytes[i] + bytes[i+1] * 256)
+  }
+  return res
+}
+
+Buffer.prototype.slice = function (start, end) {
+  var len = this.length
+  start = clamp(start, len, 0)
+  end = clamp(end, len, len)
+
+  if (Buffer._useTypedArrays) {
+    return augment(this.subarray(start, end))
+  } else {
+    var sliceLen = end - start
+    var newBuf = new Buffer(sliceLen, undefined, true)
+    for (var i = 0; i < sliceLen; i++) {
+      newBuf[i] = this[i + start]
+    }
+    return newBuf
+  }
+}
+
+// `get` will be removed in Node 0.13+
+Buffer.prototype.get = function (offset) {
+  console.log('.get() is deprecated. Access using array indexes instead.')
+  return this.readUInt8(offset)
+}
+
+// `set` will be removed in Node 0.13+
+Buffer.prototype.set = function (v, offset) {
+  console.log('.set() is deprecated. Access using array indexes instead.')
+  return this.writeUInt8(v, offset)
+}
+
+Buffer.prototype.readUInt8 = function (offset, noAssert) {
+  if (!noAssert) {
+    assert(offset !== undefined && offset !== null, 'missing offset')
+    assert(offset < this.length, 'Trying to read beyond buffer length')
+  }
+
+  if (offset >= this.length)
+    return
+
+  return this[offset]
+}
+
+function _readUInt16 (buf, offset, littleEndian, noAssert) {
+  if (!noAssert) {
+    assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+    assert(offset !== undefined && offset !== null, 'missing offset')
+    assert(offset + 1 < buf.length, 'Trying to read beyond buffer length')
+  }
+
+  var len = buf.length
+  if (offset >= len)
+    return
+
+  var val
+  if (littleEndian) {
+    val = buf[offset]
+    if (offset + 1 < len)
+      val |= buf[offset + 1] << 8
+  } else {
+    val = buf[offset] << 8
+    if (offset + 1 < len)
+      val |= buf[offset + 1]
+  }
+  return val
+}
+
+Buffer.prototype.readUInt16LE = function (offset, noAssert) {
+  return _readUInt16(this, offset, true, noAssert)
+}
+
+Buffer.prototype.readUInt16BE = function (offset, noAssert) {
+  return _readUInt16(this, offset, false, noAssert)
+}
+
+function _readUInt32 (buf, offset, littleEndian, noAssert) {
+  if (!noAssert) {
+    assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+    assert(offset !== undefined && offset !== null, 'missing offset')
+    assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
+  }
+
+  var len = buf.length
+  if (offset >= len)
+    return
+
+  var val
+  if (littleEndian) {
+    if (offset + 2 < len)
+      val = buf[offset + 2] << 16
+    if (offset + 1 < len)
+      val |= buf[offset + 1] << 8
+    val |= buf[offset]
+    if (offset + 3 < len)
+      val = val + (buf[offset + 3] << 24 >>> 0)
+  } else {
+    if (offset + 1 < len)
+      val = buf[offset + 1] << 16
+    if (offset + 2 < len)
+      val |= buf[offset + 2] << 8
+    if (offset + 3 < len)
+      val |= buf[offset + 3]
+    val = val + (buf[offset] << 24 >>> 0)
+  }
+  return val
+}
+
+Buffer.prototype.readUInt32LE = function (offset, noAssert) {
+  return _readUInt32(this, offset, true, noAssert)
+}
+
+Buffer.prototype.readUInt32BE = function (offset, noAssert) {
+  return _readUInt32(this, offset, false, noAssert)
+}
+
+Buffer.prototype.readInt8 = function (offset, noAssert) {
+  if (!noAssert) {
+    assert(offset !== undefined && offset !== null,
+        'missing offset')
+    assert(offset < this.length, 'Trying to read beyond buffer length')
+  }
+
+  if (offset >= this.length)
+    return
+
+  var neg = this[offset] & 0x80
+  if (neg)
+    return (0xff - this[offset] + 1) * -1
+  else
+    return this[offset]
+}
+
+function _readInt16 (buf, offset, littleEndian, noAssert) {
+  if (!noAssert) {
+    assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+    assert(offset !== undefined && offset !== null, 'missing offset')
+    assert(offset + 1 < buf.length, 'Trying to read beyond buffer length')
+  }
+
+  var len = buf.length
+  if (offset >= len)
+    return
+
+  var val = _readUInt16(buf, offset, littleEndian, true)
+  var neg = val & 0x8000
+  if (neg)
+    return (0xffff - val + 1) * -1
+  else
+    return val
+}
+
+Buffer.prototype.readInt16LE = function (offset, noAssert) {
+  return _readInt16(this, offset, true, noAssert)
+}
+
+Buffer.prototype.readInt16BE = function (offset, noAssert) {
+  return _readInt16(this, offset, false, noAssert)
+}
+
+function _readInt32 (buf, offset, littleEndian, noAssert) {
+  if (!noAssert) {
+    assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+    assert(offset !== undefined && offset !== null, 'missing offset')
+    assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
+  }
+
+  var len = buf.length
+  if (offset >= len)
+    return
+
+  var val = _readUInt32(buf, offset, littleEndian, true)
+  var neg = val & 0x80000000
+  if (neg)
+    return (0xffffffff - val + 1) * -1
+  else
+    return val
+}
+
+Buffer.prototype.readInt32LE = function (offset, noAssert) {
+  return _readInt32(this, offset, true, noAssert)
+}
+
+Buffer.prototype.readInt32BE = function (offset, noAssert) {
+  return _readInt32(this, offset, false, noAssert)
+}
+
+function _readFloat (buf, offset, littleEndian, noAssert) {
+  if (!noAssert) {
+    assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+    assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
+  }
+
+  return ieee754.read(buf, offset, littleEndian, 23, 4)
+}
+
+Buffer.prototype.readFloatLE = function (offset, noAssert) {
+  return _readFloat(this, offset, true, noAssert)
+}
+
+Buffer.prototype.readFloatBE = function (offset, noAssert) {
+  return _readFloat(this, offset, false, noAssert)
+}
+
+function _readDouble (buf, offset, littleEndian, noAssert) {
+  if (!noAssert) {
+    assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+    assert(offset + 7 < buf.length, 'Trying to read beyond buffer length')
+  }
+
+  return ieee754.read(buf, offset, littleEndian, 52, 8)
+}
+
+Buffer.prototype.readDoubleLE = function (offset, noAssert) {
+  return _readDouble(this, offset, true, noAssert)
+}
+
+Buffer.prototype.readDoubleBE = function (offset, noAssert) {
+  return _readDouble(this, offset, false, noAssert)
+}
+
+Buffer.prototype.writeUInt8 = function (value, offset, noAssert) {
+  if (!noAssert) {
+    assert(value !== undefined && value !== null, 'missing value')
+    assert(offset !== undefined && offset !== null, 'missing offset')
+    assert(offset < this.length, 'trying to write beyond buffer length')
+    verifuint(value, 0xff)
+  }
+
+  if (offset >= this.length) return
+
+  this[offset] = value
+}
+
+function _writeUInt16 (buf, value, offset, littleEndian, noAssert) {
+  if (!noAssert) {
+    assert(value !== undefined && value !== null, 'missing value')
+    assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+    assert(offset !== undefined && offset !== null, 'missing offset')
+    assert(offset + 1 < buf.length, 'trying to write beyond buffer length')
+    verifuint(value, 0xffff)
+  }
+
+  var len = buf.length
+  if (offset >= len)
+    return
+
+  for (var i = 0, j = Math.min(len - offset, 2); i < j; i++) {
+    buf[offset + i] =
+        (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
+            (littleEndian ? i : 1 - i) * 8
+  }
+}
+
+Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) {
+  _writeUInt16(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) {
+  _writeUInt16(this, value, offset, false, noAssert)
+}
+
+function _writeUInt32 (buf, value, offset, littleEndian, noAssert) {
+  if (!noAssert) {
+    assert(value !== undefined && value !== null, 'missing value')
+    assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+    assert(offset !== undefined && offset !== null, 'missing offset')
+    assert(offset + 3 < buf.length, 'trying to write beyond buffer length')
+    verifuint(value, 0xffffffff)
+  }
+
+  var len = buf.length
+  if (offset >= len)
+    return
+
+  for (var i = 0, j = Math.min(len - offset, 4); i < j; i++) {
+    buf[offset + i] =
+        (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
+  }
+}
+
+Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) {
+  _writeUInt32(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) {
+  _writeUInt32(this, value, offset, false, noAssert)
+}
+
+Buffer.prototype.writeInt8 = function (value, offset, noAssert) {
+  if (!noAssert) {
+    assert(value !== undefined && value !== null, 'missing value')
+    assert(offset !== undefined && offset !== null, 'missing offset')
+    assert(offset < this.length, 'Trying to write beyond buffer length')
+    verifsint(value, 0x7f, -0x80)
+  }
+
+  if (offset >= this.length)
+    return
+
+  if (value >= 0)
+    this.writeUInt8(value, offset, noAssert)
+  else
+    this.writeUInt8(0xff + value + 1, offset, noAssert)
+}
+
+function _writeInt16 (buf, value, offset, littleEndian, noAssert) {
+  if (!noAssert) {
+    assert(value !== undefined && value !== null, 'missing value')
+    assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+    assert(offset !== undefined && offset !== null, 'missing offset')
+    assert(offset + 1 < buf.length, 'Trying to write beyond buffer length')
+    verifsint(value, 0x7fff, -0x8000)
+  }
+
+  var len = buf.length
+  if (offset >= len)
+    return
+
+  if (value >= 0)
+    _writeUInt16(buf, value, offset, littleEndian, noAssert)
+  else
+    _writeUInt16(buf, 0xffff + value + 1, offset, littleEndian, noAssert)
+}
+
+Buffer.prototype.writeInt16LE = function (value, offset, noAssert) {
+  _writeInt16(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeInt16BE = function (value, offset, noAssert) {
+  _writeInt16(this, value, offset, false, noAssert)
+}
+
+function _writeInt32 (buf, value, offset, littleEndian, noAssert) {
+  if (!noAssert) {
+    assert(value !== undefined && value !== null, 'missing value')
+    assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+    assert(offset !== undefined && offset !== null, 'missing offset')
+    assert(offset + 3 < buf.length, 'Trying to write beyond buffer length')
+    verifsint(value, 0x7fffffff, -0x80000000)
+  }
+
+  var len = buf.length
+  if (offset >= len)
+    return
+
+  if (value >= 0)
+    _writeUInt32(buf, value, offset, littleEndian, noAssert)
+  else
+    _writeUInt32(buf, 0xffffffff + value + 1, offset, littleEndian, noAssert)
+}
+
+Buffer.prototype.writeInt32LE = function (value, offset, noAssert) {
+  _writeInt32(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeInt32BE = function (value, offset, noAssert) {
+  _writeInt32(this, value, offset, false, noAssert)
+}
+
+function _writeFloat (buf, value, offset, littleEndian, noAssert) {
+  if (!noAssert) {
+    assert(value !== undefined && value !== null, 'missing value')
+    assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+    assert(offset !== undefined && offset !== null, 'missing offset')
+    assert(offset + 3 < buf.length, 'Trying to write beyond buffer length')
+    verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38)
+  }
+
+  var len = buf.length
+  if (offset >= len)
+    return
+
+  ieee754.write(buf, value, offset, littleEndian, 23, 4)
+}
+
+Buffer.prototype.writeFloatLE = function (value, offset, noAssert) {
+  _writeFloat(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeFloatBE = function (value, offset, noAssert) {
+  _writeFloat(this, value, offset, false, noAssert)
+}
+
+function _writeDouble (buf, value, offset, littleEndian, noAssert) {
+  if (!noAssert) {
+    assert(value !== undefined && value !== null, 'missing value')
+    assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+    assert(offset !== undefined && offset !== null, 'missing offset')
+    assert(offset + 7 < buf.length,
+        'Trying to write beyond buffer length')
+    verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308)
+  }
+
+  var len = buf.length
+  if (offset >= len)
+    return
+
+  ieee754.write(buf, value, offset, littleEndian, 52, 8)
+}
+
+Buffer.prototype.writeDoubleLE = function (value, offset, noAssert) {
+  _writeDouble(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeDoubleBE = function (value, offset, noAssert) {
+  _writeDouble(this, value, offset, false, noAssert)
+}
+
+// fill(value, start=0, end=buffer.length)
+Buffer.prototype.fill = function (value, start, end) {
+  if (!value) value = 0
+  if (!start) start = 0
+  if (!end) end = this.length
+
+  if (typeof value === 'string') {
+    value = value.charCodeAt(0)
+  }
+
+  assert(typeof value === 'number' && !isNaN(value), 'value is not a number')
+  assert(end >= start, 'end < start')
+
+  // Fill 0 bytes; we're done
+  if (end === start) return
+  if (this.length === 0) return
+
+  assert(start >= 0 && start < this.length, 'start out of bounds')
+  assert(end >= 0 && end <= this.length, 'end out of bounds')
+
+  for (var i = start; i < end; i++) {
+    this[i] = value
+  }
+}
+
+Buffer.prototype.inspect = function () {
+  var out = []
+  var len = this.length
+  for (var i = 0; i < len; i++) {
+    out[i] = toHex(this[i])
+    if (i === exports.INSPECT_MAX_BYTES) {
+      out[i + 1] = '...'
+      break
+    }
+  }
+  return '<Buffer ' + out.join(' ') + '>'
+}
+
+/**
+ * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.
+ * Added in Node 0.12. Only available in browsers that support ArrayBuffer.
+ */
+Buffer.prototype.toArrayBuffer = function () {
+  if (typeof Uint8Array === 'function') {
+    if (Buffer._useTypedArrays) {
+      return (new Buffer(this)).buffer
+    } else {
+      var buf = new Uint8Array(this.length)
+      for (var i = 0, len = buf.length; i < len; i += 1)
+        buf[i] = this[i]
+      return buf.buffer
+    }
+  } else {
+    throw new Error('Buffer.toArrayBuffer not supported in this browser')
+  }
+}
+
+// HELPER FUNCTIONS
+// ================
+
+function stringtrim (str) {
+  if (str.trim) return str.trim()
+  return str.replace(/^\s+|\s+$/g, '')
+}
+
+var BP = Buffer.prototype
+
+/**
+ * Augment the Uint8Array *instance* (not the class!) with Buffer methods
+ */
+function augment (arr) {
+  arr._isBuffer = true
+
+  // save reference to original Uint8Array get/set methods before overwriting
+  arr._get = arr.get
+  arr._set = arr.set
+
+  // deprecated, will be removed in node 0.13+
+  arr.get = BP.get
+  arr.set = BP.set
+
+  arr.write = BP.write
+  arr.toString = BP.toString
+  arr.toLocaleString = BP.toString
+  arr.toJSON = BP.toJSON
+  arr.copy = BP.copy
+  arr.slice = BP.slice
+  arr.readUInt8 = BP.readUInt8
+  arr.readUInt16LE = BP.readUInt16LE
+  arr.readUInt16BE = BP.readUInt16BE
+  arr.readUInt32LE = BP.readUInt32LE
+  arr.readUInt32BE = BP.readUInt32BE
+  arr.readInt8 = BP.readInt8
+  arr.readInt16LE = BP.readInt16LE
+  arr.readInt16BE = BP.readInt16BE
+  arr.readInt32LE = BP.readInt32LE
+  arr.readInt32BE = BP.readInt32BE
+  arr.readFloatLE = BP.readFloatLE
+  arr.readFloatBE = BP.readFloatBE
+  arr.readDoubleLE = BP.readDoubleLE
+  arr.readDoubleBE = BP.readDoubleBE
+  arr.writeUInt8 = BP.writeUInt8
+  arr.writeUInt16LE = BP.writeUInt16LE
+  arr.writeUInt16BE = BP.writeUInt16BE
+  arr.writeUInt32LE = BP.writeUInt32LE
+  arr.writeUInt32BE = BP.writeUInt32BE
+  arr.writeInt8 = BP.writeInt8
+  arr.writeInt16LE = BP.writeInt16LE
+  arr.writeInt16BE = BP.writeInt16BE
+  arr.writeInt32LE = BP.writeInt32LE
+  arr.writeInt32BE = BP.writeInt32BE
+  arr.writeFloatLE = BP.writeFloatLE
+  arr.writeFloatBE = BP.writeFloatBE
+  arr.writeDoubleLE = BP.writeDoubleLE
+  arr.writeDoubleBE = BP.writeDoubleBE
+  arr.fill = BP.fill
+  arr.inspect = BP.inspect
+  arr.toArrayBuffer = BP.toArrayBuffer
+
+  return arr
+}
+
+// slice(start, end)
+function clamp (index, len, defaultValue) {
+  if (typeof index !== 'number') return defaultValue
+  index = ~~index;  // Coerce to integer.
+  if (index >= len) return len
+  if (index >= 0) return index
+  index += len
+  if (index >= 0) return index
+  return 0
+}
+
+function coerce (length) {
+  // Coerce length to a number (possibly NaN), round up
+  // in case it's fractional (e.g. 123.456) then do a
+  // double negate to coerce a NaN to 0. Easy, right?
+  length = ~~Math.ceil(+length)
+  return length < 0 ? 0 : length
+}
+
+function isArray (subject) {
+  return (Array.isArray || function (subject) {
+    return Object.prototype.toString.call(subject) === '[object Array]'
+  })(subject)
+}
+
+function isArrayish (subject) {
+  return isArray(subject) || Buffer.isBuffer(subject) ||
+      subject && typeof subject === 'object' &&
+      typeof subject.length === 'number'
+}
+
+function toHex (n) {
+  if (n < 16) return '0' + n.toString(16)
+  return n.toString(16)
+}
+
+function utf8ToBytes (str) {
+  var byteArray = []
+  for (var i = 0; i < str.length; i++) {
+    var b = str.charCodeAt(i)
+    if (b <= 0x7F)
+      byteArray.push(str.charCodeAt(i))
+    else {
+      var start = i
+      if (b >= 0xD800 && b <= 0xDFFF) i++
+      var h = encodeURIComponent(str.slice(start, i+1)).substr(1).split('%')
+      for (var j = 0; j < h.length; j++)
+        byteArray.push(parseInt(h[j], 16))
+    }
+  }
+  return byteArray
+}
+
+function asciiToBytes (str) {
+  var byteArray = []
+  for (var i = 0; i < str.length; i++) {
+    // Node's code seems to be doing this and not & 0x7F..
+    byteArray.push(str.charCodeAt(i) & 0xFF)
+  }
+  return byteArray
+}
+
+function utf16leToBytes (str) {
+  var c, hi, lo
+  var byteArray = []
+  for (var i = 0; i < str.length; i++) {
+    c = str.charCodeAt(i)
+    hi = c >> 8
+    lo = c % 256
+    byteArray.push(lo)
+    byteArray.push(hi)
+  }
+
+  return byteArray
+}
+
+function base64ToBytes (str) {
+  return base64.toByteArray(str)
+}
+
+function blitBuffer (src, dst, offset, length) {
+  var pos
+  for (var i = 0; i < length; i++) {
+    if ((i + offset >= dst.length) || (i >= src.length))
+      break
+    dst[i + offset] = src[i]
+  }
+  return i
+}
+
+function decodeUtf8Char (str) {
+  try {
+    return decodeURIComponent(str)
+  } catch (err) {
+    return String.fromCharCode(0xFFFD) // UTF 8 invalid char
+  }
+}
+
+/*
+ * We have to make sure that the value is a valid integer. This means that it
+ * is non-negative. It has no fractional component and that it does not
+ * exceed the maximum allowed value.
+ */
+function verifuint (value, max) {
+  assert(typeof value === 'number', 'cannot write a non-number as a number')
+  assert(value >= 0, 'specified a negative value for writing an unsigned value')
+  assert(value <= max, 'value is larger than maximum value for type')
+  assert(Math.floor(value) === value, 'value has a fractional component')
+}
+
+function verifsint (value, max, min) {
+  assert(typeof value === 'number', 'cannot write a non-number as a number')
+  assert(value <= max, 'value larger than maximum allowed value')
+  assert(value >= min, 'value smaller than minimum allowed value')
+  assert(Math.floor(value) === value, 'value has a fractional component')
+}
+
+function verifIEEE754 (value, max, min) {
+  assert(typeof value === 'number', 'cannot write a non-number as a number')
+  assert(value <= max, 'value larger than maximum allowed value')
+  assert(value >= min, 'value smaller than minimum allowed value')
+}
+
+function assert (test, message) {
+  if (!test) throw new Error(message || 'Failed assertion')
+}
+
+},{"base64-js":29,"ieee754":30}],29:[function(_dereq_,module,exports){
+var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+
+;(function (exports) {
+       'use strict';
+
+  var Arr = (typeof Uint8Array !== 'undefined')
+    ? Uint8Array
+    : Array
+
+       var ZERO   = '0'.charCodeAt(0)
+       var PLUS   = '+'.charCodeAt(0)
+       var SLASH  = '/'.charCodeAt(0)
+       var NUMBER = '0'.charCodeAt(0)
+       var LOWER  = 'a'.charCodeAt(0)
+       var UPPER  = 'A'.charCodeAt(0)
+
+       function decode (elt) {
+               var code = elt.charCodeAt(0)
+               if (code === PLUS)
+                       return 62 // '+'
+               if (code === SLASH)
+                       return 63 // '/'
+               if (code < NUMBER)
+                       return -1 //no match
+               if (code < NUMBER + 10)
+                       return code - NUMBER + 26 + 26
+               if (code < UPPER + 26)
+                       return code - UPPER
+               if (code < LOWER + 26)
+                       return code - LOWER + 26
+       }
+
+       function b64ToByteArray (b64) {
+               var i, j, l, tmp, placeHolders, arr
+
+               if (b64.length % 4 > 0) {
+                       throw new Error('Invalid string. Length must be a multiple of 4')
+               }
+
+               // the number of equal signs (place holders)
+               // if there are two placeholders, than the two characters before it
+               // represent one byte
+               // if there is only one, then the three characters before it represent 2 bytes
+               // this is just a cheap hack to not do indexOf twice
+               var len = b64.length
+               placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0
+
+               // base64 is 4/3 + up to two characters of the original data
+               arr = new Arr(b64.length * 3 / 4 - placeHolders)
+
+               // if there are placeholders, only get up to the last complete 4 chars
+               l = placeHolders > 0 ? b64.length - 4 : b64.length
+
+               var L = 0
+
+               function push (v) {
+                       arr[L++] = v
+               }
+
+               for (i = 0, j = 0; i < l; i += 4, j += 3) {
+                       tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))
+                       push((tmp & 0xFF0000) >> 16)
+                       push((tmp & 0xFF00) >> 8)
+                       push(tmp & 0xFF)
+               }
+
+               if (placeHolders === 2) {
+                       tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)
+                       push(tmp & 0xFF)
+               } else if (placeHolders === 1) {
+                       tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)
+                       push((tmp >> 8) & 0xFF)
+                       push(tmp & 0xFF)
+               }
+
+               return arr
+       }
+
+       function uint8ToBase64 (uint8) {
+               var i,
+                       extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
+                       output = "",
+                       temp, length
+
+               function encode (num) {
+                       return lookup.charAt(num)
+               }
+
+               function tripletToBase64 (num) {
+                       return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)
+               }
+
+               // go through the array every three bytes, we'll deal with trailing stuff later
+               for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
+                       temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
+                       output += tripletToBase64(temp)
+               }
+
+               // pad the end with zeros, but make sure to not forget the extra bytes
+               switch (extraBytes) {
+                       case 1:
+                               temp = uint8[uint8.length - 1]
+                               output += encode(temp >> 2)
+                               output += encode((temp << 4) & 0x3F)
+                               output += '=='
+                               break
+                       case 2:
+                               temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])
+                               output += encode(temp >> 10)
+                               output += encode((temp >> 4) & 0x3F)
+                               output += encode((temp << 2) & 0x3F)
+                               output += '='
+                               break
+               }
+
+               return output
+       }
+
+       module.exports.toByteArray = b64ToByteArray
+       module.exports.fromByteArray = uint8ToBase64
+}())
+
+},{}],30:[function(_dereq_,module,exports){
+exports.read = function(buffer, offset, isLE, mLen, nBytes) {
+  var e, m,
+      eLen = nBytes * 8 - mLen - 1,
+      eMax = (1 << eLen) - 1,
+      eBias = eMax >> 1,
+      nBits = -7,
+      i = isLE ? (nBytes - 1) : 0,
+      d = isLE ? -1 : 1,
+      s = buffer[offset + i];
+
+  i += d;
+
+  e = s & ((1 << (-nBits)) - 1);
+  s >>= (-nBits);
+  nBits += eLen;
+  for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8);
+
+  m = e & ((1 << (-nBits)) - 1);
+  e >>= (-nBits);
+  nBits += mLen;
+  for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8);
+
+  if (e === 0) {
+    e = 1 - eBias;
+  } else if (e === eMax) {
+    return m ? NaN : ((s ? -1 : 1) * Infinity);
+  } else {
+    m = m + Math.pow(2, mLen);
+    e = e - eBias;
+  }
+  return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
+};
+
+exports.write = function(buffer, value, offset, isLE, mLen, nBytes) {
+  var e, m, c,
+      eLen = nBytes * 8 - mLen - 1,
+      eMax = (1 << eLen) - 1,
+      eBias = eMax >> 1,
+      rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0),
+      i = isLE ? 0 : (nBytes - 1),
+      d = isLE ? 1 : -1,
+      s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
+
+  value = Math.abs(value);
+
+  if (isNaN(value) || value === Infinity) {
+    m = isNaN(value) ? 1 : 0;
+    e = eMax;
+  } else {
+    e = Math.floor(Math.log(value) / Math.LN2);
+    if (value * (c = Math.pow(2, -e)) < 1) {
+      e--;
+      c *= 2;
+    }
+    if (e + eBias >= 1) {
+      value += rt / c;
+    } else {
+      value += rt * Math.pow(2, 1 - eBias);
+    }
+    if (value * c >= 2) {
+      e++;
+      c /= 2;
+    }
+
+    if (e + eBias >= eMax) {
+      m = 0;
+      e = eMax;
+    } else if (e + eBias >= 1) {
+      m = (value * c - 1) * Math.pow(2, mLen);
+      e = e + eBias;
+    } else {
+      m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
+      e = 0;
+    }
+  }
+
+  for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8);
+
+  e = (e << mLen) | m;
+  eLen += mLen;
+  for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8);
+
+  buffer[offset + i - d] |= s * 128;
+};
+
+},{}],31:[function(_dereq_,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// 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.
+
+function EventEmitter() {
+  this._events = this._events || {};
+  this._maxListeners = this._maxListeners || undefined;
+}
+module.exports = EventEmitter;
+
+// Backwards-compat with node 0.10.x
+EventEmitter.EventEmitter = EventEmitter;
+
+EventEmitter.prototype._events = undefined;
+EventEmitter.prototype._maxListeners = undefined;
+
+// By default EventEmitters will print a warning if more than 10 listeners are
+// added to it. This is a useful default which helps finding memory leaks.
+EventEmitter.defaultMaxListeners = 10;
+
+// Obviously not all Emitters should be limited to 10. This function allows
+// that to be increased. Set to zero for unlimited.
+EventEmitter.prototype.setMaxListeners = function(n) {
+  if (!isNumber(n) || n < 0 || isNaN(n))
+    throw TypeError('n must be a positive number');
+  this._maxListeners = n;
+  return this;
+};
+
+EventEmitter.prototype.emit = function(type) {
+  var er, handler, len, args, i, listeners;
+
+  if (!this._events)
+    this._events = {};
+
+  // If there is no 'error' event listener then throw.
+  if (type === 'error') {
+    if (!this._events.error ||
+        (isObject(this._events.error) && !this._events.error.length)) {
+      er = arguments[1];
+      if (er instanceof Error) {
+        throw er; // Unhandled 'error' event
+      } else {
+        throw TypeError('Uncaught, unspecified "error" event.');
+      }
+      return false;
+    }
+  }
+
+  handler = this._events[type];
+
+  if (isUndefined(handler))
+    return false;
+
+  if (isFunction(handler)) {
+    switch (arguments.length) {
+      // fast cases
+      case 1:
+        handler.call(this);
+        break;
+      case 2:
+        handler.call(this, arguments[1]);
+        break;
+      case 3:
+        handler.call(this, arguments[1], arguments[2]);
+        break;
+      // slower
+      default:
+        len = arguments.length;
+        args = new Array(len - 1);
+        for (i = 1; i < len; i++)
+          args[i - 1] = arguments[i];
+        handler.apply(this, args);
+    }
+  } else if (isObject(handler)) {
+    len = arguments.length;
+    args = new Array(len - 1);
+    for (i = 1; i < len; i++)
+      args[i - 1] = arguments[i];
+
+    listeners = handler.slice();
+    len = listeners.length;
+    for (i = 0; i < len; i++)
+      listeners[i].apply(this, args);
+  }
+
+  return true;
+};
+
+EventEmitter.prototype.addListener = function(type, listener) {
+  var m;
+
+  if (!isFunction(listener))
+    throw TypeError('listener must be a function');
+
+  if (!this._events)
+    this._events = {};
+
+  // To avoid recursion in the case that type === "newListener"! Before
+  // adding it to the listeners, first emit "newListener".
+  if (this._events.newListener)
+    this.emit('newListener', type,
+              isFunction(listener.listener) ?
+              listener.listener : listener);
+
+  if (!this._events[type])
+    // Optimize the case of one listener. Don't need the extra array object.
+    this._events[type] = listener;
+  else if (isObject(this._events[type]))
+    // If we've already got an array, just append.
+    this._events[type].push(listener);
+  else
+    // Adding the second element, need to change to array.
+    this._events[type] = [this._events[type], listener];
+
+  // Check for listener leak
+  if (isObject(this._events[type]) && !this._events[type].warned) {
+    var m;
+    if (!isUndefined(this._maxListeners)) {
+      m = this._maxListeners;
+    } else {
+      m = EventEmitter.defaultMaxListeners;
+    }
+
+    if (m && m > 0 && this._events[type].length > m) {
+      this._events[type].warned = true;
+      console.error('(node) warning: possible EventEmitter memory ' +
+                    'leak detected. %d listeners added. ' +
+                    'Use emitter.setMaxListeners() to increase limit.',
+                    this._events[type].length);
+      console.trace();
+    }
+  }
+
+  return this;
+};
+
+EventEmitter.prototype.on = EventEmitter.prototype.addListener;
+
+EventEmitter.prototype.once = function(type, listener) {
+  if (!isFunction(listener))
+    throw TypeError('listener must be a function');
+
+  var fired = false;
+
+  function g() {
+    this.removeListener(type, g);
+
+    if (!fired) {
+      fired = true;
+      listener.apply(this, arguments);
+    }
+  }
+
+  g.listener = listener;
+  this.on(type, g);
+
+  return this;
+};
+
+// emits a 'removeListener' event iff the listener was removed
+EventEmitter.prototype.removeListener = function(type, listener) {
+  var list, position, length, i;
+
+  if (!isFunction(listener))
+    throw TypeError('listener must be a function');
+
+  if (!this._events || !this._events[type])
+    return this;
+
+  list = this._events[type];
+  length = list.length;
+  position = -1;
+
+  if (list === listener ||
+      (isFunction(list.listener) && list.listener === listener)) {
+    delete this._events[type];
+    if (this._events.removeListener)
+      this.emit('removeListener', type, listener);
+
+  } else if (isObject(list)) {
+    for (i = length; i-- > 0;) {
+      if (list[i] === listener ||
+          (list[i].listener && list[i].listener === listener)) {
+        position = i;
+        break;
+      }
+    }
+
+    if (position < 0)
+      return this;
+
+    if (list.length === 1) {
+      list.length = 0;
+      delete this._events[type];
+    } else {
+      list.splice(position, 1);
+    }
+
+    if (this._events.removeListener)
+      this.emit('removeListener', type, listener);
+  }
+
+  return this;
+};
+
+EventEmitter.prototype.removeAllListeners = function(type) {
+  var key, listeners;
+
+  if (!this._events)
+    return this;
+
+  // not listening for removeListener, no need to emit
+  if (!this._events.removeListener) {
+    if (arguments.length === 0)
+      this._events = {};
+    else if (this._events[type])
+      delete this._events[type];
+    return this;
+  }
+
+  // emit removeListener for all listeners on all events
+  if (arguments.length === 0) {
+    for (key in this._events) {
+      if (key === 'removeListener') continue;
+      this.removeAllListeners(key);
+    }
+    this.removeAllListeners('removeListener');
+    this._events = {};
+    return this;
+  }
+
+  listeners = this._events[type];
+
+  if (isFunction(listeners)) {
+    this.removeListener(type, listeners);
+  } else {
+    // LIFO order
+    while (listeners.length)
+      this.removeListener(type, listeners[listeners.length - 1]);
+  }
+  delete this._events[type];
+
+  return this;
+};
+
+EventEmitter.prototype.listeners = function(type) {
+  var ret;
+  if (!this._events || !this._events[type])
+    ret = [];
+  else if (isFunction(this._events[type]))
+    ret = [this._events[type]];
+  else
+    ret = this._events[type].slice();
+  return ret;
+};
+
+EventEmitter.listenerCount = function(emitter, type) {
+  var ret;
+  if (!emitter._events || !emitter._events[type])
+    ret = 0;
+  else if (isFunction(emitter._events[type]))
+    ret = 1;
+  else
+    ret = emitter._events[type].length;
+  return ret;
+};
+
+function isFunction(arg) {
+  return typeof arg === 'function';
+}
+
+function isNumber(arg) {
+  return typeof arg === 'number';
+}
+
+function isObject(arg) {
+  return typeof arg === 'object' && arg !== null;
+}
+
+function isUndefined(arg) {
+  return arg === void 0;
+}
+
+},{}],32:[function(_dereq_,module,exports){
+var http = module.exports;
+var EventEmitter = _dereq_('events').EventEmitter;
+var Request = _dereq_('./lib/request');
+var url = _dereq_('url')
+
+http.request = function (params, cb) {
+    if (typeof params === 'string') {
+        params = url.parse(params)
+    }
+    if (!params) params = {};
+    if (!params.host && !params.port) {
+        params.port = parseInt(window.location.port, 10);
+    }
+    if (!params.host && params.hostname) {
+        params.host = params.hostname;
+    }
+    
+    if (!params.scheme) params.scheme = window.location.protocol.split(':')[0];
+    if (!params.host) {
+        params.host = window.location.hostname || window.location.host;
+    }
+    if (/:/.test(params.host)) {
+        if (!params.port) {
+            params.port = params.host.split(':')[1];
+        }
+        params.host = params.host.split(':')[0];
+    }
+    if (!params.port) params.port = params.scheme == 'https' ? 443 : 80;
+    
+    var req = new Request(new xhrHttp, params);
+    if (cb) req.on('response', cb);
+    return req;
+};
+
+http.get = function (params, cb) {
+    params.method = 'GET';
+    var req = http.request(params, cb);
+    req.end();
+    return req;
+};
+
+http.Agent = function () {};
+http.Agent.defaultMaxSockets = 4;
+
+var xhrHttp = (function () {
+    if (typeof window === 'undefined') {
+        throw new Error('no window object present');
+    }
+    else if (window.XMLHttpRequest) {
+        return window.XMLHttpRequest;
+    }
+    else if (window.ActiveXObject) {
+        var axs = [
+            'Msxml2.XMLHTTP.6.0',
+            'Msxml2.XMLHTTP.3.0',
+            'Microsoft.XMLHTTP'
+        ];
+        for (var i = 0; i < axs.length; i++) {
+            try {
+                var ax = new(window.ActiveXObject)(axs[i]);
+                return function () {
+                    if (ax) {
+                        var ax_ = ax;
+                        ax = null;
+                        return ax_;
+                    }
+                    else {
+                        return new(window.ActiveXObject)(axs[i]);
+                    }
+                };
+            }
+            catch (e) {}
+        }
+        throw new Error('ajax not supported in this browser')
+    }
+    else {
+        throw new Error('ajax not supported in this browser');
+    }
+})();
+
+http.STATUS_CODES = {
+    100 : 'Continue',
+    101 : 'Switching Protocols',
+    102 : 'Processing',                 // RFC 2518, obsoleted by RFC 4918
+    200 : 'OK',
+    201 : 'Created',
+    202 : 'Accepted',
+    203 : 'Non-Authoritative Information',
+    204 : 'No Content',
+    205 : 'Reset Content',
+    206 : 'Partial Content',
+    207 : 'Multi-Status',               // RFC 4918
+    300 : 'Multiple Choices',
+    301 : 'Moved Permanently',
+    302 : 'Moved Temporarily',
+    303 : 'See Other',
+    304 : 'Not Modified',
+    305 : 'Use Proxy',
+    307 : 'Temporary Redirect',
+    400 : 'Bad Request',
+    401 : 'Unauthorized',
+    402 : 'Payment Required',
+    403 : 'Forbidden',
+    404 : 'Not Found',
+    405 : 'Method Not Allowed',
+    406 : 'Not Acceptable',
+    407 : 'Proxy Authentication Required',
+    408 : 'Request Time-out',
+    409 : 'Conflict',
+    410 : 'Gone',
+    411 : 'Length Required',
+    412 : 'Precondition Failed',
+    413 : 'Request Entity Too Large',
+    414 : 'Request-URI Too Large',
+    415 : 'Unsupported Media Type',
+    416 : 'Requested Range Not Satisfiable',
+    417 : 'Expectation Failed',
+    418 : 'I\'m a teapot',              // RFC 2324
+    422 : 'Unprocessable Entity',       // RFC 4918
+    423 : 'Locked',                     // RFC 4918
+    424 : 'Failed Dependency',          // RFC 4918
+    425 : 'Unordered Collection',       // RFC 4918
+    426 : 'Upgrade Required',           // RFC 2817
+    428 : 'Precondition Required',      // RFC 6585
+    429 : 'Too Many Requests',          // RFC 6585
+    431 : 'Request Header Fields Too Large',// RFC 6585
+    500 : 'Internal Server Error',
+    501 : 'Not Implemented',
+    502 : 'Bad Gateway',
+    503 : 'Service Unavailable',
+    504 : 'Gateway Time-out',
+    505 : 'HTTP Version Not Supported',
+    506 : 'Variant Also Negotiates',    // RFC 2295
+    507 : 'Insufficient Storage',       // RFC 4918
+    509 : 'Bandwidth Limit Exceeded',
+    510 : 'Not Extended',               // RFC 2774
+    511 : 'Network Authentication Required' // RFC 6585
+};
+},{"./lib/request":33,"events":31,"url":52}],33:[function(_dereq_,module,exports){
+var Stream = _dereq_('stream');
+var Response = _dereq_('./response');
+var Base64 = _dereq_('Base64');
+var inherits = _dereq_('inherits');
+
+var Request = module.exports = function (xhr, params) {
+    var self = this;
+    self.writable = true;
+    self.xhr = xhr;
+    self.body = [];
+    
+    self.uri = (params.scheme || 'http') + '://'
+        + params.host
+        + (params.port ? ':' + params.port : '')
+        + (params.path || '/')
+    ;
+    
+    if (typeof params.withCredentials === 'undefined') {
+        params.withCredentials = true;
+    }
+
+    try { xhr.withCredentials = params.withCredentials }
+    catch (e) {}
+    
+    xhr.open(
+        params.method || 'GET',
+        self.uri,
+        true
+    );
+
+    self._headers = {};
+    
+    if (params.headers) {
+        var keys = objectKeys(params.headers);
+        for (var i = 0; i < keys.length; i++) {
+            var key = keys[i];
+            if (!self.isSafeRequestHeader(key)) continue;
+            var value = params.headers[key];
+            self.setHeader(key, value);
+        }
+    }
+    
+    if (params.auth) {
+        //basic auth
+        this.setHeader('Authorization', 'Basic ' + Base64.btoa(params.auth));
+    }
+
+    var res = new Response;
+    res.on('close', function () {
+        self.emit('close');
+    });
+    
+    res.on('ready', function () {
+        self.emit('response', res);
+    });
+    
+    xhr.onreadystatechange = function () {
+        // Fix for IE9 bug
+        // SCRIPT575: Could not complete the operation due to error c00c023f
+        // It happens when a request is aborted, calling the success callback anyway with readyState === 4
+        if (xhr.__aborted) return;
+        res.handle(xhr);
+    };
+};
+
+inherits(Request, Stream);
+
+Request.prototype.setHeader = function (key, value) {
+    this._headers[key.toLowerCase()] = value
+};
+
+Request.prototype.getHeader = function (key) {
+    return this._headers[key.toLowerCase()]
+};
+
+Request.prototype.removeHeader = function (key) {
+    delete this._headers[key.toLowerCase()]
+};
+
+Request.prototype.write = function (s) {
+    this.body.push(s);
+};
+
+Request.prototype.destroy = function (s) {
+    this.xhr.__aborted = true;
+    this.xhr.abort();
+    this.emit('close');
+};
+
+Request.prototype.end = function (s) {
+    if (s !== undefined) this.body.push(s);
+
+    var keys = objectKeys(this._headers);
+    for (var i = 0; i < keys.length; i++) {
+        var key = keys[i];
+        var value = this._headers[key];
+        if (isArray(value)) {
+            for (var j = 0; j < value.length; j++) {
+                this.xhr.setRequestHeader(key, value[j]);
+            }
+        }
+        else this.xhr.setRequestHeader(key, value)
+    }
+
+    if (this.body.length === 0) {
+        this.xhr.send('');
+    }
+    else if (typeof this.body[0] === 'string') {
+        this.xhr.send(this.body.join(''));
+    }
+    else if (isArray(this.body[0])) {
+        var body = [];
+        for (var i = 0; i < this.body.length; i++) {
+            body.push.apply(body, this.body[i]);
+        }
+        this.xhr.send(body);
+    }
+    else if (/Array/.test(Object.prototype.toString.call(this.body[0]))) {
+        var len = 0;
+        for (var i = 0; i < this.body.length; i++) {
+            len += this.body[i].length;
+        }
+        var body = new(this.body[0].constructor)(len);
+        var k = 0;
+        
+        for (var i = 0; i < this.body.length; i++) {
+            var b = this.body[i];
+            for (var j = 0; j < b.length; j++) {
+                body[k++] = b[j];
+            }
+        }
+        this.xhr.send(body);
+    }
+    else {
+        var body = '';
+        for (var i = 0; i < this.body.length; i++) {
+            body += this.body[i].toString();
+        }
+        this.xhr.send(body);
+    }
+};
+
+// Taken from http://dxr.mozilla.org/mozilla/mozilla-central/content/base/src/nsXMLHttpRequest.cpp.html
+Request.unsafeHeaders = [
+    "accept-charset",
+    "accept-encoding",
+    "access-control-request-headers",
+    "access-control-request-method",
+    "connection",
+    "content-length",
+    "cookie",
+    "cookie2",
+    "content-transfer-encoding",
+    "date",
+    "expect",
+    "host",
+    "keep-alive",
+    "origin",
+    "referer",
+    "te",
+    "trailer",
+    "transfer-encoding",
+    "upgrade",
+    "user-agent",
+    "via"
+];
+
+Request.prototype.isSafeRequestHeader = function (headerName) {
+    if (!headerName) return false;
+    return indexOf(Request.unsafeHeaders, headerName.toLowerCase()) === -1;
+};
+
+var objectKeys = Object.keys || function (obj) {
+    var keys = [];
+    for (var key in obj) keys.push(key);
+    return keys;
+};
+
+var isArray = Array.isArray || function (xs) {
+    return Object.prototype.toString.call(xs) === '[object Array]';
+};
+
+var indexOf = function (xs, x) {
+    if (xs.indexOf) return xs.indexOf(x);
+    for (var i = 0; i < xs.length; i++) {
+        if (xs[i] === x) return i;
+    }
+    return -1;
+};
+
+},{"./response":34,"Base64":35,"inherits":37,"stream":45}],34:[function(_dereq_,module,exports){
+var Stream = _dereq_('stream');
+var util = _dereq_('util');
+
+var Response = module.exports = function (res) {
+    this.offset = 0;
+    this.readable = true;
+};
+
+util.inherits(Response, Stream);
+
+var capable = {
+    streaming : true,
+    status2 : true
+};
+
+function parseHeaders (res) {
+    var lines = res.getAllResponseHeaders().split(/\r?\n/);
+    var headers = {};
+    for (var i = 0; i < lines.length; i++) {
+        var line = lines[i];
+        if (line === '') continue;
+        
+        var m = line.match(/^([^:]+):\s*(.*)/);
+        if (m) {
+            var key = m[1].toLowerCase(), value = m[2];
+            
+            if (headers[key] !== undefined) {
+            
+                if (isArray(headers[key])) {
+                    headers[key].push(value);
+                }
+                else {
+                    headers[key] = [ headers[key], value ];
+                }
+            }
+            else {
+                headers[key] = value;
+            }
+        }
+        else {
+            headers[line] = true;
+        }
+    }
+    return headers;
+}
+
+Response.prototype.getResponse = function (xhr) {
+    var respType = String(xhr.responseType).toLowerCase();
+    if (respType === 'blob') return xhr.responseBlob || xhr.response;
+    if (respType === 'arraybuffer') return xhr.response;
+    return xhr.responseText;
+}
+
+Response.prototype.getHeader = function (key) {
+    return this.headers[key.toLowerCase()];
+};
+
+Response.prototype.handle = function (res) {
+    if (res.readyState === 2 && capable.status2) {
+        try {
+            this.statusCode = res.status;
+            this.headers = parseHeaders(res);
+        }
+        catch (err) {
+            capable.status2 = false;
+        }
+        
+        if (capable.status2) {
+            this.emit('ready');
+        }
+    }
+    else if (capable.streaming && res.readyState === 3) {
+        try {
+            if (!this.statusCode) {
+                this.statusCode = res.status;
+                this.headers = parseHeaders(res);
+                this.emit('ready');
+            }
+        }
+        catch (err) {}
+        
+        try {
+            this._emitData(res);
+        }
+        catch (err) {
+            capable.streaming = false;
+        }
+    }
+    else if (res.readyState === 4) {
+        if (!this.statusCode) {
+            this.statusCode = res.status;
+            this.emit('ready');
+        }
+        this._emitData(res);
+        
+        if (res.error) {
+            this.emit('error', this.getResponse(res));
+        }
+        else this.emit('end');
+        
+        this.emit('close');
+    }
+};
+
+Response.prototype._emitData = function (res) {
+    var respBody = this.getResponse(res);
+    if (respBody.toString().match(/ArrayBuffer/)) {
+        this.emit('data', new Uint8Array(respBody, this.offset));
+        this.offset = respBody.byteLength;
+        return;
+    }
+    if (respBody.length > this.offset) {
+        this.emit('data', respBody.slice(this.offset));
+        this.offset = respBody.length;
+    }
+};
+
+var isArray = Array.isArray || function (xs) {
+    return Object.prototype.toString.call(xs) === '[object Array]';
+};
+
+},{"stream":45,"util":54}],35:[function(_dereq_,module,exports){
+;(function () {
+
+  var object = typeof exports != 'undefined' ? exports : this; // #8: web workers
+  var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
+
+  function InvalidCharacterError(message) {
+    this.message = message;
+  }
+  InvalidCharacterError.prototype = new Error;
+  InvalidCharacterError.prototype.name = 'InvalidCharacterError';
+
+  // encoder
+  // [https://gist.github.com/999166] by [https://github.com/nignag]
+  object.btoa || (
+  object.btoa = function (input) {
+    for (
+      // initialize result and counter
+      var block, charCode, idx = 0, map = chars, output = '';
+      // if the next input index does not exist:
+      //   change the mapping table to "="
+      //   check if d has no fractional digits
+      input.charAt(idx | 0) || (map = '=', idx % 1);
+      // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
+      output += map.charAt(63 & block >> 8 - idx % 1 * 8)
+    ) {
+      charCode = input.charCodeAt(idx += 3/4);
+      if (charCode > 0xFF) {
+        throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
+      }
+      block = block << 8 | charCode;
+    }
+    return output;
+  });
+
+  // decoder
+  // [https://gist.github.com/1020396] by [https://github.com/atk]
+  object.atob || (
+  object.atob = function (input) {
+    input = input.replace(/=+$/, '')
+    if (input.length % 4 == 1) {
+      throw new InvalidCharacterError("'atob' failed: The string to be decoded is not correctly encoded.");
+    }
+    for (
+      // initialize result and counters
+      var bc = 0, bs, buffer, idx = 0, output = '';
+      // get next character
+      buffer = input.charAt(idx++);
+      // character found in table? initialize bit storage and add its ascii value;
+      ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
+        // and if not first of each 4 characters,
+        // convert the first 8 bits to one ascii character
+        bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
+    ) {
+      // try to find character in table (0-63, not found => -1)
+      buffer = chars.indexOf(buffer);
+    }
+    return output;
+  });
+
+}());
+
+},{}],36:[function(_dereq_,module,exports){
+var http = _dereq_('http');
+
+var https = module.exports;
+
+for (var key in http) {
+    if (http.hasOwnProperty(key)) https[key] = http[key];
+};
+
+https.request = function (params, cb) {
+    if (!params) params = {};
+    params.scheme = 'https';
+    return http.request.call(this, params, cb);
+}
+
+},{"http":32}],37:[function(_dereq_,module,exports){
+if (typeof Object.create === 'function') {
+  // implementation from standard node.js 'util' module
+  module.exports = function inherits(ctor, superCtor) {
+    ctor.super_ = superCtor
+    ctor.prototype = Object.create(superCtor.prototype, {
+      constructor: {
+        value: ctor,
+        enumerable: false,
+        writable: true,
+        configurable: true
+      }
+    });
+  };
+} else {
+  // old school shim for old browsers
+  module.exports = function inherits(ctor, superCtor) {
+    ctor.super_ = superCtor
+    var TempCtor = function () {}
+    TempCtor.prototype = superCtor.prototype
+    ctor.prototype = new TempCtor()
+    ctor.prototype.constructor = ctor
+  }
+}
+
+},{}],38:[function(_dereq_,module,exports){
+// shim for using process in browser
+
+var process = module.exports = {};
+
+process.nextTick = (function () {
+    var canSetImmediate = typeof window !== 'undefined'
+    && window.setImmediate;
+    var canPost = typeof window !== 'undefined'
+    && window.postMessage && window.addEventListener
+    ;
+
+    if (canSetImmediate) {
+        return function (f) { return window.setImmediate(f) };
+    }
+
+    if (canPost) {
+        var queue = [];
+        window.addEventListener('message', function (ev) {
+            var source = ev.source;
+            if ((source === window || source === null) && ev.data === 'process-tick') {
+                ev.stopPropagation();
+                if (queue.length > 0) {
+                    var fn = queue.shift();
+                    fn();
+                }
+            }
+        }, true);
+
+        return function nextTick(fn) {
+            queue.push(fn);
+            window.postMessage('process-tick', '*');
+        };
+    }
+
+    return function nextTick(fn) {
+        setTimeout(fn, 0);
+    };
+})();
+
+process.title = 'browser';
+process.browser = true;
+process.env = {};
+process.argv = [];
+
+process.binding = function (name) {
+    throw new Error('process.binding is not supported');
+}
+
+// TODO(shtylman)
+process.cwd = function () { return '/' };
+process.chdir = function (dir) {
+    throw new Error('process.chdir is not supported');
+};
+
+},{}],39:[function(_dereq_,module,exports){
+(function (process){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// 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.
+
+// resolves . and .. elements in a path array with directory names there
+// must be no slashes, empty elements, or device names (c:\) in the array
+// (so also no leading and trailing slashes - it does not distinguish
+// relative and absolute paths)
+function normalizeArray(parts, allowAboveRoot) {
+  // if the path tries to go above the root, `up` ends up > 0
+  var up = 0;
+  for (var i = parts.length - 1; i >= 0; i--) {
+    var last = parts[i];
+    if (last === '.') {
+      parts.splice(i, 1);
+    } else if (last === '..') {
+      parts.splice(i, 1);
+      up++;
+    } else if (up) {
+      parts.splice(i, 1);
+      up--;
+    }
+  }
+
+  // if the path is allowed to go above the root, restore leading ..s
+  if (allowAboveRoot) {
+    for (; up--; up) {
+      parts.unshift('..');
+    }
+  }
+
+  return parts;
+}
+
+// Split a filename into [root, dir, basename, ext], unix version
+// 'root' is just a slash, or nothing.
+var splitPathRe =
+    /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+var splitPath = function(filename) {
+  return splitPathRe.exec(filename).slice(1);
+};
+
+// path.resolve([from ...], to)
+// posix version
+exports.resolve = function() {
+  var resolvedPath = '',
+      resolvedAbsolute = false;
+
+  for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+    var path = (i >= 0) ? arguments[i] : process.cwd();
+
+    // Skip empty and invalid entries
+    if (typeof path !== 'string') {
+      throw new TypeError('Arguments to path.resolve must be strings');
+    } else if (!path) {
+      continue;
+    }
+
+    resolvedPath = path + '/' + resolvedPath;
+    resolvedAbsolute = path.charAt(0) === '/';
+  }
+
+  // At this point the path should be resolved to a full absolute path, but
+  // handle relative paths to be safe (might happen when process.cwd() fails)
+
+  // Normalize the path
+  resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
+    return !!p;
+  }), !resolvedAbsolute).join('/');
+
+  return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+};
+
+// path.normalize(path)
+// posix version
+exports.normalize = function(path) {
+  var isAbsolute = exports.isAbsolute(path),
+      trailingSlash = substr(path, -1) === '/';
+
+  // Normalize the path
+  path = normalizeArray(filter(path.split('/'), function(p) {
+    return !!p;
+  }), !isAbsolute).join('/');
+
+  if (!path && !isAbsolute) {
+    path = '.';
+  }
+  if (path && trailingSlash) {
+    path += '/';
+  }
+
+  return (isAbsolute ? '/' : '') + path;
+};
+
+// posix version
+exports.isAbsolute = function(path) {
+  return path.charAt(0) === '/';
+};
+
+// posix version
+exports.join = function() {
+  var paths = Array.prototype.slice.call(arguments, 0);
+  return exports.normalize(filter(paths, function(p, index) {
+    if (typeof p !== 'string') {
+      throw new TypeError('Arguments to path.join must be strings');
+    }
+    return p;
+  }).join('/'));
+};
+
+
+// path.relative(from, to)
+// posix version
+exports.relative = function(from, to) {
+  from = exports.resolve(from).substr(1);
+  to = exports.resolve(to).substr(1);
+
+  function trim(arr) {
+    var start = 0;
+    for (; start < arr.length; start++) {
+      if (arr[start] !== '') break;
+    }
+
+    var end = arr.length - 1;
+    for (; end >= 0; end--) {
+      if (arr[end] !== '') break;
+    }
+
+    if (start > end) return [];
+    return arr.slice(start, end - start + 1);
+  }
+
+  var fromParts = trim(from.split('/'));
+  var toParts = trim(to.split('/'));
+
+  var length = Math.min(fromParts.length, toParts.length);
+  var samePartsLength = length;
+  for (var i = 0; i < length; i++) {
+    if (fromParts[i] !== toParts[i]) {
+      samePartsLength = i;
+      break;
+    }
+  }
+
+  var outputParts = [];
+  for (var i = samePartsLength; i < fromParts.length; i++) {
+    outputParts.push('..');
+  }
+
+  outputParts = outputParts.concat(toParts.slice(samePartsLength));
+
+  return outputParts.join('/');
+};
+
+exports.sep = '/';
+exports.delimiter = ':';
+
+exports.dirname = function(path) {
+  var result = splitPath(path),
+      root = result[0],
+      dir = result[1];
+
+  if (!root && !dir) {
+    // No dirname whatsoever
+    return '.';
+  }
+
+  if (dir) {
+    // It has a dirname, strip trailing slash
+    dir = dir.substr(0, dir.length - 1);
+  }
+
+  return root + dir;
+};
+
+
+exports.basename = function(path, ext) {
+  var f = splitPath(path)[2];
+  // TODO: make this comparison case-insensitive on windows?
+  if (ext && f.substr(-1 * ext.length) === ext) {
+    f = f.substr(0, f.length - ext.length);
+  }
+  return f;
+};
+
+
+exports.extname = function(path) {
+  return splitPath(path)[3];
+};
+
+function filter (xs, f) {
+    if (xs.filter) return xs.filter(f);
+    var res = [];
+    for (var i = 0; i < xs.length; i++) {
+        if (f(xs[i], i, xs)) res.push(xs[i]);
+    }
+    return res;
+}
+
+// String.prototype.substr - negative index don't work in IE8
+var substr = 'ab'.substr(-1) === 'b'
+    ? function (str, start, len) { return str.substr(start, len) }
+    : function (str, start, len) {
+        if (start < 0) start = str.length + start;
+        return str.substr(start, len);
+    }
+;
+
+}).call(this,_dereq_("C:\\Users\\xmr\\Desktop\\clean-css\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"))
+},{"C:\\Users\\xmr\\Desktop\\clean-css\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":38}],40:[function(_dereq_,module,exports){
+(function (global){
+/*! http://mths.be/punycode v1.2.4 by @mathias */
+;(function(root) {
+
+       /** Detect free variables */
+       var freeExports = typeof exports == 'object' && exports;
+       var freeModule = typeof module == 'object' && module &&
+               module.exports == freeExports && module;
+       var freeGlobal = typeof global == 'object' && global;
+       if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
+               root = freeGlobal;
+       }
+
+       /**
+        * The `punycode` object.
+        * @name punycode
+        * @type Object
+        */
+       var punycode,
+
+       /** Highest positive signed 32-bit float value */
+       maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
+
+       /** Bootstring parameters */
+       base = 36,
+       tMin = 1,
+       tMax = 26,
+       skew = 38,
+       damp = 700,
+       initialBias = 72,
+       initialN = 128, // 0x80
+       delimiter = '-', // '\x2D'
+
+       /** Regular expressions */
+       regexPunycode = /^xn--/,
+       regexNonASCII = /[^ -~]/, // unprintable ASCII chars + non-ASCII chars
+       regexSeparators = /\x2E|\u3002|\uFF0E|\uFF61/g, // RFC 3490 separators
+
+       /** Error messages */
+       errors = {
+               'overflow': 'Overflow: input needs wider integers to process',
+               'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
+               'invalid-input': 'Invalid input'
+       },
+
+       /** Convenience shortcuts */
+       baseMinusTMin = base - tMin,
+       floor = Math.floor,
+       stringFromCharCode = String.fromCharCode,
+
+       /** Temporary variable */
+       key;
+
+       /*--------------------------------------------------------------------------*/
+
+       /**
+        * A generic error utility function.
+        * @private
+        * @param {String} type The error type.
+        * @returns {Error} Throws a `RangeError` with the applicable error message.
+        */
+       function error(type) {
+               throw RangeError(errors[type]);
+       }
+
+       /**
+        * A generic `Array#map` utility function.
+        * @private
+        * @param {Array} array The array to iterate over.
+        * @param {Function} callback The function that gets called for every array
+        * item.
+        * @returns {Array} A new array of values returned by the callback function.
+        */
+       function map(array, fn) {
+               var length = array.length;
+               while (length--) {
+                       array[length] = fn(array[length]);
+               }
+               return array;
+       }
+
+       /**
+        * A simple `Array#map`-like wrapper to work with domain name strings.
+        * @private
+        * @param {String} domain The domain name.
+        * @param {Function} callback The function that gets called for every
+        * character.
+        * @returns {Array} A new string of characters returned by the callback
+        * function.
+        */
+       function mapDomain(string, fn) {
+               return map(string.split(regexSeparators), fn).join('.');
+       }
+
+       /**
+        * Creates an array containing the numeric code points of each Unicode
+        * character in the string. While JavaScript uses UCS-2 internally,
+        * this function will convert a pair of surrogate halves (each of which
+        * UCS-2 exposes as separate characters) into a single code point,
+        * matching UTF-16.
+        * @see `punycode.ucs2.encode`
+        * @see <http://mathiasbynens.be/notes/javascript-encoding>
+        * @memberOf punycode.ucs2
+        * @name decode
+        * @param {String} string The Unicode input string (UCS-2).
+        * @returns {Array} The new array of code points.
+        */
+       function ucs2decode(string) {
+               var output = [],
+                   counter = 0,
+                   length = string.length,
+                   value,
+                   extra;
+               while (counter < length) {
+                       value = string.charCodeAt(counter++);
+                       if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+                               // high surrogate, and there is a next character
+                               extra = string.charCodeAt(counter++);
+                               if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+                                       output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+                               } else {
+                                       // unmatched surrogate; only append this code unit, in case the next
+                                       // code unit is the high surrogate of a surrogate pair
+                                       output.push(value);
+                                       counter--;
+                               }
+                       } else {
+                               output.push(value);
+                       }
+               }
+               return output;
+       }
+
+       /**
+        * Creates a string based on an array of numeric code points.
+        * @see `punycode.ucs2.decode`
+        * @memberOf punycode.ucs2
+        * @name encode
+        * @param {Array} codePoints The array of numeric code points.
+        * @returns {String} The new Unicode string (UCS-2).
+        */
+       function ucs2encode(array) {
+               return map(array, function(value) {
+                       var output = '';
+                       if (value > 0xFFFF) {
+                               value -= 0x10000;
+                               output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+                               value = 0xDC00 | value & 0x3FF;
+                       }
+                       output += stringFromCharCode(value);
+                       return output;
+               }).join('');
+       }
+
+       /**
+        * Converts a basic code point into a digit/integer.
+        * @see `digitToBasic()`
+        * @private
+        * @param {Number} codePoint The basic numeric code point value.
+        * @returns {Number} The numeric value of a basic code point (for use in
+        * representing integers) in the range `0` to `base - 1`, or `base` if
+        * the code point does not represent a value.
+        */
+       function basicToDigit(codePoint) {
+               if (codePoint - 48 < 10) {
+                       return codePoint - 22;
+               }
+               if (codePoint - 65 < 26) {
+                       return codePoint - 65;
+               }
+               if (codePoint - 97 < 26) {
+                       return codePoint - 97;
+               }
+               return base;
+       }
+
+       /**
+        * Converts a digit/integer into a basic code point.
+        * @see `basicToDigit()`
+        * @private
+        * @param {Number} digit The numeric value of a basic code point.
+        * @returns {Number} The basic code point whose value (when used for
+        * representing integers) is `digit`, which needs to be in the range
+        * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
+        * used; else, the lowercase form is used. The behavior is undefined
+        * if `flag` is non-zero and `digit` has no uppercase form.
+        */
+       function digitToBasic(digit, flag) {
+               //  0..25 map to ASCII a..z or A..Z
+               // 26..35 map to ASCII 0..9
+               return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
+       }
+
+       /**
+        * Bias adaptation function as per section 3.4 of RFC 3492.
+        * http://tools.ietf.org/html/rfc3492#section-3.4
+        * @private
+        */
+       function adapt(delta, numPoints, firstTime) {
+               var k = 0;
+               delta = firstTime ? floor(delta / damp) : delta >> 1;
+               delta += floor(delta / numPoints);
+               for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
+                       delta = floor(delta / baseMinusTMin);
+               }
+               return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
+       }
+
+       /**
+        * Converts a Punycode string of ASCII-only symbols to a string of Unicode
+        * symbols.
+        * @memberOf punycode
+        * @param {String} input The Punycode string of ASCII-only symbols.
+        * @returns {String} The resulting string of Unicode symbols.
+        */
+       function decode(input) {
+               // Don't use UCS-2
+               var output = [],
+                   inputLength = input.length,
+                   out,
+                   i = 0,
+                   n = initialN,
+                   bias = initialBias,
+                   basic,
+                   j,
+                   index,
+                   oldi,
+                   w,
+                   k,
+                   digit,
+                   t,
+                   /** Cached calculation results */
+                   baseMinusT;
+
+               // Handle the basic code points: let `basic` be the number of input code
+               // points before the last delimiter, or `0` if there is none, then copy
+               // the first basic code points to the output.
+
+               basic = input.lastIndexOf(delimiter);
+               if (basic < 0) {
+                       basic = 0;
+               }
+
+               for (j = 0; j < basic; ++j) {
+                       // if it's not a basic code point
+                       if (input.charCodeAt(j) >= 0x80) {
+                               error('not-basic');
+                       }
+                       output.push(input.charCodeAt(j));
+               }
+
+               // Main decoding loop: start just after the last delimiter if any basic code
+               // points were copied; start at the beginning otherwise.
+
+               for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
+
+                       // `index` is the index of the next character to be consumed.
+                       // Decode a generalized variable-length integer into `delta`,
+                       // which gets added to `i`. The overflow checking is easier
+                       // if we increase `i` as we go, then subtract off its starting
+                       // value at the end to obtain `delta`.
+                       for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
+
+                               if (index >= inputLength) {
+                                       error('invalid-input');
+                               }
+
+                               digit = basicToDigit(input.charCodeAt(index++));
+
+                               if (digit >= base || digit > floor((maxInt - i) / w)) {
+                                       error('overflow');
+                               }
+
+                               i += digit * w;
+                               t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+
+                               if (digit < t) {
+                                       break;
+                               }
+
+                               baseMinusT = base - t;
+                               if (w > floor(maxInt / baseMinusT)) {
+                                       error('overflow');
+                               }
+
+                               w *= baseMinusT;
+
+                       }
+
+                       out = output.length + 1;
+                       bias = adapt(i - oldi, out, oldi == 0);
+
+                       // `i` was supposed to wrap around from `out` to `0`,
+                       // incrementing `n` each time, so we'll fix that now:
+                       if (floor(i / out) > maxInt - n) {
+                               error('overflow');
+                       }
+
+                       n += floor(i / out);
+                       i %= out;
+
+                       // Insert `n` at position `i` of the output
+                       output.splice(i++, 0, n);
+
+               }
+
+               return ucs2encode(output);
+       }
+
+       /**
+        * Converts a string of Unicode symbols to a Punycode string of ASCII-only
+        * symbols.
+        * @memberOf punycode
+        * @param {String} input The string of Unicode symbols.
+        * @returns {String} The resulting Punycode string of ASCII-only symbols.
+        */
+       function encode(input) {
+               var n,
+                   delta,
+                   handledCPCount,
+                   basicLength,
+                   bias,
+                   j,
+                   m,
+                   q,
+                   k,
+                   t,
+                   currentValue,
+                   output = [],
+                   /** `inputLength` will hold the number of code points in `input`. */
+                   inputLength,
+                   /** Cached calculation results */
+                   handledCPCountPlusOne,
+                   baseMinusT,
+                   qMinusT;
+
+               // Convert the input in UCS-2 to Unicode
+               input = ucs2decode(input);
+
+               // Cache the length
+               inputLength = input.length;
+
+               // Initialize the state
+               n = initialN;
+               delta = 0;
+               bias = initialBias;
+
+               // Handle the basic code points
+               for (j = 0; j < inputLength; ++j) {
+                       currentValue = input[j];
+                       if (currentValue < 0x80) {
+                               output.push(stringFromCharCode(currentValue));
+                       }
+               }
+
+               handledCPCount = basicLength = output.length;
+
+               // `handledCPCount` is the number of code points that have been handled;
+               // `basicLength` is the number of basic code points.
+
+               // Finish the basic string - if it is not empty - with a delimiter
+               if (basicLength) {
+                       output.push(delimiter);
+               }
+
+               // Main encoding loop:
+               while (handledCPCount < inputLength) {
+
+                       // All non-basic code points < n have been handled already. Find the next
+                       // larger one:
+                       for (m = maxInt, j = 0; j < inputLength; ++j) {
+                               currentValue = input[j];
+                               if (currentValue >= n && currentValue < m) {
+                                       m = currentValue;
+                               }
+                       }
+
+                       // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
+                       // but guard against overflow
+                       handledCPCountPlusOne = handledCPCount + 1;
+                       if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
+                               error('overflow');
+                       }
+
+                       delta += (m - n) * handledCPCountPlusOne;
+                       n = m;
+
+                       for (j = 0; j < inputLength; ++j) {
+                               currentValue = input[j];
+
+                               if (currentValue < n && ++delta > maxInt) {
+                                       error('overflow');
+                               }
+
+                               if (currentValue == n) {
+                                       // Represent delta as a generalized variable-length integer
+                                       for (q = delta, k = base; /* no condition */; k += base) {
+                                               t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+                                               if (q < t) {
+                                                       break;
+                                               }
+                                               qMinusT = q - t;
+                                               baseMinusT = base - t;
+                                               output.push(
+                                                       stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
+                                               );
+                                               q = floor(qMinusT / baseMinusT);
+                                       }
+
+                                       output.push(stringFromCharCode(digitToBasic(q, 0)));
+                                       bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
+                                       delta = 0;
+                                       ++handledCPCount;
+                               }
+                       }
+
+                       ++delta;
+                       ++n;
+
+               }
+               return output.join('');
+       }
+
+       /**
+        * Converts a Punycode string representing a domain name to Unicode. Only the
+        * Punycoded parts of the domain name will be converted, i.e. it doesn't
+        * matter if you call it on a string that has already been converted to
+        * Unicode.
+        * @memberOf punycode
+        * @param {String} domain The Punycode domain name to convert to Unicode.
+        * @returns {String} The Unicode representation of the given Punycode
+        * string.
+        */
+       function toUnicode(domain) {
+               return mapDomain(domain, function(string) {
+                       return regexPunycode.test(string)
+                               ? decode(string.slice(4).toLowerCase())
+                               : string;
+               });
+       }
+
+       /**
+        * Converts a Unicode string representing a domain name to Punycode. Only the
+        * non-ASCII parts of the domain name will be converted, i.e. it doesn't
+        * matter if you call it with a domain that's already in ASCII.
+        * @memberOf punycode
+        * @param {String} domain The domain name to convert, as a Unicode string.
+        * @returns {String} The Punycode representation of the given domain name.
+        */
+       function toASCII(domain) {
+               return mapDomain(domain, function(string) {
+                       return regexNonASCII.test(string)
+                               ? 'xn--' + encode(string)
+                               : string;
+               });
+       }
+
+       /*--------------------------------------------------------------------------*/
+
+       /** Define the public API */
+       punycode = {
+               /**
+                * A string representing the current Punycode.js version number.
+                * @memberOf punycode
+                * @type String
+                */
+               'version': '1.2.4',
+               /**
+                * An object of methods to convert from JavaScript's internal character
+                * representation (UCS-2) to Unicode code points, and back.
+                * @see <http://mathiasbynens.be/notes/javascript-encoding>
+                * @memberOf punycode
+                * @type Object
+                */
+               'ucs2': {
+                       'decode': ucs2decode,
+                       'encode': ucs2encode
+               },
+               'decode': decode,
+               'encode': encode,
+               'toASCII': toASCII,
+               'toUnicode': toUnicode
+       };
+
+       /** Expose `punycode` */
+       // Some AMD build optimizers, like r.js, check for specific condition patterns
+       // like the following:
+       if (
+               typeof define == 'function' &&
+               typeof define.amd == 'object' &&
+               define.amd
+       ) {
+               define('punycode', function() {
+                       return punycode;
+               });
+       } else if (freeExports && !freeExports.nodeType) {
+               if (freeModule) { // in Node.js or RingoJS v0.8.0+
+                       freeModule.exports = punycode;
+               } else { // in Narwhal or RingoJS v0.7.0-
+                       for (key in punycode) {
+                               punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
+                       }
+               }
+       } else { // in Rhino or a web browser
+               root.punycode = punycode;
+       }
+
+}(this));
+
+}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{}],41:[function(_dereq_,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// 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.
+
+'use strict';
+
+// If obj.hasOwnProperty has been overridden, then calling
+// obj.hasOwnProperty(prop) will break.
+// See: https://github.com/joyent/node/issues/1707
+function hasOwnProperty(obj, prop) {
+  return Object.prototype.hasOwnProperty.call(obj, prop);
+}
+
+module.exports = function(qs, sep, eq, options) {
+  sep = sep || '&';
+  eq = eq || '=';
+  var obj = {};
+
+  if (typeof qs !== 'string' || qs.length === 0) {
+    return obj;
+  }
+
+  var regexp = /\+/g;
+  qs = qs.split(sep);
+
+  var maxKeys = 1000;
+  if (options && typeof options.maxKeys === 'number') {
+    maxKeys = options.maxKeys;
+  }
+
+  var len = qs.length;
+  // maxKeys <= 0 means that we should not limit keys count
+  if (maxKeys > 0 && len > maxKeys) {
+    len = maxKeys;
+  }
+
+  for (var i = 0; i < len; ++i) {
+    var x = qs[i].replace(regexp, '%20'),
+        idx = x.indexOf(eq),
+        kstr, vstr, k, v;
+
+    if (idx >= 0) {
+      kstr = x.substr(0, idx);
+      vstr = x.substr(idx + 1);
+    } else {
+      kstr = x;
+      vstr = '';
+    }
+
+    k = decodeURIComponent(kstr);
+    v = decodeURIComponent(vstr);
+
+    if (!hasOwnProperty(obj, k)) {
+      obj[k] = v;
+    } else if (isArray(obj[k])) {
+      obj[k].push(v);
+    } else {
+      obj[k] = [obj[k], v];
+    }
+  }
+
+  return obj;
+};
+
+var isArray = Array.isArray || function (xs) {
+  return Object.prototype.toString.call(xs) === '[object Array]';
+};
+
+},{}],42:[function(_dereq_,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// 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.
+
+'use strict';
+
+var stringifyPrimitive = function(v) {
+  switch (typeof v) {
+    case 'string':
+      return v;
+
+    case 'boolean':
+      return v ? 'true' : 'false';
+
+    case 'number':
+      return isFinite(v) ? v : '';
+
+    default:
+      return '';
+  }
+};
+
+module.exports = function(obj, sep, eq, name) {
+  sep = sep || '&';
+  eq = eq || '=';
+  if (obj === null) {
+    obj = undefined;
+  }
+
+  if (typeof obj === 'object') {
+    return map(objectKeys(obj), function(k) {
+      var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
+      if (isArray(obj[k])) {
+        return obj[k].map(function(v) {
+          return ks + encodeURIComponent(stringifyPrimitive(v));
+        }).join(sep);
+      } else {
+        return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
+      }
+    }).join(sep);
+
+  }
+
+  if (!name) return '';
+  return encodeURIComponent(stringifyPrimitive(name)) + eq +
+         encodeURIComponent(stringifyPrimitive(obj));
+};
+
+var isArray = Array.isArray || function (xs) {
+  return Object.prototype.toString.call(xs) === '[object Array]';
+};
+
+function map (xs, f) {
+  if (xs.map) return xs.map(f);
+  var res = [];
+  for (var i = 0; i < xs.length; i++) {
+    res.push(f(xs[i], i));
+  }
+  return res;
+}
+
+var objectKeys = Object.keys || function (obj) {
+  var res = [];
+  for (var key in obj) {
+    if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key);
+  }
+  return res;
+};
+
+},{}],43:[function(_dereq_,module,exports){
+'use strict';
+
+exports.decode = exports.parse = _dereq_('./decode');
+exports.encode = exports.stringify = _dereq_('./encode');
+
+},{"./decode":41,"./encode":42}],44:[function(_dereq_,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// 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.
+
+// a duplex stream is just a stream that is both readable and writable.
+// Since JS doesn't have multiple prototypal inheritance, this class
+// prototypally inherits from Readable, and then parasitically from
+// Writable.
+
+module.exports = Duplex;
+var inherits = _dereq_('inherits');
+var setImmediate = _dereq_('process/browser.js').nextTick;
+var Readable = _dereq_('./readable.js');
+var Writable = _dereq_('./writable.js');
+
+inherits(Duplex, Readable);
+
+Duplex.prototype.write = Writable.prototype.write;
+Duplex.prototype.end = Writable.prototype.end;
+Duplex.prototype._write = Writable.prototype._write;
+
+function Duplex(options) {
+  if (!(this instanceof Duplex))
+    return new Duplex(options);
+
+  Readable.call(this, options);
+  Writable.call(this, options);
+
+  if (options && options.readable === false)
+    this.readable = false;
+
+  if (options && options.writable === false)
+    this.writable = false;
+
+  this.allowHalfOpen = true;
+  if (options && options.allowHalfOpen === false)
+    this.allowHalfOpen = false;
+
+  this.once('end', onend);
+}
+
+// the no-half-open enforcer
+function onend() {
+  // if we allow half-open state, or if the writable side ended,
+  // then we're ok.
+  if (this.allowHalfOpen || this._writableState.ended)
+    return;
+
+  // no more data can be written.
+  // But allow more writes to happen in this tick.
+  var self = this;
+  setImmediate(function () {
+    self.end();
+  });
+}
+
+},{"./readable.js":48,"./writable.js":50,"inherits":37,"process/browser.js":46}],45:[function(_dereq_,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// 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.exports = Stream;
+
+var EE = _dereq_('events').EventEmitter;
+var inherits = _dereq_('inherits');
+
+inherits(Stream, EE);
+Stream.Readable = _dereq_('./readable.js');
+Stream.Writable = _dereq_('./writable.js');
+Stream.Duplex = _dereq_('./duplex.js');
+Stream.Transform = _dereq_('./transform.js');
+Stream.PassThrough = _dereq_('./passthrough.js');
+
+// Backwards-compat with node 0.4.x
+Stream.Stream = Stream;
+
+
+
+// old-style streams.  Note that the pipe method (the only relevant
+// part of this class) is overridden in the Readable class.
+
+function Stream() {
+  EE.call(this);
+}
+
+Stream.prototype.pipe = function(dest, options) {
+  var source = this;
+
+  function ondata(chunk) {
+    if (dest.writable) {
+      if (false === dest.write(chunk) && source.pause) {
+        source.pause();
+      }
+    }
+  }
+
+  source.on('data', ondata);
+
+  function ondrain() {
+    if (source.readable && source.resume) {
+      source.resume();
+    }
+  }
+
+  dest.on('drain', ondrain);
+
+  // If the 'end' option is not supplied, dest.end() will be called when
+  // source gets the 'end' or 'close' events.  Only dest.end() once.
+  if (!dest._isStdio && (!options || options.end !== false)) {
+    source.on('end', onend);
+    source.on('close', onclose);
+  }
+
+  var didOnEnd = false;
+  function onend() {
+    if (didOnEnd) return;
+    didOnEnd = true;
+
+    dest.end();
+  }
+
+
+  function onclose() {
+    if (didOnEnd) return;
+    didOnEnd = true;
+
+    if (typeof dest.destroy === 'function') dest.destroy();
+  }
+
+  // don't leave dangling pipes when there are errors.
+  function onerror(er) {
+    cleanup();
+    if (EE.listenerCount(this, 'error') === 0) {
+      throw er; // Unhandled stream error in pipe.
+    }
+  }
+
+  source.on('error', onerror);
+  dest.on('error', onerror);
+
+  // remove all the event listeners that were added.
+  function cleanup() {
+    source.removeListener('data', ondata);
+    dest.removeListener('drain', ondrain);
+
+    source.removeListener('end', onend);
+    source.removeListener('close', onclose);
+
+    source.removeListener('error', onerror);
+    dest.removeListener('error', onerror);
+
+    source.removeListener('end', cleanup);
+    source.removeListener('close', cleanup);
+
+    dest.removeListener('close', cleanup);
+  }
+
+  source.on('end', cleanup);
+  source.on('close', cleanup);
+
+  dest.on('close', cleanup);
+
+  dest.emit('pipe', source);
+
+  // Allow for unix-like usage: A.pipe(B).pipe(C)
+  return dest;
+};
+
+},{"./duplex.js":44,"./passthrough.js":47,"./readable.js":48,"./transform.js":49,"./writable.js":50,"events":31,"inherits":37}],46:[function(_dereq_,module,exports){
+module.exports=_dereq_(38)
+},{}],47:[function(_dereq_,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// 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.
+
+// a passthrough stream.
+// basically just the most minimal sort of Transform stream.
+// Every written chunk gets output as-is.
+
+module.exports = PassThrough;
+
+var Transform = _dereq_('./transform.js');
+var inherits = _dereq_('inherits');
+inherits(PassThrough, Transform);
+
+function PassThrough(options) {
+  if (!(this instanceof PassThrough))
+    return new PassThrough(options);
+
+  Transform.call(this, options);
+}
+
+PassThrough.prototype._transform = function(chunk, encoding, cb) {
+  cb(null, chunk);
+};
+
+},{"./transform.js":49,"inherits":37}],48:[function(_dereq_,module,exports){
+(function (process){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// 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.exports = Readable;
+Readable.ReadableState = ReadableState;
+
+var EE = _dereq_('events').EventEmitter;
+var Stream = _dereq_('./index.js');
+var Buffer = _dereq_('buffer').Buffer;
+var setImmediate = _dereq_('process/browser.js').nextTick;
+var StringDecoder;
+
+var inherits = _dereq_('inherits');
+inherits(Readable, Stream);
+
+function ReadableState(options, stream) {
+  options = options || {};
+
+  // the point at which it stops calling _read() to fill the buffer
+  // Note: 0 is a valid value, means "don't call _read preemptively ever"
+  var hwm = options.highWaterMark;
+  this.highWaterMark = (hwm || hwm === 0) ? hwm : 16 * 1024;
+
+  // cast to ints.
+  this.highWaterMark = ~~this.highWaterMark;
+
+  this.buffer = [];
+  this.length = 0;
+  this.pipes = null;
+  this.pipesCount = 0;
+  this.flowing = false;
+  this.ended = false;
+  this.endEmitted = false;
+  this.reading = false;
+
+  // In streams that never have any data, and do push(null) right away,
+  // the consumer can miss the 'end' event if they do some I/O before
+  // consuming the stream.  So, we don't emit('end') until some reading
+  // happens.
+  this.calledRead = false;
+
+  // a flag to be able to tell if the onwrite cb is called immediately,
+  // or on a later tick.  We set this to true at first, becuase any
+  // actions that shouldn't happen until "later" should generally also
+  // not happen before the first write call.
+  this.sync = true;
+
+  // whenever we return null, then we set a flag to say
+  // that we're awaiting a 'readable' event emission.
+  this.needReadable = false;
+  this.emittedReadable = false;
+  this.readableListening = false;
+
+
+  // object stream flag. Used to make read(n) ignore n and to
+  // make all the buffer merging and length checks go away
+  this.objectMode = !!options.objectMode;
+
+  // Crypto is kind of old and crusty.  Historically, its default string
+  // encoding is 'binary' so we have to make this configurable.
+  // Everything else in the universe uses 'utf8', though.
+  this.defaultEncoding = options.defaultEncoding || 'utf8';
+
+  // when piping, we only care about 'readable' events that happen
+  // after read()ing all the bytes and not getting any pushback.
+  this.ranOut = false;
+
+  // the number of writers that are awaiting a drain event in .pipe()s
+  this.awaitDrain = 0;
+
+  // if true, a maybeReadMore has been scheduled
+  this.readingMore = false;
+
+  this.decoder = null;
+  this.encoding = null;
+  if (options.encoding) {
+    if (!StringDecoder)
+      StringDecoder = _dereq_('string_decoder').StringDecoder;
+    this.decoder = new StringDecoder(options.encoding);
+    this.encoding = options.encoding;
+  }
+}
+
+function Readable(options) {
+  if (!(this instanceof Readable))
+    return new Readable(options);
+
+  this._readableState = new ReadableState(options, this);
+
+  // legacy
+  this.readable = true;
+
+  Stream.call(this);
+}
+
+// Manually shove something into the read() buffer.
+// This returns true if the highWaterMark has not been hit yet,
+// similar to how Writable.write() returns true if you should
+// write() some more.
+Readable.prototype.push = function(chunk, encoding) {
+  var state = this._readableState;
+
+  if (typeof chunk === 'string' && !state.objectMode) {
+    encoding = encoding || state.defaultEncoding;
+    if (encoding !== state.encoding) {
+      chunk = new Buffer(chunk, encoding);
+      encoding = '';
+    }
+  }
+
+  return readableAddChunk(this, state, chunk, encoding, false);
+};
+
+// Unshift should *always* be something directly out of read()
+Readable.prototype.unshift = function(chunk) {
+  var state = this._readableState;
+  return readableAddChunk(this, state, chunk, '', true);
+};
+
+function readableAddChunk(stream, state, chunk, encoding, addToFront) {
+  var er = chunkInvalid(state, chunk);
+  if (er) {
+    stream.emit('error', er);
+  } else if (chunk === null || chunk === undefined) {
+    state.reading = false;
+    if (!state.ended)
+      onEofChunk(stream, state);
+  } else if (state.objectMode || chunk && chunk.length > 0) {
+    if (state.ended && !addToFront) {
+      var e = new Error('stream.push() after EOF');
+      stream.emit('error', e);
+    } else if (state.endEmitted && addToFront) {
+      var e = new Error('stream.unshift() after end event');
+      stream.emit('error', e);
+    } else {
+      if (state.decoder && !addToFront && !encoding)
+        chunk = state.decoder.write(chunk);
+
+      // update the buffer info.
+      state.length += state.objectMode ? 1 : chunk.length;
+      if (addToFront) {
+        state.buffer.unshift(chunk);
+      } else {
+        state.reading = false;
+        state.buffer.push(chunk);
+      }
+
+      if (state.needReadable)
+        emitReadable(stream);
+
+      maybeReadMore(stream, state);
+    }
+  } else if (!addToFront) {
+    state.reading = false;
+  }
+
+  return needMoreData(state);
+}
+
+
+
+// if it's past the high water mark, we can push in some more.
+// Also, if we have no data yet, we can stand some
+// more bytes.  This is to work around cases where hwm=0,
+// such as the repl.  Also, if the push() triggered a
+// readable event, and the user called read(largeNumber) such that
+// needReadable was set, then we ought to push more, so that another
+// 'readable' event will be triggered.
+function needMoreData(state) {
+  return !state.ended &&
+         (state.needReadable ||
+          state.length < state.highWaterMark ||
+          state.length === 0);
+}
+
+// backwards compatibility.
+Readable.prototype.setEncoding = function(enc) {
+  if (!StringDecoder)
+    StringDecoder = _dereq_('string_decoder').StringDecoder;
+  this._readableState.decoder = new StringDecoder(enc);
+  this._readableState.encoding = enc;
+};
+
+// Don't raise the hwm > 128MB
+var MAX_HWM = 0x800000;
+function roundUpToNextPowerOf2(n) {
+  if (n >= MAX_HWM) {
+    n = MAX_HWM;
+  } else {
+    // Get the next highest power of 2
+    n--;
+    for (var p = 1; p < 32; p <<= 1) n |= n >> p;
+    n++;
+  }
+  return n;
+}
+
+function howMuchToRead(n, state) {
+  if (state.length === 0 && state.ended)
+    return 0;
+
+  if (state.objectMode)
+    return n === 0 ? 0 : 1;
+
+  if (isNaN(n) || n === null) {
+    // only flow one buffer at a time
+    if (state.flowing && state.buffer.length)
+      return state.buffer[0].length;
+    else
+      return state.length;
+  }
+
+  if (n <= 0)
+    return 0;
+
+  // If we're asking for more than the target buffer level,
+  // then raise the water mark.  Bump up to the next highest
+  // power of 2, to prevent increasing it excessively in tiny
+  // amounts.
+  if (n > state.highWaterMark)
+    state.highWaterMark = roundUpToNextPowerOf2(n);
+
+  // don't have that much.  return null, unless we've ended.
+  if (n > state.length) {
+    if (!state.ended) {
+      state.needReadable = true;
+      return 0;
+    } else
+      return state.length;
+  }
+
+  return n;
+}
+
+// you can override either this method, or the async _read(n) below.
+Readable.prototype.read = function(n) {
+  var state = this._readableState;
+  state.calledRead = true;
+  var nOrig = n;
+
+  if (typeof n !== 'number' || n > 0)
+    state.emittedReadable = false;
+
+  // if we're doing read(0) to trigger a readable event, but we
+  // already have a bunch of data in the buffer, then just trigger
+  // the 'readable' event and move on.
+  if (n === 0 &&
+      state.needReadable &&
+      (state.length >= state.highWaterMark || state.ended)) {
+    emitReadable(this);
+    return null;
+  }
+
+  n = howMuchToRead(n, state);
+
+  // if we've ended, and we're now clear, then finish it up.
+  if (n === 0 && state.ended) {
+    if (state.length === 0)
+      endReadable(this);
+    return null;
+  }
+
+  // All the actual chunk generation logic needs to be
+  // *below* the call to _read.  The reason is that in certain
+  // synthetic stream cases, such as passthrough streams, _read
+  // may be a completely synchronous operation which may change
+  // the state of the read buffer, providing enough data when
+  // before there was *not* enough.
+  //
+  // So, the steps are:
+  // 1. Figure out what the state of things will be after we do
+  // a read from the buffer.
+  //
+  // 2. If that resulting state will trigger a _read, then call _read.
+  // Note that this may be asynchronous, or synchronous.  Yes, it is
+  // deeply ugly to write APIs this way, but that still doesn't mean
+  // that the Readable class should behave improperly, as streams are
+  // designed to be sync/async agnostic.
+  // Take note if the _read call is sync or async (ie, if the read call
+  // has returned yet), so that we know whether or not it's safe to emit
+  // 'readable' etc.
+  //
+  // 3. Actually pull the requested chunks out of the buffer and return.
+
+  // if we need a readable event, then we need to do some reading.
+  var doRead = state.needReadable;
+
+  // if we currently have less than the highWaterMark, then also read some
+  if (state.length - n <= state.highWaterMark)
+    doRead = true;
+
+  // however, if we've ended, then there's no point, and if we're already
+  // reading, then it's unnecessary.
+  if (state.ended || state.reading)
+    doRead = false;
+
+  if (doRead) {
+    state.reading = true;
+    state.sync = true;
+    // if the length is currently zero, then we *need* a readable event.
+    if (state.length === 0)
+      state.needReadable = true;
+    // call internal read method
+    this._read(state.highWaterMark);
+    state.sync = false;
+  }
+
+  // If _read called its callback synchronously, then `reading`
+  // will be false, and we need to re-evaluate how much data we
+  // can return to the user.
+  if (doRead && !state.reading)
+    n = howMuchToRead(nOrig, state);
+
+  var ret;
+  if (n > 0)
+    ret = fromList(n, state);
+  else
+    ret = null;
+
+  if (ret === null) {
+    state.needReadable = true;
+    n = 0;
+  }
+
+  state.length -= n;
+
+  // If we have nothing in the buffer, then we want to know
+  // as soon as we *do* get something into the buffer.
+  if (state.length === 0 && !state.ended)
+    state.needReadable = true;
+
+  // If we happened to read() exactly the remaining amount in the
+  // buffer, and the EOF has been seen at this point, then make sure
+  // that we emit 'end' on the very next tick.
+  if (state.ended && !state.endEmitted && state.length === 0)
+    endReadable(this);
+
+  return ret;
+};
+
+function chunkInvalid(state, chunk) {
+  var er = null;
+  if (!Buffer.isBuffer(chunk) &&
+      'string' !== typeof chunk &&
+      chunk !== null &&
+      chunk !== undefined &&
+      !state.objectMode &&
+      !er) {
+    er = new TypeError('Invalid non-string/buffer chunk');
+  }
+  return er;
+}
+
+
+function onEofChunk(stream, state) {
+  if (state.decoder && !state.ended) {
+    var chunk = state.decoder.end();
+    if (chunk && chunk.length) {
+      state.buffer.push(chunk);
+      state.length += state.objectMode ? 1 : chunk.length;
+    }
+  }
+  state.ended = true;
+
+  // if we've ended and we have some data left, then emit
+  // 'readable' now to make sure it gets picked up.
+  if (state.length > 0)
+    emitReadable(stream);
+  else
+    endReadable(stream);
+}
+
+// Don't emit readable right away in sync mode, because this can trigger
+// another read() call => stack overflow.  This way, it might trigger
+// a nextTick recursion warning, but that's not so bad.
+function emitReadable(stream) {
+  var state = stream._readableState;
+  state.needReadable = false;
+  if (state.emittedReadable)
+    return;
+
+  state.emittedReadable = true;
+  if (state.sync)
+    setImmediate(function() {
+      emitReadable_(stream);
+    });
+  else
+    emitReadable_(stream);
+}
+
+function emitReadable_(stream) {
+  stream.emit('readable');
+}
+
+
+// at this point, the user has presumably seen the 'readable' event,
+// and called read() to consume some data.  that may have triggered
+// in turn another _read(n) call, in which case reading = true if
+// it's in progress.
+// However, if we're not ended, or reading, and the length < hwm,
+// then go ahead and try to read some more preemptively.
+function maybeReadMore(stream, state) {
+  if (!state.readingMore) {
+    state.readingMore = true;
+    setImmediate(function() {
+      maybeReadMore_(stream, state);
+    });
+  }
+}
+
+function maybeReadMore_(stream, state) {
+  var len = state.length;
+  while (!state.reading && !state.flowing && !state.ended &&
+         state.length < state.highWaterMark) {
+    stream.read(0);
+    if (len === state.length)
+      // didn't get any data, stop spinning.
+      break;
+    else
+      len = state.length;
+  }
+  state.readingMore = false;
+}
+
+// abstract method.  to be overridden in specific implementation classes.
+// call cb(er, data) where data is <= n in length.
+// for virtual (non-string, non-buffer) streams, "length" is somewhat
+// arbitrary, and perhaps not very meaningful.
+Readable.prototype._read = function(n) {
+  this.emit('error', new Error('not implemented'));
+};
+
+Readable.prototype.pipe = function(dest, pipeOpts) {
+  var src = this;
+  var state = this._readableState;
+
+  switch (state.pipesCount) {
+    case 0:
+      state.pipes = dest;
+      break;
+    case 1:
+      state.pipes = [state.pipes, dest];
+      break;
+    default:
+      state.pipes.push(dest);
+      break;
+  }
+  state.pipesCount += 1;
+
+  var doEnd = (!pipeOpts || pipeOpts.end !== false) &&
+              dest !== process.stdout &&
+              dest !== process.stderr;
+
+  var endFn = doEnd ? onend : cleanup;
+  if (state.endEmitted)
+    setImmediate(endFn);
+  else
+    src.once('end', endFn);
+
+  dest.on('unpipe', onunpipe);
+  function onunpipe(readable) {
+    if (readable !== src) return;
+    cleanup();
+  }
+
+  function onend() {
+    dest.end();
+  }
+
+  // when the dest drains, it reduces the awaitDrain counter
+  // on the source.  This would be more elegant with a .once()
+  // handler in flow(), but adding and removing repeatedly is
+  // too slow.
+  var ondrain = pipeOnDrain(src);
+  dest.on('drain', ondrain);
+
+  function cleanup() {
+    // cleanup event handlers once the pipe is broken
+    dest.removeListener('close', onclose);
+    dest.removeListener('finish', onfinish);
+    dest.removeListener('drain', ondrain);
+    dest.removeListener('error', onerror);
+    dest.removeListener('unpipe', onunpipe);
+    src.removeListener('end', onend);
+    src.removeListener('end', cleanup);
+
+    // if the reader is waiting for a drain event from this
+    // specific writer, then it would cause it to never start
+    // flowing again.
+    // So, if this is awaiting a drain, then we just call it now.
+    // If we don't know, then assume that we are waiting for one.
+    if (!dest._writableState || dest._writableState.needDrain)
+      ondrain();
+  }
+
+  // if the dest has an error, then stop piping into it.
+  // however, don't suppress the throwing behavior for this.
+  // check for listeners before emit removes one-time listeners.
+  var errListeners = EE.listenerCount(dest, 'error');
+  function onerror(er) {
+    unpipe();
+    if (errListeners === 0 && EE.listenerCount(dest, 'error') === 0)
+      dest.emit('error', er);
+  }
+  dest.once('error', onerror);
+
+  // Both close and finish should trigger unpipe, but only once.
+  function onclose() {
+    dest.removeListener('finish', onfinish);
+    unpipe();
+  }
+  dest.once('close', onclose);
+  function onfinish() {
+    dest.removeListener('close', onclose);
+    unpipe();
+  }
+  dest.once('finish', onfinish);
+
+  function unpipe() {
+    src.unpipe(dest);
+  }
+
+  // tell the dest that it's being piped to
+  dest.emit('pipe', src);
+
+  // start the flow if it hasn't been started already.
+  if (!state.flowing) {
+    // the handler that waits for readable events after all
+    // the data gets sucked out in flow.
+    // This would be easier to follow with a .once() handler
+    // in flow(), but that is too slow.
+    this.on('readable', pipeOnReadable);
+
+    state.flowing = true;
+    setImmediate(function() {
+      flow(src);
+    });
+  }
+
+  return dest;
+};
+
+function pipeOnDrain(src) {
+  return function() {
+    var dest = this;
+    var state = src._readableState;
+    state.awaitDrain--;
+    if (state.awaitDrain === 0)
+      flow(src);
+  };
+}
+
+function flow(src) {
+  var state = src._readableState;
+  var chunk;
+  state.awaitDrain = 0;
+
+  function write(dest, i, list) {
+    var written = dest.write(chunk);
+    if (false === written) {
+      state.awaitDrain++;
+    }
+  }
+
+  while (state.pipesCount && null !== (chunk = src.read())) {
+
+    if (state.pipesCount === 1)
+      write(state.pipes, 0, null);
+    else
+      forEach(state.pipes, write);
+
+    src.emit('data', chunk);
+
+    // if anyone needs a drain, then we have to wait for that.
+    if (state.awaitDrain > 0)
+      return;
+  }
+
+  // if every destination was unpiped, either before entering this
+  // function, or in the while loop, then stop flowing.
+  //
+  // NB: This is a pretty rare edge case.
+  if (state.pipesCount === 0) {
+    state.flowing = false;
+
+    // if there were data event listeners added, then switch to old mode.
+    if (EE.listenerCount(src, 'data') > 0)
+      emitDataEvents(src);
+    return;
+  }
+
+  // at this point, no one needed a drain, so we just ran out of data
+  // on the next readable event, start it over again.
+  state.ranOut = true;
+}
+
+function pipeOnReadable() {
+  if (this._readableState.ranOut) {
+    this._readableState.ranOut = false;
+    flow(this);
+  }
+}
+
+
+Readable.prototype.unpipe = function(dest) {
+  var state = this._readableState;
+
+  // if we're not piping anywhere, then do nothing.
+  if (state.pipesCount === 0)
+    return this;
+
+  // just one destination.  most common case.
+  if (state.pipesCount === 1) {
+    // passed in one, but it's not the right one.
+    if (dest && dest !== state.pipes)
+      return this;
+
+    if (!dest)
+      dest = state.pipes;
+
+    // got a match.
+    state.pipes = null;
+    state.pipesCount = 0;
+    this.removeListener('readable', pipeOnReadable);
+    state.flowing = false;
+    if (dest)
+      dest.emit('unpipe', this);
+    return this;
+  }
+
+  // slow case. multiple pipe destinations.
+
+  if (!dest) {
+    // remove all.
+    var dests = state.pipes;
+    var len = state.pipesCount;
+    state.pipes = null;
+    state.pipesCount = 0;
+    this.removeListener('readable', pipeOnReadable);
+    state.flowing = false;
+
+    for (var i = 0; i < len; i++)
+      dests[i].emit('unpipe', this);
+    return this;
+  }
+
+  // try to find the right one.
+  var i = indexOf(state.pipes, dest);
+  if (i === -1)
+    return this;
+
+  state.pipes.splice(i, 1);
+  state.pipesCount -= 1;
+  if (state.pipesCount === 1)
+    state.pipes = state.pipes[0];
+
+  dest.emit('unpipe', this);
+
+  return this;
+};
+
+// set up data events if they are asked for
+// Ensure readable listeners eventually get something
+Readable.prototype.on = function(ev, fn) {
+  var res = Stream.prototype.on.call(this, ev, fn);
+
+  if (ev === 'data' && !this._readableState.flowing)
+    emitDataEvents(this);
+
+  if (ev === 'readable' && this.readable) {
+    var state = this._readableState;
+    if (!state.readableListening) {
+      state.readableListening = true;
+      state.emittedReadable = false;
+      state.needReadable = true;
+      if (!state.reading) {
+        this.read(0);
+      } else if (state.length) {
+        emitReadable(this, state);
+      }
+    }
+  }
+
+  return res;
+};
+Readable.prototype.addListener = Readable.prototype.on;
+
+// pause() and resume() are remnants of the legacy readable stream API
+// If the user uses them, then switch into old mode.
+Readable.prototype.resume = function() {
+  emitDataEvents(this);
+  this.read(0);
+  this.emit('resume');
+};
+
+Readable.prototype.pause = function() {
+  emitDataEvents(this, true);
+  this.emit('pause');
+};
+
+function emitDataEvents(stream, startPaused) {
+  var state = stream._readableState;
+
+  if (state.flowing) {
+    // https://github.com/isaacs/readable-stream/issues/16
+    throw new Error('Cannot switch to old mode now.');
+  }
+
+  var paused = startPaused || false;
+  var readable = false;
+
+  // convert to an old-style stream.
+  stream.readable = true;
+  stream.pipe = Stream.prototype.pipe;
+  stream.on = stream.addListener = Stream.prototype.on;
+
+  stream.on('readable', function() {
+    readable = true;
+
+    var c;
+    while (!paused && (null !== (c = stream.read())))
+      stream.emit('data', c);
+
+    if (c === null) {
+      readable = false;
+      stream._readableState.needReadable = true;
+    }
+  });
+
+  stream.pause = function() {
+    paused = true;
+    this.emit('pause');
+  };
+
+  stream.resume = function() {
+    paused = false;
+    if (readable)
+      setImmediate(function() {
+        stream.emit('readable');
+      });
+    else
+      this.read(0);
+    this.emit('resume');
+  };
+
+  // now make it start, just in case it hadn't already.
+  stream.emit('readable');
+}
+
+// wrap an old-style stream as the async data source.
+// This is *not* part of the readable stream interface.
+// It is an ugly unfortunate mess of history.
+Readable.prototype.wrap = function(stream) {
+  var state = this._readableState;
+  var paused = false;
+
+  var self = this;
+  stream.on('end', function() {
+    if (state.decoder && !state.ended) {
+      var chunk = state.decoder.end();
+      if (chunk && chunk.length)
+        self.push(chunk);
+    }
+
+    self.push(null);
+  });
+
+  stream.on('data', function(chunk) {
+    if (state.decoder)
+      chunk = state.decoder.write(chunk);
+    if (!chunk || !state.objectMode && !chunk.length)
+      return;
+
+    var ret = self.push(chunk);
+    if (!ret) {
+      paused = true;
+      stream.pause();
+    }
+  });
+
+  // proxy all the other methods.
+  // important when wrapping filters and duplexes.
+  for (var i in stream) {
+    if (typeof stream[i] === 'function' &&
+        typeof this[i] === 'undefined') {
+      this[i] = function(method) { return function() {
+        return stream[method].apply(stream, arguments);
+      }}(i);
+    }
+  }
+
+  // proxy certain important events.
+  var events = ['error', 'close', 'destroy', 'pause', 'resume'];
+  forEach(events, function(ev) {
+    stream.on(ev, function (x) {
+      return self.emit.apply(self, ev, x);
+    });
+  });
+
+  // when we try to consume some more bytes, simply unpause the
+  // underlying stream.
+  self._read = function(n) {
+    if (paused) {
+      paused = false;
+      stream.resume();
+    }
+  };
+
+  return self;
+};
+
+
+
+// exposed for testing purposes only.
+Readable._fromList = fromList;
+
+// Pluck off n bytes from an array of buffers.
+// Length is the combined lengths of all the buffers in the list.
+function fromList(n, state) {
+  var list = state.buffer;
+  var length = state.length;
+  var stringMode = !!state.decoder;
+  var objectMode = !!state.objectMode;
+  var ret;
+
+  // nothing in the list, definitely empty.
+  if (list.length === 0)
+    return null;
+
+  if (length === 0)
+    ret = null;
+  else if (objectMode)
+    ret = list.shift();
+  else if (!n || n >= length) {
+    // read it all, truncate the array.
+    if (stringMode)
+      ret = list.join('');
+    else
+      ret = Buffer.concat(list, length);
+    list.length = 0;
+  } else {
+    // read just some of it.
+    if (n < list[0].length) {
+      // just take a part of the first list item.
+      // slice is the same for buffers and strings.
+      var buf = list[0];
+      ret = buf.slice(0, n);
+      list[0] = buf.slice(n);
+    } else if (n === list[0].length) {
+      // first list is a perfect match
+      ret = list.shift();
+    } else {
+      // complex case.
+      // we have enough to cover it, but it spans past the first buffer.
+      if (stringMode)
+        ret = '';
+      else
+        ret = new Buffer(n);
+
+      var c = 0;
+      for (var i = 0, l = list.length; i < l && c < n; i++) {
+        var buf = list[0];
+        var cpy = Math.min(n - c, buf.length);
+
+        if (stringMode)
+          ret += buf.slice(0, cpy);
+        else
+          buf.copy(ret, c, 0, cpy);
+
+        if (cpy < buf.length)
+          list[0] = buf.slice(cpy);
+        else
+          list.shift();
+
+        c += cpy;
+      }
+    }
+  }
+
+  return ret;
+}
+
+function endReadable(stream) {
+  var state = stream._readableState;
+
+  // If we get here before consuming all the bytes, then that is a
+  // bug in node.  Should never happen.
+  if (state.length > 0)
+    throw new Error('endReadable called on non-empty stream');
+
+  if (!state.endEmitted && state.calledRead) {
+    state.ended = true;
+    setImmediate(function() {
+      // Check that we didn't get one last unshift.
+      if (!state.endEmitted && state.length === 0) {
+        state.endEmitted = true;
+        stream.readable = false;
+        stream.emit('end');
+      }
+    });
+  }
+}
+
+function forEach (xs, f) {
+  for (var i = 0, l = xs.length; i < l; i++) {
+    f(xs[i], i);
+  }
+}
+
+function indexOf (xs, x) {
+  for (var i = 0, l = xs.length; i < l; i++) {
+    if (xs[i] === x) return i;
+  }
+  return -1;
+}
+
+}).call(this,_dereq_("C:\\Users\\xmr\\Desktop\\clean-css\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"))
+},{"./index.js":45,"C:\\Users\\xmr\\Desktop\\clean-css\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":38,"buffer":28,"events":31,"inherits":37,"process/browser.js":46,"string_decoder":51}],49:[function(_dereq_,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// 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.
+
+// a transform stream is a readable/writable stream where you do
+// something with the data.  Sometimes it's called a "filter",
+// but that's not a great name for it, since that implies a thing where
+// some bits pass through, and others are simply ignored.  (That would
+// be a valid example of a transform, of course.)
+//
+// While the output is causally related to the input, it's not a
+// necessarily symmetric or synchronous transformation.  For example,
+// a zlib stream might take multiple plain-text writes(), and then
+// emit a single compressed chunk some time in the future.
+//
+// Here's how this works:
+//
+// The Transform stream has all the aspects of the readable and writable
+// stream classes.  When you write(chunk), that calls _write(chunk,cb)
+// internally, and returns false if there's a lot of pending writes
+// buffered up.  When you call read(), that calls _read(n) until
+// there's enough pending readable data buffered up.
+//
+// In a transform stream, the written data is placed in a buffer.  When
+// _read(n) is called, it transforms the queued up data, calling the
+// buffered _write cb's as it consumes chunks.  If consuming a single
+// written chunk would result in multiple output chunks, then the first
+// outputted bit calls the readcb, and subsequent chunks just go into
+// the read buffer, and will cause it to emit 'readable' if necessary.
+//
+// This way, back-pressure is actually determined by the reading side,
+// since _read has to be called to start processing a new chunk.  However,
+// a pathological inflate type of transform can cause excessive buffering
+// here.  For example, imagine a stream where every byte of input is
+// interpreted as an integer from 0-255, and then results in that many
+// bytes of output.  Writing the 4 bytes {ff,ff,ff,ff} would result in
+// 1kb of data being output.  In this case, you could write a very small
+// amount of input, and end up with a very large amount of output.  In
+// such a pathological inflating mechanism, there'd be no way to tell
+// the system to stop doing the transform.  A single 4MB write could
+// cause the system to run out of memory.
+//
+// However, even in such a pathological case, only a single written chunk
+// would be consumed, and then the rest would wait (un-transformed) until
+// the results of the previous transformed chunk were consumed.
+
+module.exports = Transform;
+
+var Duplex = _dereq_('./duplex.js');
+var inherits = _dereq_('inherits');
+inherits(Transform, Duplex);
+
+
+function TransformState(options, stream) {
+  this.afterTransform = function(er, data) {
+    return afterTransform(stream, er, data);
+  };
+
+  this.needTransform = false;
+  this.transforming = false;
+  this.writecb = null;
+  this.writechunk = null;
+}
+
+function afterTransform(stream, er, data) {
+  var ts = stream._transformState;
+  ts.transforming = false;
+
+  var cb = ts.writecb;
+
+  if (!cb)
+    return stream.emit('error', new Error('no writecb in Transform class'));
+
+  ts.writechunk = null;
+  ts.writecb = null;
+
+  if (data !== null && data !== undefined)
+    stream.push(data);
+
+  if (cb)
+    cb(er);
+
+  var rs = stream._readableState;
+  rs.reading = false;
+  if (rs.needReadable || rs.length < rs.highWaterMark) {
+    stream._read(rs.highWaterMark);
+  }
+}
+
+
+function Transform(options) {
+  if (!(this instanceof Transform))
+    return new Transform(options);
+
+  Duplex.call(this, options);
+
+  var ts = this._transformState = new TransformState(options, this);
+
+  // when the writable side finishes, then flush out anything remaining.
+  var stream = this;
+
+  // start out asking for a readable event once data is transformed.
+  this._readableState.needReadable = true;
+
+  // we have implemented the _read method, and done the other things
+  // that Readable wants before the first _read call, so unset the
+  // sync guard flag.
+  this._readableState.sync = false;
+
+  this.once('finish', function() {
+    if ('function' === typeof this._flush)
+      this._flush(function(er) {
+        done(stream, er);
+      });
+    else
+      done(stream);
+  });
+}
+
+Transform.prototype.push = function(chunk, encoding) {
+  this._transformState.needTransform = false;
+  return Duplex.prototype.push.call(this, chunk, encoding);
+};
+
+// This is the part where you do stuff!
+// override this function in implementation classes.
+// 'chunk' is an input chunk.
+//
+// Call `push(newChunk)` to pass along transformed output
+// to the readable side.  You may call 'push' zero or more times.
+//
+// Call `cb(err)` when you are done with this chunk.  If you pass
+// an error, then that'll put the hurt on the whole operation.  If you
+// never call cb(), then you'll never get another chunk.
+Transform.prototype._transform = function(chunk, encoding, cb) {
+  throw new Error('not implemented');
+};
+
+Transform.prototype._write = function(chunk, encoding, cb) {
+  var ts = this._transformState;
+  ts.writecb = cb;
+  ts.writechunk = chunk;
+  ts.writeencoding = encoding;
+  if (!ts.transforming) {
+    var rs = this._readableState;
+    if (ts.needTransform ||
+        rs.needReadable ||
+        rs.length < rs.highWaterMark)
+      this._read(rs.highWaterMark);
+  }
+};
+
+// Doesn't matter what the args are here.
+// _transform does all the work.
+// That we got here means that the readable side wants more data.
+Transform.prototype._read = function(n) {
+  var ts = this._transformState;
+
+  if (ts.writechunk && ts.writecb && !ts.transforming) {
+    ts.transforming = true;
+    this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);
+  } else {
+    // mark that we need a transform, so that any data that comes in
+    // will get processed, now that we've asked for it.
+    ts.needTransform = true;
+  }
+};
+
+
+function done(stream, er) {
+  if (er)
+    return stream.emit('error', er);
+
+  // if there's nothing in the write buffer, then that means
+  // that nothing more will ever be provided
+  var ws = stream._writableState;
+  var rs = stream._readableState;
+  var ts = stream._transformState;
+
+  if (ws.length)
+    throw new Error('calling transform done when ws.length != 0');
+
+  if (ts.transforming)
+    throw new Error('calling transform done when still transforming');
+
+  return stream.push(null);
+}
+
+},{"./duplex.js":44,"inherits":37}],50:[function(_dereq_,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// 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.
+
+// A bit simpler than readable streams.
+// Implement an async ._write(chunk, cb), and it'll handle all
+// the drain event emission and buffering.
+
+module.exports = Writable;
+Writable.WritableState = WritableState;
+
+var isUint8Array = typeof Uint8Array !== 'undefined'
+  ? function (x) { return x instanceof Uint8Array }
+  : function (x) {
+    return x && x.constructor && x.constructor.name === 'Uint8Array'
+  }
+;
+var isArrayBuffer = typeof ArrayBuffer !== 'undefined'
+  ? function (x) { return x instanceof ArrayBuffer }
+  : function (x) {
+    return x && x.constructor && x.constructor.name === 'ArrayBuffer'
+  }
+;
+
+var inherits = _dereq_('inherits');
+var Stream = _dereq_('./index.js');
+var setImmediate = _dereq_('process/browser.js').nextTick;
+var Buffer = _dereq_('buffer').Buffer;
+
+inherits(Writable, Stream);
+
+function WriteReq(chunk, encoding, cb) {
+  this.chunk = chunk;
+  this.encoding = encoding;
+  this.callback = cb;
+}
+
+function WritableState(options, stream) {
+  options = options || {};
+
+  // the point at which write() starts returning false
+  // Note: 0 is a valid value, means that we always return false if
+  // the entire buffer is not flushed immediately on write()
+  var hwm = options.highWaterMark;
+  this.highWaterMark = (hwm || hwm === 0) ? hwm : 16 * 1024;
+
+  // object stream flag to indicate whether or not this stream
+  // contains buffers or objects.
+  this.objectMode = !!options.objectMode;
+
+  // cast to ints.
+  this.highWaterMark = ~~this.highWaterMark;
+
+  this.needDrain = false;
+  // at the start of calling end()
+  this.ending = false;
+  // when end() has been called, and returned
+  this.ended = false;
+  // when 'finish' is emitted
+  this.finished = false;
+
+  // should we decode strings into buffers before passing to _write?
+  // this is here so that some node-core streams can optimize string
+  // handling at a lower level.
+  var noDecode = options.decodeStrings === false;
+  this.decodeStrings = !noDecode;
+
+  // Crypto is kind of old and crusty.  Historically, its default string
+  // encoding is 'binary' so we have to make this configurable.
+  // Everything else in the universe uses 'utf8', though.
+  this.defaultEncoding = options.defaultEncoding || 'utf8';
+
+  // not an actual buffer we keep track of, but a measurement
+  // of how much we're waiting to get pushed to some underlying
+  // socket or file.
+  this.length = 0;
+
+  // a flag to see when we're in the middle of a write.
+  this.writing = false;
+
+  // a flag to be able to tell if the onwrite cb is called immediately,
+  // or on a later tick.  We set this to true at first, becuase any
+  // actions that shouldn't happen until "later" should generally also
+  // not happen before the first write call.
+  this.sync = true;
+
+  // a flag to know if we're processing previously buffered items, which
+  // may call the _write() callback in the same tick, so that we don't
+  // end up in an overlapped onwrite situation.
+  this.bufferProcessing = false;
+
+  // the callback that's passed to _write(chunk,cb)
+  this.onwrite = function(er) {
+    onwrite(stream, er);
+  };
+
+  // the callback that the user supplies to write(chunk,encoding,cb)
+  this.writecb = null;
+
+  // the amount that is being written when _write is called.
+  this.writelen = 0;
+
+  this.buffer = [];
+}
+
+function Writable(options) {
+  // Writable ctor is applied to Duplexes, though they're not
+  // instanceof Writable, they're instanceof Readable.
+  if (!(this instanceof Writable) && !(this instanceof Stream.Duplex))
+    return new Writable(options);
+
+  this._writableState = new WritableState(options, this);
+
+  // legacy.
+  this.writable = true;
+
+  Stream.call(this);
+}
+
+// Otherwise people can pipe Writable streams, which is just wrong.
+Writable.prototype.pipe = function() {
+  this.emit('error', new Error('Cannot pipe. Not readable.'));
+};
+
+
+function writeAfterEnd(stream, state, cb) {
+  var er = new Error('write after end');
+  // TODO: defer error events consistently everywhere, not just the cb
+  stream.emit('error', er);
+  setImmediate(function() {
+    cb(er);
+  });
+}
+
+// If we get something that is not a buffer, string, null, or undefined,
+// and we're not in objectMode, then that's an error.
+// Otherwise stream chunks are all considered to be of length=1, and the
+// watermarks determine how many objects to keep in the buffer, rather than
+// how many bytes or characters.
+function validChunk(stream, state, chunk, cb) {
+  var valid = true;
+  if (!Buffer.isBuffer(chunk) &&
+      'string' !== typeof chunk &&
+      chunk !== null &&
+      chunk !== undefined &&
+      !state.objectMode) {
+    var er = new TypeError('Invalid non-string/buffer chunk');
+    stream.emit('error', er);
+    setImmediate(function() {
+      cb(er);
+    });
+    valid = false;
+  }
+  return valid;
+}
+
+Writable.prototype.write = function(chunk, encoding, cb) {
+  var state = this._writableState;
+  var ret = false;
+
+  if (typeof encoding === 'function') {
+    cb = encoding;
+    encoding = null;
+  }
+
+  if (!Buffer.isBuffer(chunk) && isUint8Array(chunk))
+    chunk = new Buffer(chunk);
+  if (isArrayBuffer(chunk) && typeof Uint8Array !== 'undefined')
+    chunk = new Buffer(new Uint8Array(chunk));
+  
+  if (Buffer.isBuffer(chunk))
+    encoding = 'buffer';
+  else if (!encoding)
+    encoding = state.defaultEncoding;
+
+  if (typeof cb !== 'function')
+    cb = function() {};
+
+  if (state.ended)
+    writeAfterEnd(this, state, cb);
+  else if (validChunk(this, state, chunk, cb))
+    ret = writeOrBuffer(this, state, chunk, encoding, cb);
+
+  return ret;
+};
+
+function decodeChunk(state, chunk, encoding) {
+  if (!state.objectMode &&
+      state.decodeStrings !== false &&
+      typeof chunk === 'string') {
+    chunk = new Buffer(chunk, encoding);
+  }
+  return chunk;
+}
+
+// if we're already writing something, then just put this
+// in the queue, and wait our turn.  Otherwise, call _write
+// If we return false, then we need a drain event, so set that flag.
+function writeOrBuffer(stream, state, chunk, encoding, cb) {
+  chunk = decodeChunk(state, chunk, encoding);
+  var len = state.objectMode ? 1 : chunk.length;
+
+  state.length += len;
+
+  var ret = state.length < state.highWaterMark;
+  state.needDrain = !ret;
+
+  if (state.writing)
+    state.buffer.push(new WriteReq(chunk, encoding, cb));
+  else
+    doWrite(stream, state, len, chunk, encoding, cb);
+
+  return ret;
+}
+
+function doWrite(stream, state, len, chunk, encoding, cb) {
+  state.writelen = len;
+  state.writecb = cb;
+  state.writing = true;
+  state.sync = true;
+  stream._write(chunk, encoding, state.onwrite);
+  state.sync = false;
+}
+
+function onwriteError(stream, state, sync, er, cb) {
+  if (sync)
+    setImmediate(function() {
+      cb(er);
+    });
+  else
+    cb(er);
+
+  stream.emit('error', er);
+}
+
+function onwriteStateUpdate(state) {
+  state.writing = false;
+  state.writecb = null;
+  state.length -= state.writelen;
+  state.writelen = 0;
+}
+
+function onwrite(stream, er) {
+  var state = stream._writableState;
+  var sync = state.sync;
+  var cb = state.writecb;
+
+  onwriteStateUpdate(state);
+
+  if (er)
+    onwriteError(stream, state, sync, er, cb);
+  else {
+    // Check if we're actually ready to finish, but don't emit yet
+    var finished = needFinish(stream, state);
+
+    if (!finished && !state.bufferProcessing && state.buffer.length)
+      clearBuffer(stream, state);
+
+    if (sync) {
+      setImmediate(function() {
+        afterWrite(stream, state, finished, cb);
+      });
+    } else {
+      afterWrite(stream, state, finished, cb);
+    }
+  }
+}
+
+function afterWrite(stream, state, finished, cb) {
+  if (!finished)
+    onwriteDrain(stream, state);
+  cb();
+  if (finished)
+    finishMaybe(stream, state);
+}
+
+// Must force callback to be called on nextTick, so that we don't
+// emit 'drain' before the write() consumer gets the 'false' return
+// value, and has a chance to attach a 'drain' listener.
+function onwriteDrain(stream, state) {
+  if (state.length === 0 && state.needDrain) {
+    state.needDrain = false;
+    stream.emit('drain');
+  }
+}
+
+
+// if there's something in the buffer waiting, then process it
+function clearBuffer(stream, state) {
+  state.bufferProcessing = true;
+
+  for (var c = 0; c < state.buffer.length; c++) {
+    var entry = state.buffer[c];
+    var chunk = entry.chunk;
+    var encoding = entry.encoding;
+    var cb = entry.callback;
+    var len = state.objectMode ? 1 : chunk.length;
+
+    doWrite(stream, state, len, chunk, encoding, cb);
+
+    // if we didn't call the onwrite immediately, then
+    // it means that we need to wait until it does.
+    // also, that means that the chunk and cb are currently
+    // being processed, so move the buffer counter past them.
+    if (state.writing) {
+      c++;
+      break;
+    }
+  }
+
+  state.bufferProcessing = false;
+  if (c < state.buffer.length)
+    state.buffer = state.buffer.slice(c);
+  else
+    state.buffer.length = 0;
+}
+
+Writable.prototype._write = function(chunk, encoding, cb) {
+  cb(new Error('not implemented'));
+};
+
+Writable.prototype.end = function(chunk, encoding, cb) {
+  var state = this._writableState;
+
+  if (typeof chunk === 'function') {
+    cb = chunk;
+    chunk = null;
+    encoding = null;
+  } else if (typeof encoding === 'function') {
+    cb = encoding;
+    encoding = null;
+  }
+
+  if (typeof chunk !== 'undefined' && chunk !== null)
+    this.write(chunk, encoding);
+
+  // ignore unnecessary end() calls.
+  if (!state.ending && !state.finished)
+    endWritable(this, state, cb);
+};
+
+
+function needFinish(stream, state) {
+  return (state.ending &&
+          state.length === 0 &&
+          !state.finished &&
+          !state.writing);
+}
+
+function finishMaybe(stream, state) {
+  var need = needFinish(stream, state);
+  if (need) {
+    state.finished = true;
+    stream.emit('finish');
+  }
+  return need;
+}
+
+function endWritable(stream, state, cb) {
+  state.ending = true;
+  finishMaybe(stream, state);
+  if (cb) {
+    if (state.finished)
+      setImmediate(cb);
+    else
+      stream.once('finish', cb);
+  }
+  state.ended = true;
+}
+
+},{"./index.js":45,"buffer":28,"inherits":37,"process/browser.js":46}],51:[function(_dereq_,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// 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.
+
+var Buffer = _dereq_('buffer').Buffer;
+
+function assertEncoding(encoding) {
+  if (encoding && !Buffer.isEncoding(encoding)) {
+    throw new Error('Unknown encoding: ' + encoding);
+  }
+}
+
+var StringDecoder = exports.StringDecoder = function(encoding) {
+  this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, '');
+  assertEncoding(encoding);
+  switch (this.encoding) {
+    case 'utf8':
+      // CESU-8 represents each of Surrogate Pair by 3-bytes
+      this.surrogateSize = 3;
+      break;
+    case 'ucs2':
+    case 'utf16le':
+      // UTF-16 represents each of Surrogate Pair by 2-bytes
+      this.surrogateSize = 2;
+      this.detectIncompleteChar = utf16DetectIncompleteChar;
+      break;
+    case 'base64':
+      // Base-64 stores 3 bytes in 4 chars, and pads the remainder.
+      this.surrogateSize = 3;
+      this.detectIncompleteChar = base64DetectIncompleteChar;
+      break;
+    default:
+      this.write = passThroughWrite;
+      return;
+  }
+
+  this.charBuffer = new Buffer(6);
+  this.charReceived = 0;
+  this.charLength = 0;
+};
+
+
+StringDecoder.prototype.write = function(buffer) {
+  var charStr = '';
+  var offset = 0;
+
+  // if our last write ended with an incomplete multibyte character
+  while (this.charLength) {
+    // determine how many remaining bytes this buffer has to offer for this char
+    var i = (buffer.length >= this.charLength - this.charReceived) ?
+                this.charLength - this.charReceived :
+                buffer.length;
+
+    // add the new bytes to the char buffer
+    buffer.copy(this.charBuffer, this.charReceived, offset, i);
+    this.charReceived += (i - offset);
+    offset = i;
+
+    if (this.charReceived < this.charLength) {
+      // still not enough chars in this buffer? wait for more ...
+      return '';
+    }
+
+    // get the character that was split
+    charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding);
+
+    // lead surrogate (D800-DBFF) is also the incomplete character
+    var charCode = charStr.charCodeAt(charStr.length - 1);
+    if (charCode >= 0xD800 && charCode <= 0xDBFF) {
+      this.charLength += this.surrogateSize;
+      charStr = '';
+      continue;
+    }
+    this.charReceived = this.charLength = 0;
+
+    // if there are no more bytes in this buffer, just emit our char
+    if (i == buffer.length) return charStr;
+
+    // otherwise cut off the characters end from the beginning of this buffer
+    buffer = buffer.slice(i, buffer.length);
+    break;
+  }
+
+  var lenIncomplete = this.detectIncompleteChar(buffer);
+
+  var end = buffer.length;
+  if (this.charLength) {
+    // buffer the incomplete character bytes we got
+    buffer.copy(this.charBuffer, 0, buffer.length - lenIncomplete, end);
+    this.charReceived = lenIncomplete;
+    end -= lenIncomplete;
+  }
+
+  charStr += buffer.toString(this.encoding, 0, end);
+
+  var end = charStr.length - 1;
+  var charCode = charStr.charCodeAt(end);
+  // lead surrogate (D800-DBFF) is also the incomplete character
+  if (charCode >= 0xD800 && charCode <= 0xDBFF) {
+    var size = this.surrogateSize;
+    this.charLength += size;
+    this.charReceived += size;
+    this.charBuffer.copy(this.charBuffer, size, 0, size);
+    this.charBuffer.write(charStr.charAt(charStr.length - 1), this.encoding);
+    return charStr.substring(0, end);
+  }
+
+  // or just emit the charStr
+  return charStr;
+};
+
+StringDecoder.prototype.detectIncompleteChar = function(buffer) {
+  // determine how many bytes we have to check at the end of this buffer
+  var i = (buffer.length >= 3) ? 3 : buffer.length;
+
+  // Figure out if one of the last i bytes of our buffer announces an
+  // incomplete char.
+  for (; i > 0; i--) {
+    var c = buffer[buffer.length - i];
+
+    // See http://en.wikipedia.org/wiki/UTF-8#Description
+
+    // 110XXXXX
+    if (i == 1 && c >> 5 == 0x06) {
+      this.charLength = 2;
+      break;
+    }
+
+    // 1110XXXX
+    if (i <= 2 && c >> 4 == 0x0E) {
+      this.charLength = 3;
+      break;
+    }
+
+    // 11110XXX
+    if (i <= 3 && c >> 3 == 0x1E) {
+      this.charLength = 4;
+      break;
+    }
+  }
+
+  return i;
+};
+
+StringDecoder.prototype.end = function(buffer) {
+  var res = '';
+  if (buffer && buffer.length)
+    res = this.write(buffer);
+
+  if (this.charReceived) {
+    var cr = this.charReceived;
+    var buf = this.charBuffer;
+    var enc = this.encoding;
+    res += buf.slice(0, cr).toString(enc);
+  }
+
+  return res;
+};
+
+function passThroughWrite(buffer) {
+  return buffer.toString(this.encoding);
+}
+
+function utf16DetectIncompleteChar(buffer) {
+  var incomplete = this.charReceived = buffer.length % 2;
+  this.charLength = incomplete ? 2 : 0;
+  return incomplete;
+}
+
+function base64DetectIncompleteChar(buffer) {
+  var incomplete = this.charReceived = buffer.length % 3;
+  this.charLength = incomplete ? 3 : 0;
+  return incomplete;
+}
+
+},{"buffer":28}],52:[function(_dereq_,module,exports){
+/*jshint strict:true node:true es5:true onevar:true laxcomma:true laxbreak:true eqeqeq:true immed:true latedef:true*/
+(function () {
+  "use strict";
+
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// 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.
+
+var punycode = _dereq_('punycode');
+
+exports.parse = urlParse;
+exports.resolve = urlResolve;
+exports.resolveObject = urlResolveObject;
+exports.format = urlFormat;
+
+// Reference: RFC 3986, RFC 1808, RFC 2396
+
+// define these here so at least they only have to be
+// compiled once on the first module load.
+var protocolPattern = /^([a-z0-9.+-]+:)/i,
+    portPattern = /:[0-9]*$/,
+
+    // RFC 2396: characters reserved for delimiting URLs.
+    // We actually just auto-escape these.
+    delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'],
+
+    // RFC 2396: characters not allowed for various reasons.
+    unwise = ['{', '}', '|', '\\', '^', '~', '`'].concat(delims),
+
+    // Allowed by RFCs, but cause of XSS attacks.  Always escape these.
+    autoEscape = ['\''].concat(delims),
+    // Characters that are never ever allowed in a hostname.
+    // Note that any invalid chars are also handled, but these
+    // are the ones that are *expected* to be seen, so we fast-path
+    // them.
+    nonHostChars = ['%', '/', '?', ';', '#']
+      .concat(unwise).concat(autoEscape),
+    nonAuthChars = ['/', '@', '?', '#'].concat(delims),
+    hostnameMaxLen = 255,
+    hostnamePartPattern = /^[a-zA-Z0-9][a-z0-9A-Z_-]{0,62}$/,
+    hostnamePartStart = /^([a-zA-Z0-9][a-z0-9A-Z_-]{0,62})(.*)$/,
+    // protocols that can allow "unsafe" and "unwise" chars.
+    unsafeProtocol = {
+      'javascript': true,
+      'javascript:': true
+    },
+    // protocols that never have a hostname.
+    hostlessProtocol = {
+      'javascript': true,
+      'javascript:': true
+    },
+    // protocols that always have a path component.
+    pathedProtocol = {
+      'http': true,
+      'https': true,
+      'ftp': true,
+      'gopher': true,
+      'file': true,
+      'http:': true,
+      'ftp:': true,
+      'gopher:': true,
+      'file:': true
+    },
+    // protocols that always contain a // bit.
+    slashedProtocol = {
+      'http': true,
+      'https': true,
+      'ftp': true,
+      'gopher': true,
+      'file': true,
+      'http:': true,
+      'https:': true,
+      'ftp:': true,
+      'gopher:': true,
+      'file:': true
+    },
+    querystring = _dereq_('querystring');
+
+function urlParse(url, parseQueryString, slashesDenoteHost) {
+  if (url && typeof(url) === 'object' && url.href) return url;
+
+  if (typeof url !== 'string') {
+    throw new TypeError("Parameter 'url' must be a string, not " + typeof url);
+  }
+
+  var out = {},
+      rest = url;
+
+  // trim before proceeding.
+  // This is to support parse stuff like "  http://foo.com  \n"
+  rest = rest.trim();
+
+  var proto = protocolPattern.exec(rest);
+  if (proto) {
+    proto = proto[0];
+    var lowerProto = proto.toLowerCase();
+    out.protocol = lowerProto;
+    rest = rest.substr(proto.length);
+  }
+
+  // figure out if it's got a host
+  // user@server is *always* interpreted as a hostname, and url
+  // resolution will treat //foo/bar as host=foo,path=bar because that's
+  // how the browser resolves relative URLs.
+  if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
+    var slashes = rest.substr(0, 2) === '//';
+    if (slashes && !(proto && hostlessProtocol[proto])) {
+      rest = rest.substr(2);
+      out.slashes = true;
+    }
+  }
+
+  if (!hostlessProtocol[proto] &&
+      (slashes || (proto && !slashedProtocol[proto]))) {
+    // there's a hostname.
+    // the first instance of /, ?, ;, or # ends the host.
+    // don't enforce full RFC correctness, just be unstupid about it.
+
+    // If there is an @ in the hostname, then non-host chars *are* allowed
+    // to the left of the first @ sign, unless some non-auth character
+    // comes *before* the @-sign.
+    // URLs are obnoxious.
+    var atSign = rest.indexOf('@');
+    if (atSign !== -1) {
+      var auth = rest.slice(0, atSign);
+
+      // there *may be* an auth
+      var hasAuth = true;
+      for (var i = 0, l = nonAuthChars.length; i < l; i++) {
+        if (auth.indexOf(nonAuthChars[i]) !== -1) {
+          // not a valid auth.  Something like http://foo.com/bar@baz/
+          hasAuth = false;
+          break;
+        }
+      }
+
+      if (hasAuth) {
+        // pluck off the auth portion.
+        out.auth = decodeURIComponent(auth);
+        rest = rest.substr(atSign + 1);
+      }
+    }
+
+    var firstNonHost = -1;
+    for (var i = 0, l = nonHostChars.length; i < l; i++) {
+      var index = rest.indexOf(nonHostChars[i]);
+      if (index !== -1 &&
+          (firstNonHost < 0 || index < firstNonHost)) firstNonHost = index;
+    }
+
+    if (firstNonHost !== -1) {
+      out.host = rest.substr(0, firstNonHost);
+      rest = rest.substr(firstNonHost);
+    } else {
+      out.host = rest;
+      rest = '';
+    }
+
+    // pull out port.
+    var p = parseHost(out.host);
+    var keys = Object.keys(p);
+    for (var i = 0, l = keys.length; i < l; i++) {
+      var key = keys[i];
+      out[key] = p[key];
+    }
+
+    // we've indicated that there is a hostname,
+    // so even if it's empty, it has to be present.
+    out.hostname = out.hostname || '';
+
+    // if hostname begins with [ and ends with ]
+    // assume that it's an IPv6 address.
+    var ipv6Hostname = out.hostname[0] === '[' &&
+        out.hostname[out.hostname.length - 1] === ']';
+
+    // validate a little.
+    if (out.hostname.length > hostnameMaxLen) {
+      out.hostname = '';
+    } else if (!ipv6Hostname) {
+      var hostparts = out.hostname.split(/\./);
+      for (var i = 0, l = hostparts.length; i < l; i++) {
+        var part = hostparts[i];
+        if (!part) continue;
+        if (!part.match(hostnamePartPattern)) {
+          var newpart = '';
+          for (var j = 0, k = part.length; j < k; j++) {
+            if (part.charCodeAt(j) > 127) {
+              // we replace non-ASCII char with a temporary placeholder
+              // we need this to make sure size of hostname is not
+              // broken by replacing non-ASCII by nothing
+              newpart += 'x';
+            } else {
+              newpart += part[j];
+            }
+          }
+          // we test again with ASCII char only
+          if (!newpart.match(hostnamePartPattern)) {
+            var validParts = hostparts.slice(0, i);
+            var notHost = hostparts.slice(i + 1);
+            var bit = part.match(hostnamePartStart);
+            if (bit) {
+              validParts.push(bit[1]);
+              notHost.unshift(bit[2]);
+            }
+            if (notHost.length) {
+              rest = '/' + notHost.join('.') + rest;
+            }
+            out.hostname = validParts.join('.');
+            break;
+          }
+        }
+      }
+    }
+
+    // hostnames are always lower case.
+    out.hostname = out.hostname.toLowerCase();
+
+    if (!ipv6Hostname) {
+      // IDNA Support: Returns a puny coded representation of "domain".
+      // It only converts the part of the domain name that
+      // has non ASCII characters. I.e. it dosent matter if
+      // you call it with a domain that already is in ASCII.
+      var domainArray = out.hostname.split('.');
+      var newOut = [];
+      for (var i = 0; i < domainArray.length; ++i) {
+        var s = domainArray[i];
+        newOut.push(s.match(/[^A-Za-z0-9_-]/) ?
+            'xn--' + punycode.encode(s) : s);
+      }
+      out.hostname = newOut.join('.');
+    }
+
+    out.host = (out.hostname || '') +
+        ((out.port) ? ':' + out.port : '');
+    out.href += out.host;
+
+    // strip [ and ] from the hostname
+    if (ipv6Hostname) {
+      out.hostname = out.hostname.substr(1, out.hostname.length - 2);
+      if (rest[0] !== '/') {
+        rest = '/' + rest;
+      }
+    }
+  }
+
+  // now rest is set to the post-host stuff.
+  // chop off any delim chars.
+  if (!unsafeProtocol[lowerProto]) {
+
+    // First, make 100% sure that any "autoEscape" chars get
+    // escaped, even if encodeURIComponent doesn't think they
+    // need to be.
+    for (var i = 0, l = autoEscape.length; i < l; i++) {
+      var ae = autoEscape[i];
+      var esc = encodeURIComponent(ae);
+      if (esc === ae) {
+        esc = escape(ae);
+      }
+      rest = rest.split(ae).join(esc);
+    }
+  }
+
+
+  // chop off from the tail first.
+  var hash = rest.indexOf('#');
+  if (hash !== -1) {
+    // got a fragment string.
+    out.hash = rest.substr(hash);
+    rest = rest.slice(0, hash);
+  }
+  var qm = rest.indexOf('?');
+  if (qm !== -1) {
+    out.search = rest.substr(qm);
+    out.query = rest.substr(qm + 1);
+    if (parseQueryString) {
+      out.query = querystring.parse(out.query);
+    }
+    rest = rest.slice(0, qm);
+  } else if (parseQueryString) {
+    // no query string, but parseQueryString still requested
+    out.search = '';
+    out.query = {};
+  }
+  if (rest) out.pathname = rest;
+  if (slashedProtocol[proto] &&
+      out.hostname && !out.pathname) {
+    out.pathname = '/';
+  }
+
+  //to support http.request
+  if (out.pathname || out.search) {
+    out.path = (out.pathname ? out.pathname : '') +
+               (out.search ? out.search : '');
+  }
+
+  // finally, reconstruct the href based on what has been validated.
+  out.href = urlFormat(out);
+  return out;
+}
+
+// format a parsed object into a url string
+function urlFormat(obj) {
+  // ensure it's an object, and not a string url.
+  // If it's an obj, this is a no-op.
+  // this way, you can call url_format() on strings
+  // to clean up potentially wonky urls.
+  if (typeof(obj) === 'string') obj = urlParse(obj);
+
+  var auth = obj.auth || '';
+  if (auth) {
+    auth = encodeURIComponent(auth);
+    auth = auth.replace(/%3A/i, ':');
+    auth += '@';
+  }
+
+  var protocol = obj.protocol || '',
+      pathname = obj.pathname || '',
+      hash = obj.hash || '',
+      host = false,
+      query = '';
+
+  if (obj.host !== undefined) {
+    host = auth + obj.host;
+  } else if (obj.hostname !== undefined) {
+    host = auth + (obj.hostname.indexOf(':') === -1 ?
+        obj.hostname :
+        '[' + obj.hostname + ']');
+    if (obj.port) {
+      host += ':' + obj.port;
+    }
+  }
+
+  if (obj.query && typeof obj.query === 'object' &&
+      Object.keys(obj.query).length) {
+    query = querystring.stringify(obj.query);
+  }
+
+  var search = obj.search || (query && ('?' + query)) || '';
+
+  if (protocol && protocol.substr(-1) !== ':') protocol += ':';
+
+  // only the slashedProtocols get the //.  Not mailto:, xmpp:, etc.
+  // unless they had them to begin with.
+  if (obj.slashes ||
+      (!protocol || slashedProtocol[protocol]) && host !== false) {
+    host = '//' + (host || '');
+    if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname;
+  } else if (!host) {
+    host = '';
+  }
+
+  if (hash && hash.charAt(0) !== '#') hash = '#' + hash;
+  if (search && search.charAt(0) !== '?') search = '?' + search;
+
+  return protocol + host + pathname + search + hash;
+}
+
+function urlResolve(source, relative) {
+  return urlFormat(urlResolveObject(source, relative));
+}
+
+function urlResolveObject(source, relative) {
+  if (!source) return relative;
+
+  source = urlParse(urlFormat(source), false, true);
+  relative = urlParse(urlFormat(relative), false, true);
+
+  // hash is always overridden, no matter what.
+  source.hash = relative.hash;
+
+  if (relative.href === '') {
+    source.href = urlFormat(source);
+    return source;
+  }
+
+  // hrefs like //foo/bar always cut to the protocol.
+  if (relative.slashes && !relative.protocol) {
+    relative.protocol = source.protocol;
+    //urlParse appends trailing / to urls like http://www.example.com
+    if (slashedProtocol[relative.protocol] &&
+        relative.hostname && !relative.pathname) {
+      relative.path = relative.pathname = '/';
+    }
+    relative.href = urlFormat(relative);
+    return relative;
+  }
+
+  if (relative.protocol && relative.protocol !== source.protocol) {
+    // if it's a known url protocol, then changing
+    // the protocol does weird things
+    // first, if it's not file:, then we MUST have a host,
+    // and if there was a path
+    // to begin with, then we MUST have a path.
+    // if it is file:, then the host is dropped,
+    // because that's known to be hostless.
+    // anything else is assumed to be absolute.
+    if (!slashedProtocol[relative.protocol]) {
+      relative.href = urlFormat(relative);
+      return relative;
+    }
+    source.protocol = relative.protocol;
+    if (!relative.host && !hostlessProtocol[relative.protocol]) {
+      var relPath = (relative.pathname || '').split('/');
+      while (relPath.length && !(relative.host = relPath.shift()));
+      if (!relative.host) relative.host = '';
+      if (!relative.hostname) relative.hostname = '';
+      if (relPath[0] !== '') relPath.unshift('');
+      if (relPath.length < 2) relPath.unshift('');
+      relative.pathname = relPath.join('/');
+    }
+    source.pathname = relative.pathname;
+    source.search = relative.search;
+    source.query = relative.query;
+    source.host = relative.host || '';
+    source.auth = relative.auth;
+    source.hostname = relative.hostname || relative.host;
+    source.port = relative.port;
+    //to support http.request
+    if (source.pathname !== undefined || source.search !== undefined) {
+      source.path = (source.pathname ? source.pathname : '') +
+                    (source.search ? source.search : '');
+    }
+    source.slashes = source.slashes || relative.slashes;
+    source.href = urlFormat(source);
+    return source;
+  }
+
+  var isSourceAbs = (source.pathname && source.pathname.charAt(0) === '/'),
+      isRelAbs = (
+          relative.host !== undefined ||
+          relative.pathname && relative.pathname.charAt(0) === '/'
+      ),
+      mustEndAbs = (isRelAbs || isSourceAbs ||
+                    (source.host && relative.pathname)),
+      removeAllDots = mustEndAbs,
+      srcPath = source.pathname && source.pathname.split('/') || [],
+      relPath = relative.pathname && relative.pathname.split('/') || [],
+      psychotic = source.protocol &&
+          !slashedProtocol[source.protocol];
+
+  // if the url is a non-slashed url, then relative
+  // links like ../.. should be able
+  // to crawl up to the hostname, as well.  This is strange.
+  // source.protocol has already been set by now.
+  // Later on, put the first path part into the host field.
+  if (psychotic) {
+
+    delete source.hostname;
+    delete source.port;
+    if (source.host) {
+      if (srcPath[0] === '') srcPath[0] = source.host;
+      else srcPath.unshift(source.host);
+    }
+    delete source.host;
+    if (relative.protocol) {
+      delete relative.hostname;
+      delete relative.port;
+      if (relative.host) {
+        if (relPath[0] === '') relPath[0] = relative.host;
+        else relPath.unshift(relative.host);
+      }
+      delete relative.host;
+    }
+    mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === '');
+  }
+
+  if (isRelAbs) {
+    // it's absolute.
+    source.host = (relative.host || relative.host === '') ?
+                      relative.host : source.host;
+    source.hostname = (relative.hostname || relative.hostname === '') ?
+                      relative.hostname : source.hostname;
+    source.search = relative.search;
+    source.query = relative.query;
+    srcPath = relPath;
+    // fall through to the dot-handling below.
+  } else if (relPath.length) {
+    // it's relative
+    // throw away the existing file, and take the new path instead.
+    if (!srcPath) srcPath = [];
+    srcPath.pop();
+    srcPath = srcPath.concat(relPath);
+    source.search = relative.search;
+    source.query = relative.query;
+  } else if ('search' in relative) {
+    // just pull out the search.
+    // like href='?foo'.
+    // Put this after the other two cases because it simplifies the booleans
+    if (psychotic) {
+      source.hostname = source.host = srcPath.shift();
+      //occationaly the auth can get stuck only in host
+      //this especialy happens in cases like
+      //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
+      var authInHost = source.host && source.host.indexOf('@') > 0 ?
+                       source.host.split('@') : false;
+      if (authInHost) {
+        source.auth = authInHost.shift();
+        source.host = source.hostname = authInHost.shift();
+      }
+    }
+    source.search = relative.search;
+    source.query = relative.query;
+    //to support http.request
+    if (source.pathname !== undefined || source.search !== undefined) {
+      source.path = (source.pathname ? source.pathname : '') +
+                    (source.search ? source.search : '');
+    }
+    source.href = urlFormat(source);
+    return source;
+  }
+  if (!srcPath.length) {
+    // no path at all.  easy.
+    // we've already handled the other stuff above.
+    delete source.pathname;
+    //to support http.request
+    if (!source.search) {
+      source.path = '/' + source.search;
+    } else {
+      delete source.path;
+    }
+    source.href = urlFormat(source);
+    return source;
+  }
+  // if a url ENDs in . or .., then it must get a trailing slash.
+  // however, if it ends in anything else non-slashy,
+  // then it must NOT get a trailing slash.
+  var last = srcPath.slice(-1)[0];
+  var hasTrailingSlash = (
+      (source.host || relative.host) && (last === '.' || last === '..') ||
+      last === '');
+
+  // strip single dots, resolve double dots to parent dir
+  // if the path tries to go above the root, `up` ends up > 0
+  var up = 0;
+  for (var i = srcPath.length; i >= 0; i--) {
+    last = srcPath[i];
+    if (last == '.') {
+      srcPath.splice(i, 1);
+    } else if (last === '..') {
+      srcPath.splice(i, 1);
+      up++;
+    } else if (up) {
+      srcPath.splice(i, 1);
+      up--;
+    }
+  }
+
+  // if the path is allowed to go above the root, restore leading ..s
+  if (!mustEndAbs && !removeAllDots) {
+    for (; up--; up) {
+      srcPath.unshift('..');
+    }
+  }
+
+  if (mustEndAbs && srcPath[0] !== '' &&
+      (!srcPath[0] || srcPath[0].charAt(0) !== '/')) {
+    srcPath.unshift('');
+  }
+
+  if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) {
+    srcPath.push('');
+  }
+
+  var isAbsolute = srcPath[0] === '' ||
+      (srcPath[0] && srcPath[0].charAt(0) === '/');
+
+  // put the host back
+  if (psychotic) {
+    source.hostname = source.host = isAbsolute ? '' :
+                                    srcPath.length ? srcPath.shift() : '';
+    //occationaly the auth can get stuck only in host
+    //this especialy happens in cases like
+    //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
+    var authInHost = source.host && source.host.indexOf('@') > 0 ?
+                     source.host.split('@') : false;
+    if (authInHost) {
+      source.auth = authInHost.shift();
+      source.host = source.hostname = authInHost.shift();
+    }
+  }
+
+  mustEndAbs = mustEndAbs || (source.host && srcPath.length);
+
+  if (mustEndAbs && !isAbsolute) {
+    srcPath.unshift('');
+  }
+
+  source.pathname = srcPath.join('/');
+  //to support request.http
+  if (source.pathname !== undefined || source.search !== undefined) {
+    source.path = (source.pathname ? source.pathname : '') +
+                  (source.search ? source.search : '');
+  }
+  source.auth = relative.auth || source.auth;
+  source.slashes = source.slashes || relative.slashes;
+  source.href = urlFormat(source);
+  return source;
+}
+
+function parseHost(host) {
+  var out = {};
+  var port = portPattern.exec(host);
+  if (port) {
+    port = port[0];
+    if (port !== ':') {
+      out.port = port.substr(1);
+    }
+    host = host.substr(0, host.length - port.length);
+  }
+  if (host) out.hostname = host;
+  return out;
+}
+
+}());
+
+},{"punycode":40,"querystring":43}],53:[function(_dereq_,module,exports){
+module.exports = function isBuffer(arg) {
+  return arg && typeof arg === 'object'
+    && typeof arg.copy === 'function'
+    && typeof arg.fill === 'function'
+    && typeof arg.readUInt8 === 'function';
+}
+},{}],54:[function(_dereq_,module,exports){
+(function (process,global){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// 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.
+
+var formatRegExp = /%[sdj%]/g;
+exports.format = function(f) {
+  if (!isString(f)) {
+    var objects = [];
+    for (var i = 0; i < arguments.length; i++) {
+      objects.push(inspect(arguments[i]));
+    }
+    return objects.join(' ');
+  }
+
+  var i = 1;
+  var args = arguments;
+  var len = args.length;
+  var str = String(f).replace(formatRegExp, function(x) {
+    if (x === '%%') return '%';
+    if (i >= len) return x;
+    switch (x) {
+      case '%s': return String(args[i++]);
+      case '%d': return Number(args[i++]);
+      case '%j':
+        try {
+          return JSON.stringify(args[i++]);
+        } catch (_) {
+          return '[Circular]';
+        }
+      default:
+        return x;
+    }
+  });
+  for (var x = args[i]; i < len; x = args[++i]) {
+    if (isNull(x) || !isObject(x)) {
+      str += ' ' + x;
+    } else {
+      str += ' ' + inspect(x);
+    }
+  }
+  return str;
+};
+
+
+// Mark that a method should not be used.
+// Returns a modified function which warns once by default.
+// If --no-deprecation is set, then it is a no-op.
+exports.deprecate = function(fn, msg) {
+  // Allow for deprecating things in the process of starting up.
+  if (isUndefined(global.process)) {
+    return function() {
+      return exports.deprecate(fn, msg).apply(this, arguments);
+    };
+  }
+
+  if (process.noDeprecation === true) {
+    return fn;
+  }
+
+  var warned = false;
+  function deprecated() {
+    if (!warned) {
+      if (process.throwDeprecation) {
+        throw new Error(msg);
+      } else if (process.traceDeprecation) {
+        console.trace(msg);
+      } else {
+        console.error(msg);
+      }
+      warned = true;
+    }
+    return fn.apply(this, arguments);
+  }
+
+  return deprecated;
+};
+
+
+var debugs = {};
+var debugEnviron;
+exports.debuglog = function(set) {
+  if (isUndefined(debugEnviron))
+    debugEnviron = process.env.NODE_DEBUG || '';
+  set = set.toUpperCase();
+  if (!debugs[set]) {
+    if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
+      var pid = process.pid;
+      debugs[set] = function() {
+        var msg = exports.format.apply(exports, arguments);
+        console.error('%s %d: %s', set, pid, msg);
+      };
+    } else {
+      debugs[set] = function() {};
+    }
+  }
+  return debugs[set];
+};
+
+
+/**
+ * Echos the value of a value. Trys to print the value out
+ * in the best way possible given the different types.
+ *
+ * @param {Object} obj The object to print out.
+ * @param {Object} opts Optional options object that alters the output.
+ */
+/* legacy: obj, showHidden, depth, colors*/
+function inspect(obj, opts) {
+  // default options
+  var ctx = {
+    seen: [],
+    stylize: stylizeNoColor
+  };
+  // legacy...
+  if (arguments.length >= 3) ctx.depth = arguments[2];
+  if (arguments.length >= 4) ctx.colors = arguments[3];
+  if (isBoolean(opts)) {
+    // legacy...
+    ctx.showHidden = opts;
+  } else if (opts) {
+    // got an "options" object
+    exports._extend(ctx, opts);
+  }
+  // set default options
+  if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
+  if (isUndefined(ctx.depth)) ctx.depth = 2;
+  if (isUndefined(ctx.colors)) ctx.colors = false;
+  if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
+  if (ctx.colors) ctx.stylize = stylizeWithColor;
+  return formatValue(ctx, obj, ctx.depth);
+}
+exports.inspect = inspect;
+
+
+// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
+inspect.colors = {
+  'bold' : [1, 22],
+  'italic' : [3, 23],
+  'underline' : [4, 24],
+  'inverse' : [7, 27],
+  'white' : [37, 39],
+  'grey' : [90, 39],
+  'black' : [30, 39],
+  'blue' : [34, 39],
+  'cyan' : [36, 39],
+  'green' : [32, 39],
+  'magenta' : [35, 39],
+  'red' : [31, 39],
+  'yellow' : [33, 39]
+};
+
+// Don't use 'blue' not visible on cmd.exe
+inspect.styles = {
+  'special': 'cyan',
+  'number': 'yellow',
+  'boolean': 'yellow',
+  'undefined': 'grey',
+  'null': 'bold',
+  'string': 'green',
+  'date': 'magenta',
+  // "name": intentionally not styling
+  'regexp': 'red'
+};
+
+
+function stylizeWithColor(str, styleType) {
+  var style = inspect.styles[styleType];
+
+  if (style) {
+    return '\u001b[' + inspect.colors[style][0] + 'm' + str +
+           '\u001b[' + inspect.colors[style][1] + 'm';
+  } else {
+    return str;
+  }
+}
+
+
+function stylizeNoColor(str, styleType) {
+  return str;
+}
+
+
+function arrayToHash(array) {
+  var hash = {};
+
+  array.forEach(function(val, idx) {
+    hash[val] = true;
+  });
+
+  return hash;
+}
+
+
+function formatValue(ctx, value, recurseTimes) {
+  // Provide a hook for user-specified inspect functions.
+  // Check that value is an object with an inspect function on it
+  if (ctx.customInspect &&
+      value &&
+      isFunction(value.inspect) &&
+      // Filter out the util module, it's inspect function is special
+      value.inspect !== exports.inspect &&
+      // Also filter out any prototype objects using the circular check.
+      !(value.constructor && value.constructor.prototype === value)) {
+    var ret = value.inspect(recurseTimes, ctx);
+    if (!isString(ret)) {
+      ret = formatValue(ctx, ret, recurseTimes);
+    }
+    return ret;
+  }
+
+  // Primitive types cannot have properties
+  var primitive = formatPrimitive(ctx, value);
+  if (primitive) {
+    return primitive;
+  }
+
+  // Look up the keys of the object.
+  var keys = Object.keys(value);
+  var visibleKeys = arrayToHash(keys);
+
+  if (ctx.showHidden) {
+    keys = Object.getOwnPropertyNames(value);
+  }
+
+  // IE doesn't make error fields non-enumerable
+  // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
+  if (isError(value)
+      && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
+    return formatError(value);
+  }
+
+  // Some type of object without properties can be shortcutted.
+  if (keys.length === 0) {
+    if (isFunction(value)) {
+      var name = value.name ? ': ' + value.name : '';
+      return ctx.stylize('[Function' + name + ']', 'special');
+    }
+    if (isRegExp(value)) {
+      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
+    }
+    if (isDate(value)) {
+      return ctx.stylize(Date.prototype.toString.call(value), 'date');
+    }
+    if (isError(value)) {
+      return formatError(value);
+    }
+  }
+
+  var base = '', array = false, braces = ['{', '}'];
+
+  // Make Array say that they are Array
+  if (isArray(value)) {
+    array = true;
+    braces = ['[', ']'];
+  }
+
+  // Make functions say that they are functions
+  if (isFunction(value)) {
+    var n = value.name ? ': ' + value.name : '';
+    base = ' [Function' + n + ']';
+  }
+
+  // Make RegExps say that they are RegExps
+  if (isRegExp(value)) {
+    base = ' ' + RegExp.prototype.toString.call(value);
+  }
+
+  // Make dates with properties first say the date
+  if (isDate(value)) {
+    base = ' ' + Date.prototype.toUTCString.call(value);
+  }
+
+  // Make error with message first say the error
+  if (isError(value)) {
+    base = ' ' + formatError(value);
+  }
+
+  if (keys.length === 0 && (!array || value.length == 0)) {
+    return braces[0] + base + braces[1];
+  }
+
+  if (recurseTimes < 0) {
+    if (isRegExp(value)) {
+      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
+    } else {
+      return ctx.stylize('[Object]', 'special');
+    }
+  }
+
+  ctx.seen.push(value);
+
+  var output;
+  if (array) {
+    output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
+  } else {
+    output = keys.map(function(key) {
+      return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
+    });
+  }
+
+  ctx.seen.pop();
+
+  return reduceToSingleString(output, base, braces);
+}
+
+
+function formatPrimitive(ctx, value) {
+  if (isUndefined(value))
+    return ctx.stylize('undefined', 'undefined');
+  if (isString(value)) {
+    var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
+                                             .replace(/'/g, "\\'")
+                                             .replace(/\\"/g, '"') + '\'';
+    return ctx.stylize(simple, 'string');
+  }
+  if (isNumber(value))
+    return ctx.stylize('' + value, 'number');
+  if (isBoolean(value))
+    return ctx.stylize('' + value, 'boolean');
+  // For some reason typeof null is "object", so special case here.
+  if (isNull(value))
+    return ctx.stylize('null', 'null');
+}
+
+
+function formatError(value) {
+  return '[' + Error.prototype.toString.call(value) + ']';
+}
+
+
+function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
+  var output = [];
+  for (var i = 0, l = value.length; i < l; ++i) {
+    if (hasOwnProperty(value, String(i))) {
+      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
+          String(i), true));
+    } else {
+      output.push('');
+    }
+  }
+  keys.forEach(function(key) {
+    if (!key.match(/^\d+$/)) {
+      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
+          key, true));
+    }
+  });
+  return output;
+}
+
+
+function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
+  var name, str, desc;
+  desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
+  if (desc.get) {
+    if (desc.set) {
+      str = ctx.stylize('[Getter/Setter]', 'special');
+    } else {
+      str = ctx.stylize('[Getter]', 'special');
+    }
+  } else {
+    if (desc.set) {
+      str = ctx.stylize('[Setter]', 'special');
+    }
+  }
+  if (!hasOwnProperty(visibleKeys, key)) {
+    name = '[' + key + ']';
+  }
+  if (!str) {
+    if (ctx.seen.indexOf(desc.value) < 0) {
+      if (isNull(recurseTimes)) {
+        str = formatValue(ctx, desc.value, null);
+      } else {
+        str = formatValue(ctx, desc.value, recurseTimes - 1);
+      }
+      if (str.indexOf('\n') > -1) {
+        if (array) {
+          str = str.split('\n').map(function(line) {
+            return '  ' + line;
+          }).join('\n').substr(2);
+        } else {
+          str = '\n' + str.split('\n').map(function(line) {
+            return '   ' + line;
+          }).join('\n');
+        }
+      }
+    } else {
+      str = ctx.stylize('[Circular]', 'special');
+    }
+  }
+  if (isUndefined(name)) {
+    if (array && key.match(/^\d+$/)) {
+      return str;
+    }
+    name = JSON.stringify('' + key);
+    if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
+      name = name.substr(1, name.length - 2);
+      name = ctx.stylize(name, 'name');
+    } else {
+      name = name.replace(/'/g, "\\'")
+                 .replace(/\\"/g, '"')
+                 .replace(/(^"|"$)/g, "'");
+      name = ctx.stylize(name, 'string');
+    }
+  }
+
+  return name + ': ' + str;
+}
+
+
+function reduceToSingleString(output, base, braces) {
+  var numLinesEst = 0;
+  var length = output.reduce(function(prev, cur) {
+    numLinesEst++;
+    if (cur.indexOf('\n') >= 0) numLinesEst++;
+    return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
+  }, 0);
+
+  if (length > 60) {
+    return braces[0] +
+           (base === '' ? '' : base + '\n ') +
+           ' ' +
+           output.join(',\n  ') +
+           ' ' +
+           braces[1];
+  }
+
+  return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
+}
+
+
+// NOTE: These type checking functions intentionally don't use `instanceof`
+// because it is fragile and can be easily faked with `Object.create()`.
+function isArray(ar) {
+  return Array.isArray(ar);
+}
+exports.isArray = isArray;
+
+function isBoolean(arg) {
+  return typeof arg === 'boolean';
+}
+exports.isBoolean = isBoolean;
+
+function isNull(arg) {
+  return arg === null;
+}
+exports.isNull = isNull;
+
+function isNullOrUndefined(arg) {
+  return arg == null;
+}
+exports.isNullOrUndefined = isNullOrUndefined;
+
+function isNumber(arg) {
+  return typeof arg === 'number';
+}
+exports.isNumber = isNumber;
+
+function isString(arg) {
+  return typeof arg === 'string';
+}
+exports.isString = isString;
+
+function isSymbol(arg) {
+  return typeof arg === 'symbol';
+}
+exports.isSymbol = isSymbol;
+
+function isUndefined(arg) {
+  return arg === void 0;
+}
+exports.isUndefined = isUndefined;
+
+function isRegExp(re) {
+  return isObject(re) && objectToString(re) === '[object RegExp]';
+}
+exports.isRegExp = isRegExp;
+
+function isObject(arg) {
+  return typeof arg === 'object' && arg !== null;
+}
+exports.isObject = isObject;
+
+function isDate(d) {
+  return isObject(d) && objectToString(d) === '[object Date]';
+}
+exports.isDate = isDate;
+
+function isError(e) {
+  return isObject(e) &&
+      (objectToString(e) === '[object Error]' || e instanceof Error);
+}
+exports.isError = isError;
+
+function isFunction(arg) {
+  return typeof arg === 'function';
+}
+exports.isFunction = isFunction;
+
+function isPrimitive(arg) {
+  return arg === null ||
+         typeof arg === 'boolean' ||
+         typeof arg === 'number' ||
+         typeof arg === 'string' ||
+         typeof arg === 'symbol' ||  // ES6 symbol
+         typeof arg === 'undefined';
+}
+exports.isPrimitive = isPrimitive;
+
+exports.isBuffer = _dereq_('./support/isBuffer');
+
+function objectToString(o) {
+  return Object.prototype.toString.call(o);
+}
+
+
+function pad(n) {
+  return n < 10 ? '0' + n.toString(10) : n.toString(10);
+}
+
+
+var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
+              'Oct', 'Nov', 'Dec'];
+
+// 26 Feb 16:19:34
+function timestamp() {
+  var d = new Date();
+  var time = [pad(d.getHours()),
+              pad(d.getMinutes()),
+              pad(d.getSeconds())].join(':');
+  return [d.getDate(), months[d.getMonth()], time].join(' ');
+}
+
+
+// log is just a thin wrapper to console.log that prepends a timestamp
+exports.log = function() {
+  console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
+};
+
+
+/**
+ * Inherit the prototype methods from one constructor into another.
+ *
+ * The Function.prototype.inherits from lang.js rewritten as a standalone
+ * function (not on Function.prototype). NOTE: If this file is to be loaded
+ * during bootstrapping this function needs to be rewritten using some native
+ * functions as prototype setup using normal JavaScript does not work as
+ * expected during bootstrapping (see mirror.js in r114903).
+ *
+ * @param {function} ctor Constructor function which needs to inherit the
+ *     prototype.
+ * @param {function} superCtor Constructor function to inherit prototype from.
+ */
+exports.inherits = _dereq_('inherits');
+
+exports._extend = function(origin, add) {
+  // Don't do anything if add isn't an object
+  if (!add || !isObject(add)) return origin;
+
+  var keys = Object.keys(add);
+  var i = keys.length;
+  while (i--) {
+    origin[keys[i]] = add[keys[i]];
+  }
+  return origin;
+};
+
+function hasOwnProperty(obj, prop) {
+  return Object.prototype.hasOwnProperty.call(obj, prop);
+}
+
+}).call(this,_dereq_("C:\\Users\\xmr\\Desktop\\clean-css\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{"./support/isBuffer":53,"C:\\Users\\xmr\\Desktop\\clean-css\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":38,"inherits":37}]},{},[1])
+(1)
+});
\ No newline at end of file
diff --git a/csso.js b/csso.js
deleted file mode 100644 (file)
index a82b09e..0000000
--- a/csso.js
+++ /dev/null
@@ -1,3889 +0,0 @@
-var $util = {};
-
-$util.cleanInfo = function(tree) {
-    var r = [];
-    tree = tree.slice(1);
-
-    tree.forEach(function(e) {
-        r.push(Array.isArray(e) ? $util.cleanInfo(e) : e);
-    });
-
-    return r;
-};
-
-$util.treeToString = function(tree, level) {
-    var spaces = $util.dummySpaces(level),
-        level = level ? level : 0,
-        s = (level ? '\n' + spaces : '') + '[';
-
-    tree.forEach(function(e) {
-        s += (Array.isArray(e) ? $util.treeToString(e, level + 1) : e.f !== undefined ? $util.ircToString(e) : ('\'' + e.toString() + '\'')) + ', ';
-    });
-
-    return s.substr(0, s.length - 2) + ']';
-};
-
-$util.ircToString = function(o) {
-    return '{' + o.f + ',' + o.l + '}';
-};
-
-$util.dummySpaces = function(num) {
-    return '                                                  '.substr(0, num * 2);
-};
-function srcToCSSP(s, rule, _needInfo) {
-var TokenType = {
-    StringSQ: 'StringSQ',
-    StringDQ: 'StringDQ',
-    CommentML: 'CommentML',
-    CommentSL: 'CommentSL',
-
-    Newline: 'Newline',
-    Space: 'Space',
-    Tab: 'Tab',
-
-    ExclamationMark: 'ExclamationMark',         // !
-    QuotationMark: 'QuotationMark',             // "
-    NumberSign: 'NumberSign',                   // #
-    DollarSign: 'DollarSign',                   // $
-    PercentSign: 'PercentSign',                 // %
-    Ampersand: 'Ampersand',                     // &
-    Apostrophe: 'Apostrophe',                   // '
-    LeftParenthesis: 'LeftParenthesis',         // (
-    RightParenthesis: 'RightParenthesis',       // )
-    Asterisk: 'Asterisk',                       // *
-    PlusSign: 'PlusSign',                       // +
-    Comma: 'Comma',                             // ,
-    HyphenMinus: 'HyphenMinus',                 // -
-    FullStop: 'FullStop',                       // .
-    Solidus: 'Solidus',                         // /
-    Colon: 'Colon',                             // :
-    Semicolon: 'Semicolon',                     // ;
-    LessThanSign: 'LessThanSign',               // <
-    EqualsSign: 'EqualsSign',                   // =
-    GreaterThanSign: 'GreaterThanSign',         // >
-    QuestionMark: 'QuestionMark',               // ?
-    CommercialAt: 'CommercialAt',               // @
-    LeftSquareBracket: 'LeftSquareBracket',     // [
-    ReverseSolidus: 'ReverseSolidus',           // \
-    RightSquareBracket: 'RightSquareBracket',   // ]
-    CircumflexAccent: 'CircumflexAccent',       // ^
-    LowLine: 'LowLine',                         // _
-    LeftCurlyBracket: 'LeftCurlyBracket',       // {
-    VerticalLine: 'VerticalLine',               // |
-    RightCurlyBracket: 'RightCurlyBracket',     // }
-    Tilde: 'Tilde',                             // ~
-
-    Identifier: 'Identifier',
-    DecimalNumber: 'DecimalNumber'
-};
-
-function getTokens(s) {
-    var Punctuation,
-        urlMode = false,
-        blockMode = 0;
-
-    Punctuation = {
-        ' ': TokenType.Space,
-        '\n': TokenType.Newline,
-        '\r': TokenType.Newline,
-        '\t': TokenType.Tab,
-        '!': TokenType.ExclamationMark,
-        '"': TokenType.QuotationMark,
-        '#': TokenType.NumberSign,
-        '$': TokenType.DollarSign,
-        '%': TokenType.PercentSign,
-        '&': TokenType.Ampersand,
-        '\'': TokenType.Apostrophe,
-        '(': TokenType.LeftParenthesis,
-        ')': TokenType.RightParenthesis,
-        '*': TokenType.Asterisk,
-        '+': TokenType.PlusSign,
-        ',': TokenType.Comma,
-        '-': TokenType.HyphenMinus,
-        '.': TokenType.FullStop,
-        '/': TokenType.Solidus,
-        ':': TokenType.Colon,
-        ';': TokenType.Semicolon,
-        '<': TokenType.LessThanSign,
-        '=': TokenType.EqualsSign,
-        '>': TokenType.GreaterThanSign,
-        '?': TokenType.QuestionMark,
-        '@': TokenType.CommercialAt,
-        '[': TokenType.LeftSquareBracket,
-    //        '\\': TokenType.ReverseSolidus,
-        ']': TokenType.RightSquareBracket,
-        '^': TokenType.CircumflexAccent,
-        '_': TokenType.LowLine,
-        '{': TokenType.LeftCurlyBracket,
-        '|': TokenType.VerticalLine,
-        '}': TokenType.RightCurlyBracket,
-        '~': TokenType.Tilde
-    };
-
-    function isDecimalDigit(c) {
-        return '0123456789'.indexOf(c) >= 0;
-    }
-
-    function throwError(message) {
-        throw message;
-    }
-
-    var buffer = '',
-        tokens = [],
-        pos,
-        tn = 0,
-        ln = 1;
-
-    function _getTokens(s) {
-        if (!s) return [];
-
-        tokens = [];
-
-        var c, cn;
-
-        for (pos = 0; pos < s.length; pos++) {
-            c = s.charAt(pos);
-            cn = s.charAt(pos + 1);
-
-            if (c === '/' && cn === '*') {
-                parseMLComment(s);
-            } else if (!urlMode && c === '/' && cn === '/') {
-                if (blockMode > 0) parseIdentifier(s);
-                else parseSLComment(s);
-            } else if (c === '"' || c === "'") {
-                parseString(s, c);
-            } else if (c === ' ') {
-                parseSpaces(s)
-            } else if (c in Punctuation) {
-                pushToken(Punctuation[c], c);
-                if (c === '\n' || c === '\r') ln++;
-                if (c === ')') urlMode = false;
-                if (c === '{') blockMode++;
-                if (c === '}') blockMode--;
-            } else if (isDecimalDigit(c)) {
-                parseDecimalNumber(s);
-            } else {
-                parseIdentifier(s);
-            }
-        }
-
-        mark();
-
-        return tokens;
-    }
-
-    function pushToken(type, value) {
-        tokens.push({ tn: tn++, ln: ln, type: type, value: value });
-    }
-
-    function parseSpaces(s) {
-        var start = pos;
-
-        for (; pos < s.length; pos++) {
-            if (s.charAt(pos) !== ' ') break;
-        }
-
-        pushToken(TokenType.Space, s.substring(start, pos));
-        pos--;
-    }
-
-    function parseMLComment(s) {
-        var start = pos;
-
-        for (pos = pos + 2; pos < s.length; pos++) {
-            if (s.charAt(pos) === '*') {
-                if (s.charAt(pos + 1) === '/') {
-                    pos++;
-                    break;
-                }
-            }
-        }
-
-        pushToken(TokenType.CommentML, s.substring(start, pos + 1));
-    }
-
-    function parseSLComment(s) {
-        var start = pos;
-
-        for (pos = pos + 2; pos < s.length; pos++) {
-            if (s.charAt(pos) === '\n' || s.charAt(pos) === '\r') {
-                pos++;
-                break;
-            }
-        }
-
-        pushToken(TokenType.CommentSL, s.substring(start, pos));
-        pos--;
-    }
-
-    function parseString(s, q) {
-        var start = pos;
-
-        for (pos = pos + 1; pos < s.length; pos++) {
-            if (s.charAt(pos) === '\\') pos++;
-            else if (s.charAt(pos) === q) break;
-        }
-
-        pushToken(q === '"' ? TokenType.StringDQ : TokenType.StringSQ, s.substring(start, pos + 1));
-    }
-
-    function parseDecimalNumber(s) {
-        var start = pos;
-
-        for (; pos < s.length; pos++) {
-            if (!isDecimalDigit(s.charAt(pos))) break;
-        }
-
-        pushToken(TokenType.DecimalNumber, s.substring(start, pos));
-        pos--;
-    }
-
-    function parseIdentifier(s) {
-        var start = pos;
-
-        while (s.charAt(pos) === '/') pos++;
-
-        for (; pos < s.length; pos++) {
-            if (s.charAt(pos) === '\\') pos++;
-            else if (s.charAt(pos) in Punctuation) break;
-        }
-
-        var ident = s.substring(start, pos);
-
-        urlMode = urlMode || ident === 'url';
-
-        pushToken(TokenType.Identifier, ident);
-        pos--;
-    }
-
-    // ====================================
-    // second run
-    // ====================================
-
-    function mark() {
-        var ps = [], // Parenthesis
-            sbs = [], // SquareBracket
-            cbs = [], // CurlyBracket
-            t;
-
-        for (var i = 0; i < tokens.length; i++) {
-            t = tokens[i];
-            switch(t.type) {
-                case TokenType.LeftParenthesis:
-                    ps.push(i);
-                    break;
-                case TokenType.RightParenthesis:
-                    if (ps.length) {
-                        t.left = ps.pop();
-                        tokens[t.left].right = i;
-                    }
-                    break;
-                case TokenType.LeftSquareBracket:
-                    sbs.push(i);
-                    break;
-                case TokenType.RightSquareBracket:
-                    if (sbs.length) {
-                        t.left = sbs.pop();
-                        tokens[t.left].right = i;
-                    }
-                    break;
-                case TokenType.LeftCurlyBracket:
-                    cbs.push(i);
-                    break;
-                case TokenType.RightCurlyBracket:
-                    if (cbs.length) {
-                        t.left = cbs.pop();
-                        tokens[t.left].right = i;
-                    }
-                    break;
-            }
-        }
-    }
-
-    return _getTokens(s);
-}
-// version: 1.0.0
-
-function getCSSPAST(_tokens, rule, _needInfo) {
-
-    var tokens,
-        pos,
-        failLN = 0,
-        currentBlockLN = 0,
-        needInfo = false;
-
-    var CSSPNodeType,
-        CSSLevel,
-        CSSPRules;
-
-    CSSPNodeType = {
-        IdentType: 'ident',
-        AtkeywordType: 'atkeyword',
-        StringType: 'string',
-        ShashType: 'shash',
-        VhashType: 'vhash',
-        NumberType: 'number',
-        PercentageType: 'percentage',
-        DimensionType: 'dimension',
-        CdoType: 'cdo',
-        CdcType: 'cdc',
-        DecldelimType: 'decldelim',
-        SType: 's',
-        AttrselectorType: 'attrselector',
-        AttribType: 'attrib',
-        NthType: 'nth',
-        NthselectorType: 'nthselector',
-        NamespaceType: 'namespace',
-        ClazzType: 'clazz',
-        PseudoeType: 'pseudoe',
-        PseudocType: 'pseudoc',
-        DelimType: 'delim',
-        StylesheetType: 'stylesheet',
-        AtrulebType: 'atruleb',
-        AtrulesType: 'atrules',
-        AtrulerqType: 'atrulerq',
-        AtrulersType: 'atrulers',
-        AtrulerType: 'atruler',
-        BlockType: 'block',
-        RulesetType: 'ruleset',
-        CombinatorType: 'combinator',
-        SimpleselectorType: 'simpleselector',
-        SelectorType: 'selector',
-        DeclarationType: 'declaration',
-        PropertyType: 'property',
-        ImportantType: 'important',
-        UnaryType: 'unary',
-        OperatorType: 'operator',
-        BracesType: 'braces',
-        ValueType: 'value',
-        ProgidType: 'progid',
-        FiltervType: 'filterv',
-        FilterType: 'filter',
-        CommentType: 'comment',
-        UriType: 'uri',
-        RawType: 'raw',
-        FunctionBodyType: 'functionBody',
-        FunktionType: 'funktion',
-        FunctionExpressionType: 'functionExpression',
-        UnknownType: 'unknown'
-    };
-
-    CSSPRules = {
-        'ident': function() { if (checkIdent(pos)) return getIdent() },
-        'atkeyword': function() { if (checkAtkeyword(pos)) return getAtkeyword() },
-        'string': function() { if (checkString(pos)) return getString() },
-        'shash': function() { if (checkShash(pos)) return getShash() },
-        'vhash': function() { if (checkVhash(pos)) return getVhash() },
-        'number': function() { if (checkNumber(pos)) return getNumber() },
-        'percentage': function() { if (checkPercentage(pos)) return getPercentage() },
-        'dimension': function() { if (checkDimension(pos)) return getDimension() },
-//        'cdo': function() { if (checkCDO()) return getCDO() },
-//        'cdc': function() { if (checkCDC()) return getCDC() },
-        'decldelim': function() { if (checkDecldelim(pos)) return getDecldelim() },
-        's': function() { if (checkS(pos)) return getS() },
-        'attrselector': function() { if (checkAttrselector(pos)) return getAttrselector() },
-        'attrib': function() { if (checkAttrib(pos)) return getAttrib() },
-        'nth': function() { if (checkNth(pos)) return getNth() },
-        'nthselector': function() { if (checkNthselector(pos)) return getNthselector() },
-        'namespace': function() { if (checkNamespace(pos)) return getNamespace() },
-        'clazz': function() { if (checkClazz(pos)) return getClazz() },
-        'pseudoe': function() { if (checkPseudoe(pos)) return getPseudoe() },
-        'pseudoc': function() { if (checkPseudoc(pos)) return getPseudoc() },
-        'delim': function() { if (checkDelim(pos)) return getDelim() },
-        'stylesheet': function() { if (checkStylesheet(pos)) return getStylesheet() },
-        'atruleb': function() { if (checkAtruleb(pos)) return getAtruleb() },
-        'atrules': function() { if (checkAtrules(pos)) return getAtrules() },
-        'atrulerq': function() { if (checkAtrulerq(pos)) return getAtrulerq() },
-        'atrulers': function() { if (checkAtrulers(pos)) return getAtrulers() },
-        'atruler': function() { if (checkAtruler(pos)) return getAtruler() },
-        'block': function() { if (checkBlock(pos)) return getBlock() },
-        'ruleset': function() { if (checkRuleset(pos)) return getRuleset() },
-        'combinator': function() { if (checkCombinator(pos)) return getCombinator() },
-        'simpleselector': function() { if (checkSimpleselector(pos)) return getSimpleSelector() },
-        'selector': function() { if (checkSelector(pos)) return getSelector() },
-        'declaration': function() { if (checkDeclaration(pos)) return getDeclaration() },
-        'property': function() { if (checkProperty(pos)) return getProperty() },
-        'important': function() { if (checkImportant(pos)) return getImportant() },
-        'unary': function() { if (checkUnary(pos)) return getUnary() },
-        'operator': function() { if (checkOperator(pos)) return getOperator() },
-        'braces': function() { if (checkBraces(pos)) return getBraces() },
-        'value': function() { if (checkValue(pos)) return getValue() },
-        'progid': function() { if (checkProgid(pos)) return getProgid() },
-        'filterv': function() { if (checkFilterv(pos)) return getFilterv() },
-        'filter': function() { if (checkFilter(pos)) return getFilter() },
-        'comment': function() { if (checkComment(pos)) return getComment() },
-        'uri': function() { if (checkUri(pos)) return getUri() },
-        'raw': function() { if (checkRaw(pos)) return getRaw() },
-        'funktion': function() { if (checkFunktion(pos)) return getFunktion() },
-        'functionExpression': function() { if (checkFunctionExpression(pos)) return getFunctionExpression() },
-        'unknown': function() { if (checkUnknown(pos)) return getUnknown() }
-    };
-
-    function fail(token) {
-        if (token && token.ln > failLN) failLN = token.ln;
-    }
-
-    function throwError() {
-        console.error('Please check the validity of the CSS block starting from the line #' + currentBlockLN);
-        if (process) process.exit(1);
-        throw new Error();
-    }
-
-    function _getAST(_tokens, rule, _needInfo) {
-        tokens = _tokens;
-        needInfo = _needInfo;
-        pos = 0;
-
-        markSC();
-
-        return rule ? CSSPRules[rule]() : CSSPRules['stylesheet']();
-    }
-
-//any = braces | string | percentage | dimension | number | uri | functionExpression | funktion | ident | unary
-    function checkAny(_i) {
-        return checkBraces(_i) ||
-               checkString(_i) ||
-               checkPercentage(_i) ||
-               checkDimension(_i) ||
-               checkNumber(_i) ||
-               checkUri(_i) ||
-               checkFunctionExpression(_i) ||
-               checkFunktion(_i) ||
-               checkIdent(_i) ||
-               checkUnary(_i);
-    }
-
-    function getAny() {
-        if (checkBraces(pos)) return getBraces();
-        else if (checkString(pos)) return getString();
-        else if (checkPercentage(pos)) return getPercentage();
-        else if (checkDimension(pos)) return getDimension();
-        else if (checkNumber(pos)) return getNumber();
-        else if (checkUri(pos)) return getUri();
-        else if (checkFunctionExpression(pos)) return getFunctionExpression();
-        else if (checkFunktion(pos)) return getFunktion();
-        else if (checkIdent(pos)) return getIdent();
-        else if (checkUnary(pos)) return getUnary();
-    }
-
-//atkeyword = '@' ident:x -> [#atkeyword, x]
-    function checkAtkeyword(_i) {
-        var l;
-
-        if (tokens[_i++].type !== TokenType.CommercialAt) return fail(tokens[_i - 1]);
-
-        if (l = checkIdent(_i)) return l + 1;
-
-        return fail(tokens[_i]);
-    }
-
-    function getAtkeyword() {
-        var startPos = pos;
-
-        pos++;
-
-        return needInfo?
-            [{ ln: tokens[startPos].ln }, CSSPNodeType.AtkeywordType, getIdent()]:
-            [CSSPNodeType.AtkeywordType, getIdent()];
-    }
-
-//attrib = '[' sc*:s0 ident:x sc*:s1 attrselector:a sc*:s2 (ident | string):y sc*:s3 ']' -> this.concat([#attrib], s0, [x], s1, [a], s2, [y], s3)
-//       | '[' sc*:s0 ident:x sc*:s1 ']' -> this.concat([#attrib], s0, [x], s1),
-    function checkAttrib(_i) {
-        if (tokens[_i].type !== TokenType.LeftSquareBracket) return fail(tokens[_i]);
-
-        if (!tokens[_i].right) return fail(tokens[_i]);
-
-        return tokens[_i].right - _i + 1;
-    }
-
-    function checkAttrib1(_i) {
-        var start = _i;
-
-        _i++;
-
-        var l = checkSC(_i); // s0
-
-        if (l) _i += l;
-
-        if (l = checkIdent(_i)) _i += l; // x
-        else return fail(tokens[_i]);
-
-        if (l = checkSC(_i)) _i += l; // s1
-
-        if (l = checkAttrselector(_i)) _i += l; // a
-        else return fail(tokens[_i]);
-
-        if (l = checkSC(_i)) _i += l; // s2
-
-        if ((l = checkIdent(_i)) || (l = checkString(_i))) _i += l; // y
-        else return fail(tokens[_i]);
-
-        if (l = checkSC(_i)) _i += l; // s3
-
-        if (tokens[_i].type === TokenType.RightSquareBracket) return _i - start;
-
-        return fail(tokens[_i]);
-    }
-
-    function getAttrib1() {
-        var startPos = pos;
-
-        pos++;
-
-        var a = (needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.AttribType] : [CSSPNodeType.AttribType])
-                .concat(getSC())
-                .concat([getIdent()])
-                .concat(getSC())
-                .concat([getAttrselector()])
-                .concat(getSC())
-                .concat([checkString(pos)? getString() : getIdent()])
-                .concat(getSC());
-
-        pos++;
-
-        return a;
-    }
-
-    function checkAttrib2(_i) {
-        var start = _i;
-
-        _i++;
-
-        var l = checkSC(_i);
-
-        if (l) _i += l;
-
-        if (l = checkIdent(_i)) _i += l;
-
-        if (l = checkSC(_i)) _i += l;
-
-        if (tokens[_i].type === TokenType.RightSquareBracket) return _i - start;
-
-        return fail(tokens[_i]);
-    }
-
-    function getAttrib2() {
-        var startPos = pos;
-
-        pos++;
-
-        var a = (needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.AttribType] : [CSSPNodeType.AttribType])
-                .concat(getSC())
-                .concat([getIdent()])
-                .concat(getSC());
-
-        pos++;
-
-        return a;
-    }
-
-    function getAttrib() {
-        if (checkAttrib1(pos)) return getAttrib1();
-        if (checkAttrib2(pos)) return getAttrib2();
-    }
-
-//attrselector = (seq('=') | seq('~=') | seq('^=') | seq('$=') | seq('*=') | seq('|=')):x -> [#attrselector, x]
-    function checkAttrselector(_i) {
-        if (tokens[_i].type === TokenType.EqualsSign) return 1;
-        if (tokens[_i].type === TokenType.VerticalLine && (!tokens[_i + 1] || tokens[_i + 1].type !== TokenType.EqualsSign)) return 1;
-
-        if (!tokens[_i + 1] || tokens[_i + 1].type !== TokenType.EqualsSign) return fail(tokens[_i]);
-
-        switch(tokens[_i].type) {
-            case TokenType.Tilde:
-            case TokenType.CircumflexAccent:
-            case TokenType.DollarSign:
-            case TokenType.Asterisk:
-            case TokenType.VerticalLine:
-                return 2;
-        }
-
-        return fail(tokens[_i]);
-    }
-
-    function getAttrselector() {
-        var startPos = pos,
-            s = tokens[pos++].value;
-
-        if (tokens[pos] && tokens[pos].type === TokenType.EqualsSign) s += tokens[pos++].value;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.AttrselectorType, s] :
-                [CSSPNodeType.AttrselectorType, s];
-    }
-
-//atrule = atruler | atruleb | atrules
-    function checkAtrule(_i) {
-        var start = _i,
-            l;
-
-        if (tokens[start].atrule_l !== undefined) return tokens[start].atrule_l;
-
-        if (l = checkAtruler(_i)) tokens[_i].atrule_type = 1;
-        else if (l = checkAtruleb(_i)) tokens[_i].atrule_type = 2;
-        else if (l = checkAtrules(_i)) tokens[_i].atrule_type = 3;
-        else return fail(tokens[start]);
-
-        tokens[start].atrule_l = l;
-
-        return l;
-    }
-
-    function getAtrule() {
-        switch (tokens[pos].atrule_type) {
-            case 1: return getAtruler();
-            case 2: return getAtruleb();
-            case 3: return getAtrules();
-        }
-    }
-
-//atruleb = atkeyword:ak tset*:ap block:b -> this.concat([#atruleb, ak], ap, [b])
-    function checkAtruleb(_i) {
-        var start = _i,
-            l;
-
-        if (l = checkAtkeyword(_i)) _i += l;
-        else return fail(tokens[_i]);
-
-        if (l = checkTsets(_i)) _i += l;
-
-        if (l = checkBlock(_i)) _i += l;
-        else return fail(tokens[_i]);
-
-        return _i - start;
-    }
-
-    function getAtruleb() {
-        return (needInfo?
-                    [{ ln: tokens[pos].ln }, CSSPNodeType.AtrulebType, getAtkeyword()] :
-                    [CSSPNodeType.AtrulebType, getAtkeyword()])
-                        .concat(getTsets())
-                        .concat([getBlock()]);
-    }
-
-//atruler = atkeyword:ak atrulerq:x '{' atrulers:y '}' -> [#atruler, ak, x, y]
-    function checkAtruler(_i) {
-        var start = _i,
-            l;
-
-        if (l = checkAtkeyword(_i)) _i += l;
-        else return fail(tokens[_i]);
-
-        if (l = checkAtrulerq(_i)) _i += l;
-
-        if (_i < tokens.length && tokens[_i].type === TokenType.LeftCurlyBracket) _i++;
-        else return fail(tokens[_i]);
-
-        if (l = checkAtrulers(_i)) _i += l;
-
-        if (_i < tokens.length && tokens[_i].type === TokenType.RightCurlyBracket) _i++;
-        else return fail(tokens[_i]);
-
-        return _i - start;
-    }
-
-    function getAtruler() {
-        var atruler = needInfo?
-                        [{ ln: tokens[pos].ln }, CSSPNodeType.AtrulerType, getAtkeyword(), getAtrulerq()] :
-                        [CSSPNodeType.AtrulerType, getAtkeyword(), getAtrulerq()];
-
-        pos++;
-
-        atruler.push(getAtrulers());
-
-        pos++;
-
-        return atruler;
-    }
-
-//atrulerq = tset*:ap -> [#atrulerq].concat(ap)
-    function checkAtrulerq(_i) {
-        return checkTsets(_i);
-    }
-
-    function getAtrulerq() {
-        return (needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.AtrulerqType] : [CSSPNodeType.AtrulerqType]).concat(getTsets());
-    }
-
-//atrulers = sc*:s0 ruleset*:r sc*:s1 -> this.concat([#atrulers], s0, r, s1)
-    function checkAtrulers(_i) {
-        var start = _i,
-            l;
-
-        if (l = checkSC(_i)) _i += l;
-
-        while ((l = checkRuleset(_i)) || (l = checkAtrule(_i)) || (l = checkSC(_i))) {
-            _i += l;
-        }
-
-        tokens[_i].atrulers_end = 1;
-
-        if (l = checkSC(_i)) _i += l;
-
-        return _i - start;
-    }
-
-    function getAtrulers() {
-        var atrulers = (needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.AtrulersType] : [CSSPNodeType.AtrulersType]).concat(getSC()),
-            x;
-
-        while (!tokens[pos].atrulers_end) {
-            if (checkSC(pos)) {
-                atrulers = atrulers.concat(getSC());
-            } else if (checkRuleset(pos)) {
-                atrulers.push(getRuleset());
-            } else {
-                atrulers.push(getAtrule());
-            }
-        }
-
-        return atrulers.concat(getSC());
-    }
-
-//atrules = atkeyword:ak tset*:ap ';' -> this.concat([#atrules, ak], ap)
-    function checkAtrules(_i) {
-        var start = _i,
-            l;
-
-        if (l = checkAtkeyword(_i)) _i += l;
-        else return fail(tokens[_i]);
-
-        if (l = checkTsets(_i)) _i += l;
-
-        if (_i >= tokens.length) return _i - start;
-
-        if (tokens[_i].type === TokenType.Semicolon) _i++;
-        else return fail(tokens[_i]);
-
-        return _i - start;
-    }
-
-    function getAtrules() {
-        var atrules = (needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.AtrulesType, getAtkeyword()] : [CSSPNodeType.AtrulesType, getAtkeyword()]).concat(getTsets());
-
-        pos++;
-
-        return atrules;
-    }
-
-//block = '{' blockdecl*:x '}' -> this.concatContent([#block], x)
-    function checkBlock(_i) {
-        if (_i < tokens.length && tokens[_i].type === TokenType.LeftCurlyBracket) return tokens[_i].right - _i + 1;
-
-        return fail(tokens[_i]);
-    }
-
-    function getBlock() {
-        var block = needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.BlockType] : [CSSPNodeType.BlockType],
-            end = tokens[pos].right;
-
-        pos++;
-
-        while (pos < end) {
-            if (checkBlockdecl(pos)) block = block.concat(getBlockdecl());
-            else throwError();
-        }
-
-        pos = end + 1;
-
-        return block;
-    }
-
-//blockdecl = sc*:s0 (filter | declaration):x decldelim:y sc*:s1 -> this.concat(s0, [x], [y], s1)
-//          | sc*:s0 (filter | declaration):x sc*:s1 -> this.concat(s0, [x], s1)
-//          | sc*:s0 decldelim:x sc*:s1 -> this.concat(s0, [x], s1)
-//          | sc+:s0 -> s0
-
-    function checkBlockdecl(_i) {
-        var l;
-
-        if (l = _checkBlockdecl0(_i)) tokens[_i].bd_type = 1;
-        else if (l = _checkBlockdecl1(_i)) tokens[_i].bd_type = 2;
-        else if (l = _checkBlockdecl2(_i)) tokens[_i].bd_type = 3;
-        else if (l = _checkBlockdecl3(_i)) tokens[_i].bd_type = 4;
-        else return fail(tokens[_i]);
-
-        return l;
-    }
-
-    function getBlockdecl() {
-        switch (tokens[pos].bd_type) {
-            case 1: return _getBlockdecl0();
-            case 2: return _getBlockdecl1();
-            case 3: return _getBlockdecl2();
-            case 4: return _getBlockdecl3();
-        }
-    }
-
-    //sc*:s0 (filter | declaration):x decldelim:y sc*:s1 -> this.concat(s0, [x], [y], s1)
-    function _checkBlockdecl0(_i) {
-        var start = _i,
-            l;
-
-        if (l = checkSC(_i)) _i += l;
-
-        if (l = checkFilter(_i)) {
-            tokens[_i].bd_filter = 1;
-            _i += l;
-        } else if (l = checkDeclaration(_i)) {
-            tokens[_i].bd_decl = 1;
-            _i += l;
-        } else return fail(tokens[_i]);
-
-        if (_i < tokens.length && (l = checkDecldelim(_i))) _i += l;
-        else return fail(tokens[_i]);
-
-        if (l = checkSC(_i)) _i += l;
-
-        return _i - start;
-    }
-
-    function _getBlockdecl0() {
-        return getSC()
-                .concat([tokens[pos].bd_filter? getFilter() : getDeclaration()])
-                .concat([getDecldelim()])
-                .concat(getSC());
-    }
-
-    //sc*:s0 (filter | declaration):x sc*:s1 -> this.concat(s0, [x], s1)
-    function _checkBlockdecl1(_i) {
-        var start = _i,
-            l;
-
-        if (l = checkSC(_i)) _i += l;
-
-        if (l = checkFilter(_i)) {
-            tokens[_i].bd_filter = 1;
-            _i += l;
-        } else if (l = checkDeclaration(_i)) {
-            tokens[_i].bd_decl = 1;
-            _i += l;
-        } else return fail(tokens[_i]);
-
-        if (l = checkSC(_i)) _i += l;
-
-        return _i - start;
-    }
-
-    function _getBlockdecl1() {
-        return getSC()
-                .concat([tokens[pos].bd_filter? getFilter() : getDeclaration()])
-                .concat(getSC());
-    }
-
-    //sc*:s0 decldelim:x sc*:s1 -> this.concat(s0, [x], s1)
-    function _checkBlockdecl2(_i) {
-        var start = _i,
-            l;
-
-        if (l = checkSC(_i)) _i += l;
-
-        if (l = checkDecldelim(_i)) _i += l;
-        else return fail(tokens[_i]);
-
-        if (l = checkSC(_i)) _i += l;
-
-        return _i - start;
-    }
-
-    function _getBlockdecl2() {
-        return getSC()
-                 .concat([getDecldelim()])
-                 .concat(getSC());
-    }
-
-    //sc+:s0 -> s0
-    function _checkBlockdecl3(_i) {
-        return checkSC(_i);
-    }
-
-    function _getBlockdecl3() {
-        return getSC();
-    }
-
-//braces = '(' tset*:x ')' -> this.concat([#braces, '(', ')'], x)
-//       | '[' tset*:x ']' -> this.concat([#braces, '[', ']'], x)
-    function checkBraces(_i) {
-        if (_i >= tokens.length ||
-            (tokens[_i].type !== TokenType.LeftParenthesis &&
-             tokens[_i].type !== TokenType.LeftSquareBracket)
-            ) return fail(tokens[_i]);
-
-        return tokens[_i].right - _i + 1;
-    }
-
-    function getBraces() {
-        var startPos = pos,
-            left = pos,
-            right = tokens[pos].right;
-
-        pos++;
-
-        var tsets = getTsets();
-
-        pos++;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.BracesType, tokens[left].value, tokens[right].value].concat(tsets) :
-                [CSSPNodeType.BracesType, tokens[left].value, tokens[right].value].concat(tsets);
-    }
-
-    function checkCDC(_i) {}
-
-    function checkCDO(_i) {}
-
-    // node: Clazz
-    function checkClazz(_i) {
-        var l;
-
-        if (tokens[_i].clazz_l) return tokens[_i].clazz_l;
-
-        if (tokens[_i].type === TokenType.FullStop) {
-            if (l = checkIdent(_i + 1)) {
-                tokens[_i].clazz_l = l + 1;
-                return l + 1;
-            }
-        }
-
-        return fail(tokens[_i]);
-    }
-
-    function getClazz() {
-        var startPos = pos;
-
-        pos++;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.ClazzType, getIdent()] :
-                [CSSPNodeType.ClazzType, getIdent()];
-    }
-
-    // node: Combinator
-    function checkCombinator(_i) {
-        if (tokens[_i].type === TokenType.PlusSign ||
-            tokens[_i].type === TokenType.GreaterThanSign ||
-            tokens[_i].type === TokenType.Tilde) return 1;
-
-        return fail(tokens[_i]);
-    }
-
-    function getCombinator() {
-        return needInfo?
-                [{ ln: tokens[pos].ln }, CSSPNodeType.CombinatorType, tokens[pos++].value] :
-                [CSSPNodeType.CombinatorType, tokens[pos++].value];
-    }
-
-    // node: Comment
-    function checkComment(_i) {
-        if (tokens[_i].type === TokenType.CommentML) return 1;
-
-        return fail(tokens[_i]);
-    }
-
-    function getComment() {
-        var startPos = pos,
-            s = tokens[pos].value.substring(2),
-            l = s.length;
-
-        if (s.charAt(l - 2) === '*' && s.charAt(l - 1) === '/') s = s.substring(0, l - 2);
-
-        pos++;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.CommentType, s] :
-                [CSSPNodeType.CommentType, s];
-    }
-
-    // declaration = property:x ':' value:y -> [#declaration, x, y]
-    function checkDeclaration(_i) {
-        var start = _i,
-            l;
-
-        if (l = checkProperty(_i)) _i += l;
-        else return fail(tokens[_i]);
-
-        if (_i < tokens.length && tokens[_i].type === TokenType.Colon) _i++;
-        else return fail(tokens[_i]);
-
-        if (l = checkValue(_i)) _i += l;
-        else return fail(tokens[_i]);
-
-        return _i - start;
-    }
-
-    function getDeclaration() {
-        var declaration = needInfo?
-                [{ ln: tokens[pos].ln }, CSSPNodeType.DeclarationType, getProperty()] :
-                [CSSPNodeType.DeclarationType, getProperty()];
-
-        pos++;
-
-        declaration.push(getValue());
-
-        return declaration;
-    }
-
-    // node: Decldelim
-    function checkDecldelim(_i) {
-        if (_i < tokens.length && tokens[_i].type === TokenType.Semicolon) return 1;
-
-        return fail(tokens[_i]);
-    }
-
-    function getDecldelim() {
-        var startPos = pos;
-
-        pos++;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.DecldelimType] :
-                [CSSPNodeType.DecldelimType];
-    }
-
-    // node: Delim
-    function checkDelim(_i) {
-        if (_i < tokens.length && tokens[_i].type === TokenType.Comma) return 1;
-
-        if (_i >= tokens.length) return fail(tokens[tokens.length - 1]);
-
-        return fail(tokens[_i]);
-    }
-
-    function getDelim() {
-        var startPos = pos;
-
-        pos++;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.DelimType] :
-                [CSSPNodeType.DelimType];
-    }
-
-    // node: Dimension
-    function checkDimension(_i) {
-        var ln = checkNumber(_i),
-            li;
-
-        if (!ln || (ln && _i + ln >= tokens.length)) return fail(tokens[_i]);
-
-        if (li = checkNmName2(_i + ln)) return ln + li;
-
-        return fail(tokens[_i]);
-    }
-
-    function getDimension() {
-        var startPos = pos,
-            n = getNumber(),
-            dimension = needInfo ?
-                [{ ln: tokens[pos].ln }, CSSPNodeType.IdentType, getNmName2()] :
-                [CSSPNodeType.IdentType, getNmName2()];
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.DimensionType, n, dimension] :
-                [CSSPNodeType.DimensionType, n, dimension];
-    }
-
-//filter = filterp:x ':' filterv:y -> [#filter, x, y]
-    function checkFilter(_i) {
-        var start = _i,
-            l;
-
-        if (l = checkFilterp(_i)) _i += l;
-        else return fail(tokens[_i]);
-
-        if (tokens[_i].type === TokenType.Colon) _i++;
-        else return fail(tokens[_i]);
-
-        if (l = checkFilterv(_i)) _i += l;
-        else return fail(tokens[_i]);
-
-        return _i - start;
-    }
-
-    function getFilter() {
-        var filter = needInfo?
-                [{ ln: tokens[pos].ln }, CSSPNodeType.FilterType, getFilterp()] :
-                [CSSPNodeType.FilterType, getFilterp()];
-
-        pos++;
-
-        filter.push(getFilterv());
-
-        return filter;
-    }
-
-//filterp = (seq('-filter') | seq('_filter') | seq('*filter') | seq('-ms-filter') | seq('filter')):t sc*:s0 -> this.concat([#property, [#ident, t]], s0)
-    function checkFilterp(_i) {
-        var start = _i,
-            l,
-            x;
-
-        if (_i < tokens.length) {
-            if (tokens[_i].value === 'filter') l = 1;
-            else {
-                x = joinValues2(_i, 2);
-
-                if (x === '-filter' || x === '_filter' || x === '*filter') l = 2;
-                else {
-                    x = joinValues2(_i, 4);
-
-                    if (x === '-ms-filter') l = 4;
-                    else return fail(tokens[_i]);
-                }
-            }
-
-            tokens[start].filterp_l = l;
-
-            _i += l;
-
-            if (checkSC(_i)) _i += l;
-
-            return _i - start;
-        }
-
-        return fail(tokens[_i]);
-    }
-
-    function getFilterp() {
-        var startPos = pos,
-            x = joinValues2(pos, tokens[pos].filterp_l),
-            ident = needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.IdentType, x] : [CSSPNodeType.IdentType, x];
-
-        pos += tokens[pos].filterp_l;
-
-        return (needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.PropertyType, ident] : [CSSPNodeType.PropertyType, ident])
-                    .concat(getSC());
-
-    }
-
-//filterv = progid+:x -> [#filterv].concat(x)
-    function checkFilterv(_i) {
-        var start = _i,
-            l;
-
-        if (l = checkProgid(_i)) _i += l;
-        else return fail(tokens[_i]);
-
-        while (l = checkProgid(_i)) {
-            _i += l;
-        }
-
-        tokens[start].last_progid = _i;
-
-        if (_i < tokens.length && (l = checkSC(_i))) _i += l;
-
-        if (_i < tokens.length && (l = checkImportant(_i))) _i += l;
-
-        return _i - start;
-    }
-
-    function getFilterv() {
-        var filterv = needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.FiltervType] : [CSSPNodeType.FiltervType],
-            last_progid = tokens[pos].last_progid;
-
-        while (pos < last_progid) {
-            filterv.push(getProgid());
-        }
-
-        filterv = filterv.concat(checkSC(pos) ? getSC() : []);
-
-        if (pos < tokens.length && checkImportant(pos)) filterv.push(getImportant());
-
-        return filterv;
-    }
-
-//functionExpression = ``expression('' functionExpressionBody*:x ')' -> [#functionExpression, x.join('')],
-    function checkFunctionExpression(_i) {
-        var start = _i;
-
-        if (!tokens[_i] || tokens[_i++].value !== 'expression') return fail(tokens[_i - 1]);
-
-        if (!tokens[_i] || tokens[_i].type !== TokenType.LeftParenthesis) return fail(tokens[_i]);
-
-        return tokens[_i].right - start + 1;
-    }
-
-    function getFunctionExpression() {
-        var startPos = pos;
-
-        pos++;
-
-        var e = joinValues(pos + 1, tokens[pos].right - 1);
-
-        pos = tokens[pos].right + 1;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.FunctionExpressionType, e] :
-                [CSSPNodeType.FunctionExpressionType, e];
-    }
-
-//funktion = ident:x '(' functionBody:y ')' -> [#funktion, x, y]
-    function checkFunktion(_i) {
-        var start = _i,
-            l = checkIdent(_i);
-
-        if (!l) return fail(tokens[_i]);
-
-        _i += l;
-
-        if (_i >= tokens.length || tokens[_i].type !== TokenType.LeftParenthesis) return fail(tokens[_i - 1]);
-
-        return tokens[_i].right - start + 1;
-    }
-
-    function getFunktion() {
-        var startPos = pos,
-            ident = getIdent();
-
-        pos++;
-
-        var body = ident[needInfo? 2 : 1] !== 'not'?
-            getFunctionBody() :
-            getNotFunctionBody(); // ok, here we have CSS3 initial draft: http://dev.w3.org/csswg/selectors3/#negation
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.FunktionType, ident, body] :
-                [CSSPNodeType.FunktionType, ident, body];
-    }
-
-    function getFunctionBody() {
-        var startPos = pos,
-            body = [],
-            x;
-
-        while (tokens[pos].type !== TokenType.RightParenthesis) {
-            if (checkTset(pos)) {
-                x = getTset();
-                if ((needInfo && typeof x[1] === 'string') || typeof x[0] === 'string') body.push(x);
-                else body = body.concat(x);
-            } else if (checkClazz(pos)) {
-                body.push(getClazz());
-            } else {
-                throwError();
-            }
-        }
-
-        pos++;
-
-        return (needInfo?
-                    [{ ln: tokens[startPos].ln }, CSSPNodeType.FunctionBodyType] :
-                    [CSSPNodeType.FunctionBodyType]
-                ).concat(body);
-    }
-
-    function getNotFunctionBody() {
-        var startPos = pos,
-            body = [],
-            x;
-
-        while (tokens[pos].type !== TokenType.RightParenthesis) {
-            if (checkSimpleselector(pos)) {
-                body.push(getSimpleSelector());
-            } else {
-                throwError();
-            }
-        }
-
-        pos++;
-
-        return (needInfo?
-                    [{ ln: tokens[startPos].ln }, CSSPNodeType.FunctionBodyType] :
-                    [CSSPNodeType.FunctionBodyType]
-                ).concat(body);
-    }
-
-    // node: Ident
-    function checkIdent(_i) {
-        var start = _i,
-            wasIdent = false;
-
-        // start char / word
-        if (_i < tokens.length &&
-            (tokens[_i].type === TokenType.HyphenMinus ||
-            tokens[_i].type === TokenType.LowLine ||
-            tokens[_i].type === TokenType.Identifier ||
-            tokens[_i].type === TokenType.DollarSign ||
-            tokens[_i].type === TokenType.Asterisk)) _i++;
-        else return fail(tokens[_i]);
-
-        wasIdent = tokens[_i - 1].type === TokenType.Identifier;
-
-        for (; _i < tokens.length; _i++) {
-            if (tokens[_i].type !== TokenType.HyphenMinus &&
-                tokens[_i].type !== TokenType.LowLine) {
-                    if (tokens[_i].type !== TokenType.Identifier &&
-                        (tokens[_i].type !== TokenType.DecimalNumber || !wasIdent)
-                        ) break;
-                    else wasIdent = true;
-            }
-        }
-
-        if (!wasIdent && tokens[start].type !== TokenType.Asterisk) return fail(tokens[_i]);
-
-        tokens[start].ident_last = _i - 1;
-
-        return _i - start;
-    }
-
-    function getIdent() {
-        var startPos = pos,
-            s = joinValues(pos, tokens[pos].ident_last);
-
-        pos = tokens[pos].ident_last + 1;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.IdentType, s] :
-                [CSSPNodeType.IdentType, s];
-    }
-
-//important = '!' sc*:s0 seq('important') -> [#important].concat(s0)
-    function checkImportant(_i) {
-        var start = _i,
-            l;
-
-        if (tokens[_i++].type !== TokenType.ExclamationMark) return fail(tokens[_i - 1]);
-
-        if (l = checkSC(_i)) _i += l;
-
-        if (tokens[_i].value !== 'important') return fail(tokens[_i]);
-
-        return _i - start + 1;
-    }
-
-    function getImportant() {
-        var startPos = pos;
-
-        pos++;
-
-        var sc = getSC();
-
-        pos++;
-
-        return (needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.ImportantType] : [CSSPNodeType.ImportantType]).concat(sc);
-    }
-
-    // node: Namespace
-    function checkNamespace(_i) {
-        if (tokens[_i].type === TokenType.VerticalLine) return 1;
-
-        return fail(tokens[_i]);
-    }
-
-    function getNamespace() {
-        var startPos = pos;
-
-        pos++;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.NamespaceType] :
-                [CSSPNodeType.NamespaceType];
-    }
-
-//nth = (digit | 'n')+:x -> [#nth, x.join('')]
-//    | (seq('even') | seq('odd')):x -> [#nth, x]
-    function checkNth(_i) {
-        return checkNth1(_i) || checkNth2(_i);
-    }
-
-    function checkNth1(_i) {
-        var start = _i;
-
-        for (; _i < tokens.length; _i++) {
-            if (tokens[_i].type !== TokenType.DecimalNumber && tokens[_i].value !== 'n') break;
-        }
-
-        if (_i !== start) {
-            tokens[start].nth_last = _i - 1;
-            return _i - start;
-        }
-
-        return fail(tokens[_i]);
-    }
-
-    function getNth() {
-        var startPos = pos;
-
-        if (tokens[pos].nth_last) {
-            var n = needInfo?
-                        [{ ln: tokens[startPos].ln }, CSSPNodeType.NthType, joinValues(pos, tokens[pos].nth_last)] :
-                        [CSSPNodeType.NthType, joinValues(pos, tokens[pos].nth_last)];
-
-            pos = tokens[pos].nth_last + 1;
-
-            return n;
-        }
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.NthType, tokens[pos++].value] :
-                [CSSPNodeType.NthType, tokens[pos++].value];
-    }
-
-    function checkNth2(_i) {
-        if (tokens[_i].value === 'even' || tokens[_i].value === 'odd') return 1;
-
-        return fail(tokens[_i]);
-    }
-
-//nthf = ':' seq('nth-'):x (seq('child') | seq('last-child') | seq('of-type') | seq('last-of-type')):y -> (x + y)
-    function checkNthf(_i) {
-        var start = _i,
-            l = 0;
-
-        if (tokens[_i++].type !== TokenType.Colon) return fail(tokens[_i - 1]); l++;
-
-        if (tokens[_i++].value !== 'nth' || tokens[_i++].value !== '-') return fail(tokens[_i - 1]); l += 2;
-
-        if ('child' === tokens[_i].value) {
-            l += 1;
-        } else if ('last-child' === tokens[_i].value +
-                                    tokens[_i + 1].value +
-                                    tokens[_i + 2].value) {
-            l += 3;
-        } else if ('of-type' === tokens[_i].value +
-                                 tokens[_i + 1].value +
-                                 tokens[_i + 2].value) {
-            l += 3;
-        } else if ('last-of-type' === tokens[_i].value +
-                                      tokens[_i + 1].value +
-                                      tokens[_i + 2].value +
-                                      tokens[_i + 3].value +
-                                      tokens[_i + 4].value) {
-            l += 5;
-        } else return fail(tokens[_i]);
-
-        tokens[start + 1].nthf_last = start + l - 1;
-
-        return l;
-    }
-
-    function getNthf() {
-        pos++;
-
-        var s = joinValues(pos, tokens[pos].nthf_last);
-
-        pos = tokens[pos].nthf_last + 1;
-
-        return s;
-    }
-
-//nthselector = nthf:x '(' (sc | unary | nth)*:y ')' -> [#nthselector, [#ident, x]].concat(y)
-    function checkNthselector(_i) {
-        var start = _i,
-            l;
-
-        if (l = checkNthf(_i)) _i += l;
-        else return fail(tokens[_i]);
-
-        if (tokens[_i].type !== TokenType.LeftParenthesis || !tokens[_i].right) return fail(tokens[_i]);
-
-        l++;
-
-        var rp = tokens[_i++].right;
-
-        while (_i < rp) {
-            if (l = checkSC(_i)) _i += l;
-            else if (l = checkUnary(_i)) _i += l;
-            else if (l = checkNth(_i)) _i += l;
-            else return fail(tokens[_i]);
-        }
-
-        return rp - start + 1;
-    }
-
-    function getNthselector() {
-        var startPos = pos,
-            nthf = needInfo?
-                    [{ ln: tokens[pos].ln }, CSSPNodeType.IdentType, getNthf()] :
-                    [CSSPNodeType.IdentType, getNthf()],
-            ns = needInfo?
-                    [{ ln: tokens[pos].ln }, CSSPNodeType.NthselectorType, nthf] :
-                    [CSSPNodeType.NthselectorType, nthf];
-
-        pos++;
-
-        while (tokens[pos].type !== TokenType.RightParenthesis) {
-            if (checkSC(pos)) ns = ns.concat(getSC());
-            else if (checkUnary(pos)) ns.push(getUnary());
-            else if (checkNth(pos)) ns.push(getNth());
-        }
-
-        pos++;
-
-        return ns;
-    }
-
-    // node: Number
-    function checkNumber(_i) {
-        if (_i < tokens.length && tokens[_i].number_l) return tokens[_i].number_l;
-
-        if (_i < tokens.length && tokens[_i].type === TokenType.DecimalNumber &&
-            (!tokens[_i + 1] ||
-             (tokens[_i + 1] && tokens[_i + 1].type !== TokenType.FullStop))
-        ) return (tokens[_i].number_l = 1, tokens[_i].number_l); // 10
-
-        if (_i < tokens.length &&
-             tokens[_i].type === TokenType.DecimalNumber &&
-             tokens[_i + 1] && tokens[_i + 1].type === TokenType.FullStop &&
-             (!tokens[_i + 2] || (tokens[_i + 2].type !== TokenType.DecimalNumber))
-        ) return (tokens[_i].number_l = 2, tokens[_i].number_l); // 10.
-
-        if (_i < tokens.length &&
-            tokens[_i].type === TokenType.FullStop &&
-            tokens[_i + 1].type === TokenType.DecimalNumber
-        ) return (tokens[_i].number_l = 2, tokens[_i].number_l); // .10
-
-        if (_i < tokens.length &&
-            tokens[_i].type === TokenType.DecimalNumber &&
-            tokens[_i + 1] && tokens[_i + 1].type === TokenType.FullStop &&
-            tokens[_i + 2] && tokens[_i + 2].type === TokenType.DecimalNumber
-        ) return (tokens[_i].number_l = 3, tokens[_i].number_l); // 10.10
-
-        return fail(tokens[_i]);
-    }
-
-    function getNumber() {
-        var s = '',
-            startPos = pos,
-            l = tokens[pos].number_l;
-
-        for (var i = 0; i < l; i++) {
-            s += tokens[pos + i].value;
-        }
-
-        pos += l;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.NumberType, s] :
-                [CSSPNodeType.NumberType, s];
-    }
-
-    // node: Operator
-    function checkOperator(_i) {
-        if (_i < tokens.length &&
-            (tokens[_i].type === TokenType.Solidus ||
-            tokens[_i].type === TokenType.Comma ||
-            tokens[_i].type === TokenType.Colon ||
-            tokens[_i].type === TokenType.EqualsSign)) return 1;
-
-        return fail(tokens[_i]);
-    }
-
-    function getOperator() {
-        return needInfo?
-                [{ ln: tokens[pos].ln }, CSSPNodeType.OperatorType, tokens[pos++].value] :
-                [CSSPNodeType.OperatorType, tokens[pos++].value];
-    }
-
-    // node: Percentage
-    function checkPercentage(_i) {
-        var x = checkNumber(_i);
-
-        if (!x || (x && _i + x >= tokens.length)) return fail(tokens[_i]);
-
-        if (tokens[_i + x].type === TokenType.PercentSign) return x + 1;
-
-        return fail(tokens[_i]);
-    }
-
-    function getPercentage() {
-        var startPos = pos,
-            n = getNumber();
-
-        pos++;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.PercentageType, n] :
-                [CSSPNodeType.PercentageType, n];
-    }
-
-//progid = sc*:s0 seq('progid:DXImageTransform.Microsoft.'):x letter+:y '(' (m_string | m_comment | ~')' char)+:z ')' sc*:s1
-//                -> this.concat([#progid], s0, [[#raw, x + y.join('') + '(' + z.join('') + ')']], s1),
-    function checkProgid(_i) {
-        var start = _i,
-            l,
-            x;
-
-        if (l = checkSC(_i)) _i += l;
-
-        if ((x = joinValues2(_i, 6)) === 'progid:DXImageTransform.Microsoft.') {
-            _start = _i;
-            _i += 6;
-        } else return fail(tokens[_i - 1]);
-
-        if (l = checkIdent(_i)) _i += l;
-        else return fail(tokens[_i]);
-
-        if (l = checkSC(_i)) _i += l;
-
-        if (tokens[_i].type === TokenType.LeftParenthesis) {
-            tokens[start].progid_end = tokens[_i].right;
-            _i = tokens[_i].right + 1;
-        } else return fail(tokens[_i]);
-
-        if (l = checkSC(_i)) _i += l;
-
-        return _i - start;
-    }
-
-    function getProgid() {
-        var startPos = pos,
-            progid_end = tokens[pos].progid_end;
-
-        return (needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.ProgidType] : [CSSPNodeType.ProgidType])
-                .concat(getSC())
-                .concat([_getProgid(progid_end)])
-                .concat(getSC());
-    }
-
-    function _getProgid(progid_end) {
-        var startPos = pos,
-            x = joinValues(pos, progid_end);
-
-        pos = progid_end + 1;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.RawType, x] :
-                [CSSPNodeType.RawType, x];
-    }
-
-//property = ident:x sc*:s0 -> this.concat([#property, x], s0)
-    function checkProperty(_i) {
-        var start = _i,
-            l;
-
-        if (l = checkIdent(_i)) _i += l;
-        else return fail(tokens[_i]);
-
-        if (l = checkSC(_i)) _i += l;
-        return _i - start;
-    }
-
-    function getProperty() {
-        var startPos = pos;
-
-        return (needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.PropertyType, getIdent()] :
-                [CSSPNodeType.PropertyType, getIdent()])
-            .concat(getSC());
-    }
-
-    function checkPseudo(_i) {
-        return checkPseudoe(_i) ||
-               checkPseudoc(_i);
-    }
-
-    function getPseudo() {
-        if (checkPseudoe(pos)) return getPseudoe();
-        if (checkPseudoc(pos)) return getPseudoc();
-    }
-
-    function checkPseudoe(_i) {
-        var l;
-
-        if (tokens[_i++].type !== TokenType.Colon) return fail(tokens[_i - 1]);
-
-        if (tokens[_i++].type !== TokenType.Colon) return fail(tokens[_i - 1]);
-
-        if (l = checkIdent(_i)) return l + 2;
-
-        return fail(tokens[_i]);
-    }
-
-    function getPseudoe() {
-        var startPos = pos;
-
-        pos += 2;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.PseudoeType, getIdent()] :
-                [CSSPNodeType.PseudoeType, getIdent()];
-    }
-
-//pseudoc = ':' (funktion | ident):x -> [#pseudoc, x]
-    function checkPseudoc(_i) {
-        var l;
-
-        if (tokens[_i++].type !== TokenType.Colon) return fail(tokens[_i - 1]);
-
-        if ((l = checkFunktion(_i)) || (l = checkIdent(_i))) return l + 1;
-
-        return fail(tokens[_i]);
-    }
-
-    function getPseudoc() {
-        var startPos = pos;
-
-        pos++;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.PseudocType, checkFunktion(pos)? getFunktion() : getIdent()] :
-                [CSSPNodeType.PseudocType, checkFunktion(pos)? getFunktion() : getIdent()];
-    }
-
-    //ruleset = selector*:x block:y -> this.concat([#ruleset], x, [y])
-    function checkRuleset(_i) {
-        var start = _i,
-            l;
-
-        if (tokens[start].ruleset_l !== undefined) return tokens[start].ruleset_l;
-
-        while (l = checkSelector(_i)) {
-            _i += l;
-        }
-
-        if (l = checkBlock(_i)) _i += l;
-        else return fail(tokens[_i]);
-
-        tokens[start].ruleset_l = _i - start;
-
-        return _i - start;
-    }
-
-    function getRuleset() {
-        var ruleset = needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.RulesetType] : [CSSPNodeType.RulesetType];
-
-        while (!checkBlock(pos)) {
-            ruleset.push(getSelector());
-        }
-
-        ruleset.push(getBlock());
-
-        return ruleset;
-    }
-
-    // node: S
-    function checkS(_i) {
-        if (tokens[_i].ws) return tokens[_i].ws_last - _i + 1;
-
-        return fail(tokens[_i]);
-    }
-
-    function getS() {
-        var startPos = pos,
-            s = joinValues(pos, tokens[pos].ws_last);
-
-        pos = tokens[pos].ws_last + 1;
-
-        return needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.SType, s] : [CSSPNodeType.SType, s];
-    }
-
-    function checkSC(_i) {
-        var l,
-            lsc = 0;
-
-        while (_i < tokens.length) {
-            if (!(l = checkS(_i)) && !(l = checkComment(_i))) break;
-            _i += l;
-            lsc += l;
-        }
-
-        if (lsc) return lsc;
-
-        if (_i >= tokens.length) return fail(tokens[tokens.length - 1]);
-
-        return fail(tokens[_i]);
-    }
-
-    function getSC() {
-        var sc = [];
-
-        while (pos < tokens.length) {
-            if (checkS(pos)) sc.push(getS());
-            else if (checkComment(pos)) sc.push(getComment());
-            else break;
-        }
-
-        return sc;
-    }
-
-    //selector = (simpleselector | delim)+:x -> this.concat([#selector], x)
-    function checkSelector(_i) {
-        var start = _i,
-            l;
-
-        if (_i < tokens.length) {
-            while (l = checkSimpleselector(_i) || checkDelim(_i)) {
-                _i += l;
-            }
-
-            tokens[start].selector_end = _i - 1;
-
-            return _i - start;
-        }
-    }
-
-    function getSelector() {
-        var selector = needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.SelectorType] : [CSSPNodeType.SelectorType],
-            selector_end = tokens[pos].selector_end;
-
-        while (pos <= selector_end) {
-            selector.push(checkDelim(pos) ? getDelim() : getSimpleSelector());
-        }
-
-        return selector;
-    }
-
-    // node: Shash
-    function checkShash(_i) {
-        if (tokens[_i].type !== TokenType.NumberSign) return fail(tokens[_i]);
-
-        var l = checkNmName(_i + 1);
-
-        if (l) return l + 1;
-
-        return fail(tokens[_i]);
-    }
-
-    function getShash() {
-        var startPos = pos;
-
-        pos++;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.ShashType, getNmName()] :
-                [CSSPNodeType.ShashType, getNmName()];
-    }
-
-//simpleselector = (nthselector | combinator | attrib | pseudo | clazz | shash | any | sc | namespace)+:x -> this.concatContent([#simpleselector], [x])
-    function checkSimpleselector(_i) {
-        var start = _i,
-            l;
-
-        while (_i < tokens.length) {
-            if (l = _checkSimpleSelector(_i)) _i += l;
-            else break;
-        }
-
-        if (_i - start) return _i - start;
-
-        if (_i >= tokens.length) return fail(tokens[tokens.length - 1]);
-
-        return fail(tokens[_i]);
-    }
-
-    function _checkSimpleSelector(_i) {
-        return checkNthselector(_i) ||
-               checkCombinator(_i) ||
-               checkAttrib(_i) ||
-               checkPseudo(_i) ||
-               checkClazz(_i) ||
-               checkShash(_i) ||
-               checkAny(_i) ||
-               checkSC(_i) ||
-               checkNamespace(_i);
-    }
-
-    function getSimpleSelector() {
-        var ss = needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.SimpleselectorType] : [CSSPNodeType.SimpleselectorType],
-            t;
-
-        while (pos < tokens.length && _checkSimpleSelector(pos)) {
-            t = _getSimpleSelector();
-
-            if ((needInfo && typeof t[1] === 'string') || typeof t[0] === 'string') ss.push(t);
-            else ss = ss.concat(t);
-        }
-
-        return ss;
-    }
-
-    function _getSimpleSelector() {
-        if (checkNthselector(pos)) return getNthselector();
-        else if (checkCombinator(pos)) return getCombinator();
-        else if (checkAttrib(pos)) return getAttrib();
-        else if (checkPseudo(pos)) return getPseudo();
-        else if (checkClazz(pos)) return getClazz();
-        else if (checkShash(pos)) return getShash();
-        else if (checkAny(pos)) return getAny();
-        else if (checkSC(pos)) return getSC();
-        else if (checkNamespace(pos)) return getNamespace();
-    }
-
-    // node: String
-    function checkString(_i) {
-        if (_i < tokens.length &&
-            (tokens[_i].type === TokenType.StringSQ || tokens[_i].type === TokenType.StringDQ)
-        ) return 1;
-
-        return fail(tokens[_i]);
-    }
-
-    function getString() {
-        var startPos = pos;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.StringType, tokens[pos++].value] :
-                [CSSPNodeType.StringType, tokens[pos++].value];
-    }
-
-    //stylesheet = (cdo | cdc | sc | statement)*:x -> this.concat([#stylesheet], x)
-    function checkStylesheet(_i) {
-        var start = _i,
-            l;
-
-        while (_i < tokens.length) {
-            if (l = checkSC(_i)) _i += l;
-            else {
-                currentBlockLN = tokens[_i].ln;
-                if (l = checkAtrule(_i)) _i += l;
-                else if (l = checkRuleset(_i)) _i += l;
-                else if (l = checkUnknown(_i)) _i += l;
-                else throwError();
-            }
-        }
-
-        return _i - start;
-    }
-
-    function getStylesheet(_i) {
-        var t,
-            stylesheet = needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.StylesheetType] : [CSSPNodeType.StylesheetType];
-
-        while (pos < tokens.length) {
-            if (checkSC(pos)) stylesheet = stylesheet.concat(getSC());
-            else {
-                currentBlockLN = tokens[pos].ln;
-                if (checkRuleset(pos)) stylesheet.push(getRuleset());
-                else if (checkAtrule(pos)) stylesheet.push(getAtrule());
-                else if (checkUnknown(pos)) stylesheet.push(getUnknown());
-                else throwError();
-            }
-        }
-
-        return stylesheet;
-    }
-
-//tset = vhash | any | sc | operator
-    function checkTset(_i) {
-        return checkVhash(_i) ||
-               checkAny(_i) ||
-               checkSC(_i) ||
-               checkOperator(_i);
-    }
-
-    function getTset() {
-        if (checkVhash(pos)) return getVhash();
-        else if (checkAny(pos)) return getAny();
-        else if (checkSC(pos)) return getSC();
-        else if (checkOperator(pos)) return getOperator();
-    }
-
-    function checkTsets(_i) {
-        var start = _i,
-            l;
-
-        while (l = checkTset(_i)) {
-            _i += l;
-        }
-
-        return _i - start;
-    }
-
-    function getTsets() {
-        var tsets = [],
-            x;
-
-        while (x = getTset()) {
-            if ((needInfo && typeof x[1] === 'string') || typeof x[0] === 'string') tsets.push(x);
-            else tsets = tsets.concat(x);
-        }
-
-        return tsets;
-    }
-
-    // node: Unary
-    function checkUnary(_i) {
-        if (_i < tokens.length &&
-            (tokens[_i].type === TokenType.HyphenMinus ||
-            tokens[_i].type === TokenType.PlusSign)
-        ) return 1;
-
-        return fail(tokens[_i]);
-    }
-
-    function getUnary() {
-        var startPos = pos;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.UnaryType, tokens[pos++].value] :
-                [CSSPNodeType.UnaryType, tokens[pos++].value];
-    }
-
-    // node: Unknown
-    function checkUnknown(_i) {
-        if (_i < tokens.length && tokens[_i].type === TokenType.CommentSL) return 1;
-
-        return fail(tokens[_i]);
-    }
-
-    function getUnknown() {
-        var startPos = pos;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.UnknownType, tokens[pos++].value] :
-                [CSSPNodeType.UnknownType, tokens[pos++].value];
-    }
-
-//    uri = seq('url(') sc*:s0 string:x sc*:s1 ')' -> this.concat([#uri], s0, [x], s1)
-//        | seq('url(') sc*:s0 (~')' ~m_w char)*:x sc*:s1 ')' -> this.concat([#uri], s0, [[#raw, x.join('')]], s1),
-    function checkUri(_i) {
-        var start = _i,
-            l;
-
-        if (_i < tokens.length && tokens[_i++].value !== 'url') return fail(tokens[_i - 1]);
-
-        if (!tokens[_i] || tokens[_i].type !== TokenType.LeftParenthesis) return fail(tokens[_i]);
-
-        return tokens[_i].right - start + 1;
-    }
-
-    function getUri() {
-        var startPos = pos,
-            uriExcluding = {};
-
-        pos += 2;
-
-        uriExcluding[TokenType.Space] = 1;
-        uriExcluding[TokenType.Tab] = 1;
-        uriExcluding[TokenType.Newline] = 1;
-        uriExcluding[TokenType.LeftParenthesis] = 1;
-        uriExcluding[TokenType.RightParenthesis] = 1;
-
-        if (checkUri1(pos)) {
-            var uri = (needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.UriType] : [CSSPNodeType.UriType])
-                        .concat(getSC())
-                        .concat([getString()])
-                        .concat(getSC());
-
-            pos++;
-
-            return uri;
-        } else {
-            var uri = (needInfo? [{ ln: tokens[startPos].ln }, CSSPNodeType.UriType] : [CSSPNodeType.UriType])
-                        .concat(getSC()),
-                l = checkExcluding(uriExcluding, pos),
-                raw = needInfo?
-                        [{ ln: tokens[pos].ln }, CSSPNodeType.RawType, joinValues(pos, pos + l)] :
-                        [CSSPNodeType.RawType, joinValues(pos, pos + l)];
-
-            uri.push(raw);
-
-            pos += l + 1;
-
-            uri = uri.concat(getSC());
-
-            pos++;
-
-            return uri;
-        }
-    }
-
-    function checkUri1(_i) {
-        var start = _i,
-            l = checkSC(_i);
-
-        if (l) _i += l;
-
-        if (tokens[_i].type !== TokenType.StringDQ && tokens[_i].type !== TokenType.StringSQ) return fail(tokens[_i]);
-
-        _i++;
-
-        if (l = checkSC(_i)) _i += l;
-
-        return _i - start;
-    }
-
-    // value = (sc | vhash | any | block | atkeyword | operator | important)+:x -> this.concat([#value], x)
-    function checkValue(_i) {
-        var start = _i,
-            l;
-
-        while (_i < tokens.length) {
-            if (l = _checkValue(_i)) _i += l;
-            else break;
-        }
-
-        if (_i - start) return _i - start;
-
-        return fail(tokens[_i]);
-    }
-
-    function _checkValue(_i) {
-        return checkSC(_i) ||
-               checkVhash(_i) ||
-               checkAny(_i) ||
-               checkBlock(_i) ||
-               checkAtkeyword(_i) ||
-               checkOperator(_i) ||
-               checkImportant(_i);
-    }
-
-    function getValue() {
-        var ss = needInfo? [{ ln: tokens[pos].ln }, CSSPNodeType.ValueType] : [CSSPNodeType.ValueType],
-            t;
-
-        while (pos < tokens.length && _checkValue(pos)) {
-            t = _getValue();
-
-            if ((needInfo && typeof t[1] === 'string') || typeof t[0] === 'string') ss.push(t);
-            else ss = ss.concat(t);
-        }
-
-        return ss;
-    }
-
-    function _getValue() {
-        if (checkSC(pos)) return getSC();
-        else if (checkVhash(pos)) return getVhash();
-        else if (checkAny(pos)) return getAny();
-        else if (checkBlock(pos)) return getBlock();
-        else if (checkAtkeyword(pos)) return getAtkeyword();
-        else if (checkOperator(pos)) return getOperator();
-        else if (checkImportant(pos)) return getImportant();
-    }
-
-    // node: Vhash
-    function checkVhash(_i) {
-        if (_i >= tokens.length || tokens[_i].type !== TokenType.NumberSign) return fail(tokens[_i]);
-
-        var l = checkNmName2(_i + 1);
-
-        if (l) return l + 1;
-
-        return fail(tokens[_i]);
-    }
-
-    function getVhash() {
-        var startPos = pos;
-
-        pos++;
-
-        return needInfo?
-                [{ ln: tokens[startPos].ln }, CSSPNodeType.VhashType, getNmName2()] :
-                [CSSPNodeType.VhashType, getNmName2()];
-    }
-
-    function checkNmName(_i) {
-        var start = _i;
-
-        // start char / word
-        if (tokens[_i].type === TokenType.HyphenMinus ||
-            tokens[_i].type === TokenType.LowLine ||
-            tokens[_i].type === TokenType.Identifier ||
-            tokens[_i].type === TokenType.DecimalNumber) _i++;
-        else return fail(tokens[_i]);
-
-        for (; _i < tokens.length; _i++) {
-            if (tokens[_i].type !== TokenType.HyphenMinus &&
-                tokens[_i].type !== TokenType.LowLine &&
-                tokens[_i].type !== TokenType.Identifier &&
-                tokens[_i].type !== TokenType.DecimalNumber) break;
-        }
-
-        tokens[start].nm_name_last = _i - 1;
-
-        return _i - start;
-    }
-
-    function getNmName() {
-        var s = joinValues(pos, tokens[pos].nm_name_last);
-
-        pos = tokens[pos].nm_name_last + 1;
-
-        return s;
-    }
-
-    function checkNmName2(_i) {
-        var start = _i;
-
-        if (tokens[_i].type === TokenType.Identifier) return 1;
-        else if (tokens[_i].type !== TokenType.DecimalNumber) return fail(tokens[_i]);
-
-        _i++;
-
-        if (!tokens[_i] || tokens[_i].type !== TokenType.Identifier) return 1;
-
-        return 2;
-    }
-
-    function getNmName2() {
-        var s = tokens[pos].value;
-
-        if (tokens[pos++].type === TokenType.DecimalNumber &&
-                pos < tokens.length &&
-                tokens[pos].type === TokenType.Identifier
-        ) s += tokens[pos++].value;
-
-        return s;
-    }
-
-    function checkExcluding(exclude, _i) {
-        var start = _i;
-
-        while(_i < tokens.length) {
-            if (exclude[tokens[_i++].type]) break;
-        }
-
-        return _i - start - 2;
-    }
-
-    function joinValues(start, finish) {
-        var s = '';
-
-        for (var i = start; i < finish + 1; i++) {
-            s += tokens[i].value;
-        }
-
-        return s;
-    }
-
-    function joinValues2(start, num) {
-        if (start + num - 1 >= tokens.length) return;
-
-        var s = '';
-
-        for (var i = 0; i < num; i++) {
-            s += tokens[start + i].value;
-        }
-
-        return s;
-    }
-
-    function markSC() {
-        var ws = -1, // whitespaces
-            sc = -1, // ws and comments
-            t;
-
-        for (var i = 0; i < tokens.length; i++) {
-            t = tokens[i];
-            switch (t.type) {
-                case TokenType.Space:
-                case TokenType.Tab:
-                case TokenType.Newline:
-                    t.ws = true;
-                    t.sc = true;
-
-                    if (ws === -1) ws = i;
-                    if (sc === -1) sc = i;
-
-                    break;
-                case TokenType.CommentML:
-                    if (ws !== -1) {
-                        tokens[ws].ws_last = i - 1;
-                        ws = -1;
-                    }
-
-                    t.sc = true;
-
-                    break;
-                default:
-                    if (ws !== -1) {
-                        tokens[ws].ws_last = i - 1;
-                        ws = -1;
-                    }
-
-                    if (sc !== -1) {
-                        tokens[sc].sc_last = i - 1;
-                        sc = -1;
-                    }
-            }
-        }
-
-        if (ws !== -1) tokens[ws].ws_last = i - 1;
-        if (sc !== -1) tokens[sc].sc_last = i - 1;
-    }
-
-    return _getAST(_tokens, rule, _needInfo);
-}
-
-    return getCSSPAST(getTokens(s), rule, _needInfo);
-}
-var translator = new CSSOTranslator(),
-    cleanInfo = $util.cleanInfo;
-function TRBL(name, imp) {
-    this.name = TRBL.extractMain(name);
-    this.sides = {
-        'top': null,
-        'right': null,
-        'bottom': null,
-        'left': null
-    };
-    this.imp = imp ? 4 : 0;
-}
-
-TRBL.props = {
-    'margin': 1,
-    'margin-top': 1,
-    'margin-right': 1,
-    'margin-bottom': 1,
-    'margin-left': 1,
-    'padding': 1,
-    'padding-top': 1,
-    'padding-right': 1,
-    'padding-bottom': 1,
-    'padding-left': 1
-};
-
-TRBL.extractMain = function(name) {
-    var i = name.indexOf('-');
-    return i === -1 ? name : name.substr(0, i);
-};
-
-TRBL.prototype.impSum = function() {
-    var imp = 0, n = 0;
-    for (var k in this.sides) {
-        if (this.sides[k]) {
-            n++;
-            if (this.sides[k].imp) imp++;
-        }
-    }
-    return imp === n ? imp : 0;
-};
-
-TRBL.prototype.add = function(name, sValue, tValue, imp) {
-    var s = this.sides,
-        currentSide,
-        i, x, side, a = [], last,
-        imp = imp ? 1 : 0,
-        wasUnary = false;
-    if ((i = name.lastIndexOf('-')) !== -1) {
-        side = name.substr(i + 1);
-        if (side in s) {
-            if (!(currentSide = s[side]) || (imp && !currentSide.imp)) {
-                s[side] = { s: imp ? sValue.substring(0, sValue.length - 10) : sValue, t: [tValue[0]], imp: imp };
-                if (tValue[0][1] === 'unary') s[side].t.push(tValue[1]);
-            }
-            return true;
-        }
-    } else if (name === this.name) {
-        for (i = 0; i < tValue.length; i++) {
-            x = tValue[i];
-            last = a[a.length - 1];
-            switch(x[1]) {
-                case 'unary':
-                    a.push({ s: x[2], t: [x], imp: imp });
-                    wasUnary = true;
-                    break;
-                case 'number':
-                case 'ident':
-                    if (wasUnary) {
-                        last.t.push(x);
-                        last.s += x[2];
-                    } else {
-                        a.push({ s: x[2], t: [x], imp: imp });
-                    }
-                    wasUnary = false;
-                    break;
-                case 'percentage':
-                    if (wasUnary) {
-                        last.t.push(x);
-                        last.s += x[2][2] + '%';
-                    } else {
-                        a.push({ s: x[2][2] + '%', t: [x], imp: imp });
-                    }
-                    wasUnary = false;
-                    break;
-                case 'dimension':
-                    if (wasUnary) {
-                        last.t.push(x);
-                        last.s += x[2][2] + x[3][2];
-                    } else {
-                        a.push({ s: x[2][2] + x[3][2], t: [x], imp: imp });
-                    }
-                    wasUnary = false;
-                    break;
-                case 's':
-                case 'comment':
-                case 'important':
-                    break;
-                default:
-                    return false;
-            }
-        }
-
-        if (a.length > 4) return false;
-
-        if (!a[1]) a[1] = a[0];
-        if (!a[2]) a[2] = a[0];
-        if (!a[3]) a[3] = a[1];
-
-        if (!s.top) s.top = a[0];
-        if (!s.right) s.right = a[1];
-        if (!s.bottom) s.bottom = a[2];
-        if (!s.left) s.left = a[3];
-
-        return true;
-    }
-};
-
-TRBL.prototype.isOkToMinimize = function() {
-    var s = this.sides,
-        imp;
-
-    if (!!(s.top && s.right && s.bottom && s.left)) {
-        imp = s.top.imp + s.right.imp + s.bottom.imp + s.left.imp;
-        return (imp === 0 || imp === 4 || imp === this.imp);
-    }
-    return false;
-};
-
-TRBL.prototype.getValue = function() {
-    var s = this.sides,
-        a = [s.top, s.right, s.bottom, s.left],
-        r = [{}, 'value'];
-
-    if (s.left.s === s.right.s) {
-        a.length--;
-        if (s.bottom.s === s.top.s) {
-            a.length--;
-            if (s.right.s === s.top.s) {
-                a.length--;
-            }
-        }
-    }
-
-    for (var i = 0; i < a.length - 1; i++) {
-        r = r.concat(a[i].t);
-        r.push([{ s: ' ' }, 's', ' ']);
-    }
-    r = r.concat(a[i].t);
-
-    if (this.impSum()) r.push([{ s: '!important'}, 'important']);
-
-    return r;
-};
-
-TRBL.prototype.getProperty = function() {
-    return [{ s: this.name }, 'property', [{ s: this.name }, 'ident', this.name]];
-};
-
-TRBL.prototype.getString = function() {
-    var p = this.getProperty(),
-        v = this.getValue().slice(2),
-        r = p[0].s + ':';
-
-    for (var i = 0; i < v.length; i++) r += v[i][0].s;
-
-    return r;
-};
-
-function CSSOCompressor() {}
-
-CSSOCompressor.prototype.init = function() {
-    this.props = {};
-    this.shorts = {};
-    this.shorts2 = {};
-
-    this.ccrules = {}; // clean comment rules â€” special case to resolve ambiguity
-    this.crules = {}; // compress rules
-    this.prules = {}; // prepare rules
-    this.frrules = {}; // freeze ruleset rules
-    this.msrules = {}; // mark shorthands rules
-    this.csrules = {}; // clean shorthands rules
-    this.rbrules = {}; // restructure block rules
-    this.rjrules = {}; // rejoin ruleset rules
-    this.rrrules = {}; // restructure ruleset rules
-    this.frules = {}; // finalize rules
-
-    this.initRules(this.crules, this.defCCfg);
-    this.initRules(this.ccrules, this.cleanCfg);
-    this.initRules(this.frrules, this.frCfg);
-    this.initRules(this.prules, this.preCfg);
-    this.initRules(this.msrules, this.msCfg);
-    this.initRules(this.csrules, this.csCfg);
-    this.initRules(this.rbrules, this.defRBCfg);
-    this.initRules(this.rjrules, this.defRJCfg);
-    this.initRules(this.rrrules, this.defRRCfg);
-    this.initRules(this.frules, this.defFCfg);
-
-    this.shortGroupID = 0;
-    this.lastShortGroupID = 0;
-    this.lastShortSelector = 0;
-};
-
-CSSOCompressor.prototype.initRules = function(r, cfg) {
-    var o = this.order,
-        p = this.profile,
-        x, i, k,
-        t = [];
-
-    for (i = 0; i < o.length; i++) if (o[i] in cfg) t.push(o[i]);
-
-    if (!t.length) t = o;
-    for (i = 0; i < t.length; i++) {
-        x = p[t[i]];
-        for (k in x) r[k] ? r[k].push(t[i]) : r[k] = [t[i]];
-    }
-};
-
-CSSOCompressor.prototype.cleanCfg = {
-    'cleanComment': 1
-};
-
-CSSOCompressor.prototype.defCCfg = {
-    'cleanCharset': 1,
-    'cleanImport': 1,
-    'cleanWhitespace': 1,
-    'cleanDecldelim': 1,
-    'compressNumber': 1,
-    'cleanUnary': 1,
-    'compressColor': 1,
-    'compressDimension': 1,
-    'compressString': 1,
-    'compressFontWeight': 1,
-    'compressFont': 1,
-    'compressBackground': 1,
-    'cleanEmpty': 1
-};
-
-CSSOCompressor.prototype.defRBCfg = {
-    'restructureBlock': 1
-};
-
-CSSOCompressor.prototype.defRJCfg = {
-    'rejoinRuleset': 1,
-    'cleanEmpty': 1
-};
-
-CSSOCompressor.prototype.defRRCfg = {
-    'restructureRuleset': 1,
-    'cleanEmpty': 1
-};
-
-CSSOCompressor.prototype.defFCfg = {
-    'cleanEmpty': 1,
-    'delimSelectors': 1,
-    'delimBlocks': 1
-};
-
-CSSOCompressor.prototype.preCfg = {
-    'destroyDelims': 1,
-    'preTranslate': 1
-};
-
-CSSOCompressor.prototype.msCfg = {
-    'markShorthands': 1
-};
-
-CSSOCompressor.prototype.frCfg = {
-    'freezeRulesets': 1
-};
-
-CSSOCompressor.prototype.csCfg = {
-    'cleanShorthands': 1,
-    'cleanEmpty': 1
-};
-
-CSSOCompressor.prototype.order = [
-    'cleanCharset',
-    'cleanImport',
-    'cleanComment',
-    'cleanWhitespace',
-    'compressNumber',
-    'cleanUnary',
-    'compressColor',
-    'compressDimension',
-    'compressString',
-    'compressFontWeight',
-    'compressFont',
-    'compressBackground',
-    'freezeRulesets',
-    'destroyDelims',
-    'preTranslate',
-    'markShorthands',
-    'cleanShorthands',
-    'restructureBlock',
-    'rejoinRuleset',
-    'restructureRuleset',
-    'cleanEmpty',
-    'delimSelectors',
-    'delimBlocks'
-];
-
-CSSOCompressor.prototype.profile = {
-    'cleanCharset': {
-        'atrules': 1
-    },
-    'cleanImport': {
-        'atrules': 1
-    },
-    'cleanWhitespace': {
-        's': 1
-    },
-    'compressNumber': {
-        'number': 1
-    },
-    'cleanUnary': {
-        'unary': 1
-    },
-    'compressColor': {
-        'vhash': 1,
-        'funktion': 1,
-        'ident': 1
-    },
-    'compressDimension': {
-        'dimension': 1
-    },
-    'compressString': {
-        'string': 1
-    },
-    'compressFontWeight': {
-        'declaration': 1
-    },
-    'compressFont': {
-        'declaration': 1
-    },
-    'compressBackground': {
-        'declaration': 1
-    },
-    'cleanComment': {
-        'comment': 1
-    },
-    'cleanDecldelim': {
-        'block': 1
-    },
-    'cleanEmpty': {
-        'ruleset': 1,
-        'atruleb': 1,
-        'atruler': 1
-    },
-    'destroyDelims': {
-        'decldelim': 1,
-        'delim': 1
-    },
-    'preTranslate': {
-        'declaration': 1,
-        'property': 1,
-        'simpleselector': 1,
-        'filter': 1,
-        'value': 1,
-        'number': 1,
-        'percentage': 1,
-        'dimension': 1,
-        'ident': 1
-    },
-    'restructureBlock': {
-        'block': 1
-    },
-    'rejoinRuleset': {
-        'ruleset': 1
-    },
-    'restructureRuleset': {
-        'ruleset': 1
-    },
-    'delimSelectors': {
-        'selector': 1
-    },
-    'delimBlocks': {
-        'block': 1
-    },
-    'markShorthands': {
-        'block': 1
-    },
-    'cleanShorthands': {
-        'declaration': 1
-    },
-    'freezeRulesets': {
-        'ruleset': 1
-    }
-};
-
-CSSOCompressor.prototype.isContainer = function(o) {
-    if (Array.isArray(o)) {
-        for (var i = 0; i < o.length; i++) if (Array.isArray(o[i])) return true;
-    }
-};
-
-CSSOCompressor.prototype.process = function(rules, token, container, i, path) {
-    var rule = token[1];
-    if (rule && rules[rule]) {
-        var r = rules[rule],
-            x1 = token, x2,
-            o = this.order, k;
-        for (var k = 0; k < r.length; k++) {
-            x2 = this[r[k]](x1, rule, container, i, path);
-            if (x2 === null) return null;
-            else if (x2 !== undefined) x1 = x2;
-        }
-    }
-    return x1;
-};
-
-CSSOCompressor.prototype.compress = function(tree, ro) {
-    tree = tree || ['stylesheet'];
-    this.init();
-    this.info = true;
-
-    var x = (typeof tree[0] !== 'string') ? tree : this.injectInfo([tree])[0],
-        l0, l1 = 100000000000, ls,
-        x0, x1, xs,
-        protectedComment = this.findProtectedComment(tree);
-
-    // compression without restructure
-    x = this.walk(this.ccrules, x, '/0');
-    x = this.walk(this.crules, x, '/0');
-    x = this.walk(this.prules, x, '/0');
-    x = this.walk(this.frrules, x, '/0');
-
-    ls = translator.translate(cleanInfo(x)).length;
-
-    if (!ro) { // restructure ON
-        xs = this.copyArray(x);
-        x = this.walk(this.rjrules, x, '/0');
-        this.disjoin(x);
-        x = this.walk(this.msrules, x, '/0');
-        x = this.walk(this.csrules, x, '/0');
-        x = this.walk(this.rbrules, x, '/0');
-        do {
-            l0 = l1;
-            x0 = this.copyArray(x);
-            x = this.walk(this.rjrules, x, '/0');
-            x = this.walk(this.rrrules, x, '/0');
-            l1 = translator.translate(cleanInfo(x)).length;
-            x1 = this.copyArray(x);
-        } while (l0 > l1);
-        if (ls < l0 && ls < l1) x = xs;
-        else if (l0 < l1) x = x0;
-    }
-
-    x = this.walk(this.frules, x, '/0');
-
-    if (protectedComment) x.splice(2, 0, protectedComment);
-
-    return x;
-};
-
-CSSOCompressor.prototype.findProtectedComment = function(tree) {
-    var token;
-    for (var i = 2; i < tree.length; i++) {
-        token = tree[i];
-        if (token[1] === 'comment' && token[2].length > 0 && token[2].charAt(0) === '!') return token;
-        if (token[1] !== 's') return;
-    }
-};
-
-CSSOCompressor.prototype.injectInfo = function(token) {
-    var t;
-    for (var i = token.length - 1; i > -1; i--) {
-        t = token[i];
-        if (t && Array.isArray(t)) {
-            if (this.isContainer(t)) t = this.injectInfo(t);
-            t.splice(0, 0, {});
-        }
-    }
-    return token;
-};
-
-CSSOCompressor.prototype.disjoin = function(container) {
-    var t, s, r, sr;
-
-    for (var i = container.length - 1; i > -1; i--) {
-        t = container[i];
-        if (t && Array.isArray(t)) {
-            if (t[1] === 'ruleset') {
-                t[0].shortGroupID = this.shortGroupID++;
-                s = t[2];
-                if (s.length > 3) {
-                    sr = s.slice(0, 2);
-                    for (var k = s.length - 1; k > 1; k--) {
-                        r = this.copyArray(t);
-                        r[2] = sr.concat([s[k]]);
-                        r[2][0].s = s[k][0].s;
-                        container.splice(i + 1, 0, r);
-                    }
-                    container.splice(i, 1);
-                }
-            }
-        }
-        if (this.isContainer(t)) this.disjoin(t);
-    }
-};
-
-CSSOCompressor.prototype.walk = function(rules, container, path) {
-    var t, x;
-    for (var i = container.length - 1; i > -1; i--) {
-        t = container[i];
-        if (t && Array.isArray(t)) {
-            t[0].parent = container;
-            if (this.isContainer(t)) t = this.walk(rules, t, path + '/' + i); // go inside
-            if (t === null) container.splice(i, 1);
-            else {
-                if (x = this.process(rules, t, container, i, path)) container[i] = x; // compressed not null
-                else if (x === null) container.splice(i, 1); // null is the mark to delete token
-            }
-        }
-    }
-    return container.length ? container : null;
-};
-
-CSSOCompressor.prototype.freezeRulesets = function(token, rule, container, i) {
-    var info = token[0],
-        selector = token[2];
-
-    info.freeze = this.freezeNeeded(selector);
-    info.freezeID = this.selectorSignature(selector);
-    info.pseudoID = this.composePseudoID(selector);
-    info.pseudoSignature = this.pseudoSelectorSignature(selector, this.allowedPClasses, true);
-    this.markSimplePseudo(selector);
-
-    return token;
-};
-
-CSSOCompressor.prototype.markSimplePseudo = function(selector) {
-    var ss, sg = {};
-
-    for (var i = 2; i < selector.length; i++) {
-        ss = selector[i];
-        ss[0].pseudo = this.containsPseudo(ss);
-        ss[0].sg = sg;
-        sg[ss[0].s] = 1;
-    }
-};
-
-CSSOCompressor.prototype.composePseudoID = function(selector) {
-    var a = [], ss;
-
-    for (var i = 2; i < selector.length; i++) {
-        ss = selector[i];
-        if (this.containsPseudo(ss)) {
-            a.push(ss[0].s);
-        }
-    }
-
-    a.sort();
-
-    return a.join(',');
-};
-
-CSSOCompressor.prototype.containsPseudo = function(sselector) {
-    for (var j = 2; j < sselector.length; j++) {
-        switch (sselector[j][1]) {
-            case 'pseudoc':
-            case 'pseudoe':
-            case 'nthselector':
-                if (!(sselector[j][2][2] in this.notFPClasses)) return true;
-        }
-    }
-};
-
-CSSOCompressor.prototype.selectorSignature = function(selector) {
-    var a = [];
-
-    for (var i = 2; i < selector.length; i++) {
-        a.push(translator.translate(cleanInfo(selector[i])));
-    }
-
-    a.sort();
-
-    return a.join(',');
-};
-
-CSSOCompressor.prototype.pseudoSelectorSignature = function(selector, exclude, dontAppendExcludeMark) {
-    var a = [], b = {}, ss, wasExclude = false;
-    exclude = exclude || {};
-
-    for (var i = 2; i < selector.length; i++) {
-        ss = selector[i];
-        for (var j = 2; j < ss.length; j++) {
-            switch (ss[j][1]) {
-                case 'pseudoc':
-                case 'pseudoe':
-                case 'nthselector':
-                    if (!(ss[j][2][2] in exclude)) b[ss[j][2][2]] = 1;
-                    else wasExclude = true;
-                    break;
-            }
-        }
-    }
-
-    for (var k in b) a.push(k);
-
-    a.sort();
-
-    return a.join(',') + (dontAppendExcludeMark? '' : wasExclude);
-};
-
-CSSOCompressor.prototype.notFPClasses = {
-    'link': 1,
-    'visited': 1,
-    'hover': 1,
-    'active': 1,
-    'first-letter': 1,
-    'first-line': 1
-};
-
-CSSOCompressor.prototype.notFPElements = {
-    'first-letter': 1,
-    'first-line': 1
-};
-
-CSSOCompressor.prototype.freezeNeeded = function(selector) {
-    var ss;
-    for (var i = 2; i < selector.length; i++) {
-        ss = selector[i];
-        for (var j = 2; j < ss.length; j++) {
-            switch (ss[j][1]) {
-                case 'pseudoc':
-                    if (!(ss[j][2][2] in this.notFPClasses)) return true;
-                    break;
-                case 'pseudoe':
-                    if (!(ss[j][2][2] in this.notFPElements)) return true;
-                    break;
-                case 'nthselector':
-                    return true;
-                    break;
-            }
-        }
-    }
-    return false;
-};
-
-CSSOCompressor.prototype.cleanCharset = function(token, rule, container, i) {
-    if (token[2][2][2] === 'charset') {
-        for (i = i - 1; i > 1; i--) {
-            if (container[i][1] !== 's' && container[i][1] !== 'comment') return null;
-        }
-    }
-};
-
-CSSOCompressor.prototype.cleanImport = function(token, rule, container, i) {
-    var x;
-    for (i = i - 1; i > 1; i--) {
-        x = container[i][1];
-        if (x !== 's' && x !== 'comment') {
-            if (x === 'atrules') {
-                x = container[i][2][2][2];
-                if (x !== 'import' && x !== 'charset') return null;
-            } else return null;
-        }
-    }
-};
-
-CSSOCompressor.prototype.cleanComment = function(token, rule, container, i) {
-    var pr = ((container[1] === 'braces' && i === 4) ||
-              (container[1] !== 'braces' && i === 2)) ? null : container[i - 1][1],
-        nr = i === container.length - 1 ? null : container[i + 1][1];
-
-    if (nr !== null && pr !== null) {
-        if (this._cleanComment(nr) || this._cleanComment(pr)) return null;
-    } else return null;
-};
-
-CSSOCompressor.prototype._cleanComment = function(r) {
-    switch(r) {
-        case 's':
-        case 'operator':
-        case 'attrselector':
-        case 'block':
-        case 'decldelim':
-        case 'ruleset':
-        case 'declaration':
-        case 'atruleb':
-        case 'atrules':
-        case 'atruler':
-        case 'important':
-        case 'nth':
-        case 'combinator':
-            return true;
-    }
-};
-
-CSSOCompressor.prototype.nextToken = function(container, type, i, exactly) {
-    var t, r;
-    for (; i < container.length; i++) {
-        t = container[i];
-        if (Array.isArray(t)) {
-            r = t[1];
-            if (r === type) return t;
-            else if (exactly && r !== 's') return;
-        }
-    }
-};
-
-CSSOCompressor.prototype.cleanWhitespace = function(token, rule, container, i) {
-    var pr = ((container[1] === 'braces' && i === 4) ||
-              (container[1] !== 'braces' && i === 2)) ? null : container[i - 1][1],
-        nr = i === container.length - 1 ? null : container[i + 1][1];
-
-    if (nr === 'unknown') token[2] = '\n';
-    else {
-        if (!(container[1] === 'atrulerq' && !pr) && !this.issue16(container, i)) {
-            if (nr !== null && pr !== null) {
-                if (this._cleanWhitespace(nr, false) || this._cleanWhitespace(pr, true)) return null;
-            } else return null;
-        }
-
-        token[2] = ' ';
-    }
-
-    return token;
-};
-
-// See https://github.com/afelix/csso/issues/16
-CSSOCompressor.prototype.issue16 = function(container, i) {
-    return (i !== 2 && i !== container.length - 1 && container[i - 1][1] === 'uri');
-};
-
-CSSOCompressor.prototype._cleanWhitespace = function(r, left) {
-    switch(r) {
-        case 's':
-        case 'operator':
-        case 'attrselector':
-        case 'block':
-        case 'decldelim':
-        case 'ruleset':
-        case 'declaration':
-        case 'atruleb':
-        case 'atrules':
-        case 'atruler':
-        case 'important':
-        case 'nth':
-        case 'combinator':
-            return true;
-    }
-    if (left) {
-        switch(r) {
-            case 'funktion':
-            case 'braces':
-            case 'uri':
-                return true;
-        }
-    }
-};
-
-CSSOCompressor.prototype.cleanDecldelim = function(token) {
-    for (var i = token.length - 1; i > 1; i--) {
-        if (token[i][1] === 'decldelim' &&
-            token[i + 1][1] !== 'declaration') token.splice(i, 1);
-    }
-    if (token[2][1] === 'decldelim') token.splice(2, 1);
-    return token;
-};
-
-CSSOCompressor.prototype.compressNumber = function(token, rule, container, i) {
-    var x = token[2];
-
-    if (/^0*/.test(x)) x = x.replace(/^0+/, '');
-    if (/\.0*$/.test(x)) x = x.replace(/\.0*$/, '');
-    if (/\..*[1-9]+0+$/.test(x)) x = x.replace(/0+$/, '');
-    if (x === '.' || x === '') x = '0';
-
-    token[2] = x;
-    token[0].s = x;
-    return token;
-};
-
-CSSOCompressor.prototype.findDeclaration = function(token) {
-    var parent = token;
-    while ((parent = parent[0].parent) && parent[1] !== 'declaration');
-    return parent;
-};
-
-CSSOCompressor.prototype.cleanUnary = function(token, rule, container, i) {
-    var next = container[i + 1];
-    if (next && next[1] === 'number' && next[2] === '0') return null;
-    return token;
-};
-
-CSSOCompressor.prototype.compressColor = function(token, rule, container, i) {
-    switch(rule) {
-        case 'vhash':
-            return this.compressHashColor(token);
-        case 'funktion':
-            return this.compressFunctionColor(token);
-        case 'ident':
-            return this.compressIdentColor(token, rule, container, i);
-    }
-};
-
-CSSOCompressor.prototype.compressIdentColor = function(token, rule, container) {
-    var map = { 'yellow': 'ff0',
-                'fuchsia': 'f0f',
-                'white': 'fff',
-                'black': '000',
-                'blue': '00f',
-                'aqua': '0ff' },
-        allow = { 'value': 1, 'functionBody': 1 },
-        _x = token[2].toLowerCase();
-
-    if (container[1] in allow && _x in map) return [{}, 'vhash', map[_x]];
-};
-
-CSSOCompressor.prototype.compressHashColor = function(token) {
-    return this._compressHashColor(token[2], token[0]);
-};
-
-CSSOCompressor.prototype._compressHashColor = function(x, info) {
-    var map = { 'f00': 'red',
-                'c0c0c0': 'silver',
-                '808080': 'gray',
-                '800000': 'maroon',
-                '800080': 'purple',
-                '008000': 'green',
-                '808000': 'olive',
-                '000080': 'navy',
-                '008080': 'teal'},
-        _x = x;
-    x = x.toLowerCase();
-
-    if (x.length === 6 &&
-        x.charAt(0) === x.charAt(1) &&
-        x.charAt(2) === x.charAt(3) &&
-        x.charAt(4) === x.charAt(5)) x = x.charAt(0) + x.charAt(2) + x.charAt(4);
-
-    return map[x] ? [info, 'string', map[x]] : [info, 'vhash', (x.length < _x.length ? x : _x)];
-};
-
-CSSOCompressor.prototype.compressFunctionColor = function(token) {
-    var i, v = [], t, h = '', body;
-
-    if (token[2][2] === 'rgb') {
-        body = token[3];
-        for (i = 2; i < body.length; i++) {
-            t = body[i][1];
-            if (t === 'number') v.push(body[i]);
-            else if (t !== 'operator') { v = []; break }
-        }
-        if (v.length === 3) {
-            h += (t = Number(v[0][2]).toString(16)).length === 1 ? '0' + t : t;
-            h += (t = Number(v[1][2]).toString(16)).length === 1 ? '0' + t : t;
-            h += (t = Number(v[2][2]).toString(16)).length === 1 ? '0' + t : t;
-            if (h.length === 6) return this._compressHashColor(h, {});
-        }
-    }
-};
-
-CSSOCompressor.prototype.compressDimension = function(token) {
-    var declaration;
-    if (token[2][2] === '0') {
-        if (token[3][2] === 's' && (declaration = this.findDeclaration(token))) {
-            var declName = declaration[2][2][2];
-            if  (declName === '-moz-transition') return; // https://github.com/css/csso/issues/82
-            if  (declName === '-moz-animation' || declName === 'animation') return; // https://github.com/css/csso/issues/100
-        }
-        return token[2];
-    }
-};
-
-CSSOCompressor.prototype.compressString = function(token, rule, container) {
-    var s = token[2], r = '', c;
-    for (var i = 0; i < s.length; i++) {
-        c = s.charAt(i);
-        if (c === '\\' && s.charAt(i + 1) === '\n') i++;
-        else r += c;
-    }
-//    if (container[1] === 'attrib' && /^('|")[a-zA-Z0-9]*('|")$/.test(r)) {
-//        r = r.substring(1, r.length - 1);
-//    }
-    if (s.length !== r.length) return [{}, 'string', r];
-};
-
-CSSOCompressor.prototype.compressFontWeight = function(token) {
-    var p = token[2],
-        v = token[3];
-    if (p[2][2].indexOf('font-weight') !== -1 && v[2][1] === 'ident') {
-        if (v[2][2] === 'normal') v[2] = [{}, 'number', '400'];
-        else if (v[2][2] === 'bold') v[2] = [{}, 'number', '700'];
-        return token;
-    }
-};
-
-CSSOCompressor.prototype.compressFont = function(token) {
-    var p = token[2],
-        v = token[3],
-        i, x, t;
-    if (/font$/.test(p[2][2]) && v.length) {
-        v.splice(2, 0, [{}, 's', '']);
-        for (i = v.length - 1; i > 2; i--) {
-            x = v[i];
-            if (x[1] === 'ident') {
-                x = x[2];
-                if (x === 'bold') v[i] = [{}, 'number', '700'];
-                else if (x === 'normal') {
-                    t = v[i - 1];
-                    if (t[1] === 'operator' && t[2] === '/') v.splice(--i, 2);
-                    else v.splice(i, 1);
-                    if (v[i - 1][1] === 's') v.splice(--i, 1);
-                }
-                else if (x === 'medium' && v[i + 1] && v[i + 1][2] !== '/') {
-                    v.splice(i, 1);
-                    if (v[i - 1][1] === 's') v.splice(--i, 1);
-                }
-            }
-        }
-        if (v.length > 2 && v[2][1] === 's') v.splice(2, 1);
-        if (v.length === 2) v.push([{}, 'ident', 'normal']);
-        return token;
-    }
-};
-
-CSSOCompressor.prototype.compressBackground = function(token) {
-    var p = token[2],
-        v = token[3],
-        i, x, t,
-        n = v[v.length - 1][1] === 'important' ? 3 : 2;
-    if (/background$/.test(p[2][2]) && v.length) {
-        v.splice(2, 0, [{}, 's', '']);
-        for (i = v.length - 1; i > n; i--) {
-            x = v[i];
-            if (x[1] === 'ident') {
-                x = x[2];
-                if (x === 'transparent' || x === 'none' || x === 'repeat' || x === 'scroll') {
-                    v.splice(i, 1);
-                    if (v[i - 1][1] === 's') v.splice(--i, 1);
-                }
-            }
-        }
-        if (v.length > 2 && v[2][1] === 's') v.splice(2, 1);
-        if (v.length === 2) v.splice(2, 0, [{}, 'number', '0'], [{}, 's', ' '], [{}, 'number', '0']);
-        return token;
-    }
-};
-
-CSSOCompressor.prototype.cleanEmpty = function(token, rule) {
-    switch(rule) {
-        case 'ruleset':
-            if (token[3].length === 2) return null;
-            break;
-        case 'atruleb':
-            if (token[token.length - 1].length < 3) return null;
-            break;
-        case 'atruler':
-            if (token[4].length < 3) return null;
-            break;
-    }
-};
-
-CSSOCompressor.prototype.destroyDelims = function() {
-    return null;
-};
-
-CSSOCompressor.prototype.preTranslate = function(token) {
-    token[0].s = translator.translate(cleanInfo(token));
-    return token;
-};
-
-CSSOCompressor.prototype.markShorthands = function(token, rule, container, j, path) {
-    if (container[1] === 'ruleset') {
-        var selector = container[2][2][0].s,
-            freeze = container[0].freeze,
-            freezeID = container[0].freezeID;
-    } else {
-        var selector = '',
-            freeze = false,
-            freezeID = 'fake';
-    }
-    var x, p, v, imp, s, key, sh,
-        pre = this.pathUp(path) + '/' + (freeze ? '&' + freezeID + '&' : '') + selector + '/',
-        createNew, shortsI, shortGroupID = container[0].shortGroupID;
-
-    for (var i = token.length - 1; i > -1; i--) {
-        createNew = true;
-        x = token[i];
-        if (x[1] === 'declaration') {
-            v = x[3];
-            imp = v[v.length - 1][1] === 'important';
-            p = x[2][0].s;
-            x[0].id = path + '/' + i;
-            if (p in TRBL.props) {
-                key = pre + TRBL.extractMain(p);
-                var shorts = this.shorts2[key] || [];
-                shortsI = shorts.length === 0 ? 0 : shorts.length - 1;
-
-                if (!this.lastShortSelector || selector === this.lastShortSelector || shortGroupID === this.lastShortGroupID) {
-                    if (shorts.length) {
-                        sh = shorts[shortsI];
-                        //if (imp && !sh.imp) sh.invalid = true;
-                        createNew = false;
-                    }
-                }
-
-                if (createNew) {
-                    x[0].replaceByShort = true;
-                    x[0].shorthandKey = { key: key, i: shortsI };
-                    sh = new TRBL(p, imp);
-                    shorts.push(sh);
-                }
-
-                if (!sh.invalid) {
-                    x[0].removeByShort = true;
-                    x[0].shorthandKey = { key: key, i: shortsI };
-                    sh.add(p, v[0].s, v.slice(2), imp);
-                }
-
-                this.shorts2[key] = shorts;
-
-                this.lastShortSelector = selector;
-                this.lastShortGroupID = shortGroupID;
-            }
-        }
-    }
-
-
-    return token;
-};
-
-CSSOCompressor.prototype.cleanShorthands = function(token) {
-    if (token[0].removeByShort || token[0].replaceByShort) {
-        var s, t, sKey = token[0].shorthandKey;
-
-        s = this.shorts2[sKey.key][sKey.i];
-
-        if (!s.invalid && s.isOkToMinimize()) {
-            if (token[0].replaceByShort) {
-                t = [{}, 'declaration', s.getProperty(), s.getValue()];
-                t[0].s = translator.translate(cleanInfo(t));
-                return t;
-            } else return null;
-        }
-    }
-};
-
-CSSOCompressor.prototype.dontRestructure = {
-    'src': 1, // https://github.com/afelix/csso/issues/50
-    'clip': 1, // https://github.com/afelix/csso/issues/57
-    'display': 1 // https://github.com/afelix/csso/issues/71
-};
-
-CSSOCompressor.prototype.restructureBlock = function(token, rule, container, j, path) {
-    if (container[1] === 'ruleset') {
-        var props = this.props,
-            isPseudo = container[2][2][0].pseudo,
-            selector = container[2][2][0].s,
-            freeze = container[0].freeze,
-            freezeID = container[0].freezeID,
-            pseudoID = container[0].pseudoID,
-            sg = container[2][2][0].sg;
-    } else {
-        var props = {},
-            isPseudo = false,
-            selector = '',
-            freeze = false,
-            freezeID = 'fake',
-            pseudoID = 'fake',
-            sg = {};
-    }
-
-    var x, p, v, imp, t,
-        pre = this.pathUp(path) + '/' + selector + '/',
-        ppre;
-    for (var i = token.length - 1; i > -1; i--) {
-        x = token[i];
-        if (x[1] === 'declaration') {
-            v = x[3];
-            imp = v[v.length - 1][1] === 'important';
-            p = x[2][0].s;
-            ppre = this.buildPPre(pre, p, v, x, freeze);
-            x[0].id = path + '/' + i;
-            if (!this.dontRestructure[p] && (t = props[ppre])) {
-                if ((isPseudo && freezeID === t.freezeID) || // pseudo from equal selectors group
-                    (!isPseudo && pseudoID === t.pseudoID) || // not pseudo from equal pseudo signature group
-                    (isPseudo && pseudoID === t.pseudoID && this.hashInHash(sg, t.sg))) { // pseudo from covered selectors group
-                    if (imp && !t.imp) {
-                        props[ppre] = { block: token, imp: imp, id: x[0].id, sg: sg,
-                                        freeze: freeze, path: path, freezeID: freezeID, pseudoID: pseudoID };
-                        this.deleteProperty(t.block, t.id);
-                    } else {
-                        token.splice(i, 1);
-                    }
-                }
-            } else if (this.needless(p, props, pre, imp, v, x, freeze)) {
-                token.splice(i, 1);
-            } else {
-                props[ppre] = { block: token, imp: imp, id: x[0].id, sg: sg,
-                                freeze: freeze, path: path, freezeID: freezeID, pseudoID: pseudoID };
-            }
-        }
-    }
-    return token;
-};
-
-CSSOCompressor.prototype.buildPPre = function(pre, p, v, d, freeze) {
-    var fp = freeze ? 'ft:' : 'ff:';
-    if (p.indexOf('background') !== -1) return fp + pre + d[0].s;
-
-    var _v = v.slice(2),
-        colorMark = [
-            0, // ident, vhash, rgb
-            0, // hsl
-            0, // hsla
-            0  // rgba
-        ],
-        vID = '';
-
-    for (var i = 0; i < _v.length; i++) {
-        if (!vID) vID = this.getVendorIDFromToken(_v[i]);
-        switch(_v[i][1]) {
-            case 'vhash':
-            case 'ident':
-                colorMark[0] = 1; break;
-            case 'funktion':
-                switch(_v[i][2][2]) {
-                    case 'rgb':
-                        colorMark[0] = 1; break;
-                    case 'hsl':
-                        colorMark[1] = 1; break;
-                    case 'hsla':
-                        colorMark[2] = 1; break;
-                    case 'rgba':
-                        colorMark[3] = 1; break;
-                }
-                break;
-        }
-    }
-
-    return fp + pre + p + colorMark.join('') + (vID ? vID : '');
-};
-
-CSSOCompressor.prototype.vendorID = {
-    '-o-': 'o',
-    '-moz-': 'm',
-    '-webkit-': 'w',
-    '-ms-': 'i',
-    '-epub-': 'e',
-    '-apple-': 'a',
-    '-xv-': 'x',
-    '-wap-': 'p'
-};
-
-CSSOCompressor.prototype.getVendorIDFromToken = function(token) {
-    var vID;
-    switch(token[1]) {
-        case 'ident':
-            if (vID = this.getVendorFromString(token[2])) return this.vendorID[vID];
-            break;
-        case 'funktion':
-            if (vID = this.getVendorFromString(token[2][2])) return this.vendorID[vID];
-            break;
-    }
-};
-
-CSSOCompressor.prototype.getVendorFromString = function(string) {
-    var vendor = string.charAt(0), i;
-    if (vendor === '-') {
-        if ((i = string.indexOf('-', 2)) !== -1) return string.substr(0, i + 1);
-    }
-    return '';
-};
-
-CSSOCompressor.prototype.deleteProperty = function(block, id) {
-    var d;
-    for (var i = block.length - 1; i > 1; i--) {
-        d = block[i];
-        if (Array.isArray(d) && d[1] === 'declaration' && d[0].id === id) {
-            block.splice(i, 1);
-            return;
-        }
-    }
-};
-
-CSSOCompressor.prototype.nlTable = {
-    'border-width': ['border'],
-    'border-style': ['border'],
-    'border-color': ['border'],
-    'border-top': ['border'],
-    'border-right': ['border'],
-    'border-bottom': ['border'],
-    'border-left': ['border'],
-    'border-top-width': ['border-top', 'border-width', 'border'],
-    'border-right-width': ['border-right', 'border-width', 'border'],
-    'border-bottom-width': ['border-bottom', 'border-width', 'border'],
-    'border-left-width': ['border-left', 'border-width', 'border'],
-    'border-top-style': ['border-top', 'border-style', 'border'],
-    'border-right-style': ['border-right', 'border-style', 'border'],
-    'border-bottom-style': ['border-bottom', 'border-style', 'border'],
-    'border-left-style': ['border-left', 'border-style', 'border'],
-    'border-top-color': ['border-top', 'border-color', 'border'],
-    'border-right-color': ['border-right', 'border-color', 'border'],
-    'border-bottom-color': ['border-bottom', 'border-color', 'border'],
-    'border-left-color': ['border-left', 'border-color', 'border'],
-    'margin-top': ['margin'],
-    'margin-right': ['margin'],
-    'margin-bottom': ['margin'],
-    'margin-left': ['margin'],
-    'padding-top': ['padding'],
-    'padding-right': ['padding'],
-    'padding-bottom': ['padding'],
-    'padding-left': ['padding'],
-    'font-style': ['font'],
-    'font-variant': ['font'],
-    'font-weight': ['font'],
-    'font-size': ['font'],
-    'font-family': ['font'],
-    'list-style-type': ['list-style'],
-    'list-style-position': ['list-style'],
-    'list-style-image': ['list-style']
-};
-
-CSSOCompressor.prototype.needless = function(name, props, pre, imp, v, d, freeze) {
-    var hack = name.charAt(0);
-    if (hack === '*' || hack === '_' || hack === '$') name = name.substr(1);
-    else if (hack === '/' && name.charAt(1) === '/') {
-        hack = '//';
-        name = name.substr(2);
-    } else hack = '';
-
-    var vendor = this.getVendorFromString(name),
-        prop = name.substr(vendor.length),
-        x, t, ppre;
-
-    if (prop in this.nlTable) {
-        x = this.nlTable[prop];
-        for (var i = 0; i < x.length; i++) {
-            ppre = this.buildPPre(pre, hack + vendor + x[i], v, d, freeze);
-            if (t = props[ppre]) return (!imp || t.imp);
-        }
-    }
-};
-
-CSSOCompressor.prototype.rejoinRuleset = function(token, rule, container, i) {
-    var p = (i === 2 || container[i - 1][1] === 'unknown') ? null : container[i - 1],
-        ps = p ? p[2].slice(2) : [],
-        pb = p ? p[3].slice(2) : [],
-        ts = token[2].slice(2),
-        tb = token[3].slice(2),
-        ph, th, r;
-
-    if (!tb.length) return null;
-
-    if (ps.length && pb.length && token[0].pseudoSignature == p[0].pseudoSignature) {
-        if (token[1] !== p[1]) return;
-        // try to join by selectors
-        ph = this.getHash(ps);
-        th = this.getHash(ts);
-
-        if (this.equalHash(th, ph)) {
-            p[3] = p[3].concat(token[3].splice(2));
-            return null;
-        }
-        if (this.okToJoinByProperties(token, p)) {
-            // try to join by properties
-            r = this.analyze(token, p);
-            if (!r.ne1.length && !r.ne2.length) {
-                p[2] = this.cleanSelector(p[2].concat(token[2].splice(2)));
-                p[2][0].s = translator.translate(cleanInfo(p[2]));
-                return null;
-            }
-        }
-    }
-};
-
-CSSOCompressor.prototype.okToJoinByProperties = function(r0, r1) {
-    var i0 = r0[0], i1 = r1[0];
-
-    // same frozen ruleset
-    if (i0.freezeID === i1.freezeID) return true;
-
-    // same pseudo-classes in selectors
-    if (i0.pseudoID === i1.pseudoID) return true;
-
-    // different frozen rulesets
-    if (i0.freeze && i1.freeze) {
-        return this.pseudoSelectorSignature(r0[2], this.allowedPClasses) === this.pseudoSelectorSignature(r1[2], this.allowedPClasses);
-    }
-
-    // is it frozen at all?
-    return !(i0.freeze || i1.freeze);
-};
-
-CSSOCompressor.prototype.allowedPClasses = {
-    'after': 1,
-    'before': 1
-};
-
-CSSOCompressor.prototype.containsOnlyAllowedPClasses = function(selector) {
-    var ss;
-    for (var i = 2; i < selector.length; i++) {
-        ss = selector[i];
-        for (var j = 2; j < ss.length; j++) {
-            if (ss[j][1] == 'pseudoc' || ss[j][1] == 'pseudoe') {
-                if (!(ss[j][2][2] in this.allowedPClasses)) return false;
-            }
-        }
-    }
-    return true;
-};
-
-CSSOCompressor.prototype.restructureRuleset = function(token, rule, container, i) {
-    var p = (i === 2 || container[i - 1][1] === 'unknown') ? null : container[i - 1],
-        ps = p ? p[2].slice(2) : [],
-        pb = p ? p[3].slice(2) : [],
-        tb = token[3].slice(2),
-        r, nr;
-
-    if (!tb.length) return null;
-
-    if (ps.length && pb.length && token[0].pseudoSignature == p[0].pseudoSignature) {
-        if (token[1] !== p[1]) return;
-        // try to join by properties
-        r = this.analyze(token, p);
-
-        if (r.eq.length && (r.ne1.length || r.ne2.length)) {
-            if (r.ne1.length && !r.ne2.length) { // p in token
-                var ns = token[2].slice(2), // TODO: copypaste
-                    nss = translator.translate(cleanInfo(token[2])),
-                    sl = nss.length + // selector length
-                         ns.length - 1, // delims length
-                    bl = this.calcLength(r.eq) + // declarations length
-                         r.eq.length - 1; // decldelims length
-                if (sl < bl) {
-                    p[2] = this.cleanSelector(p[2].concat(token[2].slice(2)));
-                    token[3].splice(2);
-                    token[3] = token[3].concat(r.ne1);
-                    return token;
-                }
-            } else if (r.ne2.length && !r.ne1.length) { // token in p
-                var ns = p[2].slice(2),
-                    nss = translator.translate(cleanInfo(p[2])),
-                    sl = nss.length + // selector length
-                         ns.length - 1, // delims length
-                    bl = this.calcLength(r.eq) + // declarations length
-                         r.eq.length - 1; // decldelims length
-                if (sl < bl) {
-                    token[2] = this.cleanSelector(p[2].concat(token[2].slice(2)));
-                    p[3].splice(2);
-                    p[3] = p[3].concat(r.ne2);
-                    return token;
-                }
-            } else { // extract equal block?
-                var ns = this.cleanSelector(p[2].concat(token[2].slice(2))),
-                    nss = translator.translate(cleanInfo(ns)),
-                    rl = nss.length + // selector length
-                         ns.length - 1 + // delims length
-                         2, // braces length
-                    bl = this.calcLength(r.eq) + // declarations length
-                         r.eq.length - 1; // decldelims length
-
-                if (bl >= rl) { // ok, it's good enough to extract
-                    ns[0].s = nss;
-                    nr = [{f:0, l:0}, 'ruleset', ns, [{f:0,l:0}, 'block'].concat(r.eq)];
-                    token[3].splice(2);
-                    token[3] = token[3].concat(r.ne1);
-                    p[3].splice(2);
-                    p[3] = p[3].concat(r.ne2);
-                    container.splice(i, 0, nr);
-                    return nr;
-                }
-            }
-        }
-    }
-};
-
-CSSOCompressor.prototype.calcLength = function(tokens) {
-    var r = 0;
-    for (var i = 0; i < tokens.length; i++) r += tokens[i][0].s.length;
-    return r;
-};
-
-CSSOCompressor.prototype.cleanSelector = function(token) {
-    if (token.length === 2) return null;
-    var h = {}, s;
-    for (var i = 2; i < token.length; i++) {
-        s = token[i][0].s;
-        if (s in h) token.splice(i, 1), i--;
-        else h[s] = 1;
-    }
-
-    return token;
-};
-
-CSSOCompressor.prototype.analyze = function(r1, r2) {
-    var r = { eq: [], ne1: [], ne2: [] };
-
-    if (r1[1] !== r2[1]) return r;
-
-    var b1 = r1[3], b2 = r2[3],
-        d1 = b1.slice(2), d2 = b2.slice(2),
-        h1, h2, i, x;
-
-    h1 = this.getHash(d1);
-    h2 = this.getHash(d2);
-
-    for (i = 0; i < d1.length; i++) {
-        x = d1[i];
-        if (x[0].s in h2) r.eq.push(x);
-        else r.ne1.push(x);
-    }
-
-    for (i = 0; i < d2.length; i++) {
-        x = d2[i];
-        if (!(x[0].s in h1)) r.ne2.push(x);
-    }
-
-    return r;
-};
-
-CSSOCompressor.prototype.equalHash = function(h0, h1) {
-    var k;
-    for (k in h0) if (!(k in h1)) return false;
-    for (k in h1) if (!(k in h0)) return false;
-    return true;
-};
-
-CSSOCompressor.prototype.getHash = function(tokens) {
-    var r = {};
-    for (var i = 0; i < tokens.length; i++) r[tokens[i][0].s] = 1;
-    return r;
-};
-
-CSSOCompressor.prototype.hashInHash = function(h0, h1) {
-    for (var k in h0) if (!(k in h1)) return false;
-    return true;
-};
-
-CSSOCompressor.prototype.delimSelectors = function(token) {
-    for (var i = token.length - 1; i > 2; i--) {
-        token.splice(i, 0, [{}, 'delim']);
-    }
-};
-
-CSSOCompressor.prototype.delimBlocks = function(token) {
-    for (var i = token.length - 1; i > 2; i--) {
-        token.splice(i, 0, [{}, 'decldelim']);
-    }
-};
-
-CSSOCompressor.prototype.copyArray = function(a) {
-    var r = [], t;
-
-    for (var i = 0; i < a.length; i++) {
-        t = a[i];
-        if (Array.isArray(t)) r.push(this.copyArray(t));
-        else if (typeof t === 'object') r.push(this.copyObject(t));
-        else r.push(t);
-    }
-
-    return r;
-};
-
-CSSOCompressor.prototype.copyObject = function(o) {
-    var r = {};
-    for (var k in o) r[k] = o[k];
-    return r;
-};
-
-CSSOCompressor.prototype.pathUp = function(path) {
-    return path.substr(0, path.lastIndexOf('/'));
-};
-function CSSOTranslator() {}
-
-CSSOTranslator.prototype.translate = function(tree) {
-//    console.trace('--------');
-//    console.log(tree);
-    return this._t(tree);
-};
-
-CSSOTranslator.prototype._m_simple = {
-    'unary': 1, 'nth': 1, 'combinator': 1, 'ident': 1, 'number': 1, 's': 1,
-    'string': 1, 'attrselector': 1, 'operator': 1, 'raw': 1, 'unknown': 1
-};
-
-CSSOTranslator.prototype._m_composite = {
-    'simpleselector': 1, 'dimension': 1, 'selector': 1, 'property': 1, 'value': 1,
-    'filterv': 1, 'progid': 1, 'ruleset': 1, 'atruleb': 1, 'atrulerq': 1, 'atrulers': 1,
-    'stylesheet': 1
-};
-
-CSSOTranslator.prototype._m_primitive = {
-    'cdo': 'cdo', 'cdc': 'cdc', 'decldelim': ';', 'namespace': '|', 'delim': ','
-};
-
-CSSOTranslator.prototype._t = function(tree) {
-    var t = tree[0];
-    if (t in this._m_primitive) return this._m_primitive[t];
-    else if (t in this._m_simple) return this._simple(tree);
-    else if (t in this._m_composite) return this._composite(tree);
-    return this[t](tree);
-};
-
-CSSOTranslator.prototype._composite = function(t, i) {
-    var s = '';
-    i = i === undefined ? 1 : i;
-    for (; i < t.length; i++) s += this._t(t[i]);
-    return s;
-};
-
-CSSOTranslator.prototype._simple = function(t) {
-    return t[1];
-};
-
-CSSOTranslator.prototype.percentage = function(t) {
-    return this._t(t[1]) + '%';
-};
-
-CSSOTranslator.prototype.comment = function(t) {
-    return '/*' + t[1] + '*/';
-};
-
-CSSOTranslator.prototype.clazz = function(t) {
-    return '.' + this._t(t[1]);
-};
-
-CSSOTranslator.prototype.atkeyword = function(t) {
-    return '@' + this._t(t[1]);
-};
-
-CSSOTranslator.prototype.shash = function(t) {
-    return '#' + t[1];
-};
-
-CSSOTranslator.prototype.vhash = function(t) {
-    return '#' + t[1];
-};
-
-CSSOTranslator.prototype.attrib = function(t) {
-    return '[' + this._composite(t) + ']';
-};
-
-CSSOTranslator.prototype.important = function(t) {
-    return '!' + this._composite(t) + 'important';
-};
-
-CSSOTranslator.prototype.nthselector = function(t) {
-    return ':' + this._simple(t[1]) + '(' + this._composite(t, 2) + ')';
-};
-
-CSSOTranslator.prototype.funktion = function(t) {
-    return this._simple(t[1]) + '(' + this._composite(t[2]) + ')';
-};
-
-CSSOTranslator.prototype.declaration = function(t) {
-    return this._t(t[1]) + ':' + this._t(t[2]);
-};
-
-CSSOTranslator.prototype.filter = function(t) {
-    return this._t(t[1]) + ':' + this._t(t[2]);
-};
-
-CSSOTranslator.prototype.block = function(t) {
-    return '{' + this._composite(t) + '}';
-};
-
-CSSOTranslator.prototype.braces = function(t) {
-    return t[1] + this._composite(t, 3) + t[2];
-};
-
-CSSOTranslator.prototype.atrules = function(t) {
-    return this._composite(t) + ';';
-};
-
-CSSOTranslator.prototype.atruler = function(t) {
-    return this._t(t[1]) + this._t(t[2]) + '{' + this._t(t[3]) + '}';
-};
-
-CSSOTranslator.prototype.pseudoe = function(t) {
-    return '::' + this._t(t[1]);
-};
-
-CSSOTranslator.prototype.pseudoc = function(t) {
-    return ':' + this._t(t[1]);
-};
-
-CSSOTranslator.prototype.uri = function(t) {
-    return 'url(' + this._composite(t) + ')';
-};
-
-CSSOTranslator.prototype.functionExpression = function(t) {
-    return 'expression(' + t[1] + ')';
-};
index 93697f7..fc3650d 100644 (file)
   }
 })(typeof exports === 'undefined' ? this : exports);
 
-/* global CSSOCompressor: true, CSSOTranslator: true, cleanInfo: true, srcToCSSP: true */
-
 (function(global) {
   'use strict';
 
 
   function minifyCSS(text) {
     try {
-      var csso;
+      var CleanCSS;
 
-      if (typeof require === 'function' && (csso = require('csso'))) {
-        return csso.justDoIt(text);
+      if (typeof require === 'function' && (CleanCSS = require('clean-css'))) {
+        return new CleanCSS().minify(text);
       }
-      else if (typeof CSSOCompressor !== 'undefined' &&
-               typeof CSSOTranslator !== 'undefined') {
-
-        var compressor = new CSSOCompressor(),
-            translator = new CSSOTranslator();
-
-        return translator.translate(cleanInfo(compressor.compress(srcToCSSP(text, 'stylesheet', true))));
+      else if (typeof CleanCSS !== 'undefined') {
+        return new CleanCSS().minify(text);
       }
     }
     catch (err) { }
index 67d2d95..5034342 100644 (file)
@@ -3,4 +3,4 @@
  * Copyright 2010-2014 Juriy "kangax" Zaytsev
  * Licensed under MIT (https://github.com/kangax/html-minifier/blob/gh-pages/LICENSE)
  */
-!function(a){"use strict";function b(a){for(var b={},c=a.split(","),d=0;d<c.length;d++)b[c[d]]=!0,b[c[d].toUpperCase()]=!0;return b}var c,d,e,f=/^<([\w:-]+)((?:\s*[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,g=/^<\/([\w:-]+)[^>]*>/,h=/\/>$/,i=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g,j=/^<!DOCTYPE [^>]+>/i,k=/<(%|\?)/,l=/(%|\?)>/,m=b("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed"),n=b("a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var"),o=b("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),p=b("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected"),q=b("script,style"),r={},s=a.HTMLParser=function(a,b){function s(a,c,d,e){for(var f=!1;!b.html5&&z.last()&&n[z.last()];)t("",z.last());if(o[c]&&z.last()===c&&t("",c),e=m[c]||!!e,e?f=a.match(h):z.push(c),b.start){var g=[];d.replace(i,function(a,b){var c=arguments[2]?arguments[2]:arguments[3]?arguments[3]:arguments[4]?arguments[4]:p[b]?b:"";g.push({name:b,value:c,escaped:c.replace(/(^|[^\\])"/g,"$1&quot;")})}),b.start&&b.start(c,g,e,f)}}function t(a,c){var d;if(c)for(d=z.length-1;d>=0&&z[d]!==c;d--);else d=0;if(d>=0){for(var e=z.length-1;e>=d;e--)b.end&&b.end(z[e]);z.length=d}}var u,v,w,x,y,z=[],A=a;for(z.last=function(){return this[this.length-1]};a;){if(v=!0,z.last()&&q[z.last()])c=z.last().toLowerCase(),d=r[c]||(r[c]=new RegExp("([\\s\\S]*?)</"+c+"[^>]*>","i")),a=a.replace(d,function(a,d){return"script"!==c&&"style"!==c&&(d=d.replace(/<!--([\s\S]*?)-->/g,"$1").replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g,"$1")),b.chars&&b.chars(d),""}),t("",c);else if(0===a.indexOf("<!--")?(u=a.indexOf("-->"),u>=0&&(b.comment&&b.comment(a.substring(4,u)),a=a.substring(u+3),v=!1)):0===a.search(k)?(u=a.search(l),u>=0&&(b.ignore&&b.ignore(a.substring(0,u+2)),a=a.substring(u+2),v=!1)):(w=j.exec(a))?(b.doctype&&b.doctype(w[0]),a=a.substring(w[0].length),v=!1):0===a.indexOf("</")?(w=a.match(g),w&&(a=a.substring(w[0].length),w[0].replace(g,t),x="/"+w[1],v=!1)):0===a.indexOf("<")&&(w=a.match(f),w&&(a=a.substring(w[0].length),w[0].replace(f,s),x=w[1],v=!1)),v){u=a.indexOf("<");var B=0>u?a:a.substring(0,u);a=0>u?"":a.substring(u),e=a.match(f),e?y=e[1]:(e=a.match(g),y=e?"/"+e[1]:""),b.chars&&b.chars(B,x,y)}if(a===A)throw"Parse Error: "+a;A=a}t()};a.HTMLtoXML=function(a){var b="";return new s(a,{start:function(a,c,d){b+="<"+a;for(var e=0;e<c.length;e++)b+=" "+c[e].name+'="'+c[e].escaped+'"';b+=(d?"/":"")+">"},end:function(a){b+="</"+a+">"},chars:function(a){b+=a},comment:function(a){b+="<!--"+a+"-->"},ignore:function(a){b+=a}}),b},a.HTMLtoDOM=function(a,c){var d=b("html,head,body,title"),e={link:"head",base:"head"};c?c=c.ownerDocument||c.getOwnerDocument&&c.getOwnerDocument()||c:"undefined"!=typeof DOMDocument?c=new DOMDocument:"undefined"!=typeof document&&document.implementation&&document.implementation.createDocument?c=document.implementation.createDocument("","",null):"undefined"!=typeof ActiveX&&(c=new ActiveXObject("Msxml.DOMDocument"));var f=[],g=c.documentElement||c.getDocumentElement&&c.getDocumentElement();if(!g&&c.createElement&&!function(){var a=c.createElement("html"),b=c.createElement("head");b.appendChild(c.createElement("title")),a.appendChild(b),a.appendChild(c.createElement("body")),c.appendChild(a)}(),c.getElementsByTagName)for(var h in d)d[h]=c.getElementsByTagName(h)[0];var i=d.body;return new s(a,{start:function(a,b,g){if(d[a])return void(i=d[a]);var h=c.createElement(a);for(var j in b)h.setAttribute(b[j].name,b[j].value);e[a]&&"boolean"!=typeof d[e[a]]?d[e[a]].appendChild(h):i&&i.appendChild&&i.appendChild(h),g||(f.push(h),i=h)},end:function(){f.length-=1,i=f[f.length-1]},chars:function(a){i.appendChild(c.createTextNode(a))},comment:function(){},ignore:function(){}}),c}}("undefined"==typeof exports?this:exports),function(a){"use strict";function b(a){return a.replace(/\s+/g," ")}function c(a,b,c){var d=["a","abbr","acronym","b","bdi","bdo","big","button","cite","code","del","dfn","em","font","i","ins","kbd","mark","q","rt","rp","s","samp","small","span","strike","strong","sub","sup","time","tt","u","var"];return b&&"img"!==b&&("/"!==b.substr(0,1)||"/"===b.substr(0,1)&&-1===d.indexOf(b.substr(1)))&&(a=a.replace(/^\s+/,"")),c&&"img"!==c&&("/"===c.substr(0,1)||"/"!==c.substr(0,1)&&-1===d.indexOf(c))&&(a=a.replace(/\s+$/,"")),b&&c?a.replace(/[\t\n\r]+/g," ").replace(/[ ]+/g," "):a}function d(a){return/\[if[^\]]+\]/.test(a)||/\s*(<!\[endif\])$/.test(a)}function e(a){return/^!/.test(a)}function f(a){return/^on[a-z]+/.test(a)}function g(a){return/^[^\x20\t\n\f\r"'`=<>]+$/.test(a)&&!/\/$/.test(a)&&!/\/$/.test(a)}function h(a,b){for(var c=a.length;c--;)if(a[c].name.toLowerCase()===b)return!0;return!1}function i(a,b,c,d){return c=E(c.toLowerCase()),"script"===a&&"language"===b&&"javascript"===c||"form"===a&&"method"===b&&"get"===c||"input"===a&&"type"===b&&"text"===c||"script"===a&&"charset"===b&&!h(d,"src")||"a"===a&&"name"===b&&h(d,"id")||"area"===a&&"shape"===b&&"rect"===c}function j(a,b,c){return"script"===a&&"type"===b&&"text/javascript"===E(c.toLowerCase())}function k(a,b,c){return("style"===a||"link"===a)&&"type"===b&&"text/css"===E(c.toLowerCase())}function l(a){return/^(?:allowfullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultchecked|defaultmuted|defaultselected|defer|disabled|draggable|enabled|formnovalidate|hidden|indeterminate|inert|ismap|itemscope|loop|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|pauseonexit|readonly|required|reversed|scoped|seamless|selected|sortable|spellcheck|translate|truespeed|typemustmatch|visible)$/.test(a)}function m(a,b){return/^(?:a|area|link|base)$/.test(b)&&"href"===a||"img"===b&&/^(?:src|longdesc|usemap)$/.test(a)||"object"===b&&/^(?:classid|codebase|data|usemap)$/.test(a)||"q"===b&&"cite"===a||"blockquote"===b&&"cite"===a||("ins"===b||"del"===b)&&"cite"===a||"form"===b&&"action"===a||"input"===b&&("src"===a||"usemap"===a)||"head"===b&&"profile"===a||"script"===b&&("src"===a||"for"===a)}function n(a,b){return/^(?:a|area|object|button)$/.test(b)&&"tabindex"===a||"input"===b&&("maxlength"===a||"tabindex"===a)||"select"===b&&("size"===a||"tabindex"===a)||"textarea"===b&&/^(?:rows|cols|tabindex)$/.test(a)||"colgroup"===b&&"span"===a||"col"===b&&"span"===a||("th"===b||"td"===b)&&("rowspan"===a||"colspan"===a)}function o(a,c,d){return f(c)?E(d).replace(/^javascript:\s*/i,"").replace(/\s*;$/,""):"class"===c?b(E(d)):m(c,a)||n(c,a)?E(d):"style"===c?E(d).replace(/\s*;\s*$/,""):d}function p(a){return a.replace(/^(\[[^\]]+\]>)\s*/,"$1").replace(/\s*(<!\[endif\])$/,"$1")}function q(a){return a.replace(/^(?:\s*\/\*\s*<!\[CDATA\[\s*\*\/|\s*\/\/\s*<!\[CDATA\[.*)/,"").replace(/(?:\/\*\s*\]\]>\s*\*\/|\/\/\s*\]\]>)\s*$/,"")}function r(a,b){return a.replace(F[b],"").replace(G[b],"")}function s(a){return/^(?:html|t?body|t?head|tfoot|tr|td|th|dt|dd|option|colgroup|source)$/.test(a)}function t(a,b,c){var d=/^(["'])?\s*\1$/.test(c);return d?"input"===a&&"value"===b||H.test(b):!1}function u(a){return"textarea"!==a}function v(a){return!/^(?:script|style|pre|textarea)$/.test(a)}function w(a){return!/^(?:pre|textarea)$/.test(a)}function x(a,b,c,d){var e,f=d.caseSensitive?a.name:a.name.toLowerCase(),h=a.escaped;return d.removeRedundantAttributes&&i(c,f,h,b)||d.removeScriptTypeAttributes&&j(c,f,h)||d.removeStyleLinkTypeAttributes&&k(c,f,h)?"":(h=o(c,f,h),d.removeAttributeQuotes&&g(h)||(h='"'+h+'"'),d.removeEmptyAttributes&&t(c,f,h)?"":(e=d.collapseBooleanAttributes&&l(f)?f:f+"="+h," "+e))}function y(a){for(var b=["canCollapseWhitespace","canTrimWhitespace"],c=0,d=b.length;d>c;c++)a[b[c]]||(a[b[c]]=function(){return!1})}function z(b){try{var c=a.UglifyJS;if("undefined"==typeof c&&"function"==typeof require&&(c=require("uglify-js")),!c)return b;if(c.minify)return c.minify(b,{fromString:!0}).code;if(c.parse){var d=c.parse(b);d.figure_out_scope();var e=c.Compressor(),f=d.transform(e);f.figure_out_scope(),f.compute_char_frequency(),f.mangle_names();var g=c.OutputStream();return f.print(g),g.toString()}return b}catch(h){return console.log(h),b}}function A(a){try{var b;if("function"==typeof require&&(b=require("csso")))return b.justDoIt(a);if("undefined"!=typeof CSSOCompressor&&"undefined"!=typeof CSSOTranslator){var c=new CSSOCompressor,d=new CSSOTranslator;return d.translate(cleanInfo(c.compress(srcToCSSP(a,"stylesheet",!0))))}}catch(e){}return a}function B(a,f){function g(a,b){return v(a)||f.canCollapseWhitespace(a,b)}function h(a,b){return w(a)||f.canTrimWhitespace(a,b)}f=f||{},a=E(a),y(f);var i=[],j=[],k="",l="",m=[],n=[],o=[],t=f.lint,B=new Date;new D(a,{html5:"undefined"!=typeof f.html5?f.html5:!0,start:function(a,b,c,d){a=a.toLowerCase(),l=a,k="",m=b,f.collapseWhitespace&&(h(a,b)||n.push(a),g(a,b)||o.push(a)),j.push("<",a),t&&t.testElement(a);for(var e=0,i=b.length;i>e;e++)t&&t.testAttribute(a,b[e].name.toLowerCase(),b[e].escaped),j.push(x(b[e],b,a,f));j.push((d&&f.keepClosingSlash?"/":"")+">")},end:function(a){f.collapseWhitespace&&(n.length&&a===n[n.length-1]&&n.pop(),o.length&&a===o[o.length-1]&&o.pop());var b=""===k&&a===l;return f.removeEmptyElements&&b&&u(a)?void j.splice(j.lastIndexOf("<")):void(f.removeOptionalTags&&s(a)||(j.push("</",a.toLowerCase(),">"),i.push.apply(i,j),j.length=0,k=""))},chars:function(a,d,e){("script"===l||"style"===l)&&(f.removeCommentsFromCDATA&&(a=r(a,l)),f.removeCDATASectionsFromCDATA&&(a=q(a))),"script"===l&&f.minifyJS&&(a=z(a)),"style"===l&&f.minifyCSS&&(a=A(a)),f.collapseWhitespace&&(n.length||(a=d||e?c(a,d,e):E(a)),o.length||(a=b(a))),k=a,t&&t.testChars(a),j.push(a)},comment:function(a){a=f.removeComments?d(a)?"<!--"+p(a)+"-->":e(a)?"<!--"+a+"-->":"":"<!--"+a+"-->",j.push(a)},ignore:function(a){j.push(f.removeIgnored?"":a)},doctype:function(a){j.push(f.useShortDoctype?"<!DOCTYPE html>":b(a))}}),i.push.apply(i,j);var F=i.join("");return C("minified in: "+(new Date-B)+"ms"),F}var C,D;C=a.console&&a.console.log?function(b){a.console.log(b)}:function(){},a.HTMLParser?D=a.HTMLParser:"function"==typeof require&&(D=require("./htmlparser").HTMLParser);var E=function(a){return a.replace(/^\s+/,"").replace(/\s+$/,"")};String.prototype.trim&&(E=function(a){return a.trim()});var F={script:/^\s*(?:\/\/)?\s*<!--.*\n?/,style:/^\s*<!--\s*/},G={script:/\s*(?:\/\/)?\s*-->\s*$/,style:/\s*-->\s*$/},H=new RegExp("^(?:class|id|style|title|lang|dir|on(?:focus|blur|change|click|dblclick|mouse(?:down|up|over|move|out)|key(?:press|down|up)))$");"undefined"!=typeof exports?exports.minify=B:a.minify=B}(this),function(a){"use strict";function b(a){return/^(?:b|i|big|small|hr|blink|marquee)$/.test(a)}function c(a){return/^(?:applet|basefont|center|dir|font|isindex|s|strike|u)$/.test(a)}function d(a){return/^on[a-z]+/.test(a)}function e(a){return"style"===a.toLowerCase()}function f(a,b){return"align"===b&&/^(?:caption|applet|iframe|img|imput|object|legend|table|hr|div|h[1-6]|p)$/.test(a)||"alink"===b&&"body"===a||"alt"===b&&"applet"===a||"archive"===b&&"applet"===a||"background"===b&&"body"===a||"bgcolor"===b&&/^(?:table|t[rdh]|body)$/.test(a)||"border"===b&&/^(?:img|object)$/.test(a)||"clear"===b&&"br"===a||"code"===b&&"applet"===a||"codebase"===b&&"applet"===a||"color"===b&&/^(?:base(?:font)?)$/.test(a)||"compact"===b&&/^(?:dir|[dou]l|menu)$/.test(a)||"face"===b&&/^base(?:font)?$/.test(a)||"height"===b&&/^(?:t[dh]|applet)$/.test(a)||"hspace"===b&&/^(?:applet|img|object)$/.test(a)||"language"===b&&"script"===a||"link"===b&&"body"===a||"name"===b&&"applet"===a||"noshade"===b&&"hr"===a||"nowrap"===b&&/^t[dh]$/.test(a)||"object"===b&&"applet"===a||"prompt"===b&&"isindex"===a||"size"===b&&/^(?:hr|font|basefont)$/.test(a)||"start"===b&&"ol"===a||"text"===b&&"body"===a||"type"===b&&/^(?:li|ol|ul)$/.test(a)||"value"===b&&"li"===a||"version"===b&&"html"===a||"vlink"===b&&"body"===a||"vspace"===b&&/^(?:applet|img|object)$/.test(a)||"width"===b&&/^(?:hr|td|th|applet|pre)$/.test(a)}function g(a,b){return"href"===a&&/^\s*javascript\s*:\s*void\s*(\s+0|\(\s*0\s*\))\s*$/i.test(b)}function h(){this.log=[],this._lastElement=null,this._isElementRepeated=!1}h.prototype.testElement=function(a){c(a)?this.log.push('Found <span class="deprecated-element">deprecated</span> <strong><code>&lt;'+a+"&gt;</code></strong> element"):b(a)?this.log.push('Found <span class="presentational-element">presentational</span> <strong><code>&lt;'+a+"&gt;</code></strong> element"):this.checkRepeatingElement(a)},h.prototype.checkRepeatingElement=function(a){"br"===a&&"br"===this._lastElement?this._isElementRepeated=!0:this._isElementRepeated&&(this._reportRepeatingElement(),this._isElementRepeated=!1),this._lastElement=a},h.prototype._reportRepeatingElement=function(){this.log.push("Found <code>&lt;br></code> sequence. Try replacing it with styling.")},h.prototype.testAttribute=function(a,b,c){d(b)?this.log.push('Found <span class="event-attribute">event attribute</span> (<strong>'+b+"</strong>) on <strong><code>&lt;"+a+"&gt;</code></strong> element."):f(a,b)?this.log.push('Found <span class="deprecated-attribute">deprecated</span> <strong>'+b+"</strong> attribute on <strong><code>&lt;"+a+"&gt;</code></strong> element."):e(b)?this.log.push('Found <span class="style-attribute">style attribute</span> on <strong><code>&lt;'+a+"&gt;</code></strong> element."):g(b,c)&&this.log.push('Found <span class="inaccessible-attribute">inaccessible attribute</span> (on <strong><code>&lt;'+a+"&gt;</code></strong> element).")},h.prototype.testChars=function(a){this._lastElement="",/(&nbsp;\s*){2,}/.test(a)&&this.log.push("Found repeating <strong><code>&amp;nbsp;</code></strong> sequence. Try replacing it with styling.")},h.prototype.test=function(a,b,c){this.testElement(a),this.testAttribute(a,b,c)},h.prototype.populate=function(a){if(this._isElementRepeated&&this._reportRepeatingElement(),this.log.length)if(a)a.innerHTML="<ol><li>"+this.log.join("<li>")+"</ol>";else{var b=" - "+this.log.join("\n - ").replace(/(<([^>]+)>)/gi,"").replace(/&lt;/g,"<").replace(/&gt;/g,">");console.log(b)}},a.HTMLLint=h}("undefined"==typeof exports?this:exports);
\ No newline at end of file
+!function(a){"use strict";function b(a){for(var b={},c=a.split(","),d=0;d<c.length;d++)b[c[d]]=!0,b[c[d].toUpperCase()]=!0;return b}var c,d,e,f=/^<([\w:-]+)((?:\s*[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,g=/^<\/([\w:-]+)[^>]*>/,h=/\/>$/,i=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g,j=/^<!DOCTYPE [^>]+>/i,k=/<(%|\?)/,l=/(%|\?)>/,m=b("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed"),n=b("a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var"),o=b("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),p=b("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected"),q=b("script,style"),r={},s=a.HTMLParser=function(a,b){function s(a,c,d,e){for(var f=!1;!b.html5&&z.last()&&n[z.last()];)t("",z.last());if(o[c]&&z.last()===c&&t("",c),e=m[c]||!!e,e?f=a.match(h):z.push(c),b.start){var g=[];d.replace(i,function(a,b){var c=arguments[2]?arguments[2]:arguments[3]?arguments[3]:arguments[4]?arguments[4]:p[b]?b:"";g.push({name:b,value:c,escaped:c.replace(/(^|[^\\])"/g,"$1&quot;")})}),b.start&&b.start(c,g,e,f)}}function t(a,c){var d;if(c)for(d=z.length-1;d>=0&&z[d]!==c;d--);else d=0;if(d>=0){for(var e=z.length-1;e>=d;e--)b.end&&b.end(z[e]);z.length=d}}var u,v,w,x,y,z=[],A=a;for(z.last=function(){return this[this.length-1]};a;){if(v=!0,z.last()&&q[z.last()])c=z.last().toLowerCase(),d=r[c]||(r[c]=new RegExp("([\\s\\S]*?)</"+c+"[^>]*>","i")),a=a.replace(d,function(a,d){return"script"!==c&&"style"!==c&&(d=d.replace(/<!--([\s\S]*?)-->/g,"$1").replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g,"$1")),b.chars&&b.chars(d),""}),t("",c);else if(0===a.indexOf("<!--")?(u=a.indexOf("-->"),u>=0&&(b.comment&&b.comment(a.substring(4,u)),a=a.substring(u+3),v=!1)):0===a.search(k)?(u=a.search(l),u>=0&&(b.ignore&&b.ignore(a.substring(0,u+2)),a=a.substring(u+2),v=!1)):(w=j.exec(a))?(b.doctype&&b.doctype(w[0]),a=a.substring(w[0].length),v=!1):0===a.indexOf("</")?(w=a.match(g),w&&(a=a.substring(w[0].length),w[0].replace(g,t),x="/"+w[1],v=!1)):0===a.indexOf("<")&&(w=a.match(f),w&&(a=a.substring(w[0].length),w[0].replace(f,s),x=w[1],v=!1)),v){u=a.indexOf("<");var B=0>u?a:a.substring(0,u);a=0>u?"":a.substring(u),e=a.match(f),e?y=e[1]:(e=a.match(g),y=e?"/"+e[1]:""),b.chars&&b.chars(B,x,y)}if(a===A)throw"Parse Error: "+a;A=a}t()};a.HTMLtoXML=function(a){var b="";return new s(a,{start:function(a,c,d){b+="<"+a;for(var e=0;e<c.length;e++)b+=" "+c[e].name+'="'+c[e].escaped+'"';b+=(d?"/":"")+">"},end:function(a){b+="</"+a+">"},chars:function(a){b+=a},comment:function(a){b+="<!--"+a+"-->"},ignore:function(a){b+=a}}),b},a.HTMLtoDOM=function(a,c){var d=b("html,head,body,title"),e={link:"head",base:"head"};c?c=c.ownerDocument||c.getOwnerDocument&&c.getOwnerDocument()||c:"undefined"!=typeof DOMDocument?c=new DOMDocument:"undefined"!=typeof document&&document.implementation&&document.implementation.createDocument?c=document.implementation.createDocument("","",null):"undefined"!=typeof ActiveX&&(c=new ActiveXObject("Msxml.DOMDocument"));var f=[],g=c.documentElement||c.getDocumentElement&&c.getDocumentElement();if(!g&&c.createElement&&!function(){var a=c.createElement("html"),b=c.createElement("head");b.appendChild(c.createElement("title")),a.appendChild(b),a.appendChild(c.createElement("body")),c.appendChild(a)}(),c.getElementsByTagName)for(var h in d)d[h]=c.getElementsByTagName(h)[0];var i=d.body;return new s(a,{start:function(a,b,g){if(d[a])return void(i=d[a]);var h=c.createElement(a);for(var j in b)h.setAttribute(b[j].name,b[j].value);e[a]&&"boolean"!=typeof d[e[a]]?d[e[a]].appendChild(h):i&&i.appendChild&&i.appendChild(h),g||(f.push(h),i=h)},end:function(){f.length-=1,i=f[f.length-1]},chars:function(a){i.appendChild(c.createTextNode(a))},comment:function(){},ignore:function(){}}),c}}("undefined"==typeof exports?this:exports),function(a){"use strict";function b(a){return a.replace(/\s+/g," ")}function c(a,b,c){var d=["a","abbr","acronym","b","bdi","bdo","big","button","cite","code","del","dfn","em","font","i","ins","kbd","mark","q","rt","rp","s","samp","small","span","strike","strong","sub","sup","time","tt","u","var"];return b&&"img"!==b&&("/"!==b.substr(0,1)||"/"===b.substr(0,1)&&-1===d.indexOf(b.substr(1)))&&(a=a.replace(/^\s+/,"")),c&&"img"!==c&&("/"===c.substr(0,1)||"/"!==c.substr(0,1)&&-1===d.indexOf(c))&&(a=a.replace(/\s+$/,"")),b&&c?a.replace(/[\t\n\r]+/g," ").replace(/[ ]+/g," "):a}function d(a){return/\[if[^\]]+\]/.test(a)||/\s*(<!\[endif\])$/.test(a)}function e(a){return/^!/.test(a)}function f(a){return/^on[a-z]+/.test(a)}function g(a){return/^[^\x20\t\n\f\r"'`=<>]+$/.test(a)&&!/\/$/.test(a)&&!/\/$/.test(a)}function h(a,b){for(var c=a.length;c--;)if(a[c].name.toLowerCase()===b)return!0;return!1}function i(a,b,c,d){return c=E(c.toLowerCase()),"script"===a&&"language"===b&&"javascript"===c||"form"===a&&"method"===b&&"get"===c||"input"===a&&"type"===b&&"text"===c||"script"===a&&"charset"===b&&!h(d,"src")||"a"===a&&"name"===b&&h(d,"id")||"area"===a&&"shape"===b&&"rect"===c}function j(a,b,c){return"script"===a&&"type"===b&&"text/javascript"===E(c.toLowerCase())}function k(a,b,c){return("style"===a||"link"===a)&&"type"===b&&"text/css"===E(c.toLowerCase())}function l(a){return/^(?:allowfullscreen|async|autofocus|autoplay|checked|compact|controls|declare|default|defaultchecked|defaultmuted|defaultselected|defer|disabled|draggable|enabled|formnovalidate|hidden|indeterminate|inert|ismap|itemscope|loop|multiple|muted|nohref|noresize|noshade|novalidate|nowrap|open|pauseonexit|readonly|required|reversed|scoped|seamless|selected|sortable|spellcheck|translate|truespeed|typemustmatch|visible)$/.test(a)}function m(a,b){return/^(?:a|area|link|base)$/.test(b)&&"href"===a||"img"===b&&/^(?:src|longdesc|usemap)$/.test(a)||"object"===b&&/^(?:classid|codebase|data|usemap)$/.test(a)||"q"===b&&"cite"===a||"blockquote"===b&&"cite"===a||("ins"===b||"del"===b)&&"cite"===a||"form"===b&&"action"===a||"input"===b&&("src"===a||"usemap"===a)||"head"===b&&"profile"===a||"script"===b&&("src"===a||"for"===a)}function n(a,b){return/^(?:a|area|object|button)$/.test(b)&&"tabindex"===a||"input"===b&&("maxlength"===a||"tabindex"===a)||"select"===b&&("size"===a||"tabindex"===a)||"textarea"===b&&/^(?:rows|cols|tabindex)$/.test(a)||"colgroup"===b&&"span"===a||"col"===b&&"span"===a||("th"===b||"td"===b)&&("rowspan"===a||"colspan"===a)}function o(a,c,d){return f(c)?E(d).replace(/^javascript:\s*/i,"").replace(/\s*;$/,""):"class"===c?b(E(d)):m(c,a)||n(c,a)?E(d):"style"===c?E(d).replace(/\s*;\s*$/,""):d}function p(a){return a.replace(/^(\[[^\]]+\]>)\s*/,"$1").replace(/\s*(<!\[endif\])$/,"$1")}function q(a){return a.replace(/^(?:\s*\/\*\s*<!\[CDATA\[\s*\*\/|\s*\/\/\s*<!\[CDATA\[.*)/,"").replace(/(?:\/\*\s*\]\]>\s*\*\/|\/\/\s*\]\]>)\s*$/,"")}function r(a,b){return a.replace(F[b],"").replace(G[b],"")}function s(a){return/^(?:html|t?body|t?head|tfoot|tr|td|th|dt|dd|option|colgroup|source)$/.test(a)}function t(a,b,c){var d=/^(["'])?\s*\1$/.test(c);return d?"input"===a&&"value"===b||H.test(b):!1}function u(a){return"textarea"!==a}function v(a){return!/^(?:script|style|pre|textarea)$/.test(a)}function w(a){return!/^(?:pre|textarea)$/.test(a)}function x(a,b,c,d){var e,f=d.caseSensitive?a.name:a.name.toLowerCase(),h=a.escaped;return d.removeRedundantAttributes&&i(c,f,h,b)||d.removeScriptTypeAttributes&&j(c,f,h)||d.removeStyleLinkTypeAttributes&&k(c,f,h)?"":(h=o(c,f,h),d.removeAttributeQuotes&&g(h)||(h='"'+h+'"'),d.removeEmptyAttributes&&t(c,f,h)?"":(e=d.collapseBooleanAttributes&&l(f)?f:f+"="+h," "+e))}function y(a){for(var b=["canCollapseWhitespace","canTrimWhitespace"],c=0,d=b.length;d>c;c++)a[b[c]]||(a[b[c]]=function(){return!1})}function z(b){try{var c=a.UglifyJS;if("undefined"==typeof c&&"function"==typeof require&&(c=require("uglify-js")),!c)return b;if(c.minify)return c.minify(b,{fromString:!0}).code;if(c.parse){var d=c.parse(b);d.figure_out_scope();var e=c.Compressor(),f=d.transform(e);f.figure_out_scope(),f.compute_char_frequency(),f.mangle_names();var g=c.OutputStream();return f.print(g),g.toString()}return b}catch(h){return console.log(h),b}}function A(a){try{var b;if("function"==typeof require&&(b=require("clean-css")))return(new b).minify(a);if("undefined"!=typeof b)return(new b).minify(a)}catch(c){}return a}function B(a,f){function g(a,b){return v(a)||f.canCollapseWhitespace(a,b)}function h(a,b){return w(a)||f.canTrimWhitespace(a,b)}f=f||{},a=E(a),y(f);var i=[],j=[],k="",l="",m=[],n=[],o=[],t=f.lint,B=new Date;new D(a,{html5:"undefined"!=typeof f.html5?f.html5:!0,start:function(a,b,c,d){a=a.toLowerCase(),l=a,k="",m=b,f.collapseWhitespace&&(h(a,b)||n.push(a),g(a,b)||o.push(a)),j.push("<",a),t&&t.testElement(a);for(var e=0,i=b.length;i>e;e++)t&&t.testAttribute(a,b[e].name.toLowerCase(),b[e].escaped),j.push(x(b[e],b,a,f));j.push((d&&f.keepClosingSlash?"/":"")+">")},end:function(a){f.collapseWhitespace&&(n.length&&a===n[n.length-1]&&n.pop(),o.length&&a===o[o.length-1]&&o.pop());var b=""===k&&a===l;return f.removeEmptyElements&&b&&u(a)?void j.splice(j.lastIndexOf("<")):void(f.removeOptionalTags&&s(a)||(j.push("</",a.toLowerCase(),">"),i.push.apply(i,j),j.length=0,k=""))},chars:function(a,d,e){("script"===l||"style"===l)&&(f.removeCommentsFromCDATA&&(a=r(a,l)),f.removeCDATASectionsFromCDATA&&(a=q(a))),"script"===l&&f.minifyJS&&(a=z(a)),"style"===l&&f.minifyCSS&&(a=A(a)),f.collapseWhitespace&&(n.length||(a=d||e?c(a,d,e):E(a)),o.length||(a=b(a))),k=a,t&&t.testChars(a),j.push(a)},comment:function(a){a=f.removeComments?d(a)?"<!--"+p(a)+"-->":e(a)?"<!--"+a+"-->":"":"<!--"+a+"-->",j.push(a)},ignore:function(a){j.push(f.removeIgnored?"":a)},doctype:function(a){j.push(f.useShortDoctype?"<!DOCTYPE html>":b(a))}}),i.push.apply(i,j);var F=i.join("");return C("minified in: "+(new Date-B)+"ms"),F}var C,D;C=a.console&&a.console.log?function(b){a.console.log(b)}:function(){},a.HTMLParser?D=a.HTMLParser:"function"==typeof require&&(D=require("./htmlparser").HTMLParser);var E=function(a){return a.replace(/^\s+/,"").replace(/\s+$/,"")};String.prototype.trim&&(E=function(a){return a.trim()});var F={script:/^\s*(?:\/\/)?\s*<!--.*\n?/,style:/^\s*<!--\s*/},G={script:/\s*(?:\/\/)?\s*-->\s*$/,style:/\s*-->\s*$/},H=new RegExp("^(?:class|id|style|title|lang|dir|on(?:focus|blur|change|click|dblclick|mouse(?:down|up|over|move|out)|key(?:press|down|up)))$");"undefined"!=typeof exports?exports.minify=B:a.minify=B}(this),function(a){"use strict";function b(a){return/^(?:b|i|big|small|hr|blink|marquee)$/.test(a)}function c(a){return/^(?:applet|basefont|center|dir|font|isindex|s|strike|u)$/.test(a)}function d(a){return/^on[a-z]+/.test(a)}function e(a){return"style"===a.toLowerCase()}function f(a,b){return"align"===b&&/^(?:caption|applet|iframe|img|imput|object|legend|table|hr|div|h[1-6]|p)$/.test(a)||"alink"===b&&"body"===a||"alt"===b&&"applet"===a||"archive"===b&&"applet"===a||"background"===b&&"body"===a||"bgcolor"===b&&/^(?:table|t[rdh]|body)$/.test(a)||"border"===b&&/^(?:img|object)$/.test(a)||"clear"===b&&"br"===a||"code"===b&&"applet"===a||"codebase"===b&&"applet"===a||"color"===b&&/^(?:base(?:font)?)$/.test(a)||"compact"===b&&/^(?:dir|[dou]l|menu)$/.test(a)||"face"===b&&/^base(?:font)?$/.test(a)||"height"===b&&/^(?:t[dh]|applet)$/.test(a)||"hspace"===b&&/^(?:applet|img|object)$/.test(a)||"language"===b&&"script"===a||"link"===b&&"body"===a||"name"===b&&"applet"===a||"noshade"===b&&"hr"===a||"nowrap"===b&&/^t[dh]$/.test(a)||"object"===b&&"applet"===a||"prompt"===b&&"isindex"===a||"size"===b&&/^(?:hr|font|basefont)$/.test(a)||"start"===b&&"ol"===a||"text"===b&&"body"===a||"type"===b&&/^(?:li|ol|ul)$/.test(a)||"value"===b&&"li"===a||"version"===b&&"html"===a||"vlink"===b&&"body"===a||"vspace"===b&&/^(?:applet|img|object)$/.test(a)||"width"===b&&/^(?:hr|td|th|applet|pre)$/.test(a)}function g(a,b){return"href"===a&&/^\s*javascript\s*:\s*void\s*(\s+0|\(\s*0\s*\))\s*$/i.test(b)}function h(){this.log=[],this._lastElement=null,this._isElementRepeated=!1}h.prototype.testElement=function(a){c(a)?this.log.push('Found <span class="deprecated-element">deprecated</span> <strong><code>&lt;'+a+"&gt;</code></strong> element"):b(a)?this.log.push('Found <span class="presentational-element">presentational</span> <strong><code>&lt;'+a+"&gt;</code></strong> element"):this.checkRepeatingElement(a)},h.prototype.checkRepeatingElement=function(a){"br"===a&&"br"===this._lastElement?this._isElementRepeated=!0:this._isElementRepeated&&(this._reportRepeatingElement(),this._isElementRepeated=!1),this._lastElement=a},h.prototype._reportRepeatingElement=function(){this.log.push("Found <code>&lt;br></code> sequence. Try replacing it with styling.")},h.prototype.testAttribute=function(a,b,c){d(b)?this.log.push('Found <span class="event-attribute">event attribute</span> (<strong>'+b+"</strong>) on <strong><code>&lt;"+a+"&gt;</code></strong> element."):f(a,b)?this.log.push('Found <span class="deprecated-attribute">deprecated</span> <strong>'+b+"</strong> attribute on <strong><code>&lt;"+a+"&gt;</code></strong> element."):e(b)?this.log.push('Found <span class="style-attribute">style attribute</span> on <strong><code>&lt;'+a+"&gt;</code></strong> element."):g(b,c)&&this.log.push('Found <span class="inaccessible-attribute">inaccessible attribute</span> (on <strong><code>&lt;'+a+"&gt;</code></strong> element).")},h.prototype.testChars=function(a){this._lastElement="",/(&nbsp;\s*){2,}/.test(a)&&this.log.push("Found repeating <strong><code>&amp;nbsp;</code></strong> sequence. Try replacing it with styling.")},h.prototype.test=function(a,b,c){this.testElement(a),this.testAttribute(a,b,c)},h.prototype.populate=function(a){if(this._isElementRepeated&&this._reportRepeatingElement(),this.log.length)if(a)a.innerHTML="<ol><li>"+this.log.join("<li>")+"</ol>";else{var b=" - "+this.log.join("\n - ").replace(/(<([^>]+)>)/gi,"").replace(/&lt;/g,"<").replace(/&gt;/g,">");console.log(b)}},a.HTMLLint=h}("undefined"==typeof exports?this:exports);
\ No newline at end of file
index 52a97b7..1f60d06 100644 (file)
       </p>
     </div>
     <script src="uglify.js"></script>
-    <script src="csso.js"></script>
+    <script src="cleancss-browser.js"></script>
     <script src="dist/htmlminifier.min.js"></script>
     <script src="master.js"></script>
   </body>
index 82852b8..f3558b7 100644 (file)
@@ -37,7 +37,7 @@
     "test": "grunt test"
   },
   "dependencies": {
-    "csso": "1.3.x",
+    "clean-css": "2.1.x",
     "uglify-js": "2.4.x"
   },
   "devDependencies": {
index 78fa4a1..8993e68 100644 (file)
@@ -1,5 +1,3 @@
-/* global CSSOCompressor: true, CSSOTranslator: true, cleanInfo: true, srcToCSSP: true */
-
 (function(global) {
   'use strict';
 
 
   function minifyCSS(text) {
     try {
-      var csso;
+      var CleanCSS;
 
-      if (typeof require === 'function' && (csso = require('csso'))) {
-        return csso.justDoIt(text);
+      if (typeof require === 'function' && (CleanCSS = require('clean-css'))) {
+        return new CleanCSS().minify(text);
       }
-      else if (typeof CSSOCompressor !== 'undefined' &&
-               typeof CSSOTranslator !== 'undefined') {
-
-        var compressor = new CSSOCompressor(),
-            translator = new CSSOTranslator();
-
-        return translator.translate(cleanInfo(compressor.compress(srcToCSSP(text, 'stylesheet', true))));
+      else if (typeof CleanCSS !== 'undefined') {
+        return new CleanCSS().minify(text);
       }
     }
     catch (err) { }
index 4259d01..8f5bd76 100644 (file)
@@ -5,7 +5,7 @@
     <title>HTML Minifier Tests</title>
     <link rel="stylesheet" href="http://cdn.jsdelivr.net/qunit/1.14.0/qunit.css">
     <script src="http://cdn.jsdelivr.net/qunit/1.14.0/qunit.js"></script>
-    <script src="../csso.js"></script>
+    <script src="../cleancss-browser.js"></script>
     <script src="../uglify.js"></script>
     <script src="../dist/htmlminifier.js"></script>
   </head>