From: XhmikosR Date: Tue, 18 Mar 2014 15:14:55 +0000 (+0200) Subject: Try clean-css. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=6e6b80b39bdb119133e01b3cda52612695cce651;p=html-minifier.git Try clean-css. --- diff --git a/README.md b/README.md index 3a0d9cb..ef69346 100644 --- 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 index 0000000..3117519 --- /dev/null +++ b/cleancss-browser.js @@ -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 -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
    + 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
      and 'decimal' for
        + // -- 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 + * 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 '' +} + +/** + * 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 + * @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 state to , + // 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 + * @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 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] + ')'; -}; diff --git a/dist/htmlminifier.js b/dist/htmlminifier.js index 93697f7..fc3650d 100644 --- a/dist/htmlminifier.js +++ b/dist/htmlminifier.js @@ -407,8 +407,6 @@ } })(typeof exports === 'undefined' ? this : exports); -/* global CSSOCompressor: true, CSSOTranslator: true, cleanInfo: true, srcToCSSP: true */ - (function(global) { 'use strict'; @@ -741,18 +739,13 @@ 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) { } diff --git a/dist/htmlminifier.min.js b/dist/htmlminifier.min.js index 67d2d95..5034342 100644 --- a/dist/htmlminifier.min.js +++ b/dist/htmlminifier.min.js @@ -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\s]+))?)*)\s*(\/?)>/,g=/^<\/([\w:-]+)[^>]*>/,h=/\/>$/,i=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g,j=/^]+>/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"")})}),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]*?)]*>","i")),a=a.replace(d,function(a,d){return"script"!==c&&"style"!==c&&(d=d.replace(//g,"$1").replace(//g,"$1")),b.chars&&b.chars(d),""}),t("",c);else if(0===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("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"},end:function(a){b+=""},chars:function(a){b+=a},comment:function(a){b+=""},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*(]+$/.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*(\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(""),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)?"":e(a)?"":"":"",j.push(a)},ignore:function(a){j.push(f.removeIgnored?"":a)},doctype:function(a){j.push(f.useShortDoctype?"":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*\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 deprecated <'+a+"> element"):b(a)?this.log.push('Found presentational <'+a+"> 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 <br> sequence. Try replacing it with styling.")},h.prototype.testAttribute=function(a,b,c){d(b)?this.log.push('Found event attribute ('+b+") on <"+a+"> element."):f(a,b)?this.log.push('Found deprecated '+b+" attribute on <"+a+"> element."):e(b)?this.log.push('Found style attribute on <'+a+"> element."):g(b,c)&&this.log.push('Found inaccessible attribute (on <'+a+"> element).")},h.prototype.testChars=function(a){this._lastElement="",/( \s*){2,}/.test(a)&&this.log.push("Found repeating &nbsp; 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="
        1. "+this.log.join("
        2. ")+"
        ";else{var b=" - "+this.log.join("\n - ").replace(/(<([^>]+)>)/gi,"").replace(/</g,"<").replace(/>/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\s]+))?)*)\s*(\/?)>/,g=/^<\/([\w:-]+)[^>]*>/,h=/\/>$/,i=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g,j=/^]+>/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"")})}),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]*?)]*>","i")),a=a.replace(d,function(a,d){return"script"!==c&&"style"!==c&&(d=d.replace(//g,"$1").replace(//g,"$1")),b.chars&&b.chars(d),""}),t("",c);else if(0===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("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"},end:function(a){b+=""},chars:function(a){b+=a},comment:function(a){b+=""},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*(]+$/.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*(\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(""),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)?"":e(a)?"":"":"",j.push(a)},ignore:function(a){j.push(f.removeIgnored?"":a)},doctype:function(a){j.push(f.useShortDoctype?"":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*\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 deprecated <'+a+"> element"):b(a)?this.log.push('Found presentational <'+a+"> 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 <br> sequence. Try replacing it with styling.")},h.prototype.testAttribute=function(a,b,c){d(b)?this.log.push('Found event attribute ('+b+") on <"+a+"> element."):f(a,b)?this.log.push('Found deprecated '+b+" attribute on <"+a+"> element."):e(b)?this.log.push('Found style attribute on <'+a+"> element."):g(b,c)&&this.log.push('Found inaccessible attribute (on <'+a+"> element).")},h.prototype.testChars=function(a){this._lastElement="",/( \s*){2,}/.test(a)&&this.log.push("Found repeating &nbsp; 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="
        1. "+this.log.join("
        2. ")+"
        ";else{var b=" - "+this.log.join("\n - ").replace(/(<([^>]+)>)/gi,"").replace(/</g,"<").replace(/>/g,">");console.log(b)}},a.HTMLLint=h}("undefined"==typeof exports?this:exports); \ No newline at end of file diff --git a/index.html b/index.html index 52a97b7..1f60d06 100644 --- a/index.html +++ b/index.html @@ -203,7 +203,7 @@

        - + diff --git a/package.json b/package.json index 82852b8..f3558b7 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "test": "grunt test" }, "dependencies": { - "csso": "1.3.x", + "clean-css": "2.1.x", "uglify-js": "2.4.x" }, "devDependencies": { diff --git a/src/htmlminifier.js b/src/htmlminifier.js index 78fa4a1..8993e68 100644 --- a/src/htmlminifier.js +++ b/src/htmlminifier.js @@ -1,5 +1,3 @@ -/* global CSSOCompressor: true, CSSOTranslator: true, cleanInfo: true, srcToCSSP: true */ - (function(global) { 'use strict'; @@ -332,18 +330,13 @@ 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) { } diff --git a/tests/index.html b/tests/index.html index 4259d01..8f5bd76 100644 --- a/tests/index.html +++ b/tests/index.html @@ -5,7 +5,7 @@ HTML Minifier Tests - +