home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-includes / js / codemirror / csslint.js < prev    next >
Encoding:
JavaScript  |  2017-11-02  |  368.8 KB  |  10,859 lines

  1. /*!
  2. CSSLint v1.0.4
  3. Copyright (c) 2016 Nicole Sullivan and Nicholas C. Zakas. All rights reserved.
  4.  
  5. Permission is hereby granted, free of charge, to any person obtaining a copy
  6. of this software and associated documentation files (the 'Software'), to deal
  7. in the Software without restriction, including without limitation the rights
  8. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. copies of the Software, and to permit persons to whom the Software is
  10. furnished to do so, subject to the following conditions:
  11.  
  12. The above copyright notice and this permission notice shall be included in
  13. all copies or substantial portions of the Software.
  14.  
  15. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. THE SOFTWARE.
  22.  
  23. */
  24.  
  25. var CSSLint = (function(){
  26.   var module = module || {},
  27.       exports = exports || {};
  28.  
  29. /*!
  30. Parser-Lib
  31. Copyright (c) 2009-2016 Nicholas C. Zakas. All rights reserved.
  32.  
  33. Permission is hereby granted, free of charge, to any person obtaining a copy
  34. of this software and associated documentation files (the "Software"), to deal
  35. in the Software without restriction, including without limitation the rights
  36. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  37. copies of the Software, and to permit persons to whom the Software is
  38. furnished to do so, subject to the following conditions:
  39.  
  40. The above copyright notice and this permission notice shall be included in
  41. all copies or substantial portions of the Software.
  42.  
  43. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  44. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  45. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  46. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  47. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  48. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  49. THE SOFTWARE.
  50. */
  51. /* Version v1.1.0, Build time: 6-December-2016 10:31:29 */
  52. var parserlib = (function () {
  53. var require;
  54. require=(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);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  55. "use strict";
  56.  
  57. /* exported Colors */
  58.  
  59. var Colors = module.exports = {
  60.     __proto__       :null,
  61.     aliceblue       :"#f0f8ff",
  62.     antiquewhite    :"#faebd7",
  63.     aqua            :"#00ffff",
  64.     aquamarine      :"#7fffd4",
  65.     azure           :"#f0ffff",
  66.     beige           :"#f5f5dc",
  67.     bisque          :"#ffe4c4",
  68.     black           :"#000000",
  69.     blanchedalmond  :"#ffebcd",
  70.     blue            :"#0000ff",
  71.     blueviolet      :"#8a2be2",
  72.     brown           :"#a52a2a",
  73.     burlywood       :"#deb887",
  74.     cadetblue       :"#5f9ea0",
  75.     chartreuse      :"#7fff00",
  76.     chocolate       :"#d2691e",
  77.     coral           :"#ff7f50",
  78.     cornflowerblue  :"#6495ed",
  79.     cornsilk        :"#fff8dc",
  80.     crimson         :"#dc143c",
  81.     cyan            :"#00ffff",
  82.     darkblue        :"#00008b",
  83.     darkcyan        :"#008b8b",
  84.     darkgoldenrod   :"#b8860b",
  85.     darkgray        :"#a9a9a9",
  86.     darkgrey        :"#a9a9a9",
  87.     darkgreen       :"#006400",
  88.     darkkhaki       :"#bdb76b",
  89.     darkmagenta     :"#8b008b",
  90.     darkolivegreen  :"#556b2f",
  91.     darkorange      :"#ff8c00",
  92.     darkorchid      :"#9932cc",
  93.     darkred         :"#8b0000",
  94.     darksalmon      :"#e9967a",
  95.     darkseagreen    :"#8fbc8f",
  96.     darkslateblue   :"#483d8b",
  97.     darkslategray   :"#2f4f4f",
  98.     darkslategrey   :"#2f4f4f",
  99.     darkturquoise   :"#00ced1",
  100.     darkviolet      :"#9400d3",
  101.     deeppink        :"#ff1493",
  102.     deepskyblue     :"#00bfff",
  103.     dimgray         :"#696969",
  104.     dimgrey         :"#696969",
  105.     dodgerblue      :"#1e90ff",
  106.     firebrick       :"#b22222",
  107.     floralwhite     :"#fffaf0",
  108.     forestgreen     :"#228b22",
  109.     fuchsia         :"#ff00ff",
  110.     gainsboro       :"#dcdcdc",
  111.     ghostwhite      :"#f8f8ff",
  112.     gold            :"#ffd700",
  113.     goldenrod       :"#daa520",
  114.     gray            :"#808080",
  115.     grey            :"#808080",
  116.     green           :"#008000",
  117.     greenyellow     :"#adff2f",
  118.     honeydew        :"#f0fff0",
  119.     hotpink         :"#ff69b4",
  120.     indianred       :"#cd5c5c",
  121.     indigo          :"#4b0082",
  122.     ivory           :"#fffff0",
  123.     khaki           :"#f0e68c",
  124.     lavender        :"#e6e6fa",
  125.     lavenderblush   :"#fff0f5",
  126.     lawngreen       :"#7cfc00",
  127.     lemonchiffon    :"#fffacd",
  128.     lightblue       :"#add8e6",
  129.     lightcoral      :"#f08080",
  130.     lightcyan       :"#e0ffff",
  131.     lightgoldenrodyellow  :"#fafad2",
  132.     lightgray       :"#d3d3d3",
  133.     lightgrey       :"#d3d3d3",
  134.     lightgreen      :"#90ee90",
  135.     lightpink       :"#ffb6c1",
  136.     lightsalmon     :"#ffa07a",
  137.     lightseagreen   :"#20b2aa",
  138.     lightskyblue    :"#87cefa",
  139.     lightslategray  :"#778899",
  140.     lightslategrey  :"#778899",
  141.     lightsteelblue  :"#b0c4de",
  142.     lightyellow     :"#ffffe0",
  143.     lime            :"#00ff00",
  144.     limegreen       :"#32cd32",
  145.     linen           :"#faf0e6",
  146.     magenta         :"#ff00ff",
  147.     maroon          :"#800000",
  148.     mediumaquamarine:"#66cdaa",
  149.     mediumblue      :"#0000cd",
  150.     mediumorchid    :"#ba55d3",
  151.     mediumpurple    :"#9370d8",
  152.     mediumseagreen  :"#3cb371",
  153.     mediumslateblue :"#7b68ee",
  154.     mediumspringgreen   :"#00fa9a",
  155.     mediumturquoise :"#48d1cc",
  156.     mediumvioletred :"#c71585",
  157.     midnightblue    :"#191970",
  158.     mintcream       :"#f5fffa",
  159.     mistyrose       :"#ffe4e1",
  160.     moccasin        :"#ffe4b5",
  161.     navajowhite     :"#ffdead",
  162.     navy            :"#000080",
  163.     oldlace         :"#fdf5e6",
  164.     olive           :"#808000",
  165.     olivedrab       :"#6b8e23",
  166.     orange          :"#ffa500",
  167.     orangered       :"#ff4500",
  168.     orchid          :"#da70d6",
  169.     palegoldenrod   :"#eee8aa",
  170.     palegreen       :"#98fb98",
  171.     paleturquoise   :"#afeeee",
  172.     palevioletred   :"#d87093",
  173.     papayawhip      :"#ffefd5",
  174.     peachpuff       :"#ffdab9",
  175.     peru            :"#cd853f",
  176.     pink            :"#ffc0cb",
  177.     plum            :"#dda0dd",
  178.     powderblue      :"#b0e0e6",
  179.     purple          :"#800080",
  180.     red             :"#ff0000",
  181.     rosybrown       :"#bc8f8f",
  182.     royalblue       :"#4169e1",
  183.     saddlebrown     :"#8b4513",
  184.     salmon          :"#fa8072",
  185.     sandybrown      :"#f4a460",
  186.     seagreen        :"#2e8b57",
  187.     seashell        :"#fff5ee",
  188.     sienna          :"#a0522d",
  189.     silver          :"#c0c0c0",
  190.     skyblue         :"#87ceeb",
  191.     slateblue       :"#6a5acd",
  192.     slategray       :"#708090",
  193.     slategrey       :"#708090",
  194.     snow            :"#fffafa",
  195.     springgreen     :"#00ff7f",
  196.     steelblue       :"#4682b4",
  197.     tan             :"#d2b48c",
  198.     teal            :"#008080",
  199.     thistle         :"#d8bfd8",
  200.     tomato          :"#ff6347",
  201.     turquoise       :"#40e0d0",
  202.     violet          :"#ee82ee",
  203.     wheat           :"#f5deb3",
  204.     white           :"#ffffff",
  205.     whitesmoke      :"#f5f5f5",
  206.     yellow          :"#ffff00",
  207.     yellowgreen     :"#9acd32",
  208.     //'currentColor' color keyword https://www.w3.org/TR/css3-color/#currentcolor
  209.     currentColor        :"The value of the 'color' property.",
  210.     //CSS2 system colors https://www.w3.org/TR/css3-color/#css2-system
  211.     activeBorder        :"Active window border.",
  212.     activecaption       :"Active window caption.",
  213.     appworkspace        :"Background color of multiple document interface.",
  214.     background          :"Desktop background.",
  215.     buttonface          :"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.",
  216.     buttonhighlight     :"The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.",
  217.     buttonshadow        :"The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.",
  218.     buttontext          :"Text on push buttons.",
  219.     captiontext         :"Text in caption, size box, and scrollbar arrow box.",
  220.     graytext            :"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.",
  221.     greytext            :"Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color.",
  222.     highlight           :"Item(s) selected in a control.",
  223.     highlighttext       :"Text of item(s) selected in a control.",
  224.     inactiveborder      :"Inactive window border.",
  225.     inactivecaption     :"Inactive window caption.",
  226.     inactivecaptiontext :"Color of text in an inactive caption.",
  227.     infobackground      :"Background color for tooltip controls.",
  228.     infotext            :"Text color for tooltip controls.",
  229.     menu                :"Menu background.",
  230.     menutext            :"Text in menus.",
  231.     scrollbar           :"Scroll bar gray area.",
  232.     threeddarkshadow    :"The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
  233.     threedface          :"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
  234.     threedhighlight     :"The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
  235.     threedlightshadow   :"The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
  236.     threedshadow        :"The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
  237.     window              :"Window background.",
  238.     windowframe         :"Window frame.",
  239.     windowtext          :"Text in windows."
  240. };
  241.  
  242. },{}],2:[function(require,module,exports){
  243. "use strict";
  244.  
  245. module.exports = Combinator;
  246.  
  247. var SyntaxUnit = require("../util/SyntaxUnit");
  248.  
  249. var Parser = require("./Parser");
  250.  
  251. /**
  252.  * Represents a selector combinator (whitespace, +, >).
  253.  * @namespace parserlib.css
  254.  * @class Combinator
  255.  * @extends parserlib.util.SyntaxUnit
  256.  * @constructor
  257.  * @param {String} text The text representation of the unit.
  258.  * @param {int} line The line of text on which the unit resides.
  259.  * @param {int} col The column of text on which the unit resides.
  260.  */
  261. function Combinator(text, line, col) {
  262.  
  263.     SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE);
  264.  
  265.     /**
  266.      * The type of modifier.
  267.      * @type String
  268.      * @property type
  269.      */
  270.     this.type = "unknown";
  271.  
  272.     //pretty simple
  273.     if (/^\s+$/.test(text)) {
  274.         this.type = "descendant";
  275.     } else if (text === ">") {
  276.         this.type = "child";
  277.     } else if (text === "+") {
  278.         this.type = "adjacent-sibling";
  279.     } else if (text === "~") {
  280.         this.type = "sibling";
  281.     }
  282.  
  283. }
  284.  
  285. Combinator.prototype = new SyntaxUnit();
  286. Combinator.prototype.constructor = Combinator;
  287.  
  288.  
  289. },{"../util/SyntaxUnit":26,"./Parser":6}],3:[function(require,module,exports){
  290. "use strict";
  291.  
  292. module.exports = Matcher;
  293.  
  294. var StringReader = require("../util/StringReader");
  295. var SyntaxError = require("../util/SyntaxError");
  296.  
  297. /**
  298.  * This class implements a combinator library for matcher functions.
  299.  * The combinators are described at:
  300.  * https://developer.mozilla.org/en-US/docs/Web/CSS/Value_definition_syntax#Component_value_combinators
  301.  */
  302. function Matcher(matchFunc, toString) {
  303.     this.match = function(expression) {
  304.         // Save/restore marks to ensure that failed matches always restore
  305.         // the original location in the expression.
  306.         var result;
  307.         expression.mark();
  308.         result = matchFunc(expression);
  309.         if (result) {
  310.             expression.drop();
  311.         } else {
  312.             expression.restore();
  313.         }
  314.         return result;
  315.     };
  316.     this.toString = typeof toString === "function" ? toString : function() {
  317.         return toString;
  318.     };
  319. }
  320.  
  321. /** Precedence table of combinators. */
  322. Matcher.prec = {
  323.     MOD:    5,
  324.     SEQ:    4,
  325.     ANDAND: 3,
  326.     OROR:   2,
  327.     ALT:    1
  328. };
  329.  
  330. /** Simple recursive-descent grammar to build matchers from strings. */
  331. Matcher.parse = function(str) {
  332.     var reader, eat, expr, oror, andand, seq, mod, term, result;
  333.     reader = new StringReader(str);
  334.     eat = function(matcher) {
  335.         var result = reader.readMatch(matcher);
  336.         if (result === null) {
  337.             throw new SyntaxError(
  338.                 "Expected "+matcher, reader.getLine(), reader.getCol());
  339.         }
  340.         return result;
  341.     };
  342.     expr = function() {
  343.         // expr = oror (" | " oror)*
  344.         var m = [ oror() ];
  345.         while (reader.readMatch(" | ") !== null) {
  346.             m.push(oror());
  347.         }
  348.         return m.length === 1 ? m[0] : Matcher.alt.apply(Matcher, m);
  349.     };
  350.     oror = function() {
  351.         // oror = andand ( " || " andand)*
  352.         var m = [ andand() ];
  353.         while (reader.readMatch(" || ") !== null) {
  354.             m.push(andand());
  355.         }
  356.         return m.length === 1 ? m[0] : Matcher.oror.apply(Matcher, m);
  357.     };
  358.     andand = function() {
  359.         // andand = seq ( " && " seq)*
  360.         var m = [ seq() ];
  361.         while (reader.readMatch(" && ") !== null) {
  362.             m.push(seq());
  363.         }
  364.         return m.length === 1 ? m[0] : Matcher.andand.apply(Matcher, m);
  365.     };
  366.     seq = function() {
  367.         // seq = mod ( " " mod)*
  368.         var m = [ mod() ];
  369.         while (reader.readMatch(/^ (?![&|\]])/) !== null) {
  370.             m.push(mod());
  371.         }
  372.         return m.length === 1 ? m[0] : Matcher.seq.apply(Matcher, m);
  373.     };
  374.     mod = function() {
  375.         // mod = term ( "?" | "*" | "+" | "#" | "{<num>,<num>}" )?
  376.         var m = term();
  377.         if (reader.readMatch("?") !== null) {
  378.             return m.question();
  379.         } else if (reader.readMatch("*") !== null) {
  380.             return m.star();
  381.         } else if (reader.readMatch("+") !== null) {
  382.             return m.plus();
  383.         } else if (reader.readMatch("#") !== null) {
  384.             return m.hash();
  385.         } else if (reader.readMatch(/^\{\s*/) !== null) {
  386.             var min = eat(/^\d+/);
  387.             eat(/^\s*,\s*/);
  388.             var max = eat(/^\d+/);
  389.             eat(/^\s*\}/);
  390.             return m.braces(+min, +max);
  391.         }
  392.         return m;
  393.     };
  394.     term = function() {
  395.         // term = <nt> | literal | "[ " expression " ]"
  396.         if (reader.readMatch("[ ") !== null) {
  397.             var m = expr();
  398.             eat(" ]");
  399.             return m;
  400.         }
  401.         return Matcher.fromType(eat(/^[^ ?*+#{]+/));
  402.     };
  403.     result = expr();
  404.     if (!reader.eof()) {
  405.         throw new SyntaxError(
  406.             "Expected end of string", reader.getLine(), reader.getCol());
  407.     }
  408.     return result;
  409. };
  410.  
  411. /**
  412.  * Convert a string to a matcher (parsing simple alternations),
  413.  * or do nothing if the argument is already a matcher.
  414.  */
  415. Matcher.cast = function(m) {
  416.     if (m instanceof Matcher) {
  417.         return m;
  418.     }
  419.     return Matcher.parse(m);
  420. };
  421.  
  422. /**
  423.  * Create a matcher for a single type.
  424.  */
  425. Matcher.fromType = function(type) {
  426.     // Late require of ValidationTypes to break a dependency cycle.
  427.     var ValidationTypes = require("./ValidationTypes");
  428.     return new Matcher(function(expression) {
  429.         return expression.hasNext() && ValidationTypes.isType(expression, type);
  430.     }, type);
  431. };
  432.  
  433. /**
  434.  * Create a matcher for one or more juxtaposed words, which all must
  435.  * occur, in the given order.
  436.  */
  437. Matcher.seq = function() {
  438.     var ms = Array.prototype.slice.call(arguments).map(Matcher.cast);
  439.     if (ms.length === 1) {
  440.         return ms[0];
  441.     }
  442.     return new Matcher(function(expression) {
  443.         var i, result = true;
  444.         for (i = 0; result && i < ms.length; i++) {
  445.             result = ms[i].match(expression);
  446.         }
  447.         return result;
  448.     }, function(prec) {
  449.         var p = Matcher.prec.SEQ;
  450.         var s = ms.map(function(m) {
  451.             return m.toString(p);
  452.         }).join(" ");
  453.         if (prec > p) {
  454.             s = "[ " + s + " ]";
  455.         }
  456.         return s;
  457.     });
  458. };
  459.  
  460. /**
  461.  * Create a matcher for one or more alternatives, where exactly one
  462.  * must occur.
  463.  */
  464. Matcher.alt = function() {
  465.     var ms = Array.prototype.slice.call(arguments).map(Matcher.cast);
  466.     if (ms.length === 1) {
  467.         return ms[0];
  468.     }
  469.     return new Matcher(function(expression) {
  470.         var i, result = false;
  471.         for (i = 0; !result && i < ms.length; i++) {
  472.             result = ms[i].match(expression);
  473.         }
  474.         return result;
  475.     }, function(prec) {
  476.         var p = Matcher.prec.ALT;
  477.         var s = ms.map(function(m) {
  478.             return m.toString(p);
  479.         }).join(" | ");
  480.         if (prec > p) {
  481.             s = "[ " + s + " ]";
  482.         }
  483.         return s;
  484.     });
  485. };
  486.  
  487. /**
  488.  * Create a matcher for two or more options.  This implements the
  489.  * double bar (||) and double ampersand (&&) operators, as well as
  490.  * variants of && where some of the alternatives are optional.
  491.  * This will backtrack through even successful matches to try to
  492.  * maximize the number of items matched.
  493.  */
  494. Matcher.many = function(required) {
  495.     var ms = Array.prototype.slice.call(arguments, 1).reduce(function(acc, v) {
  496.         if (v.expand) {
  497.             // Insert all of the options for the given complex rule as
  498.             // individual options.
  499.             var ValidationTypes = require("./ValidationTypes");
  500.             acc.push.apply(acc, ValidationTypes.complex[v.expand].options);
  501.         } else {
  502.             acc.push(Matcher.cast(v));
  503.         }
  504.         return acc;
  505.     }, []);
  506.  
  507.     if (required === true) {
  508.         required = ms.map(function() {
  509.             return true;
  510.         });
  511.     }
  512.  
  513.     var result = new Matcher(function(expression) {
  514.         var seen = [], max = 0, pass = 0;
  515.         var success = function(matchCount) {
  516.             if (pass === 0) {
  517.                 max = Math.max(matchCount, max);
  518.                 return matchCount === ms.length;
  519.             } else {
  520.                 return matchCount === max;
  521.             }
  522.         };
  523.         var tryMatch = function(matchCount) {
  524.             for (var i = 0; i < ms.length; i++) {
  525.                 if (seen[i]) {
  526.                     continue;
  527.                 }
  528.                 expression.mark();
  529.                 if (ms[i].match(expression)) {
  530.                     seen[i] = true;
  531.                     // Increase matchCount iff this was a required element
  532.                     // (or if all the elements are optional)
  533.                     if (tryMatch(matchCount + ((required === false || required[i]) ? 1 : 0))) {
  534.                         expression.drop();
  535.                         return true;
  536.                     }
  537.                     // Backtrack: try *not* matching using this rule, and
  538.                     // let's see if it leads to a better overall match.
  539.                     expression.restore();
  540.                     seen[i] = false;
  541.                 } else {
  542.                     expression.drop();
  543.                 }
  544.             }
  545.             return success(matchCount);
  546.         };
  547.         if (!tryMatch(0)) {
  548.             // Couldn't get a complete match, retrace our steps to make the
  549.             // match with the maximum # of required elements.
  550.             pass++;
  551.             tryMatch(0);
  552.         }
  553.  
  554.         if (required === false) {
  555.             return max > 0;
  556.         }
  557.         // Use finer-grained specification of which matchers are required.
  558.         for (var i = 0; i < ms.length; i++) {
  559.             if (required[i] && !seen[i]) {
  560.                 return false;
  561.             }
  562.         }
  563.         return true;
  564.     }, function(prec) {
  565.         var p = required === false ? Matcher.prec.OROR : Matcher.prec.ANDAND;
  566.         var s = ms.map(function(m, i) {
  567.             if (required !== false && !required[i]) {
  568.                 return m.toString(Matcher.prec.MOD) + "?";
  569.             }
  570.             return m.toString(p);
  571.         }).join(required === false ? " || " : " && ");
  572.         if (prec > p) {
  573.             s = "[ " + s + " ]";
  574.         }
  575.         return s;
  576.     });
  577.     result.options = ms;
  578.     return result;
  579. };
  580.  
  581. /**
  582.  * Create a matcher for two or more options, where all options are
  583.  * mandatory but they may appear in any order.
  584.  */
  585. Matcher.andand = function() {
  586.     var args = Array.prototype.slice.call(arguments);
  587.     args.unshift(true);
  588.     return Matcher.many.apply(Matcher, args);
  589. };
  590.  
  591. /**
  592.  * Create a matcher for two or more options, where options are
  593.  * optional and may appear in any order, but at least one must be
  594.  * present.
  595.  */
  596. Matcher.oror = function() {
  597.     var args = Array.prototype.slice.call(arguments);
  598.     args.unshift(false);
  599.     return Matcher.many.apply(Matcher, args);
  600. };
  601.  
  602. /** Instance methods on Matchers. */
  603. Matcher.prototype = {
  604.     constructor: Matcher,
  605.     // These are expected to be overridden in every instance.
  606.     match: function() { throw new Error("unimplemented"); },
  607.     toString: function() { throw new Error("unimplemented"); },
  608.     // This returns a standalone function to do the matching.
  609.     func: function() { return this.match.bind(this); },
  610.     // Basic combinators
  611.     then: function(m) { return Matcher.seq(this, m); },
  612.     or: function(m) { return Matcher.alt(this, m); },
  613.     andand: function(m) { return Matcher.many(true, this, m); },
  614.     oror: function(m) { return Matcher.many(false, this, m); },
  615.     // Component value multipliers
  616.     star: function() { return this.braces(0, Infinity, "*"); },
  617.     plus: function() { return this.braces(1, Infinity, "+"); },
  618.     question: function() { return this.braces(0, 1, "?"); },
  619.     hash: function() {
  620.         return this.braces(1, Infinity, "#", Matcher.cast(","));
  621.     },
  622.     braces: function(min, max, marker, optSep) {
  623.         var m1 = this, m2 = optSep ? optSep.then(this) : this;
  624.         if (!marker) {
  625.             marker = "{" + min + "," + max + "}";
  626.         }
  627.         return new Matcher(function(expression) {
  628.             var result = true, i;
  629.             for (i = 0; i < max; i++) {
  630.                 if (i > 0 && optSep) {
  631.                     result = m2.match(expression);
  632.                 } else {
  633.                     result = m1.match(expression);
  634.                 }
  635.                 if (!result) {
  636.                     break;
  637.                 }
  638.             }
  639.             return i >= min;
  640.         }, function() {
  641.             return m1.toString(Matcher.prec.MOD) + marker;
  642.         });
  643.     }
  644. };
  645.  
  646. },{"../util/StringReader":24,"../util/SyntaxError":25,"./ValidationTypes":21}],4:[function(require,module,exports){
  647. "use strict";
  648.  
  649. module.exports = MediaFeature;
  650.  
  651. var SyntaxUnit = require("../util/SyntaxUnit");
  652.  
  653. var Parser = require("./Parser");
  654.  
  655. /**
  656.  * Represents a media feature, such as max-width:500.
  657.  * @namespace parserlib.css
  658.  * @class MediaFeature
  659.  * @extends parserlib.util.SyntaxUnit
  660.  * @constructor
  661.  * @param {SyntaxUnit} name The name of the feature.
  662.  * @param {SyntaxUnit} value The value of the feature or null if none.
  663.  */
  664. function MediaFeature(name, value) {
  665.  
  666.     SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE);
  667.  
  668.     /**
  669.      * The name of the media feature
  670.      * @type String
  671.      * @property name
  672.      */
  673.     this.name = name;
  674.  
  675.     /**
  676.      * The value for the feature or null if there is none.
  677.      * @type SyntaxUnit
  678.      * @property value
  679.      */
  680.     this.value = value;
  681. }
  682.  
  683. MediaFeature.prototype = new SyntaxUnit();
  684. MediaFeature.prototype.constructor = MediaFeature;
  685.  
  686.  
  687. },{"../util/SyntaxUnit":26,"./Parser":6}],5:[function(require,module,exports){
  688. "use strict";
  689.  
  690. module.exports = MediaQuery;
  691.  
  692. var SyntaxUnit = require("../util/SyntaxUnit");
  693.  
  694. var Parser = require("./Parser");
  695.  
  696. /**
  697.  * Represents an individual media query.
  698.  * @namespace parserlib.css
  699.  * @class MediaQuery
  700.  * @extends parserlib.util.SyntaxUnit
  701.  * @constructor
  702.  * @param {String} modifier The modifier "not" or "only" (or null).
  703.  * @param {String} mediaType The type of media (i.e., "print").
  704.  * @param {Array} parts Array of selectors parts making up this selector.
  705.  * @param {int} line The line of text on which the unit resides.
  706.  * @param {int} col The column of text on which the unit resides.
  707.  */
  708. function MediaQuery(modifier, mediaType, features, line, col) {
  709.  
  710.     SyntaxUnit.call(this, (modifier ? modifier + " ": "") + (mediaType ? mediaType : "") + (mediaType && features.length > 0 ? " and " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE);
  711.  
  712.     /**
  713.      * The media modifier ("not" or "only")
  714.      * @type String
  715.      * @property modifier
  716.      */
  717.     this.modifier = modifier;
  718.  
  719.     /**
  720.      * The mediaType (i.e., "print")
  721.      * @type String
  722.      * @property mediaType
  723.      */
  724.     this.mediaType = mediaType;
  725.  
  726.     /**
  727.      * The parts that make up the selector.
  728.      * @type Array
  729.      * @property features
  730.      */
  731.     this.features = features;
  732.  
  733. }
  734.  
  735. MediaQuery.prototype = new SyntaxUnit();
  736. MediaQuery.prototype.constructor = MediaQuery;
  737.  
  738.  
  739. },{"../util/SyntaxUnit":26,"./Parser":6}],6:[function(require,module,exports){
  740. "use strict";
  741.  
  742. module.exports = Parser;
  743.  
  744. var EventTarget = require("../util/EventTarget");
  745. var SyntaxError = require("../util/SyntaxError");
  746. var SyntaxUnit = require("../util/SyntaxUnit");
  747.  
  748. var Combinator = require("./Combinator");
  749. var MediaFeature = require("./MediaFeature");
  750. var MediaQuery = require("./MediaQuery");
  751. var PropertyName = require("./PropertyName");
  752. var PropertyValue = require("./PropertyValue");
  753. var PropertyValuePart = require("./PropertyValuePart");
  754. var Selector = require("./Selector");
  755. var SelectorPart = require("./SelectorPart");
  756. var SelectorSubPart = require("./SelectorSubPart");
  757. var TokenStream = require("./TokenStream");
  758. var Tokens = require("./Tokens");
  759. var Validation = require("./Validation");
  760.  
  761. /**
  762.  * A CSS3 parser.
  763.  * @namespace parserlib.css
  764.  * @class Parser
  765.  * @constructor
  766.  * @param {Object} options (Optional) Various options for the parser:
  767.  *      starHack (true|false) to allow IE6 star hack as valid,
  768.  *      underscoreHack (true|false) to interpret leading underscores
  769.  *      as IE6-7 targeting for known properties, ieFilters (true|false)
  770.  *      to indicate that IE < 8 filters should be accepted and not throw
  771.  *      syntax errors.
  772.  */
  773. function Parser(options) {
  774.  
  775.     //inherit event functionality
  776.     EventTarget.call(this);
  777.  
  778.  
  779.     this.options = options || {};
  780.  
  781.     this._tokenStream = null;
  782. }
  783.  
  784. //Static constants
  785. Parser.DEFAULT_TYPE = 0;
  786. Parser.COMBINATOR_TYPE = 1;
  787. Parser.MEDIA_FEATURE_TYPE = 2;
  788. Parser.MEDIA_QUERY_TYPE = 3;
  789. Parser.PROPERTY_NAME_TYPE = 4;
  790. Parser.PROPERTY_VALUE_TYPE = 5;
  791. Parser.PROPERTY_VALUE_PART_TYPE = 6;
  792. Parser.SELECTOR_TYPE = 7;
  793. Parser.SELECTOR_PART_TYPE = 8;
  794. Parser.SELECTOR_SUB_PART_TYPE = 9;
  795.  
  796. Parser.prototype = function() {
  797.  
  798.     var proto = new EventTarget(),  //new prototype
  799.         prop,
  800.         additions =  {
  801.             __proto__: null,
  802.  
  803.             //restore constructor
  804.             constructor: Parser,
  805.  
  806.             //instance constants - yuck
  807.             DEFAULT_TYPE : 0,
  808.             COMBINATOR_TYPE : 1,
  809.             MEDIA_FEATURE_TYPE : 2,
  810.             MEDIA_QUERY_TYPE : 3,
  811.             PROPERTY_NAME_TYPE : 4,
  812.             PROPERTY_VALUE_TYPE : 5,
  813.             PROPERTY_VALUE_PART_TYPE : 6,
  814.             SELECTOR_TYPE : 7,
  815.             SELECTOR_PART_TYPE : 8,
  816.             SELECTOR_SUB_PART_TYPE : 9,
  817.  
  818.             //-----------------------------------------------------------------
  819.             // Grammar
  820.             //-----------------------------------------------------------------
  821.  
  822.             _stylesheet: function() {
  823.  
  824.                 /*
  825.                  * stylesheet
  826.                  *  : [ CHARSET_SYM S* STRING S* ';' ]?
  827.                  *    [S|CDO|CDC]* [ import [S|CDO|CDC]* ]*
  828.                  *    [ namespace [S|CDO|CDC]* ]*
  829.                  *    [ [ ruleset | media | page | font_face | keyframes_rule | supports_rule ] [S|CDO|CDC]* ]*
  830.                  *  ;
  831.                  */
  832.  
  833.                 var tokenStream = this._tokenStream,
  834.                     count,
  835.                     token,
  836.                     tt;
  837.  
  838.                 this.fire("startstylesheet");
  839.  
  840.                 //try to read character set
  841.                 this._charset();
  842.  
  843.                 this._skipCruft();
  844.  
  845.                 //try to read imports - may be more than one
  846.                 while (tokenStream.peek() === Tokens.IMPORT_SYM) {
  847.                     this._import();
  848.                     this._skipCruft();
  849.                 }
  850.  
  851.                 //try to read namespaces - may be more than one
  852.                 while (tokenStream.peek() === Tokens.NAMESPACE_SYM) {
  853.                     this._namespace();
  854.                     this._skipCruft();
  855.                 }
  856.  
  857.                 //get the next token
  858.                 tt = tokenStream.peek();
  859.  
  860.                 //try to read the rest
  861.                 while (tt > Tokens.EOF) {
  862.  
  863.                     try {
  864.  
  865.                         switch (tt) {
  866.                             case Tokens.MEDIA_SYM:
  867.                                 this._media();
  868.                                 this._skipCruft();
  869.                                 break;
  870.                             case Tokens.PAGE_SYM:
  871.                                 this._page();
  872.                                 this._skipCruft();
  873.                                 break;
  874.                             case Tokens.FONT_FACE_SYM:
  875.                                 this._font_face();
  876.                                 this._skipCruft();
  877.                                 break;
  878.                             case Tokens.KEYFRAMES_SYM:
  879.                                 this._keyframes();
  880.                                 this._skipCruft();
  881.                                 break;
  882.                             case Tokens.VIEWPORT_SYM:
  883.                                 this._viewport();
  884.                                 this._skipCruft();
  885.                                 break;
  886.                             case Tokens.DOCUMENT_SYM:
  887.                                 this._document();
  888.                                 this._skipCruft();
  889.                                 break;
  890.                             case Tokens.SUPPORTS_SYM:
  891.                                 this._supports();
  892.                                 this._skipCruft();
  893.                                 break;
  894.                             case Tokens.UNKNOWN_SYM:  //unknown @ rule
  895.                                 tokenStream.get();
  896.                                 if (!this.options.strict) {
  897.  
  898.                                     //fire error event
  899.                                     this.fire({
  900.                                         type:       "error",
  901.                                         error:      null,
  902.                                         message:    "Unknown @ rule: " + tokenStream.LT(0).value + ".",
  903.                                         line:       tokenStream.LT(0).startLine,
  904.                                         col:        tokenStream.LT(0).startCol
  905.                                     });
  906.  
  907.                                     //skip braces
  908.                                     count=0;
  909.                                     while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) === Tokens.LBRACE) {
  910.                                         count++;    //keep track of nesting depth
  911.                                     }
  912.  
  913.                                     while (count) {
  914.                                         tokenStream.advance([Tokens.RBRACE]);
  915.                                         count--;
  916.                                     }
  917.  
  918.                                 } else {
  919.                                     //not a syntax error, rethrow it
  920.                                     throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol);
  921.                                 }
  922.                                 break;
  923.                             case Tokens.S:
  924.                                 this._readWhitespace();
  925.                                 break;
  926.                             default:
  927.                                 if (!this._ruleset()) {
  928.  
  929.                                     //error handling for known issues
  930.                                     switch (tt) {
  931.                                         case Tokens.CHARSET_SYM:
  932.                                             token = tokenStream.LT(1);
  933.                                             this._charset(false);
  934.                                             throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol);
  935.                                         case Tokens.IMPORT_SYM:
  936.                                             token = tokenStream.LT(1);
  937.                                             this._import(false);
  938.                                             throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol);
  939.                                         case Tokens.NAMESPACE_SYM:
  940.                                             token = tokenStream.LT(1);
  941.                                             this._namespace(false);
  942.                                             throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol);
  943.                                         default:
  944.                                             tokenStream.get();  //get the last token
  945.                                             this._unexpectedToken(tokenStream.token());
  946.                                     }
  947.  
  948.                                 }
  949.                         }
  950.                     } catch (ex) {
  951.                         if (ex instanceof SyntaxError && !this.options.strict) {
  952.                             this.fire({
  953.                                 type:       "error",
  954.                                 error:      ex,
  955.                                 message:    ex.message,
  956.                                 line:       ex.line,
  957.                                 col:        ex.col
  958.                             });
  959.                         } else {
  960.                             throw ex;
  961.                         }
  962.                     }
  963.  
  964.                     tt = tokenStream.peek();
  965.                 }
  966.  
  967.                 if (tt !== Tokens.EOF) {
  968.                     this._unexpectedToken(tokenStream.token());
  969.                 }
  970.  
  971.                 this.fire("endstylesheet");
  972.             },
  973.  
  974.             _charset: function(emit) {
  975.                 var tokenStream = this._tokenStream,
  976.                     charset,
  977.                     token,
  978.                     line,
  979.                     col;
  980.  
  981.                 if (tokenStream.match(Tokens.CHARSET_SYM)) {
  982.                     line = tokenStream.token().startLine;
  983.                     col = tokenStream.token().startCol;
  984.  
  985.                     this._readWhitespace();
  986.                     tokenStream.mustMatch(Tokens.STRING);
  987.  
  988.                     token = tokenStream.token();
  989.                     charset = token.value;
  990.  
  991.                     this._readWhitespace();
  992.                     tokenStream.mustMatch(Tokens.SEMICOLON);
  993.  
  994.                     if (emit !== false) {
  995.                         this.fire({
  996.                             type:   "charset",
  997.                             charset:charset,
  998.                             line:   line,
  999.                             col:    col
  1000.                         });
  1001.                     }
  1002.                 }
  1003.             },
  1004.  
  1005.             _import: function(emit) {
  1006.                 /*
  1007.                  * import
  1008.                  *   : IMPORT_SYM S*
  1009.                  *    [STRING|URI] S* media_query_list? ';' S*
  1010.                  */
  1011.  
  1012.                 var tokenStream = this._tokenStream,
  1013.                     uri,
  1014.                     importToken,
  1015.                     mediaList   = [];
  1016.  
  1017.                 //read import symbol
  1018.                 tokenStream.mustMatch(Tokens.IMPORT_SYM);
  1019.                 importToken = tokenStream.token();
  1020.                 this._readWhitespace();
  1021.  
  1022.                 tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);
  1023.  
  1024.                 //grab the URI value
  1025.                 uri = tokenStream.token().value.replace(/^(?:url\()?["']?([^"']+?)["']?\)?$/, "$1");
  1026.  
  1027.                 this._readWhitespace();
  1028.  
  1029.                 mediaList = this._media_query_list();
  1030.  
  1031.                 //must end with a semicolon
  1032.                 tokenStream.mustMatch(Tokens.SEMICOLON);
  1033.                 this._readWhitespace();
  1034.  
  1035.                 if (emit !== false) {
  1036.                     this.fire({
  1037.                         type:   "import",
  1038.                         uri:    uri,
  1039.                         media:  mediaList,
  1040.                         line:   importToken.startLine,
  1041.                         col:    importToken.startCol
  1042.                     });
  1043.                 }
  1044.  
  1045.             },
  1046.  
  1047.             _namespace: function(emit) {
  1048.                 /*
  1049.                  * namespace
  1050.                  *   : NAMESPACE_SYM S* [namespace_prefix S*]? [STRING|URI] S* ';' S*
  1051.                  */
  1052.  
  1053.                 var tokenStream = this._tokenStream,
  1054.                     line,
  1055.                     col,
  1056.                     prefix,
  1057.                     uri;
  1058.  
  1059.                 //read import symbol
  1060.                 tokenStream.mustMatch(Tokens.NAMESPACE_SYM);
  1061.                 line = tokenStream.token().startLine;
  1062.                 col = tokenStream.token().startCol;
  1063.                 this._readWhitespace();
  1064.  
  1065.                 //it's a namespace prefix - no _namespace_prefix() method because it's just an IDENT
  1066.                 if (tokenStream.match(Tokens.IDENT)) {
  1067.                     prefix = tokenStream.token().value;
  1068.                     this._readWhitespace();
  1069.                 }
  1070.  
  1071.                 tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);
  1072.                 /*if (!tokenStream.match(Tokens.STRING)){
  1073.                     tokenStream.mustMatch(Tokens.URI);
  1074.                 }*/
  1075.  
  1076.                 //grab the URI value
  1077.                 uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1");
  1078.  
  1079.                 this._readWhitespace();
  1080.  
  1081.                 //must end with a semicolon
  1082.                 tokenStream.mustMatch(Tokens.SEMICOLON);
  1083.                 this._readWhitespace();
  1084.  
  1085.                 if (emit !== false) {
  1086.                     this.fire({
  1087.                         type:   "namespace",
  1088.                         prefix: prefix,
  1089.                         uri:    uri,
  1090.                         line:   line,
  1091.                         col:    col
  1092.                     });
  1093.                 }
  1094.  
  1095.             },
  1096.  
  1097.             _supports: function(emit) {
  1098.                 /*
  1099.                  * supports_rule
  1100.                  *  : SUPPORTS_SYM S* supports_condition S* group_rule_body
  1101.                  *  ;
  1102.                  */
  1103.                 var tokenStream = this._tokenStream,
  1104.                     line,
  1105.                     col;
  1106.  
  1107.                 if (tokenStream.match(Tokens.SUPPORTS_SYM)) {
  1108.                     line = tokenStream.token().startLine;
  1109.                     col = tokenStream.token().startCol;
  1110.  
  1111.                     this._readWhitespace();
  1112.                     this._supports_condition();
  1113.                     this._readWhitespace();
  1114.  
  1115.                     tokenStream.mustMatch(Tokens.LBRACE);
  1116.                     this._readWhitespace();
  1117.  
  1118.                     if (emit !== false) {
  1119.                         this.fire({
  1120.                             type:   "startsupports",
  1121.                             line:   line,
  1122.                             col:    col
  1123.                         });
  1124.                     }
  1125.  
  1126.                     while (true) {
  1127.                         if (!this._ruleset()) {
  1128.                             break;
  1129.                         }
  1130.                     }
  1131.  
  1132.                     tokenStream.mustMatch(Tokens.RBRACE);
  1133.                     this._readWhitespace();
  1134.  
  1135.                     this.fire({
  1136.                         type:   "endsupports",
  1137.                         line:   line,
  1138.                         col:    col
  1139.                     });
  1140.                 }
  1141.             },
  1142.  
  1143.             _supports_condition: function() {
  1144.                 /*
  1145.                  * supports_condition
  1146.                  *  : supports_negation | supports_conjunction | supports_disjunction |
  1147.                  *    supports_condition_in_parens
  1148.                  *  ;
  1149.                  */
  1150.                 var tokenStream = this._tokenStream,
  1151.                     ident;
  1152.  
  1153.                 if (tokenStream.match(Tokens.IDENT)) {
  1154.                     ident = tokenStream.token().value.toLowerCase();
  1155.  
  1156.                     if (ident === "not") {
  1157.                         tokenStream.mustMatch(Tokens.S);
  1158.                         this._supports_condition_in_parens();
  1159.                     } else {
  1160.                         tokenStream.unget();
  1161.                     }
  1162.                 } else {
  1163.                     this._supports_condition_in_parens();
  1164.                     this._readWhitespace();
  1165.  
  1166.                     while (tokenStream.peek() === Tokens.IDENT) {
  1167.                         ident = tokenStream.LT(1).value.toLowerCase();
  1168.                         if (ident === "and" || ident === "or") {
  1169.                             tokenStream.mustMatch(Tokens.IDENT);
  1170.                             this._readWhitespace();
  1171.                             this._supports_condition_in_parens();
  1172.                             this._readWhitespace();
  1173.                         }
  1174.                     }
  1175.                 }
  1176.             },
  1177.  
  1178.             _supports_condition_in_parens: function() {
  1179.                 /*
  1180.                  * supports_condition_in_parens
  1181.                  *  : ( '(' S* supports_condition S* ')' ) | supports_declaration_condition |
  1182.                  *    general_enclosed
  1183.                  *  ;
  1184.                  */
  1185.                 var tokenStream = this._tokenStream,
  1186.                     ident;
  1187.  
  1188.                 if (tokenStream.match(Tokens.LPAREN)) {
  1189.                     this._readWhitespace();
  1190.                     if (tokenStream.match(Tokens.IDENT)) {
  1191.                         // look ahead for not keyword, if not given, continue with declaration condition.
  1192.                         ident = tokenStream.token().value.toLowerCase();
  1193.                         if (ident === "not") {
  1194.                             this._readWhitespace();
  1195.                             this._supports_condition();
  1196.                             this._readWhitespace();
  1197.                             tokenStream.mustMatch(Tokens.RPAREN);
  1198.                         } else {
  1199.                             tokenStream.unget();
  1200.                             this._supports_declaration_condition(false);
  1201.                         }
  1202.                     } else {
  1203.                         this._supports_condition();
  1204.                         this._readWhitespace();
  1205.                         tokenStream.mustMatch(Tokens.RPAREN);
  1206.                     }
  1207.                 } else {
  1208.                     this._supports_declaration_condition();
  1209.                 }
  1210.             },
  1211.  
  1212.             _supports_declaration_condition: function(requireStartParen) {
  1213.                 /*
  1214.                  * supports_declaration_condition
  1215.                  *  : '(' S* declaration ')'
  1216.                  *  ;
  1217.                  */
  1218.                 var tokenStream = this._tokenStream;
  1219.  
  1220.                 if (requireStartParen !== false) {
  1221.                     tokenStream.mustMatch(Tokens.LPAREN);
  1222.                 }
  1223.                 this._readWhitespace();
  1224.                 this._declaration();
  1225.                 tokenStream.mustMatch(Tokens.RPAREN);
  1226.             },
  1227.  
  1228.             _media: function() {
  1229.                 /*
  1230.                  * media
  1231.                  *   : MEDIA_SYM S* media_query_list S* '{' S* ruleset* '}' S*
  1232.                  *   ;
  1233.                  */
  1234.                 var tokenStream     = this._tokenStream,
  1235.                     line,
  1236.                     col,
  1237.                     mediaList;//       = [];
  1238.  
  1239.                 //look for @media
  1240.                 tokenStream.mustMatch(Tokens.MEDIA_SYM);
  1241.                 line = tokenStream.token().startLine;
  1242.                 col = tokenStream.token().startCol;
  1243.  
  1244.                 this._readWhitespace();
  1245.  
  1246.                 mediaList = this._media_query_list();
  1247.  
  1248.                 tokenStream.mustMatch(Tokens.LBRACE);
  1249.                 this._readWhitespace();
  1250.  
  1251.                 this.fire({
  1252.                     type:   "startmedia",
  1253.                     media:  mediaList,
  1254.                     line:   line,
  1255.                     col:    col
  1256.                 });
  1257.  
  1258.                 while (true) {
  1259.                     if (tokenStream.peek() === Tokens.PAGE_SYM) {
  1260.                         this._page();
  1261.                     } else if (tokenStream.peek() === Tokens.FONT_FACE_SYM) {
  1262.                         this._font_face();
  1263.                     } else if (tokenStream.peek() === Tokens.VIEWPORT_SYM) {
  1264.                         this._viewport();
  1265.                     } else if (tokenStream.peek() === Tokens.DOCUMENT_SYM) {
  1266.                         this._document();
  1267.                     } else if (tokenStream.peek() === Tokens.SUPPORTS_SYM) {
  1268.                         this._supports();
  1269.                     } else if (tokenStream.peek() === Tokens.MEDIA_SYM) {
  1270.                         this._media();
  1271.                     } else if (!this._ruleset()) {
  1272.                         break;
  1273.                     }
  1274.                 }
  1275.  
  1276.                 tokenStream.mustMatch(Tokens.RBRACE);
  1277.                 this._readWhitespace();
  1278.  
  1279.                 this.fire({
  1280.                     type:   "endmedia",
  1281.                     media:  mediaList,
  1282.                     line:   line,
  1283.                     col:    col
  1284.                 });
  1285.             },
  1286.  
  1287.  
  1288.             //CSS3 Media Queries
  1289.             _media_query_list: function() {
  1290.                 /*
  1291.                  * media_query_list
  1292.                  *   : S* [media_query [ ',' S* media_query ]* ]?
  1293.                  *   ;
  1294.                  */
  1295.                 var tokenStream = this._tokenStream,
  1296.                     mediaList   = [];
  1297.  
  1298.  
  1299.                 this._readWhitespace();
  1300.  
  1301.                 if (tokenStream.peek() === Tokens.IDENT || tokenStream.peek() === Tokens.LPAREN) {
  1302.                     mediaList.push(this._media_query());
  1303.                 }
  1304.  
  1305.                 while (tokenStream.match(Tokens.COMMA)) {
  1306.                     this._readWhitespace();
  1307.                     mediaList.push(this._media_query());
  1308.                 }
  1309.  
  1310.                 return mediaList;
  1311.             },
  1312.  
  1313.             /*
  1314.              * Note: "expression" in the grammar maps to the _media_expression
  1315.              * method.
  1316.  
  1317.              */
  1318.             _media_query: function() {
  1319.                 /*
  1320.                  * media_query
  1321.                  *   : [ONLY | NOT]? S* media_type S* [ AND S* expression ]*
  1322.                  *   | expression [ AND S* expression ]*
  1323.                  *   ;
  1324.                  */
  1325.                 var tokenStream = this._tokenStream,
  1326.                     type        = null,
  1327.                     ident       = null,
  1328.                     token       = null,
  1329.                     expressions = [];
  1330.  
  1331.                 if (tokenStream.match(Tokens.IDENT)) {
  1332.                     ident = tokenStream.token().value.toLowerCase();
  1333.  
  1334.                     //since there's no custom tokens for these, need to manually check
  1335.                     if (ident !== "only" && ident !== "not") {
  1336.                         tokenStream.unget();
  1337.                         ident = null;
  1338.                     } else {
  1339.                         token = tokenStream.token();
  1340.                     }
  1341.                 }
  1342.  
  1343.                 this._readWhitespace();
  1344.  
  1345.                 if (tokenStream.peek() === Tokens.IDENT) {
  1346.                     type = this._media_type();
  1347.                     if (token === null) {
  1348.                         token = tokenStream.token();
  1349.                     }
  1350.                 } else if (tokenStream.peek() === Tokens.LPAREN) {
  1351.                     if (token === null) {
  1352.                         token = tokenStream.LT(1);
  1353.                     }
  1354.                     expressions.push(this._media_expression());
  1355.                 }
  1356.  
  1357.                 if (type === null && expressions.length === 0) {
  1358.                     return null;
  1359.                 } else {
  1360.                     this._readWhitespace();
  1361.                     while (tokenStream.match(Tokens.IDENT)) {
  1362.                         if (tokenStream.token().value.toLowerCase() !== "and") {
  1363.                             this._unexpectedToken(tokenStream.token());
  1364.                         }
  1365.  
  1366.                         this._readWhitespace();
  1367.                         expressions.push(this._media_expression());
  1368.                     }
  1369.                 }
  1370.  
  1371.                 return new MediaQuery(ident, type, expressions, token.startLine, token.startCol);
  1372.             },
  1373.  
  1374.             //CSS3 Media Queries
  1375.             _media_type: function() {
  1376.                 /*
  1377.                  * media_type
  1378.                  *   : IDENT
  1379.                  *   ;
  1380.                  */
  1381.                 return this._media_feature();
  1382.             },
  1383.  
  1384.             /**
  1385.              * Note: in CSS3 Media Queries, this is called "expression".
  1386.              * Renamed here to avoid conflict with CSS3 Selectors
  1387.              * definition of "expression". Also note that "expr" in the
  1388.              * grammar now maps to "expression" from CSS3 selectors.
  1389.              * @method _media_expression
  1390.              * @private
  1391.              */
  1392.             _media_expression: function() {
  1393.                 /*
  1394.                  * expression
  1395.                  *  : '(' S* media_feature S* [ ':' S* expr ]? ')' S*
  1396.                  *  ;
  1397.                  */
  1398.                 var tokenStream = this._tokenStream,
  1399.                     feature     = null,
  1400.                     token,
  1401.                     expression  = null;
  1402.  
  1403.                 tokenStream.mustMatch(Tokens.LPAREN);
  1404.  
  1405.                 feature = this._media_feature();
  1406.                 this._readWhitespace();
  1407.  
  1408.                 if (tokenStream.match(Tokens.COLON)) {
  1409.                     this._readWhitespace();
  1410.                     token = tokenStream.LT(1);
  1411.                     expression = this._expression();
  1412.                 }
  1413.  
  1414.                 tokenStream.mustMatch(Tokens.RPAREN);
  1415.                 this._readWhitespace();
  1416.  
  1417.                 return new MediaFeature(feature, expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null);
  1418.             },
  1419.  
  1420.             //CSS3 Media Queries
  1421.             _media_feature: function() {
  1422.                 /*
  1423.                  * media_feature
  1424.                  *   : IDENT
  1425.                  *   ;
  1426.                  */
  1427.                 var tokenStream = this._tokenStream;
  1428.  
  1429.                 this._readWhitespace();
  1430.  
  1431.                 tokenStream.mustMatch(Tokens.IDENT);
  1432.  
  1433.                 return SyntaxUnit.fromToken(tokenStream.token());
  1434.             },
  1435.  
  1436.             //CSS3 Paged Media
  1437.             _page: function() {
  1438.                 /*
  1439.                  * page:
  1440.                  *    PAGE_SYM S* IDENT? pseudo_page? S*
  1441.                  *    '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S*
  1442.                  *    ;
  1443.                  */
  1444.                 var tokenStream = this._tokenStream,
  1445.                     line,
  1446.                     col,
  1447.                     identifier  = null,
  1448.                     pseudoPage  = null;
  1449.  
  1450.                 //look for @page
  1451.                 tokenStream.mustMatch(Tokens.PAGE_SYM);
  1452.                 line = tokenStream.token().startLine;
  1453.                 col = tokenStream.token().startCol;
  1454.  
  1455.                 this._readWhitespace();
  1456.  
  1457.                 if (tokenStream.match(Tokens.IDENT)) {
  1458.                     identifier = tokenStream.token().value;
  1459.  
  1460.                     //The value 'auto' may not be used as a page name and MUST be treated as a syntax error.
  1461.                     if (identifier.toLowerCase() === "auto") {
  1462.                         this._unexpectedToken(tokenStream.token());
  1463.                     }
  1464.                 }
  1465.  
  1466.                 //see if there's a colon upcoming
  1467.                 if (tokenStream.peek() === Tokens.COLON) {
  1468.                     pseudoPage = this._pseudo_page();
  1469.                 }
  1470.  
  1471.                 this._readWhitespace();
  1472.  
  1473.                 this.fire({
  1474.                     type:   "startpage",
  1475.                     id:     identifier,
  1476.                     pseudo: pseudoPage,
  1477.                     line:   line,
  1478.                     col:    col
  1479.                 });
  1480.  
  1481.                 this._readDeclarations(true, true);
  1482.  
  1483.                 this.fire({
  1484.                     type:   "endpage",
  1485.                     id:     identifier,
  1486.                     pseudo: pseudoPage,
  1487.                     line:   line,
  1488.                     col:    col
  1489.                 });
  1490.  
  1491.             },
  1492.  
  1493.             //CSS3 Paged Media
  1494.             _margin: function() {
  1495.                 /*
  1496.                  * margin :
  1497.                  *    margin_sym S* '{' declaration [ ';' S* declaration? ]* '}' S*
  1498.                  *    ;
  1499.                  */
  1500.                 var tokenStream = this._tokenStream,
  1501.                     line,
  1502.                     col,
  1503.                     marginSym   = this._margin_sym();
  1504.  
  1505.                 if (marginSym) {
  1506.                     line = tokenStream.token().startLine;
  1507.                     col = tokenStream.token().startCol;
  1508.  
  1509.                     this.fire({
  1510.                         type: "startpagemargin",
  1511.                         margin: marginSym,
  1512.                         line:   line,
  1513.                         col:    col
  1514.                     });
  1515.  
  1516.                     this._readDeclarations(true);
  1517.  
  1518.                     this.fire({
  1519.                         type: "endpagemargin",
  1520.                         margin: marginSym,
  1521.                         line:   line,
  1522.                         col:    col
  1523.                     });
  1524.                     return true;
  1525.                 } else {
  1526.                     return false;
  1527.                 }
  1528.             },
  1529.  
  1530.             //CSS3 Paged Media
  1531.             _margin_sym: function() {
  1532.  
  1533.                 /*
  1534.                  * margin_sym :
  1535.                  *    TOPLEFTCORNER_SYM |
  1536.                  *    TOPLEFT_SYM |
  1537.                  *    TOPCENTER_SYM |
  1538.                  *    TOPRIGHT_SYM |
  1539.                  *    TOPRIGHTCORNER_SYM |
  1540.                  *    BOTTOMLEFTCORNER_SYM |
  1541.                  *    BOTTOMLEFT_SYM |
  1542.                  *    BOTTOMCENTER_SYM |
  1543.                  *    BOTTOMRIGHT_SYM |
  1544.                  *    BOTTOMRIGHTCORNER_SYM |
  1545.                  *    LEFTTOP_SYM |
  1546.                  *    LEFTMIDDLE_SYM |
  1547.                  *    LEFTBOTTOM_SYM |
  1548.                  *    RIGHTTOP_SYM |
  1549.                  *    RIGHTMIDDLE_SYM |
  1550.                  *    RIGHTBOTTOM_SYM
  1551.                  *    ;
  1552.                  */
  1553.  
  1554.                 var tokenStream = this._tokenStream;
  1555.  
  1556.                 if (tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM,
  1557.                         Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM,
  1558.                         Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM,
  1559.                         Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM,
  1560.                         Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM,
  1561.                         Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM,
  1562.                         Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM])) {
  1563.                     return SyntaxUnit.fromToken(tokenStream.token());
  1564.                 } else {
  1565.                     return null;
  1566.                 }
  1567.  
  1568.             },
  1569.  
  1570.             _pseudo_page: function() {
  1571.                 /*
  1572.                  * pseudo_page
  1573.                  *   : ':' IDENT
  1574.                  *   ;
  1575.                  */
  1576.  
  1577.                 var tokenStream = this._tokenStream;
  1578.  
  1579.                 tokenStream.mustMatch(Tokens.COLON);
  1580.                 tokenStream.mustMatch(Tokens.IDENT);
  1581.  
  1582.                 //TODO: CSS3 Paged Media says only "left", "center", and "right" are allowed
  1583.  
  1584.                 return tokenStream.token().value;
  1585.             },
  1586.  
  1587.             _font_face: function() {
  1588.                 /*
  1589.                  * font_face
  1590.                  *   : FONT_FACE_SYM S*
  1591.                  *     '{' S* declaration [ ';' S* declaration ]* '}' S*
  1592.                  *   ;
  1593.                  */
  1594.                 var tokenStream = this._tokenStream,
  1595.                     line,
  1596.                     col;
  1597.  
  1598.                 //look for @page
  1599.                 tokenStream.mustMatch(Tokens.FONT_FACE_SYM);
  1600.                 line = tokenStream.token().startLine;
  1601.                 col = tokenStream.token().startCol;
  1602.  
  1603.                 this._readWhitespace();
  1604.  
  1605.                 this.fire({
  1606.                     type:   "startfontface",
  1607.                     line:   line,
  1608.                     col:    col
  1609.                 });
  1610.  
  1611.                 this._readDeclarations(true);
  1612.  
  1613.                 this.fire({
  1614.                     type:   "endfontface",
  1615.                     line:   line,
  1616.                     col:    col
  1617.                 });
  1618.             },
  1619.  
  1620.             _viewport: function() {
  1621.                 /*
  1622.                  * viewport
  1623.                  *   : VIEWPORT_SYM S*
  1624.                  *     '{' S* declaration? [ ';' S* declaration? ]* '}' S*
  1625.                  *   ;
  1626.                  */
  1627.                 var tokenStream = this._tokenStream,
  1628.                     line,
  1629.                     col;
  1630.  
  1631.                 tokenStream.mustMatch(Tokens.VIEWPORT_SYM);
  1632.                 line = tokenStream.token().startLine;
  1633.                 col = tokenStream.token().startCol;
  1634.  
  1635.                 this._readWhitespace();
  1636.  
  1637.                 this.fire({
  1638.                     type:   "startviewport",
  1639.                     line:   line,
  1640.                     col:    col
  1641.                 });
  1642.  
  1643.                 this._readDeclarations(true);
  1644.  
  1645.                 this.fire({
  1646.                     type:   "endviewport",
  1647.                     line:   line,
  1648.                     col:    col
  1649.                 });
  1650.  
  1651.             },
  1652.  
  1653.             _document: function() {
  1654.                 /*
  1655.                  * document
  1656.                  *   : DOCUMENT_SYM S*
  1657.                  *     _document_function [ ',' S* _document_function ]* S*
  1658.                  *     '{' S* ruleset* '}'
  1659.                  *   ;
  1660.                  */
  1661.  
  1662.                 var tokenStream = this._tokenStream,
  1663.                     token,
  1664.                     functions = [],
  1665.                     prefix = "";
  1666.  
  1667.                 tokenStream.mustMatch(Tokens.DOCUMENT_SYM);
  1668.                 token = tokenStream.token();
  1669.                 if (/^@\-([^\-]+)\-/.test(token.value)) {
  1670.                     prefix = RegExp.$1;
  1671.                 }
  1672.  
  1673.                 this._readWhitespace();
  1674.                 functions.push(this._document_function());
  1675.  
  1676.                 while (tokenStream.match(Tokens.COMMA)) {
  1677.                     this._readWhitespace();
  1678.                     functions.push(this._document_function());
  1679.                 }
  1680.  
  1681.                 tokenStream.mustMatch(Tokens.LBRACE);
  1682.                 this._readWhitespace();
  1683.  
  1684.                 this.fire({
  1685.                     type:      "startdocument",
  1686.                     functions: functions,
  1687.                     prefix:    prefix,
  1688.                     line:      token.startLine,
  1689.                     col:       token.startCol
  1690.                 });
  1691.  
  1692.                 var ok = true;
  1693.                 while (ok) {
  1694.                     switch (tokenStream.peek()) {
  1695.                         case Tokens.PAGE_SYM:
  1696.                             this._page();
  1697.                             break;
  1698.                         case Tokens.FONT_FACE_SYM:
  1699.                             this._font_face();
  1700.                             break;
  1701.                         case Tokens.VIEWPORT_SYM:
  1702.                             this._viewport();
  1703.                             break;
  1704.                         case Tokens.MEDIA_SYM:
  1705.                             this._media();
  1706.                             break;
  1707.                         case Tokens.KEYFRAMES_SYM:
  1708.                             this._keyframes();
  1709.                             break;
  1710.                         case Tokens.DOCUMENT_SYM:
  1711.                             this._document();
  1712.                             break;
  1713.                         default:
  1714.                             ok = Boolean(this._ruleset());
  1715.                     }
  1716.                 }
  1717.  
  1718.                 tokenStream.mustMatch(Tokens.RBRACE);
  1719.                 token = tokenStream.token();
  1720.                 this._readWhitespace();
  1721.  
  1722.                 this.fire({
  1723.                     type:      "enddocument",
  1724.                     functions: functions,
  1725.                     prefix:    prefix,
  1726.                     line:      token.startLine,
  1727.                     col:       token.startCol
  1728.                 });
  1729.             },
  1730.  
  1731.             _document_function: function() {
  1732.                 /*
  1733.                  * document_function
  1734.                  *   : function | URI S*
  1735.                  *   ;
  1736.                  */
  1737.  
  1738.                 var tokenStream = this._tokenStream,
  1739.                     value;
  1740.  
  1741.                 if (tokenStream.match(Tokens.URI)) {
  1742.                     value = tokenStream.token().value;
  1743.                     this._readWhitespace();
  1744.                 } else {
  1745.                     value = this._function();
  1746.                 }
  1747.  
  1748.                 return value;
  1749.             },
  1750.  
  1751.             _operator: function(inFunction) {
  1752.  
  1753.                 /*
  1754.                  * operator (outside function)
  1755.                  *  : '/' S* | ',' S* | /( empty )/
  1756.                  * operator (inside function)
  1757.                  *  : '/' S* | '+' S* | '*' S* | '-' S* /( empty )/
  1758.                  *  ;
  1759.                  */
  1760.  
  1761.                 var tokenStream = this._tokenStream,
  1762.                     token       = null;
  1763.  
  1764.                 if (tokenStream.match([Tokens.SLASH, Tokens.COMMA]) ||
  1765.                     (inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS]))) {
  1766.                     token =  tokenStream.token();
  1767.                     this._readWhitespace();
  1768.                 }
  1769.                 return token ? PropertyValuePart.fromToken(token) : null;
  1770.  
  1771.             },
  1772.  
  1773.             _combinator: function() {
  1774.  
  1775.                 /*
  1776.                  * combinator
  1777.                  *  : PLUS S* | GREATER S* | TILDE S* | S+
  1778.                  *  ;
  1779.                  */
  1780.  
  1781.                 var tokenStream = this._tokenStream,
  1782.                     value       = null,
  1783.                     token;
  1784.  
  1785.                 if (tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])) {
  1786.                     token = tokenStream.token();
  1787.                     value = new Combinator(token.value, token.startLine, token.startCol);
  1788.                     this._readWhitespace();
  1789.                 }
  1790.  
  1791.                 return value;
  1792.             },
  1793.  
  1794.             _unary_operator: function() {
  1795.  
  1796.                 /*
  1797.                  * unary_operator
  1798.                  *  : '-' | '+'
  1799.                  *  ;
  1800.                  */
  1801.  
  1802.                 var tokenStream = this._tokenStream;
  1803.  
  1804.                 if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])) {
  1805.                     return tokenStream.token().value;
  1806.                 } else {
  1807.                     return null;
  1808.                 }
  1809.             },
  1810.  
  1811.             _property: function() {
  1812.  
  1813.                 /*
  1814.                  * property
  1815.                  *   : IDENT S*
  1816.                  *   ;
  1817.                  */
  1818.  
  1819.                 var tokenStream = this._tokenStream,
  1820.                     value       = null,
  1821.                     hack        = null,
  1822.                     tokenValue,
  1823.                     token,
  1824.                     line,
  1825.                     col;
  1826.  
  1827.                 //check for star hack - throws error if not allowed
  1828.                 if (tokenStream.peek() === Tokens.STAR && this.options.starHack) {
  1829.                     tokenStream.get();
  1830.                     token = tokenStream.token();
  1831.                     hack = token.value;
  1832.                     line = token.startLine;
  1833.                     col = token.startCol;
  1834.                 }
  1835.  
  1836.                 if (tokenStream.match(Tokens.IDENT)) {
  1837.                     token = tokenStream.token();
  1838.                     tokenValue = token.value;
  1839.  
  1840.                     //check for underscore hack - no error if not allowed because it's valid CSS syntax
  1841.                     if (tokenValue.charAt(0) === "_" && this.options.underscoreHack) {
  1842.                         hack = "_";
  1843.                         tokenValue = tokenValue.substring(1);
  1844.                     }
  1845.  
  1846.                     value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol));
  1847.                     this._readWhitespace();
  1848.                 }
  1849.  
  1850.                 return value;
  1851.             },
  1852.  
  1853.             //Augmented with CSS3 Selectors
  1854.             _ruleset: function() {
  1855.                 /*
  1856.                  * ruleset
  1857.                  *   : selectors_group
  1858.                  *     '{' S* declaration? [ ';' S* declaration? ]* '}' S*
  1859.                  *   ;
  1860.                  */
  1861.  
  1862.                 var tokenStream = this._tokenStream,
  1863.                     tt,
  1864.                     selectors;
  1865.  
  1866.  
  1867.                 /*
  1868.                  * Error Recovery: If even a single selector fails to parse,
  1869.                  * then the entire ruleset should be thrown away.
  1870.                  */
  1871.                 try {
  1872.                     selectors = this._selectors_group();
  1873.                 } catch (ex) {
  1874.                     if (ex instanceof SyntaxError && !this.options.strict) {
  1875.  
  1876.                         //fire error event
  1877.                         this.fire({
  1878.                             type:       "error",
  1879.                             error:      ex,
  1880.                             message:    ex.message,
  1881.                             line:       ex.line,
  1882.                             col:        ex.col
  1883.                         });
  1884.  
  1885.                         //skip over everything until closing brace
  1886.                         tt = tokenStream.advance([Tokens.RBRACE]);
  1887.                         if (tt === Tokens.RBRACE) {
  1888.                             //if there's a right brace, the rule is finished so don't do anything
  1889.                         } else {
  1890.                             //otherwise, rethrow the error because it wasn't handled properly
  1891.                             throw ex;
  1892.                         }
  1893.  
  1894.                     } else {
  1895.                         //not a syntax error, rethrow it
  1896.                         throw ex;
  1897.                     }
  1898.  
  1899.                     //trigger parser to continue
  1900.                     return true;
  1901.                 }
  1902.  
  1903.                 //if it got here, all selectors parsed
  1904.                 if (selectors) {
  1905.  
  1906.                     this.fire({
  1907.                         type:       "startrule",
  1908.                         selectors:  selectors,
  1909.                         line:       selectors[0].line,
  1910.                         col:        selectors[0].col
  1911.                     });
  1912.  
  1913.                     this._readDeclarations(true);
  1914.  
  1915.                     this.fire({
  1916.                         type:       "endrule",
  1917.                         selectors:  selectors,
  1918.                         line:       selectors[0].line,
  1919.                         col:        selectors[0].col
  1920.                     });
  1921.  
  1922.                 }
  1923.  
  1924.                 return selectors;
  1925.  
  1926.             },
  1927.  
  1928.             //CSS3 Selectors
  1929.             _selectors_group: function() {
  1930.  
  1931.                 /*
  1932.                  * selectors_group
  1933.                  *   : selector [ COMMA S* selector ]*
  1934.                  *   ;
  1935.                  */
  1936.                 var tokenStream = this._tokenStream,
  1937.                     selectors   = [],
  1938.                     selector;
  1939.  
  1940.                 selector = this._selector();
  1941.                 if (selector !== null) {
  1942.  
  1943.                     selectors.push(selector);
  1944.                     while (tokenStream.match(Tokens.COMMA)) {
  1945.                         this._readWhitespace();
  1946.                         selector = this._selector();
  1947.                         if (selector !== null) {
  1948.                             selectors.push(selector);
  1949.                         } else {
  1950.                             this._unexpectedToken(tokenStream.LT(1));
  1951.                         }
  1952.                     }
  1953.                 }
  1954.  
  1955.                 return selectors.length ? selectors : null;
  1956.             },
  1957.  
  1958.             //CSS3 Selectors
  1959.             _selector: function() {
  1960.                 /*
  1961.                  * selector
  1962.                  *   : simple_selector_sequence [ combinator simple_selector_sequence ]*
  1963.                  *   ;
  1964.                  */
  1965.  
  1966.                 var tokenStream = this._tokenStream,
  1967.                     selector    = [],
  1968.                     nextSelector = null,
  1969.                     combinator  = null,
  1970.                     ws          = null;
  1971.  
  1972.                 //if there's no simple selector, then there's no selector
  1973.                 nextSelector = this._simple_selector_sequence();
  1974.                 if (nextSelector === null) {
  1975.                     return null;
  1976.                 }
  1977.  
  1978.                 selector.push(nextSelector);
  1979.  
  1980.                 do {
  1981.  
  1982.                     //look for a combinator
  1983.                     combinator = this._combinator();
  1984.  
  1985.                     if (combinator !== null) {
  1986.                         selector.push(combinator);
  1987.                         nextSelector = this._simple_selector_sequence();
  1988.  
  1989.                         //there must be a next selector
  1990.                         if (nextSelector === null) {
  1991.                             this._unexpectedToken(tokenStream.LT(1));
  1992.                         } else {
  1993.  
  1994.                             //nextSelector is an instance of SelectorPart
  1995.                             selector.push(nextSelector);
  1996.                         }
  1997.                     } else {
  1998.  
  1999.                         //if there's not whitespace, we're done
  2000.                         if (this._readWhitespace()) {
  2001.  
  2002.                             //add whitespace separator
  2003.                             ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol);
  2004.  
  2005.                             //combinator is not required
  2006.                             combinator = this._combinator();
  2007.  
  2008.                             //selector is required if there's a combinator
  2009.                             nextSelector = this._simple_selector_sequence();
  2010.                             if (nextSelector === null) {
  2011.                                 if (combinator !== null) {
  2012.                                     this._unexpectedToken(tokenStream.LT(1));
  2013.                                 }
  2014.                             } else {
  2015.  
  2016.                                 if (combinator !== null) {
  2017.                                     selector.push(combinator);
  2018.                                 } else {
  2019.                                     selector.push(ws);
  2020.                                 }
  2021.  
  2022.                                 selector.push(nextSelector);
  2023.                             }
  2024.                         } else {
  2025.                             break;
  2026.                         }
  2027.  
  2028.                     }
  2029.                 } while (true);
  2030.  
  2031.                 return new Selector(selector, selector[0].line, selector[0].col);
  2032.             },
  2033.  
  2034.             //CSS3 Selectors
  2035.             _simple_selector_sequence: function() {
  2036.                 /*
  2037.                  * simple_selector_sequence
  2038.                  *   : [ type_selector | universal ]
  2039.                  *     [ HASH | class | attrib | pseudo | negation ]*
  2040.                  *   | [ HASH | class | attrib | pseudo | negation ]+
  2041.                  *   ;
  2042.                  */
  2043.  
  2044.                 var tokenStream = this._tokenStream,
  2045.  
  2046.                     //parts of a simple selector
  2047.                     elementName = null,
  2048.                     modifiers   = [],
  2049.  
  2050.                     //complete selector text
  2051.                     selectorText= "",
  2052.  
  2053.                     //the different parts after the element name to search for
  2054.                     components  = [
  2055.                         //HASH
  2056.                         function() {
  2057.                             return tokenStream.match(Tokens.HASH) ?
  2058.                                     new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) :
  2059.                                     null;
  2060.                         },
  2061.                         this._class,
  2062.                         this._attrib,
  2063.                         this._pseudo,
  2064.                         this._negation
  2065.                     ],
  2066.                     i           = 0,
  2067.                     len         = components.length,
  2068.                     component   = null,
  2069.                     line,
  2070.                     col;
  2071.  
  2072.  
  2073.                 //get starting line and column for the selector
  2074.                 line = tokenStream.LT(1).startLine;
  2075.                 col = tokenStream.LT(1).startCol;
  2076.  
  2077.                 elementName = this._type_selector();
  2078.                 if (!elementName) {
  2079.                     elementName = this._universal();
  2080.                 }
  2081.  
  2082.                 if (elementName !== null) {
  2083.                     selectorText += elementName;
  2084.                 }
  2085.  
  2086.                 while (true) {
  2087.  
  2088.                     //whitespace means we're done
  2089.                     if (tokenStream.peek() === Tokens.S) {
  2090.                         break;
  2091.                     }
  2092.  
  2093.                     //check for each component
  2094.                     while (i < len && component === null) {
  2095.                         component = components[i++].call(this);
  2096.                     }
  2097.  
  2098.                     if (component === null) {
  2099.  
  2100.                         //we don't have a selector
  2101.                         if (selectorText === "") {
  2102.                             return null;
  2103.                         } else {
  2104.                             break;
  2105.                         }
  2106.                     } else {
  2107.                         i = 0;
  2108.                         modifiers.push(component);
  2109.                         selectorText += component.toString();
  2110.                         component = null;
  2111.                     }
  2112.                 }
  2113.  
  2114.  
  2115.                 return selectorText !== "" ?
  2116.                         new SelectorPart(elementName, modifiers, selectorText, line, col) :
  2117.                         null;
  2118.             },
  2119.  
  2120.             //CSS3 Selectors
  2121.             _type_selector: function() {
  2122.                 /*
  2123.                  * type_selector
  2124.                  *   : [ namespace_prefix ]? element_name
  2125.                  *   ;
  2126.                  */
  2127.  
  2128.                 var tokenStream = this._tokenStream,
  2129.                     ns          = this._namespace_prefix(),
  2130.                     elementName = this._element_name();
  2131.  
  2132.                 if (!elementName) {
  2133.                     /*
  2134.                      * Need to back out the namespace that was read due to both
  2135.                      * type_selector and universal reading namespace_prefix
  2136.                      * first. Kind of hacky, but only way I can figure out
  2137.                      * right now how to not change the grammar.
  2138.                      */
  2139.                     if (ns) {
  2140.                         tokenStream.unget();
  2141.                         if (ns.length > 1) {
  2142.                             tokenStream.unget();
  2143.                         }
  2144.                     }
  2145.  
  2146.                     return null;
  2147.                 } else {
  2148.                     if (ns) {
  2149.                         elementName.text = ns + elementName.text;
  2150.                         elementName.col -= ns.length;
  2151.                     }
  2152.                     return elementName;
  2153.                 }
  2154.             },
  2155.  
  2156.             //CSS3 Selectors
  2157.             _class: function() {
  2158.                 /*
  2159.                  * class
  2160.                  *   : '.' IDENT
  2161.                  *   ;
  2162.                  */
  2163.  
  2164.                 var tokenStream = this._tokenStream,
  2165.                     token;
  2166.  
  2167.                 if (tokenStream.match(Tokens.DOT)) {
  2168.                     tokenStream.mustMatch(Tokens.IDENT);
  2169.                     token = tokenStream.token();
  2170.                     return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1);
  2171.                 } else {
  2172.                     return null;
  2173.                 }
  2174.  
  2175.             },
  2176.  
  2177.             //CSS3 Selectors
  2178.             _element_name: function() {
  2179.                 /*
  2180.                  * element_name
  2181.                  *   : IDENT
  2182.                  *   ;
  2183.                  */
  2184.  
  2185.                 var tokenStream = this._tokenStream,
  2186.                     token;
  2187.  
  2188.                 if (tokenStream.match(Tokens.IDENT)) {
  2189.                     token = tokenStream.token();
  2190.                     return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol);
  2191.  
  2192.                 } else {
  2193.                     return null;
  2194.                 }
  2195.             },
  2196.  
  2197.             //CSS3 Selectors
  2198.             _namespace_prefix: function() {
  2199.                 /*
  2200.                  * namespace_prefix
  2201.                  *   : [ IDENT | '*' ]? '|'
  2202.                  *   ;
  2203.                  */
  2204.                 var tokenStream = this._tokenStream,
  2205.                     value       = "";
  2206.  
  2207.                 //verify that this is a namespace prefix
  2208.                 if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE) {
  2209.  
  2210.                     if (tokenStream.match([Tokens.IDENT, Tokens.STAR])) {
  2211.                         value += tokenStream.token().value;
  2212.                     }
  2213.  
  2214.                     tokenStream.mustMatch(Tokens.PIPE);
  2215.                     value += "|";
  2216.  
  2217.                 }
  2218.  
  2219.                 return value.length ? value : null;
  2220.             },
  2221.  
  2222.             //CSS3 Selectors
  2223.             _universal: function() {
  2224.                 /*
  2225.                  * universal
  2226.                  *   : [ namespace_prefix ]? '*'
  2227.                  *   ;
  2228.                  */
  2229.                 var tokenStream = this._tokenStream,
  2230.                     value       = "",
  2231.                     ns;
  2232.  
  2233.                 ns = this._namespace_prefix();
  2234.                 if (ns) {
  2235.                     value += ns;
  2236.                 }
  2237.  
  2238.                 if (tokenStream.match(Tokens.STAR)) {
  2239.                     value += "*";
  2240.                 }
  2241.  
  2242.                 return value.length ? value : null;
  2243.  
  2244.             },
  2245.  
  2246.             //CSS3 Selectors
  2247.             _attrib: function() {
  2248.                 /*
  2249.                  * attrib
  2250.                  *   : '[' S* [ namespace_prefix ]? IDENT S*
  2251.                  *         [ [ PREFIXMATCH |
  2252.                  *             SUFFIXMATCH |
  2253.                  *             SUBSTRINGMATCH |
  2254.                  *             '=' |
  2255.                  *             INCLUDES |
  2256.                  *             DASHMATCH ] S* [ IDENT | STRING ] S*
  2257.                  *         ]? ']'
  2258.                  *   ;
  2259.                  */
  2260.  
  2261.                 var tokenStream = this._tokenStream,
  2262.                     value       = null,
  2263.                     ns,
  2264.                     token;
  2265.  
  2266.                 if (tokenStream.match(Tokens.LBRACKET)) {
  2267.                     token = tokenStream.token();
  2268.                     value = token.value;
  2269.                     value += this._readWhitespace();
  2270.  
  2271.                     ns = this._namespace_prefix();
  2272.  
  2273.                     if (ns) {
  2274.                         value += ns;
  2275.                     }
  2276.  
  2277.                     tokenStream.mustMatch(Tokens.IDENT);
  2278.                     value += tokenStream.token().value;
  2279.                     value += this._readWhitespace();
  2280.  
  2281.                     if (tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH,
  2282.                             Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])) {
  2283.  
  2284.                         value += tokenStream.token().value;
  2285.                         value += this._readWhitespace();
  2286.  
  2287.                         tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);
  2288.                         value += tokenStream.token().value;
  2289.                         value += this._readWhitespace();
  2290.                     }
  2291.  
  2292.                     tokenStream.mustMatch(Tokens.RBRACKET);
  2293.  
  2294.                     return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol);
  2295.                 } else {
  2296.                     return null;
  2297.                 }
  2298.             },
  2299.  
  2300.             //CSS3 Selectors
  2301.             _pseudo: function() {
  2302.  
  2303.                 /*
  2304.                  * pseudo
  2305.                  *   : ':' ':'? [ IDENT | functional_pseudo ]
  2306.                  *   ;
  2307.                  */
  2308.  
  2309.                 var tokenStream = this._tokenStream,
  2310.                     pseudo      = null,
  2311.                     colons      = ":",
  2312.                     line,
  2313.                     col;
  2314.  
  2315.                 if (tokenStream.match(Tokens.COLON)) {
  2316.  
  2317.                     if (tokenStream.match(Tokens.COLON)) {
  2318.                         colons += ":";
  2319.                     }
  2320.  
  2321.                     if (tokenStream.match(Tokens.IDENT)) {
  2322.                         pseudo = tokenStream.token().value;
  2323.                         line = tokenStream.token().startLine;
  2324.                         col = tokenStream.token().startCol - colons.length;
  2325.                     } else if (tokenStream.peek() === Tokens.FUNCTION) {
  2326.                         line = tokenStream.LT(1).startLine;
  2327.                         col = tokenStream.LT(1).startCol - colons.length;
  2328.                         pseudo = this._functional_pseudo();
  2329.                     }
  2330.  
  2331.                     if (pseudo) {
  2332.                         pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col);
  2333.                     } else {
  2334.                         var startLine = tokenStream.LT(1).startLine,
  2335.                             startCol  = tokenStream.LT(0).startCol;
  2336.                         throw new SyntaxError("Expected a `FUNCTION` or `IDENT` after colon at line " + startLine + ", col " + startCol + ".", startLine, startCol);
  2337.                     }
  2338.                 }
  2339.  
  2340.                 return pseudo;
  2341.             },
  2342.  
  2343.             //CSS3 Selectors
  2344.             _functional_pseudo: function() {
  2345.                 /*
  2346.                  * functional_pseudo
  2347.                  *   : FUNCTION S* expression ')'
  2348.                  *   ;
  2349.                 */
  2350.  
  2351.                 var tokenStream = this._tokenStream,
  2352.                     value = null;
  2353.  
  2354.                 if (tokenStream.match(Tokens.FUNCTION)) {
  2355.                     value = tokenStream.token().value;
  2356.                     value += this._readWhitespace();
  2357.                     value += this._expression();
  2358.                     tokenStream.mustMatch(Tokens.RPAREN);
  2359.                     value += ")";
  2360.                 }
  2361.  
  2362.                 return value;
  2363.             },
  2364.  
  2365.             //CSS3 Selectors
  2366.             _expression: function() {
  2367.                 /*
  2368.                  * expression
  2369.                  *   : [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+
  2370.                  *   ;
  2371.                  */
  2372.  
  2373.                 var tokenStream = this._tokenStream,
  2374.                     value       = "";
  2375.  
  2376.                 while (tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION,
  2377.                         Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH,
  2378.                         Tokens.FREQ, Tokens.ANGLE, Tokens.TIME,
  2379.                         Tokens.RESOLUTION, Tokens.SLASH])) {
  2380.  
  2381.                     value += tokenStream.token().value;
  2382.                     value += this._readWhitespace();
  2383.                 }
  2384.  
  2385.                 return value.length ? value : null;
  2386.  
  2387.             },
  2388.  
  2389.             //CSS3 Selectors
  2390.             _negation: function() {
  2391.                 /*
  2392.                  * negation
  2393.                  *   : NOT S* negation_arg S* ')'
  2394.                  *   ;
  2395.                  */
  2396.  
  2397.                 var tokenStream = this._tokenStream,
  2398.                     line,
  2399.                     col,
  2400.                     value       = "",
  2401.                     arg,
  2402.                     subpart     = null;
  2403.  
  2404.                 if (tokenStream.match(Tokens.NOT)) {
  2405.                     value = tokenStream.token().value;
  2406.                     line = tokenStream.token().startLine;
  2407.                     col = tokenStream.token().startCol;
  2408.                     value += this._readWhitespace();
  2409.                     arg = this._negation_arg();
  2410.                     value += arg;
  2411.                     value += this._readWhitespace();
  2412.                     tokenStream.match(Tokens.RPAREN);
  2413.                     value += tokenStream.token().value;
  2414.  
  2415.                     subpart = new SelectorSubPart(value, "not", line, col);
  2416.                     subpart.args.push(arg);
  2417.                 }
  2418.  
  2419.                 return subpart;
  2420.             },
  2421.  
  2422.             //CSS3 Selectors
  2423.             _negation_arg: function() {
  2424.                 /*
  2425.                  * negation_arg
  2426.                  *   : type_selector | universal | HASH | class | attrib | pseudo
  2427.                  *   ;
  2428.                  */
  2429.  
  2430.                 var tokenStream = this._tokenStream,
  2431.                     args        = [
  2432.                         this._type_selector,
  2433.                         this._universal,
  2434.                         function() {
  2435.                             return tokenStream.match(Tokens.HASH) ?
  2436.                                     new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) :
  2437.                                     null;
  2438.                         },
  2439.                         this._class,
  2440.                         this._attrib,
  2441.                         this._pseudo
  2442.                     ],
  2443.                     arg         = null,
  2444.                     i           = 0,
  2445.                     len         = args.length,
  2446.                     line,
  2447.                     col,
  2448.                     part;
  2449.  
  2450.                 line = tokenStream.LT(1).startLine;
  2451.                 col = tokenStream.LT(1).startCol;
  2452.  
  2453.                 while (i < len && arg === null) {
  2454.  
  2455.                     arg = args[i].call(this);
  2456.                     i++;
  2457.                 }
  2458.  
  2459.                 //must be a negation arg
  2460.                 if (arg === null) {
  2461.                     this._unexpectedToken(tokenStream.LT(1));
  2462.                 }
  2463.  
  2464.                 //it's an element name
  2465.                 if (arg.type === "elementName") {
  2466.                     part = new SelectorPart(arg, [], arg.toString(), line, col);
  2467.                 } else {
  2468.                     part = new SelectorPart(null, [arg], arg.toString(), line, col);
  2469.                 }
  2470.  
  2471.                 return part;
  2472.             },
  2473.  
  2474.             _declaration: function() {
  2475.  
  2476.                 /*
  2477.                  * declaration
  2478.                  *   : property ':' S* expr prio?
  2479.                  *   | /( empty )/
  2480.                  *   ;
  2481.                  */
  2482.  
  2483.                 var tokenStream = this._tokenStream,
  2484.                     property    = null,
  2485.                     expr        = null,
  2486.                     prio        = null,
  2487.                     invalid     = null,
  2488.                     propertyName= "";
  2489.  
  2490.                 property = this._property();
  2491.                 if (property !== null) {
  2492.  
  2493.                     tokenStream.mustMatch(Tokens.COLON);
  2494.                     this._readWhitespace();
  2495.  
  2496.                     expr = this._expr();
  2497.  
  2498.                     //if there's no parts for the value, it's an error
  2499.                     if (!expr || expr.length === 0) {
  2500.                         this._unexpectedToken(tokenStream.LT(1));
  2501.                     }
  2502.  
  2503.                     prio = this._prio();
  2504.  
  2505.                     /*
  2506.                      * If hacks should be allowed, then only check the root
  2507.                      * property. If hacks should not be allowed, treat
  2508.                      * _property or *property as invalid properties.
  2509.                      */
  2510.                     propertyName = property.toString();
  2511.                     if (this.options.starHack && property.hack === "*" ||
  2512.                             this.options.underscoreHack && property.hack === "_") {
  2513.  
  2514.                         propertyName = property.text;
  2515.                     }
  2516.  
  2517.                     try {
  2518.                         this._validateProperty(propertyName, expr);
  2519.                     } catch (ex) {
  2520.                         invalid = ex;
  2521.                     }
  2522.  
  2523.                     this.fire({
  2524.                         type:       "property",
  2525.                         property:   property,
  2526.                         value:      expr,
  2527.                         important:  prio,
  2528.                         line:       property.line,
  2529.                         col:        property.col,
  2530.                         invalid:    invalid
  2531.                     });
  2532.  
  2533.                     return true;
  2534.                 } else {
  2535.                     return false;
  2536.                 }
  2537.             },
  2538.  
  2539.             _prio: function() {
  2540.                 /*
  2541.                  * prio
  2542.                  *   : IMPORTANT_SYM S*
  2543.                  *   ;
  2544.                  */
  2545.  
  2546.                 var tokenStream = this._tokenStream,
  2547.                     result      = tokenStream.match(Tokens.IMPORTANT_SYM);
  2548.  
  2549.                 this._readWhitespace();
  2550.                 return result;
  2551.             },
  2552.  
  2553.             _expr: function(inFunction) {
  2554.                 /*
  2555.                  * expr
  2556.                  *   : term [ operator term ]*
  2557.                  *   ;
  2558.                  */
  2559.  
  2560.                 var values      = [],
  2561.                     //valueParts    = [],
  2562.                     value       = null,
  2563.                     operator    = null;
  2564.  
  2565.                 value = this._term(inFunction);
  2566.                 if (value !== null) {
  2567.  
  2568.                     values.push(value);
  2569.  
  2570.                     do {
  2571.                         operator = this._operator(inFunction);
  2572.  
  2573.                         //if there's an operator, keep building up the value parts
  2574.                         if (operator) {
  2575.                             values.push(operator);
  2576.                         } /*else {
  2577.                             //if there's not an operator, you have a full value
  2578.                             values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col));
  2579.                             valueParts = [];
  2580.                         }*/
  2581.  
  2582.                         value = this._term(inFunction);
  2583.  
  2584.                         if (value === null) {
  2585.                             break;
  2586.                         } else {
  2587.                             values.push(value);
  2588.                         }
  2589.                     } while (true);
  2590.                 }
  2591.  
  2592.                 //cleanup
  2593.                 /*if (valueParts.length) {
  2594.                     values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col));
  2595.                 }*/
  2596.  
  2597.                 return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null;
  2598.             },
  2599.  
  2600.             _term: function(inFunction) {
  2601.  
  2602.                 /*
  2603.                  * term
  2604.                  *   : unary_operator?
  2605.                  *     [ NUMBER S* | PERCENTAGE S* | LENGTH S* | ANGLE S* |
  2606.                  *       TIME S* | FREQ S* | function | ie_function ]
  2607.                  *   | STRING S* | IDENT S* | URI S* | UNICODERANGE S* | hexcolor
  2608.                  *   ;
  2609.                  */
  2610.  
  2611.                 var tokenStream = this._tokenStream,
  2612.                     unary       = null,
  2613.                     value       = null,
  2614.                     endChar     = null,
  2615.                     part        = null,
  2616.                     token,
  2617.                     line,
  2618.                     col;
  2619.  
  2620.                 //returns the operator or null
  2621.                 unary = this._unary_operator();
  2622.                 if (unary !== null) {
  2623.                     line = tokenStream.token().startLine;
  2624.                     col = tokenStream.token().startCol;
  2625.                 }
  2626.  
  2627.                 //exception for IE filters
  2628.                 if (tokenStream.peek() === Tokens.IE_FUNCTION && this.options.ieFilters) {
  2629.  
  2630.                     value = this._ie_function();
  2631.                     if (unary === null) {
  2632.                         line = tokenStream.token().startLine;
  2633.                         col = tokenStream.token().startCol;
  2634.                     }
  2635.  
  2636.                 //see if it's a simple block
  2637.                 } else if (inFunction && tokenStream.match([Tokens.LPAREN, Tokens.LBRACE, Tokens.LBRACKET])) {
  2638.  
  2639.                     token = tokenStream.token();
  2640.                     endChar = token.endChar;
  2641.                     value = token.value + this._expr(inFunction).text;
  2642.                     if (unary === null) {
  2643.                         line = tokenStream.token().startLine;
  2644.                         col = tokenStream.token().startCol;
  2645.                     }
  2646.                     tokenStream.mustMatch(Tokens.type(endChar));
  2647.                     value += endChar;
  2648.                     this._readWhitespace();
  2649.  
  2650.                 //see if there's a simple match
  2651.                 } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH,
  2652.                         Tokens.ANGLE, Tokens.TIME,
  2653.                         Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])) {
  2654.  
  2655.                     value = tokenStream.token().value;
  2656.                     if (unary === null) {
  2657.                         line = tokenStream.token().startLine;
  2658.                         col = tokenStream.token().startCol;
  2659.                         // Correct potentially-inaccurate IDENT parsing in
  2660.                         // PropertyValuePart constructor.
  2661.                         part = PropertyValuePart.fromToken(tokenStream.token());
  2662.                     }
  2663.                     this._readWhitespace();
  2664.                 } else {
  2665.  
  2666.                     //see if it's a color
  2667.                     token = this._hexcolor();
  2668.                     if (token === null) {
  2669.  
  2670.                         //if there's no unary, get the start of the next token for line/col info
  2671.                         if (unary === null) {
  2672.                             line = tokenStream.LT(1).startLine;
  2673.                             col = tokenStream.LT(1).startCol;
  2674.                         }
  2675.  
  2676.                         //has to be a function
  2677.                         if (value === null) {
  2678.  
  2679.                             /*
  2680.                              * This checks for alpha(opacity=0) style of IE
  2681.                              * functions. IE_FUNCTION only presents progid: style.
  2682.                              */
  2683.                             if (tokenStream.LA(3) === Tokens.EQUALS && this.options.ieFilters) {
  2684.                                 value = this._ie_function();
  2685.                             } else {
  2686.                                 value = this._function();
  2687.                             }
  2688.                         }
  2689.  
  2690.                         /*if (value === null) {
  2691.                             return null;
  2692.                             //throw new Error("Expected identifier at line " + tokenStream.token().startLine + ", character " +  tokenStream.token().startCol + ".");
  2693.                         }*/
  2694.  
  2695.                     } else {
  2696.                         value = token.value;
  2697.                         if (unary === null) {
  2698.                             line = token.startLine;
  2699.                             col = token.startCol;
  2700.                         }
  2701.                     }
  2702.  
  2703.                 }
  2704.  
  2705.                 return part !== null ? part : value !== null ?
  2706.                         new PropertyValuePart(unary !== null ? unary + value : value, line, col) :
  2707.                         null;
  2708.  
  2709.             },
  2710.  
  2711.             _function: function() {
  2712.  
  2713.                 /*
  2714.                  * function
  2715.                  *   : FUNCTION S* expr ')' S*
  2716.                  *   ;
  2717.                  */
  2718.  
  2719.                 var tokenStream = this._tokenStream,
  2720.                     functionText = null,
  2721.                     expr        = null,
  2722.                     lt;
  2723.  
  2724.                 if (tokenStream.match(Tokens.FUNCTION)) {
  2725.                     functionText = tokenStream.token().value;
  2726.                     this._readWhitespace();
  2727.                     expr = this._expr(true);
  2728.                     functionText += expr;
  2729.  
  2730.                     //START: Horrible hack in case it's an IE filter
  2731.                     if (this.options.ieFilters && tokenStream.peek() === Tokens.EQUALS) {
  2732.                         do {
  2733.  
  2734.                             if (this._readWhitespace()) {
  2735.                                 functionText += tokenStream.token().value;
  2736.                             }
  2737.  
  2738.                             //might be second time in the loop
  2739.                             if (tokenStream.LA(0) === Tokens.COMMA) {
  2740.                                 functionText += tokenStream.token().value;
  2741.                             }
  2742.  
  2743.                             tokenStream.match(Tokens.IDENT);
  2744.                             functionText += tokenStream.token().value;
  2745.  
  2746.                             tokenStream.match(Tokens.EQUALS);
  2747.                             functionText += tokenStream.token().value;
  2748.  
  2749.                             //functionText += this._term();
  2750.                             lt = tokenStream.peek();
  2751.                             while (lt !== Tokens.COMMA && lt !== Tokens.S && lt !== Tokens.RPAREN) {
  2752.                                 tokenStream.get();
  2753.                                 functionText += tokenStream.token().value;
  2754.                                 lt = tokenStream.peek();
  2755.                             }
  2756.                         } while (tokenStream.match([Tokens.COMMA, Tokens.S]));
  2757.                     }
  2758.  
  2759.                     //END: Horrible Hack
  2760.  
  2761.                     tokenStream.match(Tokens.RPAREN);
  2762.                     functionText += ")";
  2763.                     this._readWhitespace();
  2764.                 }
  2765.  
  2766.                 return functionText;
  2767.             },
  2768.  
  2769.             _ie_function: function() {
  2770.  
  2771.                 /* (My own extension)
  2772.                  * ie_function
  2773.                  *   : IE_FUNCTION S* IDENT '=' term [S* ','? IDENT '=' term]+ ')' S*
  2774.                  *   ;
  2775.                  */
  2776.  
  2777.                 var tokenStream = this._tokenStream,
  2778.                     functionText = null,
  2779.                     lt;
  2780.  
  2781.                 //IE function can begin like a regular function, too
  2782.                 if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])) {
  2783.                     functionText = tokenStream.token().value;
  2784.  
  2785.                     do {
  2786.  
  2787.                         if (this._readWhitespace()) {
  2788.                             functionText += tokenStream.token().value;
  2789.                         }
  2790.  
  2791.                         //might be second time in the loop
  2792.                         if (tokenStream.LA(0) === Tokens.COMMA) {
  2793.                             functionText += tokenStream.token().value;
  2794.                         }
  2795.  
  2796.                         tokenStream.match(Tokens.IDENT);
  2797.                         functionText += tokenStream.token().value;
  2798.  
  2799.                         tokenStream.match(Tokens.EQUALS);
  2800.                         functionText += tokenStream.token().value;
  2801.  
  2802.                         //functionText += this._term();
  2803.                         lt = tokenStream.peek();
  2804.                         while (lt !== Tokens.COMMA && lt !== Tokens.S && lt !== Tokens.RPAREN) {
  2805.                             tokenStream.get();
  2806.                             functionText += tokenStream.token().value;
  2807.                             lt = tokenStream.peek();
  2808.                         }
  2809.                     } while (tokenStream.match([Tokens.COMMA, Tokens.S]));
  2810.  
  2811.                     tokenStream.match(Tokens.RPAREN);
  2812.                     functionText += ")";
  2813.                     this._readWhitespace();
  2814.                 }
  2815.  
  2816.                 return functionText;
  2817.             },
  2818.  
  2819.             _hexcolor: function() {
  2820.                 /*
  2821.                  * There is a constraint on the color that it must
  2822.                  * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F])
  2823.                  * after the "#"; e.g., "#000" is OK, but "#abcd" is not.
  2824.                  *
  2825.                  * hexcolor
  2826.                  *   : HASH S*
  2827.                  *   ;
  2828.                  */
  2829.  
  2830.                 var tokenStream = this._tokenStream,
  2831.                     token = null,
  2832.                     color;
  2833.  
  2834.                 if (tokenStream.match(Tokens.HASH)) {
  2835.  
  2836.                     //need to do some validation here
  2837.  
  2838.                     token = tokenStream.token();
  2839.                     color = token.value;
  2840.                     if (!/#[a-f0-9]{3,6}/i.test(color)) {
  2841.                         throw new SyntaxError("Expected a hex color but found '" + color + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
  2842.                     }
  2843.                     this._readWhitespace();
  2844.                 }
  2845.  
  2846.                 return token;
  2847.             },
  2848.  
  2849.             //-----------------------------------------------------------------
  2850.             // Animations methods
  2851.             //-----------------------------------------------------------------
  2852.  
  2853.             _keyframes: function() {
  2854.  
  2855.                 /*
  2856.                  * keyframes:
  2857.                  *   : KEYFRAMES_SYM S* keyframe_name S* '{' S* keyframe_rule* '}' {
  2858.                  *   ;
  2859.                  */
  2860.                 var tokenStream = this._tokenStream,
  2861.                     token,
  2862.                     tt,
  2863.                     name,
  2864.                     prefix = "";
  2865.  
  2866.                 tokenStream.mustMatch(Tokens.KEYFRAMES_SYM);
  2867.                 token = tokenStream.token();
  2868.                 if (/^@\-([^\-]+)\-/.test(token.value)) {
  2869.                     prefix = RegExp.$1;
  2870.                 }
  2871.  
  2872.                 this._readWhitespace();
  2873.                 name = this._keyframe_name();
  2874.  
  2875.                 this._readWhitespace();
  2876.                 tokenStream.mustMatch(Tokens.LBRACE);
  2877.  
  2878.                 this.fire({
  2879.                     type:   "startkeyframes",
  2880.                     name:   name,
  2881.                     prefix: prefix,
  2882.                     line:   token.startLine,
  2883.                     col:    token.startCol
  2884.                 });
  2885.  
  2886.                 this._readWhitespace();
  2887.                 tt = tokenStream.peek();
  2888.  
  2889.                 //check for key
  2890.                 while (tt === Tokens.IDENT || tt === Tokens.PERCENTAGE) {
  2891.                     this._keyframe_rule();
  2892.                     this._readWhitespace();
  2893.                     tt = tokenStream.peek();
  2894.                 }
  2895.  
  2896.                 this.fire({
  2897.                     type:   "endkeyframes",
  2898.                     name:   name,
  2899.                     prefix: prefix,
  2900.                     line:   token.startLine,
  2901.                     col:    token.startCol
  2902.                 });
  2903.  
  2904.                 this._readWhitespace();
  2905.                 tokenStream.mustMatch(Tokens.RBRACE);
  2906.                 this._readWhitespace();
  2907.  
  2908.             },
  2909.  
  2910.             _keyframe_name: function() {
  2911.  
  2912.                 /*
  2913.                  * keyframe_name:
  2914.                  *   : IDENT
  2915.                  *   | STRING
  2916.                  *   ;
  2917.                  */
  2918.                 var tokenStream = this._tokenStream;
  2919.  
  2920.                 tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);
  2921.                 return SyntaxUnit.fromToken(tokenStream.token());
  2922.             },
  2923.  
  2924.             _keyframe_rule: function() {
  2925.  
  2926.                 /*
  2927.                  * keyframe_rule:
  2928.                  *   : key_list S*
  2929.                  *     '{' S* declaration [ ';' S* declaration ]* '}' S*
  2930.                  *   ;
  2931.                  */
  2932.                 var keyList = this._key_list();
  2933.  
  2934.                 this.fire({
  2935.                     type:   "startkeyframerule",
  2936.                     keys:   keyList,
  2937.                     line:   keyList[0].line,
  2938.                     col:    keyList[0].col
  2939.                 });
  2940.  
  2941.                 this._readDeclarations(true);
  2942.  
  2943.                 this.fire({
  2944.                     type:   "endkeyframerule",
  2945.                     keys:   keyList,
  2946.                     line:   keyList[0].line,
  2947.                     col:    keyList[0].col
  2948.                 });
  2949.  
  2950.             },
  2951.  
  2952.             _key_list: function() {
  2953.  
  2954.                 /*
  2955.                  * key_list:
  2956.                  *   : key [ S* ',' S* key]*
  2957.                  *   ;
  2958.                  */
  2959.                 var tokenStream = this._tokenStream,
  2960.                     keyList = [];
  2961.  
  2962.                 //must be least one key
  2963.                 keyList.push(this._key());
  2964.  
  2965.                 this._readWhitespace();
  2966.  
  2967.                 while (tokenStream.match(Tokens.COMMA)) {
  2968.                     this._readWhitespace();
  2969.                     keyList.push(this._key());
  2970.                     this._readWhitespace();
  2971.                 }
  2972.  
  2973.                 return keyList;
  2974.             },
  2975.  
  2976.             _key: function() {
  2977.                 /*
  2978.                  * There is a restriction that IDENT can be only "from" or "to".
  2979.                  *
  2980.                  * key
  2981.                  *   : PERCENTAGE
  2982.                  *   | IDENT
  2983.                  *   ;
  2984.                  */
  2985.  
  2986.                 var tokenStream = this._tokenStream,
  2987.                     token;
  2988.  
  2989.                 if (tokenStream.match(Tokens.PERCENTAGE)) {
  2990.                     return SyntaxUnit.fromToken(tokenStream.token());
  2991.                 } else if (tokenStream.match(Tokens.IDENT)) {
  2992.                     token = tokenStream.token();
  2993.  
  2994.                     if (/from|to/i.test(token.value)) {
  2995.                         return SyntaxUnit.fromToken(token);
  2996.                     }
  2997.  
  2998.                     tokenStream.unget();
  2999.                 }
  3000.  
  3001.                 //if it gets here, there wasn't a valid token, so time to explode
  3002.                 this._unexpectedToken(tokenStream.LT(1));
  3003.             },
  3004.  
  3005.             //-----------------------------------------------------------------
  3006.             // Helper methods
  3007.             //-----------------------------------------------------------------
  3008.  
  3009.             /**
  3010.              * Not part of CSS grammar, but useful for skipping over
  3011.              * combination of white space and HTML-style comments.
  3012.              * @return {void}
  3013.              * @method _skipCruft
  3014.              * @private
  3015.              */
  3016.             _skipCruft: function() {
  3017.                 while (this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])) {
  3018.                     //noop
  3019.                 }
  3020.             },
  3021.  
  3022.             /**
  3023.              * Not part of CSS grammar, but this pattern occurs frequently
  3024.              * in the official CSS grammar. Split out here to eliminate
  3025.              * duplicate code.
  3026.              * @param {Boolean} checkStart Indicates if the rule should check
  3027.              *      for the left brace at the beginning.
  3028.              * @param {Boolean} readMargins Indicates if the rule should check
  3029.              *      for margin patterns.
  3030.              * @return {void}
  3031.              * @method _readDeclarations
  3032.              * @private
  3033.              */
  3034.             _readDeclarations: function(checkStart, readMargins) {
  3035.                 /*
  3036.                  * Reads the pattern
  3037.                  * S* '{' S* declaration [ ';' S* declaration ]* '}' S*
  3038.                  * or
  3039.                  * S* '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S*
  3040.                  * Note that this is how it is described in CSS3 Paged Media, but is actually incorrect.
  3041.                  * A semicolon is only necessary following a declaration if there's another declaration
  3042.                  * or margin afterwards.
  3043.                  */
  3044.                 var tokenStream = this._tokenStream,
  3045.                     tt;
  3046.  
  3047.  
  3048.                 this._readWhitespace();
  3049.  
  3050.                 if (checkStart) {
  3051.                     tokenStream.mustMatch(Tokens.LBRACE);
  3052.                 }
  3053.  
  3054.                 this._readWhitespace();
  3055.  
  3056.                 try {
  3057.  
  3058.                     while (true) {
  3059.  
  3060.                         if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())) {
  3061.                             //noop
  3062.                         } else if (this._declaration()) {
  3063.                             if (!tokenStream.match(Tokens.SEMICOLON)) {
  3064.                                 break;
  3065.                             }
  3066.                         } else {
  3067.                             break;
  3068.                         }
  3069.  
  3070.                         //if ((!this._margin() && !this._declaration()) || !tokenStream.match(Tokens.SEMICOLON)){
  3071.                         //    break;
  3072.                         //}
  3073.                         this._readWhitespace();
  3074.                     }
  3075.  
  3076.                     tokenStream.mustMatch(Tokens.RBRACE);
  3077.                     this._readWhitespace();
  3078.  
  3079.                 } catch (ex) {
  3080.                     if (ex instanceof SyntaxError && !this.options.strict) {
  3081.  
  3082.                         //fire error event
  3083.                         this.fire({
  3084.                             type:       "error",
  3085.                             error:      ex,
  3086.                             message:    ex.message,
  3087.                             line:       ex.line,
  3088.                             col:        ex.col
  3089.                         });
  3090.  
  3091.                         //see if there's another declaration
  3092.                         tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]);
  3093.                         if (tt === Tokens.SEMICOLON) {
  3094.                             //if there's a semicolon, then there might be another declaration
  3095.                             this._readDeclarations(false, readMargins);
  3096.                         } else if (tt !== Tokens.RBRACE) {
  3097.                             //if there's a right brace, the rule is finished so don't do anything
  3098.                             //otherwise, rethrow the error because it wasn't handled properly
  3099.                             throw ex;
  3100.                         }
  3101.  
  3102.                     } else {
  3103.                         //not a syntax error, rethrow it
  3104.                         throw ex;
  3105.                     }
  3106.                 }
  3107.  
  3108.             },
  3109.  
  3110.             /**
  3111.              * In some cases, you can end up with two white space tokens in a
  3112.              * row. Instead of making a change in every function that looks for
  3113.              * white space, this function is used to match as much white space
  3114.              * as necessary.
  3115.              * @method _readWhitespace
  3116.              * @return {String} The white space if found, empty string if not.
  3117.              * @private
  3118.              */
  3119.             _readWhitespace: function() {
  3120.  
  3121.                 var tokenStream = this._tokenStream,
  3122.                     ws = "";
  3123.  
  3124.                 while (tokenStream.match(Tokens.S)) {
  3125.                     ws += tokenStream.token().value;
  3126.                 }
  3127.  
  3128.                 return ws;
  3129.             },
  3130.  
  3131.  
  3132.             /**
  3133.              * Throws an error when an unexpected token is found.
  3134.              * @param {Object} token The token that was found.
  3135.              * @method _unexpectedToken
  3136.              * @return {void}
  3137.              * @private
  3138.              */
  3139.             _unexpectedToken: function(token) {
  3140.                 throw new SyntaxError("Unexpected token '" + token.value + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
  3141.             },
  3142.  
  3143.             /**
  3144.              * Helper method used for parsing subparts of a style sheet.
  3145.              * @return {void}
  3146.              * @method _verifyEnd
  3147.              * @private
  3148.              */
  3149.             _verifyEnd: function() {
  3150.                 if (this._tokenStream.LA(1) !== Tokens.EOF) {
  3151.                     this._unexpectedToken(this._tokenStream.LT(1));
  3152.                 }
  3153.             },
  3154.  
  3155.             //-----------------------------------------------------------------
  3156.             // Validation methods
  3157.             //-----------------------------------------------------------------
  3158.             _validateProperty: function(property, value) {
  3159.                 Validation.validate(property, value);
  3160.             },
  3161.  
  3162.             //-----------------------------------------------------------------
  3163.             // Parsing methods
  3164.             //-----------------------------------------------------------------
  3165.  
  3166.             parse: function(input) {
  3167.                 this._tokenStream = new TokenStream(input, Tokens);
  3168.                 this._stylesheet();
  3169.             },
  3170.  
  3171.             parseStyleSheet: function(input) {
  3172.                 //just passthrough
  3173.                 return this.parse(input);
  3174.             },
  3175.  
  3176.             parseMediaQuery: function(input) {
  3177.                 this._tokenStream = new TokenStream(input, Tokens);
  3178.                 var result = this._media_query();
  3179.  
  3180.                 //if there's anything more, then it's an invalid selector
  3181.                 this._verifyEnd();
  3182.  
  3183.                 //otherwise return result
  3184.                 return result;
  3185.             },
  3186.  
  3187.             /**
  3188.              * Parses a property value (everything after the semicolon).
  3189.              * @return {parserlib.css.PropertyValue} The property value.
  3190.              * @throws parserlib.util.SyntaxError If an unexpected token is found.
  3191.              * @method parserPropertyValue
  3192.              */
  3193.             parsePropertyValue: function(input) {
  3194.  
  3195.                 this._tokenStream = new TokenStream(input, Tokens);
  3196.                 this._readWhitespace();
  3197.  
  3198.                 var result = this._expr();
  3199.  
  3200.                 //okay to have a trailing white space
  3201.                 this._readWhitespace();
  3202.  
  3203.                 //if there's anything more, then it's an invalid selector
  3204.                 this._verifyEnd();
  3205.  
  3206.                 //otherwise return result
  3207.                 return result;
  3208.             },
  3209.  
  3210.             /**
  3211.              * Parses a complete CSS rule, including selectors and
  3212.              * properties.
  3213.              * @param {String} input The text to parser.
  3214.              * @return {Boolean} True if the parse completed successfully, false if not.
  3215.              * @method parseRule
  3216.              */
  3217.             parseRule: function(input) {
  3218.                 this._tokenStream = new TokenStream(input, Tokens);
  3219.  
  3220.                 //skip any leading white space
  3221.                 this._readWhitespace();
  3222.  
  3223.                 var result = this._ruleset();
  3224.  
  3225.                 //skip any trailing white space
  3226.                 this._readWhitespace();
  3227.  
  3228.                 //if there's anything more, then it's an invalid selector
  3229.                 this._verifyEnd();
  3230.  
  3231.                 //otherwise return result
  3232.                 return result;
  3233.             },
  3234.  
  3235.             /**
  3236.              * Parses a single CSS selector (no comma)
  3237.              * @param {String} input The text to parse as a CSS selector.
  3238.              * @return {Selector} An object representing the selector.
  3239.              * @throws parserlib.util.SyntaxError If an unexpected token is found.
  3240.              * @method parseSelector
  3241.              */
  3242.             parseSelector: function(input) {
  3243.  
  3244.                 this._tokenStream = new TokenStream(input, Tokens);
  3245.  
  3246.                 //skip any leading white space
  3247.                 this._readWhitespace();
  3248.  
  3249.                 var result = this._selector();
  3250.  
  3251.                 //skip any trailing white space
  3252.                 this._readWhitespace();
  3253.  
  3254.                 //if there's anything more, then it's an invalid selector
  3255.                 this._verifyEnd();
  3256.  
  3257.                 //otherwise return result
  3258.                 return result;
  3259.             },
  3260.  
  3261.             /**
  3262.              * Parses an HTML style attribute: a set of CSS declarations
  3263.              * separated by semicolons.
  3264.              * @param {String} input The text to parse as a style attribute
  3265.              * @return {void}
  3266.              * @method parseStyleAttribute
  3267.              */
  3268.             parseStyleAttribute: function(input) {
  3269.                 input += "}"; // for error recovery in _readDeclarations()
  3270.                 this._tokenStream = new TokenStream(input, Tokens);
  3271.                 this._readDeclarations();
  3272.             }
  3273.         };
  3274.  
  3275.     //copy over onto prototype
  3276.     for (prop in additions) {
  3277.         if (Object.prototype.hasOwnProperty.call(additions, prop)) {
  3278.             proto[prop] = additions[prop];
  3279.         }
  3280.     }
  3281.  
  3282.     return proto;
  3283. }();
  3284.  
  3285.  
  3286. /*
  3287. nth
  3288.   : S* [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]? |
  3289.          ['-'|'+']? INTEGER | {O}{D}{D} | {E}{V}{E}{N} ] S*
  3290.   ;
  3291. */
  3292.  
  3293. },{"../util/EventTarget":23,"../util/SyntaxError":25,"../util/SyntaxUnit":26,"./Combinator":2,"./MediaFeature":4,"./MediaQuery":5,"./PropertyName":8,"./PropertyValue":9,"./PropertyValuePart":11,"./Selector":13,"./SelectorPart":14,"./SelectorSubPart":15,"./TokenStream":17,"./Tokens":18,"./Validation":19}],7:[function(require,module,exports){
  3294. "use strict";
  3295.  
  3296. /* exported Properties */
  3297.  
  3298. var Properties = module.exports = {
  3299.     __proto__: null,
  3300.  
  3301.     //A
  3302.     "align-items"                   : "flex-start | flex-end | center | baseline | stretch",
  3303.     "align-content"                 : "flex-start | flex-end | center | space-between | space-around | stretch",
  3304.     "align-self"                    : "auto | flex-start | flex-end | center | baseline | stretch",
  3305.     "all"                           : "initial | inherit | unset",
  3306.     "-webkit-align-items"           : "flex-start | flex-end | center | baseline | stretch",
  3307.     "-webkit-align-content"         : "flex-start | flex-end | center | space-between | space-around | stretch",
  3308.     "-webkit-align-self"            : "auto | flex-start | flex-end | center | baseline | stretch",
  3309.     "alignment-adjust"              : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>",
  3310.     "alignment-baseline"            : "auto | baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
  3311.     "animation"                     : 1,
  3312.     "animation-delay"               : "<time>#",
  3313.     "animation-direction"           : "<single-animation-direction>#",
  3314.     "animation-duration"            : "<time>#",
  3315.     "animation-fill-mode"           : "[ none | forwards | backwards | both ]#",
  3316.     "animation-iteration-count"     : "[ <number> | infinite ]#",
  3317.     "animation-name"                : "[ none | <single-animation-name> ]#",
  3318.     "animation-play-state"          : "[ running | paused ]#",
  3319.     "animation-timing-function"     : 1,
  3320.  
  3321.     //vendor prefixed
  3322.     "-moz-animation-delay"               : "<time>#",
  3323.     "-moz-animation-direction"           : "[ normal | alternate ]#",
  3324.     "-moz-animation-duration"            : "<time>#",
  3325.     "-moz-animation-iteration-count"     : "[ <number> | infinite ]#",
  3326.     "-moz-animation-name"                : "[ none | <single-animation-name> ]#",
  3327.     "-moz-animation-play-state"          : "[ running | paused ]#",
  3328.  
  3329.     "-ms-animation-delay"               : "<time>#",
  3330.     "-ms-animation-direction"           : "[ normal | alternate ]#",
  3331.     "-ms-animation-duration"            : "<time>#",
  3332.     "-ms-animation-iteration-count"     : "[ <number> | infinite ]#",
  3333.     "-ms-animation-name"                : "[ none | <single-animation-name> ]#",
  3334.     "-ms-animation-play-state"          : "[ running | paused ]#",
  3335.  
  3336.     "-webkit-animation-delay"               : "<time>#",
  3337.     "-webkit-animation-direction"           : "[ normal | alternate ]#",
  3338.     "-webkit-animation-duration"            : "<time>#",
  3339.     "-webkit-animation-fill-mode"           : "[ none | forwards | backwards | both ]#",
  3340.     "-webkit-animation-iteration-count"     : "[ <number> | infinite ]#",
  3341.     "-webkit-animation-name"                : "[ none | <single-animation-name> ]#",
  3342.     "-webkit-animation-play-state"          : "[ running | paused ]#",
  3343.  
  3344.     "-o-animation-delay"               : "<time>#",
  3345.     "-o-animation-direction"           : "[ normal | alternate ]#",
  3346.     "-o-animation-duration"            : "<time>#",
  3347.     "-o-animation-iteration-count"     : "[ <number> | infinite ]#",
  3348.     "-o-animation-name"                : "[ none | <single-animation-name> ]#",
  3349.     "-o-animation-play-state"          : "[ running | paused ]#",
  3350.  
  3351.     "appearance"                    : "none | auto",
  3352.     "-moz-appearance"               : "none | button | button-arrow-down | button-arrow-next | button-arrow-previous | button-arrow-up | button-bevel | button-focus | caret | checkbox | checkbox-container | checkbox-label | checkmenuitem | dualbutton | groupbox | listbox | listitem | menuarrow | menubar | menucheckbox | menuimage | menuitem | menuitemtext | menulist | menulist-button | menulist-text | menulist-textfield | menupopup | menuradio | menuseparator | meterbar | meterchunk | progressbar | progressbar-vertical | progresschunk | progresschunk-vertical | radio | radio-container | radio-label | radiomenuitem | range | range-thumb | resizer | resizerpanel | scale-horizontal | scalethumbend | scalethumb-horizontal | scalethumbstart | scalethumbtick | scalethumb-vertical | scale-vertical | scrollbarbutton-down | scrollbarbutton-left | scrollbarbutton-right | scrollbarbutton-up | scrollbarthumb-horizontal | scrollbarthumb-vertical | scrollbartrack-horizontal | scrollbartrack-vertical | searchfield | separator | sheet | spinner | spinner-downbutton | spinner-textfield | spinner-upbutton | splitter | statusbar | statusbarpanel | tab | tabpanel | tabpanels | tab-scroll-arrow-back | tab-scroll-arrow-forward | textfield | textfield-multiline | toolbar | toolbarbutton | toolbarbutton-dropdown | toolbargripper | toolbox | tooltip | treeheader | treeheadercell | treeheadersortarrow | treeitem | treeline | treetwisty | treetwistyopen | treeview | -moz-mac-unified-toolbar | -moz-win-borderless-glass | -moz-win-browsertabbar-toolbox | -moz-win-communicationstext | -moz-win-communications-toolbox | -moz-win-exclude-glass | -moz-win-glass | -moz-win-mediatext | -moz-win-media-toolbox | -moz-window-button-box | -moz-window-button-box-maximized | -moz-window-button-close | -moz-window-button-maximize | -moz-window-button-minimize | -moz-window-button-restore | -moz-window-frame-bottom | -moz-window-frame-left | -moz-window-frame-right | -moz-window-titlebar | -moz-window-titlebar-maximized",
  3353.     "-ms-appearance"                : "none | icon | window | desktop | workspace | document | tooltip | dialog | button | push-button | hyperlink | radio | radio-button | checkbox | menu-item | tab | menu | menubar | pull-down-menu | pop-up-menu | list-menu | radio-group | checkbox-group | outline-tree | range | field | combo-box | signature | password | normal",
  3354.     "-webkit-appearance"            : "none | button | button-bevel | caps-lock-indicator | caret | checkbox | default-button | listbox    | listitem | media-fullscreen-button | media-mute-button | media-play-button | media-seek-back-button    | media-seek-forward-button    | media-slider | media-sliderthumb | menulist    | menulist-button    | menulist-text    | menulist-textfield | push-button    | radio    | searchfield    | searchfield-cancel-button    | searchfield-decoration | searchfield-results-button | searchfield-results-decoration | slider-horizontal | slider-vertical | sliderthumb-horizontal | sliderthumb-vertical    | square-button    | textarea    | textfield    | scrollbarbutton-down | scrollbarbutton-left | scrollbarbutton-right | scrollbarbutton-up | scrollbargripper-horizontal | scrollbargripper-vertical | scrollbarthumb-horizontal | scrollbarthumb-vertical | scrollbartrack-horizontal | scrollbartrack-vertical",
  3355.     "-o-appearance"                 : "none | window | desktop | workspace | document | tooltip | dialog | button | push-button | hyperlink | radio | radio-button | checkbox | menu-item | tab | menu | menubar | pull-down-menu | pop-up-menu | list-menu | radio-group | checkbox-group | outline-tree | range | field | combo-box | signature | password | normal",
  3356.  
  3357.     "azimuth"                       : "<azimuth>",
  3358.  
  3359.     //B
  3360.     "backface-visibility"           : "visible | hidden",
  3361.     "background"                    : 1,
  3362.     "background-attachment"         : "<attachment>#",
  3363.     "background-clip"               : "<box>#",
  3364.     "background-color"              : "<color>",
  3365.     "background-image"              : "<bg-image>#",
  3366.     "background-origin"             : "<box>#",
  3367.     "background-position"           : "<bg-position>",
  3368.     "background-repeat"             : "<repeat-style>#",
  3369.     "background-size"               : "<bg-size>#",
  3370.     "baseline-shift"                : "baseline | sub | super | <percentage> | <length>",
  3371.     "behavior"                      : 1,
  3372.     "binding"                       : 1,
  3373.     "bleed"                         : "<length>",
  3374.     "bookmark-label"                : "<content> | <attr> | <string>",
  3375.     "bookmark-level"                : "none | <integer>",
  3376.     "bookmark-state"                : "open | closed",
  3377.     "bookmark-target"               : "none | <uri> | <attr>",
  3378.     "border"                        : "<border-width> || <border-style> || <color>",
  3379.     "border-bottom"                 : "<border-width> || <border-style> || <color>",
  3380.     "border-bottom-color"           : "<color>",
  3381.     "border-bottom-left-radius"     :  "<x-one-radius>",
  3382.     "border-bottom-right-radius"    :  "<x-one-radius>",
  3383.     "border-bottom-style"           : "<border-style>",
  3384.     "border-bottom-width"           : "<border-width>",
  3385.     "border-collapse"               : "collapse | separate",
  3386.     "border-color"                  : "<color>{1,4}",
  3387.     "border-image"                  : 1,
  3388.     "border-image-outset"           : "[ <length> | <number> ]{1,4}",
  3389.     "border-image-repeat"           : "[ stretch | repeat | round ]{1,2}",
  3390.     "border-image-slice"            : "<border-image-slice>",
  3391.     "border-image-source"           : "<image> | none",
  3392.     "border-image-width"            : "[ <length> | <percentage> | <number> | auto ]{1,4}",
  3393.     "border-left"                   : "<border-width> || <border-style> || <color>",
  3394.     "border-left-color"             : "<color>",
  3395.     "border-left-style"             : "<border-style>",
  3396.     "border-left-width"             : "<border-width>",
  3397.     "border-radius"                 : "<border-radius>",
  3398.     "border-right"                  : "<border-width> || <border-style> || <color>",
  3399.     "border-right-color"            : "<color>",
  3400.     "border-right-style"            : "<border-style>",
  3401.     "border-right-width"            : "<border-width>",
  3402.     "border-spacing"                : "<length>{1,2}",
  3403.     "border-style"                  : "<border-style>{1,4}",
  3404.     "border-top"                    : "<border-width> || <border-style> || <color>",
  3405.     "border-top-color"              : "<color>",
  3406.     "border-top-left-radius"        : "<x-one-radius>",
  3407.     "border-top-right-radius"       : "<x-one-radius>",
  3408.     "border-top-style"              : "<border-style>",
  3409.     "border-top-width"              : "<border-width>",
  3410.     "border-width"                  : "<border-width>{1,4}",
  3411.     "bottom"                        : "<margin-width>",
  3412.     "-moz-box-align"                : "start | end | center | baseline | stretch",
  3413.     "-moz-box-decoration-break"     : "slice | clone",
  3414.     "-moz-box-direction"            : "normal | reverse",
  3415.     "-moz-box-flex"                 : "<number>",
  3416.     "-moz-box-flex-group"           : "<integer>",
  3417.     "-moz-box-lines"                : "single | multiple",
  3418.     "-moz-box-ordinal-group"        : "<integer>",
  3419.     "-moz-box-orient"               : "horizontal | vertical | inline-axis | block-axis",
  3420.     "-moz-box-pack"                 : "start | end | center | justify",
  3421.     "-o-box-decoration-break"       : "slice | clone",
  3422.     "-webkit-box-align"             : "start | end | center | baseline | stretch",
  3423.     "-webkit-box-decoration-break"  : "slice | clone",
  3424.     "-webkit-box-direction"         : "normal | reverse",
  3425.     "-webkit-box-flex"              : "<number>",
  3426.     "-webkit-box-flex-group"        : "<integer>",
  3427.     "-webkit-box-lines"             : "single | multiple",
  3428.     "-webkit-box-ordinal-group"     : "<integer>",
  3429.     "-webkit-box-orient"            : "horizontal | vertical | inline-axis | block-axis",
  3430.     "-webkit-box-pack"              : "start | end | center | justify",
  3431.     "box-decoration-break"          : "slice | clone",
  3432.     "box-shadow"                    : "<box-shadow>",
  3433.     "box-sizing"                    : "content-box | border-box",
  3434.     "break-after"                   : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column",
  3435.     "break-before"                  : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column",
  3436.     "break-inside"                  : "auto | avoid | avoid-page | avoid-column",
  3437.  
  3438.     //C
  3439.     "caption-side"                  : "top | bottom",
  3440.     "clear"                         : "none | right | left | both",
  3441.     "clip"                          : "<shape> | auto",
  3442.     "-webkit-clip-path"             : "<clip-source> | <clip-path> | none",
  3443.     "clip-path"                     : "<clip-source> | <clip-path> | none",
  3444.     "clip-rule"                     : "nonzero | evenodd",
  3445.     "color"                         : "<color>",
  3446.     "color-interpolation"           : "auto | sRGB | linearRGB",
  3447.     "color-interpolation-filters"   : "auto | sRGB | linearRGB",
  3448.     "color-profile"                 : 1,
  3449.     "color-rendering"               : "auto | optimizeSpeed | optimizeQuality",
  3450.     "column-count"                  : "<integer> | auto",                      //https://www.w3.org/TR/css3-multicol/
  3451.     "column-fill"                   : "auto | balance",
  3452.     "column-gap"                    : "<length> | normal",
  3453.     "column-rule"                   : "<border-width> || <border-style> || <color>",
  3454.     "column-rule-color"             : "<color>",
  3455.     "column-rule-style"             : "<border-style>",
  3456.     "column-rule-width"             : "<border-width>",
  3457.     "column-span"                   : "none | all",
  3458.     "column-width"                  : "<length> | auto",
  3459.     "columns"                       : 1,
  3460.     "content"                       : 1,
  3461.     "counter-increment"             : 1,
  3462.     "counter-reset"                 : 1,
  3463.     "crop"                          : "<shape> | auto",
  3464.     "cue"                           : "cue-after | cue-before",
  3465.     "cue-after"                     : 1,
  3466.     "cue-before"                    : 1,
  3467.     "cursor"                        : 1,
  3468.  
  3469.     //D
  3470.     "direction"                     : "ltr | rtl",
  3471.     "display"                       : "inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | grid | inline-grid | run-in | ruby | ruby-base | ruby-text | ruby-base-container | ruby-text-container | contents | none | -moz-box | -moz-inline-block | -moz-inline-box | -moz-inline-grid | -moz-inline-stack | -moz-inline-table | -moz-grid | -moz-grid-group | -moz-grid-line | -moz-groupbox | -moz-deck | -moz-popup | -moz-stack | -moz-marker | -webkit-box | -webkit-inline-box | -ms-flexbox | -ms-inline-flexbox | flex | -webkit-flex | inline-flex | -webkit-inline-flex",
  3472.     "dominant-baseline"             : "auto | use-script | no-change | reset-size | ideographic | alphabetic | hanging | mathematical | central | middle | text-after-edge | text-before-edge",
  3473.     "drop-initial-after-adjust"     : "central | middle | after-edge | text-after-edge | ideographic | alphabetic | mathematical | <percentage> | <length>",
  3474.     "drop-initial-after-align"      : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
  3475.     "drop-initial-before-adjust"    : "before-edge | text-before-edge | central | middle | hanging | mathematical | <percentage> | <length>",
  3476.     "drop-initial-before-align"     : "caps-height | baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
  3477.     "drop-initial-size"             : "auto | line | <length> | <percentage>",
  3478.     "drop-initial-value"            : "<integer>",
  3479.  
  3480.     //E
  3481.     "elevation"                     : "<angle> | below | level | above | higher | lower",
  3482.     "empty-cells"                   : "show | hide",
  3483.     "enable-background"             : 1,
  3484.  
  3485.     //F
  3486.     "fill"                          : "<paint>",
  3487.     "fill-opacity"                  : "<opacity-value>",
  3488.     "fill-rule"                     : "nonzero | evenodd",
  3489.     "filter"                        : "<filter-function-list> | none",
  3490.     "fit"                           : "fill | hidden | meet | slice",
  3491.     "fit-position"                  : 1,
  3492.     "flex"                          : "<flex>",
  3493.     "flex-basis"                    : "<width>",
  3494.     "flex-direction"                : "row | row-reverse | column | column-reverse",
  3495.     "flex-flow"                     : "<flex-direction> || <flex-wrap>",
  3496.     "flex-grow"                     : "<number>",
  3497.     "flex-shrink"                   : "<number>",
  3498.     "flex-wrap"                     : "nowrap | wrap | wrap-reverse",
  3499.     "-webkit-flex"                  : "<flex>",
  3500.     "-webkit-flex-basis"            : "<width>",
  3501.     "-webkit-flex-direction"        : "row | row-reverse | column | column-reverse",
  3502.     "-webkit-flex-flow"             : "<flex-direction> || <flex-wrap>",
  3503.     "-webkit-flex-grow"             : "<number>",
  3504.     "-webkit-flex-shrink"           : "<number>",
  3505.     "-webkit-flex-wrap"             : "nowrap | wrap | wrap-reverse",
  3506.     "-ms-flex"                      : "<flex>",
  3507.     "-ms-flex-align"                : "start | end | center | stretch | baseline",
  3508.     "-ms-flex-direction"            : "row | row-reverse | column | column-reverse",
  3509.     "-ms-flex-order"                : "<number>",
  3510.     "-ms-flex-pack"                 : "start | end | center | justify",
  3511.     "-ms-flex-wrap"                 : "nowrap | wrap | wrap-reverse",
  3512.     "float"                         : "left | right | none",
  3513.     "float-offset"                  : 1,
  3514.     "flood-color"                   : 1,
  3515.     "flood-opacity"                 : "<opacity-value>",
  3516.     "font"                          : "<font-shorthand> | caption | icon | menu | message-box | small-caption | status-bar",
  3517.     "font-family"                   : "<font-family>",
  3518.     "font-feature-settings"         : "<feature-tag-value> | normal",
  3519.     "font-kerning"                  : "auto | normal | none",
  3520.     "font-size"                     : "<font-size>",
  3521.     "font-size-adjust"              : "<number> | none",
  3522.     "font-stretch"                  : "<font-stretch>",
  3523.     "font-style"                    : "<font-style>",
  3524.     "font-variant"                  : "<font-variant> | normal | none",
  3525.     "font-variant-alternates"       : "<font-variant-alternates> | normal",
  3526.     "font-variant-caps"             : "<font-variant-caps> | normal",
  3527.     "font-variant-east-asian"       : "<font-variant-east-asian> | normal",
  3528.     "font-variant-ligatures"        : "<font-variant-ligatures> | normal | none",
  3529.     "font-variant-numeric"          : "<font-variant-numeric> | normal",
  3530.     "font-variant-position"         : "normal | sub | super",
  3531.     "font-weight"                   : "<font-weight>",
  3532.  
  3533.     //G
  3534.     "glyph-orientation-horizontal"  : "<glyph-angle>",
  3535.     "glyph-orientation-vertical"    : "auto | <glyph-angle>",
  3536.     "grid"                          : 1,
  3537.     "grid-area"                     : 1,
  3538.     "grid-auto-columns"             : 1,
  3539.     "grid-auto-flow"                : 1,
  3540.     "grid-auto-position"            : 1,
  3541.     "grid-auto-rows"                : 1,
  3542.     "grid-cell-stacking"            : "columns | rows | layer",
  3543.     "grid-column"                   : 1,
  3544.     "grid-columns"                  : 1,
  3545.     "grid-column-align"             : "start | end | center | stretch",
  3546.     "grid-column-sizing"            : 1,
  3547.     "grid-column-start"             : 1,
  3548.     "grid-column-end"               : 1,
  3549.     "grid-column-span"              : "<integer>",
  3550.     "grid-flow"                     : "none | rows | columns",
  3551.     "grid-layer"                    : "<integer>",
  3552.     "grid-row"                      : 1,
  3553.     "grid-rows"                     : 1,
  3554.     "grid-row-align"                : "start | end | center | stretch",
  3555.     "grid-row-start"                : 1,
  3556.     "grid-row-end"                  : 1,
  3557.     "grid-row-span"                 : "<integer>",
  3558.     "grid-row-sizing"               : 1,
  3559.     "grid-template"                 : 1,
  3560.     "grid-template-areas"           : 1,
  3561.     "grid-template-columns"         : 1,
  3562.     "grid-template-rows"            : 1,
  3563.  
  3564.     //H
  3565.     "hanging-punctuation"           : 1,
  3566.     "height"                        : "<margin-width> | <content-sizing>",
  3567.     "hyphenate-after"               : "<integer> | auto",
  3568.     "hyphenate-before"              : "<integer> | auto",
  3569.     "hyphenate-character"           : "<string> | auto",
  3570.     "hyphenate-lines"               : "no-limit | <integer>",
  3571.     "hyphenate-resource"            : 1,
  3572.     "hyphens"                       : "none | manual | auto",
  3573.  
  3574.     //I
  3575.     "icon"                          : 1,
  3576.     "image-orientation"             : "angle | auto",
  3577.     "image-rendering"               : "auto | optimizeSpeed | optimizeQuality",
  3578.     "image-resolution"              : 1,
  3579.     "ime-mode"                      : "auto | normal | active | inactive | disabled",
  3580.     "inline-box-align"              : "last | <integer>",
  3581.  
  3582.     //J
  3583.     "justify-content"               : "flex-start | flex-end | center | space-between | space-around",
  3584.     "-webkit-justify-content"       : "flex-start | flex-end | center | space-between | space-around",
  3585.  
  3586.     //K
  3587.     "kerning"                       : "auto | <length>",
  3588.  
  3589.     //L
  3590.     "left"                          : "<margin-width>",
  3591.     "letter-spacing"                : "<length> | normal",
  3592.     "line-height"                   : "<line-height>",
  3593.     "line-break"                    : "auto | loose | normal | strict",
  3594.     "line-stacking"                 : 1,
  3595.     "line-stacking-ruby"            : "exclude-ruby | include-ruby",
  3596.     "line-stacking-shift"           : "consider-shifts | disregard-shifts",
  3597.     "line-stacking-strategy"        : "inline-line-height | block-line-height | max-height | grid-height",
  3598.     "list-style"                    : 1,
  3599.     "list-style-image"              : "<uri> | none",
  3600.     "list-style-position"           : "inside | outside",
  3601.     "list-style-type"               : "disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha | none",
  3602.  
  3603.     //M
  3604.     "margin"                        : "<margin-width>{1,4}",
  3605.     "margin-bottom"                 : "<margin-width>",
  3606.     "margin-left"                   : "<margin-width>",
  3607.     "margin-right"                  : "<margin-width>",
  3608.     "margin-top"                    : "<margin-width>",
  3609.     "mark"                          : 1,
  3610.     "mark-after"                    : 1,
  3611.     "mark-before"                   : 1,
  3612.     "marker"                        : 1,
  3613.     "marker-end"                    : 1,
  3614.     "marker-mid"                    : 1,
  3615.     "marker-start"                  : 1,
  3616.     "marks"                         : 1,
  3617.     "marquee-direction"             : 1,
  3618.     "marquee-play-count"            : 1,
  3619.     "marquee-speed"                 : 1,
  3620.     "marquee-style"                 : 1,
  3621.     "mask"                          : 1,
  3622.     "max-height"                    : "<length> | <percentage> | <content-sizing> | none",
  3623.     "max-width"                     : "<length> | <percentage> | <content-sizing> | none",
  3624.     "min-height"                    : "<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats",
  3625.     "min-width"                     : "<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats",
  3626.     "move-to"                       : 1,
  3627.  
  3628.     //N
  3629.     "nav-down"                      : 1,
  3630.     "nav-index"                     : 1,
  3631.     "nav-left"                      : 1,
  3632.     "nav-right"                     : 1,
  3633.     "nav-up"                        : 1,
  3634.  
  3635.     //O
  3636.     "object-fit"                    : "fill | contain | cover | none | scale-down",
  3637.     "object-position"               : "<position>",
  3638.     "opacity"                       : "<opacity-value>",
  3639.     "order"                         : "<integer>",
  3640.     "-webkit-order"                 : "<integer>",
  3641.     "orphans"                       : "<integer>",
  3642.     "outline"                       : 1,
  3643.     "outline-color"                 : "<color> | invert",
  3644.     "outline-offset"                : 1,
  3645.     "outline-style"                 : "<border-style>",
  3646.     "outline-width"                 : "<border-width>",
  3647.     "overflow"                      : "visible | hidden | scroll | auto",
  3648.     "overflow-style"                : 1,
  3649.     "overflow-wrap"                 : "normal | break-word",
  3650.     "overflow-x"                    : 1,
  3651.     "overflow-y"                    : 1,
  3652.  
  3653.     //P
  3654.     "padding"                       : "<padding-width>{1,4}",
  3655.     "padding-bottom"                : "<padding-width>",
  3656.     "padding-left"                  : "<padding-width>",
  3657.     "padding-right"                 : "<padding-width>",
  3658.     "padding-top"                   : "<padding-width>",
  3659.     "page"                          : 1,
  3660.     "page-break-after"              : "auto | always | avoid | left | right",
  3661.     "page-break-before"             : "auto | always | avoid | left | right",
  3662.     "page-break-inside"             : "auto | avoid",
  3663.     "page-policy"                   : 1,
  3664.     "pause"                         : 1,
  3665.     "pause-after"                   : 1,
  3666.     "pause-before"                  : 1,
  3667.     "perspective"                   : 1,
  3668.     "perspective-origin"            : 1,
  3669.     "phonemes"                      : 1,
  3670.     "pitch"                         : 1,
  3671.     "pitch-range"                   : 1,
  3672.     "play-during"                   : 1,
  3673.     "pointer-events"                : "auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all",
  3674.     "position"                      : "static | relative | absolute | fixed",
  3675.     "presentation-level"            : 1,
  3676.     "punctuation-trim"              : 1,
  3677.  
  3678.     //Q
  3679.     "quotes"                        : 1,
  3680.  
  3681.     //R
  3682.     "rendering-intent"              : 1,
  3683.     "resize"                        : 1,
  3684.     "rest"                          : 1,
  3685.     "rest-after"                    : 1,
  3686.     "rest-before"                   : 1,
  3687.     "richness"                      : 1,
  3688.     "right"                         : "<margin-width>",
  3689.     "rotation"                      : 1,
  3690.     "rotation-point"                : 1,
  3691.     "ruby-align"                    : 1,
  3692.     "ruby-overhang"                 : 1,
  3693.     "ruby-position"                 : 1,
  3694.     "ruby-span"                     : 1,
  3695.  
  3696.     //S
  3697.     "shape-rendering"               : "auto | optimizeSpeed | crispEdges | geometricPrecision",
  3698.     "size"                          : 1,
  3699.     "speak"                         : "normal | none | spell-out",
  3700.     "speak-header"                  : "once | always",
  3701.     "speak-numeral"                 : "digits | continuous",
  3702.     "speak-punctuation"             : "code | none",
  3703.     "speech-rate"                   : 1,
  3704.     "src"                           : 1,
  3705.     "stop-color"                    : 1,
  3706.     "stop-opacity"                  : "<opacity-value>",
  3707.     "stress"                        : 1,
  3708.     "string-set"                    : 1,
  3709.     "stroke"                        : "<paint>",
  3710.     "stroke-dasharray"              : "none | <dasharray>",
  3711.     "stroke-dashoffset"             : "<percentage> | <length>",
  3712.     "stroke-linecap"                : "butt | round | square",
  3713.     "stroke-linejoin"               : "miter | round | bevel",
  3714.     "stroke-miterlimit"             : "<miterlimit>",
  3715.     "stroke-opacity"                : "<opacity-value>",
  3716.     "stroke-width"                  : "<percentage> | <length>",
  3717.  
  3718.     "table-layout"                  : "auto | fixed",
  3719.     "tab-size"                      : "<integer> | <length>",
  3720.     "target"                        : 1,
  3721.     "target-name"                   : 1,
  3722.     "target-new"                    : 1,
  3723.     "target-position"               : 1,
  3724.     "text-align"                    : "left | right | center | justify | match-parent | start | end",
  3725.     "text-align-last"               : 1,
  3726.     "text-anchor"                   : "start | middle | end",
  3727.     "text-decoration"               : "<text-decoration-line> || <text-decoration-style> || <text-decoration-color>",
  3728.     "text-decoration-color"         : "<text-decoration-color>",
  3729.     "text-decoration-line"          : "<text-decoration-line>",
  3730.     "text-decoration-style"         : "<text-decoration-style>",
  3731.     "text-emphasis"                 : 1,
  3732.     "text-height"                   : 1,
  3733.     "text-indent"                   : "<length> | <percentage>",
  3734.     "text-justify"                  : "auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida",
  3735.     "text-outline"                  : 1,
  3736.     "text-overflow"                 : 1,
  3737.     "text-rendering"                : "auto | optimizeSpeed | optimizeLegibility | geometricPrecision",
  3738.     "text-shadow"                   : 1,
  3739.     "text-transform"                : "capitalize | uppercase | lowercase | none",
  3740.     "text-wrap"                     : "normal | none | avoid",
  3741.     "top"                           : "<margin-width>",
  3742.     "-ms-touch-action"              : "auto | none | pan-x | pan-y | pan-left | pan-right | pan-up | pan-down | manipulation",
  3743.     "touch-action"                  : "auto | none | pan-x | pan-y | pan-left | pan-right | pan-up | pan-down | manipulation",
  3744.     "transform"                     : 1,
  3745.     "transform-origin"              : 1,
  3746.     "transform-style"               : 1,
  3747.     "transition"                    : 1,
  3748.     "transition-delay"              : 1,
  3749.     "transition-duration"           : 1,
  3750.     "transition-property"           : 1,
  3751.     "transition-timing-function"    : 1,
  3752.  
  3753.     //U
  3754.     "unicode-bidi"                  : "normal | embed | isolate | bidi-override | isolate-override | plaintext",
  3755.     "user-modify"                   : "read-only | read-write | write-only",
  3756.     "user-select"                   : "none | text | toggle | element | elements | all",
  3757.  
  3758.     //V
  3759.     "vertical-align"                : "auto | use-script | baseline | sub | super | top | text-top | central | middle | bottom | text-bottom | <percentage> | <length>",
  3760.     "visibility"                    : "visible | hidden | collapse",
  3761.     "voice-balance"                 : 1,
  3762.     "voice-duration"                : 1,
  3763.     "voice-family"                  : 1,
  3764.     "voice-pitch"                   : 1,
  3765.     "voice-pitch-range"             : 1,
  3766.     "voice-rate"                    : 1,
  3767.     "voice-stress"                  : 1,
  3768.     "voice-volume"                  : 1,
  3769.     "volume"                        : 1,
  3770.  
  3771.     //W
  3772.     "white-space"                   : "normal | pre | nowrap | pre-wrap | pre-line | -pre-wrap | -o-pre-wrap | -moz-pre-wrap | -hp-pre-wrap",   // https://perishablepress.com/wrapping-content/
  3773.     "white-space-collapse"          : 1,
  3774.     "widows"                        : "<integer>",
  3775.     "width"                         : "<length> | <percentage> | <content-sizing> | auto",
  3776.     "will-change"                   : "<will-change>",
  3777.     "word-break"                    : "normal | keep-all | break-all",
  3778.     "word-spacing"                  : "<length> | normal",
  3779.     "word-wrap"                     : "normal | break-word",
  3780.     "writing-mode"                  : "horizontal-tb | vertical-rl | vertical-lr | lr-tb | rl-tb | tb-rl | bt-rl | tb-lr | bt-lr | lr-bt | rl-bt | lr | rl | tb",
  3781.  
  3782.     //Z
  3783.     "z-index"                       : "<integer> | auto",
  3784.     "zoom"                          : "<number> | <percentage> | normal"
  3785. };
  3786.  
  3787. },{}],8:[function(require,module,exports){
  3788. "use strict";
  3789.  
  3790. module.exports = PropertyName;
  3791.  
  3792. var SyntaxUnit = require("../util/SyntaxUnit");
  3793.  
  3794. var Parser = require("./Parser");
  3795.  
  3796. /**
  3797.  * Represents a selector combinator (whitespace, +, >).
  3798.  * @namespace parserlib.css
  3799.  * @class PropertyName
  3800.  * @extends parserlib.util.SyntaxUnit
  3801.  * @constructor
  3802.  * @param {String} text The text representation of the unit.
  3803.  * @param {String} hack The type of IE hack applied ("*", "_", or null).
  3804.  * @param {int} line The line of text on which the unit resides.
  3805.  * @param {int} col The column of text on which the unit resides.
  3806.  */
  3807. function PropertyName(text, hack, line, col) {
  3808.  
  3809.     SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_NAME_TYPE);
  3810.  
  3811.     /**
  3812.      * The type of IE hack applied ("*", "_", or null).
  3813.      * @type String
  3814.      * @property hack
  3815.      */
  3816.     this.hack = hack;
  3817.  
  3818. }
  3819.  
  3820. PropertyName.prototype = new SyntaxUnit();
  3821. PropertyName.prototype.constructor = PropertyName;
  3822. PropertyName.prototype.toString = function() {
  3823.     return (this.hack ? this.hack : "") + this.text;
  3824. };
  3825.  
  3826. },{"../util/SyntaxUnit":26,"./Parser":6}],9:[function(require,module,exports){
  3827. "use strict";
  3828.  
  3829. module.exports = PropertyValue;
  3830.  
  3831. var SyntaxUnit = require("../util/SyntaxUnit");
  3832.  
  3833. var Parser = require("./Parser");
  3834.  
  3835. /**
  3836.  * Represents a single part of a CSS property value, meaning that it represents
  3837.  * just everything single part between ":" and ";". If there are multiple values
  3838.  * separated by commas, this type represents just one of the values.
  3839.  * @param {String[]} parts An array of value parts making up this value.
  3840.  * @param {int} line The line of text on which the unit resides.
  3841.  * @param {int} col The column of text on which the unit resides.
  3842.  * @namespace parserlib.css
  3843.  * @class PropertyValue
  3844.  * @extends parserlib.util.SyntaxUnit
  3845.  * @constructor
  3846.  */
  3847. function PropertyValue(parts, line, col) {
  3848.  
  3849.     SyntaxUnit.call(this, parts.join(" "), line, col, Parser.PROPERTY_VALUE_TYPE);
  3850.  
  3851.     /**
  3852.      * The parts that make up the selector.
  3853.      * @type Array
  3854.      * @property parts
  3855.      */
  3856.     this.parts = parts;
  3857.  
  3858. }
  3859.  
  3860. PropertyValue.prototype = new SyntaxUnit();
  3861. PropertyValue.prototype.constructor = PropertyValue;
  3862.  
  3863.  
  3864. },{"../util/SyntaxUnit":26,"./Parser":6}],10:[function(require,module,exports){
  3865. "use strict";
  3866.  
  3867. module.exports = PropertyValueIterator;
  3868.  
  3869. /**
  3870.  * A utility class that allows for easy iteration over the various parts of a
  3871.  * property value.
  3872.  * @param {parserlib.css.PropertyValue} value The property value to iterate over.
  3873.  * @namespace parserlib.css
  3874.  * @class PropertyValueIterator
  3875.  * @constructor
  3876.  */
  3877. function PropertyValueIterator(value) {
  3878.  
  3879.     /**
  3880.      * Iterator value
  3881.      * @type int
  3882.      * @property _i
  3883.      * @private
  3884.      */
  3885.     this._i = 0;
  3886.  
  3887.     /**
  3888.      * The parts that make up the value.
  3889.      * @type Array
  3890.      * @property _parts
  3891.      * @private
  3892.      */
  3893.     this._parts = value.parts;
  3894.  
  3895.     /**
  3896.      * Keeps track of bookmarks along the way.
  3897.      * @type Array
  3898.      * @property _marks
  3899.      * @private
  3900.      */
  3901.     this._marks = [];
  3902.  
  3903.     /**
  3904.      * Holds the original property value.
  3905.      * @type parserlib.css.PropertyValue
  3906.      * @property value
  3907.      */
  3908.     this.value = value;
  3909.  
  3910. }
  3911.  
  3912. /**
  3913.  * Returns the total number of parts in the value.
  3914.  * @return {int} The total number of parts in the value.
  3915.  * @method count
  3916.  */
  3917. PropertyValueIterator.prototype.count = function() {
  3918.     return this._parts.length;
  3919. };
  3920.  
  3921. /**
  3922.  * Indicates if the iterator is positioned at the first item.
  3923.  * @return {Boolean} True if positioned at first item, false if not.
  3924.  * @method isFirst
  3925.  */
  3926. PropertyValueIterator.prototype.isFirst = function() {
  3927.     return this._i === 0;
  3928. };
  3929.  
  3930. /**
  3931.  * Indicates if there are more parts of the property value.
  3932.  * @return {Boolean} True if there are more parts, false if not.
  3933.  * @method hasNext
  3934.  */
  3935. PropertyValueIterator.prototype.hasNext = function() {
  3936.     return this._i < this._parts.length;
  3937. };
  3938.  
  3939. /**
  3940.  * Marks the current spot in the iteration so it can be restored to
  3941.  * later on.
  3942.  * @return {void}
  3943.  * @method mark
  3944.  */
  3945. PropertyValueIterator.prototype.mark = function() {
  3946.     this._marks.push(this._i);
  3947. };
  3948.  
  3949. /**
  3950.  * Returns the next part of the property value or null if there is no next
  3951.  * part. Does not move the internal counter forward.
  3952.  * @return {parserlib.css.PropertyValuePart} The next part of the property value or null if there is no next
  3953.  * part.
  3954.  * @method peek
  3955.  */
  3956. PropertyValueIterator.prototype.peek = function(count) {
  3957.     return this.hasNext() ? this._parts[this._i + (count || 0)] : null;
  3958. };
  3959.  
  3960. /**
  3961.  * Returns the next part of the property value or null if there is no next
  3962.  * part.
  3963.  * @return {parserlib.css.PropertyValuePart} The next part of the property value or null if there is no next
  3964.  * part.
  3965.  * @method next
  3966.  */
  3967. PropertyValueIterator.prototype.next = function() {
  3968.     return this.hasNext() ? this._parts[this._i++] : null;
  3969. };
  3970.  
  3971. /**
  3972.  * Returns the previous part of the property value or null if there is no
  3973.  * previous part.
  3974.  * @return {parserlib.css.PropertyValuePart} The previous part of the
  3975.  * property value or null if there is no previous part.
  3976.  * @method previous
  3977.  */
  3978. PropertyValueIterator.prototype.previous = function() {
  3979.     return this._i > 0 ? this._parts[--this._i] : null;
  3980. };
  3981.  
  3982. /**
  3983.  * Restores the last saved bookmark.
  3984.  * @return {void}
  3985.  * @method restore
  3986.  */
  3987. PropertyValueIterator.prototype.restore = function() {
  3988.     if (this._marks.length) {
  3989.         this._i = this._marks.pop();
  3990.     }
  3991. };
  3992.  
  3993. /**
  3994.  * Drops the last saved bookmark.
  3995.  * @return {void}
  3996.  * @method drop
  3997.  */
  3998. PropertyValueIterator.prototype.drop = function() {
  3999.     this._marks.pop();
  4000. };
  4001.  
  4002. },{}],11:[function(require,module,exports){
  4003. "use strict";
  4004.  
  4005. module.exports = PropertyValuePart;
  4006.  
  4007. var SyntaxUnit = require("../util/SyntaxUnit");
  4008.  
  4009. var Colors = require("./Colors");
  4010. var Parser = require("./Parser");
  4011. var Tokens = require("./Tokens");
  4012.  
  4013. /**
  4014.  * Represents a single part of a CSS property value, meaning that it represents
  4015.  * just one part of the data between ":" and ";".
  4016.  * @param {String} text The text representation of the unit.
  4017.  * @param {int} line The line of text on which the unit resides.
  4018.  * @param {int} col The column of text on which the unit resides.
  4019.  * @namespace parserlib.css
  4020.  * @class PropertyValuePart
  4021.  * @extends parserlib.util.SyntaxUnit
  4022.  * @constructor
  4023.  */
  4024. function PropertyValuePart(text, line, col, optionalHint) {
  4025.     var hint = optionalHint || {};
  4026.  
  4027.     SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_VALUE_PART_TYPE);
  4028.  
  4029.     /**
  4030.      * Indicates the type of value unit.
  4031.      * @type String
  4032.      * @property type
  4033.      */
  4034.     this.type = "unknown";
  4035.  
  4036.     //figure out what type of data it is
  4037.  
  4038.     var temp;
  4039.  
  4040.     //it is a measurement?
  4041.     if (/^([+\-]?[\d\.]+)([a-z]+)$/i.test(text)) {  //dimension
  4042.         this.type = "dimension";
  4043.         this.value = +RegExp.$1;
  4044.         this.units = RegExp.$2;
  4045.  
  4046.         //try to narrow down
  4047.         switch (this.units.toLowerCase()) {
  4048.  
  4049.             case "em":
  4050.             case "rem":
  4051.             case "ex":
  4052.             case "px":
  4053.             case "cm":
  4054.             case "mm":
  4055.             case "in":
  4056.             case "pt":
  4057.             case "pc":
  4058.             case "ch":
  4059.             case "vh":
  4060.             case "vw":
  4061.             case "vmax":
  4062.             case "vmin":
  4063.                 this.type = "length";
  4064.                 break;
  4065.  
  4066.             case "fr":
  4067.                 this.type = "grid";
  4068.                 break;
  4069.  
  4070.             case "deg":
  4071.             case "rad":
  4072.             case "grad":
  4073.             case "turn":
  4074.                 this.type = "angle";
  4075.                 break;
  4076.  
  4077.             case "ms":
  4078.             case "s":
  4079.                 this.type = "time";
  4080.                 break;
  4081.  
  4082.             case "hz":
  4083.             case "khz":
  4084.                 this.type = "frequency";
  4085.                 break;
  4086.  
  4087.             case "dpi":
  4088.             case "dpcm":
  4089.                 this.type = "resolution";
  4090.                 break;
  4091.  
  4092.             //default
  4093.  
  4094.         }
  4095.  
  4096.     } else if (/^([+\-]?[\d\.]+)%$/i.test(text)) {  //percentage
  4097.         this.type = "percentage";
  4098.         this.value = +RegExp.$1;
  4099.     } else if (/^([+\-]?\d+)$/i.test(text)) {  //integer
  4100.         this.type = "integer";
  4101.         this.value = +RegExp.$1;
  4102.     } else if (/^([+\-]?[\d\.]+)$/i.test(text)) {  //number
  4103.         this.type = "number";
  4104.         this.value = +RegExp.$1;
  4105.  
  4106.     } else if (/^#([a-f0-9]{3,6})/i.test(text)) {  //hexcolor
  4107.         this.type = "color";
  4108.         temp = RegExp.$1;
  4109.         if (temp.length === 3) {
  4110.             this.red    = parseInt(temp.charAt(0)+temp.charAt(0), 16);
  4111.             this.green  = parseInt(temp.charAt(1)+temp.charAt(1), 16);
  4112.             this.blue   = parseInt(temp.charAt(2)+temp.charAt(2), 16);
  4113.         } else {
  4114.             this.red    = parseInt(temp.substring(0, 2), 16);
  4115.             this.green  = parseInt(temp.substring(2, 4), 16);
  4116.             this.blue   = parseInt(temp.substring(4, 6), 16);
  4117.         }
  4118.     } else if (/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i.test(text)) { //rgb() color with absolute numbers
  4119.         this.type   = "color";
  4120.         this.red    = +RegExp.$1;
  4121.         this.green  = +RegExp.$2;
  4122.         this.blue   = +RegExp.$3;
  4123.     } else if (/^rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)) { //rgb() color with percentages
  4124.         this.type   = "color";
  4125.         this.red    = +RegExp.$1 * 255 / 100;
  4126.         this.green  = +RegExp.$2 * 255 / 100;
  4127.         this.blue   = +RegExp.$3 * 255 / 100;
  4128.     } else if (/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/i.test(text)) { //rgba() color with absolute numbers
  4129.         this.type   = "color";
  4130.         this.red    = +RegExp.$1;
  4131.         this.green  = +RegExp.$2;
  4132.         this.blue   = +RegExp.$3;
  4133.         this.alpha  = +RegExp.$4;
  4134.     } else if (/^rgba\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)) { //rgba() color with percentages
  4135.         this.type   = "color";
  4136.         this.red    = +RegExp.$1 * 255 / 100;
  4137.         this.green  = +RegExp.$2 * 255 / 100;
  4138.         this.blue   = +RegExp.$3 * 255 / 100;
  4139.         this.alpha  = +RegExp.$4;
  4140.     } else if (/^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)) { //hsl()
  4141.         this.type   = "color";
  4142.         this.hue    = +RegExp.$1;
  4143.         this.saturation = +RegExp.$2 / 100;
  4144.         this.lightness  = +RegExp.$3 / 100;
  4145.     } else if (/^hsla\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)) { //hsla() color with percentages
  4146.         this.type   = "color";
  4147.         this.hue    = +RegExp.$1;
  4148.         this.saturation = +RegExp.$2 / 100;
  4149.         this.lightness  = +RegExp.$3 / 100;
  4150.         this.alpha  = +RegExp.$4;
  4151.     } else if (/^url\(("([^\\"]|\\.)*")\)/i.test(text)) { //URI
  4152.         // generated by TokenStream.readURI, so always double-quoted.
  4153.         this.type   = "uri";
  4154.         this.uri    = PropertyValuePart.parseString(RegExp.$1);
  4155.     } else if (/^([^\(]+)\(/i.test(text)) {
  4156.         this.type   = "function";
  4157.         this.name   = RegExp.$1;
  4158.         this.value  = text;
  4159.     } else if (/^"([^\n\r\f\\"]|\\\r\n|\\[^\r0-9a-f]|\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?)*"/i.test(text)) {    //double-quoted string
  4160.         this.type   = "string";
  4161.         this.value  = PropertyValuePart.parseString(text);
  4162.     } else if (/^'([^\n\r\f\\']|\\\r\n|\\[^\r0-9a-f]|\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?)*'/i.test(text)) {    //single-quoted string
  4163.         this.type   = "string";
  4164.         this.value  = PropertyValuePart.parseString(text);
  4165.     } else if (Colors[text.toLowerCase()]) {  //named color
  4166.         this.type   = "color";
  4167.         temp        = Colors[text.toLowerCase()].substring(1);
  4168.         this.red    = parseInt(temp.substring(0, 2), 16);
  4169.         this.green  = parseInt(temp.substring(2, 4), 16);
  4170.         this.blue   = parseInt(temp.substring(4, 6), 16);
  4171.     } else if (/^[,\/]$/.test(text)) {
  4172.         this.type   = "operator";
  4173.         this.value  = text;
  4174.     } else if (/^-?[a-z_\u00A0-\uFFFF][a-z0-9\-_\u00A0-\uFFFF]*$/i.test(text)) {
  4175.         this.type   = "identifier";
  4176.         this.value  = text;
  4177.     }
  4178.  
  4179.     // There can be ambiguity with escape sequences in identifiers, as
  4180.     // well as with "color" parts which are also "identifiers", so record
  4181.     // an explicit hint when the token generating this PropertyValuePart
  4182.     // was an identifier.
  4183.     this.wasIdent = Boolean(hint.ident);
  4184.  
  4185. }
  4186.  
  4187. PropertyValuePart.prototype = new SyntaxUnit();
  4188. PropertyValuePart.prototype.constructor = PropertyValuePart;
  4189.  
  4190. /**
  4191.  * Helper method to parse a CSS string.
  4192.  */
  4193. PropertyValuePart.parseString = function(str) {
  4194.     str = str.slice(1, -1); // Strip surrounding single/double quotes
  4195.     var replacer = function(match, esc) {
  4196.         if (/^(\n|\r\n|\r|\f)$/.test(esc)) {
  4197.             return "";
  4198.         }
  4199.         var m = /^[0-9a-f]{1,6}/i.exec(esc);
  4200.         if (m) {
  4201.             var codePoint = parseInt(m[0], 16);
  4202.             if (String.fromCodePoint) {
  4203.                 return String.fromCodePoint(codePoint);
  4204.             } else {
  4205.                 // XXX No support for surrogates on old JavaScript engines.
  4206.                 return String.fromCharCode(codePoint);
  4207.             }
  4208.         }
  4209.         return esc;
  4210.     };
  4211.     return str.replace(/\\(\r\n|[^\r0-9a-f]|[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?)/ig,
  4212.                        replacer);
  4213. };
  4214.  
  4215. /**
  4216.  * Helper method to serialize a CSS string.
  4217.  */
  4218. PropertyValuePart.serializeString = function(value) {
  4219.     var replacer = function(match, c) {
  4220.         if (c === "\"") {
  4221.             return "\\" + c;
  4222.         }
  4223.         var cp = String.codePointAt ? String.codePointAt(0) :
  4224.             // We only escape non-surrogate chars, so using charCodeAt
  4225.             // is harmless here.
  4226.             String.charCodeAt(0);
  4227.         return "\\" + cp.toString(16) + " ";
  4228.     };
  4229.     return "\"" + value.replace(/["\r\n\f]/g, replacer) + "\"";
  4230. };
  4231.  
  4232. /**
  4233.  * Create a new syntax unit based solely on the given token.
  4234.  * Convenience method for creating a new syntax unit when
  4235.  * it represents a single token instead of multiple.
  4236.  * @param {Object} token The token object to represent.
  4237.  * @return {parserlib.css.PropertyValuePart} The object representing the token.
  4238.  * @static
  4239.  * @method fromToken
  4240.  */
  4241. PropertyValuePart.fromToken = function(token) {
  4242.     var part = new PropertyValuePart(token.value, token.startLine, token.startCol, {
  4243.         // Tokens can have escaped characters that would fool the type
  4244.         // identification in the PropertyValuePart constructor, so pass
  4245.         // in a hint if this was an identifier.
  4246.         ident: token.type === Tokens.IDENT
  4247.     });
  4248.     return part;
  4249. };
  4250.  
  4251. },{"../util/SyntaxUnit":26,"./Colors":1,"./Parser":6,"./Tokens":18}],12:[function(require,module,exports){
  4252. "use strict";
  4253.  
  4254. var Pseudos = module.exports = {
  4255.     __proto__:       null,
  4256.     ":first-letter": 1,
  4257.     ":first-line":   1,
  4258.     ":before":       1,
  4259.     ":after":        1
  4260. };
  4261.  
  4262. Pseudos.ELEMENT = 1;
  4263. Pseudos.CLASS = 2;
  4264.  
  4265. Pseudos.isElement = function(pseudo) {
  4266.     return pseudo.indexOf("::") === 0 || Pseudos[pseudo.toLowerCase()] === Pseudos.ELEMENT;
  4267. };
  4268.  
  4269. },{}],13:[function(require,module,exports){
  4270. "use strict";
  4271.  
  4272. module.exports = Selector;
  4273.  
  4274. var SyntaxUnit = require("../util/SyntaxUnit");
  4275.  
  4276. var Parser = require("./Parser");
  4277. var Specificity = require("./Specificity");
  4278.  
  4279. /**
  4280.  * Represents an entire single selector, including all parts but not
  4281.  * including multiple selectors (those separated by commas).
  4282.  * @namespace parserlib.css
  4283.  * @class Selector
  4284.  * @extends parserlib.util.SyntaxUnit
  4285.  * @constructor
  4286.  * @param {Array} parts Array of selectors parts making up this selector.
  4287.  * @param {int} line The line of text on which the unit resides.
  4288.  * @param {int} col The column of text on which the unit resides.
  4289.  */
  4290. function Selector(parts, line, col) {
  4291.  
  4292.     SyntaxUnit.call(this, parts.join(" "), line, col, Parser.SELECTOR_TYPE);
  4293.  
  4294.     /**
  4295.      * The parts that make up the selector.
  4296.      * @type Array
  4297.      * @property parts
  4298.      */
  4299.     this.parts = parts;
  4300.  
  4301.     /**
  4302.      * The specificity of the selector.
  4303.      * @type parserlib.css.Specificity
  4304.      * @property specificity
  4305.      */
  4306.     this.specificity = Specificity.calculate(this);
  4307.  
  4308. }
  4309.  
  4310. Selector.prototype = new SyntaxUnit();
  4311. Selector.prototype.constructor = Selector;
  4312.  
  4313.  
  4314. },{"../util/SyntaxUnit":26,"./Parser":6,"./Specificity":16}],14:[function(require,module,exports){
  4315. "use strict";
  4316.  
  4317. module.exports = SelectorPart;
  4318.  
  4319. var SyntaxUnit = require("../util/SyntaxUnit");
  4320.  
  4321. var Parser = require("./Parser");
  4322.  
  4323. /**
  4324.  * Represents a single part of a selector string, meaning a single set of
  4325.  * element name and modifiers. This does not include combinators such as
  4326.  * spaces, +, >, etc.
  4327.  * @namespace parserlib.css
  4328.  * @class SelectorPart
  4329.  * @extends parserlib.util.SyntaxUnit
  4330.  * @constructor
  4331.  * @param {String} elementName The element name in the selector or null
  4332.  *      if there is no element name.
  4333.  * @param {Array} modifiers Array of individual modifiers for the element.
  4334.  *      May be empty if there are none.
  4335.  * @param {String} text The text representation of the unit.
  4336.  * @param {int} line The line of text on which the unit resides.
  4337.  * @param {int} col The column of text on which the unit resides.
  4338.  */
  4339. function SelectorPart(elementName, modifiers, text, line, col) {
  4340.  
  4341.     SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_PART_TYPE);
  4342.  
  4343.     /**
  4344.      * The tag name of the element to which this part
  4345.      * of the selector affects.
  4346.      * @type String
  4347.      * @property elementName
  4348.      */
  4349.     this.elementName = elementName;
  4350.  
  4351.     /**
  4352.      * The parts that come after the element name, such as class names, IDs,
  4353.      * pseudo classes/elements, etc.
  4354.      * @type Array
  4355.      * @property modifiers
  4356.      */
  4357.     this.modifiers = modifiers;
  4358.  
  4359. }
  4360.  
  4361. SelectorPart.prototype = new SyntaxUnit();
  4362. SelectorPart.prototype.constructor = SelectorPart;
  4363.  
  4364.  
  4365. },{"../util/SyntaxUnit":26,"./Parser":6}],15:[function(require,module,exports){
  4366. "use strict";
  4367.  
  4368. module.exports = SelectorSubPart;
  4369.  
  4370. var SyntaxUnit = require("../util/SyntaxUnit");
  4371.  
  4372. var Parser = require("./Parser");
  4373.  
  4374. /**
  4375.  * Represents a selector modifier string, meaning a class name, element name,
  4376.  * element ID, pseudo rule, etc.
  4377.  * @namespace parserlib.css
  4378.  * @class SelectorSubPart
  4379.  * @extends parserlib.util.SyntaxUnit
  4380.  * @constructor
  4381.  * @param {String} text The text representation of the unit.
  4382.  * @param {String} type The type of selector modifier.
  4383.  * @param {int} line The line of text on which the unit resides.
  4384.  * @param {int} col The column of text on which the unit resides.
  4385.  */
  4386. function SelectorSubPart(text, type, line, col) {
  4387.  
  4388.     SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_SUB_PART_TYPE);
  4389.  
  4390.     /**
  4391.      * The type of modifier.
  4392.      * @type String
  4393.      * @property type
  4394.      */
  4395.     this.type = type;
  4396.  
  4397.     /**
  4398.      * Some subparts have arguments, this represents them.
  4399.      * @type Array
  4400.      * @property args
  4401.      */
  4402.     this.args = [];
  4403.  
  4404. }
  4405.  
  4406. SelectorSubPart.prototype = new SyntaxUnit();
  4407. SelectorSubPart.prototype.constructor = SelectorSubPart;
  4408.  
  4409.  
  4410. },{"../util/SyntaxUnit":26,"./Parser":6}],16:[function(require,module,exports){
  4411. "use strict";
  4412.  
  4413. module.exports = Specificity;
  4414.  
  4415. var Pseudos = require("./Pseudos");
  4416. var SelectorPart = require("./SelectorPart");
  4417.  
  4418. /**
  4419.  * Represents a selector's specificity.
  4420.  * @namespace parserlib.css
  4421.  * @class Specificity
  4422.  * @constructor
  4423.  * @param {int} a Should be 1 for inline styles, zero for stylesheet styles
  4424.  * @param {int} b Number of ID selectors
  4425.  * @param {int} c Number of classes and pseudo classes
  4426.  * @param {int} d Number of element names and pseudo elements
  4427.  */
  4428. function Specificity(a, b, c, d) {
  4429.     this.a = a;
  4430.     this.b = b;
  4431.     this.c = c;
  4432.     this.d = d;
  4433. }
  4434.  
  4435. Specificity.prototype = {
  4436.     constructor: Specificity,
  4437.  
  4438.     /**
  4439.      * Compare this specificity to another.
  4440.      * @param {Specificity} other The other specificity to compare to.
  4441.      * @return {int} -1 if the other specificity is larger, 1 if smaller, 0 if equal.
  4442.      * @method compare
  4443.      */
  4444.     compare: function(other) {
  4445.         var comps = ["a", "b", "c", "d"],
  4446.             i, len;
  4447.  
  4448.         for (i=0, len=comps.length; i < len; i++) {
  4449.             if (this[comps[i]] < other[comps[i]]) {
  4450.                 return -1;
  4451.             } else if (this[comps[i]] > other[comps[i]]) {
  4452.                 return 1;
  4453.             }
  4454.         }
  4455.  
  4456.         return 0;
  4457.     },
  4458.  
  4459.     /**
  4460.      * Creates a numeric value for the specificity.
  4461.      * @return {int} The numeric value for the specificity.
  4462.      * @method valueOf
  4463.      */
  4464.     valueOf: function() {
  4465.         return (this.a * 1000) + (this.b * 100) + (this.c * 10) + this.d;
  4466.     },
  4467.  
  4468.     /**
  4469.      * Returns a string representation for specificity.
  4470.      * @return {String} The string representation of specificity.
  4471.      * @method toString
  4472.      */
  4473.     toString: function() {
  4474.         return this.a + "," + this.b + "," + this.c + "," + this.d;
  4475.     }
  4476.  
  4477. };
  4478.  
  4479. /**
  4480.  * Calculates the specificity of the given selector.
  4481.  * @param {parserlib.css.Selector} The selector to calculate specificity for.
  4482.  * @return {parserlib.css.Specificity} The specificity of the selector.
  4483.  * @static
  4484.  * @method calculate
  4485.  */
  4486. Specificity.calculate = function(selector) {
  4487.  
  4488.     var i, len,
  4489.         part,
  4490.         b=0, c=0, d=0;
  4491.  
  4492.     function updateValues(part) {
  4493.  
  4494.         var i, j, len, num,
  4495.             elementName = part.elementName ? part.elementName.text : "",
  4496.             modifier;
  4497.  
  4498.         if (elementName && elementName.charAt(elementName.length-1) !== "*") {
  4499.             d++;
  4500.         }
  4501.  
  4502.         for (i=0, len=part.modifiers.length; i < len; i++) {
  4503.             modifier = part.modifiers[i];
  4504.             switch (modifier.type) {
  4505.                 case "class":
  4506.                 case "attribute":
  4507.                     c++;
  4508.                     break;
  4509.  
  4510.                 case "id":
  4511.                     b++;
  4512.                     break;
  4513.  
  4514.                 case "pseudo":
  4515.                     if (Pseudos.isElement(modifier.text)) {
  4516.                         d++;
  4517.                     } else {
  4518.                         c++;
  4519.                     }
  4520.                     break;
  4521.  
  4522.                 case "not":
  4523.                     for (j=0, num=modifier.args.length; j < num; j++) {
  4524.                         updateValues(modifier.args[j]);
  4525.                     }
  4526.             }
  4527.         }
  4528.     }
  4529.  
  4530.     for (i=0, len=selector.parts.length; i < len; i++) {
  4531.         part = selector.parts[i];
  4532.  
  4533.         if (part instanceof SelectorPart) {
  4534.             updateValues(part);
  4535.         }
  4536.     }
  4537.  
  4538.     return new Specificity(0, b, c, d);
  4539. };
  4540.  
  4541. },{"./Pseudos":12,"./SelectorPart":14}],17:[function(require,module,exports){
  4542. "use strict";
  4543.  
  4544. module.exports = TokenStream;
  4545.  
  4546. var TokenStreamBase = require("../util/TokenStreamBase");
  4547.  
  4548. var PropertyValuePart = require("./PropertyValuePart");
  4549. var Tokens = require("./Tokens");
  4550.  
  4551. var h = /^[0-9a-fA-F]$/,
  4552.     nonascii = /^[\u00A0-\uFFFF]$/,
  4553.     nl = /\n|\r\n|\r|\f/,
  4554.     whitespace = /\u0009|\u000a|\u000c|\u000d|\u0020/;
  4555.  
  4556. //-----------------------------------------------------------------------------
  4557. // Helper functions
  4558. //-----------------------------------------------------------------------------
  4559.  
  4560.  
  4561. function isHexDigit(c) {
  4562.     return c !== null && h.test(c);
  4563. }
  4564.  
  4565. function isDigit(c) {
  4566.     return c !== null && /\d/.test(c);
  4567. }
  4568.  
  4569. function isWhitespace(c) {
  4570.     return c !== null && whitespace.test(c);
  4571. }
  4572.  
  4573. function isNewLine(c) {
  4574.     return c !== null && nl.test(c);
  4575. }
  4576.  
  4577. function isNameStart(c) {
  4578.     return c !== null && /[a-z_\u00A0-\uFFFF\\]/i.test(c);
  4579. }
  4580.  
  4581. function isNameChar(c) {
  4582.     return c !== null && (isNameStart(c) || /[0-9\-\\]/.test(c));
  4583. }
  4584.  
  4585. function isIdentStart(c) {
  4586.     return c !== null && (isNameStart(c) || /\-\\/.test(c));
  4587. }
  4588.  
  4589. function mix(receiver, supplier) {
  4590.     for (var prop in supplier) {
  4591.         if (Object.prototype.hasOwnProperty.call(supplier, prop)) {
  4592.             receiver[prop] = supplier[prop];
  4593.         }
  4594.     }
  4595.     return receiver;
  4596. }
  4597.  
  4598. //-----------------------------------------------------------------------------
  4599. // CSS Token Stream
  4600. //-----------------------------------------------------------------------------
  4601.  
  4602.  
  4603. /**
  4604.  * A token stream that produces CSS tokens.
  4605.  * @param {String|Reader} input The source of text to tokenize.
  4606.  * @constructor
  4607.  * @class TokenStream
  4608.  * @namespace parserlib.css
  4609.  */
  4610. function TokenStream(input) {
  4611.     TokenStreamBase.call(this, input, Tokens);
  4612. }
  4613.  
  4614. TokenStream.prototype = mix(new TokenStreamBase(), {
  4615.  
  4616.     /**
  4617.      * Overrides the TokenStreamBase method of the same name
  4618.      * to produce CSS tokens.
  4619.      * @return {Object} A token object representing the next token.
  4620.      * @method _getToken
  4621.      * @private
  4622.      */
  4623.     _getToken: function() {
  4624.  
  4625.         var c,
  4626.             reader = this._reader,
  4627.             token   = null,
  4628.             startLine   = reader.getLine(),
  4629.             startCol    = reader.getCol();
  4630.  
  4631.         c = reader.read();
  4632.  
  4633.  
  4634.         while (c) {
  4635.             switch (c) {
  4636.  
  4637.                 /*
  4638.                  * Potential tokens:
  4639.                  * - COMMENT
  4640.                  * - SLASH
  4641.                  * - CHAR
  4642.                  */
  4643.                 case "/":
  4644.  
  4645.                     if (reader.peek() === "*") {
  4646.                         token = this.commentToken(c, startLine, startCol);
  4647.                     } else {
  4648.                         token = this.charToken(c, startLine, startCol);
  4649.                     }
  4650.                     break;
  4651.  
  4652.                 /*
  4653.                  * Potential tokens:
  4654.                  * - DASHMATCH
  4655.                  * - INCLUDES
  4656.                  * - PREFIXMATCH
  4657.                  * - SUFFIXMATCH
  4658.                  * - SUBSTRINGMATCH
  4659.                  * - CHAR
  4660.                  */
  4661.                 case "|":
  4662.                 case "~":
  4663.                 case "^":
  4664.                 case "$":
  4665.                 case "*":
  4666.                     if (reader.peek() === "=") {
  4667.                         token = this.comparisonToken(c, startLine, startCol);
  4668.                     } else {
  4669.                         token = this.charToken(c, startLine, startCol);
  4670.                     }
  4671.                     break;
  4672.  
  4673.                 /*
  4674.                  * Potential tokens:
  4675.                  * - STRING
  4676.                  * - INVALID
  4677.                  */
  4678.                 case "\"":
  4679.                 case "'":
  4680.                     token = this.stringToken(c, startLine, startCol);
  4681.                     break;
  4682.  
  4683.                 /*
  4684.                  * Potential tokens:
  4685.                  * - HASH
  4686.                  * - CHAR
  4687.                  */
  4688.                 case "#":
  4689.                     if (isNameChar(reader.peek())) {
  4690.                         token = this.hashToken(c, startLine, startCol);
  4691.                     } else {
  4692.                         token = this.charToken(c, startLine, startCol);
  4693.                     }
  4694.                     break;
  4695.  
  4696.                 /*
  4697.                  * Potential tokens:
  4698.                  * - DOT
  4699.                  * - NUMBER
  4700.                  * - DIMENSION
  4701.                  * - PERCENTAGE
  4702.                  */
  4703.                 case ".":
  4704.                     if (isDigit(reader.peek())) {
  4705.                         token = this.numberToken(c, startLine, startCol);
  4706.                     } else {
  4707.                         token = this.charToken(c, startLine, startCol);
  4708.                     }
  4709.                     break;
  4710.  
  4711.                 /*
  4712.                  * Potential tokens:
  4713.                  * - CDC
  4714.                  * - MINUS
  4715.                  * - NUMBER
  4716.                  * - DIMENSION
  4717.                  * - PERCENTAGE
  4718.                  */
  4719.                 case "-":
  4720.                     if (reader.peek() === "-") {  //could be closing HTML-style comment
  4721.                         token = this.htmlCommentEndToken(c, startLine, startCol);
  4722.                     } else if (isNameStart(reader.peek())) {
  4723.                         token = this.identOrFunctionToken(c, startLine, startCol);
  4724.                     } else {
  4725.                         token = this.charToken(c, startLine, startCol);
  4726.                     }
  4727.                     break;
  4728.  
  4729.                 /*
  4730.                  * Potential tokens:
  4731.                  * - IMPORTANT_SYM
  4732.                  * - CHAR
  4733.                  */
  4734.                 case "!":
  4735.                     token = this.importantToken(c, startLine, startCol);
  4736.                     break;
  4737.  
  4738.                 /*
  4739.                  * Any at-keyword or CHAR
  4740.                  */
  4741.                 case "@":
  4742.                     token = this.atRuleToken(c, startLine, startCol);
  4743.                     break;
  4744.  
  4745.                 /*
  4746.                  * Potential tokens:
  4747.                  * - NOT
  4748.                  * - CHAR
  4749.                  */
  4750.                 case ":":
  4751.                     token = this.notToken(c, startLine, startCol);
  4752.                     break;
  4753.  
  4754.                 /*
  4755.                  * Potential tokens:
  4756.                  * - CDO
  4757.                  * - CHAR
  4758.                  */
  4759.                 case "<":
  4760.                     token = this.htmlCommentStartToken(c, startLine, startCol);
  4761.                     break;
  4762.  
  4763.                 /*
  4764.                  * Potential tokens:
  4765.                  * - IDENT
  4766.                  * - CHAR
  4767.                  */
  4768.                 case "\\":
  4769.                     if (/[^\r\n\f]/.test(reader.peek())) {
  4770.                         token = this.identOrFunctionToken(this.readEscape(c, true), startLine, startCol);
  4771.                     } else {
  4772.                         token = this.charToken(c, startLine, startCol);
  4773.                     }
  4774.                     break;
  4775.  
  4776.                 /*
  4777.                  * Potential tokens:
  4778.                  * - UNICODE_RANGE
  4779.                  * - URL
  4780.                  * - CHAR
  4781.                  */
  4782.                 case "U":
  4783.                 case "u":
  4784.                     if (reader.peek() === "+") {
  4785.                         token = this.unicodeRangeToken(c, startLine, startCol);
  4786.                         break;
  4787.                     }
  4788.                     /* falls through */
  4789.                 default:
  4790.  
  4791.                     /*
  4792.                      * Potential tokens:
  4793.                      * - NUMBER
  4794.                      * - DIMENSION
  4795.                      * - LENGTH
  4796.                      * - FREQ
  4797.                      * - TIME
  4798.                      * - EMS
  4799.                      * - EXS
  4800.                      * - ANGLE
  4801.                      */
  4802.                     if (isDigit(c)) {
  4803.                         token = this.numberToken(c, startLine, startCol);
  4804.                     } else
  4805.  
  4806.                     /*
  4807.                      * Potential tokens:
  4808.                      * - S
  4809.                      */
  4810.                     if (isWhitespace(c)) {
  4811.                         token = this.whitespaceToken(c, startLine, startCol);
  4812.                     } else
  4813.  
  4814.                     /*
  4815.                      * Potential tokens:
  4816.                      * - IDENT
  4817.                      */
  4818.                     if (isIdentStart(c)) {
  4819.                         token = this.identOrFunctionToken(c, startLine, startCol);
  4820.                     } else {
  4821.                        /*
  4822.                         * Potential tokens:
  4823.                         * - CHAR
  4824.                         * - PLUS
  4825.                         */
  4826.                         token = this.charToken(c, startLine, startCol);
  4827.                     }
  4828.  
  4829.             }
  4830.  
  4831.             //make sure this token is wanted
  4832.             //TODO: check channel
  4833.             break;
  4834.         }
  4835.  
  4836.         if (!token && c === null) {
  4837.             token = this.createToken(Tokens.EOF, null, startLine, startCol);
  4838.         }
  4839.  
  4840.         return token;
  4841.     },
  4842.  
  4843.     //-------------------------------------------------------------------------
  4844.     // Methods to create tokens
  4845.     //-------------------------------------------------------------------------
  4846.  
  4847.     /**
  4848.      * Produces a token based on available data and the current
  4849.      * reader position information. This method is called by other
  4850.      * private methods to create tokens and is never called directly.
  4851.      * @param {int} tt The token type.
  4852.      * @param {String} value The text value of the token.
  4853.      * @param {int} startLine The beginning line for the character.
  4854.      * @param {int} startCol The beginning column for the character.
  4855.      * @param {Object} options (Optional) Specifies a channel property
  4856.      *      to indicate that a different channel should be scanned
  4857.      *      and/or a hide property indicating that the token should
  4858.      *      be hidden.
  4859.      * @return {Object} A token object.
  4860.      * @method createToken
  4861.      */
  4862.     createToken: function(tt, value, startLine, startCol, options) {
  4863.         var reader = this._reader;
  4864.         options = options || {};
  4865.  
  4866.         return {
  4867.             value:      value,
  4868.             type:       tt,
  4869.             channel:    options.channel,
  4870.             endChar:    options.endChar,
  4871.             hide:       options.hide || false,
  4872.             startLine:  startLine,
  4873.             startCol:   startCol,
  4874.             endLine:    reader.getLine(),
  4875.             endCol:     reader.getCol()
  4876.         };
  4877.     },
  4878.  
  4879.     //-------------------------------------------------------------------------
  4880.     // Methods to create specific tokens
  4881.     //-------------------------------------------------------------------------
  4882.  
  4883.     /**
  4884.      * Produces a token for any at-rule. If the at-rule is unknown, then
  4885.      * the token is for a single "@" character.
  4886.      * @param {String} first The first character for the token.
  4887.      * @param {int} startLine The beginning line for the character.
  4888.      * @param {int} startCol The beginning column for the character.
  4889.      * @return {Object} A token object.
  4890.      * @method atRuleToken
  4891.      */
  4892.     atRuleToken: function(first, startLine, startCol) {
  4893.         var rule    = first,
  4894.             reader  = this._reader,
  4895.             tt      = Tokens.CHAR,
  4896.             ident;
  4897.  
  4898.         /*
  4899.          * First, mark where we are. There are only four @ rules,
  4900.          * so anything else is really just an invalid token.
  4901.          * Basically, if this doesn't match one of the known @
  4902.          * rules, just return '@' as an unknown token and allow
  4903.          * parsing to continue after that point.
  4904.          */
  4905.         reader.mark();
  4906.  
  4907.         //try to find the at-keyword
  4908.         ident = this.readName();
  4909.         rule = first + ident;
  4910.         tt = Tokens.type(rule.toLowerCase());
  4911.  
  4912.         //if it's not valid, use the first character only and reset the reader
  4913.         if (tt === Tokens.CHAR || tt === Tokens.UNKNOWN) {
  4914.             if (rule.length > 1) {
  4915.                 tt = Tokens.UNKNOWN_SYM;
  4916.             } else {
  4917.                 tt = Tokens.CHAR;
  4918.                 rule = first;
  4919.                 reader.reset();
  4920.             }
  4921.         }
  4922.  
  4923.         return this.createToken(tt, rule, startLine, startCol);
  4924.     },
  4925.  
  4926.     /**
  4927.      * Produces a character token based on the given character
  4928.      * and location in the stream. If there's a special (non-standard)
  4929.      * token name, this is used; otherwise CHAR is used.
  4930.      * @param {String} c The character for the token.
  4931.      * @param {int} startLine The beginning line for the character.
  4932.      * @param {int} startCol The beginning column for the character.
  4933.      * @return {Object} A token object.
  4934.      * @method charToken
  4935.      */
  4936.     charToken: function(c, startLine, startCol) {
  4937.         var tt = Tokens.type(c);
  4938.         var opts = {};
  4939.  
  4940.         if (tt === -1) {
  4941.             tt = Tokens.CHAR;
  4942.         } else {
  4943.             opts.endChar = Tokens[tt].endChar;
  4944.         }
  4945.  
  4946.         return this.createToken(tt, c, startLine, startCol, opts);
  4947.     },
  4948.  
  4949.     /**
  4950.      * Produces a character token based on the given character
  4951.      * and location in the stream. If there's a special (non-standard)
  4952.      * token name, this is used; otherwise CHAR is used.
  4953.      * @param {String} first The first character for the token.
  4954.      * @param {int} startLine The beginning line for the character.
  4955.      * @param {int} startCol The beginning column for the character.
  4956.      * @return {Object} A token object.
  4957.      * @method commentToken
  4958.      */
  4959.     commentToken: function(first, startLine, startCol) {
  4960.         var comment = this.readComment(first);
  4961.  
  4962.         return this.createToken(Tokens.COMMENT, comment, startLine, startCol);
  4963.     },
  4964.  
  4965.     /**
  4966.      * Produces a comparison token based on the given character
  4967.      * and location in the stream. The next character must be
  4968.      * read and is already known to be an equals sign.
  4969.      * @param {String} c The character for the token.
  4970.      * @param {int} startLine The beginning line for the character.
  4971.      * @param {int} startCol The beginning column for the character.
  4972.      * @return {Object} A token object.
  4973.      * @method comparisonToken
  4974.      */
  4975.     comparisonToken: function(c, startLine, startCol) {
  4976.         var reader  = this._reader,
  4977.             comparison  = c + reader.read(),
  4978.             tt      = Tokens.type(comparison) || Tokens.CHAR;
  4979.  
  4980.         return this.createToken(tt, comparison, startLine, startCol);
  4981.     },
  4982.  
  4983.     /**
  4984.      * Produces a hash token based on the specified information. The
  4985.      * first character provided is the pound sign (#) and then this
  4986.      * method reads a name afterward.
  4987.      * @param {String} first The first character (#) in the hash name.
  4988.      * @param {int} startLine The beginning line for the character.
  4989.      * @param {int} startCol The beginning column for the character.
  4990.      * @return {Object} A token object.
  4991.      * @method hashToken
  4992.      */
  4993.     hashToken: function(first, startLine, startCol) {
  4994.         var name    = this.readName(first);
  4995.  
  4996.         return this.createToken(Tokens.HASH, name, startLine, startCol);
  4997.     },
  4998.  
  4999.     /**
  5000.      * Produces a CDO or CHAR token based on the specified information. The
  5001.      * first character is provided and the rest is read by the function to determine
  5002.      * the correct token to create.
  5003.      * @param {String} first The first character in the token.
  5004.      * @param {int} startLine The beginning line for the character.
  5005.      * @param {int} startCol The beginning column for the character.
  5006.      * @return {Object} A token object.
  5007.      * @method htmlCommentStartToken
  5008.      */
  5009.     htmlCommentStartToken: function(first, startLine, startCol) {
  5010.         var reader      = this._reader,
  5011.             text        = first;
  5012.  
  5013.         reader.mark();
  5014.         text += reader.readCount(3);
  5015.  
  5016.         if (text === "<!--") {
  5017.             return this.createToken(Tokens.CDO, text, startLine, startCol);
  5018.         } else {
  5019.             reader.reset();
  5020.             return this.charToken(first, startLine, startCol);
  5021.         }
  5022.     },
  5023.  
  5024.     /**
  5025.      * Produces a CDC or CHAR token based on the specified information. The
  5026.      * first character is provided and the rest is read by the function to determine
  5027.      * the correct token to create.
  5028.      * @param {String} first The first character in the token.
  5029.      * @param {int} startLine The beginning line for the character.
  5030.      * @param {int} startCol The beginning column for the character.
  5031.      * @return {Object} A token object.
  5032.      * @method htmlCommentEndToken
  5033.      */
  5034.     htmlCommentEndToken: function(first, startLine, startCol) {
  5035.         var reader      = this._reader,
  5036.             text        = first;
  5037.  
  5038.         reader.mark();
  5039.         text += reader.readCount(2);
  5040.  
  5041.         if (text === "-->") {
  5042.             return this.createToken(Tokens.CDC, text, startLine, startCol);
  5043.         } else {
  5044.             reader.reset();
  5045.             return this.charToken(first, startLine, startCol);
  5046.         }
  5047.     },
  5048.  
  5049.     /**
  5050.      * Produces an IDENT or FUNCTION token based on the specified information. The
  5051.      * first character is provided and the rest is read by the function to determine
  5052.      * the correct token to create.
  5053.      * @param {String} first The first character in the identifier.
  5054.      * @param {int} startLine The beginning line for the character.
  5055.      * @param {int} startCol The beginning column for the character.
  5056.      * @return {Object} A token object.
  5057.      * @method identOrFunctionToken
  5058.      */
  5059.     identOrFunctionToken: function(first, startLine, startCol) {
  5060.         var reader  = this._reader,
  5061.             ident   = this.readName(first),
  5062.             tt      = Tokens.IDENT,
  5063.             uriFns  = ["url(", "url-prefix(", "domain("],
  5064.             uri;
  5065.  
  5066.         //if there's a left paren immediately after, it's a URI or function
  5067.         if (reader.peek() === "(") {
  5068.             ident += reader.read();
  5069.             if (uriFns.indexOf(ident.toLowerCase()) > -1) {
  5070.                 reader.mark();
  5071.                 uri = this.readURI(ident);
  5072.                 if (uri === null) {
  5073.                     //didn't find a valid URL or there's no closing paren
  5074.                     reader.reset();
  5075.                     tt = Tokens.FUNCTION;
  5076.                 } else {
  5077.                     tt = Tokens.URI;
  5078.                     ident = uri;
  5079.                 }
  5080.             } else {
  5081.                 tt = Tokens.FUNCTION;
  5082.             }
  5083.         } else if (reader.peek() === ":") {  //might be an IE function
  5084.  
  5085.             //IE-specific functions always being with progid:
  5086.             if (ident.toLowerCase() === "progid") {
  5087.                 ident += reader.readTo("(");
  5088.                 tt = Tokens.IE_FUNCTION;
  5089.             }
  5090.         }
  5091.  
  5092.         return this.createToken(tt, ident, startLine, startCol);
  5093.     },
  5094.  
  5095.     /**
  5096.      * Produces an IMPORTANT_SYM or CHAR token based on the specified information. The
  5097.      * first character is provided and the rest is read by the function to determine
  5098.      * the correct token to create.
  5099.      * @param {String} first The first character in the token.
  5100.      * @param {int} startLine The beginning line for the character.
  5101.      * @param {int} startCol The beginning column for the character.
  5102.      * @return {Object} A token object.
  5103.      * @method importantToken
  5104.      */
  5105.     importantToken: function(first, startLine, startCol) {
  5106.         var reader      = this._reader,
  5107.             important   = first,
  5108.             tt          = Tokens.CHAR,
  5109.             temp,
  5110.             c;
  5111.  
  5112.         reader.mark();
  5113.         c = reader.read();
  5114.  
  5115.         while (c) {
  5116.  
  5117.             //there can be a comment in here
  5118.             if (c === "/") {
  5119.  
  5120.                 //if the next character isn't a star, then this isn't a valid !important token
  5121.                 if (reader.peek() !== "*") {
  5122.                     break;
  5123.                 } else {
  5124.                     temp = this.readComment(c);
  5125.                     if (temp === "") {    //broken!
  5126.                         break;
  5127.                     }
  5128.                 }
  5129.             } else if (isWhitespace(c)) {
  5130.                 important += c + this.readWhitespace();
  5131.             } else if (/i/i.test(c)) {
  5132.                 temp = reader.readCount(8);
  5133.                 if (/mportant/i.test(temp)) {
  5134.                     important += c + temp;
  5135.                     tt = Tokens.IMPORTANT_SYM;
  5136.  
  5137.                 }
  5138.                 break;  //we're done
  5139.             } else {
  5140.                 break;
  5141.             }
  5142.  
  5143.             c = reader.read();
  5144.         }
  5145.  
  5146.         if (tt === Tokens.CHAR) {
  5147.             reader.reset();
  5148.             return this.charToken(first, startLine, startCol);
  5149.         } else {
  5150.             return this.createToken(tt, important, startLine, startCol);
  5151.         }
  5152.  
  5153.  
  5154.     },
  5155.  
  5156.     /**
  5157.      * Produces a NOT or CHAR token based on the specified information. The
  5158.      * first character is provided and the rest is read by the function to determine
  5159.      * the correct token to create.
  5160.      * @param {String} first The first character in the token.
  5161.      * @param {int} startLine The beginning line for the character.
  5162.      * @param {int} startCol The beginning column for the character.
  5163.      * @return {Object} A token object.
  5164.      * @method notToken
  5165.      */
  5166.     notToken: function(first, startLine, startCol) {
  5167.         var reader      = this._reader,
  5168.             text        = first;
  5169.  
  5170.         reader.mark();
  5171.         text += reader.readCount(4);
  5172.  
  5173.         if (text.toLowerCase() === ":not(") {
  5174.             return this.createToken(Tokens.NOT, text, startLine, startCol);
  5175.         } else {
  5176.             reader.reset();
  5177.             return this.charToken(first, startLine, startCol);
  5178.         }
  5179.     },
  5180.  
  5181.     /**
  5182.      * Produces a number token based on the given character
  5183.      * and location in the stream. This may return a token of
  5184.      * NUMBER, EMS, EXS, LENGTH, ANGLE, TIME, FREQ, DIMENSION,
  5185.      * or PERCENTAGE.
  5186.      * @param {String} first The first character for the token.
  5187.      * @param {int} startLine The beginning line for the character.
  5188.      * @param {int} startCol The beginning column for the character.
  5189.      * @return {Object} A token object.
  5190.      * @method numberToken
  5191.      */
  5192.     numberToken: function(first, startLine, startCol) {
  5193.         var reader  = this._reader,
  5194.             value   = this.readNumber(first),
  5195.             ident,
  5196.             tt      = Tokens.NUMBER,
  5197.             c       = reader.peek();
  5198.  
  5199.         if (isIdentStart(c)) {
  5200.             ident = this.readName(reader.read());
  5201.             value += ident;
  5202.  
  5203.             if (/^em$|^ex$|^px$|^gd$|^rem$|^vw$|^vh$|^vmax$|^vmin$|^ch$|^cm$|^mm$|^in$|^pt$|^pc$/i.test(ident)) {
  5204.                 tt = Tokens.LENGTH;
  5205.             } else if (/^deg|^rad$|^grad$|^turn$/i.test(ident)) {
  5206.                 tt = Tokens.ANGLE;
  5207.             } else if (/^ms$|^s$/i.test(ident)) {
  5208.                 tt = Tokens.TIME;
  5209.             } else if (/^hz$|^khz$/i.test(ident)) {
  5210.                 tt = Tokens.FREQ;
  5211.             } else if (/^dpi$|^dpcm$/i.test(ident)) {
  5212.                 tt = Tokens.RESOLUTION;
  5213.             } else {
  5214.                 tt = Tokens.DIMENSION;
  5215.             }
  5216.  
  5217.         } else if (c === "%") {
  5218.             value += reader.read();
  5219.             tt = Tokens.PERCENTAGE;
  5220.         }
  5221.  
  5222.         return this.createToken(tt, value, startLine, startCol);
  5223.     },
  5224.  
  5225.     /**
  5226.      * Produces a string token based on the given character
  5227.      * and location in the stream. Since strings may be indicated
  5228.      * by single or double quotes, a failure to match starting
  5229.      * and ending quotes results in an INVALID token being generated.
  5230.      * The first character in the string is passed in and then
  5231.      * the rest are read up to and including the final quotation mark.
  5232.      * @param {String} first The first character in the string.
  5233.      * @param {int} startLine The beginning line for the character.
  5234.      * @param {int} startCol The beginning column for the character.
  5235.      * @return {Object} A token object.
  5236.      * @method stringToken
  5237.      */
  5238.     stringToken: function(first, startLine, startCol) {
  5239.         var delim   = first,
  5240.             string  = first,
  5241.             reader  = this._reader,
  5242.             tt      = Tokens.STRING,
  5243.             c       = reader.read(),
  5244.             i;
  5245.  
  5246.         while (c) {
  5247.             string += c;
  5248.  
  5249.             if (c === "\\") {
  5250.                 c = reader.read();
  5251.                 if (c === null) {
  5252.                     break; // premature EOF after backslash
  5253.                 } else if (/[^\r\n\f0-9a-f]/i.test(c)) {
  5254.                     // single-character escape
  5255.                     string += c;
  5256.                 } else {
  5257.                     // read up to six hex digits
  5258.                     for (i=0; isHexDigit(c) && i<6; i++) {
  5259.                         string += c;
  5260.                         c = reader.read();
  5261.                     }
  5262.                     // swallow trailing newline or space
  5263.                     if (c === "\r" && reader.peek() === "\n") {
  5264.                         string += c;
  5265.                         c = reader.read();
  5266.                     }
  5267.                     if (isWhitespace(c)) {
  5268.                         string += c;
  5269.                     } else {
  5270.                         // This character is null or not part of the escape;
  5271.                         // jump back to the top to process it.
  5272.                         continue;
  5273.                     }
  5274.                 }
  5275.             } else if (c === delim) {
  5276.                 break; // delimiter found.
  5277.             } else if (isNewLine(reader.peek())) {
  5278.                 // newline without an escapement: it's an invalid string
  5279.                 tt = Tokens.INVALID;
  5280.                 break;
  5281.             }
  5282.             c = reader.read();
  5283.         }
  5284.  
  5285.         //if c is null, that means we're out of input and the string was never closed
  5286.         if (c === null) {
  5287.             tt = Tokens.INVALID;
  5288.         }
  5289.  
  5290.         return this.createToken(tt, string, startLine, startCol);
  5291.     },
  5292.  
  5293.     unicodeRangeToken: function(first, startLine, startCol) {
  5294.         var reader  = this._reader,
  5295.             value   = first,
  5296.             temp,
  5297.             tt      = Tokens.CHAR;
  5298.  
  5299.         //then it should be a unicode range
  5300.         if (reader.peek() === "+") {
  5301.             reader.mark();
  5302.             value += reader.read();
  5303.             value += this.readUnicodeRangePart(true);
  5304.  
  5305.             //ensure there's an actual unicode range here
  5306.             if (value.length === 2) {
  5307.                 reader.reset();
  5308.             } else {
  5309.  
  5310.                 tt = Tokens.UNICODE_RANGE;
  5311.  
  5312.                 //if there's a ? in the first part, there can't be a second part
  5313.                 if (value.indexOf("?") === -1) {
  5314.  
  5315.                     if (reader.peek() === "-") {
  5316.                         reader.mark();
  5317.                         temp = reader.read();
  5318.                         temp += this.readUnicodeRangePart(false);
  5319.  
  5320.                         //if there's not another value, back up and just take the first
  5321.                         if (temp.length === 1) {
  5322.                             reader.reset();
  5323.                         } else {
  5324.                             value += temp;
  5325.                         }
  5326.                     }
  5327.  
  5328.                 }
  5329.             }
  5330.         }
  5331.  
  5332.         return this.createToken(tt, value, startLine, startCol);
  5333.     },
  5334.  
  5335.     /**
  5336.      * Produces a S token based on the specified information. Since whitespace
  5337.      * may have multiple characters, this consumes all whitespace characters
  5338.      * into a single token.
  5339.      * @param {String} first The first character in the token.
  5340.      * @param {int} startLine The beginning line for the character.
  5341.      * @param {int} startCol The beginning column for the character.
  5342.      * @return {Object} A token object.
  5343.      * @method whitespaceToken
  5344.      */
  5345.     whitespaceToken: function(first, startLine, startCol) {
  5346.         var value   = first + this.readWhitespace();
  5347.         return this.createToken(Tokens.S, value, startLine, startCol);
  5348.     },
  5349.  
  5350.  
  5351.     //-------------------------------------------------------------------------
  5352.     // Methods to read values from the string stream
  5353.     //-------------------------------------------------------------------------
  5354.  
  5355.     readUnicodeRangePart: function(allowQuestionMark) {
  5356.         var reader  = this._reader,
  5357.             part = "",
  5358.             c       = reader.peek();
  5359.  
  5360.         //first read hex digits
  5361.         while (isHexDigit(c) && part.length < 6) {
  5362.             reader.read();
  5363.             part += c;
  5364.             c = reader.peek();
  5365.         }
  5366.  
  5367.         //then read question marks if allowed
  5368.         if (allowQuestionMark) {
  5369.             while (c === "?" && part.length < 6) {
  5370.                 reader.read();
  5371.                 part += c;
  5372.                 c = reader.peek();
  5373.             }
  5374.         }
  5375.  
  5376.         //there can't be any other characters after this point
  5377.  
  5378.         return part;
  5379.     },
  5380.  
  5381.     readWhitespace: function() {
  5382.         var reader  = this._reader,
  5383.             whitespace = "",
  5384.             c       = reader.peek();
  5385.  
  5386.         while (isWhitespace(c)) {
  5387.             reader.read();
  5388.             whitespace += c;
  5389.             c = reader.peek();
  5390.         }
  5391.  
  5392.         return whitespace;
  5393.     },
  5394.     readNumber: function(first) {
  5395.         var reader  = this._reader,
  5396.             number  = first,
  5397.             hasDot  = (first === "."),
  5398.             c       = reader.peek();
  5399.  
  5400.  
  5401.         while (c) {
  5402.             if (isDigit(c)) {
  5403.                 number += reader.read();
  5404.             } else if (c === ".") {
  5405.                 if (hasDot) {
  5406.                     break;
  5407.                 } else {
  5408.                     hasDot = true;
  5409.                     number += reader.read();
  5410.                 }
  5411.             } else {
  5412.                 break;
  5413.             }
  5414.  
  5415.             c = reader.peek();
  5416.         }
  5417.  
  5418.         return number;
  5419.     },
  5420.  
  5421.     // returns null w/o resetting reader if string is invalid.
  5422.     readString: function() {
  5423.         var token = this.stringToken(this._reader.read(), 0, 0);
  5424.         return token.type === Tokens.INVALID ? null : token.value;
  5425.     },
  5426.  
  5427.     // returns null w/o resetting reader if URI is invalid.
  5428.     readURI: function(first) {
  5429.         var reader  = this._reader,
  5430.             uri     = first,
  5431.             inner   = "",
  5432.             c       = reader.peek();
  5433.  
  5434.         //skip whitespace before
  5435.         while (c && isWhitespace(c)) {
  5436.             reader.read();
  5437.             c = reader.peek();
  5438.         }
  5439.  
  5440.         //it's a string
  5441.         if (c === "'" || c === "\"") {
  5442.             inner = this.readString();
  5443.             if (inner !== null) {
  5444.                 inner = PropertyValuePart.parseString(inner);
  5445.             }
  5446.         } else {
  5447.             inner = this.readUnquotedURL();
  5448.         }
  5449.  
  5450.         c = reader.peek();
  5451.  
  5452.         //skip whitespace after
  5453.         while (c && isWhitespace(c)) {
  5454.             reader.read();
  5455.             c = reader.peek();
  5456.         }
  5457.  
  5458.         //if there was no inner value or the next character isn't closing paren, it's not a URI
  5459.         if (inner === null || c !== ")") {
  5460.             uri = null;
  5461.         } else {
  5462.             // Ensure argument to URL is always double-quoted
  5463.             // (This simplifies later processing in PropertyValuePart.)
  5464.             uri += PropertyValuePart.serializeString(inner) + reader.read();
  5465.         }
  5466.  
  5467.         return uri;
  5468.     },
  5469.     // This method never fails, although it may return an empty string.
  5470.     readUnquotedURL: function(first) {
  5471.         var reader  = this._reader,
  5472.             url     = first || "",
  5473.             c;
  5474.  
  5475.         for (c = reader.peek(); c; c = reader.peek()) {
  5476.             // Note that the grammar at
  5477.             // https://www.w3.org/TR/CSS2/grammar.html#scanner
  5478.             // incorrectly includes the backslash character in the
  5479.             // `url` production, although it is correctly omitted in
  5480.             // the `baduri1` production.
  5481.             if (nonascii.test(c) || /^[\-!#$%&*-\[\]-~]$/.test(c)) {
  5482.                 url += c;
  5483.                 reader.read();
  5484.             } else if (c === "\\") {
  5485.                 if (/^[^\r\n\f]$/.test(reader.peek(2))) {
  5486.                     url += this.readEscape(reader.read(), true);
  5487.                 } else {
  5488.                     break; // bad escape sequence.
  5489.                 }
  5490.             } else {
  5491.                 break; // bad character
  5492.             }
  5493.         }
  5494.  
  5495.         return url;
  5496.     },
  5497.  
  5498.     readName: function(first) {
  5499.         var reader  = this._reader,
  5500.             ident   = first || "",
  5501.             c;
  5502.  
  5503.         for (c = reader.peek(); c; c = reader.peek()) {
  5504.             if (c === "\\") {
  5505.                 if (/^[^\r\n\f]$/.test(reader.peek(2))) {
  5506.                     ident += this.readEscape(reader.read(), true);
  5507.                 } else {
  5508.                     // Bad escape sequence.
  5509.                     break;
  5510.                 }
  5511.             } else if (isNameChar(c)) {
  5512.                 ident += reader.read();
  5513.             } else {
  5514.                 break;
  5515.             }
  5516.         }
  5517.  
  5518.         return ident;
  5519.     },
  5520.  
  5521.     readEscape: function(first, unescape) {
  5522.         var reader  = this._reader,
  5523.             cssEscape = first || "",
  5524.             i       = 0,
  5525.             c       = reader.peek();
  5526.  
  5527.         if (isHexDigit(c)) {
  5528.             do {
  5529.                 cssEscape += reader.read();
  5530.                 c = reader.peek();
  5531.             } while (c && isHexDigit(c) && ++i < 6);
  5532.         }
  5533.  
  5534.         if (cssEscape.length === 1) {
  5535.             if (/^[^\r\n\f0-9a-f]$/.test(c)) {
  5536.                 reader.read();
  5537.                 if (unescape) {
  5538.                     return c;
  5539.                 }
  5540.             } else {
  5541.                 // We should never get here (readName won't call readEscape
  5542.                 // if the escape sequence is bad).
  5543.                 throw new Error("Bad escape sequence.");
  5544.             }
  5545.         } else if (c === "\r") {
  5546.             reader.read();
  5547.             if (reader.peek() === "\n") {
  5548.                 c += reader.read();
  5549.             }
  5550.         } else if (/^[ \t\n\f]$/.test(c)) {
  5551.             reader.read();
  5552.         } else {
  5553.             c = "";
  5554.         }
  5555.  
  5556.         if (unescape) {
  5557.             var cp = parseInt(cssEscape.slice(first.length), 16);
  5558.             return String.fromCodePoint ? String.fromCodePoint(cp) :
  5559.                 String.fromCharCode(cp);
  5560.         }
  5561.         return cssEscape + c;
  5562.     },
  5563.  
  5564.     readComment: function(first) {
  5565.         var reader  = this._reader,
  5566.             comment = first || "",
  5567.             c       = reader.read();
  5568.  
  5569.         if (c === "*") {
  5570.             while (c) {
  5571.                 comment += c;
  5572.  
  5573.                 //look for end of comment
  5574.                 if (comment.length > 2 && c === "*" && reader.peek() === "/") {
  5575.                     comment += reader.read();
  5576.                     break;
  5577.                 }
  5578.  
  5579.                 c = reader.read();
  5580.             }
  5581.  
  5582.             return comment;
  5583.         } else {
  5584.             return "";
  5585.         }
  5586.  
  5587.     }
  5588. });
  5589.  
  5590. },{"../util/TokenStreamBase":27,"./PropertyValuePart":11,"./Tokens":18}],18:[function(require,module,exports){
  5591. "use strict";
  5592.  
  5593. var Tokens = module.exports = [
  5594.  
  5595.     /*
  5596.      * The following token names are defined in CSS3 Grammar: https://www.w3.org/TR/css3-syntax/#lexical
  5597.      */
  5598.  
  5599.     // HTML-style comments
  5600.     { name: "CDO" },
  5601.     { name: "CDC" },
  5602.  
  5603.     // ignorables
  5604.     { name: "S", whitespace: true/*, channel: "ws"*/ },
  5605.     { name: "COMMENT", comment: true, hide: true, channel: "comment" },
  5606.  
  5607.     // attribute equality
  5608.     { name: "INCLUDES", text: "~=" },
  5609.     { name: "DASHMATCH", text: "|=" },
  5610.     { name: "PREFIXMATCH", text: "^=" },
  5611.     { name: "SUFFIXMATCH", text: "$=" },
  5612.     { name: "SUBSTRINGMATCH", text: "*=" },
  5613.  
  5614.     // identifier types
  5615.     { name: "STRING" },
  5616.     { name: "IDENT" },
  5617.     { name: "HASH" },
  5618.  
  5619.     // at-keywords
  5620.     { name: "IMPORT_SYM", text: "@import" },
  5621.     { name: "PAGE_SYM", text: "@page" },
  5622.     { name: "MEDIA_SYM", text: "@media" },
  5623.     { name: "FONT_FACE_SYM", text: "@font-face" },
  5624.     { name: "CHARSET_SYM", text: "@charset" },
  5625.     { name: "NAMESPACE_SYM", text: "@namespace" },
  5626.     { name: "SUPPORTS_SYM", text: "@supports" },
  5627.     { name: "VIEWPORT_SYM", text: ["@viewport", "@-ms-viewport", "@-o-viewport"] },
  5628.     { name: "DOCUMENT_SYM", text: ["@document", "@-moz-document"] },
  5629.     { name: "UNKNOWN_SYM" },
  5630.     //{ name: "ATKEYWORD"},
  5631.  
  5632.     // CSS3 animations
  5633.     { name: "KEYFRAMES_SYM", text: [ "@keyframes", "@-webkit-keyframes", "@-moz-keyframes", "@-o-keyframes" ] },
  5634.  
  5635.     // important symbol
  5636.     { name: "IMPORTANT_SYM" },
  5637.  
  5638.     // measurements
  5639.     { name: "LENGTH" },
  5640.     { name: "ANGLE" },
  5641.     { name: "TIME" },
  5642.     { name: "FREQ" },
  5643.     { name: "DIMENSION" },
  5644.     { name: "PERCENTAGE" },
  5645.     { name: "NUMBER" },
  5646.  
  5647.     // functions
  5648.     { name: "URI" },
  5649.     { name: "FUNCTION" },
  5650.  
  5651.     // Unicode ranges
  5652.     { name: "UNICODE_RANGE" },
  5653.  
  5654.     /*
  5655.      * The following token names are defined in CSS3 Selectors: https://www.w3.org/TR/css3-selectors/#selector-syntax
  5656.      */
  5657.  
  5658.     // invalid string
  5659.     { name: "INVALID" },
  5660.  
  5661.     // combinators
  5662.     { name: "PLUS", text: "+" },
  5663.     { name: "GREATER", text: ">" },
  5664.     { name: "COMMA", text: "," },
  5665.     { name: "TILDE", text: "~" },
  5666.  
  5667.     // modifier
  5668.     { name: "NOT" },
  5669.  
  5670.     /*
  5671.      * Defined in CSS3 Paged Media
  5672.      */
  5673.     { name: "TOPLEFTCORNER_SYM", text: "@top-left-corner" },
  5674.     { name: "TOPLEFT_SYM", text: "@top-left" },
  5675.     { name: "TOPCENTER_SYM", text: "@top-center" },
  5676.     { name: "TOPRIGHT_SYM", text: "@top-right" },
  5677.     { name: "TOPRIGHTCORNER_SYM", text: "@top-right-corner" },
  5678.     { name: "BOTTOMLEFTCORNER_SYM", text: "@bottom-left-corner" },
  5679.     { name: "BOTTOMLEFT_SYM", text: "@bottom-left" },
  5680.     { name: "BOTTOMCENTER_SYM", text: "@bottom-center" },
  5681.     { name: "BOTTOMRIGHT_SYM", text: "@bottom-right" },
  5682.     { name: "BOTTOMRIGHTCORNER_SYM", text: "@bottom-right-corner" },
  5683.     { name: "LEFTTOP_SYM", text: "@left-top" },
  5684.     { name: "LEFTMIDDLE_SYM", text: "@left-middle" },
  5685.     { name: "LEFTBOTTOM_SYM", text: "@left-bottom" },
  5686.     { name: "RIGHTTOP_SYM", text: "@right-top" },
  5687.     { name: "RIGHTMIDDLE_SYM", text: "@right-middle" },
  5688.     { name: "RIGHTBOTTOM_SYM", text: "@right-bottom" },
  5689.  
  5690.     /*
  5691.      * The following token names are defined in CSS3 Media Queries: https://www.w3.org/TR/css3-mediaqueries/#syntax
  5692.      */
  5693.     /*{ name: "MEDIA_ONLY", state: "media"},
  5694.     { name: "MEDIA_NOT", state: "media"},
  5695.     { name: "MEDIA_AND", state: "media"},*/
  5696.     { name: "RESOLUTION", state: "media" },
  5697.  
  5698.     /*
  5699.      * The following token names are not defined in any CSS specification but are used by the lexer.
  5700.      */
  5701.  
  5702.     // not a real token, but useful for stupid IE filters
  5703.     { name: "IE_FUNCTION" },
  5704.  
  5705.     // part of CSS3 grammar but not the Flex code
  5706.     { name: "CHAR" },
  5707.  
  5708.     // TODO: Needed?
  5709.     // Not defined as tokens, but might as well be
  5710.     {
  5711.         name: "PIPE",
  5712.         text: "|"
  5713.     },
  5714.     {
  5715.         name: "SLASH",
  5716.         text: "/"
  5717.     },
  5718.     {
  5719.         name: "MINUS",
  5720.         text: "-"
  5721.     },
  5722.     {
  5723.         name: "STAR",
  5724.         text: "*"
  5725.     },
  5726.  
  5727.     {
  5728.         name: "LBRACE",
  5729.         endChar: "}",
  5730.         text: "{"
  5731.     },
  5732.     {
  5733.         name: "RBRACE",
  5734.         text: "}"
  5735.     },
  5736.     {
  5737.         name: "LBRACKET",
  5738.         endChar: "]",
  5739.         text: "["
  5740.     },
  5741.     {
  5742.         name: "RBRACKET",
  5743.         text: "]"
  5744.     },
  5745.     {
  5746.         name: "EQUALS",
  5747.         text: "="
  5748.     },
  5749.     {
  5750.         name: "COLON",
  5751.         text: ":"
  5752.     },
  5753.     {
  5754.         name: "SEMICOLON",
  5755.         text: ";"
  5756.     },
  5757.     {
  5758.         name: "LPAREN",
  5759.         endChar: ")",
  5760.         text: "("
  5761.     },
  5762.     {
  5763.         name: "RPAREN",
  5764.         text: ")"
  5765.     },
  5766.     {
  5767.         name: "DOT",
  5768.         text: "."
  5769.     }
  5770. ];
  5771.  
  5772. (function() {
  5773.     var nameMap = [],
  5774.         typeMap = Object.create(null);
  5775.  
  5776.     Tokens.UNKNOWN = -1;
  5777.     Tokens.unshift({ name:"EOF" });
  5778.     for (var i=0, len = Tokens.length; i < len; i++) {
  5779.         nameMap.push(Tokens[i].name);
  5780.         Tokens[Tokens[i].name] = i;
  5781.         if (Tokens[i].text) {
  5782.             if (Tokens[i].text instanceof Array) {
  5783.                 for (var j=0; j < Tokens[i].text.length; j++) {
  5784.                     typeMap[Tokens[i].text[j]] = i;
  5785.                 }
  5786.             } else {
  5787.                 typeMap[Tokens[i].text] = i;
  5788.             }
  5789.         }
  5790.     }
  5791.  
  5792.     Tokens.name = function(tt) {
  5793.         return nameMap[tt];
  5794.     };
  5795.  
  5796.     Tokens.type = function(c) {
  5797.         return typeMap[c] || -1;
  5798.     };
  5799. })();
  5800.  
  5801. },{}],19:[function(require,module,exports){
  5802. "use strict";
  5803.  
  5804. /* exported Validation */
  5805.  
  5806. var Matcher = require("./Matcher");
  5807. var Properties = require("./Properties");
  5808. var ValidationTypes = require("./ValidationTypes");
  5809. var ValidationError = require("./ValidationError");
  5810. var PropertyValueIterator = require("./PropertyValueIterator");
  5811.  
  5812. var Validation = module.exports = {
  5813.  
  5814.     validate: function(property, value) {
  5815.  
  5816.         //normalize name
  5817.         var name        = property.toString().toLowerCase(),
  5818.             expression  = new PropertyValueIterator(value),
  5819.             spec        = Properties[name],
  5820.             part;
  5821.  
  5822.         if (!spec) {
  5823.             if (name.indexOf("-") !== 0) {    //vendor prefixed are ok
  5824.                 throw new ValidationError("Unknown property '" + property + "'.", property.line, property.col);
  5825.             }
  5826.         } else if (typeof spec !== "number") {
  5827.  
  5828.             // All properties accept some CSS-wide values.
  5829.             // https://drafts.csswg.org/css-values-3/#common-keywords
  5830.             if (ValidationTypes.isAny(expression, "inherit | initial | unset")) {
  5831.                 if (expression.hasNext()) {
  5832.                     part = expression.next();
  5833.                     throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
  5834.                 }
  5835.                 return;
  5836.             }
  5837.  
  5838.             // Property-specific validation.
  5839.             this.singleProperty(spec, expression);
  5840.  
  5841.         }
  5842.  
  5843.     },
  5844.  
  5845.     singleProperty: function(types, expression) {
  5846.  
  5847.         var result      = false,
  5848.             value       = expression.value,
  5849.             part;
  5850.  
  5851.         result = Matcher.parse(types).match(expression);
  5852.  
  5853.         if (!result) {
  5854.             if (expression.hasNext() && !expression.isFirst()) {
  5855.                 part = expression.peek();
  5856.                 throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
  5857.             } else {
  5858.                 throw new ValidationError("Expected (" + ValidationTypes.describe(types) + ") but found '" + value + "'.", value.line, value.col);
  5859.             }
  5860.         } else if (expression.hasNext()) {
  5861.             part = expression.next();
  5862.             throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
  5863.         }
  5864.  
  5865.     }
  5866.  
  5867. };
  5868.  
  5869. },{"./Matcher":3,"./Properties":7,"./PropertyValueIterator":10,"./ValidationError":20,"./ValidationTypes":21}],20:[function(require,module,exports){
  5870. "use strict";
  5871.  
  5872. module.exports = ValidationError;
  5873.  
  5874. /**
  5875.  * Type to use when a validation error occurs.
  5876.  * @class ValidationError
  5877.  * @namespace parserlib.util
  5878.  * @constructor
  5879.  * @param {String} message The error message.
  5880.  * @param {int} line The line at which the error occurred.
  5881.  * @param {int} col The column at which the error occurred.
  5882.  */
  5883. function ValidationError(message, line, col) {
  5884.  
  5885.     /**
  5886.      * The column at which the error occurred.
  5887.      * @type int
  5888.      * @property col
  5889.      */
  5890.     this.col = col;
  5891.  
  5892.     /**
  5893.      * The line at which the error occurred.
  5894.      * @type int
  5895.      * @property line
  5896.      */
  5897.     this.line = line;
  5898.  
  5899.     /**
  5900.      * The text representation of the unit.
  5901.      * @type String
  5902.      * @property text
  5903.      */
  5904.     this.message = message;
  5905.  
  5906. }
  5907.  
  5908. //inherit from Error
  5909. ValidationError.prototype = new Error();
  5910.  
  5911. },{}],21:[function(require,module,exports){
  5912. "use strict";
  5913.  
  5914. var ValidationTypes = module.exports;
  5915.  
  5916. var Matcher = require("./Matcher");
  5917.  
  5918. function copy(to, from) {
  5919.     Object.keys(from).forEach(function(prop) {
  5920.         to[prop] = from[prop];
  5921.     });
  5922. }
  5923. copy(ValidationTypes, {
  5924.  
  5925.     isLiteral: function (part, literals) {
  5926.         var text = part.text.toString().toLowerCase(),
  5927.             args = literals.split(" | "),
  5928.             i, len, found = false;
  5929.  
  5930.         for (i=0, len=args.length; i < len && !found; i++) {
  5931.             if (args[i].charAt(0) === "<") {
  5932.                 found = this.simple[args[i]](part);
  5933.             } else if (args[i].slice(-2) === "()") {
  5934.                 found = (part.type === "function" &&
  5935.                          part.name === args[i].slice(0, -2));
  5936.             } else if (text === args[i].toLowerCase()) {
  5937.                 found = true;
  5938.             }
  5939.         }
  5940.  
  5941.         return found;
  5942.     },
  5943.  
  5944.     isSimple: function(type) {
  5945.         return Boolean(this.simple[type]);
  5946.     },
  5947.  
  5948.     isComplex: function(type) {
  5949.         return Boolean(this.complex[type]);
  5950.     },
  5951.  
  5952.     describe: function(type) {
  5953.         if (this.complex[type] instanceof Matcher) {
  5954.             return this.complex[type].toString(0);
  5955.         }
  5956.         return type;
  5957.     },
  5958.  
  5959.     /**
  5960.      * Determines if the next part(s) of the given expression
  5961.      * are any of the given types.
  5962.      */
  5963.     isAny: function (expression, types) {
  5964.         var args = types.split(" | "),
  5965.             i, len, found = false;
  5966.  
  5967.         for (i=0, len=args.length; i < len && !found && expression.hasNext(); i++) {
  5968.             found = this.isType(expression, args[i]);
  5969.         }
  5970.  
  5971.         return found;
  5972.     },
  5973.  
  5974.     /**
  5975.      * Determines if the next part(s) of the given expression
  5976.      * are one of a group.
  5977.      */
  5978.     isAnyOfGroup: function(expression, types) {
  5979.         var args = types.split(" || "),
  5980.             i, len, found = false;
  5981.  
  5982.         for (i=0, len=args.length; i < len && !found; i++) {
  5983.             found = this.isType(expression, args[i]);
  5984.         }
  5985.  
  5986.         return found ? args[i-1] : false;
  5987.     },
  5988.  
  5989.     /**
  5990.      * Determines if the next part(s) of the given expression
  5991.      * are of a given type.
  5992.      */
  5993.     isType: function (expression, type) {
  5994.         var part = expression.peek(),
  5995.             result = false;
  5996.  
  5997.         if (type.charAt(0) !== "<") {
  5998.             result = this.isLiteral(part, type);
  5999.             if (result) {
  6000.                 expression.next();
  6001.             }
  6002.         } else if (this.simple[type]) {
  6003.             result = this.simple[type](part);
  6004.             if (result) {
  6005.                 expression.next();
  6006.             }
  6007.         } else if (this.complex[type] instanceof Matcher) {
  6008.             result = this.complex[type].match(expression);
  6009.         } else {
  6010.             result = this.complex[type](expression);
  6011.         }
  6012.  
  6013.         return result;
  6014.     },
  6015.  
  6016.  
  6017.     simple: {
  6018.         __proto__: null,
  6019.  
  6020.         "<absolute-size>":
  6021.             "xx-small | x-small | small | medium | large | x-large | xx-large",
  6022.  
  6023.         "<animateable-feature>":
  6024.             "scroll-position | contents | <animateable-feature-name>",
  6025.  
  6026.         "<animateable-feature-name>": function(part) {
  6027.             return this["<ident>"](part) &&
  6028.                 !/^(unset|initial|inherit|will-change|auto|scroll-position|contents)$/i.test(part);
  6029.         },
  6030.  
  6031.         "<angle>": function(part) {
  6032.             return part.type === "angle";
  6033.         },
  6034.  
  6035.         "<attachment>": "scroll | fixed | local",
  6036.  
  6037.         "<attr>": "attr()",
  6038.  
  6039.         // inset() = inset( <shape-arg>{1,4} [round <border-radius>]? )
  6040.         // circle() = circle( [<shape-radius>]? [at <position>]? )
  6041.         // ellipse() = ellipse( [<shape-radius>{2}]? [at <position>]? )
  6042.         // polygon() = polygon( [<fill-rule>,]? [<shape-arg> <shape-arg>]# )
  6043.         "<basic-shape>": "inset() | circle() | ellipse() | polygon()",
  6044.  
  6045.         "<bg-image>": "<image> | <gradient> | none",
  6046.  
  6047.         "<border-style>":
  6048.             "none | hidden | dotted | dashed | solid | double | groove | " +
  6049.             "ridge | inset | outset",
  6050.  
  6051.         "<border-width>": "<length> | thin | medium | thick",
  6052.  
  6053.         "<box>": "padding-box | border-box | content-box",
  6054.  
  6055.         "<clip-source>": "<uri>",
  6056.  
  6057.         "<color>": function(part) {
  6058.             return part.type === "color" || String(part) === "transparent" || String(part) === "currentColor";
  6059.         },
  6060.  
  6061.         // The SVG <color> spec doesn't include "currentColor" or "transparent" as a color.
  6062.         "<color-svg>": function(part) {
  6063.             return part.type === "color";
  6064.         },
  6065.  
  6066.         "<content>": "content()",
  6067.  
  6068.         // https://www.w3.org/TR/css3-sizing/#width-height-keywords
  6069.         "<content-sizing>":
  6070.             "fill-available | -moz-available | -webkit-fill-available | " +
  6071.             "max-content | -moz-max-content | -webkit-max-content | " +
  6072.             "min-content | -moz-min-content | -webkit-min-content | " +
  6073.             "fit-content | -moz-fit-content | -webkit-fit-content",
  6074.  
  6075.         "<feature-tag-value>": function(part) {
  6076.             return part.type === "function" && /^[A-Z0-9]{4}$/i.test(part);
  6077.         },
  6078.  
  6079.         // custom() isn't actually in the spec
  6080.         "<filter-function>":
  6081.             "blur() | brightness() | contrast() | custom() | " +
  6082.             "drop-shadow() | grayscale() | hue-rotate() | invert() | " +
  6083.             "opacity() | saturate() | sepia()",
  6084.  
  6085.         "<flex-basis>": "<width>",
  6086.  
  6087.         "<flex-direction>": "row | row-reverse | column | column-reverse",
  6088.  
  6089.         "<flex-grow>": "<number>",
  6090.  
  6091.         "<flex-shrink>": "<number>",
  6092.  
  6093.         "<flex-wrap>": "nowrap | wrap | wrap-reverse",
  6094.  
  6095.         "<font-size>":
  6096.             "<absolute-size> | <relative-size> | <length> | <percentage>",
  6097.  
  6098.         "<font-stretch>":
  6099.             "normal | ultra-condensed | extra-condensed | condensed | " +
  6100.             "semi-condensed | semi-expanded | expanded | extra-expanded | " +
  6101.             "ultra-expanded",
  6102.  
  6103.         "<font-style>": "normal | italic | oblique",
  6104.  
  6105.         "<font-variant-caps>":
  6106.             "small-caps | all-small-caps | petite-caps | all-petite-caps | " +
  6107.             "unicase | titling-caps",
  6108.  
  6109.         "<font-variant-css21>": "normal | small-caps",
  6110.  
  6111.         "<font-weight>":
  6112.             "normal | bold | bolder | lighter | " +
  6113.             "100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900",
  6114.  
  6115.         "<generic-family>":
  6116.             "serif | sans-serif | cursive | fantasy | monospace",
  6117.  
  6118.         "<geometry-box>": "<shape-box> | fill-box | stroke-box | view-box",
  6119.  
  6120.         "<glyph-angle>": function(part) {
  6121.             return part.type === "angle" && part.units === "deg";
  6122.         },
  6123.  
  6124.         "<gradient>": function(part) {
  6125.             return part.type === "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?(?:repeating\-)?(?:radial\-|linear\-)?gradient/i.test(part);
  6126.         },
  6127.  
  6128.         "<icccolor>":
  6129.             "cielab() | cielch() | cielchab() | " +
  6130.             "icc-color() | icc-named-color()",
  6131.  
  6132.         //any identifier
  6133.         "<ident>": function(part) {
  6134.             return part.type === "identifier" || part.wasIdent;
  6135.         },
  6136.  
  6137.         "<ident-not-generic-family>": function(part) {
  6138.             return this["<ident>"](part) && !this["<generic-family>"](part);
  6139.         },
  6140.  
  6141.         "<image>": "<uri>",
  6142.  
  6143.         "<integer>": function(part) {
  6144.             return part.type === "integer";
  6145.         },
  6146.  
  6147.         "<length>": function(part) {
  6148.             if (part.type === "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?calc/i.test(part)) {
  6149.                 return true;
  6150.             } else {
  6151.                 return part.type === "length" || part.type === "number" || part.type === "integer" || String(part) === "0";
  6152.             }
  6153.         },
  6154.  
  6155.         "<line>": function(part) {
  6156.             return part.type === "integer";
  6157.         },
  6158.  
  6159.         "<line-height>": "<number> | <length> | <percentage> | normal",
  6160.  
  6161.         "<margin-width>": "<length> | <percentage> | auto",
  6162.  
  6163.         "<miterlimit>": function(part) {
  6164.             return this["<number>"](part) && part.value >= 1;
  6165.         },
  6166.  
  6167.         "<nonnegative-length-or-percentage>": function(part) {
  6168.             return (this["<length>"](part) || this["<percentage>"](part)) &&
  6169.                 (String(part) === "0" || part.type === "function" || (part.value) >= 0);
  6170.         },
  6171.  
  6172.         "<nonnegative-number-or-percentage>": function(part) {
  6173.             return (this["<number>"](part) || this["<percentage>"](part)) &&
  6174.                 (String(part) === "0" || part.type === "function" || (part.value) >= 0);
  6175.         },
  6176.  
  6177.         "<number>": function(part) {
  6178.             return part.type === "number" || this["<integer>"](part);
  6179.         },
  6180.  
  6181.         "<opacity-value>": function(part) {
  6182.             return this["<number>"](part) && part.value >= 0 && part.value <= 1;
  6183.         },
  6184.  
  6185.         "<padding-width>": "<nonnegative-length-or-percentage>",
  6186.  
  6187.         "<percentage>": function(part) {
  6188.             return part.type === "percentage" || String(part) === "0";
  6189.         },
  6190.  
  6191.         "<relative-size>": "smaller | larger",
  6192.  
  6193.         "<shape>": "rect() | inset-rect()",
  6194.  
  6195.         "<shape-box>": "<box> | margin-box",
  6196.  
  6197.         "<single-animation-direction>":
  6198.             "normal | reverse | alternate | alternate-reverse",
  6199.  
  6200.         "<single-animation-name>": function(part) {
  6201.             return this["<ident>"](part) &&
  6202.                 /^-?[a-z_][-a-z0-9_]+$/i.test(part) &&
  6203.                 !/^(none|unset|initial|inherit)$/i.test(part);
  6204.         },
  6205.  
  6206.         "<string>": function(part) {
  6207.             return part.type === "string";
  6208.         },
  6209.  
  6210.         "<time>": function(part) {
  6211.             return part.type === "time";
  6212.         },
  6213.  
  6214.         "<uri>": function(part) {
  6215.             return part.type === "uri";
  6216.         },
  6217.  
  6218.         "<width>": "<margin-width>"
  6219.     },
  6220.  
  6221.     complex: {
  6222.         __proto__: null,
  6223.  
  6224.         "<azimuth>":
  6225.             "<angle>" +
  6226.             " | " +
  6227.             "[ [ left-side | far-left | left | center-left | center | " +
  6228.             "center-right | right | far-right | right-side ] || behind ]" +
  6229.             " | "+
  6230.             "leftwards | rightwards",
  6231.  
  6232.         "<bg-position>": "<position>#",
  6233.  
  6234.         "<bg-size>":
  6235.             "[ <length> | <percentage> | auto ]{1,2} | cover | contain",
  6236.  
  6237.         "<border-image-slice>":
  6238.         // [<number> | <percentage>]{1,4} && fill?
  6239.         // *but* fill can appear between any of the numbers
  6240.         Matcher.many([true /* first element is required */],
  6241.                      Matcher.cast("<nonnegative-number-or-percentage>"),
  6242.                      Matcher.cast("<nonnegative-number-or-percentage>"),
  6243.                      Matcher.cast("<nonnegative-number-or-percentage>"),
  6244.                      Matcher.cast("<nonnegative-number-or-percentage>"),
  6245.                      "fill"),
  6246.  
  6247.         "<border-radius>":
  6248.             "<nonnegative-length-or-percentage>{1,4} " +
  6249.             "[ / <nonnegative-length-or-percentage>{1,4} ]?",
  6250.  
  6251.         "<box-shadow>": "none | <shadow>#",
  6252.  
  6253.         "<clip-path>": "<basic-shape> || <geometry-box>",
  6254.  
  6255.         "<dasharray>":
  6256.         // "list of comma and/or white space separated <length>s and
  6257.         // <percentage>s".  There is a non-negative constraint.
  6258.         Matcher.cast("<nonnegative-length-or-percentage>")
  6259.             .braces(1, Infinity, "#", Matcher.cast(",").question()),
  6260.  
  6261.         "<family-name>":
  6262.             // <string> | <IDENT>+
  6263.             "<string> | <ident-not-generic-family> <ident>*",
  6264.  
  6265.         "<filter-function-list>": "[ <filter-function> | <uri> ]+",
  6266.  
  6267.         // https://www.w3.org/TR/2014/WD-css-flexbox-1-20140325/#flex-property
  6268.         "<flex>":
  6269.             "none | [ <flex-grow> <flex-shrink>? || <flex-basis> ]",
  6270.  
  6271.         "<font-family>": "[ <generic-family> | <family-name> ]#",
  6272.  
  6273.         "<font-shorthand>":
  6274.             "[ <font-style> || <font-variant-css21> || " +
  6275.             "<font-weight> || <font-stretch> ]? <font-size> " +
  6276.             "[ / <line-height> ]? <font-family>",
  6277.  
  6278.         "<font-variant-alternates>":
  6279.             // stylistic(<feature-value-name>)
  6280.             "stylistic() || " +
  6281.             "historical-forms || " +
  6282.             // styleset(<feature-value-name> #)
  6283.             "styleset() || " +
  6284.             // character-variant(<feature-value-name> #)
  6285.             "character-variant() || " +
  6286.             // swash(<feature-value-name>)
  6287.             "swash() || " +
  6288.             // ornaments(<feature-value-name>)
  6289.             "ornaments() || " +
  6290.             // annotation(<feature-value-name>)
  6291.             "annotation()",
  6292.  
  6293.         "<font-variant-ligatures>":
  6294.             // <common-lig-values>
  6295.             "[ common-ligatures | no-common-ligatures ] || " +
  6296.             // <discretionary-lig-values>
  6297.             "[ discretionary-ligatures | no-discretionary-ligatures ] || " +
  6298.             // <historical-lig-values>
  6299.             "[ historical-ligatures | no-historical-ligatures ] || " +
  6300.             // <contextual-alt-values>
  6301.             "[ contextual | no-contextual ]",
  6302.  
  6303.         "<font-variant-numeric>":
  6304.             // <numeric-figure-values>
  6305.             "[ lining-nums | oldstyle-nums ] || " +
  6306.             // <numeric-spacing-values>
  6307.             "[ proportional-nums | tabular-nums ] || " +
  6308.             // <numeric-fraction-values>
  6309.             "[ diagonal-fractions | stacked-fractions ] || " +
  6310.             "ordinal || slashed-zero",
  6311.  
  6312.         "<font-variant-east-asian>":
  6313.             // <east-asian-variant-values>
  6314.             "[ jis78 | jis83 | jis90 | jis04 | simplified | traditional ] || " +
  6315.             // <east-asian-width-values>
  6316.             "[ full-width | proportional-width ] || " +
  6317.             "ruby",
  6318.  
  6319.         // Note that <color> here is "as defined in the SVG spec", which
  6320.         // is more restrictive that the <color> defined in the CSS spec.
  6321.         // none | currentColor | <color> [<icccolor>]? |
  6322.         // <funciri> [ none | currentColor | <color> [<icccolor>]? ]?
  6323.         "<paint>": "<paint-basic> | <uri> <paint-basic>?",
  6324.  
  6325.         // Helper definition for <paint> above.
  6326.         "<paint-basic>": "none | currentColor | <color-svg> <icccolor>?",
  6327.  
  6328.         "<position>":
  6329.             // Because our `alt` combinator is ordered, we need to test these
  6330.             // in order from longest possible match to shortest.
  6331.             "[ center | [ left | right ] [ <percentage> | <length> ]? ] && " +
  6332.             "[ center | [ top | bottom ] [ <percentage> | <length> ]? ]" +
  6333.             " | " +
  6334.             "[ left | center | right | <percentage> | <length> ] " +
  6335.             "[ top | center | bottom | <percentage> | <length> ]" +
  6336.             " | " +
  6337.             "[ left | center | right | top | bottom | <percentage> | <length> ]",
  6338.  
  6339.         "<repeat-style>":
  6340.             "repeat-x | repeat-y | [ repeat | space | round | no-repeat ]{1,2}",
  6341.  
  6342.         "<shadow>":
  6343.         //inset? && [ <length>{2,4} && <color>? ]
  6344.         Matcher.many([true /* length is required */],
  6345.                      Matcher.cast("<length>").braces(2, 4), "inset", "<color>"),
  6346.  
  6347.         "<text-decoration-color>":
  6348.            "<color>",
  6349.  
  6350.         "<text-decoration-line>":
  6351.             "none | [ underline || overline || line-through || blink ]",
  6352.  
  6353.         "<text-decoration-style>":
  6354.             "solid | double | dotted | dashed | wavy",
  6355.  
  6356.         "<will-change>":
  6357.             "auto | <animateable-feature>#",
  6358.  
  6359.         "<x-one-radius>":
  6360.             //[ <length> | <percentage> ] [ <length> | <percentage> ]?
  6361.             "[ <length> | <percentage> ]{1,2}"
  6362.     }
  6363. });
  6364.  
  6365. Object.keys(ValidationTypes.simple).forEach(function(nt) {
  6366.     var rule = ValidationTypes.simple[nt];
  6367.     if (typeof rule === "string") {
  6368.         ValidationTypes.simple[nt] = function(part) {
  6369.             return ValidationTypes.isLiteral(part, rule);
  6370.         };
  6371.     }
  6372. });
  6373.  
  6374. Object.keys(ValidationTypes.complex).forEach(function(nt) {
  6375.     var rule = ValidationTypes.complex[nt];
  6376.     if (typeof rule === "string") {
  6377.         ValidationTypes.complex[nt] = Matcher.parse(rule);
  6378.     }
  6379. });
  6380.  
  6381. // Because this is defined relative to other complex validation types,
  6382. // we need to define it *after* the rest of the types are initialized.
  6383. ValidationTypes.complex["<font-variant>"] =
  6384.     Matcher.oror({ expand: "<font-variant-ligatures>" },
  6385.                  { expand: "<font-variant-alternates>" },
  6386.                  "<font-variant-caps>",
  6387.                  { expand: "<font-variant-numeric>" },
  6388.                  { expand: "<font-variant-east-asian>" });
  6389.  
  6390. },{"./Matcher":3}],22:[function(require,module,exports){
  6391. "use strict";
  6392.  
  6393. module.exports = {
  6394.     Colors            : require("./Colors"),
  6395.     Combinator        : require("./Combinator"),
  6396.     Parser            : require("./Parser"),
  6397.     PropertyName      : require("./PropertyName"),
  6398.     PropertyValue     : require("./PropertyValue"),
  6399.     PropertyValuePart : require("./PropertyValuePart"),
  6400.     Matcher           : require("./Matcher"),
  6401.     MediaFeature      : require("./MediaFeature"),
  6402.     MediaQuery        : require("./MediaQuery"),
  6403.     Selector          : require("./Selector"),
  6404.     SelectorPart      : require("./SelectorPart"),
  6405.     SelectorSubPart   : require("./SelectorSubPart"),
  6406.     Specificity       : require("./Specificity"),
  6407.     TokenStream       : require("./TokenStream"),
  6408.     Tokens            : require("./Tokens"),
  6409.     ValidationError   : require("./ValidationError")
  6410. };
  6411.  
  6412. },{"./Colors":1,"./Combinator":2,"./Matcher":3,"./MediaFeature":4,"./MediaQuery":5,"./Parser":6,"./PropertyName":8,"./PropertyValue":9,"./PropertyValuePart":11,"./Selector":13,"./SelectorPart":14,"./SelectorSubPart":15,"./Specificity":16,"./TokenStream":17,"./Tokens":18,"./ValidationError":20}],23:[function(require,module,exports){
  6413. "use strict";
  6414.  
  6415. module.exports = EventTarget;
  6416.  
  6417. /**
  6418.  * A generic base to inherit from for any object
  6419.  * that needs event handling.
  6420.  * @class EventTarget
  6421.  * @constructor
  6422.  */
  6423. function EventTarget() {
  6424.  
  6425.     /**
  6426.      * The array of listeners for various events.
  6427.      * @type Object
  6428.      * @property _listeners
  6429.      * @private
  6430.      */
  6431.     this._listeners = Object.create(null);
  6432. }
  6433.  
  6434. EventTarget.prototype = {
  6435.  
  6436.     //restore constructor
  6437.     constructor: EventTarget,
  6438.  
  6439.     /**
  6440.      * Adds a listener for a given event type.
  6441.      * @param {String} type The type of event to add a listener for.
  6442.      * @param {Function} listener The function to call when the event occurs.
  6443.      * @return {void}
  6444.      * @method addListener
  6445.      */
  6446.     addListener: function(type, listener) {
  6447.         if (!this._listeners[type]) {
  6448.             this._listeners[type] = [];
  6449.         }
  6450.  
  6451.         this._listeners[type].push(listener);
  6452.     },
  6453.  
  6454.     /**
  6455.      * Fires an event based on the passed-in object.
  6456.      * @param {Object|String} event An object with at least a 'type' attribute
  6457.      *      or a string indicating the event name.
  6458.      * @return {void}
  6459.      * @method fire
  6460.      */
  6461.     fire: function(event) {
  6462.         if (typeof event === "string") {
  6463.             event = { type: event };
  6464.         }
  6465.         if (typeof event.target !== "undefined") {
  6466.             event.target = this;
  6467.         }
  6468.  
  6469.         if (typeof event.type === "undefined") {
  6470.             throw new Error("Event object missing 'type' property.");
  6471.         }
  6472.  
  6473.         if (this._listeners[event.type]) {
  6474.  
  6475.             //create a copy of the array and use that so listeners can't chane
  6476.             var listeners = this._listeners[event.type].concat();
  6477.             for (var i=0, len=listeners.length; i < len; i++) {
  6478.                 listeners[i].call(this, event);
  6479.             }
  6480.         }
  6481.     },
  6482.  
  6483.     /**
  6484.      * Removes a listener for a given event type.
  6485.      * @param {String} type The type of event to remove a listener from.
  6486.      * @param {Function} listener The function to remove from the event.
  6487.      * @return {void}
  6488.      * @method removeListener
  6489.      */
  6490.     removeListener: function(type, listener) {
  6491.         if (this._listeners[type]) {
  6492.             var listeners = this._listeners[type];
  6493.             for (var i=0, len=listeners.length; i < len; i++) {
  6494.                 if (listeners[i] === listener) {
  6495.                     listeners.splice(i, 1);
  6496.                     break;
  6497.                 }
  6498.             }
  6499.  
  6500.  
  6501.         }
  6502.     }
  6503. };
  6504.  
  6505. },{}],24:[function(require,module,exports){
  6506. "use strict";
  6507.  
  6508. module.exports = StringReader;
  6509.  
  6510. /**
  6511.  * Convenient way to read through strings.
  6512.  * @namespace parserlib.util
  6513.  * @class StringReader
  6514.  * @constructor
  6515.  * @param {String} text The text to read.
  6516.  */
  6517. function StringReader(text) {
  6518.  
  6519.     /**
  6520.      * The input text with line endings normalized.
  6521.      * @property _input
  6522.      * @type String
  6523.      * @private
  6524.      */
  6525.     this._input = text.replace(/(\r\n?|\n)/g, "\n");
  6526.  
  6527.  
  6528.     /**
  6529.      * The row for the character to be read next.
  6530.      * @property _line
  6531.      * @type int
  6532.      * @private
  6533.      */
  6534.     this._line = 1;
  6535.  
  6536.  
  6537.     /**
  6538.      * The column for the character to be read next.
  6539.      * @property _col
  6540.      * @type int
  6541.      * @private
  6542.      */
  6543.     this._col = 1;
  6544.  
  6545.     /**
  6546.      * The index of the character in the input to be read next.
  6547.      * @property _cursor
  6548.      * @type int
  6549.      * @private
  6550.      */
  6551.     this._cursor = 0;
  6552. }
  6553.  
  6554. StringReader.prototype = {
  6555.  
  6556.     // restore constructor
  6557.     constructor: StringReader,
  6558.  
  6559.     //-------------------------------------------------------------------------
  6560.     // Position info
  6561.     //-------------------------------------------------------------------------
  6562.  
  6563.     /**
  6564.      * Returns the column of the character to be read next.
  6565.      * @return {int} The column of the character to be read next.
  6566.      * @method getCol
  6567.      */
  6568.     getCol: function() {
  6569.         return this._col;
  6570.     },
  6571.  
  6572.     /**
  6573.      * Returns the row of the character to be read next.
  6574.      * @return {int} The row of the character to be read next.
  6575.      * @method getLine
  6576.      */
  6577.     getLine: function() {
  6578.         return this._line;
  6579.     },
  6580.  
  6581.     /**
  6582.      * Determines if you're at the end of the input.
  6583.      * @return {Boolean} True if there's no more input, false otherwise.
  6584.      * @method eof
  6585.      */
  6586.     eof: function() {
  6587.         return this._cursor === this._input.length;
  6588.     },
  6589.  
  6590.     //-------------------------------------------------------------------------
  6591.     // Basic reading
  6592.     //-------------------------------------------------------------------------
  6593.  
  6594.     /**
  6595.      * Reads the next character without advancing the cursor.
  6596.      * @param {int} count How many characters to look ahead (default is 1).
  6597.      * @return {String} The next character or null if there is no next character.
  6598.      * @method peek
  6599.      */
  6600.     peek: function(count) {
  6601.         var c = null;
  6602.         count = typeof count === "undefined" ? 1 : count;
  6603.  
  6604.         // if we're not at the end of the input...
  6605.         if (this._cursor < this._input.length) {
  6606.  
  6607.             // get character and increment cursor and column
  6608.             c = this._input.charAt(this._cursor + count - 1);
  6609.         }
  6610.  
  6611.         return c;
  6612.     },
  6613.  
  6614.     /**
  6615.      * Reads the next character from the input and adjusts the row and column
  6616.      * accordingly.
  6617.      * @return {String} The next character or null if there is no next character.
  6618.      * @method read
  6619.      */
  6620.     read: function() {
  6621.         var c = null;
  6622.  
  6623.         // if we're not at the end of the input...
  6624.         if (this._cursor < this._input.length) {
  6625.  
  6626.             // if the last character was a newline, increment row count
  6627.             // and reset column count
  6628.             if (this._input.charAt(this._cursor) === "\n") {
  6629.                 this._line++;
  6630.                 this._col=1;
  6631.             } else {
  6632.                 this._col++;
  6633.             }
  6634.  
  6635.             // get character and increment cursor and column
  6636.             c = this._input.charAt(this._cursor++);
  6637.         }
  6638.  
  6639.         return c;
  6640.     },
  6641.  
  6642.     //-------------------------------------------------------------------------
  6643.     // Misc
  6644.     //-------------------------------------------------------------------------
  6645.  
  6646.     /**
  6647.      * Saves the current location so it can be returned to later.
  6648.      * @method mark
  6649.      * @return {void}
  6650.      */
  6651.     mark: function() {
  6652.         this._bookmark = {
  6653.             cursor: this._cursor,
  6654.             line:   this._line,
  6655.             col:    this._col
  6656.         };
  6657.     },
  6658.  
  6659.     reset: function() {
  6660.         if (this._bookmark) {
  6661.             this._cursor = this._bookmark.cursor;
  6662.             this._line = this._bookmark.line;
  6663.             this._col = this._bookmark.col;
  6664.             delete this._bookmark;
  6665.         }
  6666.     },
  6667.  
  6668.     //-------------------------------------------------------------------------
  6669.     // Advanced reading
  6670.     //-------------------------------------------------------------------------
  6671.  
  6672.     /**
  6673.      * Reads up to and including the given string. Throws an error if that
  6674.      * string is not found.
  6675.      * @param {String} pattern The string to read.
  6676.      * @return {String} The string when it is found.
  6677.      * @throws Error when the string pattern is not found.
  6678.      * @method readTo
  6679.      */
  6680.     readTo: function(pattern) {
  6681.  
  6682.         var buffer = "",
  6683.             c;
  6684.  
  6685.         /*
  6686.          * First, buffer must be the same length as the pattern.
  6687.          * Then, buffer must end with the pattern or else reach the
  6688.          * end of the input.
  6689.          */
  6690.         while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) !== buffer.length - pattern.length) {
  6691.             c = this.read();
  6692.             if (c) {
  6693.                 buffer += c;
  6694.             } else {
  6695.                 throw new Error("Expected \"" + pattern + "\" at line " + this._line  + ", col " + this._col + ".");
  6696.             }
  6697.         }
  6698.  
  6699.         return buffer;
  6700.  
  6701.     },
  6702.  
  6703.     /**
  6704.      * Reads characters while each character causes the given
  6705.      * filter function to return true. The function is passed
  6706.      * in each character and either returns true to continue
  6707.      * reading or false to stop.
  6708.      * @param {Function} filter The function to read on each character.
  6709.      * @return {String} The string made up of all characters that passed the
  6710.      *      filter check.
  6711.      * @method readWhile
  6712.      */
  6713.     readWhile: function(filter) {
  6714.  
  6715.         var buffer = "",
  6716.             c = this.peek();
  6717.  
  6718.         while (c !== null && filter(c)) {
  6719.             buffer += this.read();
  6720.             c = this.peek();
  6721.         }
  6722.  
  6723.         return buffer;
  6724.  
  6725.     },
  6726.  
  6727.     /**
  6728.      * Reads characters that match either text or a regular expression and
  6729.      * returns those characters. If a match is found, the row and column
  6730.      * are adjusted; if no match is found, the reader's state is unchanged.
  6731.      * reading or false to stop.
  6732.      * @param {String|RegExp} matcher If a string, then the literal string
  6733.      *      value is searched for. If a regular expression, then any string
  6734.      *      matching the pattern is search for.
  6735.      * @return {String} The string made up of all characters that matched or
  6736.      *      null if there was no match.
  6737.      * @method readMatch
  6738.      */
  6739.     readMatch: function(matcher) {
  6740.  
  6741.         var source = this._input.substring(this._cursor),
  6742.             value = null;
  6743.  
  6744.         // if it's a string, just do a straight match
  6745.         if (typeof matcher === "string") {
  6746.             if (source.slice(0, matcher.length) === matcher) {
  6747.                 value = this.readCount(matcher.length);
  6748.             }
  6749.         } else if (matcher instanceof RegExp) {
  6750.             if (matcher.test(source)) {
  6751.                 value = this.readCount(RegExp.lastMatch.length);
  6752.             }
  6753.         }
  6754.  
  6755.         return value;
  6756.     },
  6757.  
  6758.  
  6759.     /**
  6760.      * Reads a given number of characters. If the end of the input is reached,
  6761.      * it reads only the remaining characters and does not throw an error.
  6762.      * @param {int} count The number of characters to read.
  6763.      * @return {String} The string made up the read characters.
  6764.      * @method readCount
  6765.      */
  6766.     readCount: function(count) {
  6767.         var buffer = "";
  6768.  
  6769.         while (count--) {
  6770.             buffer += this.read();
  6771.         }
  6772.  
  6773.         return buffer;
  6774.     }
  6775.  
  6776. };
  6777.  
  6778. },{}],25:[function(require,module,exports){
  6779. "use strict";
  6780.  
  6781. module.exports = SyntaxError;
  6782.  
  6783. /**
  6784.  * Type to use when a syntax error occurs.
  6785.  * @class SyntaxError
  6786.  * @namespace parserlib.util
  6787.  * @constructor
  6788.  * @param {String} message The error message.
  6789.  * @param {int} line The line at which the error occurred.
  6790.  * @param {int} col The column at which the error occurred.
  6791.  */
  6792. function SyntaxError(message, line, col) {
  6793.     Error.call(this);
  6794.     this.name = this.constructor.name;
  6795.  
  6796.     /**
  6797.      * The column at which the error occurred.
  6798.      * @type int
  6799.      * @property col
  6800.      */
  6801.     this.col = col;
  6802.  
  6803.     /**
  6804.      * The line at which the error occurred.
  6805.      * @type int
  6806.      * @property line
  6807.      */
  6808.     this.line = line;
  6809.  
  6810.     /**
  6811.      * The text representation of the unit.
  6812.      * @type String
  6813.      * @property text
  6814.      */
  6815.     this.message = message;
  6816.  
  6817. }
  6818.  
  6819. //inherit from Error
  6820. SyntaxError.prototype = Object.create(Error.prototype); // jshint ignore:line
  6821. SyntaxError.prototype.constructor = SyntaxError; // jshint ignore:line
  6822.  
  6823. },{}],26:[function(require,module,exports){
  6824. "use strict";
  6825.  
  6826. module.exports = SyntaxUnit;
  6827.  
  6828. /**
  6829.  * Base type to represent a single syntactic unit.
  6830.  * @class SyntaxUnit
  6831.  * @namespace parserlib.util
  6832.  * @constructor
  6833.  * @param {String} text The text of the unit.
  6834.  * @param {int} line The line of text on which the unit resides.
  6835.  * @param {int} col The column of text on which the unit resides.
  6836.  */
  6837. function SyntaxUnit(text, line, col, type) {
  6838.  
  6839.  
  6840.     /**
  6841.      * The column of text on which the unit resides.
  6842.      * @type int
  6843.      * @property col
  6844.      */
  6845.     this.col = col;
  6846.  
  6847.     /**
  6848.      * The line of text on which the unit resides.
  6849.      * @type int
  6850.      * @property line
  6851.      */
  6852.     this.line = line;
  6853.  
  6854.     /**
  6855.      * The text representation of the unit.
  6856.      * @type String
  6857.      * @property text
  6858.      */
  6859.     this.text = text;
  6860.  
  6861.     /**
  6862.      * The type of syntax unit.
  6863.      * @type int
  6864.      * @property type
  6865.      */
  6866.     this.type = type;
  6867. }
  6868.  
  6869. /**
  6870.  * Create a new syntax unit based solely on the given token.
  6871.  * Convenience method for creating a new syntax unit when
  6872.  * it represents a single token instead of multiple.
  6873.  * @param {Object} token The token object to represent.
  6874.  * @return {parserlib.util.SyntaxUnit} The object representing the token.
  6875.  * @static
  6876.  * @method fromToken
  6877.  */
  6878. SyntaxUnit.fromToken = function(token) {
  6879.     return new SyntaxUnit(token.value, token.startLine, token.startCol);
  6880. };
  6881.  
  6882. SyntaxUnit.prototype = {
  6883.  
  6884.     //restore constructor
  6885.     constructor: SyntaxUnit,
  6886.  
  6887.     /**
  6888.      * Returns the text representation of the unit.
  6889.      * @return {String} The text representation of the unit.
  6890.      * @method valueOf
  6891.      */
  6892.     valueOf: function() {
  6893.         return this.toString();
  6894.     },
  6895.  
  6896.     /**
  6897.      * Returns the text representation of the unit.
  6898.      * @return {String} The text representation of the unit.
  6899.      * @method toString
  6900.      */
  6901.     toString: function() {
  6902.         return this.text;
  6903.     }
  6904.  
  6905. };
  6906.  
  6907. },{}],27:[function(require,module,exports){
  6908. "use strict";
  6909.  
  6910. module.exports = TokenStreamBase;
  6911.  
  6912. var StringReader = require("./StringReader");
  6913. var SyntaxError = require("./SyntaxError");
  6914.  
  6915. /**
  6916.  * Generic TokenStream providing base functionality.
  6917.  * @class TokenStreamBase
  6918.  * @namespace parserlib.util
  6919.  * @constructor
  6920.  * @param {String|StringReader} input The text to tokenize or a reader from
  6921.  *      which to read the input.
  6922.  */
  6923. function TokenStreamBase(input, tokenData) {
  6924.  
  6925.     /**
  6926.      * The string reader for easy access to the text.
  6927.      * @type StringReader
  6928.      * @property _reader
  6929.      * @private
  6930.      */
  6931.     this._reader = new StringReader(input ? input.toString() : "");
  6932.  
  6933.     /**
  6934.      * Token object for the last consumed token.
  6935.      * @type Token
  6936.      * @property _token
  6937.      * @private
  6938.      */
  6939.     this._token = null;
  6940.  
  6941.     /**
  6942.      * The array of token information.
  6943.      * @type Array
  6944.      * @property _tokenData
  6945.      * @private
  6946.      */
  6947.     this._tokenData = tokenData;
  6948.  
  6949.     /**
  6950.      * Lookahead token buffer.
  6951.      * @type Array
  6952.      * @property _lt
  6953.      * @private
  6954.      */
  6955.     this._lt = [];
  6956.  
  6957.     /**
  6958.      * Lookahead token buffer index.
  6959.      * @type int
  6960.      * @property _ltIndex
  6961.      * @private
  6962.      */
  6963.     this._ltIndex = 0;
  6964.  
  6965.     this._ltIndexCache = [];
  6966. }
  6967.  
  6968. /**
  6969.  * Accepts an array of token information and outputs
  6970.  * an array of token data containing key-value mappings
  6971.  * and matching functions that the TokenStream needs.
  6972.  * @param {Array} tokens An array of token descriptors.
  6973.  * @return {Array} An array of processed token data.
  6974.  * @method createTokenData
  6975.  * @static
  6976.  */
  6977. TokenStreamBase.createTokenData = function(tokens) {
  6978.  
  6979.     var nameMap     = [],
  6980.         typeMap     = Object.create(null),
  6981.         tokenData     = tokens.concat([]),
  6982.         i            = 0,
  6983.         len            = tokenData.length+1;
  6984.  
  6985.     tokenData.UNKNOWN = -1;
  6986.     tokenData.unshift({ name:"EOF" });
  6987.  
  6988.     for (; i < len; i++) {
  6989.         nameMap.push(tokenData[i].name);
  6990.         tokenData[tokenData[i].name] = i;
  6991.         if (tokenData[i].text) {
  6992.             typeMap[tokenData[i].text] = i;
  6993.         }
  6994.     }
  6995.  
  6996.     tokenData.name = function(tt) {
  6997.         return nameMap[tt];
  6998.     };
  6999.  
  7000.     tokenData.type = function(c) {
  7001.         return typeMap[c];
  7002.     };
  7003.  
  7004.     return tokenData;
  7005. };
  7006.  
  7007. TokenStreamBase.prototype = {
  7008.  
  7009.     //restore constructor
  7010.     constructor: TokenStreamBase,
  7011.  
  7012.     //-------------------------------------------------------------------------
  7013.     // Matching methods
  7014.     //-------------------------------------------------------------------------
  7015.  
  7016.     /**
  7017.      * Determines if the next token matches the given token type.
  7018.      * If so, that token is consumed; if not, the token is placed
  7019.      * back onto the token stream. You can pass in any number of
  7020.      * token types and this will return true if any of the token
  7021.      * types is found.
  7022.      * @param {int|int[]} tokenTypes Either a single token type or an array of
  7023.      *      token types that the next token might be. If an array is passed,
  7024.      *      it's assumed that the token can be any of these.
  7025.      * @param {variant} channel (Optional) The channel to read from. If not
  7026.      *      provided, reads from the default (unnamed) channel.
  7027.      * @return {Boolean} True if the token type matches, false if not.
  7028.      * @method match
  7029.      */
  7030.     match: function(tokenTypes, channel) {
  7031.  
  7032.         //always convert to an array, makes things easier
  7033.         if (!(tokenTypes instanceof Array)) {
  7034.             tokenTypes = [tokenTypes];
  7035.         }
  7036.  
  7037.         var tt  = this.get(channel),
  7038.             i   = 0,
  7039.             len = tokenTypes.length;
  7040.  
  7041.         while (i < len) {
  7042.             if (tt === tokenTypes[i++]) {
  7043.                 return true;
  7044.             }
  7045.         }
  7046.  
  7047.         //no match found, put the token back
  7048.         this.unget();
  7049.         return false;
  7050.     },
  7051.  
  7052.     /**
  7053.      * Determines if the next token matches the given token type.
  7054.      * If so, that token is consumed; if not, an error is thrown.
  7055.      * @param {int|int[]} tokenTypes Either a single token type or an array of
  7056.      *      token types that the next token should be. If an array is passed,
  7057.      *      it's assumed that the token must be one of these.
  7058.      * @return {void}
  7059.      * @method mustMatch
  7060.      */
  7061.     mustMatch: function(tokenTypes) {
  7062.  
  7063.         var token;
  7064.  
  7065.         //always convert to an array, makes things easier
  7066.         if (!(tokenTypes instanceof Array)) {
  7067.             tokenTypes = [tokenTypes];
  7068.         }
  7069.  
  7070.         if (!this.match.apply(this, arguments)) {
  7071.             token = this.LT(1);
  7072.             throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name +
  7073.                 " at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
  7074.         }
  7075.     },
  7076.  
  7077.     //-------------------------------------------------------------------------
  7078.     // Consuming methods
  7079.     //-------------------------------------------------------------------------
  7080.  
  7081.     /**
  7082.      * Keeps reading from the token stream until either one of the specified
  7083.      * token types is found or until the end of the input is reached.
  7084.      * @param {int|int[]} tokenTypes Either a single token type or an array of
  7085.      *      token types that the next token should be. If an array is passed,
  7086.      *      it's assumed that the token must be one of these.
  7087.      * @param {variant} channel (Optional) The channel to read from. If not
  7088.      *      provided, reads from the default (unnamed) channel.
  7089.      * @return {void}
  7090.      * @method advance
  7091.      */
  7092.     advance: function(tokenTypes, channel) {
  7093.  
  7094.         while (this.LA(0) !== 0 && !this.match(tokenTypes, channel)) {
  7095.             this.get();
  7096.         }
  7097.  
  7098.         return this.LA(0);
  7099.     },
  7100.  
  7101.     /**
  7102.      * Consumes the next token from the token stream.
  7103.      * @return {int} The token type of the token that was just consumed.
  7104.      * @method get
  7105.      */
  7106.     get: function(channel) {
  7107.  
  7108.         var tokenInfo   = this._tokenData,
  7109.             i           =0,
  7110.             token,
  7111.             info;
  7112.  
  7113.         //check the lookahead buffer first
  7114.         if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length) {
  7115.  
  7116.             i++;
  7117.             this._token = this._lt[this._ltIndex++];
  7118.             info = tokenInfo[this._token.type];
  7119.  
  7120.             //obey channels logic
  7121.             while ((info.channel !== undefined && channel !== info.channel) &&
  7122.                     this._ltIndex < this._lt.length) {
  7123.                 this._token = this._lt[this._ltIndex++];
  7124.                 info = tokenInfo[this._token.type];
  7125.                 i++;
  7126.             }
  7127.  
  7128.             //here be dragons
  7129.             if ((info.channel === undefined || channel === info.channel) &&
  7130.                     this._ltIndex <= this._lt.length) {
  7131.                 this._ltIndexCache.push(i);
  7132.                 return this._token.type;
  7133.             }
  7134.         }
  7135.  
  7136.         //call token retriever method
  7137.         token = this._getToken();
  7138.  
  7139.         //if it should be hidden, don't save a token
  7140.         if (token.type > -1 && !tokenInfo[token.type].hide) {
  7141.  
  7142.             //apply token channel
  7143.             token.channel = tokenInfo[token.type].channel;
  7144.  
  7145.             //save for later
  7146.             this._token = token;
  7147.             this._lt.push(token);
  7148.  
  7149.             //save space that will be moved (must be done before array is truncated)
  7150.             this._ltIndexCache.push(this._lt.length - this._ltIndex + i);
  7151.  
  7152.             //keep the buffer under 5 items
  7153.             if (this._lt.length > 5) {
  7154.                 this._lt.shift();
  7155.             }
  7156.  
  7157.             //also keep the shift buffer under 5 items
  7158.             if (this._ltIndexCache.length > 5) {
  7159.                 this._ltIndexCache.shift();
  7160.             }
  7161.  
  7162.             //update lookahead index
  7163.             this._ltIndex = this._lt.length;
  7164.         }
  7165.  
  7166.         /*
  7167.          * Skip to the next token if:
  7168.          * 1. The token type is marked as hidden.
  7169.          * 2. The token type has a channel specified and it isn't the current channel.
  7170.          */
  7171.         info = tokenInfo[token.type];
  7172.         if (info &&
  7173.                 (info.hide ||
  7174.                 (info.channel !== undefined && channel !== info.channel))) {
  7175.             return this.get(channel);
  7176.         } else {
  7177.             //return just the type
  7178.             return token.type;
  7179.         }
  7180.     },
  7181.  
  7182.     /**
  7183.      * Looks ahead a certain number of tokens and returns the token type at
  7184.      * that position. This will throw an error if you lookahead past the
  7185.      * end of input, past the size of the lookahead buffer, or back past
  7186.      * the first token in the lookahead buffer.
  7187.      * @param {int} The index of the token type to retrieve. 0 for the
  7188.      *      current token, 1 for the next, -1 for the previous, etc.
  7189.      * @return {int} The token type of the token in the given position.
  7190.      * @method LA
  7191.      */
  7192.     LA: function(index) {
  7193.         var total = index,
  7194.             tt;
  7195.         if (index > 0) {
  7196.             //TODO: Store 5 somewhere
  7197.             if (index > 5) {
  7198.                 throw new Error("Too much lookahead.");
  7199.             }
  7200.  
  7201.             //get all those tokens
  7202.             while (total) {
  7203.                 tt = this.get();
  7204.                 total--;
  7205.             }
  7206.  
  7207.             //unget all those tokens
  7208.             while (total < index) {
  7209.                 this.unget();
  7210.                 total++;
  7211.             }
  7212.         } else if (index < 0) {
  7213.  
  7214.             if (this._lt[this._ltIndex+index]) {
  7215.                 tt = this._lt[this._ltIndex+index].type;
  7216.             } else {
  7217.                 throw new Error("Too much lookbehind.");
  7218.             }
  7219.  
  7220.         } else {
  7221.             tt = this._token.type;
  7222.         }
  7223.  
  7224.         return tt;
  7225.  
  7226.     },
  7227.  
  7228.     /**
  7229.      * Looks ahead a certain number of tokens and returns the token at
  7230.      * that position. This will throw an error if you lookahead past the
  7231.      * end of input, past the size of the lookahead buffer, or back past
  7232.      * the first token in the lookahead buffer.
  7233.      * @param {int} The index of the token type to retrieve. 0 for the
  7234.      *      current token, 1 for the next, -1 for the previous, etc.
  7235.      * @return {Object} The token of the token in the given position.
  7236.      * @method LA
  7237.      */
  7238.     LT: function(index) {
  7239.  
  7240.         //lookahead first to prime the token buffer
  7241.         this.LA(index);
  7242.  
  7243.         //now find the token, subtract one because _ltIndex is already at the next index
  7244.         return this._lt[this._ltIndex+index-1];
  7245.     },
  7246.  
  7247.     /**
  7248.      * Returns the token type for the next token in the stream without
  7249.      * consuming it.
  7250.      * @return {int} The token type of the next token in the stream.
  7251.      * @method peek
  7252.      */
  7253.     peek: function() {
  7254.         return this.LA(1);
  7255.     },
  7256.  
  7257.     /**
  7258.      * Returns the actual token object for the last consumed token.
  7259.      * @return {Token} The token object for the last consumed token.
  7260.      * @method token
  7261.      */
  7262.     token: function() {
  7263.         return this._token;
  7264.     },
  7265.  
  7266.     /**
  7267.      * Returns the name of the token for the given token type.
  7268.      * @param {int} tokenType The type of token to get the name of.
  7269.      * @return {String} The name of the token or "UNKNOWN_TOKEN" for any
  7270.      *      invalid token type.
  7271.      * @method tokenName
  7272.      */
  7273.     tokenName: function(tokenType) {
  7274.         if (tokenType < 0 || tokenType > this._tokenData.length) {
  7275.             return "UNKNOWN_TOKEN";
  7276.         } else {
  7277.             return this._tokenData[tokenType].name;
  7278.         }
  7279.     },
  7280.  
  7281.     /**
  7282.      * Returns the token type value for the given token name.
  7283.      * @param {String} tokenName The name of the token whose value should be returned.
  7284.      * @return {int} The token type value for the given token name or -1
  7285.      *      for an unknown token.
  7286.      * @method tokenName
  7287.      */
  7288.     tokenType: function(tokenName) {
  7289.         return this._tokenData[tokenName] || -1;
  7290.     },
  7291.  
  7292.     /**
  7293.      * Returns the last consumed token to the token stream.
  7294.      * @method unget
  7295.      */
  7296.     unget: function() {
  7297.         //if (this._ltIndex > -1) {
  7298.         if (this._ltIndexCache.length) {
  7299.             this._ltIndex -= this._ltIndexCache.pop();//--;
  7300.             this._token = this._lt[this._ltIndex - 1];
  7301.         } else {
  7302.             throw new Error("Too much lookahead.");
  7303.         }
  7304.     }
  7305.  
  7306. };
  7307.  
  7308.  
  7309. },{"./StringReader":24,"./SyntaxError":25}],28:[function(require,module,exports){
  7310. "use strict";
  7311.  
  7312. module.exports = {
  7313.     StringReader    : require("./StringReader"),
  7314.     SyntaxError     : require("./SyntaxError"),
  7315.     SyntaxUnit      : require("./SyntaxUnit"),
  7316.     EventTarget     : require("./EventTarget"),
  7317.     TokenStreamBase : require("./TokenStreamBase")
  7318. };
  7319.  
  7320. },{"./EventTarget":23,"./StringReader":24,"./SyntaxError":25,"./SyntaxUnit":26,"./TokenStreamBase":27}],"parserlib":[function(require,module,exports){
  7321. "use strict";
  7322.  
  7323. module.exports = {
  7324.     css  : require("./css"),
  7325.     util : require("./util")
  7326. };
  7327.  
  7328. },{"./css":22,"./util":28}]},{},[]);
  7329.  
  7330. return require('parserlib');
  7331. })();
  7332. var clone = (function() {
  7333. 'use strict';
  7334.  
  7335. var nativeMap;
  7336. try {
  7337.   nativeMap = Map;
  7338. } catch(_) {
  7339.   // maybe a reference error because no `Map`. Give it a dummy value that no
  7340.   // value will ever be an instanceof.
  7341.   nativeMap = function() {};
  7342. }
  7343.  
  7344. var nativeSet;
  7345. try {
  7346.   nativeSet = Set;
  7347. } catch(_) {
  7348.   nativeSet = function() {};
  7349. }
  7350.  
  7351. var nativePromise;
  7352. try {
  7353.   nativePromise = Promise;
  7354. } catch(_) {
  7355.   nativePromise = function() {};
  7356. }
  7357.  
  7358. /**
  7359.  * Clones (copies) an Object using deep copying.
  7360.  *
  7361.  * This function supports circular references by default, but if you are certain
  7362.  * there are no circular references in your object, you can save some CPU time
  7363.  * by calling clone(obj, false).
  7364.  *
  7365.  * Caution: if `circular` is false and `parent` contains circular references,
  7366.  * your program may enter an infinite loop and crash.
  7367.  *
  7368.  * @param `parent` - the object to be cloned
  7369.  * @param `circular` - set to true if the object to be cloned may contain
  7370.  *    circular references. (optional - true by default)
  7371.  * @param `depth` - set to a number if the object is only to be cloned to
  7372.  *    a particular depth. (optional - defaults to Infinity)
  7373.  * @param `prototype` - sets the prototype to be used when cloning an object.
  7374.  *    (optional - defaults to parent prototype).
  7375.  * @param `includeNonEnumerable` - set to true if the non-enumerable properties
  7376.  *    should be cloned as well. Non-enumerable properties on the prototype
  7377.  *    chain will be ignored. (optional - false by default)
  7378. */
  7379. function clone(parent, circular, depth, prototype, includeNonEnumerable) {
  7380.   if (typeof circular === 'object') {
  7381.     depth = circular.depth;
  7382.     prototype = circular.prototype;
  7383.     includeNonEnumerable = circular.includeNonEnumerable;
  7384.     circular = circular.circular;
  7385.   }
  7386.   // maintain two arrays for circular references, where corresponding parents
  7387.   // and children have the same index
  7388.   var allParents = [];
  7389.   var allChildren = [];
  7390.  
  7391.   var useBuffer = typeof Buffer != 'undefined';
  7392.  
  7393.   if (typeof circular == 'undefined')
  7394.     circular = true;
  7395.  
  7396.   if (typeof depth == 'undefined')
  7397.     depth = Infinity;
  7398.  
  7399.   // recurse this function so we don't reset allParents and allChildren
  7400.   function _clone(parent, depth) {
  7401.     // cloning null always returns null
  7402.     if (parent === null)
  7403.       return null;
  7404.  
  7405.     if (depth === 0)
  7406.       return parent;
  7407.  
  7408.     var child;
  7409.     var proto;
  7410.     if (typeof parent != 'object') {
  7411.       return parent;
  7412.     }
  7413.  
  7414.     if (parent instanceof nativeMap) {
  7415.       child = new nativeMap();
  7416.     } else if (parent instanceof nativeSet) {
  7417.       child = new nativeSet();
  7418.     } else if (parent instanceof nativePromise) {
  7419.       child = new nativePromise(function (resolve, reject) {
  7420.         parent.then(function(value) {
  7421.           resolve(_clone(value, depth - 1));
  7422.         }, function(err) {
  7423.           reject(_clone(err, depth - 1));
  7424.         });
  7425.       });
  7426.     } else if (clone.__isArray(parent)) {
  7427.       child = [];
  7428.     } else if (clone.__isRegExp(parent)) {
  7429.       child = new RegExp(parent.source, __getRegExpFlags(parent));
  7430.       if (parent.lastIndex) child.lastIndex = parent.lastIndex;
  7431.     } else if (clone.__isDate(parent)) {
  7432.       child = new Date(parent.getTime());
  7433.     } else if (useBuffer && Buffer.isBuffer(parent)) {
  7434.       child = new Buffer(parent.length);
  7435.       parent.copy(child);
  7436.       return child;
  7437.     } else if (parent instanceof Error) {
  7438.       child = Object.create(parent);
  7439.     } else {
  7440.       if (typeof prototype == 'undefined') {
  7441.         proto = Object.getPrototypeOf(parent);
  7442.         child = Object.create(proto);
  7443.       }
  7444.       else {
  7445.         child = Object.create(prototype);
  7446.         proto = prototype;
  7447.       }
  7448.     }
  7449.  
  7450.     if (circular) {
  7451.       var index = allParents.indexOf(parent);
  7452.  
  7453.       if (index != -1) {
  7454.         return allChildren[index];
  7455.       }
  7456.       allParents.push(parent);
  7457.       allChildren.push(child);
  7458.     }
  7459.  
  7460.     if (parent instanceof nativeMap) {
  7461.       var keyIterator = parent.keys();
  7462.       while(true) {
  7463.         var next = keyIterator.next();
  7464.         if (next.done) {
  7465.           break;
  7466.         }
  7467.         var keyChild = _clone(next.value, depth - 1);
  7468.         var valueChild = _clone(parent.get(next.value), depth - 1);
  7469.         child.set(keyChild, valueChild);
  7470.       }
  7471.     }
  7472.     if (parent instanceof nativeSet) {
  7473.       var iterator = parent.keys();
  7474.       while(true) {
  7475.         var next = iterator.next();
  7476.         if (next.done) {
  7477.           break;
  7478.         }
  7479.         var entryChild = _clone(next.value, depth - 1);
  7480.         child.add(entryChild);
  7481.       }
  7482.     }
  7483.  
  7484.     for (var i in parent) {
  7485.       var attrs;
  7486.       if (proto) {
  7487.         attrs = Object.getOwnPropertyDescriptor(proto, i);
  7488.       }
  7489.  
  7490.       if (attrs && attrs.set == null) {
  7491.         continue;
  7492.       }
  7493.       child[i] = _clone(parent[i], depth - 1);
  7494.     }
  7495.  
  7496.     if (Object.getOwnPropertySymbols) {
  7497.       var symbols = Object.getOwnPropertySymbols(parent);
  7498.       for (var i = 0; i < symbols.length; i++) {
  7499.         // Don't need to worry about cloning a symbol because it is a primitive,
  7500.         // like a number or string.
  7501.         var symbol = symbols[i];
  7502.         var descriptor = Object.getOwnPropertyDescriptor(parent, symbol);
  7503.         if (descriptor && !descriptor.enumerable && !includeNonEnumerable) {
  7504.           continue;
  7505.         }
  7506.         child[symbol] = _clone(parent[symbol], depth - 1);
  7507.         if (!descriptor.enumerable) {
  7508.           Object.defineProperty(child, symbol, {
  7509.             enumerable: false
  7510.           });
  7511.         }
  7512.       }
  7513.     }
  7514.  
  7515.     if (includeNonEnumerable) {
  7516.       var allPropertyNames = Object.getOwnPropertyNames(parent);
  7517.       for (var i = 0; i < allPropertyNames.length; i++) {
  7518.         var propertyName = allPropertyNames[i];
  7519.         var descriptor = Object.getOwnPropertyDescriptor(parent, propertyName);
  7520.         if (descriptor && descriptor.enumerable) {
  7521.           continue;
  7522.         }
  7523.         child[propertyName] = _clone(parent[propertyName], depth - 1);
  7524.         Object.defineProperty(child, propertyName, {
  7525.           enumerable: false
  7526.         });
  7527.       }
  7528.     }
  7529.  
  7530.     return child;
  7531.   }
  7532.  
  7533.   return _clone(parent, depth);
  7534. }
  7535.  
  7536. /**
  7537.  * Simple flat clone using prototype, accepts only objects, usefull for property
  7538.  * override on FLAT configuration object (no nested props).
  7539.  *
  7540.  * USE WITH CAUTION! This may not behave as you wish if you do not know how this
  7541.  * works.
  7542.  */
  7543. clone.clonePrototype = function clonePrototype(parent) {
  7544.   if (parent === null)
  7545.     return null;
  7546.  
  7547.   var c = function () {};
  7548.   c.prototype = parent;
  7549.   return new c();
  7550. };
  7551.  
  7552. // private utility functions
  7553.  
  7554. function __objToStr(o) {
  7555.   return Object.prototype.toString.call(o);
  7556. }
  7557. clone.__objToStr = __objToStr;
  7558.  
  7559. function __isDate(o) {
  7560.   return typeof o === 'object' && __objToStr(o) === '[object Date]';
  7561. }
  7562. clone.__isDate = __isDate;
  7563.  
  7564. function __isArray(o) {
  7565.   return typeof o === 'object' && __objToStr(o) === '[object Array]';
  7566. }
  7567. clone.__isArray = __isArray;
  7568.  
  7569. function __isRegExp(o) {
  7570.   return typeof o === 'object' && __objToStr(o) === '[object RegExp]';
  7571. }
  7572. clone.__isRegExp = __isRegExp;
  7573.  
  7574. function __getRegExpFlags(re) {
  7575.   var flags = '';
  7576.   if (re.global) flags += 'g';
  7577.   if (re.ignoreCase) flags += 'i';
  7578.   if (re.multiline) flags += 'm';
  7579.   return flags;
  7580. }
  7581. clone.__getRegExpFlags = __getRegExpFlags;
  7582.  
  7583. return clone;
  7584. })();
  7585.  
  7586. if (typeof module === 'object' && module.exports) {
  7587.   module.exports = clone;
  7588. }
  7589.  
  7590. /**
  7591.  * Main CSSLint object.
  7592.  * @class CSSLint
  7593.  * @static
  7594.  * @extends parserlib.util.EventTarget
  7595.  */
  7596.  
  7597. /* global parserlib, clone, Reporter */
  7598. /* exported CSSLint */
  7599.  
  7600. var CSSLint = (function() {
  7601.     "use strict";
  7602.  
  7603.     var rules           = [],
  7604.         formatters      = [],
  7605.         embeddedRuleset = /\/\*\s*csslint([^\*]*)\*\//,
  7606.         api             = new parserlib.util.EventTarget();
  7607.  
  7608.     api.version = "1.0.4";
  7609.  
  7610.     //-------------------------------------------------------------------------
  7611.     // Rule Management
  7612.     //-------------------------------------------------------------------------
  7613.  
  7614.     /**
  7615.      * Adds a new rule to the engine.
  7616.      * @param {Object} rule The rule to add.
  7617.      * @method addRule
  7618.      */
  7619.     api.addRule = function(rule) {
  7620.         rules.push(rule);
  7621.         rules[rule.id] = rule;
  7622.     };
  7623.  
  7624.     /**
  7625.      * Clears all rule from the engine.
  7626.      * @method clearRules
  7627.      */
  7628.     api.clearRules = function() {
  7629.         rules = [];
  7630.     };
  7631.  
  7632.     /**
  7633.      * Returns the rule objects.
  7634.      * @return An array of rule objects.
  7635.      * @method getRules
  7636.      */
  7637.     api.getRules = function() {
  7638.         return [].concat(rules).sort(function(a, b) {
  7639.             return a.id > b.id ? 1 : 0;
  7640.         });
  7641.     };
  7642.  
  7643.     /**
  7644.      * Returns a ruleset configuration object with all current rules.
  7645.      * @return A ruleset object.
  7646.      * @method getRuleset
  7647.      */
  7648.     api.getRuleset = function() {
  7649.         var ruleset = {},
  7650.             i = 0,
  7651.             len = rules.length;
  7652.  
  7653.         while (i < len) {
  7654.             ruleset[rules[i++].id] = 1;    // by default, everything is a warning
  7655.         }
  7656.  
  7657.         return ruleset;
  7658.     };
  7659.  
  7660.     /**
  7661.      * Returns a ruleset object based on embedded rules.
  7662.      * @param {String} text A string of css containing embedded rules.
  7663.      * @param {Object} ruleset A ruleset object to modify.
  7664.      * @return {Object} A ruleset object.
  7665.      * @method getEmbeddedRuleset
  7666.      */
  7667.     function applyEmbeddedRuleset(text, ruleset) {
  7668.         var valueMap,
  7669.             embedded = text && text.match(embeddedRuleset),
  7670.             rules = embedded && embedded[1];
  7671.  
  7672.         if (rules) {
  7673.             valueMap = {
  7674.                 "true": 2,  // true is error
  7675.                 "": 1,      // blank is warning
  7676.                 "false": 0, // false is ignore
  7677.  
  7678.                 "2": 2,     // explicit error
  7679.                 "1": 1,     // explicit warning
  7680.                 "0": 0      // explicit ignore
  7681.             };
  7682.  
  7683.             rules.toLowerCase().split(",").forEach(function(rule) {
  7684.                 var pair = rule.split(":"),
  7685.                     property = pair[0] || "",
  7686.                     value = pair[1] || "";
  7687.  
  7688.                 ruleset[property.trim()] = valueMap[value.trim()];
  7689.             });
  7690.         }
  7691.  
  7692.         return ruleset;
  7693.     }
  7694.  
  7695.     //-------------------------------------------------------------------------
  7696.     // Formatters
  7697.     //-------------------------------------------------------------------------
  7698.  
  7699.     /**
  7700.      * Adds a new formatter to the engine.
  7701.      * @param {Object} formatter The formatter to add.
  7702.      * @method addFormatter
  7703.      */
  7704.     api.addFormatter = function(formatter) {
  7705.         // formatters.push(formatter);
  7706.         formatters[formatter.id] = formatter;
  7707.     };
  7708.  
  7709.     /**
  7710.      * Retrieves a formatter for use.
  7711.      * @param {String} formatId The name of the format to retrieve.
  7712.      * @return {Object} The formatter or undefined.
  7713.      * @method getFormatter
  7714.      */
  7715.     api.getFormatter = function(formatId) {
  7716.         return formatters[formatId];
  7717.     };
  7718.  
  7719.     /**
  7720.      * Formats the results in a particular format for a single file.
  7721.      * @param {Object} result The results returned from CSSLint.verify().
  7722.      * @param {String} filename The filename for which the results apply.
  7723.      * @param {String} formatId The name of the formatter to use.
  7724.      * @param {Object} options (Optional) for special output handling.
  7725.      * @return {String} A formatted string for the results.
  7726.      * @method format
  7727.      */
  7728.     api.format = function(results, filename, formatId, options) {
  7729.         var formatter = this.getFormatter(formatId),
  7730.             result = null;
  7731.  
  7732.         if (formatter) {
  7733.             result = formatter.startFormat();
  7734.             result += formatter.formatResults(results, filename, options || {});
  7735.             result += formatter.endFormat();
  7736.         }
  7737.  
  7738.         return result;
  7739.     };
  7740.  
  7741.     /**
  7742.      * Indicates if the given format is supported.
  7743.      * @param {String} formatId The ID of the format to check.
  7744.      * @return {Boolean} True if the format exists, false if not.
  7745.      * @method hasFormat
  7746.      */
  7747.     api.hasFormat = function(formatId) {
  7748.         return formatters.hasOwnProperty(formatId);
  7749.     };
  7750.  
  7751.     //-------------------------------------------------------------------------
  7752.     // Verification
  7753.     //-------------------------------------------------------------------------
  7754.  
  7755.     /**
  7756.      * Starts the verification process for the given CSS text.
  7757.      * @param {String} text The CSS text to verify.
  7758.      * @param {Object} ruleset (Optional) List of rules to apply. If null, then
  7759.      *      all rules are used. If a rule has a value of 1 then it's a warning,
  7760.      *      a value of 2 means it's an error.
  7761.      * @return {Object} Results of the verification.
  7762.      * @method verify
  7763.      */
  7764.     api.verify = function(text, ruleset) {
  7765.  
  7766.         var i = 0,
  7767.             reporter,
  7768.             lines,
  7769.             allow = {},
  7770.             ignore = [],
  7771.             report,
  7772.             parser = new parserlib.css.Parser({
  7773.                 starHack: true,
  7774.                 ieFilters: true,
  7775.                 underscoreHack: true,
  7776.                 strict: false
  7777.             });
  7778.  
  7779.         // normalize line endings
  7780.         lines = text.replace(/\n\r?/g, "$split$").split("$split$");
  7781.  
  7782.         // find 'allow' comments
  7783.         CSSLint.Util.forEach(lines, function (line, lineno) {
  7784.             var allowLine = line && line.match(/\/\*[ \t]*csslint[ \t]+allow:[ \t]*([^\*]*)\*\//i),
  7785.                 allowRules = allowLine && allowLine[1],
  7786.                 allowRuleset = {};
  7787.  
  7788.             if (allowRules) {
  7789.                 allowRules.toLowerCase().split(",").forEach(function(allowRule) {
  7790.                     allowRuleset[allowRule.trim()] = true;
  7791.                 });
  7792.                 if (Object.keys(allowRuleset).length > 0) {
  7793.                     allow[lineno + 1] = allowRuleset;
  7794.                 }
  7795.             }
  7796.         });
  7797.  
  7798.         var ignoreStart = null,
  7799.             ignoreEnd = null;
  7800.         CSSLint.Util.forEach(lines, function (line, lineno) {
  7801.             // Keep oldest, "unclosest" ignore:start
  7802.             if (ignoreStart === null && line.match(/\/\*[ \t]*csslint[ \t]+ignore:start[ \t]*\*\//i)) {
  7803.                 ignoreStart = lineno;
  7804.             }
  7805.  
  7806.             if (line.match(/\/\*[ \t]*csslint[ \t]+ignore:end[ \t]*\*\//i)) {
  7807.                 ignoreEnd = lineno;
  7808.             }
  7809.  
  7810.             if (ignoreStart !== null && ignoreEnd !== null) {
  7811.                 ignore.push([ignoreStart, ignoreEnd]);
  7812.                 ignoreStart = ignoreEnd = null;
  7813.             }
  7814.         });
  7815.  
  7816.         // Close remaining ignore block, if any
  7817.         if (ignoreStart !== null) {
  7818.             ignore.push([ignoreStart, lines.length]);
  7819.         }
  7820.  
  7821.         if (!ruleset) {
  7822.             ruleset = this.getRuleset();
  7823.         }
  7824.  
  7825.         if (embeddedRuleset.test(text)) {
  7826.             // defensively copy so that caller's version does not get modified
  7827.             ruleset = clone(ruleset);
  7828.             ruleset = applyEmbeddedRuleset(text, ruleset);
  7829.         }
  7830.  
  7831.         reporter = new Reporter(lines, ruleset, allow, ignore);
  7832.  
  7833.         ruleset.errors = 2;       // always report parsing errors as errors
  7834.         for (i in ruleset) {
  7835.             if (ruleset.hasOwnProperty(i) && ruleset[i]) {
  7836.                 if (rules[i]) {
  7837.                     rules[i].init(parser, reporter);
  7838.                 }
  7839.             }
  7840.         }
  7841.  
  7842.  
  7843.         // capture most horrible error type
  7844.         try {
  7845.             parser.parse(text);
  7846.         } catch (ex) {
  7847.             reporter.error("Fatal error, cannot continue: " + ex.message, ex.line, ex.col, {});
  7848.         }
  7849.  
  7850.         report = {
  7851.             messages    : reporter.messages,
  7852.             stats       : reporter.stats,
  7853.             ruleset     : reporter.ruleset,
  7854.             allow       : reporter.allow,
  7855.             ignore      : reporter.ignore
  7856.         };
  7857.  
  7858.         // sort by line numbers, rollups at the bottom
  7859.         report.messages.sort(function (a, b) {
  7860.             if (a.rollup && !b.rollup) {
  7861.                 return 1;
  7862.             } else if (!a.rollup && b.rollup) {
  7863.                 return -1;
  7864.             } else {
  7865.                 return a.line - b.line;
  7866.             }
  7867.         });
  7868.  
  7869.         return report;
  7870.     };
  7871.  
  7872.     //-------------------------------------------------------------------------
  7873.     // Publish the API
  7874.     //-------------------------------------------------------------------------
  7875.  
  7876.     return api;
  7877.  
  7878. })();
  7879.  
  7880. /**
  7881.  * An instance of Report is used to report results of the
  7882.  * verification back to the main API.
  7883.  * @class Reporter
  7884.  * @constructor
  7885.  * @param {String[]} lines The text lines of the source.
  7886.  * @param {Object} ruleset The set of rules to work with, including if
  7887.  *      they are errors or warnings.
  7888.  * @param {Object} explicitly allowed lines
  7889.  * @param {[][]} ingore list of line ranges to be ignored
  7890.  */
  7891. function Reporter(lines, ruleset, allow, ignore) {
  7892.     "use strict";
  7893.  
  7894.     /**
  7895.      * List of messages being reported.
  7896.      * @property messages
  7897.      * @type String[]
  7898.      */
  7899.     this.messages = [];
  7900.  
  7901.     /**
  7902.      * List of statistics being reported.
  7903.      * @property stats
  7904.      * @type String[]
  7905.      */
  7906.     this.stats = [];
  7907.  
  7908.     /**
  7909.      * Lines of code being reported on. Used to provide contextual information
  7910.      * for messages.
  7911.      * @property lines
  7912.      * @type String[]
  7913.      */
  7914.     this.lines = lines;
  7915.  
  7916.     /**
  7917.      * Information about the rules. Used to determine whether an issue is an
  7918.      * error or warning.
  7919.      * @property ruleset
  7920.      * @type Object
  7921.      */
  7922.     this.ruleset = ruleset;
  7923.  
  7924.     /**
  7925.      * Lines with specific rule messages to leave out of the report.
  7926.      * @property allow
  7927.      * @type Object
  7928.      */
  7929.     this.allow = allow;
  7930.     if (!this.allow) {
  7931.         this.allow = {};
  7932.     }
  7933.  
  7934.     /**
  7935.      * Linesets not to include in the report.
  7936.      * @property ignore
  7937.      * @type [][]
  7938.      */
  7939.     this.ignore = ignore;
  7940.     if (!this.ignore) {
  7941.         this.ignore = [];
  7942.     }
  7943. }
  7944.  
  7945. Reporter.prototype = {
  7946.  
  7947.     // restore constructor
  7948.     constructor: Reporter,
  7949.  
  7950.     /**
  7951.      * Report an error.
  7952.      * @param {String} message The message to store.
  7953.      * @param {int} line The line number.
  7954.      * @param {int} col The column number.
  7955.      * @param {Object} rule The rule this message relates to.
  7956.      * @method error
  7957.      */
  7958.     error: function(message, line, col, rule) {
  7959.         "use strict";
  7960.         this.messages.push({
  7961.             type    : "error",
  7962.             line    : line,
  7963.             col     : col,
  7964.             message : message,
  7965.             evidence: this.lines[line-1],
  7966.             rule    : rule || {}
  7967.         });
  7968.     },
  7969.  
  7970.     /**
  7971.      * Report an warning.
  7972.      * @param {String} message The message to store.
  7973.      * @param {int} line The line number.
  7974.      * @param {int} col The column number.
  7975.      * @param {Object} rule The rule this message relates to.
  7976.      * @method warn
  7977.      * @deprecated Use report instead.
  7978.      */
  7979.     warn: function(message, line, col, rule) {
  7980.         "use strict";
  7981.         this.report(message, line, col, rule);
  7982.     },
  7983.  
  7984.     /**
  7985.      * Report an issue.
  7986.      * @param {String} message The message to store.
  7987.      * @param {int} line The line number.
  7988.      * @param {int} col The column number.
  7989.      * @param {Object} rule The rule this message relates to.
  7990.      * @method report
  7991.      */
  7992.     report: function(message, line, col, rule) {
  7993.         "use strict";
  7994.  
  7995.         // Check if rule violation should be allowed
  7996.         if (this.allow.hasOwnProperty(line) && this.allow[line].hasOwnProperty(rule.id)) {
  7997.             return;
  7998.         }
  7999.  
  8000.         var ignore = false;
  8001.         CSSLint.Util.forEach(this.ignore, function (range) {
  8002.             if (range[0] <= line && line <= range[1]) {
  8003.                 ignore = true;
  8004.             }
  8005.         });
  8006.         if (ignore) {
  8007.             return;
  8008.         }
  8009.  
  8010.         this.messages.push({
  8011.             type    : this.ruleset[rule.id] === 2 ? "error" : "warning",
  8012.             line    : line,
  8013.             col     : col,
  8014.             message : message,
  8015.             evidence: this.lines[line-1],
  8016.             rule    : rule
  8017.         });
  8018.     },
  8019.  
  8020.     /**
  8021.      * Report some informational text.
  8022.      * @param {String} message The message to store.
  8023.      * @param {int} line The line number.
  8024.      * @param {int} col The column number.
  8025.      * @param {Object} rule The rule this message relates to.
  8026.      * @method info
  8027.      */
  8028.     info: function(message, line, col, rule) {
  8029.         "use strict";
  8030.         this.messages.push({
  8031.             type    : "info",
  8032.             line    : line,
  8033.             col     : col,
  8034.             message : message,
  8035.             evidence: this.lines[line-1],
  8036.             rule    : rule
  8037.         });
  8038.     },
  8039.  
  8040.     /**
  8041.      * Report some rollup error information.
  8042.      * @param {String} message The message to store.
  8043.      * @param {Object} rule The rule this message relates to.
  8044.      * @method rollupError
  8045.      */
  8046.     rollupError: function(message, rule) {
  8047.         "use strict";
  8048.         this.messages.push({
  8049.             type    : "error",
  8050.             rollup  : true,
  8051.             message : message,
  8052.             rule    : rule
  8053.         });
  8054.     },
  8055.  
  8056.     /**
  8057.      * Report some rollup warning information.
  8058.      * @param {String} message The message to store.
  8059.      * @param {Object} rule The rule this message relates to.
  8060.      * @method rollupWarn
  8061.      */
  8062.     rollupWarn: function(message, rule) {
  8063.         "use strict";
  8064.         this.messages.push({
  8065.             type    : "warning",
  8066.             rollup  : true,
  8067.             message : message,
  8068.             rule    : rule
  8069.         });
  8070.     },
  8071.  
  8072.     /**
  8073.      * Report a statistic.
  8074.      * @param {String} name The name of the stat to store.
  8075.      * @param {Variant} value The value of the stat.
  8076.      * @method stat
  8077.      */
  8078.     stat: function(name, value) {
  8079.         "use strict";
  8080.         this.stats[name] = value;
  8081.     }
  8082. };
  8083.  
  8084. // expose for testing purposes
  8085. CSSLint._Reporter = Reporter;
  8086.  
  8087. /*
  8088.  * Utility functions that make life easier.
  8089.  */
  8090. CSSLint.Util = {
  8091.     /*
  8092.      * Adds all properties from supplier onto receiver,
  8093.      * overwriting if the same name already exists on
  8094.      * receiver.
  8095.      * @param {Object} The object to receive the properties.
  8096.      * @param {Object} The object to provide the properties.
  8097.      * @return {Object} The receiver
  8098.      */
  8099.     mix: function(receiver, supplier) {
  8100.         "use strict";
  8101.         var prop;
  8102.  
  8103.         for (prop in supplier) {
  8104.             if (supplier.hasOwnProperty(prop)) {
  8105.                 receiver[prop] = supplier[prop];
  8106.             }
  8107.         }
  8108.  
  8109.         return prop;
  8110.     },
  8111.  
  8112.     /*
  8113.      * Polyfill for array indexOf() method.
  8114.      * @param {Array} values The array to search.
  8115.      * @param {Variant} value The value to search for.
  8116.      * @return {int} The index of the value if found, -1 if not.
  8117.      */
  8118.     indexOf: function(values, value) {
  8119.         "use strict";
  8120.         if (values.indexOf) {
  8121.             return values.indexOf(value);
  8122.         } else {
  8123.             for (var i=0, len=values.length; i < len; i++) {
  8124.                 if (values[i] === value) {
  8125.                     return i;
  8126.                 }
  8127.             }
  8128.             return -1;
  8129.         }
  8130.     },
  8131.  
  8132.     /*
  8133.      * Polyfill for array forEach() method.
  8134.      * @param {Array} values The array to operate on.
  8135.      * @param {Function} func The function to call on each item.
  8136.      * @return {void}
  8137.      */
  8138.     forEach: function(values, func) {
  8139.         "use strict";
  8140.         if (values.forEach) {
  8141.             return values.forEach(func);
  8142.         } else {
  8143.             for (var i=0, len=values.length; i < len; i++) {
  8144.                 func(values[i], i, values);
  8145.             }
  8146.         }
  8147.     }
  8148. };
  8149.  
  8150. /*
  8151.  * Rule: Don't use adjoining classes (.foo.bar).
  8152.  */
  8153.  
  8154. CSSLint.addRule({
  8155.  
  8156.     // rule information
  8157.     id: "adjoining-classes",
  8158.     name: "Disallow adjoining classes",
  8159.     desc: "Don't use adjoining classes.",
  8160.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-adjoining-classes",
  8161.     browsers: "IE6",
  8162.  
  8163.     // initialization
  8164.     init: function(parser, reporter) {
  8165.         "use strict";
  8166.         var rule = this;
  8167.         parser.addListener("startrule", function(event) {
  8168.             var selectors = event.selectors,
  8169.                 selector,
  8170.                 part,
  8171.                 modifier,
  8172.                 classCount,
  8173.                 i, j, k;
  8174.  
  8175.             for (i=0; i < selectors.length; i++) {
  8176.                 selector = selectors[i];
  8177.                 for (j=0; j < selector.parts.length; j++) {
  8178.                     part = selector.parts[j];
  8179.                     if (part.type === parser.SELECTOR_PART_TYPE) {
  8180.                         classCount = 0;
  8181.                         for (k=0; k < part.modifiers.length; k++) {
  8182.                             modifier = part.modifiers[k];
  8183.                             if (modifier.type === "class") {
  8184.                                 classCount++;
  8185.                             }
  8186.                             if (classCount > 1){
  8187.                                 reporter.report("Adjoining classes: "+selectors[i].text, part.line, part.col, rule);
  8188.                             }
  8189.                         }
  8190.                     }
  8191.                 }
  8192.             }
  8193.         });
  8194.     }
  8195.  
  8196. });
  8197.  
  8198. /*
  8199.  * Rule: Don't use width or height when using padding or border.
  8200.  */
  8201. CSSLint.addRule({
  8202.  
  8203.     // rule information
  8204.     id: "box-model",
  8205.     name: "Beware of broken box size",
  8206.     desc: "Don't use width or height when using padding or border.",
  8207.     url: "https://github.com/CSSLint/csslint/wiki/Beware-of-box-model-size",
  8208.     browsers: "All",
  8209.  
  8210.     // initialization
  8211.     init: function(parser, reporter) {
  8212.         "use strict";
  8213.         var rule = this,
  8214.             widthProperties = {
  8215.                 border: 1,
  8216.                 "border-left": 1,
  8217.                 "border-right": 1,
  8218.                 padding: 1,
  8219.                 "padding-left": 1,
  8220.                 "padding-right": 1
  8221.             },
  8222.             heightProperties = {
  8223.                 border: 1,
  8224.                 "border-bottom": 1,
  8225.                 "border-top": 1,
  8226.                 padding: 1,
  8227.                 "padding-bottom": 1,
  8228.                 "padding-top": 1
  8229.             },
  8230.             properties,
  8231.             boxSizing = false;
  8232.  
  8233.         function startRule() {
  8234.             properties = {};
  8235.             boxSizing = false;
  8236.         }
  8237.  
  8238.         function endRule() {
  8239.             var prop, value;
  8240.  
  8241.             if (!boxSizing) {
  8242.                 if (properties.height) {
  8243.                     for (prop in heightProperties) {
  8244.                         if (heightProperties.hasOwnProperty(prop) && properties[prop]) {
  8245.                             value = properties[prop].value;
  8246.                             // special case for padding
  8247.                             if (!(prop === "padding" && value.parts.length === 2 && value.parts[0].value === 0)) {
  8248.                                 reporter.report("Using height with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
  8249.                             }
  8250.                         }
  8251.                     }
  8252.                 }
  8253.  
  8254.                 if (properties.width) {
  8255.                     for (prop in widthProperties) {
  8256.                         if (widthProperties.hasOwnProperty(prop) && properties[prop]) {
  8257.                             value = properties[prop].value;
  8258.  
  8259.                             if (!(prop === "padding" && value.parts.length === 2 && value.parts[1].value === 0)) {
  8260.                                 reporter.report("Using width with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
  8261.                             }
  8262.                         }
  8263.                     }
  8264.                 }
  8265.             }
  8266.         }
  8267.  
  8268.         parser.addListener("startrule", startRule);
  8269.         parser.addListener("startfontface", startRule);
  8270.         parser.addListener("startpage", startRule);
  8271.         parser.addListener("startpagemargin", startRule);
  8272.         parser.addListener("startkeyframerule", startRule);
  8273.         parser.addListener("startviewport", startRule);
  8274.  
  8275.         parser.addListener("property", function(event) {
  8276.             var name = event.property.text.toLowerCase();
  8277.  
  8278.             if (heightProperties[name] || widthProperties[name]) {
  8279.                 if (!/^0\S*$/.test(event.value) && !(name === "border" && event.value.toString() === "none")) {
  8280.                     properties[name] = {
  8281.                         line: event.property.line,
  8282.                         col: event.property.col,
  8283.                         value: event.value
  8284.                     };
  8285.                 }
  8286.             } else {
  8287.                 if (/^(width|height)/i.test(name) && /^(length|percentage)/.test(event.value.parts[0].type)) {
  8288.                     properties[name] = 1;
  8289.                 } else if (name === "box-sizing") {
  8290.                     boxSizing = true;
  8291.                 }
  8292.             }
  8293.  
  8294.         });
  8295.  
  8296.         parser.addListener("endrule", endRule);
  8297.         parser.addListener("endfontface", endRule);
  8298.         parser.addListener("endpage", endRule);
  8299.         parser.addListener("endpagemargin", endRule);
  8300.         parser.addListener("endkeyframerule", endRule);
  8301.         parser.addListener("endviewport", endRule);
  8302.     }
  8303.  
  8304. });
  8305.  
  8306. /*
  8307.  * Rule: box-sizing doesn't work in IE6 and IE7.
  8308.  */
  8309.  
  8310. CSSLint.addRule({
  8311.  
  8312.     // rule information
  8313.     id: "box-sizing",
  8314.     name: "Disallow use of box-sizing",
  8315.     desc: "The box-sizing properties isn't supported in IE6 and IE7.",
  8316.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-box-sizing",
  8317.     browsers: "IE6, IE7",
  8318.     tags: ["Compatibility"],
  8319.  
  8320.     // initialization
  8321.     init: function(parser, reporter) {
  8322.         "use strict";
  8323.         var rule = this;
  8324.  
  8325.         parser.addListener("property", function(event) {
  8326.             var name = event.property.text.toLowerCase();
  8327.  
  8328.             if (name === "box-sizing") {
  8329.                 reporter.report("The box-sizing property isn't supported in IE6 and IE7.", event.line, event.col, rule);
  8330.             }
  8331.         });
  8332.     }
  8333.  
  8334. });
  8335.  
  8336. /*
  8337.  * Rule: Use the bulletproof @font-face syntax to avoid 404's in old IE
  8338.  * (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax)
  8339.  */
  8340.  
  8341. CSSLint.addRule({
  8342.  
  8343.     // rule information
  8344.     id: "bulletproof-font-face",
  8345.     name: "Use the bulletproof @font-face syntax",
  8346.     desc: "Use the bulletproof @font-face syntax to avoid 404's in old IE (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax).",
  8347.     url: "https://github.com/CSSLint/csslint/wiki/Bulletproof-font-face",
  8348.     browsers: "All",
  8349.  
  8350.     // initialization
  8351.     init: function(parser, reporter) {
  8352.         "use strict";
  8353.         var rule = this,
  8354.             fontFaceRule = false,
  8355.             firstSrc = true,
  8356.             ruleFailed = false,
  8357.             line, col;
  8358.  
  8359.         // Mark the start of a @font-face declaration so we only test properties inside it
  8360.         parser.addListener("startfontface", function() {
  8361.             fontFaceRule = true;
  8362.         });
  8363.  
  8364.         parser.addListener("property", function(event) {
  8365.             // If we aren't inside an @font-face declaration then just return
  8366.             if (!fontFaceRule) {
  8367.                 return;
  8368.             }
  8369.  
  8370.             var propertyName = event.property.toString().toLowerCase(),
  8371.                 value = event.value.toString();
  8372.  
  8373.             // Set the line and col numbers for use in the endfontface listener
  8374.             line = event.line;
  8375.             col = event.col;
  8376.  
  8377.             // This is the property that we care about, we can ignore the rest
  8378.             if (propertyName === "src") {
  8379.                 var regex = /^\s?url\(['"].+\.eot\?.*['"]\)\s*format\(['"]embedded-opentype['"]\).*$/i;
  8380.  
  8381.                 // We need to handle the advanced syntax with two src properties
  8382.                 if (!value.match(regex) && firstSrc) {
  8383.                     ruleFailed = true;
  8384.                     firstSrc = false;
  8385.                 } else if (value.match(regex) && !firstSrc) {
  8386.                     ruleFailed = false;
  8387.                 }
  8388.             }
  8389.  
  8390.  
  8391.         });
  8392.  
  8393.         // Back to normal rules that we don't need to test
  8394.         parser.addListener("endfontface", function() {
  8395.             fontFaceRule = false;
  8396.  
  8397.             if (ruleFailed) {
  8398.                 reporter.report("@font-face declaration doesn't follow the fontspring bulletproof syntax.", line, col, rule);
  8399.             }
  8400.         });
  8401.     }
  8402. });
  8403.  
  8404. /*
  8405.  * Rule: Include all compatible vendor prefixes to reach a wider
  8406.  * range of users.
  8407.  */
  8408.  
  8409. CSSLint.addRule({
  8410.  
  8411.     // rule information
  8412.     id: "compatible-vendor-prefixes",
  8413.     name: "Require compatible vendor prefixes",
  8414.     desc: "Include all compatible vendor prefixes to reach a wider range of users.",
  8415.     url: "https://github.com/CSSLint/csslint/wiki/Require-compatible-vendor-prefixes",
  8416.     browsers: "All",
  8417.  
  8418.     // initialization
  8419.     init: function (parser, reporter) {
  8420.         "use strict";
  8421.         var rule = this,
  8422.             compatiblePrefixes,
  8423.             properties,
  8424.             prop,
  8425.             variations,
  8426.             prefixed,
  8427.             i,
  8428.             len,
  8429.             inKeyFrame = false,
  8430.             arrayPush = Array.prototype.push,
  8431.             applyTo = [];
  8432.  
  8433.         // See http://peter.sh/experiments/vendor-prefixed-css-property-overview/ for details
  8434.         compatiblePrefixes = {
  8435.             "animation"                  : "webkit",
  8436.             "animation-delay"            : "webkit",
  8437.             "animation-direction"        : "webkit",
  8438.             "animation-duration"         : "webkit",
  8439.             "animation-fill-mode"        : "webkit",
  8440.             "animation-iteration-count"  : "webkit",
  8441.             "animation-name"             : "webkit",
  8442.             "animation-play-state"       : "webkit",
  8443.             "animation-timing-function"  : "webkit",
  8444.             "appearance"                 : "webkit moz",
  8445.             "border-end"                 : "webkit moz",
  8446.             "border-end-color"           : "webkit moz",
  8447.             "border-end-style"           : "webkit moz",
  8448.             "border-end-width"           : "webkit moz",
  8449.             "border-image"               : "webkit moz o",
  8450.             "border-radius"              : "webkit",
  8451.             "border-start"               : "webkit moz",
  8452.             "border-start-color"         : "webkit moz",
  8453.             "border-start-style"         : "webkit moz",
  8454.             "border-start-width"         : "webkit moz",
  8455.             "box-align"                  : "webkit moz ms",
  8456.             "box-direction"              : "webkit moz ms",
  8457.             "box-flex"                   : "webkit moz ms",
  8458.             "box-lines"                  : "webkit ms",
  8459.             "box-ordinal-group"          : "webkit moz ms",
  8460.             "box-orient"                 : "webkit moz ms",
  8461.             "box-pack"                   : "webkit moz ms",
  8462.             "box-sizing"                 : "",
  8463.             "box-shadow"                 : "",
  8464.             "column-count"               : "webkit moz ms",
  8465.             "column-gap"                 : "webkit moz ms",
  8466.             "column-rule"                : "webkit moz ms",
  8467.             "column-rule-color"          : "webkit moz ms",
  8468.             "column-rule-style"          : "webkit moz ms",
  8469.             "column-rule-width"          : "webkit moz ms",
  8470.             "column-width"               : "webkit moz ms",
  8471.             "hyphens"                    : "epub moz",
  8472.             "line-break"                 : "webkit ms",
  8473.             "margin-end"                 : "webkit moz",
  8474.             "margin-start"               : "webkit moz",
  8475.             "marquee-speed"              : "webkit wap",
  8476.             "marquee-style"              : "webkit wap",
  8477.             "padding-end"                : "webkit moz",
  8478.             "padding-start"              : "webkit moz",
  8479.             "tab-size"                   : "moz o",
  8480.             "text-size-adjust"           : "webkit ms",
  8481.             "transform"                  : "webkit ms",
  8482.             "transform-origin"           : "webkit ms",
  8483.             "transition"                 : "",
  8484.             "transition-delay"           : "",
  8485.             "transition-duration"        : "",
  8486.             "transition-property"        : "",
  8487.             "transition-timing-function" : "",
  8488.             "user-modify"                : "webkit moz",
  8489.             "user-select"                : "webkit moz ms",
  8490.             "word-break"                 : "epub ms",
  8491.             "writing-mode"               : "epub ms"
  8492.         };
  8493.  
  8494.  
  8495.         for (prop in compatiblePrefixes) {
  8496.             if (compatiblePrefixes.hasOwnProperty(prop)) {
  8497.                 variations = [];
  8498.                 prefixed = compatiblePrefixes[prop].split(" ");
  8499.                 for (i = 0, len = prefixed.length; i < len; i++) {
  8500.                     variations.push("-" + prefixed[i] + "-" + prop);
  8501.                 }
  8502.                 compatiblePrefixes[prop] = variations;
  8503.                 arrayPush.apply(applyTo, variations);
  8504.             }
  8505.         }
  8506.  
  8507.         parser.addListener("startrule", function () {
  8508.             properties = [];
  8509.         });
  8510.  
  8511.         parser.addListener("startkeyframes", function (event) {
  8512.             inKeyFrame = event.prefix || true;
  8513.         });
  8514.  
  8515.         parser.addListener("endkeyframes", function () {
  8516.             inKeyFrame = false;
  8517.         });
  8518.  
  8519.         parser.addListener("property", function (event) {
  8520.             var name = event.property;
  8521.             if (CSSLint.Util.indexOf(applyTo, name.text) > -1) {
  8522.  
  8523.                 // e.g., -moz-transform is okay to be alone in @-moz-keyframes
  8524.                 if (!inKeyFrame || typeof inKeyFrame !== "string" ||
  8525.                         name.text.indexOf("-" + inKeyFrame + "-") !== 0) {
  8526.                     properties.push(name);
  8527.                 }
  8528.             }
  8529.         });
  8530.  
  8531.         parser.addListener("endrule", function () {
  8532.             if (!properties.length) {
  8533.                 return;
  8534.             }
  8535.  
  8536.             var propertyGroups = {},
  8537.                 i,
  8538.                 len,
  8539.                 name,
  8540.                 prop,
  8541.                 variations,
  8542.                 value,
  8543.                 full,
  8544.                 actual,
  8545.                 item,
  8546.                 propertiesSpecified;
  8547.  
  8548.             for (i = 0, len = properties.length; i < len; i++) {
  8549.                 name = properties[i];
  8550.  
  8551.                 for (prop in compatiblePrefixes) {
  8552.                     if (compatiblePrefixes.hasOwnProperty(prop)) {
  8553.                         variations = compatiblePrefixes[prop];
  8554.                         if (CSSLint.Util.indexOf(variations, name.text) > -1) {
  8555.                             if (!propertyGroups[prop]) {
  8556.                                 propertyGroups[prop] = {
  8557.                                     full: variations.slice(0),
  8558.                                     actual: [],
  8559.                                     actualNodes: []
  8560.                                 };
  8561.                             }
  8562.                             if (CSSLint.Util.indexOf(propertyGroups[prop].actual, name.text) === -1) {
  8563.                                 propertyGroups[prop].actual.push(name.text);
  8564.                                 propertyGroups[prop].actualNodes.push(name);
  8565.                             }
  8566.                         }
  8567.                     }
  8568.                 }
  8569.             }
  8570.  
  8571.             for (prop in propertyGroups) {
  8572.                 if (propertyGroups.hasOwnProperty(prop)) {
  8573.                     value = propertyGroups[prop];
  8574.                     full = value.full;
  8575.                     actual = value.actual;
  8576.  
  8577.                     if (full.length > actual.length) {
  8578.                         for (i = 0, len = full.length; i < len; i++) {
  8579.                             item = full[i];
  8580.                             if (CSSLint.Util.indexOf(actual, item) === -1) {
  8581.                                 propertiesSpecified = (actual.length === 1) ? actual[0] : (actual.length === 2) ? actual.join(" and ") : actual.join(", ");
  8582.                                 reporter.report("The property " + item + " is compatible with " + propertiesSpecified + " and should be included as well.", value.actualNodes[0].line, value.actualNodes[0].col, rule);
  8583.                             }
  8584.                         }
  8585.  
  8586.                     }
  8587.                 }
  8588.             }
  8589.         });
  8590.     }
  8591. });
  8592.  
  8593. /*
  8594.  * Rule: Certain properties don't play well with certain display values.
  8595.  * - float should not be used with inline-block
  8596.  * - height, width, margin-top, margin-bottom, float should not be used with inline
  8597.  * - vertical-align should not be used with block
  8598.  * - margin, float should not be used with table-*
  8599.  */
  8600.  
  8601. CSSLint.addRule({
  8602.  
  8603.     // rule information
  8604.     id: "display-property-grouping",
  8605.     name: "Require properties appropriate for display",
  8606.     desc: "Certain properties shouldn't be used with certain display property values.",
  8607.     url: "https://github.com/CSSLint/csslint/wiki/Require-properties-appropriate-for-display",
  8608.     browsers: "All",
  8609.  
  8610.     // initialization
  8611.     init: function(parser, reporter) {
  8612.         "use strict";
  8613.         var rule = this;
  8614.  
  8615.         var propertiesToCheck = {
  8616.                 display: 1,
  8617.                 "float": "none",
  8618.                 height: 1,
  8619.                 width: 1,
  8620.                 margin: 1,
  8621.                 "margin-left": 1,
  8622.                 "margin-right": 1,
  8623.                 "margin-bottom": 1,
  8624.                 "margin-top": 1,
  8625.                 padding: 1,
  8626.                 "padding-left": 1,
  8627.                 "padding-right": 1,
  8628.                 "padding-bottom": 1,
  8629.                 "padding-top": 1,
  8630.                 "vertical-align": 1
  8631.             },
  8632.             properties;
  8633.  
  8634.         function reportProperty(name, display, msg) {
  8635.             if (properties[name]) {
  8636.                 if (typeof propertiesToCheck[name] !== "string" || properties[name].value.toLowerCase() !== propertiesToCheck[name]) {
  8637.                     reporter.report(msg || name + " can't be used with display: " + display + ".", properties[name].line, properties[name].col, rule);
  8638.                 }
  8639.             }
  8640.         }
  8641.  
  8642.         function startRule() {
  8643.             properties = {};
  8644.         }
  8645.  
  8646.         function endRule() {
  8647.  
  8648.             var display = properties.display ? properties.display.value : null;
  8649.             if (display) {
  8650.                 switch (display) {
  8651.  
  8652.                     case "inline":
  8653.                         // height, width, margin-top, margin-bottom, float should not be used with inline
  8654.                         reportProperty("height", display);
  8655.                         reportProperty("width", display);
  8656.                         reportProperty("margin", display);
  8657.                         reportProperty("margin-top", display);
  8658.                         reportProperty("margin-bottom", display);
  8659.                         reportProperty("float", display, "display:inline has no effect on floated elements (but may be used to fix the IE6 double-margin bug).");
  8660.                         break;
  8661.  
  8662.                     case "block":
  8663.                         // vertical-align should not be used with block
  8664.                         reportProperty("vertical-align", display);
  8665.                         break;
  8666.  
  8667.                     case "inline-block":
  8668.                         // float should not be used with inline-block
  8669.                         reportProperty("float", display);
  8670.                         break;
  8671.  
  8672.                     default:
  8673.                         // margin, float should not be used with table
  8674.                         if (display.indexOf("table-") === 0) {
  8675.                             reportProperty("margin", display);
  8676.                             reportProperty("margin-left", display);
  8677.                             reportProperty("margin-right", display);
  8678.                             reportProperty("margin-top", display);
  8679.                             reportProperty("margin-bottom", display);
  8680.                             reportProperty("float", display);
  8681.                         }
  8682.  
  8683.                         // otherwise do nothing
  8684.                 }
  8685.             }
  8686.  
  8687.         }
  8688.  
  8689.         parser.addListener("startrule", startRule);
  8690.         parser.addListener("startfontface", startRule);
  8691.         parser.addListener("startkeyframerule", startRule);
  8692.         parser.addListener("startpagemargin", startRule);
  8693.         parser.addListener("startpage", startRule);
  8694.         parser.addListener("startviewport", startRule);
  8695.  
  8696.         parser.addListener("property", function(event) {
  8697.             var name = event.property.text.toLowerCase();
  8698.  
  8699.             if (propertiesToCheck[name]) {
  8700.                 properties[name] = {
  8701.                     value: event.value.text,
  8702.                     line: event.property.line,
  8703.                     col: event.property.col
  8704.                 };
  8705.             }
  8706.         });
  8707.  
  8708.         parser.addListener("endrule", endRule);
  8709.         parser.addListener("endfontface", endRule);
  8710.         parser.addListener("endkeyframerule", endRule);
  8711.         parser.addListener("endpagemargin", endRule);
  8712.         parser.addListener("endpage", endRule);
  8713.         parser.addListener("endviewport", endRule);
  8714.  
  8715.     }
  8716.  
  8717. });
  8718.  
  8719. /*
  8720.  * Rule: Disallow duplicate background-images (using url).
  8721.  */
  8722.  
  8723. CSSLint.addRule({
  8724.  
  8725.     // rule information
  8726.     id: "duplicate-background-images",
  8727.     name: "Disallow duplicate background images",
  8728.     desc: "Every background-image should be unique. Use a common class for e.g. sprites.",
  8729.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-duplicate-background-images",
  8730.     browsers: "All",
  8731.  
  8732.     // initialization
  8733.     init: function(parser, reporter) {
  8734.         "use strict";
  8735.         var rule = this,
  8736.             stack = {};
  8737.  
  8738.         parser.addListener("property", function(event) {
  8739.             var name = event.property.text,
  8740.                 value = event.value,
  8741.                 i, len;
  8742.  
  8743.             if (name.match(/background/i)) {
  8744.                 for (i=0, len=value.parts.length; i < len; i++) {
  8745.                     if (value.parts[i].type === "uri") {
  8746.                         if (typeof stack[value.parts[i].uri] === "undefined") {
  8747.                             stack[value.parts[i].uri] = event;
  8748.                         } else {
  8749.                             reporter.report("Background image '" + value.parts[i].uri + "' was used multiple times, first declared at line " + stack[value.parts[i].uri].line + ", col " + stack[value.parts[i].uri].col + ".", event.line, event.col, rule);
  8750.                         }
  8751.                     }
  8752.                 }
  8753.             }
  8754.         });
  8755.     }
  8756. });
  8757.  
  8758. /*
  8759.  * Rule: Duplicate properties must appear one after the other. If an already-defined
  8760.  * property appears somewhere else in the rule, then it's likely an error.
  8761.  */
  8762.  
  8763. CSSLint.addRule({
  8764.  
  8765.     // rule information
  8766.     id: "duplicate-properties",
  8767.     name: "Disallow duplicate properties",
  8768.     desc: "Duplicate properties must appear one after the other.",
  8769.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-duplicate-properties",
  8770.     browsers: "All",
  8771.  
  8772.     // initialization
  8773.     init: function(parser, reporter) {
  8774.         "use strict";
  8775.         var rule = this,
  8776.             properties,
  8777.             lastProperty;
  8778.  
  8779.         function startRule() {
  8780.             properties = {};
  8781.         }
  8782.  
  8783.         parser.addListener("startrule", startRule);
  8784.         parser.addListener("startfontface", startRule);
  8785.         parser.addListener("startpage", startRule);
  8786.         parser.addListener("startpagemargin", startRule);
  8787.         parser.addListener("startkeyframerule", startRule);
  8788.         parser.addListener("startviewport", startRule);
  8789.  
  8790.         parser.addListener("property", function(event) {
  8791.             var property = event.property,
  8792.                 name = property.text.toLowerCase();
  8793.  
  8794.             if (properties[name] && (lastProperty !== name || properties[name] === event.value.text)) {
  8795.                 reporter.report("Duplicate property '" + event.property + "' found.", event.line, event.col, rule);
  8796.             }
  8797.  
  8798.             properties[name] = event.value.text;
  8799.             lastProperty = name;
  8800.  
  8801.         });
  8802.  
  8803.  
  8804.     }
  8805.  
  8806. });
  8807.  
  8808. /*
  8809.  * Rule: Style rules without any properties defined should be removed.
  8810.  */
  8811.  
  8812. CSSLint.addRule({
  8813.  
  8814.     // rule information
  8815.     id: "empty-rules",
  8816.     name: "Disallow empty rules",
  8817.     desc: "Rules without any properties specified should be removed.",
  8818.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-empty-rules",
  8819.     browsers: "All",
  8820.  
  8821.     // initialization
  8822.     init: function(parser, reporter) {
  8823.         "use strict";
  8824.         var rule = this,
  8825.             count = 0;
  8826.  
  8827.         parser.addListener("startrule", function() {
  8828.             count=0;
  8829.         });
  8830.  
  8831.         parser.addListener("property", function() {
  8832.             count++;
  8833.         });
  8834.  
  8835.         parser.addListener("endrule", function(event) {
  8836.             var selectors = event.selectors;
  8837.             if (count === 0) {
  8838.                 reporter.report("Rule is empty.", selectors[0].line, selectors[0].col, rule);
  8839.             }
  8840.         });
  8841.     }
  8842.  
  8843. });
  8844.  
  8845. /*
  8846.  * Rule: There should be no syntax errors. (Duh.)
  8847.  */
  8848.  
  8849. CSSLint.addRule({
  8850.  
  8851.     // rule information
  8852.     id: "errors",
  8853.     name: "Parsing Errors",
  8854.     desc: "This rule looks for recoverable syntax errors.",
  8855.     browsers: "All",
  8856.  
  8857.     // initialization
  8858.     init: function(parser, reporter) {
  8859.         "use strict";
  8860.         var rule = this;
  8861.  
  8862.         parser.addListener("error", function(event) {
  8863.             reporter.error(event.message, event.line, event.col, rule);
  8864.         });
  8865.  
  8866.     }
  8867.  
  8868. });
  8869.  
  8870. CSSLint.addRule({
  8871.  
  8872.     // rule information
  8873.     id: "fallback-colors",
  8874.     name: "Require fallback colors",
  8875.     desc: "For older browsers that don't support RGBA, HSL, or HSLA, provide a fallback color.",
  8876.     url: "https://github.com/CSSLint/csslint/wiki/Require-fallback-colors",
  8877.     browsers: "IE6,IE7,IE8",
  8878.  
  8879.     // initialization
  8880.     init: function(parser, reporter) {
  8881.         "use strict";
  8882.         var rule = this,
  8883.             lastProperty,
  8884.             propertiesToCheck = {
  8885.                 color: 1,
  8886.                 background: 1,
  8887.                 "border-color": 1,
  8888.                 "border-top-color": 1,
  8889.                 "border-right-color": 1,
  8890.                 "border-bottom-color": 1,
  8891.                 "border-left-color": 1,
  8892.                 border: 1,
  8893.                 "border-top": 1,
  8894.                 "border-right": 1,
  8895.                 "border-bottom": 1,
  8896.                 "border-left": 1,
  8897.                 "background-color": 1
  8898.             };
  8899.  
  8900.         function startRule() {
  8901.             lastProperty = null;
  8902.         }
  8903.  
  8904.         parser.addListener("startrule", startRule);
  8905.         parser.addListener("startfontface", startRule);
  8906.         parser.addListener("startpage", startRule);
  8907.         parser.addListener("startpagemargin", startRule);
  8908.         parser.addListener("startkeyframerule", startRule);
  8909.         parser.addListener("startviewport", startRule);
  8910.  
  8911.         parser.addListener("property", function(event) {
  8912.             var property = event.property,
  8913.                 name = property.text.toLowerCase(),
  8914.                 parts = event.value.parts,
  8915.                 i = 0,
  8916.                 colorType = "",
  8917.                 len = parts.length;
  8918.  
  8919.             if (propertiesToCheck[name]) {
  8920.                 while (i < len) {
  8921.                     if (parts[i].type === "color") {
  8922.                         if ("alpha" in parts[i] || "hue" in parts[i]) {
  8923.  
  8924.                             if (/([^\)]+)\(/.test(parts[i])) {
  8925.                                 colorType = RegExp.$1.toUpperCase();
  8926.                             }
  8927.  
  8928.                             if (!lastProperty || (lastProperty.property.text.toLowerCase() !== name || lastProperty.colorType !== "compat")) {
  8929.                                 reporter.report("Fallback " + name + " (hex or RGB) should precede " + colorType + " " + name + ".", event.line, event.col, rule);
  8930.                             }
  8931.                         } else {
  8932.                             event.colorType = "compat";
  8933.                         }
  8934.                     }
  8935.  
  8936.                     i++;
  8937.                 }
  8938.             }
  8939.  
  8940.             lastProperty = event;
  8941.         });
  8942.  
  8943.     }
  8944.  
  8945. });
  8946.  
  8947. /*
  8948.  * Rule: You shouldn't use more than 10 floats. If you do, there's probably
  8949.  * room for some abstraction.
  8950.  */
  8951.  
  8952. CSSLint.addRule({
  8953.  
  8954.     // rule information
  8955.     id: "floats",
  8956.     name: "Disallow too many floats",
  8957.     desc: "This rule tests if the float property is used too many times",
  8958.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-too-many-floats",
  8959.     browsers: "All",
  8960.  
  8961.     // initialization
  8962.     init: function(parser, reporter) {
  8963.         "use strict";
  8964.         var rule = this;
  8965.         var count = 0;
  8966.  
  8967.         // count how many times "float" is used
  8968.         parser.addListener("property", function(event) {
  8969.             if (event.property.text.toLowerCase() === "float" &&
  8970.                     event.value.text.toLowerCase() !== "none") {
  8971.                 count++;
  8972.             }
  8973.         });
  8974.  
  8975.         // report the results
  8976.         parser.addListener("endstylesheet", function() {
  8977.             reporter.stat("floats", count);
  8978.             if (count >= 10) {
  8979.                 reporter.rollupWarn("Too many floats (" + count + "), you're probably using them for layout. Consider using a grid system instead.", rule);
  8980.             }
  8981.         });
  8982.     }
  8983.  
  8984. });
  8985.  
  8986. /*
  8987.  * Rule: Avoid too many @font-face declarations in the same stylesheet.
  8988.  */
  8989.  
  8990. CSSLint.addRule({
  8991.  
  8992.     // rule information
  8993.     id: "font-faces",
  8994.     name: "Don't use too many web fonts",
  8995.     desc: "Too many different web fonts in the same stylesheet.",
  8996.     url: "https://github.com/CSSLint/csslint/wiki/Don%27t-use-too-many-web-fonts",
  8997.     browsers: "All",
  8998.  
  8999.     // initialization
  9000.     init: function(parser, reporter) {
  9001.         "use strict";
  9002.         var rule = this,
  9003.             count = 0;
  9004.  
  9005.  
  9006.         parser.addListener("startfontface", function() {
  9007.             count++;
  9008.         });
  9009.  
  9010.         parser.addListener("endstylesheet", function() {
  9011.             if (count > 5) {
  9012.                 reporter.rollupWarn("Too many @font-face declarations (" + count + ").", rule);
  9013.             }
  9014.         });
  9015.     }
  9016.  
  9017. });
  9018.  
  9019. /*
  9020.  * Rule: You shouldn't need more than 9 font-size declarations.
  9021.  */
  9022.  
  9023. CSSLint.addRule({
  9024.  
  9025.     // rule information
  9026.     id: "font-sizes",
  9027.     name: "Disallow too many font sizes",
  9028.     desc: "Checks the number of font-size declarations.",
  9029.     url: "https://github.com/CSSLint/csslint/wiki/Don%27t-use-too-many-font-size-declarations",
  9030.     browsers: "All",
  9031.  
  9032.     // initialization
  9033.     init: function(parser, reporter) {
  9034.         "use strict";
  9035.         var rule = this,
  9036.             count = 0;
  9037.  
  9038.         // check for use of "font-size"
  9039.         parser.addListener("property", function(event) {
  9040.             if (event.property.toString() === "font-size") {
  9041.                 count++;
  9042.             }
  9043.         });
  9044.  
  9045.         // report the results
  9046.         parser.addListener("endstylesheet", function() {
  9047.             reporter.stat("font-sizes", count);
  9048.             if (count >= 10) {
  9049.                 reporter.rollupWarn("Too many font-size declarations (" + count + "), abstraction needed.", rule);
  9050.             }
  9051.         });
  9052.     }
  9053.  
  9054. });
  9055.  
  9056. /*
  9057.  * Rule: When using a vendor-prefixed gradient, make sure to use them all.
  9058.  */
  9059.  
  9060. CSSLint.addRule({
  9061.  
  9062.     // rule information
  9063.     id: "gradients",
  9064.     name: "Require all gradient definitions",
  9065.     desc: "When using a vendor-prefixed gradient, make sure to use them all.",
  9066.     url: "https://github.com/CSSLint/csslint/wiki/Require-all-gradient-definitions",
  9067.     browsers: "All",
  9068.  
  9069.     // initialization
  9070.     init: function(parser, reporter) {
  9071.         "use strict";
  9072.         var rule = this,
  9073.             gradients;
  9074.  
  9075.         parser.addListener("startrule", function() {
  9076.             gradients = {
  9077.                 moz: 0,
  9078.                 webkit: 0,
  9079.                 oldWebkit: 0,
  9080.                 o: 0
  9081.             };
  9082.         });
  9083.  
  9084.         parser.addListener("property", function(event) {
  9085.  
  9086.             if (/\-(moz|o|webkit)(?:\-(?:linear|radial))\-gradient/i.test(event.value)) {
  9087.                 gradients[RegExp.$1] = 1;
  9088.             } else if (/\-webkit\-gradient/i.test(event.value)) {
  9089.                 gradients.oldWebkit = 1;
  9090.             }
  9091.  
  9092.         });
  9093.  
  9094.         parser.addListener("endrule", function(event) {
  9095.             var missing = [];
  9096.  
  9097.             if (!gradients.moz) {
  9098.                 missing.push("Firefox 3.6+");
  9099.             }
  9100.  
  9101.             if (!gradients.webkit) {
  9102.                 missing.push("Webkit (Safari 5+, Chrome)");
  9103.             }
  9104.  
  9105.             if (!gradients.oldWebkit) {
  9106.                 missing.push("Old Webkit (Safari 4+, Chrome)");
  9107.             }
  9108.  
  9109.             if (!gradients.o) {
  9110.                 missing.push("Opera 11.1+");
  9111.             }
  9112.  
  9113.             if (missing.length && missing.length < 4) {
  9114.                 reporter.report("Missing vendor-prefixed CSS gradients for " + missing.join(", ") + ".", event.selectors[0].line, event.selectors[0].col, rule);
  9115.             }
  9116.  
  9117.         });
  9118.  
  9119.     }
  9120.  
  9121. });
  9122.  
  9123. /*
  9124.  * Rule: Don't use IDs for selectors.
  9125.  */
  9126.  
  9127. CSSLint.addRule({
  9128.  
  9129.     // rule information
  9130.     id: "ids",
  9131.     name: "Disallow IDs in selectors",
  9132.     desc: "Selectors should not contain IDs.",
  9133.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-IDs-in-selectors",
  9134.     browsers: "All",
  9135.  
  9136.     // initialization
  9137.     init: function(parser, reporter) {
  9138.         "use strict";
  9139.         var rule = this;
  9140.         parser.addListener("startrule", function(event) {
  9141.             var selectors = event.selectors,
  9142.                 selector,
  9143.                 part,
  9144.                 modifier,
  9145.                 idCount,
  9146.                 i, j, k;
  9147.  
  9148.             for (i=0; i < selectors.length; i++) {
  9149.                 selector = selectors[i];
  9150.                 idCount = 0;
  9151.  
  9152.                 for (j=0; j < selector.parts.length; j++) {
  9153.                     part = selector.parts[j];
  9154.                     if (part.type === parser.SELECTOR_PART_TYPE) {
  9155.                         for (k=0; k < part.modifiers.length; k++) {
  9156.                             modifier = part.modifiers[k];
  9157.                             if (modifier.type === "id") {
  9158.                                 idCount++;
  9159.                             }
  9160.                         }
  9161.                     }
  9162.                 }
  9163.  
  9164.                 if (idCount === 1) {
  9165.                     reporter.report("Don't use IDs in selectors.", selector.line, selector.col, rule);
  9166.                 } else if (idCount > 1) {
  9167.                     reporter.report(idCount + " IDs in the selector, really?", selector.line, selector.col, rule);
  9168.                 }
  9169.             }
  9170.  
  9171.         });
  9172.     }
  9173.  
  9174. });
  9175.  
  9176. /*
  9177.  * Rule: IE6-9 supports up to 31 stylesheet import.
  9178.  * Reference:
  9179.  * http://blogs.msdn.com/b/ieinternals/archive/2011/05/14/internet-explorer-stylesheet-rule-selector-import-sheet-limit-maximum.aspx
  9180.  */
  9181.  
  9182. CSSLint.addRule({
  9183.  
  9184.     // rule information
  9185.     id: "import-ie-limit",
  9186.     name: "@import limit on IE6-IE9",
  9187.     desc: "IE6-9 supports up to 31 @import per stylesheet",
  9188.     browsers: "IE6, IE7, IE8, IE9",
  9189.  
  9190.     // initialization
  9191.     init: function(parser, reporter) {
  9192.         "use strict";
  9193.         var rule = this,
  9194.             MAX_IMPORT_COUNT = 31,
  9195.             count = 0;
  9196.  
  9197.         function startPage() {
  9198.             count = 0;
  9199.         }
  9200.  
  9201.         parser.addListener("startpage", startPage);
  9202.  
  9203.         parser.addListener("import", function() {
  9204.             count++;
  9205.         });
  9206.  
  9207.         parser.addListener("endstylesheet", function() {
  9208.             if (count > MAX_IMPORT_COUNT) {
  9209.                 reporter.rollupError(
  9210.                     "Too many @import rules (" + count + "). IE6-9 supports up to 31 import per stylesheet.",
  9211.                     rule
  9212.                 );
  9213.             }
  9214.         });
  9215.     }
  9216.  
  9217. });
  9218.  
  9219. /*
  9220.  * Rule: Don't use @import, use <link> instead.
  9221.  */
  9222.  
  9223. CSSLint.addRule({
  9224.  
  9225.     // rule information
  9226.     id: "import",
  9227.     name: "Disallow @import",
  9228.     desc: "Don't use @import, use <link> instead.",
  9229.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-%40import",
  9230.     browsers: "All",
  9231.  
  9232.     // initialization
  9233.     init: function(parser, reporter) {
  9234.         "use strict";
  9235.         var rule = this;
  9236.  
  9237.         parser.addListener("import", function(event) {
  9238.             reporter.report("@import prevents parallel downloads, use <link> instead.", event.line, event.col, rule);
  9239.         });
  9240.  
  9241.     }
  9242.  
  9243. });
  9244.  
  9245. /*
  9246.  * Rule: Make sure !important is not overused, this could lead to specificity
  9247.  * war. Display a warning on !important declarations, an error if it's
  9248.  * used more at least 10 times.
  9249.  */
  9250.  
  9251. CSSLint.addRule({
  9252.  
  9253.     // rule information
  9254.     id: "important",
  9255.     name: "Disallow !important",
  9256.     desc: "Be careful when using !important declaration",
  9257.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-%21important",
  9258.     browsers: "All",
  9259.  
  9260.     // initialization
  9261.     init: function(parser, reporter) {
  9262.         "use strict";
  9263.         var rule = this,
  9264.             count = 0;
  9265.  
  9266.         // warn that important is used and increment the declaration counter
  9267.         parser.addListener("property", function(event) {
  9268.             if (event.important === true) {
  9269.                 count++;
  9270.                 reporter.report("Use of !important", event.line, event.col, rule);
  9271.             }
  9272.         });
  9273.  
  9274.         // if there are more than 10, show an error
  9275.         parser.addListener("endstylesheet", function() {
  9276.             reporter.stat("important", count);
  9277.             if (count >= 10) {
  9278.                 reporter.rollupWarn("Too many !important declarations (" + count + "), try to use less than 10 to avoid specificity issues.", rule);
  9279.             }
  9280.         });
  9281.     }
  9282.  
  9283. });
  9284.  
  9285. /*
  9286.  * Rule: Properties should be known (listed in CSS3 specification) or
  9287.  * be a vendor-prefixed property.
  9288.  */
  9289.  
  9290. CSSLint.addRule({
  9291.  
  9292.     // rule information
  9293.     id: "known-properties",
  9294.     name: "Require use of known properties",
  9295.     desc: "Properties should be known (listed in CSS3 specification) or be a vendor-prefixed property.",
  9296.     url: "https://github.com/CSSLint/csslint/wiki/Require-use-of-known-properties",
  9297.     browsers: "All",
  9298.  
  9299.     // initialization
  9300.     init: function(parser, reporter) {
  9301.         "use strict";
  9302.         var rule = this;
  9303.  
  9304.         parser.addListener("property", function(event) {
  9305.  
  9306.             // the check is handled entirely by the parser-lib (https://github.com/nzakas/parser-lib)
  9307.             if (event.invalid) {
  9308.                 reporter.report(event.invalid.message, event.line, event.col, rule);
  9309.             }
  9310.  
  9311.         });
  9312.     }
  9313.  
  9314. });
  9315.  
  9316. /*
  9317.  * Rule: All properties should be in alphabetical order.
  9318.  */
  9319.  
  9320. CSSLint.addRule({
  9321.  
  9322.     // rule information
  9323.     id: "order-alphabetical",
  9324.     name: "Alphabetical order",
  9325.     desc: "Assure properties are in alphabetical order",
  9326.     browsers: "All",
  9327.  
  9328.     // initialization
  9329.     init: function(parser, reporter) {
  9330.         "use strict";
  9331.         var rule = this,
  9332.             properties;
  9333.  
  9334.         var startRule = function () {
  9335.             properties = [];
  9336.         };
  9337.  
  9338.         var endRule = function(event) {
  9339.             var currentProperties = properties.join(","),
  9340.                 expectedProperties = properties.sort().join(",");
  9341.  
  9342.             if (currentProperties !== expectedProperties) {
  9343.                 reporter.report("Rule doesn't have all its properties in alphabetical order.", event.line, event.col, rule);
  9344.             }
  9345.         };
  9346.  
  9347.         parser.addListener("startrule", startRule);
  9348.         parser.addListener("startfontface", startRule);
  9349.         parser.addListener("startpage", startRule);
  9350.         parser.addListener("startpagemargin", startRule);
  9351.         parser.addListener("startkeyframerule", startRule);
  9352.         parser.addListener("startviewport", startRule);
  9353.  
  9354.         parser.addListener("property", function(event) {
  9355.             var name = event.property.text,
  9356.                 lowerCasePrefixLessName = name.toLowerCase().replace(/^-.*?-/, "");
  9357.  
  9358.             properties.push(lowerCasePrefixLessName);
  9359.         });
  9360.  
  9361.         parser.addListener("endrule", endRule);
  9362.         parser.addListener("endfontface", endRule);
  9363.         parser.addListener("endpage", endRule);
  9364.         parser.addListener("endpagemargin", endRule);
  9365.         parser.addListener("endkeyframerule", endRule);
  9366.         parser.addListener("endviewport", endRule);
  9367.     }
  9368.  
  9369. });
  9370.  
  9371. /*
  9372.  * Rule: outline: none or outline: 0 should only be used in a :focus rule
  9373.  *       and only if there are other properties in the same rule.
  9374.  */
  9375.  
  9376. CSSLint.addRule({
  9377.  
  9378.     // rule information
  9379.     id: "outline-none",
  9380.     name: "Disallow outline: none",
  9381.     desc: "Use of outline: none or outline: 0 should be limited to :focus rules.",
  9382.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-outline%3Anone",
  9383.     browsers: "All",
  9384.     tags: ["Accessibility"],
  9385.  
  9386.     // initialization
  9387.     init: function(parser, reporter) {
  9388.         "use strict";
  9389.         var rule = this,
  9390.             lastRule;
  9391.  
  9392.         function startRule(event) {
  9393.             if (event.selectors) {
  9394.                 lastRule = {
  9395.                     line: event.line,
  9396.                     col: event.col,
  9397.                     selectors: event.selectors,
  9398.                     propCount: 0,
  9399.                     outline: false
  9400.                 };
  9401.             } else {
  9402.                 lastRule = null;
  9403.             }
  9404.         }
  9405.  
  9406.         function endRule() {
  9407.             if (lastRule) {
  9408.                 if (lastRule.outline) {
  9409.                     if (lastRule.selectors.toString().toLowerCase().indexOf(":focus") === -1) {
  9410.                         reporter.report("Outlines should only be modified using :focus.", lastRule.line, lastRule.col, rule);
  9411.                     } else if (lastRule.propCount === 1) {
  9412.                         reporter.report("Outlines shouldn't be hidden unless other visual changes are made.", lastRule.line, lastRule.col, rule);
  9413.                     }
  9414.                 }
  9415.             }
  9416.         }
  9417.  
  9418.         parser.addListener("startrule", startRule);
  9419.         parser.addListener("startfontface", startRule);
  9420.         parser.addListener("startpage", startRule);
  9421.         parser.addListener("startpagemargin", startRule);
  9422.         parser.addListener("startkeyframerule", startRule);
  9423.         parser.addListener("startviewport", startRule);
  9424.  
  9425.         parser.addListener("property", function(event) {
  9426.             var name = event.property.text.toLowerCase(),
  9427.                 value = event.value;
  9428.  
  9429.             if (lastRule) {
  9430.                 lastRule.propCount++;
  9431.                 if (name === "outline" && (value.toString() === "none" || value.toString() === "0")) {
  9432.                     lastRule.outline = true;
  9433.                 }
  9434.             }
  9435.  
  9436.         });
  9437.  
  9438.         parser.addListener("endrule", endRule);
  9439.         parser.addListener("endfontface", endRule);
  9440.         parser.addListener("endpage", endRule);
  9441.         parser.addListener("endpagemargin", endRule);
  9442.         parser.addListener("endkeyframerule", endRule);
  9443.         parser.addListener("endviewport", endRule);
  9444.  
  9445.     }
  9446.  
  9447. });
  9448.  
  9449. /*
  9450.  * Rule: Don't use classes or IDs with elements (a.foo or a#foo).
  9451.  */
  9452.  
  9453. CSSLint.addRule({
  9454.  
  9455.     // rule information
  9456.     id: "overqualified-elements",
  9457.     name: "Disallow overqualified elements",
  9458.     desc: "Don't use classes or IDs with elements (a.foo or a#foo).",
  9459.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-overqualified-elements",
  9460.     browsers: "All",
  9461.  
  9462.     // initialization
  9463.     init: function(parser, reporter) {
  9464.         "use strict";
  9465.         var rule = this,
  9466.             classes = {};
  9467.  
  9468.         parser.addListener("startrule", function(event) {
  9469.             var selectors = event.selectors,
  9470.                 selector,
  9471.                 part,
  9472.                 modifier,
  9473.                 i, j, k;
  9474.  
  9475.             for (i=0; i < selectors.length; i++) {
  9476.                 selector = selectors[i];
  9477.  
  9478.                 for (j=0; j < selector.parts.length; j++) {
  9479.                     part = selector.parts[j];
  9480.                     if (part.type === parser.SELECTOR_PART_TYPE) {
  9481.                         for (k=0; k < part.modifiers.length; k++) {
  9482.                             modifier = part.modifiers[k];
  9483.                             if (part.elementName && modifier.type === "id") {
  9484.                                 reporter.report("Element (" + part + ") is overqualified, just use " + modifier + " without element name.", part.line, part.col, rule);
  9485.                             } else if (modifier.type === "class") {
  9486.  
  9487.                                 if (!classes[modifier]) {
  9488.                                     classes[modifier] = [];
  9489.                                 }
  9490.                                 classes[modifier].push({
  9491.                                     modifier: modifier,
  9492.                                     part: part
  9493.                                 });
  9494.                             }
  9495.                         }
  9496.                     }
  9497.                 }
  9498.             }
  9499.         });
  9500.  
  9501.         parser.addListener("endstylesheet", function() {
  9502.  
  9503.             var prop;
  9504.             for (prop in classes) {
  9505.                 if (classes.hasOwnProperty(prop)) {
  9506.  
  9507.                     // one use means that this is overqualified
  9508.                     if (classes[prop].length === 1 && classes[prop][0].part.elementName) {
  9509.                         reporter.report("Element (" + classes[prop][0].part + ") is overqualified, just use " + classes[prop][0].modifier + " without element name.", classes[prop][0].part.line, classes[prop][0].part.col, rule);
  9510.                     }
  9511.                 }
  9512.             }
  9513.         });
  9514.     }
  9515.  
  9516. });
  9517.  
  9518. /*
  9519.  * Rule: Headings (h1-h6) should not be qualified (namespaced).
  9520.  */
  9521.  
  9522. CSSLint.addRule({
  9523.  
  9524.     // rule information
  9525.     id: "qualified-headings",
  9526.     name: "Disallow qualified headings",
  9527.     desc: "Headings should not be qualified (namespaced).",
  9528.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-qualified-headings",
  9529.     browsers: "All",
  9530.  
  9531.     // initialization
  9532.     init: function(parser, reporter) {
  9533.         "use strict";
  9534.         var rule = this;
  9535.  
  9536.         parser.addListener("startrule", function(event) {
  9537.             var selectors = event.selectors,
  9538.                 selector,
  9539.                 part,
  9540.                 i, j;
  9541.  
  9542.             for (i=0; i < selectors.length; i++) {
  9543.                 selector = selectors[i];
  9544.  
  9545.                 for (j=0; j < selector.parts.length; j++) {
  9546.                     part = selector.parts[j];
  9547.                     if (part.type === parser.SELECTOR_PART_TYPE) {
  9548.                         if (part.elementName && /h[1-6]/.test(part.elementName.toString()) && j > 0) {
  9549.                             reporter.report("Heading (" + part.elementName + ") should not be qualified.", part.line, part.col, rule);
  9550.                         }
  9551.                     }
  9552.                 }
  9553.             }
  9554.         });
  9555.     }
  9556.  
  9557. });
  9558.  
  9559. /*
  9560.  * Rule: Selectors that look like regular expressions are slow and should be avoided.
  9561.  */
  9562.  
  9563. CSSLint.addRule({
  9564.  
  9565.     // rule information
  9566.     id: "regex-selectors",
  9567.     name: "Disallow selectors that look like regexs",
  9568.     desc: "Selectors that look like regular expressions are slow and should be avoided.",
  9569.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-selectors-that-look-like-regular-expressions",
  9570.     browsers: "All",
  9571.  
  9572.     // initialization
  9573.     init: function(parser, reporter) {
  9574.         "use strict";
  9575.         var rule = this;
  9576.  
  9577.         parser.addListener("startrule", function(event) {
  9578.             var selectors = event.selectors,
  9579.                 selector,
  9580.                 part,
  9581.                 modifier,
  9582.                 i, j, k;
  9583.  
  9584.             for (i=0; i < selectors.length; i++) {
  9585.                 selector = selectors[i];
  9586.                 for (j=0; j < selector.parts.length; j++) {
  9587.                     part = selector.parts[j];
  9588.                     if (part.type === parser.SELECTOR_PART_TYPE) {
  9589.                         for (k=0; k < part.modifiers.length; k++) {
  9590.                             modifier = part.modifiers[k];
  9591.                             if (modifier.type === "attribute") {
  9592.                                 if (/([~\|\^\$\*]=)/.test(modifier)) {
  9593.                                     reporter.report("Attribute selectors with " + RegExp.$1 + " are slow!", modifier.line, modifier.col, rule);
  9594.                                 }
  9595.                             }
  9596.  
  9597.                         }
  9598.                     }
  9599.                 }
  9600.             }
  9601.         });
  9602.     }
  9603.  
  9604. });
  9605.  
  9606. /*
  9607.  * Rule: Total number of rules should not exceed x.
  9608.  */
  9609.  
  9610. CSSLint.addRule({
  9611.  
  9612.     // rule information
  9613.     id: "rules-count",
  9614.     name: "Rules Count",
  9615.     desc: "Track how many rules there are.",
  9616.     browsers: "All",
  9617.  
  9618.     // initialization
  9619.     init: function(parser, reporter) {
  9620.         "use strict";
  9621.         var count = 0;
  9622.  
  9623.         // count each rule
  9624.         parser.addListener("startrule", function() {
  9625.             count++;
  9626.         });
  9627.  
  9628.         parser.addListener("endstylesheet", function() {
  9629.             reporter.stat("rule-count", count);
  9630.         });
  9631.     }
  9632.  
  9633. });
  9634.  
  9635. /*
  9636.  * Rule: Warn people with approaching the IE 4095 limit
  9637.  */
  9638.  
  9639. CSSLint.addRule({
  9640.  
  9641.     // rule information
  9642.     id: "selector-max-approaching",
  9643.     name: "Warn when approaching the 4095 selector limit for IE",
  9644.     desc: "Will warn when selector count is >= 3800 selectors.",
  9645.     browsers: "IE",
  9646.  
  9647.     // initialization
  9648.     init: function(parser, reporter) {
  9649.         "use strict";
  9650.         var rule = this, count = 0;
  9651.  
  9652.         parser.addListener("startrule", function(event) {
  9653.             count += event.selectors.length;
  9654.         });
  9655.  
  9656.         parser.addListener("endstylesheet", function() {
  9657.             if (count >= 3800) {
  9658.                 reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.", 0, 0, rule);
  9659.             }
  9660.         });
  9661.     }
  9662.  
  9663. });
  9664.  
  9665. /*
  9666.  * Rule: Warn people past the IE 4095 limit
  9667.  */
  9668.  
  9669. CSSLint.addRule({
  9670.  
  9671.     // rule information
  9672.     id: "selector-max",
  9673.     name: "Error when past the 4095 selector limit for IE",
  9674.     desc: "Will error when selector count is > 4095.",
  9675.     browsers: "IE",
  9676.  
  9677.     // initialization
  9678.     init: function(parser, reporter) {
  9679.         "use strict";
  9680.         var rule = this, count = 0;
  9681.  
  9682.         parser.addListener("startrule", function(event) {
  9683.             count += event.selectors.length;
  9684.         });
  9685.  
  9686.         parser.addListener("endstylesheet", function() {
  9687.             if (count > 4095) {
  9688.                 reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.", 0, 0, rule);
  9689.             }
  9690.         });
  9691.     }
  9692.  
  9693. });
  9694.  
  9695. /*
  9696.  * Rule: Avoid new-line characters in selectors.
  9697.  */
  9698.  
  9699. CSSLint.addRule({
  9700.  
  9701.     // rule information
  9702.     id: "selector-newline",
  9703.     name: "Disallow new-line characters in selectors",
  9704.     desc: "New-line characters in selectors are usually a forgotten comma and not a descendant combinator.",
  9705.     browsers: "All",
  9706.  
  9707.     // initialization
  9708.     init: function(parser, reporter) {
  9709.         "use strict";
  9710.         var rule = this;
  9711.  
  9712.         function startRule(event) {
  9713.             var i, len, selector, p, n, pLen, part, part2, type, currentLine, nextLine,
  9714.                 selectors = event.selectors;
  9715.  
  9716.             for (i = 0, len = selectors.length; i < len; i++) {
  9717.                 selector = selectors[i];
  9718.                 for (p = 0, pLen = selector.parts.length; p < pLen; p++) {
  9719.                     for (n = p + 1; n < pLen; n++) {
  9720.                         part = selector.parts[p];
  9721.                         part2 = selector.parts[n];
  9722.                         type = part.type;
  9723.                         currentLine = part.line;
  9724.                         nextLine = part2.line;
  9725.  
  9726.                         if (type === "descendant" && nextLine > currentLine) {
  9727.                             reporter.report("newline character found in selector (forgot a comma?)", currentLine, selectors[i].parts[0].col, rule);
  9728.                         }
  9729.                     }
  9730.                 }
  9731.  
  9732.             }
  9733.         }
  9734.  
  9735.         parser.addListener("startrule", startRule);
  9736.  
  9737.     }
  9738. });
  9739.  
  9740. /*
  9741.  * Rule: Use shorthand properties where possible.
  9742.  *
  9743.  */
  9744.  
  9745. CSSLint.addRule({
  9746.  
  9747.     // rule information
  9748.     id: "shorthand",
  9749.     name: "Require shorthand properties",
  9750.     desc: "Use shorthand properties where possible.",
  9751.     url: "https://github.com/CSSLint/csslint/wiki/Require-shorthand-properties",
  9752.     browsers: "All",
  9753.  
  9754.     // initialization
  9755.     init: function(parser, reporter) {
  9756.         "use strict";
  9757.         var rule = this,
  9758.             prop, i, len,
  9759.             propertiesToCheck = {},
  9760.             properties,
  9761.             mapping = {
  9762.                 "margin": [
  9763.                     "margin-top",
  9764.                     "margin-bottom",
  9765.                     "margin-left",
  9766.                     "margin-right"
  9767.                 ],
  9768.                 "padding": [
  9769.                     "padding-top",
  9770.                     "padding-bottom",
  9771.                     "padding-left",
  9772.                     "padding-right"
  9773.                 ]
  9774.             };
  9775.  
  9776.         // initialize propertiesToCheck
  9777.         for (prop in mapping) {
  9778.             if (mapping.hasOwnProperty(prop)) {
  9779.                 for (i=0, len=mapping[prop].length; i < len; i++) {
  9780.                     propertiesToCheck[mapping[prop][i]] = prop;
  9781.                 }
  9782.             }
  9783.         }
  9784.  
  9785.         function startRule() {
  9786.             properties = {};
  9787.         }
  9788.  
  9789.         // event handler for end of rules
  9790.         function endRule(event) {
  9791.  
  9792.             var prop, i, len, total;
  9793.  
  9794.             // check which properties this rule has
  9795.             for (prop in mapping) {
  9796.                 if (mapping.hasOwnProperty(prop)) {
  9797.                     total=0;
  9798.  
  9799.                     for (i=0, len=mapping[prop].length; i < len; i++) {
  9800.                         total += properties[mapping[prop][i]] ? 1 : 0;
  9801.                     }
  9802.  
  9803.                     if (total === mapping[prop].length) {
  9804.                         reporter.report("The properties " + mapping[prop].join(", ") + " can be replaced by " + prop + ".", event.line, event.col, rule);
  9805.                     }
  9806.                 }
  9807.             }
  9808.         }
  9809.  
  9810.         parser.addListener("startrule", startRule);
  9811.         parser.addListener("startfontface", startRule);
  9812.  
  9813.         // check for use of "font-size"
  9814.         parser.addListener("property", function(event) {
  9815.             var name = event.property.toString().toLowerCase();
  9816.  
  9817.             if (propertiesToCheck[name]) {
  9818.                 properties[name] = 1;
  9819.             }
  9820.         });
  9821.  
  9822.         parser.addListener("endrule", endRule);
  9823.         parser.addListener("endfontface", endRule);
  9824.  
  9825.     }
  9826.  
  9827. });
  9828.  
  9829. /*
  9830.  * Rule: Don't use properties with a star prefix.
  9831.  *
  9832.  */
  9833.  
  9834. CSSLint.addRule({
  9835.  
  9836.     // rule information
  9837.     id: "star-property-hack",
  9838.     name: "Disallow properties with a star prefix",
  9839.     desc: "Checks for the star property hack (targets IE6/7)",
  9840.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-star-hack",
  9841.     browsers: "All",
  9842.  
  9843.     // initialization
  9844.     init: function(parser, reporter) {
  9845.         "use strict";
  9846.         var rule = this;
  9847.  
  9848.         // check if property name starts with "*"
  9849.         parser.addListener("property", function(event) {
  9850.             var property = event.property;
  9851.  
  9852.             if (property.hack === "*") {
  9853.                 reporter.report("Property with star prefix found.", event.property.line, event.property.col, rule);
  9854.             }
  9855.         });
  9856.     }
  9857. });
  9858.  
  9859. /*
  9860.  * Rule: Don't use text-indent for image replacement if you need to support rtl.
  9861.  *
  9862.  */
  9863.  
  9864. CSSLint.addRule({
  9865.  
  9866.     // rule information
  9867.     id: "text-indent",
  9868.     name: "Disallow negative text-indent",
  9869.     desc: "Checks for text indent less than -99px",
  9870.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-negative-text-indent",
  9871.     browsers: "All",
  9872.  
  9873.     // initialization
  9874.     init: function(parser, reporter) {
  9875.         "use strict";
  9876.         var rule = this,
  9877.             textIndent,
  9878.             direction;
  9879.  
  9880.  
  9881.         function startRule() {
  9882.             textIndent = false;
  9883.             direction = "inherit";
  9884.         }
  9885.  
  9886.         // event handler for end of rules
  9887.         function endRule() {
  9888.             if (textIndent && direction !== "ltr") {
  9889.                 reporter.report("Negative text-indent doesn't work well with RTL. If you use text-indent for image replacement explicitly set direction for that item to ltr.", textIndent.line, textIndent.col, rule);
  9890.             }
  9891.         }
  9892.  
  9893.         parser.addListener("startrule", startRule);
  9894.         parser.addListener("startfontface", startRule);
  9895.  
  9896.         // check for use of "font-size"
  9897.         parser.addListener("property", function(event) {
  9898.             var name = event.property.toString().toLowerCase(),
  9899.                 value = event.value;
  9900.  
  9901.             if (name === "text-indent" && value.parts[0].value < -99) {
  9902.                 textIndent = event.property;
  9903.             } else if (name === "direction" && value.toString() === "ltr") {
  9904.                 direction = "ltr";
  9905.             }
  9906.         });
  9907.  
  9908.         parser.addListener("endrule", endRule);
  9909.         parser.addListener("endfontface", endRule);
  9910.  
  9911.     }
  9912.  
  9913. });
  9914.  
  9915. /*
  9916.  * Rule: Don't use properties with a underscore prefix.
  9917.  *
  9918.  */
  9919.  
  9920. CSSLint.addRule({
  9921.  
  9922.     // rule information
  9923.     id: "underscore-property-hack",
  9924.     name: "Disallow properties with an underscore prefix",
  9925.     desc: "Checks for the underscore property hack (targets IE6)",
  9926.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-underscore-hack",
  9927.     browsers: "All",
  9928.  
  9929.     // initialization
  9930.     init: function(parser, reporter) {
  9931.         "use strict";
  9932.         var rule = this;
  9933.  
  9934.         // check if property name starts with "_"
  9935.         parser.addListener("property", function(event) {
  9936.             var property = event.property;
  9937.  
  9938.             if (property.hack === "_") {
  9939.                 reporter.report("Property with underscore prefix found.", event.property.line, event.property.col, rule);
  9940.             }
  9941.         });
  9942.     }
  9943. });
  9944.  
  9945. /*
  9946.  * Rule: Headings (h1-h6) should be defined only once.
  9947.  */
  9948.  
  9949. CSSLint.addRule({
  9950.  
  9951.     // rule information
  9952.     id: "unique-headings",
  9953.     name: "Headings should only be defined once",
  9954.     desc: "Headings should be defined only once.",
  9955.     url: "https://github.com/CSSLint/csslint/wiki/Headings-should-only-be-defined-once",
  9956.     browsers: "All",
  9957.  
  9958.     // initialization
  9959.     init: function(parser, reporter) {
  9960.         "use strict";
  9961.         var rule = this;
  9962.  
  9963.         var headings = {
  9964.             h1: 0,
  9965.             h2: 0,
  9966.             h3: 0,
  9967.             h4: 0,
  9968.             h5: 0,
  9969.             h6: 0
  9970.         };
  9971.  
  9972.         parser.addListener("startrule", function(event) {
  9973.             var selectors = event.selectors,
  9974.                 selector,
  9975.                 part,
  9976.                 pseudo,
  9977.                 i, j;
  9978.  
  9979.             for (i=0; i < selectors.length; i++) {
  9980.                 selector = selectors[i];
  9981.                 part = selector.parts[selector.parts.length-1];
  9982.  
  9983.                 if (part.elementName && /(h[1-6])/i.test(part.elementName.toString())) {
  9984.  
  9985.                     for (j=0; j < part.modifiers.length; j++) {
  9986.                         if (part.modifiers[j].type === "pseudo") {
  9987.                             pseudo = true;
  9988.                             break;
  9989.                         }
  9990.                     }
  9991.  
  9992.                     if (!pseudo) {
  9993.                         headings[RegExp.$1]++;
  9994.                         if (headings[RegExp.$1] > 1) {
  9995.                             reporter.report("Heading (" + part.elementName + ") has already been defined.", part.line, part.col, rule);
  9996.                         }
  9997.                     }
  9998.                 }
  9999.             }
  10000.         });
  10001.  
  10002.         parser.addListener("endstylesheet", function() {
  10003.             var prop,
  10004.                 messages = [];
  10005.  
  10006.             for (prop in headings) {
  10007.                 if (headings.hasOwnProperty(prop)) {
  10008.                     if (headings[prop] > 1) {
  10009.                         messages.push(headings[prop] + " " + prop + "s");
  10010.                     }
  10011.                 }
  10012.             }
  10013.  
  10014.             if (messages.length) {
  10015.                 reporter.rollupWarn("You have " + messages.join(", ") + " defined in this stylesheet.", rule);
  10016.             }
  10017.         });
  10018.     }
  10019.  
  10020. });
  10021.  
  10022. /*
  10023.  * Rule: Don't use universal selector because it's slow.
  10024.  */
  10025.  
  10026. CSSLint.addRule({
  10027.  
  10028.     // rule information
  10029.     id: "universal-selector",
  10030.     name: "Disallow universal selector",
  10031.     desc: "The universal selector (*) is known to be slow.",
  10032.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-universal-selector",
  10033.     browsers: "All",
  10034.  
  10035.     // initialization
  10036.     init: function(parser, reporter) {
  10037.         "use strict";
  10038.         var rule = this;
  10039.  
  10040.         parser.addListener("startrule", function(event) {
  10041.             var selectors = event.selectors,
  10042.                 selector,
  10043.                 part,
  10044.                 i;
  10045.  
  10046.             for (i=0; i < selectors.length; i++) {
  10047.                 selector = selectors[i];
  10048.  
  10049.                 part = selector.parts[selector.parts.length-1];
  10050.                 if (part.elementName === "*") {
  10051.                     reporter.report(rule.desc, part.line, part.col, rule);
  10052.                 }
  10053.             }
  10054.         });
  10055.     }
  10056.  
  10057. });
  10058.  
  10059. /*
  10060.  * Rule: Don't use unqualified attribute selectors because they're just like universal selectors.
  10061.  */
  10062.  
  10063. CSSLint.addRule({
  10064.  
  10065.     // rule information
  10066.     id: "unqualified-attributes",
  10067.     name: "Disallow unqualified attribute selectors",
  10068.     desc: "Unqualified attribute selectors are known to be slow.",
  10069.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-unqualified-attribute-selectors",
  10070.     browsers: "All",
  10071.  
  10072.     // initialization
  10073.     init: function(parser, reporter) {
  10074.         "use strict";
  10075.  
  10076.         var rule = this;
  10077.  
  10078.         parser.addListener("startrule", function(event) {
  10079.  
  10080.             var selectors = event.selectors,
  10081.                 selectorContainsClassOrId = false,
  10082.                 selector,
  10083.                 part,
  10084.                 modifier,
  10085.                 i, k;
  10086.  
  10087.             for (i=0; i < selectors.length; i++) {
  10088.                 selector = selectors[i];
  10089.  
  10090.                 part = selector.parts[selector.parts.length-1];
  10091.                 if (part.type === parser.SELECTOR_PART_TYPE) {
  10092.                     for (k=0; k < part.modifiers.length; k++) {
  10093.                         modifier = part.modifiers[k];
  10094.  
  10095.                         if (modifier.type === "class" || modifier.type === "id") {
  10096.                             selectorContainsClassOrId = true;
  10097.                             break;
  10098.                         }
  10099.                     }
  10100.  
  10101.                     if (!selectorContainsClassOrId) {
  10102.                         for (k=0; k < part.modifiers.length; k++) {
  10103.                             modifier = part.modifiers[k];
  10104.                             if (modifier.type === "attribute" && (!part.elementName || part.elementName === "*")) {
  10105.                                 reporter.report(rule.desc, part.line, part.col, rule);
  10106.                             }
  10107.                         }
  10108.                     }
  10109.                 }
  10110.  
  10111.             }
  10112.         });
  10113.     }
  10114.  
  10115. });
  10116.  
  10117. /*
  10118.  * Rule: When using a vendor-prefixed property, make sure to
  10119.  * include the standard one.
  10120.  */
  10121.  
  10122. CSSLint.addRule({
  10123.  
  10124.     // rule information
  10125.     id: "vendor-prefix",
  10126.     name: "Require standard property with vendor prefix",
  10127.     desc: "When using a vendor-prefixed property, make sure to include the standard one.",
  10128.     url: "https://github.com/CSSLint/csslint/wiki/Require-standard-property-with-vendor-prefix",
  10129.     browsers: "All",
  10130.  
  10131.     // initialization
  10132.     init: function(parser, reporter) {
  10133.         "use strict";
  10134.         var rule = this,
  10135.             properties,
  10136.             num,
  10137.             propertiesToCheck = {
  10138.                 "-webkit-border-radius": "border-radius",
  10139.                 "-webkit-border-top-left-radius": "border-top-left-radius",
  10140.                 "-webkit-border-top-right-radius": "border-top-right-radius",
  10141.                 "-webkit-border-bottom-left-radius": "border-bottom-left-radius",
  10142.                 "-webkit-border-bottom-right-radius": "border-bottom-right-radius",
  10143.  
  10144.                 "-o-border-radius": "border-radius",
  10145.                 "-o-border-top-left-radius": "border-top-left-radius",
  10146.                 "-o-border-top-right-radius": "border-top-right-radius",
  10147.                 "-o-border-bottom-left-radius": "border-bottom-left-radius",
  10148.                 "-o-border-bottom-right-radius": "border-bottom-right-radius",
  10149.  
  10150.                 "-moz-border-radius": "border-radius",
  10151.                 "-moz-border-radius-topleft": "border-top-left-radius",
  10152.                 "-moz-border-radius-topright": "border-top-right-radius",
  10153.                 "-moz-border-radius-bottomleft": "border-bottom-left-radius",
  10154.                 "-moz-border-radius-bottomright": "border-bottom-right-radius",
  10155.  
  10156.                 "-moz-column-count": "column-count",
  10157.                 "-webkit-column-count": "column-count",
  10158.  
  10159.                 "-moz-column-gap": "column-gap",
  10160.                 "-webkit-column-gap": "column-gap",
  10161.  
  10162.                 "-moz-column-rule": "column-rule",
  10163.                 "-webkit-column-rule": "column-rule",
  10164.  
  10165.                 "-moz-column-rule-style": "column-rule-style",
  10166.                 "-webkit-column-rule-style": "column-rule-style",
  10167.  
  10168.                 "-moz-column-rule-color": "column-rule-color",
  10169.                 "-webkit-column-rule-color": "column-rule-color",
  10170.  
  10171.                 "-moz-column-rule-width": "column-rule-width",
  10172.                 "-webkit-column-rule-width": "column-rule-width",
  10173.  
  10174.                 "-moz-column-width": "column-width",
  10175.                 "-webkit-column-width": "column-width",
  10176.  
  10177.                 "-webkit-column-span": "column-span",
  10178.                 "-webkit-columns": "columns",
  10179.  
  10180.                 "-moz-box-shadow": "box-shadow",
  10181.                 "-webkit-box-shadow": "box-shadow",
  10182.  
  10183.                 "-moz-transform": "transform",
  10184.                 "-webkit-transform": "transform",
  10185.                 "-o-transform": "transform",
  10186.                 "-ms-transform": "transform",
  10187.  
  10188.                 "-moz-transform-origin": "transform-origin",
  10189.                 "-webkit-transform-origin": "transform-origin",
  10190.                 "-o-transform-origin": "transform-origin",
  10191.                 "-ms-transform-origin": "transform-origin",
  10192.  
  10193.                 "-moz-box-sizing": "box-sizing",
  10194.                 "-webkit-box-sizing": "box-sizing"
  10195.             };
  10196.  
  10197.         // event handler for beginning of rules
  10198.         function startRule() {
  10199.             properties = {};
  10200.             num = 1;
  10201.         }
  10202.  
  10203.         // event handler for end of rules
  10204.         function endRule() {
  10205.             var prop,
  10206.                 i,
  10207.                 len,
  10208.                 needed,
  10209.                 actual,
  10210.                 needsStandard = [];
  10211.  
  10212.             for (prop in properties) {
  10213.                 if (propertiesToCheck[prop]) {
  10214.                     needsStandard.push({
  10215.                         actual: prop,
  10216.                         needed: propertiesToCheck[prop]
  10217.                     });
  10218.                 }
  10219.             }
  10220.  
  10221.             for (i=0, len=needsStandard.length; i < len; i++) {
  10222.                 needed = needsStandard[i].needed;
  10223.                 actual = needsStandard[i].actual;
  10224.  
  10225.                 if (!properties[needed]) {
  10226.                     reporter.report("Missing standard property '" + needed + "' to go along with '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);
  10227.                 } else {
  10228.                     // make sure standard property is last
  10229.                     if (properties[needed][0].pos < properties[actual][0].pos) {
  10230.                         reporter.report("Standard property '" + needed + "' should come after vendor-prefixed property '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);
  10231.                     }
  10232.                 }
  10233.             }
  10234.  
  10235.         }
  10236.  
  10237.         parser.addListener("startrule", startRule);
  10238.         parser.addListener("startfontface", startRule);
  10239.         parser.addListener("startpage", startRule);
  10240.         parser.addListener("startpagemargin", startRule);
  10241.         parser.addListener("startkeyframerule", startRule);
  10242.         parser.addListener("startviewport", startRule);
  10243.  
  10244.         parser.addListener("property", function(event) {
  10245.             var name = event.property.text.toLowerCase();
  10246.  
  10247.             if (!properties[name]) {
  10248.                 properties[name] = [];
  10249.             }
  10250.  
  10251.             properties[name].push({
  10252.                 name: event.property,
  10253.                 value: event.value,
  10254.                 pos: num++
  10255.             });
  10256.         });
  10257.  
  10258.         parser.addListener("endrule", endRule);
  10259.         parser.addListener("endfontface", endRule);
  10260.         parser.addListener("endpage", endRule);
  10261.         parser.addListener("endpagemargin", endRule);
  10262.         parser.addListener("endkeyframerule", endRule);
  10263.         parser.addListener("endviewport", endRule);
  10264.     }
  10265.  
  10266. });
  10267.  
  10268. /*
  10269.  * Rule: You don't need to specify units when a value is 0.
  10270.  */
  10271.  
  10272. CSSLint.addRule({
  10273.  
  10274.     // rule information
  10275.     id: "zero-units",
  10276.     name: "Disallow units for 0 values",
  10277.     desc: "You don't need to specify units when a value is 0.",
  10278.     url: "https://github.com/CSSLint/csslint/wiki/Disallow-units-for-zero-values",
  10279.     browsers: "All",
  10280.  
  10281.     // initialization
  10282.     init: function(parser, reporter) {
  10283.         "use strict";
  10284.         var rule = this;
  10285.  
  10286.         // count how many times "float" is used
  10287.         parser.addListener("property", function(event) {
  10288.             var parts = event.value.parts,
  10289.                 i = 0,
  10290.                 len = parts.length;
  10291.  
  10292.             while (i < len) {
  10293.                 if ((parts[i].units || parts[i].type === "percentage") && parts[i].value === 0 && parts[i].type !== "time") {
  10294.                     reporter.report("Values of 0 shouldn't have units specified.", parts[i].line, parts[i].col, rule);
  10295.                 }
  10296.                 i++;
  10297.             }
  10298.  
  10299.         });
  10300.  
  10301.     }
  10302.  
  10303. });
  10304.  
  10305. (function() {
  10306.     "use strict";
  10307.  
  10308.     /**
  10309.      * Replace special characters before write to output.
  10310.      *
  10311.      * Rules:
  10312.      *  - single quotes is the escape sequence for double-quotes
  10313.      *  - & is the escape sequence for &
  10314.      *  - < is the escape sequence for <
  10315.      *  - > is the escape sequence for >
  10316.      *
  10317.      * @param {String} message to escape
  10318.      * @return escaped message as {String}
  10319.      */
  10320.     var xmlEscape = function(str) {
  10321.         if (!str || str.constructor !== String) {
  10322.             return "";
  10323.         }
  10324.  
  10325.         return str.replace(/["&><]/g, function(match) {
  10326.             switch (match) {
  10327.                 case "\"":
  10328.                     return """;
  10329.                 case "&":
  10330.                     return "&";
  10331.                 case "<":
  10332.                     return "<";
  10333.                 case ">":
  10334.                     return ">";
  10335.             }
  10336.         });
  10337.     };
  10338.  
  10339.     CSSLint.addFormatter({
  10340.         // format information
  10341.         id: "checkstyle-xml",
  10342.         name: "Checkstyle XML format",
  10343.  
  10344.         /**
  10345.          * Return opening root XML tag.
  10346.          * @return {String} to prepend before all results
  10347.          */
  10348.         startFormat: function() {
  10349.             return "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>";
  10350.         },
  10351.  
  10352.         /**
  10353.          * Return closing root XML tag.
  10354.          * @return {String} to append after all results
  10355.          */
  10356.         endFormat: function() {
  10357.             return "</checkstyle>";
  10358.         },
  10359.  
  10360.         /**
  10361.          * Returns message when there is a file read error.
  10362.          * @param {String} filename The name of the file that caused the error.
  10363.          * @param {String} message The error message
  10364.          * @return {String} The error message.
  10365.          */
  10366.         readError: function(filename, message) {
  10367.             return "<file name=\"" + xmlEscape(filename) + "\"><error line=\"0\" column=\"0\" severty=\"error\" message=\"" + xmlEscape(message) + "\"></error></file>";
  10368.         },
  10369.  
  10370.         /**
  10371.          * Given CSS Lint results for a file, return output for this format.
  10372.          * @param results {Object} with error and warning messages
  10373.          * @param filename {String} relative file path
  10374.          * @param options {Object} (UNUSED for now) specifies special handling of output
  10375.          * @return {String} output for results
  10376.          */
  10377.         formatResults: function(results, filename/*, options*/) {
  10378.             var messages = results.messages,
  10379.                 output = [];
  10380.  
  10381.             /**
  10382.              * Generate a source string for a rule.
  10383.              * Checkstyle source strings usually resemble Java class names e.g
  10384.              * net.csslint.SomeRuleName
  10385.              * @param {Object} rule
  10386.              * @return rule source as {String}
  10387.              */
  10388.             var generateSource = function(rule) {
  10389.                 if (!rule || !("name" in rule)) {
  10390.                     return "";
  10391.                 }
  10392.                 return "net.csslint." + rule.name.replace(/\s/g, "");
  10393.             };
  10394.  
  10395.  
  10396.             if (messages.length > 0) {
  10397.                 output.push("<file name=\""+filename+"\">");
  10398.                 CSSLint.Util.forEach(messages, function (message) {
  10399.                     // ignore rollups for now
  10400.                     if (!message.rollup) {
  10401.                         output.push("<error line=\"" + message.line + "\" column=\"" + message.col + "\" severity=\"" + message.type + "\"" +
  10402.                           " message=\"" + xmlEscape(message.message) + "\" source=\"" + generateSource(message.rule) +"\"/>");
  10403.                     }
  10404.                 });
  10405.                 output.push("</file>");
  10406.             }
  10407.  
  10408.             return output.join("");
  10409.         }
  10410.     });
  10411.  
  10412. }());
  10413.  
  10414. CSSLint.addFormatter({
  10415.     // format information
  10416.     id: "compact",
  10417.     name: "Compact, 'porcelain' format",
  10418.  
  10419.     /**
  10420.      * Return content to be printed before all file results.
  10421.      * @return {String} to prepend before all results
  10422.      */
  10423.     startFormat: function() {
  10424.         "use strict";
  10425.         return "";
  10426.     },
  10427.  
  10428.     /**
  10429.      * Return content to be printed after all file results.
  10430.      * @return {String} to append after all results
  10431.      */
  10432.     endFormat: function() {
  10433.         "use strict";
  10434.         return "";
  10435.     },
  10436.  
  10437.     /**
  10438.      * Given CSS Lint results for a file, return output for this format.
  10439.      * @param results {Object} with error and warning messages
  10440.      * @param filename {String} relative file path
  10441.      * @param options {Object} (Optional) specifies special handling of output
  10442.      * @return {String} output for results
  10443.      */
  10444.     formatResults: function(results, filename, options) {
  10445.         "use strict";
  10446.         var messages = results.messages,
  10447.             output = "";
  10448.         options = options || {};
  10449.  
  10450.         /**
  10451.          * Capitalize and return given string.
  10452.          * @param str {String} to capitalize
  10453.          * @return {String} capitalized
  10454.          */
  10455.         var capitalize = function(str) {
  10456.             return str.charAt(0).toUpperCase() + str.slice(1);
  10457.         };
  10458.  
  10459.         if (messages.length === 0) {
  10460.             return options.quiet ? "" : filename + ": Lint Free!";
  10461.         }
  10462.  
  10463.         CSSLint.Util.forEach(messages, function(message) {
  10464.             if (message.rollup) {
  10465.                 output += filename + ": " + capitalize(message.type) + " - " + message.message + " (" + message.rule.id + ")\n";
  10466.             } else {
  10467.                 output += filename + ": line " + message.line +
  10468.                     ", col " + message.col + ", " + capitalize(message.type) + " - " + message.message + " (" + message.rule.id + ")\n";
  10469.             }
  10470.         });
  10471.  
  10472.         return output;
  10473.     }
  10474. });
  10475.  
  10476. CSSLint.addFormatter({
  10477.     // format information
  10478.     id: "csslint-xml",
  10479.     name: "CSSLint XML format",
  10480.  
  10481.     /**
  10482.      * Return opening root XML tag.
  10483.      * @return {String} to prepend before all results
  10484.      */
  10485.     startFormat: function() {
  10486.         "use strict";
  10487.         return "<?xml version=\"1.0\" encoding=\"utf-8\"?><csslint>";
  10488.     },
  10489.  
  10490.     /**
  10491.      * Return closing root XML tag.
  10492.      * @return {String} to append after all results
  10493.      */
  10494.     endFormat: function() {
  10495.         "use strict";
  10496.         return "</csslint>";
  10497.     },
  10498.  
  10499.     /**
  10500.      * Given CSS Lint results for a file, return output for this format.
  10501.      * @param results {Object} with error and warning messages
  10502.      * @param filename {String} relative file path
  10503.      * @param options {Object} (UNUSED for now) specifies special handling of output
  10504.      * @return {String} output for results
  10505.      */
  10506.     formatResults: function(results, filename/*, options*/) {
  10507.         "use strict";
  10508.         var messages = results.messages,
  10509.             output = [];
  10510.  
  10511.         /**
  10512.          * Replace special characters before write to output.
  10513.          *
  10514.          * Rules:
  10515.          *  - single quotes is the escape sequence for double-quotes
  10516.          *  - & is the escape sequence for &
  10517.          *  - < is the escape sequence for <
  10518.          *  - > is the escape sequence for >
  10519.          *
  10520.          * @param {String} message to escape
  10521.          * @return escaped message as {String}
  10522.          */
  10523.         var escapeSpecialCharacters = function(str) {
  10524.             if (!str || str.constructor !== String) {
  10525.                 return "";
  10526.             }
  10527.             return str.replace(/"/g, "'").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
  10528.         };
  10529.  
  10530.         if (messages.length > 0) {
  10531.             output.push("<file name=\""+filename+"\">");
  10532.             CSSLint.Util.forEach(messages, function (message) {
  10533.                 if (message.rollup) {
  10534.                     output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
  10535.                 } else {
  10536.                     output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" +
  10537.                         " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
  10538.                 }
  10539.             });
  10540.             output.push("</file>");
  10541.         }
  10542.  
  10543.         return output.join("");
  10544.     }
  10545. });
  10546.  
  10547. /* globals JSON: true */
  10548.  
  10549. CSSLint.addFormatter({
  10550.     // format information
  10551.     id: "json",
  10552.     name: "JSON",
  10553.  
  10554.     /**
  10555.      * Return content to be printed before all file results.
  10556.      * @return {String} to prepend before all results
  10557.      */
  10558.     startFormat: function() {
  10559.         "use strict";
  10560.         this.json = [];
  10561.         return "";
  10562.     },
  10563.  
  10564.     /**
  10565.      * Return content to be printed after all file results.
  10566.      * @return {String} to append after all results
  10567.      */
  10568.     endFormat: function() {
  10569.         "use strict";
  10570.         var ret = "";
  10571.         if (this.json.length > 0) {
  10572.             if (this.json.length === 1) {
  10573.                 ret = JSON.stringify(this.json[0]);
  10574.             } else {
  10575.                 ret = JSON.stringify(this.json);
  10576.             }
  10577.         }
  10578.         return ret;
  10579.     },
  10580.  
  10581.     /**
  10582.      * Given CSS Lint results for a file, return output for this format.
  10583.      * @param results {Object} with error and warning messages
  10584.      * @param filename {String} relative file path (Unused)
  10585.      * @return {String} output for results
  10586.      */
  10587.     formatResults: function(results, filename, options) {
  10588.         "use strict";
  10589.         if (results.messages.length > 0 || !options.quiet) {
  10590.             this.json.push({
  10591.                 filename: filename,
  10592.                 messages: results.messages,
  10593.                 stats: results.stats
  10594.             });
  10595.         }
  10596.         return "";
  10597.     }
  10598. });
  10599.  
  10600. CSSLint.addFormatter({
  10601.     // format information
  10602.     id: "junit-xml",
  10603.     name: "JUNIT XML format",
  10604.  
  10605.     /**
  10606.      * Return opening root XML tag.
  10607.      * @return {String} to prepend before all results
  10608.      */
  10609.     startFormat: function() {
  10610.         "use strict";
  10611.         return "<?xml version=\"1.0\" encoding=\"utf-8\"?><testsuites>";
  10612.     },
  10613.  
  10614.     /**
  10615.      * Return closing root XML tag.
  10616.      * @return {String} to append after all results
  10617.      */
  10618.     endFormat: function() {
  10619.         "use strict";
  10620.         return "</testsuites>";
  10621.     },
  10622.  
  10623.     /**
  10624.      * Given CSS Lint results for a file, return output for this format.
  10625.      * @param results {Object} with error and warning messages
  10626.      * @param filename {String} relative file path
  10627.      * @param options {Object} (UNUSED for now) specifies special handling of output
  10628.      * @return {String} output for results
  10629.      */
  10630.     formatResults: function(results, filename/*, options*/) {
  10631.         "use strict";
  10632.  
  10633.         var messages = results.messages,
  10634.             output = [],
  10635.             tests = {
  10636.                 "error": 0,
  10637.                 "failure": 0
  10638.             };
  10639.  
  10640.         /**
  10641.          * Generate a source string for a rule.
  10642.          * JUNIT source strings usually resemble Java class names e.g
  10643.          * net.csslint.SomeRuleName
  10644.          * @param {Object} rule
  10645.          * @return rule source as {String}
  10646.          */
  10647.         var generateSource = function(rule) {
  10648.             if (!rule || !("name" in rule)) {
  10649.                 return "";
  10650.             }
  10651.             return "net.csslint." + rule.name.replace(/\s/g, "");
  10652.         };
  10653.  
  10654.         /**
  10655.          * Replace special characters before write to output.
  10656.          *
  10657.          * Rules:
  10658.          *  - single quotes is the escape sequence for double-quotes
  10659.          *  - < is the escape sequence for <
  10660.          *  - > is the escape sequence for >
  10661.          *
  10662.          * @param {String} message to escape
  10663.          * @return escaped message as {String}
  10664.          */
  10665.         var escapeSpecialCharacters = function(str) {
  10666.  
  10667.             if (!str || str.constructor !== String) {
  10668.                 return "";
  10669.             }
  10670.  
  10671.             return str.replace(/"/g, "'").replace(/</g, "<").replace(/>/g, ">");
  10672.  
  10673.         };
  10674.  
  10675.         if (messages.length > 0) {
  10676.  
  10677.             messages.forEach(function (message) {
  10678.  
  10679.                 // since junit has no warning class
  10680.                 // all issues as errors
  10681.                 var type = message.type === "warning" ? "error" : message.type;
  10682.  
  10683.                 // ignore rollups for now
  10684.                 if (!message.rollup) {
  10685.  
  10686.                     // build the test case separately, once joined
  10687.                     // we'll add it to a custom array filtered by type
  10688.                     output.push("<testcase time=\"0\" name=\"" + generateSource(message.rule) + "\">");
  10689.                     output.push("<" + type + " message=\"" + escapeSpecialCharacters(message.message) + "\"><![CDATA[" + message.line + ":" + message.col + ":" + escapeSpecialCharacters(message.evidence) + "]]></" + type + ">");
  10690.                     output.push("</testcase>");
  10691.  
  10692.                     tests[type] += 1;
  10693.  
  10694.                 }
  10695.  
  10696.             });
  10697.  
  10698.             output.unshift("<testsuite time=\"0\" tests=\"" + messages.length + "\" skipped=\"0\" errors=\"" + tests.error + "\" failures=\"" + tests.failure + "\" package=\"net.csslint\" name=\"" + filename + "\">");
  10699.             output.push("</testsuite>");
  10700.  
  10701.         }
  10702.  
  10703.         return output.join("");
  10704.  
  10705.     }
  10706. });
  10707.  
  10708. CSSLint.addFormatter({
  10709.     // format information
  10710.     id: "lint-xml",
  10711.     name: "Lint XML format",
  10712.  
  10713.     /**
  10714.      * Return opening root XML tag.
  10715.      * @return {String} to prepend before all results
  10716.      */
  10717.     startFormat: function() {
  10718.         "use strict";
  10719.         return "<?xml version=\"1.0\" encoding=\"utf-8\"?><lint>";
  10720.     },
  10721.  
  10722.     /**
  10723.      * Return closing root XML tag.
  10724.      * @return {String} to append after all results
  10725.      */
  10726.     endFormat: function() {
  10727.         "use strict";
  10728.         return "</lint>";
  10729.     },
  10730.  
  10731.     /**
  10732.      * Given CSS Lint results for a file, return output for this format.
  10733.      * @param results {Object} with error and warning messages
  10734.      * @param filename {String} relative file path
  10735.      * @param options {Object} (UNUSED for now) specifies special handling of output
  10736.      * @return {String} output for results
  10737.      */
  10738.     formatResults: function(results, filename/*, options*/) {
  10739.         "use strict";
  10740.         var messages = results.messages,
  10741.             output = [];
  10742.  
  10743.         /**
  10744.          * Replace special characters before write to output.
  10745.          *
  10746.          * Rules:
  10747.          *  - single quotes is the escape sequence for double-quotes
  10748.          *  - & is the escape sequence for &
  10749.          *  - < is the escape sequence for <
  10750.          *  - > is the escape sequence for >
  10751.          *
  10752.          * @param {String} message to escape
  10753.          * @return escaped message as {String}
  10754.          */
  10755.         var escapeSpecialCharacters = function(str) {
  10756.             if (!str || str.constructor !== String) {
  10757.                 return "";
  10758.             }
  10759.             return str.replace(/"/g, "'").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
  10760.         };
  10761.  
  10762.         if (messages.length > 0) {
  10763.  
  10764.             output.push("<file name=\""+filename+"\">");
  10765.             CSSLint.Util.forEach(messages, function (message) {
  10766.                 if (message.rollup) {
  10767.                     output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
  10768.                 } else {
  10769.                     var rule = "";
  10770.                     if (message.rule && message.rule.id) {
  10771.                         rule = "rule=\"" + escapeSpecialCharacters(message.rule.id) + "\" ";
  10772.                     }
  10773.                     output.push("<issue " + rule + "line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" +
  10774.                         " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
  10775.                 }
  10776.             });
  10777.             output.push("</file>");
  10778.         }
  10779.  
  10780.         return output.join("");
  10781.     }
  10782. });
  10783.  
  10784. CSSLint.addFormatter({
  10785.     // format information
  10786.     id: "text",
  10787.     name: "Plain Text",
  10788.  
  10789.     /**
  10790.      * Return content to be printed before all file results.
  10791.      * @return {String} to prepend before all results
  10792.      */
  10793.     startFormat: function() {
  10794.         "use strict";
  10795.         return "";
  10796.     },
  10797.  
  10798.     /**
  10799.      * Return content to be printed after all file results.
  10800.      * @return {String} to append after all results
  10801.      */
  10802.     endFormat: function() {
  10803.         "use strict";
  10804.         return "";
  10805.     },
  10806.  
  10807.     /**
  10808.      * Given CSS Lint results for a file, return output for this format.
  10809.      * @param results {Object} with error and warning messages
  10810.      * @param filename {String} relative file path
  10811.      * @param options {Object} (Optional) specifies special handling of output
  10812.      * @return {String} output for results
  10813.      */
  10814.     formatResults: function(results, filename, options) {
  10815.         "use strict";
  10816.         var messages = results.messages,
  10817.             output = "";
  10818.         options = options || {};
  10819.  
  10820.         if (messages.length === 0) {
  10821.             return options.quiet ? "" : "\n\ncsslint: No errors in " + filename + ".";
  10822.         }
  10823.  
  10824.         output = "\n\ncsslint: There ";
  10825.         if (messages.length === 1) {
  10826.             output += "is 1 problem";
  10827.         } else {
  10828.             output += "are " + messages.length + " problems";
  10829.         }
  10830.         output += " in " + filename + ".";
  10831.  
  10832.         var pos = filename.lastIndexOf("/"),
  10833.             shortFilename = filename;
  10834.  
  10835.         if (pos === -1) {
  10836.             pos = filename.lastIndexOf("\\");
  10837.         }
  10838.         if (pos > -1) {
  10839.             shortFilename = filename.substring(pos+1);
  10840.         }
  10841.  
  10842.         CSSLint.Util.forEach(messages, function (message, i) {
  10843.             output = output + "\n\n" + shortFilename;
  10844.             if (message.rollup) {
  10845.                 output += "\n" + (i+1) + ": " + message.type;
  10846.                 output += "\n" + message.message;
  10847.             } else {
  10848.                 output += "\n" + (i+1) + ": " + message.type + " at line " + message.line + ", col " + message.col;
  10849.                 output += "\n" + message.message;
  10850.                 output += "\n" + message.evidence;
  10851.             }
  10852.         });
  10853.  
  10854.         return output;
  10855.     }
  10856. });
  10857.  
  10858. return CSSLint;
  10859. })();