“no use strict”; ;(function(window) { if (typeof window.window != “undefined” && window.document) {

return;

}

window.console = function() {

var msgs = Array.prototype.slice.call(arguments, 0);
postMessage({type: "log", data: msgs});

}; window.console.error = window.console.warn = window.console.log = window.console.trace = window.console;

window.window = window; window.ace = window;

window.onerror = function(message, file, line, col, err) {

postMessage({type: "error", data: {
    message: message,
    file: file,
    line: line, 
    col: col,
    stack: err.stack
}});

};

window.normalizeModule = function(parentId, moduleName) {

// normalize plugin requires
if (moduleName.indexOf("!") !== -1) {
    var chunks = moduleName.split("!");
    return window.normalizeModule(parentId, chunks[0]) + "!" + window.normalizeModule(parentId, chunks[1]);
}
// normalize relative requires
if (moduleName.charAt(0) == ".") {
    var base = parentId.split("/").slice(0, -1).join("/");
    moduleName = (base ? base + "/" : "") + moduleName;

    while(moduleName.indexOf(".") !== -1 && previous != moduleName) {
        var previous = moduleName;
        moduleName = moduleName.replace(/^\.\//, "").replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, "");
    }
}

return moduleName;

};

window.require = function(parentId, id) {

if (!id) {
    id = parentId;
    parentId = null;
}
if (!id.charAt)
    throw new Error("worker.js require() accepts only (parentId, id) as arguments");

id = window.normalizeModule(parentId, id);

var module = window.require.modules[id];
if (module) {
    if (!module.initialized) {
        module.initialized = true;
        module.exports = module.factory().exports;
    }
    return module.exports;
}

var chunks = id.split("/");
if (!window.require.tlns)
    return console.log("unable to load " + id);
chunks[0] = window.require.tlns[chunks[0]] || chunks[0];
var path = chunks.join("/") + ".js";

window.require.id = id;
importScripts(path);
return window.require(parentId, id);

}; window.require.modules = {}; window.require.tlns = {};

window.define = function(id, deps, factory) {

if (arguments.length == 2) {
    factory = deps;
    if (typeof id != "string") {
        deps = id;
        id = window.require.id;
    }
} else if (arguments.length == 1) {
    factory = id;
    deps = [];
    id = window.require.id;
}

if (typeof factory != "function") {
    window.require.modules[id] = {
        exports: factory,
        initialized: true
    };
    return;
}

if (!deps.length)
    // If there is no dependencies, we inject 'require', 'exports' and
    // 'module' as dependencies, to provide CommonJS compatibility.
    deps = ['require', 'exports', 'module'];

var req = function(childId) {
    return window.require(id, childId);
};

window.require.modules[id] = {
    exports: {},
    factory: function() {
        var module = this;
        var returnExports = factory.apply(this, deps.map(function(dep) {
          switch(dep) {
              // Because 'require', 'exports' and 'module' aren't actual
              // dependencies, we must handle them seperately.
              case 'require': return req;
              case 'exports': return module.exports;
              case 'module':  return module;
              // But for all other dependencies, we can just go ahead and
              // require them.
              default:        return req(dep);
          }
        }));
        if (returnExports)
            module.exports = returnExports;
        return module;
    }
};

}; window.define.amd = {};

window.initBaseUrls = function initBaseUrls(topLevelNamespaces) {

require.tlns = topLevelNamespaces;

};

window.initSender = function initSender() {

var EventEmitter = window.require("ace/lib/event_emitter").EventEmitter;
var oop = window.require("ace/lib/oop");

var Sender = function() {};

(function() {

    oop.implement(this, EventEmitter);

    this.callback = function(data, callbackId) {
        postMessage({
            type: "call",
            id: callbackId,
            data: data
        });
    };

    this.emit = function(name, data) {
        postMessage({
            type: "event",
            name: name,
            data: data
        });
    };

}).call(Sender.prototype);

return new Sender();

};

var main = window.main = null; var sender = window.sender = null;

window.onmessage = function(e) {

var msg = e.data;
if (msg.command) {
    if (main[msg.command])
        main[msg.command].apply(main, msg.args);
    else
        throw new Error("Unknown command:" + msg.command);
}
else if (msg.init) {        
    initBaseUrls(msg.tlns);
    require("ace/lib/es5-shim");
    sender = window.sender = initSender();
    var clazz = require(msg.module)[msg.classname];
    main = window.main = new clazz(sender);
} 
else if (msg.event && sender) {
    sender._signal(msg.event, msg.data);
}

}; })(this);

ace.define(“ace/lib/oop”,, function(require, exports, module) { “use strict”;

exports.inherits = function(ctor, superCtor) {

ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
    constructor: {
        value: ctor,
        enumerable: false,
        writable: true,
        configurable: true
    }
});

};

exports.mixin = function(obj, mixin) {

for (var key in mixin) {
    obj[key] = mixin[key];
}
return obj;

};

exports.implement = function(proto, mixin) {

exports.mixin(proto, mixin);

};

});

ace.define(“ace/lib/lang”,, function(require, exports, module) { “use strict”;

exports.last = function(a) {

return a[a.length - 1];

};

exports.stringReverse = function(string) {

return string.split("").reverse().join("");

};

exports.stringRepeat = function (string, count) {

var result = '';
while (count > 0) {
    if (count & 1)
        result += string;

    if (count >>= 1)
        string += string;
}
return result;

};

var trimBeginRegexp = /^ss*/; var trimEndRegexp = /ss*$/;

exports.stringTrimLeft = function (string) {

return string.replace(trimBeginRegexp, '');

};

exports.stringTrimRight = function (string) {

return string.replace(trimEndRegexp, '');

};

exports.copyObject = function(obj) {

var copy = {};
for (var key in obj) {
    copy[key] = obj[key];
}
return copy;

};

exports.copyArray = function(array){

var copy = [];
for (var i=0, l=array.length; i<l; i++) {
    if (array[i] && typeof array[i] == "object")
        copy[i] = this.copyObject( array[i] );
    else 
        copy[i] = array[i];
}
return copy;

};

exports.deepCopy = function (obj) {

if (typeof obj !== "object" || !obj)
    return obj;
var cons = obj.constructor;
if (cons === RegExp)
    return obj;

var copy = cons();
for (var key in obj) {
    if (typeof obj[key] === "object") {
        copy[key] = exports.deepCopy(obj[key]);
    } else {
        copy[key] = obj[key];
    }
}
return copy;

};

exports.arrayToMap = function(arr) {

var map = {};
for (var i=0; i<arr.length; i++) {
    map[arr[i]] = 1;
}
return map;

};

exports.createMap = function(props) {

var map = Object.create(null);
for (var i in props) {
    map[i] = props[i];
}
return map;

}; exports.arrayRemove = function(array, value) {

for (var i = 0; i <= array.length; i++) {
  if (value === array[i]) {
    array.splice(i, 1);
  }
}

};

exports.escapeRegExp = function(str) {

return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');

};

exports.escapeHTML = function(str) {

return str.replace(/&/g, "&#38;").replace(/"/g, "&#34;").replace(/'/g, "&#39;").replace(/</g, "&#60;");

};

exports.getMatchOffsets = function(string, regExp) {

var matches = [];

string.replace(regExp, function(str) {
    matches.push({
        offset: arguments[arguments.length-2],
        length: str.length
    });
});

return matches;

}; exports.deferredCall = function(fcn) {

var timer = null;
var callback = function() {
    timer = null;
    fcn();
};

var deferred = function(timeout) {
    deferred.cancel();
    timer = setTimeout(callback, timeout || 0);
    return deferred;
};

deferred.schedule = deferred;

deferred.call = function() {
    this.cancel();
    fcn();
    return deferred;
};

deferred.cancel = function() {
    clearTimeout(timer);
    timer = null;
    return deferred;
};

deferred.isPending = function() {
    return timer;
};

return deferred;

};

exports.delayedCall = function(fcn, defaultTimeout) {

var timer = null;
var callback = function() {
    timer = null;
    fcn();
};

var _self = function(timeout) {
    if (timer == null)
        timer = setTimeout(callback, timeout || defaultTimeout);
};

_self.delay = function(timeout) {
    timer && clearTimeout(timer);
    timer = setTimeout(callback, timeout || defaultTimeout);
};
_self.schedule = _self;

_self.call = function() {
    this.cancel();
    fcn();
};

_self.cancel = function() {
    timer && clearTimeout(timer);
    timer = null;
};

_self.isPending = function() {
    return timer;
};

return _self;

}; });

ace.define(“ace/lib/event_emitter”,, function(require, exports, module) { “use strict”;

var EventEmitter = {}; var stopPropagation = function() { this.propagationStopped = true; }; var preventDefault = function() { this.defaultPrevented = true; };

EventEmitter._emit = EventEmitter._dispatchEvent = function(eventName, e) {

this._eventRegistry || (this._eventRegistry = {});
this._defaultHandlers || (this._defaultHandlers = {});

var listeners = this._eventRegistry[eventName] || [];
var defaultHandler = this._defaultHandlers[eventName];
if (!listeners.length && !defaultHandler)
    return;

if (typeof e != "object" || !e)
    e = {};

if (!e.type)
    e.type = eventName;
if (!e.stopPropagation)
    e.stopPropagation = stopPropagation;
if (!e.preventDefault)
    e.preventDefault = preventDefault;

listeners = listeners.slice();
for (var i=0; i<listeners.length; i++) {
    listeners[i](e, this);
    if (e.propagationStopped)
        break;
}

if (defaultHandler && !e.defaultPrevented)
    return defaultHandler(e, this);

};

EventEmitter._signal = function(eventName, e) {

var listeners = (this._eventRegistry || {})[eventName];
if (!listeners)
    return;
listeners = listeners.slice();
for (var i=0; i<listeners.length; i++)
    listeners[i](e, this);

};

EventEmitter.once = function(eventName, callback) {

var _self = this;
callback && this.addEventListener(eventName, function newCallback() {
    _self.removeEventListener(eventName, newCallback);
    callback.apply(null, arguments);
});

};

EventEmitter.setDefaultHandler = function(eventName, callback) {

var handlers = this._defaultHandlers
if (!handlers)
    handlers = this._defaultHandlers = {_disabled_: {}};

if (handlers[eventName]) {
    var old = handlers[eventName];
    var disabled = handlers._disabled_[eventName];
    if (!disabled)
        handlers._disabled_[eventName] = disabled = [];
    disabled.push(old);
    var i = disabled.indexOf(callback);
    if (i != -1) 
        disabled.splice(i, 1);
}
handlers[eventName] = callback;

}; EventEmitter.removeDefaultHandler = function(eventName, callback) {

var handlers = this._defaultHandlers
if (!handlers)
    return;
var disabled = handlers._disabled_[eventName];

if (handlers[eventName] == callback) {
    var old = handlers[eventName];
    if (disabled)
        this.setDefaultHandler(eventName, disabled.pop());
} else if (disabled) {
    var i = disabled.indexOf(callback);
    if (i != -1)
        disabled.splice(i, 1);
}

};

EventEmitter.on = EventEmitter.addEventListener = function(eventName, callback, capturing) {

this._eventRegistry = this._eventRegistry || {};

var listeners = this._eventRegistry[eventName];
if (!listeners)
    listeners = this._eventRegistry[eventName] = [];

if (listeners.indexOf(callback) == -1)
    listeners[capturing ? "unshift" : "push"](callback);
return callback;

};

EventEmitter.off = EventEmitter.removeListener = EventEmitter.removeEventListener = function(eventName, callback) {

this._eventRegistry = this._eventRegistry || {};

var listeners = this._eventRegistry[eventName];
if (!listeners)
    return;

var index = listeners.indexOf(callback);
if (index !== -1)
    listeners.splice(index, 1);

};

EventEmitter.removeAllListeners = function(eventName) {

if (this._eventRegistry) this._eventRegistry[eventName] = [];

};

exports.EventEmitter = EventEmitter;

});

ace.define(“ace/range”,, function(require, exports, module) { “use strict”; var comparePoints = function(p1, p2) {

return p1.row - p2.row || p1.column - p2.column;

}; var Range = function(startRow, startColumn, endRow, endColumn) {

this.start = {
    row: startRow,
    column: startColumn
};

this.end = {
    row: endRow,
    column: endColumn
};

};

(function() {

this.isEqual = function(range) {
    return this.start.row === range.start.row &&
        this.end.row === range.end.row &&
        this.start.column === range.start.column &&
        this.end.column === range.end.column;
};
this.toString = function() {
    return ("Range: [" + this.start.row + "/" + this.start.column +
        "] -> [" + this.end.row + "/" + this.end.column + "]");
};

this.contains = function(row, column) {
    return this.compare(row, column) == 0;
};
this.compareRange = function(range) {
    var cmp,
        end = range.end,
        start = range.start;

    cmp = this.compare(end.row, end.column);
    if (cmp == 1) {
        cmp = this.compare(start.row, start.column);
        if (cmp == 1) {
            return 2;
        } else if (cmp == 0) {
            return 1;
        } else {
            return 0;
        }
    } else if (cmp == -1) {
        return -2;
    } else {
        cmp = this.compare(start.row, start.column);
        if (cmp == -1) {
            return -1;
        } else if (cmp == 1) {
            return 42;
        } else {
            return 0;
        }
    }
};
this.comparePoint = function(p) {
    return this.compare(p.row, p.column);
};
this.containsRange = function(range) {
    return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0;
};
this.intersects = function(range) {
    var cmp = this.compareRange(range);
    return (cmp == -1 || cmp == 0 || cmp == 1);
};
this.isEnd = function(row, column) {
    return this.end.row == row && this.end.column == column;
};
this.isStart = function(row, column) {
    return this.start.row == row && this.start.column == column;
};
this.setStart = function(row, column) {
    if (typeof row == "object") {
        this.start.column = row.column;
        this.start.row = row.row;
    } else {
        this.start.row = row;
        this.start.column = column;
    }
};
this.setEnd = function(row, column) {
    if (typeof row == "object") {
        this.end.column = row.column;
        this.end.row = row.row;
    } else {
        this.end.row = row;
        this.end.column = column;
    }
};
this.inside = function(row, column) {
    if (this.compare(row, column) == 0) {
        if (this.isEnd(row, column) || this.isStart(row, column)) {
            return false;
        } else {
            return true;
        }
    }
    return false;
};
this.insideStart = function(row, column) {
    if (this.compare(row, column) == 0) {
        if (this.isEnd(row, column)) {
            return false;
        } else {
            return true;
        }
    }
    return false;
};
this.insideEnd = function(row, column) {
    if (this.compare(row, column) == 0) {
        if (this.isStart(row, column)) {
            return false;
        } else {
            return true;
        }
    }
    return false;
};
this.compare = function(row, column) {
    if (!this.isMultiLine()) {
        if (row === this.start.row) {
            return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0);
        };
    }

    if (row < this.start.row)
        return -1;

    if (row > this.end.row)
        return 1;

    if (this.start.row === row)
        return column >= this.start.column ? 0 : -1;

    if (this.end.row === row)
        return column <= this.end.column ? 0 : 1;

    return 0;
};
this.compareStart = function(row, column) {
    if (this.start.row == row && this.start.column == column) {
        return -1;
    } else {
        return this.compare(row, column);
    }
};
this.compareEnd = function(row, column) {
    if (this.end.row == row && this.end.column == column) {
        return 1;
    } else {
        return this.compare(row, column);
    }
};
this.compareInside = function(row, column) {
    if (this.end.row == row && this.end.column == column) {
        return 1;
    } else if (this.start.row == row && this.start.column == column) {
        return -1;
    } else {
        return this.compare(row, column);
    }
};
this.clipRows = function(firstRow, lastRow) {
    if (this.end.row > lastRow)
        var end = {row: lastRow + 1, column: 0};
    else if (this.end.row < firstRow)
        var end = {row: firstRow, column: 0};

    if (this.start.row > lastRow)
        var start = {row: lastRow + 1, column: 0};
    else if (this.start.row < firstRow)
        var start = {row: firstRow, column: 0};

    return Range.fromPoints(start || this.start, end || this.end);
};
this.extend = function(row, column) {
    var cmp = this.compare(row, column);

    if (cmp == 0)
        return this;
    else if (cmp == -1)
        var start = {row: row, column: column};
    else
        var end = {row: row, column: column};

    return Range.fromPoints(start || this.start, end || this.end);
};

this.isEmpty = function() {
    return (this.start.row === this.end.row && this.start.column === this.end.column);
};
this.isMultiLine = function() {
    return (this.start.row !== this.end.row);
};
this.clone = function() {
    return Range.fromPoints(this.start, this.end);
};
this.collapseRows = function() {
    if (this.end.column == 0)
        return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0)
    else
        return new Range(this.start.row, 0, this.end.row, 0)
};
this.toScreenRange = function(session) {
    var screenPosStart = session.documentToScreenPosition(this.start);
    var screenPosEnd = session.documentToScreenPosition(this.end);

    return new Range(
        screenPosStart.row, screenPosStart.column,
        screenPosEnd.row, screenPosEnd.column
    );
};
this.moveBy = function(row, column) {
    this.start.row += row;
    this.start.column += column;
    this.end.row += row;
    this.end.column += column;
};

}).call(Range.prototype); Range.fromPoints = function(start, end) {

return new Range(start.row, start.column, end.row, end.column);

}; Range.comparePoints = comparePoints;

Range.comparePoints = function(p1, p2) {

return p1.row - p2.row || p1.column - p2.column;

};

exports.Range = Range; });

ace.define(“ace/anchor”,, function(require, exports, module) { “use strict”;

var oop = require(“./lib/oop”); var EventEmitter = require(“./lib/event_emitter”).EventEmitter;

var Anchor = exports.Anchor = function(doc, row, column) {

this.$onChange = this.onChange.bind(this);
this.attach(doc);

if (typeof column == "undefined")
    this.setPosition(row.row, row.column);
else
    this.setPosition(row, column);

};

(function() {

oop.implement(this, EventEmitter);
this.getPosition = function() {
    return this.$clipPositionToDocument(this.row, this.column);
};
this.getDocument = function() {
    return this.document;
};
this.$insertRight = false;
this.onChange = function(e) {
    var delta = e.data;
    var range = delta.range;

    if (range.start.row == range.end.row && range.start.row != this.row)
        return;

    if (range.start.row > this.row)
        return;

    if (range.start.row == this.row && range.start.column > this.column)
        return;

    var row = this.row;
    var column = this.column;
    var start = range.start;
    var end = range.end;

    if (delta.action === "insertText") {
        if (start.row === row && start.column <= column) {
            if (start.column === column && this.$insertRight) {
            } else if (start.row === end.row) {
                column += end.column - start.column;
            } else {
                column -= start.column;
                row += end.row - start.row;
            }
        } else if (start.row !== end.row && start.row < row) {
            row += end.row - start.row;
        }
    } else if (delta.action === "insertLines") {
        if (start.row === row && column === 0 && this.$insertRight) {
        }
        else if (start.row <= row) {
            row += end.row - start.row;
        }
    } else if (delta.action === "removeText") {
        if (start.row === row && start.column < column) {
            if (end.column >= column)
                column = start.column;
            else
                column = Math.max(0, column - (end.column - start.column));

        } else if (start.row !== end.row && start.row < row) {
            if (end.row === row)
                column = Math.max(0, column - end.column) + start.column;
            row -= (end.row - start.row);
        } else if (end.row === row) {
            row -= end.row - start.row;
            column = Math.max(0, column - end.column) + start.column;
        }
    } else if (delta.action == "removeLines") {
        if (start.row <= row) {
            if (end.row <= row)
                row -= end.row - start.row;
            else {
                row = start.row;
                column = 0;
            }
        }
    }

    this.setPosition(row, column, true);
};
this.setPosition = function(row, column, noClip) {
    var pos;
    if (noClip) {
        pos = {
            row: row,
            column: column
        };
    } else {
        pos = this.$clipPositionToDocument(row, column);
    }

    if (this.row == pos.row && this.column == pos.column)
        return;

    var old = {
        row: this.row,
        column: this.column
    };

    this.row = pos.row;
    this.column = pos.column;
    this._signal("change", {
        old: old,
        value: pos
    });
};
this.detach = function() {
    this.document.removeEventListener("change", this.$onChange);
};
this.attach = function(doc) {
    this.document = doc || this.document;
    this.document.on("change", this.$onChange);
};
this.$clipPositionToDocument = function(row, column) {
    var pos = {};

    if (row >= this.document.getLength()) {
        pos.row = Math.max(0, this.document.getLength() - 1);
        pos.column = this.document.getLine(pos.row).length;
    }
    else if (row < 0) {
        pos.row = 0;
        pos.column = 0;
    }
    else {
        pos.row = row;
        pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column));
    }

    if (column < 0)
        pos.column = 0;

    return pos;
};

}).call(Anchor.prototype);

});

ace.define(“ace/document”,, function(require, exports, module) { “use strict”;

var oop = require(“./lib/oop”); var EventEmitter = require(“./lib/event_emitter”).EventEmitter; var Range = require(“./range”).Range; var Anchor = require(“./anchor”).Anchor;

var Document = function(text) {

this.$lines = [];
if (text.length === 0) {
    this.$lines = [""];
} else if (Array.isArray(text)) {
    this._insertLines(0, text);
} else {
    this.insert({row: 0, column:0}, text);
}

};

(function() {

oop.implement(this, EventEmitter);
this.setValue = function(text) {
    var len = this.getLength();
    this.remove(new Range(0, 0, len, this.getLine(len-1).length));
    this.insert({row: 0, column:0}, text);
};
this.getValue = function() {
    return this.getAllLines().join(this.getNewLineCharacter());
};
this.createAnchor = function(row, column) {
    return new Anchor(this, row, column);
};
if ("aaa".split(/a/).length === 0)
    this.$split = function(text) {
        return text.replace(/\r\n|\r/g, "\n").split("\n");
    };
else
    this.$split = function(text) {
        return text.split(/\r\n|\r|\n/);
    };

this.$detectNewLine = function(text) {
    var match = text.match(/^.*?(\r\n|\r|\n)/m);
    this.$autoNewLine = match ? match[1] : "\n";
    this._signal("changeNewLineMode");
};
this.getNewLineCharacter = function() {
    switch (this.$newLineMode) {
      case "windows":
        return "\r\n";
      case "unix":
        return "\n";
      default:
        return this.$autoNewLine || "\n";
    }
};

this.$autoNewLine = "";
this.$newLineMode = "auto";
this.setNewLineMode = function(newLineMode) {
    if (this.$newLineMode === newLineMode)
        return;

    this.$newLineMode = newLineMode;
    this._signal("changeNewLineMode");
};
this.getNewLineMode = function() {
    return this.$newLineMode;
};
this.isNewLine = function(text) {
    return (text == "\r\n" || text == "\r" || text == "\n");
};
this.getLine = function(row) {
    return this.$lines[row] || "";
};
this.getLines = function(firstRow, lastRow) {
    return this.$lines.slice(firstRow, lastRow + 1);
};
this.getAllLines = function() {
    return this.getLines(0, this.getLength());
};
this.getLength = function() {
    return this.$lines.length;
};
this.getTextRange = function(range) {
    if (range.start.row == range.end.row) {
        return this.getLine(range.start.row)
            .substring(range.start.column, range.end.column);
    }
    var lines = this.getLines(range.start.row, range.end.row);
    lines[0] = (lines[0] || "").substring(range.start.column);
    var l = lines.length - 1;
    if (range.end.row - range.start.row == l)
        lines[l] = lines[l].substring(0, range.end.column);
    return lines.join(this.getNewLineCharacter());
};

this.$clipPosition = function(position) {
    var length = this.getLength();
    if (position.row >= length) {
        position.row = Math.max(0, length - 1);
        position.column = this.getLine(length-1).length;
    } else if (position.row < 0)
        position.row = 0;
    return position;
};
this.insert = function(position, text) {
    if (!text || text.length === 0)
        return position;

    position = this.$clipPosition(position);
    if (this.getLength() <= 1)
        this.$detectNewLine(text);

    var lines = this.$split(text);
    var firstLine = lines.splice(0, 1)[0];
    var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0];

    position = this.insertInLine(position, firstLine);
    if (lastLine !== null) {
        position = this.insertNewLine(position); // terminate first line
        position = this._insertLines(position.row, lines);
        position = this.insertInLine(position, lastLine || "");
    }
    return position;
};
this.insertLines = function(row, lines) {
    if (row >= this.getLength())
        return this.insert({row: row, column: 0}, "\n" + lines.join("\n"));
    return this._insertLines(Math.max(row, 0), lines);
};
this._insertLines = function(row, lines) {
    if (lines.length == 0)
        return {row: row, column: 0};
    while (lines.length > 0xF000) {
        var end = this._insertLines(row, lines.slice(0, 0xF000));
        lines = lines.slice(0xF000);
        row = end.row;
    }

    var args = [row, 0];
    args.push.apply(args, lines);
    this.$lines.splice.apply(this.$lines, args);

    var range = new Range(row, 0, row + lines.length, 0);
    var delta = {
        action: "insertLines",
        range: range,
        lines: lines
    };
    this._signal("change", { data: delta });
    return range.end;
};
this.insertNewLine = function(position) {
    position = this.$clipPosition(position);
    var line = this.$lines[position.row] || "";

    this.$lines[position.row] = line.substring(0, position.column);
    this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length));

    var end = {
        row : position.row + 1,
        column : 0
    };

    var delta = {
        action: "insertText",
        range: Range.fromPoints(position, end),
        text: this.getNewLineCharacter()
    };
    this._signal("change", { data: delta });

    return end;
};
this.insertInLine = function(position, text) {
    if (text.length == 0)
        return position;

    var line = this.$lines[position.row] || "";

    this.$lines[position.row] = line.substring(0, position.column) + text
            + line.substring(position.column);

    var end = {
        row : position.row,
        column : position.column + text.length
    };

    var delta = {
        action: "insertText",
        range: Range.fromPoints(position, end),
        text: text
    };
    this._signal("change", { data: delta });

    return end;
};
this.remove = function(range) {
    if (!(range instanceof Range))
        range = Range.fromPoints(range.start, range.end);
    range.start = this.$clipPosition(range.start);
    range.end = this.$clipPosition(range.end);

    if (range.isEmpty())
        return range.start;

    var firstRow = range.start.row;
    var lastRow = range.end.row;

    if (range.isMultiLine()) {
        var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1;
        var lastFullRow = lastRow - 1;

        if (range.end.column > 0)
            this.removeInLine(lastRow, 0, range.end.column);

        if (lastFullRow >= firstFullRow)
            this._removeLines(firstFullRow, lastFullRow);

        if (firstFullRow != firstRow) {
            this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length);
            this.removeNewLine(range.start.row);
        }
    }
    else {
        this.removeInLine(firstRow, range.start.column, range.end.column);
    }
    return range.start;
};
this.removeInLine = function(row, startColumn, endColumn) {
    if (startColumn == endColumn)
        return;

    var range = new Range(row, startColumn, row, endColumn);
    var line = this.getLine(row);
    var removed = line.substring(startColumn, endColumn);
    var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length);
    this.$lines.splice(row, 1, newLine);

    var delta = {
        action: "removeText",
        range: range,
        text: removed
    };
    this._signal("change", { data: delta });
    return range.start;
};
this.removeLines = function(firstRow, lastRow) {
    if (firstRow < 0 || lastRow >= this.getLength())
        return this.remove(new Range(firstRow, 0, lastRow + 1, 0));
    return this._removeLines(firstRow, lastRow);
};

this._removeLines = function(firstRow, lastRow) {
    var range = new Range(firstRow, 0, lastRow + 1, 0);
    var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1);

    var delta = {
        action: "removeLines",
        range: range,
        nl: this.getNewLineCharacter(),
        lines: removed
    };
    this._signal("change", { data: delta });
    return removed;
};
this.removeNewLine = function(row) {
    var firstLine = this.getLine(row);
    var secondLine = this.getLine(row+1);

    var range = new Range(row, firstLine.length, row+1, 0);
    var line = firstLine + secondLine;

    this.$lines.splice(row, 2, line);

    var delta = {
        action: "removeText",
        range: range,
        text: this.getNewLineCharacter()
    };
    this._signal("change", { data: delta });
};
this.replace = function(range, text) {
    if (!(range instanceof Range))
        range = Range.fromPoints(range.start, range.end);
    if (text.length == 0 && range.isEmpty())
        return range.start;
    if (text == this.getTextRange(range))
        return range.end;

    this.remove(range);
    if (text) {
        var end = this.insert(range.start, text);
    }
    else {
        end = range.start;
    }

    return end;
};
this.applyDeltas = function(deltas) {
    for (var i=0; i<deltas.length; i++) {
        var delta = deltas[i];
        var range = Range.fromPoints(delta.range.start, delta.range.end);

        if (delta.action == "insertLines")
            this.insertLines(range.start.row, delta.lines);
        else if (delta.action == "insertText")
            this.insert(range.start, delta.text);
        else if (delta.action == "removeLines")
            this._removeLines(range.start.row, range.end.row - 1);
        else if (delta.action == "removeText")
            this.remove(range);
    }
};
this.revertDeltas = function(deltas) {
    for (var i=deltas.length-1; i>=0; i--) {
        var delta = deltas[i];

        var range = Range.fromPoints(delta.range.start, delta.range.end);

        if (delta.action == "insertLines")
            this._removeLines(range.start.row, range.end.row - 1);
        else if (delta.action == "insertText")
            this.remove(range);
        else if (delta.action == "removeLines")
            this._insertLines(range.start.row, delta.lines);
        else if (delta.action == "removeText")
            this.insert(range.start, delta.text);
    }
};
this.indexToPosition = function(index, startRow) {
    var lines = this.$lines || this.getAllLines();
    var newlineLength = this.getNewLineCharacter().length;
    for (var i = startRow || 0, l = lines.length; i < l; i++) {
        index -= lines[i].length + newlineLength;
        if (index < 0)
            return {row: i, column: index + lines[i].length + newlineLength};
    }
    return {row: l-1, column: lines[l-1].length};
};
this.positionToIndex = function(pos, startRow) {
    var lines = this.$lines || this.getAllLines();
    var newlineLength = this.getNewLineCharacter().length;
    var index = 0;
    var row = Math.min(pos.row, lines.length);
    for (var i = startRow || 0; i < row; ++i)
        index += lines[i].length + newlineLength;

    return index + pos.column;
};

}).call(Document.prototype);

exports.Document = Document; });

ace.define(“ace/worker/mirror”,, function(require, exports, module) { “use strict”;

var Document = require(“../document”).Document; var lang = require(“../lib/lang”);

var Mirror = exports.Mirror = function(sender) {

this.sender = sender;
var doc = this.doc = new Document("");

var deferredUpdate = this.deferredUpdate = lang.delayedCall(this.onUpdate.bind(this));

var _self = this;
sender.on("change", function(e) {
    doc.applyDeltas(e.data);
    if (_self.$timeout)
        return deferredUpdate.schedule(_self.$timeout);
    _self.onUpdate();
});

};

(function() {

this.$timeout = 500;

this.setTimeout = function(timeout) {
    this.$timeout = timeout;
};

this.setValue = function(value) {
    this.doc.setValue(value);
    this.deferredUpdate.schedule(this.$timeout);
};

this.getValue = function(callbackId) {
    this.sender.callback(this.doc.getValue(), callbackId);
};

this.onUpdate = function() {
};

this.isPending = function() {
    return this.deferredUpdate.isPending();
};

}).call(Mirror.prototype);

});

ace.define(“ace/mode/css/csslint”,, function(require, exports, module) { var parserlib = {}; (function(){ function EventTarget(){

this._listeners = {};

}

EventTarget.prototype = {

constructor: EventTarget,
addListener: function(type, listener){
    if (!this._listeners[type]){
        this._listeners[type] = [];
    }

    this._listeners[type].push(listener);
},
fire: function(event){
    if (typeof event == "string"){
        event = { type: event };
    }
    if (typeof event.target != "undefined"){
        event.target = this;
    }

    if (typeof event.type == "undefined"){
        throw new Error("Event object missing 'type' property.");
    }

    if (this._listeners[event.type]){
        var listeners = this._listeners[event.type].concat();
        for (var i=0, len=listeners.length; i < len; i++){
            listeners[i].call(this, event);
        }
    }
},
removeListener: function(type, listener){
    if (this._listeners[type]){
        var listeners = this._listeners[type];
        for (var i=0, len=listeners.length; i < len; i++){
            if (listeners[i] === listener){
                listeners.splice(i, 1);
                break;
            }
        }

    }
}

}; function StringReader(text){

this._input = text.replace(/\n\r?/g, "\n");
this._line = 1;
this._col = 1;
this._cursor = 0;

}

StringReader.prototype = {

constructor: StringReader,
getCol: function(){
    return this._col;
},
getLine: function(){
    return this._line ;
},
eof: function(){
    return (this._cursor == this._input.length);
},
peek: function(count){
    var c = null;
    count = (typeof count == "undefined" ? 1 : count);
    if (this._cursor < this._input.length){
        c = this._input.charAt(this._cursor + count - 1);
    }

    return c;
},
read: function(){
    var c = null;
    if (this._cursor < this._input.length){
        if (this._input.charAt(this._cursor) == "\n"){
            this._line++;
            this._col=1;
        } else {
            this._col++;
        }
        c = this._input.charAt(this._cursor++);
    }

    return c;
},
mark: function(){
    this._bookmark = {
        cursor: this._cursor,
        line:   this._line,
        col:    this._col
    };
},

reset: function(){
    if (this._bookmark){
        this._cursor = this._bookmark.cursor;
        this._line = this._bookmark.line;
        this._col = this._bookmark.col;
        delete this._bookmark;
    }
},
readTo: function(pattern){

    var buffer = "",
        c;
    while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) != buffer.length - pattern.length){
        c = this.read();
        if (c){
            buffer += c;
        } else {
            throw new Error("Expected \"" + pattern + "\" at line " + this._line  + ", col " + this._col + ".");
        }
    }

    return buffer;

},
readWhile: function(filter){

    var buffer = "",
        c = this.read();

    while(c !== null && filter(c)){
        buffer += c;
        c = this.read();
    }

    return buffer;

},
readMatch: function(matcher){

    var source = this._input.substring(this._cursor),
        value = null;
    if (typeof matcher == "string"){
        if (source.indexOf(matcher) === 0){
            value = this.readCount(matcher.length);
        }
    } else if (matcher instanceof RegExp){
        if (matcher.test(source)){
            value = this.readCount(RegExp.lastMatch.length);
        }
    }

    return value;
},
readCount: function(count){
    var buffer = "";

    while(count--){
        buffer += this.read();
    }

    return buffer;
}

}; function SyntaxError(message, line, col){

this.col = col;
this.line = line;
this.message = message;

} SyntaxError.prototype = new Error(); function SyntaxUnit(text, line, col, type){

this.col = col;
this.line = line;
this.text = text;
this.type = type;

} SyntaxUnit.fromToken = function(token){

return new SyntaxUnit(token.value, token.startLine, token.startCol);

};

SyntaxUnit.prototype = {

constructor: SyntaxUnit,
valueOf: function(){
    return this.text;
},
toString: function(){
    return this.text;
}

}; function TokenStreamBase(input, tokenData){

this._reader = input ? new StringReader(input.toString()) : null;
this._token = null;
this._tokenData = tokenData;
this._lt = [];
this._ltIndex = 0;

this._ltIndexCache = [];

} TokenStreamBase.createTokenData = function(tokens){

var nameMap     = [],
    typeMap     = {},
    tokenData     = tokens.concat([]),
    i            = 0,
    len            = tokenData.length+1;

tokenData.UNKNOWN = -1;
tokenData.unshift({name:"EOF"});

for (; i < len; i++){
    nameMap.push(tokenData[i].name);
    tokenData[tokenData[i].name] = i;
    if (tokenData[i].text){
        typeMap[tokenData[i].text] = i;
    }
}

tokenData.name = function(tt){
    return nameMap[tt];
};

tokenData.type = function(c){
    return typeMap[c];
};

return tokenData;

};

TokenStreamBase.prototype = {

constructor: TokenStreamBase,
match: function(tokenTypes, channel){
    if (!(tokenTypes instanceof Array)){
        tokenTypes = [tokenTypes];
    }

    var tt  = this.get(channel),
        i   = 0,
        len = tokenTypes.length;

    while(i < len){
        if (tt == tokenTypes[i++]){
            return true;
        }
    }
    this.unget();
    return false;
},
mustMatch: function(tokenTypes, channel){

    var token;
    if (!(tokenTypes instanceof Array)){
        tokenTypes = [tokenTypes];
    }

    if (!this.match.apply(this, arguments)){
        token = this.LT(1);
        throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name +
            " at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
    }
},
advance: function(tokenTypes, channel){

    while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){
        this.get();
    }

    return this.LA(0);
},
get: function(channel){

    var tokenInfo   = this._tokenData,
        reader      = this._reader,
        value,
        i           =0,
        len         = tokenInfo.length,
        found       = false,
        token,
        info;
    if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length){

        i++;
        this._token = this._lt[this._ltIndex++];
        info = tokenInfo[this._token.type];
        while((info.channel !== undefined && channel !== info.channel) &&
                this._ltIndex < this._lt.length){
            this._token = this._lt[this._ltIndex++];
            info = tokenInfo[this._token.type];
            i++;
        }
        if ((info.channel === undefined || channel === info.channel) &&
                this._ltIndex <= this._lt.length){
            this._ltIndexCache.push(i);
            return this._token.type;
        }
    }
    token = this._getToken();
    if (token.type > -1 && !tokenInfo[token.type].hide){
        token.channel = tokenInfo[token.type].channel;
        this._token = token;
        this._lt.push(token);
        this._ltIndexCache.push(this._lt.length - this._ltIndex + i);
        if (this._lt.length > 5){
            this._lt.shift();
        }
        if (this._ltIndexCache.length > 5){
            this._ltIndexCache.shift();
        }
        this._ltIndex = this._lt.length;
    }
    info = tokenInfo[token.type];
    if (info &&
            (info.hide ||
            (info.channel !== undefined && channel !== info.channel))){
        return this.get(channel);
    } else {
        return token.type;
    }
},
LA: function(index){
    var total = index,
        tt;
    if (index > 0){
        if (index > 5){
            throw new Error("Too much lookahead.");
        }
        while(total){
            tt = this.get();
            total--;
        }
        while(total < index){
            this.unget();
            total++;
        }
    } else if (index < 0){

        if(this._lt[this._ltIndex+index]){
            tt = this._lt[this._ltIndex+index].type;
        } else {
            throw new Error("Too much lookbehind.");
        }

    } else {
        tt = this._token.type;
    }

    return tt;

},
LT: function(index){
    this.LA(index);
    return this._lt[this._ltIndex+index-1];
},
peek: function(){
    return this.LA(1);
},
token: function(){
    return this._token;
},
tokenName: function(tokenType){
    if (tokenType < 0 || tokenType > this._tokenData.length){
        return "UNKNOWN_TOKEN";
    } else {
        return this._tokenData[tokenType].name;
    }
},
tokenType: function(tokenName){
    return this._tokenData[tokenName] || -1;
},
unget: function(){
    if (this._ltIndexCache.length){
        this._ltIndex -= this._ltIndexCache.pop();//--;
        this._token = this._lt[this._ltIndex - 1];
    } else {
        throw new Error("Too much lookahead.");
    }
}

};

parserlib.util = { StringReader: StringReader, SyntaxError : SyntaxError, SyntaxUnit : SyntaxUnit, EventTarget : EventTarget, TokenStreamBase : TokenStreamBase }; })(); (function(){ var EventTarget = parserlib.util.EventTarget, TokenStreamBase = parserlib.util.TokenStreamBase, StringReader = parserlib.util.StringReader, SyntaxError = parserlib.util.SyntaxError, SyntaxUnit = parserlib.util.SyntaxUnit;

var Colors = {

aliceblue       :"#f0f8ff",
antiquewhite    :"#faebd7",
aqua            :"#00ffff",
aquamarine      :"#7fffd4",
azure           :"#f0ffff",
beige           :"#f5f5dc",
bisque          :"#ffe4c4",
black           :"#000000",
blanchedalmond  :"#ffebcd",
blue            :"#0000ff",
blueviolet      :"#8a2be2",
brown           :"#a52a2a",
burlywood       :"#deb887",
cadetblue       :"#5f9ea0",
chartreuse      :"#7fff00",
chocolate       :"#d2691e",
coral           :"#ff7f50",
cornflowerblue  :"#6495ed",
cornsilk        :"#fff8dc",
crimson         :"#dc143c",
cyan            :"#00ffff",
darkblue        :"#00008b",
darkcyan        :"#008b8b",
darkgoldenrod   :"#b8860b",
darkgray        :"#a9a9a9",
darkgrey        :"#a9a9a9",
darkgreen       :"#006400",
darkkhaki       :"#bdb76b",
darkmagenta     :"#8b008b",
darkolivegreen  :"#556b2f",
darkorange      :"#ff8c00",
darkorchid      :"#9932cc",
darkred         :"#8b0000",
darksalmon      :"#e9967a",
darkseagreen    :"#8fbc8f",
darkslateblue   :"#483d8b",
darkslategray   :"#2f4f4f",
darkslategrey   :"#2f4f4f",
darkturquoise   :"#00ced1",
darkviolet      :"#9400d3",
deeppink        :"#ff1493",
deepskyblue     :"#00bfff",
dimgray         :"#696969",
dimgrey         :"#696969",
dodgerblue      :"#1e90ff",
firebrick       :"#b22222",
floralwhite     :"#fffaf0",
forestgreen     :"#228b22",
fuchsia         :"#ff00ff",
gainsboro       :"#dcdcdc",
ghostwhite      :"#f8f8ff",
gold            :"#ffd700",
goldenrod       :"#daa520",
gray            :"#808080",
grey            :"#808080",
green           :"#008000",
greenyellow     :"#adff2f",
honeydew        :"#f0fff0",
hotpink         :"#ff69b4",
indianred       :"#cd5c5c",
indigo          :"#4b0082",
ivory           :"#fffff0",
khaki           :"#f0e68c",
lavender        :"#e6e6fa",
lavenderblush   :"#fff0f5",
lawngreen       :"#7cfc00",
lemonchiffon    :"#fffacd",
lightblue       :"#add8e6",
lightcoral      :"#f08080",
lightcyan       :"#e0ffff",
lightgoldenrodyellow  :"#fafad2",
lightgray       :"#d3d3d3",
lightgrey       :"#d3d3d3",
lightgreen      :"#90ee90",
lightpink       :"#ffb6c1",
lightsalmon     :"#ffa07a",
lightseagreen   :"#20b2aa",
lightskyblue    :"#87cefa",
lightslategray  :"#778899",
lightslategrey  :"#778899",
lightsteelblue  :"#b0c4de",
lightyellow     :"#ffffe0",
lime            :"#00ff00",
limegreen       :"#32cd32",
linen           :"#faf0e6",
magenta         :"#ff00ff",
maroon          :"#800000",
mediumaquamarine:"#66cdaa",
mediumblue      :"#0000cd",
mediumorchid    :"#ba55d3",
mediumpurple    :"#9370d8",
mediumseagreen  :"#3cb371",
mediumslateblue :"#7b68ee",
mediumspringgreen   :"#00fa9a",
mediumturquoise :"#48d1cc",
mediumvioletred :"#c71585",
midnightblue    :"#191970",
mintcream       :"#f5fffa",
mistyrose       :"#ffe4e1",
moccasin        :"#ffe4b5",
navajowhite     :"#ffdead",
navy            :"#000080",
oldlace         :"#fdf5e6",
olive           :"#808000",
olivedrab       :"#6b8e23",
orange          :"#ffa500",
orangered       :"#ff4500",
orchid          :"#da70d6",
palegoldenrod   :"#eee8aa",
palegreen       :"#98fb98",
paleturquoise   :"#afeeee",
palevioletred   :"#d87093",
papayawhip      :"#ffefd5",
peachpuff       :"#ffdab9",
peru            :"#cd853f",
pink            :"#ffc0cb",
plum            :"#dda0dd",
powderblue      :"#b0e0e6",
purple          :"#800080",
red             :"#ff0000",
rosybrown       :"#bc8f8f",
royalblue       :"#4169e1",
saddlebrown     :"#8b4513",
salmon          :"#fa8072",
sandybrown      :"#f4a460",
seagreen        :"#2e8b57",
seashell        :"#fff5ee",
sienna          :"#a0522d",
silver          :"#c0c0c0",
skyblue         :"#87ceeb",
slateblue       :"#6a5acd",
slategray       :"#708090",
slategrey       :"#708090",
snow            :"#fffafa",
springgreen     :"#00ff7f",
steelblue       :"#4682b4",
tan             :"#d2b48c",
teal            :"#008080",
thistle         :"#d8bfd8",
tomato          :"#ff6347",
turquoise       :"#40e0d0",
violet          :"#ee82ee",
wheat           :"#f5deb3",
white           :"#ffffff",
whitesmoke      :"#f5f5f5",
yellow          :"#ffff00",
yellowgreen     :"#9acd32",
activeBorder        :"Active window border.",
activecaption       :"Active window caption.",
appworkspace        :"Background color of multiple document interface.",
background          :"Desktop background.",
buttonface          :"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.",
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.",
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.",
buttontext          :"Text on push buttons.",
captiontext         :"Text in caption, size box, and scrollbar arrow box.",
graytext            :"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.",
greytext            :"Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color.",
highlight           :"Item(s) selected in a control.",
highlighttext       :"Text of item(s) selected in a control.",
inactiveborder      :"Inactive window border.",
inactivecaption     :"Inactive window caption.",
inactivecaptiontext :"Color of text in an inactive caption.",
infobackground      :"Background color for tooltip controls.",
infotext            :"Text color for tooltip controls.",
menu                :"Menu background.",
menutext            :"Text in menus.",
scrollbar           :"Scroll bar gray area.",
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.",
threedface          :"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
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.",
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.",
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.",
window              :"Window background.",
windowframe         :"Window frame.",
windowtext          :"Text in windows."

}; function Combinator(text, line, col){

SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE);
this.type = "unknown";
if (/^\s+$/.test(text)){
    this.type = "descendant";
} else if (text == ">"){
    this.type = "child";
} else if (text == "+"){
    this.type = "adjacent-sibling";
} else if (text == "~"){
    this.type = "sibling";
}

}

Combinator.prototype = new SyntaxUnit(); Combinator.prototype.constructor = Combinator; function MediaFeature(name, value){

SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE);
this.name = name;
this.value = value;

}

MediaFeature.prototype = new SyntaxUnit(); MediaFeature.prototype.constructor = MediaFeature; function MediaQuery(modifier, mediaType, features, line, col){

SyntaxUnit.call(this, (modifier ? modifier + " ": "") + (mediaType ? mediaType : "") + (mediaType && features.length > 0 ? " and " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE);
this.modifier = modifier;
this.mediaType = mediaType;
this.features = features;

}

MediaQuery.prototype = new SyntaxUnit(); MediaQuery.prototype.constructor = MediaQuery; function Parser(options){

EventTarget.call(this);

this.options = options || {};

this._tokenStream = null;

} Parser.DEFAULT_TYPE = 0; Parser.COMBINATOR_TYPE = 1; Parser.MEDIA_FEATURE_TYPE = 2; Parser.MEDIA_QUERY_TYPE = 3; Parser.PROPERTY_NAME_TYPE = 4; Parser.PROPERTY_VALUE_TYPE = 5; Parser.PROPERTY_VALUE_PART_TYPE = 6; Parser.SELECTOR_TYPE = 7; Parser.SELECTOR_PART_TYPE = 8; Parser.SELECTOR_SUB_PART_TYPE = 9;

Parser.prototype = function(){

var proto = new EventTarget(),  //new prototype
    prop,
    additions =  {
        constructor: Parser,
        DEFAULT_TYPE : 0,
        COMBINATOR_TYPE : 1,
        MEDIA_FEATURE_TYPE : 2,
        MEDIA_QUERY_TYPE : 3,
        PROPERTY_NAME_TYPE : 4,
        PROPERTY_VALUE_TYPE : 5,
        PROPERTY_VALUE_PART_TYPE : 6,
        SELECTOR_TYPE : 7,
        SELECTOR_PART_TYPE : 8,
        SELECTOR_SUB_PART_TYPE : 9,

        _stylesheet: function(){

            var tokenStream = this._tokenStream,
                charset     = null,
                count,
                token,
                tt;

            this.fire("startstylesheet");
            this._charset();

            this._skipCruft();
            while (tokenStream.peek() == Tokens.IMPORT_SYM){
                this._import();
                this._skipCruft();
            }
            while (tokenStream.peek() == Tokens.NAMESPACE_SYM){
                this._namespace();
                this._skipCruft();
            }
            tt = tokenStream.peek();
            while(tt > Tokens.EOF){

                try {

                    switch(tt){
                        case Tokens.MEDIA_SYM:
                            this._media();
                            this._skipCruft();
                            break;
                        case Tokens.PAGE_SYM:
                            this._page();
                            this._skipCruft();
                            break;
                        case Tokens.FONT_FACE_SYM:
                            this._font_face();
                            this._skipCruft();
                            break;
                        case Tokens.KEYFRAMES_SYM:
                            this._keyframes();
                            this._skipCruft();
                            break;
                        case Tokens.VIEWPORT_SYM:
                            this._viewport();
                            this._skipCruft();
                            break;
                        case Tokens.UNKNOWN_SYM:  //unknown @ rule
                            tokenStream.get();
                            if (!this.options.strict){
                                this.fire({
                                    type:       "error",
                                    error:      null,
                                    message:    "Unknown @ rule: " + tokenStream.LT(0).value + ".",
                                    line:       tokenStream.LT(0).startLine,
                                    col:        tokenStream.LT(0).startCol
                                });
                                count=0;
                                while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){
                                    count++;    //keep track of nesting depth
                                }

                                while(count){
                                    tokenStream.advance([Tokens.RBRACE]);
                                    count--;
                                }

                            } else {
                                throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol);
                            }
                            break;
                        case Tokens.S:
                            this._readWhitespace();
                            break;
                        default:
                            if(!this._ruleset()){
                                switch(tt){
                                    case Tokens.CHARSET_SYM:
                                        token = tokenStream.LT(1);
                                        this._charset(false);
                                        throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol);
                                    case Tokens.IMPORT_SYM:
                                        token = tokenStream.LT(1);
                                        this._import(false);
                                        throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol);
                                    case Tokens.NAMESPACE_SYM:
                                        token = tokenStream.LT(1);
                                        this._namespace(false);
                                        throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol);
                                    default:
                                        tokenStream.get();  //get the last token
                                        this._unexpectedToken(tokenStream.token());
                                }

                            }
                    }
                } catch(ex) {
                    if (ex instanceof SyntaxError && !this.options.strict){
                        this.fire({
                            type:       "error",
                            error:      ex,
                            message:    ex.message,
                            line:       ex.line,
                            col:        ex.col
                        });
                    } else {
                        throw ex;
                    }
                }

                tt = tokenStream.peek();
            }

            if (tt != Tokens.EOF){
                this._unexpectedToken(tokenStream.token());
            }

            this.fire("endstylesheet");
        },

        _charset: function(emit){
            var tokenStream = this._tokenStream,
                charset,
                token,
                line,
                col;

            if (tokenStream.match(Tokens.CHARSET_SYM)){
                line = tokenStream.token().startLine;
                col = tokenStream.token().startCol;

                this._readWhitespace();
                tokenStream.mustMatch(Tokens.STRING);

                token = tokenStream.token();
                charset = token.value;

                this._readWhitespace();
                tokenStream.mustMatch(Tokens.SEMICOLON);

                if (emit !== false){
                    this.fire({
                        type:   "charset",
                        charset:charset,
                        line:   line,
                        col:    col
                    });
                }
            }
        },

        _import: function(emit){

            var tokenStream = this._tokenStream,
                tt,
                uri,
                importToken,
                mediaList   = [];
            tokenStream.mustMatch(Tokens.IMPORT_SYM);
            importToken = tokenStream.token();
            this._readWhitespace();

            tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);
            uri = tokenStream.token().value.replace(/^(?:url\()?["']?([^"']+?)["']?\)?$/, "$1");

            this._readWhitespace();

            mediaList = this._media_query_list();
            tokenStream.mustMatch(Tokens.SEMICOLON);
            this._readWhitespace();

            if (emit !== false){
                this.fire({
                    type:   "import",
                    uri:    uri,
                    media:  mediaList,
                    line:   importToken.startLine,
                    col:    importToken.startCol
                });
            }

        },

        _namespace: function(emit){

            var tokenStream = this._tokenStream,
                line,
                col,
                prefix,
                uri;
            tokenStream.mustMatch(Tokens.NAMESPACE_SYM);
            line = tokenStream.token().startLine;
            col = tokenStream.token().startCol;
            this._readWhitespace();
            if (tokenStream.match(Tokens.IDENT)){
                prefix = tokenStream.token().value;
                this._readWhitespace();
            }

            tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);
            uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1");

            this._readWhitespace();
            tokenStream.mustMatch(Tokens.SEMICOLON);
            this._readWhitespace();

            if (emit !== false){
                this.fire({
                    type:   "namespace",
                    prefix: prefix,
                    uri:    uri,
                    line:   line,
                    col:    col
                });
            }

        },

        _media: function(){
            var tokenStream     = this._tokenStream,
                line,
                col,
                mediaList;//       = [];
            tokenStream.mustMatch(Tokens.MEDIA_SYM);
            line = tokenStream.token().startLine;
            col = tokenStream.token().startCol;

            this._readWhitespace();

            mediaList = this._media_query_list();

            tokenStream.mustMatch(Tokens.LBRACE);
            this._readWhitespace();

            this.fire({
                type:   "startmedia",
                media:  mediaList,
                line:   line,
                col:    col
            });

            while(true) {
                if (tokenStream.peek() == Tokens.PAGE_SYM){
                    this._page();
                } else if (tokenStream.peek() == Tokens.FONT_FACE_SYM){
                    this._font_face();
                } else if (tokenStream.peek() == Tokens.VIEWPORT_SYM){
                    this._viewport();
                } else if (!this._ruleset()){
                    break;
                }
            }

            tokenStream.mustMatch(Tokens.RBRACE);
            this._readWhitespace();

            this.fire({
                type:   "endmedia",
                media:  mediaList,
                line:   line,
                col:    col
            });
        },
        _media_query_list: function(){
            var tokenStream = this._tokenStream,
                mediaList   = [];

            this._readWhitespace();

            if (tokenStream.peek() == Tokens.IDENT || tokenStream.peek() == Tokens.LPAREN){
                mediaList.push(this._media_query());
            }

            while(tokenStream.match(Tokens.COMMA)){
                this._readWhitespace();
                mediaList.push(this._media_query());
            }

            return mediaList;
        },
        _media_query: function(){
            var tokenStream = this._tokenStream,
                type        = null,
                ident       = null,
                token       = null,
                expressions = [];

            if (tokenStream.match(Tokens.IDENT)){
                ident = tokenStream.token().value.toLowerCase();
                if (ident != "only" && ident != "not"){
                    tokenStream.unget();
                    ident = null;
                } else {
                    token = tokenStream.token();
                }
            }

            this._readWhitespace();

            if (tokenStream.peek() == Tokens.IDENT){
                type = this._media_type();
                if (token === null){
                    token = tokenStream.token();
                }
            } else if (tokenStream.peek() == Tokens.LPAREN){
                if (token === null){
                    token = tokenStream.LT(1);
                }
                expressions.push(this._media_expression());
            }

            if (type === null && expressions.length === 0){
                return null;
            } else {
                this._readWhitespace();
                while (tokenStream.match(Tokens.IDENT)){
                    if (tokenStream.token().value.toLowerCase() != "and"){
                        this._unexpectedToken(tokenStream.token());
                    }

                    this._readWhitespace();
                    expressions.push(this._media_expression());
                }
            }

            return new MediaQuery(ident, type, expressions, token.startLine, token.startCol);
        },
        _media_type: function(){
            return this._media_feature();
        },
        _media_expression: function(){
            var tokenStream = this._tokenStream,
                feature     = null,
                token,
                expression  = null;

            tokenStream.mustMatch(Tokens.LPAREN);

            feature = this._media_feature();
            this._readWhitespace();

            if (tokenStream.match(Tokens.COLON)){
                this._readWhitespace();
                token = tokenStream.LT(1);
                expression = this._expression();
            }

            tokenStream.mustMatch(Tokens.RPAREN);
            this._readWhitespace();

            return new MediaFeature(feature, (expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null));
        },
        _media_feature: function(){
            var tokenStream = this._tokenStream;

            tokenStream.mustMatch(Tokens.IDENT);

            return SyntaxUnit.fromToken(tokenStream.token());
        },
        _page: function(){
            var tokenStream = this._tokenStream,
                line,
                col,
                identifier  = null,
                pseudoPage  = null;
            tokenStream.mustMatch(Tokens.PAGE_SYM);
            line = tokenStream.token().startLine;
            col = tokenStream.token().startCol;

            this._readWhitespace();

            if (tokenStream.match(Tokens.IDENT)){
                identifier = tokenStream.token().value;
                if (identifier.toLowerCase() === "auto"){
                    this._unexpectedToken(tokenStream.token());
                }
            }
            if (tokenStream.peek() == Tokens.COLON){
                pseudoPage = this._pseudo_page();
            }

            this._readWhitespace();

            this.fire({
                type:   "startpage",
                id:     identifier,
                pseudo: pseudoPage,
                line:   line,
                col:    col
            });

            this._readDeclarations(true, true);

            this.fire({
                type:   "endpage",
                id:     identifier,
                pseudo: pseudoPage,
                line:   line,
                col:    col
            });

        },
        _margin: function(){
            var tokenStream = this._tokenStream,
                line,
                col,
                marginSym   = this._margin_sym();

            if (marginSym){
                line = tokenStream.token().startLine;
                col = tokenStream.token().startCol;

                this.fire({
                    type: "startpagemargin",
                    margin: marginSym,
                    line:   line,
                    col:    col
                });

                this._readDeclarations(true);

                this.fire({
                    type: "endpagemargin",
                    margin: marginSym,
                    line:   line,
                    col:    col
                });
                return true;
            } else {
                return false;
            }
        },
        _margin_sym: function(){

            var tokenStream = this._tokenStream;

            if(tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM,
                    Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM,
                    Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM,
                    Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM,
                    Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM,
                    Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM,
                    Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM]))
            {
                return SyntaxUnit.fromToken(tokenStream.token());
            } else {
                return null;
            }

        },

        _pseudo_page: function(){

            var tokenStream = this._tokenStream;

            tokenStream.mustMatch(Tokens.COLON);
            tokenStream.mustMatch(Tokens.IDENT);

            return tokenStream.token().value;
        },

        _font_face: function(){
            var tokenStream = this._tokenStream,
                line,
                col;
            tokenStream.mustMatch(Tokens.FONT_FACE_SYM);
            line = tokenStream.token().startLine;
            col = tokenStream.token().startCol;

            this._readWhitespace();

            this.fire({
                type:   "startfontface",
                line:   line,
                col:    col
            });

            this._readDeclarations(true);

            this.fire({
                type:   "endfontface",
                line:   line,
                col:    col
            });
        },

        _viewport: function(){
             var tokenStream = this._tokenStream,
                line,
                col;

                tokenStream.mustMatch(Tokens.VIEWPORT_SYM);
                line = tokenStream.token().startLine;
                col = tokenStream.token().startCol;

                this._readWhitespace();

                this.fire({
                    type:   "startviewport",
                    line:   line,
                    col:    col
                });

                this._readDeclarations(true);

                this.fire({
                    type:   "endviewport",
                    line:   line,
                    col:    col
                });

        },

        _operator: function(inFunction){

            var tokenStream = this._tokenStream,
                token       = null;

            if (tokenStream.match([Tokens.SLASH, Tokens.COMMA]) ||
                (inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS]))){
                token =  tokenStream.token();
                this._readWhitespace();
            }
            return token ? PropertyValuePart.fromToken(token) : null;

        },

        _combinator: function(){

            var tokenStream = this._tokenStream,
                value       = null,
                token;

            if(tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])){
                token = tokenStream.token();
                value = new Combinator(token.value, token.startLine, token.startCol);
                this._readWhitespace();
            }

            return value;
        },

        _unary_operator: function(){

            var tokenStream = this._tokenStream;

            if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])){
                return tokenStream.token().value;
            } else {
                return null;
            }
        },

        _property: function(){

            var tokenStream = this._tokenStream,
                value       = null,
                hack        = null,
                tokenValue,
                token,
                line,
                col;
            if (tokenStream.peek() == Tokens.STAR && this.options.starHack){
                tokenStream.get();
                token = tokenStream.token();
                hack = token.value;
                line = token.startLine;
                col = token.startCol;
            }

            if(tokenStream.match(Tokens.IDENT)){
                token = tokenStream.token();
                tokenValue = token.value;
                if (tokenValue.charAt(0) == "_" && this.options.underscoreHack){
                    hack = "_";
                    tokenValue = tokenValue.substring(1);
                }

                value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol));
                this._readWhitespace();
            }

            return value;
        },
        _ruleset: function(){

            var tokenStream = this._tokenStream,
                tt,
                selectors;
            try {
                selectors = this._selectors_group();
            } catch (ex){
                if (ex instanceof SyntaxError && !this.options.strict){
                    this.fire({
                        type:       "error",
                        error:      ex,
                        message:    ex.message,
                        line:       ex.line,
                        col:        ex.col
                    });
                    tt = tokenStream.advance([Tokens.RBRACE]);
                    if (tt == Tokens.RBRACE){
                    } else {
                        throw ex;
                    }

                } else {
                    throw ex;
                }
                return true;
            }
            if (selectors){

                this.fire({
                    type:       "startrule",
                    selectors:  selectors,
                    line:       selectors[0].line,
                    col:        selectors[0].col
                });

                this._readDeclarations(true);

                this.fire({
                    type:       "endrule",
                    selectors:  selectors,
                    line:       selectors[0].line,
                    col:        selectors[0].col
                });

            }

            return selectors;

        },
        _selectors_group: function(){
            var tokenStream = this._tokenStream,
                selectors   = [],
                selector;

            selector = this._selector();
            if (selector !== null){

                selectors.push(selector);
                while(tokenStream.match(Tokens.COMMA)){
                    this._readWhitespace();
                    selector = this._selector();
                    if (selector !== null){
                        selectors.push(selector);
                    } else {
                        this._unexpectedToken(tokenStream.LT(1));
                    }
                }
            }

            return selectors.length ? selectors : null;
        },
        _selector: function(){

            var tokenStream = this._tokenStream,
                selector    = [],
                nextSelector = null,
                combinator  = null,
                ws          = null;
            nextSelector = this._simple_selector_sequence();
            if (nextSelector === null){
                return null;
            }

            selector.push(nextSelector);

            do {
                combinator = this._combinator();

                if (combinator !== null){
                    selector.push(combinator);
                    nextSelector = this._simple_selector_sequence();
                    if (nextSelector === null){
                        this._unexpectedToken(tokenStream.LT(1));
                    } else {
                        selector.push(nextSelector);
                    }
                } else {
                    if (this._readWhitespace()){
                        ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol);
                        combinator = this._combinator();
                        nextSelector = this._simple_selector_sequence();
                        if (nextSelector === null){
                            if (combinator !== null){
                                this._unexpectedToken(tokenStream.LT(1));
                            }
                        } else {

                            if (combinator !== null){
                                selector.push(combinator);
                            } else {
                                selector.push(ws);
                            }

                            selector.push(nextSelector);
                        }
                    } else {
                        break;
                    }

                }
            } while(true);

            return new Selector(selector, selector[0].line, selector[0].col);
        },
        _simple_selector_sequence: function(){

            var tokenStream = this._tokenStream,
                elementName = null,
                modifiers   = [],
                selectorText= "",
                components  = [
                    function(){
                        return tokenStream.match(Tokens.HASH) ?
                                new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) :
                                null;
                    },
                    this._class,
                    this._attrib,
                    this._pseudo,
                    this._negation
                ],
                i           = 0,
                len         = components.length,
                component   = null,
                found       = false,
                line,
                col;
            line = tokenStream.LT(1).startLine;
            col = tokenStream.LT(1).startCol;

            elementName = this._type_selector();
            if (!elementName){
                elementName = this._universal();
            }

            if (elementName !== null){
                selectorText += elementName;
            }

            while(true){
                if (tokenStream.peek() === Tokens.S){
                    break;
                }
                while(i < len && component === null){
                    component = components[i++].call(this);
                }

                if (component === null){
                    if (selectorText === ""){
                        return null;
                    } else {
                        break;
                    }
                } else {
                    i = 0;
                    modifiers.push(component);
                    selectorText += component.toString();
                    component = null;
                }
            }

            return selectorText !== "" ?
                    new SelectorPart(elementName, modifiers, selectorText, line, col) :
                    null;
        },
        _type_selector: function(){

            var tokenStream = this._tokenStream,
                ns          = this._namespace_prefix(),
                elementName = this._element_name();

            if (!elementName){
                if (ns){
                    tokenStream.unget();
                    if (ns.length > 1){
                        tokenStream.unget();
                    }
                }

                return null;
            } else {
                if (ns){
                    elementName.text = ns + elementName.text;
                    elementName.col -= ns.length;
                }
                return elementName;
            }
        },
        _class: function(){

            var tokenStream = this._tokenStream,
                token;

            if (tokenStream.match(Tokens.DOT)){
                tokenStream.mustMatch(Tokens.IDENT);
                token = tokenStream.token();
                return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1);
            } else {
                return null;
            }

        },
        _element_name: function(){

            var tokenStream = this._tokenStream,
                token;

            if (tokenStream.match(Tokens.IDENT)){
                token = tokenStream.token();
                return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol);

            } else {
                return null;
            }
        },
        _namespace_prefix: function(){
            var tokenStream = this._tokenStream,
                value       = "";
            if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE){

                if(tokenStream.match([Tokens.IDENT, Tokens.STAR])){
                    value += tokenStream.token().value;
                }

                tokenStream.mustMatch(Tokens.PIPE);
                value += "|";

            }

            return value.length ? value : null;
        },
        _universal: function(){
            var tokenStream = this._tokenStream,
                value       = "",
                ns;

            ns = this._namespace_prefix();
            if(ns){
                value += ns;
            }

            if(tokenStream.match(Tokens.STAR)){
                value += "*";
            }

            return value.length ? value : null;

       },
        _attrib: function(){

            var tokenStream = this._tokenStream,
                value       = null,
                ns,
                token;

            if (tokenStream.match(Tokens.LBRACKET)){
                token = tokenStream.token();
                value = token.value;
                value += this._readWhitespace();

                ns = this._namespace_prefix();

                if (ns){
                    value += ns;
                }

                tokenStream.mustMatch(Tokens.IDENT);
                value += tokenStream.token().value;
                value += this._readWhitespace();

                if(tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH,
                        Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])){

                    value += tokenStream.token().value;
                    value += this._readWhitespace();

                    tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);
                    value += tokenStream.token().value;
                    value += this._readWhitespace();
                }

                tokenStream.mustMatch(Tokens.RBRACKET);

                return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol);
            } else {
                return null;
            }
        },
        _pseudo: function(){

            var tokenStream = this._tokenStream,
                pseudo      = null,
                colons      = ":",
                line,
                col;

            if (tokenStream.match(Tokens.COLON)){

                if (tokenStream.match(Tokens.COLON)){
                    colons += ":";
                }

                if (tokenStream.match(Tokens.IDENT)){
                    pseudo = tokenStream.token().value;
                    line = tokenStream.token().startLine;
                    col = tokenStream.token().startCol - colons.length;
                } else if (tokenStream.peek() == Tokens.FUNCTION){
                    line = tokenStream.LT(1).startLine;
                    col = tokenStream.LT(1).startCol - colons.length;
                    pseudo = this._functional_pseudo();
                }

                if (pseudo){
                    pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col);
                }
            }

            return pseudo;
        },
        _functional_pseudo: function(){

            var tokenStream = this._tokenStream,
                value = null;

            if(tokenStream.match(Tokens.FUNCTION)){
                value = tokenStream.token().value;
                value += this._readWhitespace();
                value += this._expression();
                tokenStream.mustMatch(Tokens.RPAREN);
                value += ")";
            }

            return value;
        },
        _expression: function(){

            var tokenStream = this._tokenStream,
                value       = "";

            while(tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION,
                    Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH,
                    Tokens.FREQ, Tokens.ANGLE, Tokens.TIME,
                    Tokens.RESOLUTION, Tokens.SLASH])){

                value += tokenStream.token().value;
                value += this._readWhitespace();
            }

            return value.length ? value : null;

        },
        _negation: function(){

            var tokenStream = this._tokenStream,
                line,
                col,
                value       = "",
                arg,
                subpart     = null;

            if (tokenStream.match(Tokens.NOT)){
                value = tokenStream.token().value;
                line = tokenStream.token().startLine;
                col = tokenStream.token().startCol;
                value += this._readWhitespace();
                arg = this._negation_arg();
                value += arg;
                value += this._readWhitespace();
                tokenStream.match(Tokens.RPAREN);
                value += tokenStream.token().value;

                subpart = new SelectorSubPart(value, "not", line, col);
                subpart.args.push(arg);
            }

            return subpart;
        },
        _negation_arg: function(){

            var tokenStream = this._tokenStream,
                args        = [
                    this._type_selector,
                    this._universal,
                    function(){
                        return tokenStream.match(Tokens.HASH) ?
                                new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) :
                                null;
                    },
                    this._class,
                    this._attrib,
                    this._pseudo
                ],
                arg         = null,
                i           = 0,
                len         = args.length,
                elementName,
                line,
                col,
                part;

            line = tokenStream.LT(1).startLine;
            col = tokenStream.LT(1).startCol;

            while(i < len && arg === null){

                arg = args[i].call(this);
                i++;
            }
            if (arg === null){
                this._unexpectedToken(tokenStream.LT(1));
            }
            if (arg.type == "elementName"){
                part = new SelectorPart(arg, [], arg.toString(), line, col);
            } else {
                part = new SelectorPart(null, [arg], arg.toString(), line, col);
            }

            return part;
        },

        _declaration: function(){

            var tokenStream = this._tokenStream,
                property    = null,
                expr        = null,
                prio        = null,
                error       = null,
                invalid     = null,
                propertyName= "";

            property = this._property();
            if (property !== null){

                tokenStream.mustMatch(Tokens.COLON);
                this._readWhitespace();

                expr = this._expr();
                if (!expr || expr.length === 0){
                    this._unexpectedToken(tokenStream.LT(1));
                }

                prio = this._prio();
                propertyName = property.toString();
                if (this.options.starHack && property.hack == "*" ||
                        this.options.underscoreHack && property.hack == "_") {

                    propertyName = property.text;
                }

                try {
                    this._validateProperty(propertyName, expr);
                } catch (ex) {
                    invalid = ex;
                }

                this.fire({
                    type:       "property",
                    property:   property,
                    value:      expr,
                    important:  prio,
                    line:       property.line,
                    col:        property.col,
                    invalid:    invalid
                });

                return true;
            } else {
                return false;
            }
        },

        _prio: function(){

            var tokenStream = this._tokenStream,
                result      = tokenStream.match(Tokens.IMPORTANT_SYM);

            this._readWhitespace();
            return result;
        },

        _expr: function(inFunction){

            var tokenStream = this._tokenStream,
                values      = [],
                value       = null,
                operator    = null;

            value = this._term(inFunction);
            if (value !== null){

                values.push(value);

                do {
                    operator = this._operator(inFunction);
                    if (operator){
                        values.push(operator);
                    } /*else {
                                                    values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col));
                                                    valueParts = [];
                                            }*/

                    value = this._term(inFunction);

                    if (value === null){
                        break;
                    } else {
                        values.push(value);
                    }
                } while(true);
            }

            return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null;
        },

        _term: function(inFunction){

            var tokenStream = this._tokenStream,
                unary       = null,
                value       = null,
                endChar     = null,
                token,
                line,
                col;
            unary = this._unary_operator();
            if (unary !== null){
                line = tokenStream.token().startLine;
                col = tokenStream.token().startCol;
            }
            if (tokenStream.peek() == Tokens.IE_FUNCTION && this.options.ieFilters){

                value = this._ie_function();
                if (unary === null){
                    line = tokenStream.token().startLine;
                    col = tokenStream.token().startCol;
                }
            } else if (inFunction && tokenStream.match([Tokens.LPAREN, Tokens.LBRACE, Tokens.LBRACKET])){

                token = tokenStream.token();
                endChar = token.endChar;
                value = token.value + this._expr(inFunction).text;
                if (unary === null){
                    line = tokenStream.token().startLine;
                    col = tokenStream.token().startCol;
                }
                tokenStream.mustMatch(Tokens.type(endChar));
                value += endChar;
                this._readWhitespace();
            } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH,
                    Tokens.ANGLE, Tokens.TIME,
                    Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])){

                value = tokenStream.token().value;
                if (unary === null){
                    line = tokenStream.token().startLine;
                    col = tokenStream.token().startCol;
                }
                this._readWhitespace();
            } else {
                token = this._hexcolor();
                if (token === null){
                    if (unary === null){
                        line = tokenStream.LT(1).startLine;
                        col = tokenStream.LT(1).startCol;
                    }
                    if (value === null){
                        if (tokenStream.LA(3) == Tokens.EQUALS && this.options.ieFilters){
                            value = this._ie_function();
                        } else {
                            value = this._function();
                        }
                    }

                } else {
                    value = token.value;
                    if (unary === null){
                        line = token.startLine;
                        col = token.startCol;
                    }
                }

            }

            return value !== null ?
                    new PropertyValuePart(unary !== null ? unary + value : value, line, col) :
                    null;

        },

        _function: function(){

            var tokenStream = this._tokenStream,
                functionText = null,
                expr        = null,
                lt;

            if (tokenStream.match(Tokens.FUNCTION)){
                functionText = tokenStream.token().value;
                this._readWhitespace();
                expr = this._expr(true);
                functionText += expr;
                if (this.options.ieFilters && tokenStream.peek() == Tokens.EQUALS){
                    do {

                        if (this._readWhitespace()){
                            functionText += tokenStream.token().value;
                        }
                        if (tokenStream.LA(0) == Tokens.COMMA){
                            functionText += tokenStream.token().value;
                        }

                        tokenStream.match(Tokens.IDENT);
                        functionText += tokenStream.token().value;

                        tokenStream.match(Tokens.EQUALS);
                        functionText += tokenStream.token().value;
                        lt = tokenStream.peek();
                        while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){
                            tokenStream.get();
                            functionText += tokenStream.token().value;
                            lt = tokenStream.peek();
                        }
                    } while(tokenStream.match([Tokens.COMMA, Tokens.S]));
                }

                tokenStream.match(Tokens.RPAREN);
                functionText += ")";
                this._readWhitespace();
            }

            return functionText;
        },

        _ie_function: function(){

            var tokenStream = this._tokenStream,
                functionText = null,
                expr        = null,
                lt;
            if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])){
                functionText = tokenStream.token().value;

                do {

                    if (this._readWhitespace()){
                        functionText += tokenStream.token().value;
                    }
                    if (tokenStream.LA(0) == Tokens.COMMA){
                        functionText += tokenStream.token().value;
                    }

                    tokenStream.match(Tokens.IDENT);
                    functionText += tokenStream.token().value;

                    tokenStream.match(Tokens.EQUALS);
                    functionText += tokenStream.token().value;
                    lt = tokenStream.peek();
                    while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){
                        tokenStream.get();
                        functionText += tokenStream.token().value;
                        lt = tokenStream.peek();
                    }
                } while(tokenStream.match([Tokens.COMMA, Tokens.S]));

                tokenStream.match(Tokens.RPAREN);
                functionText += ")";
                this._readWhitespace();
            }

            return functionText;
        },

        _hexcolor: function(){

            var tokenStream = this._tokenStream,
                token = null,
                color;

            if(tokenStream.match(Tokens.HASH)){

                token = tokenStream.token();
                color = token.value;
                if (!/#[a-f0-9]{3,6}/i.test(color)){
                    throw new SyntaxError("Expected a hex color but found '" + color + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
                }
                this._readWhitespace();
            }

            return token;
        },

        _keyframes: function(){
            var tokenStream = this._tokenStream,
                token,
                tt,
                name,
                prefix = "";

            tokenStream.mustMatch(Tokens.KEYFRAMES_SYM);
            token = tokenStream.token();
            if (/^@\-([^\-]+)\-/.test(token.value)) {
                prefix = RegExp.$1;
            }

            this._readWhitespace();
            name = this._keyframe_name();

            this._readWhitespace();
            tokenStream.mustMatch(Tokens.LBRACE);

            this.fire({
                type:   "startkeyframes",
                name:   name,
                prefix: prefix,
                line:   token.startLine,
                col:    token.startCol
            });

            this._readWhitespace();
            tt = tokenStream.peek();
            while(tt == Tokens.IDENT || tt == Tokens.PERCENTAGE) {
                this._keyframe_rule();
                this._readWhitespace();
                tt = tokenStream.peek();
            }

            this.fire({
                type:   "endkeyframes",
                name:   name,
                prefix: prefix,
                line:   token.startLine,
                col:    token.startCol
            });

            this._readWhitespace();
            tokenStream.mustMatch(Tokens.RBRACE);

        },

        _keyframe_name: function(){
            var tokenStream = this._tokenStream,
                token;

            tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);
            return SyntaxUnit.fromToken(tokenStream.token());
        },

        _keyframe_rule: function(){
            var tokenStream = this._tokenStream,
                token,
                keyList = this._key_list();

            this.fire({
                type:   "startkeyframerule",
                keys:   keyList,
                line:   keyList[0].line,
                col:    keyList[0].col
            });

            this._readDeclarations(true);

            this.fire({
                type:   "endkeyframerule",
                keys:   keyList,
                line:   keyList[0].line,
                col:    keyList[0].col
            });

        },

        _key_list: function(){
            var tokenStream = this._tokenStream,
                token,
                key,
                keyList = [];
            keyList.push(this._key());

            this._readWhitespace();

            while(tokenStream.match(Tokens.COMMA)){
                this._readWhitespace();
                keyList.push(this._key());
                this._readWhitespace();
            }

            return keyList;
        },

        _key: function(){

            var tokenStream = this._tokenStream,
                token;

            if (tokenStream.match(Tokens.PERCENTAGE)){
                return SyntaxUnit.fromToken(tokenStream.token());
            } else if (tokenStream.match(Tokens.IDENT)){
                token = tokenStream.token();

                if (/from|to/i.test(token.value)){
                    return SyntaxUnit.fromToken(token);
                }

                tokenStream.unget();
            }
            this._unexpectedToken(tokenStream.LT(1));
        },
        _skipCruft: function(){
            while(this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])){
            }
        },
        _readDeclarations: function(checkStart, readMargins){
            var tokenStream = this._tokenStream,
                tt;

            this._readWhitespace();

            if (checkStart){
                tokenStream.mustMatch(Tokens.LBRACE);
            }

            this._readWhitespace();

            try {

                while(true){

                    if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())){
                    } else if (this._declaration()){
                        if (!tokenStream.match(Tokens.SEMICOLON)){
                            break;
                        }
                    } else {
                        break;
                    }
                    this._readWhitespace();
                }

                tokenStream.mustMatch(Tokens.RBRACE);
                this._readWhitespace();

            } catch (ex) {
                if (ex instanceof SyntaxError && !this.options.strict){
                    this.fire({
                        type:       "error",
                        error:      ex,
                        message:    ex.message,
                        line:       ex.line,
                        col:        ex.col
                    });
                    tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]);
                    if (tt == Tokens.SEMICOLON){
                        this._readDeclarations(false, readMargins);
                    } else if (tt != Tokens.RBRACE){
                        throw ex;
                    }

                } else {
                    throw ex;
                }
            }

        },
        _readWhitespace: function(){

            var tokenStream = this._tokenStream,
                ws = "";

            while(tokenStream.match(Tokens.S)){
                ws += tokenStream.token().value;
            }

            return ws;
        },
        _unexpectedToken: function(token){
            throw new SyntaxError("Unexpected token '" + token.value + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
        },
        _verifyEnd: function(){
            if (this._tokenStream.LA(1) != Tokens.EOF){
                this._unexpectedToken(this._tokenStream.LT(1));
            }
        },
        _validateProperty: function(property, value){
            Validation.validate(property, value);
        },

        parse: function(input){
            this._tokenStream = new TokenStream(input, Tokens);
            this._stylesheet();
        },

        parseStyleSheet: function(input){
            return this.parse(input);
        },

        parseMediaQuery: function(input){
            this._tokenStream = new TokenStream(input, Tokens);
            var result = this._media_query();
            this._verifyEnd();
            return result;
        },
        parsePropertyValue: function(input){

            this._tokenStream = new TokenStream(input, Tokens);
            this._readWhitespace();

            var result = this._expr();
            this._readWhitespace();
            this._verifyEnd();
            return result;
        },
        parseRule: function(input){
            this._tokenStream = new TokenStream(input, Tokens);
            this._readWhitespace();

            var result = this._ruleset();
            this._readWhitespace();
            this._verifyEnd();
            return result;
        },
        parseSelector: function(input){

            this._tokenStream = new TokenStream(input, Tokens);
            this._readWhitespace();

            var result = this._selector();
            this._readWhitespace();
            this._verifyEnd();
            return result;
        },
        parseStyleAttribute: function(input){
            input += "}"; // for error recovery in _readDeclarations()
            this._tokenStream = new TokenStream(input, Tokens);
            this._readDeclarations();
        }
    };
for (prop in additions){
    if (additions.hasOwnProperty(prop)){
        proto[prop] = additions[prop];
    }
}

return proto;

}(); var Properties = {

"align-items"                   : "flex-start | flex-end | center | baseline | stretch",
"align-content"                 : "flex-start | flex-end | center | space-between | space-around | stretch",
"align-self"                    : "auto | flex-start | flex-end | center | baseline | stretch",
"-webkit-align-items"           : "flex-start | flex-end | center | baseline | stretch",
"-webkit-align-content"         : "flex-start | flex-end | center | space-between | space-around | stretch",
"-webkit-align-self"            : "auto | flex-start | flex-end | center | baseline | stretch",
"alignment-adjust"              : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>",
"alignment-baseline"            : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
"animation"                     : 1,
"animation-delay"               : { multi: "<time>", comma: true },
"animation-direction"           : { multi: "normal | alternate", comma: true },
"animation-duration"            : { multi: "<time>", comma: true },
"animation-fill-mode"           : { multi: "none | forwards | backwards | both", comma: true },
"animation-iteration-count"     : { multi: "<number> | infinite", comma: true },
"animation-name"                : { multi: "none | <ident>", comma: true },
"animation-play-state"          : { multi: "running | paused", comma: true },
"animation-timing-function"     : 1,
"-moz-animation-delay"               : { multi: "<time>", comma: true },
"-moz-animation-direction"           : { multi: "normal | alternate", comma: true },
"-moz-animation-duration"            : { multi: "<time>", comma: true },
"-moz-animation-iteration-count"     : { multi: "<number> | infinite", comma: true },
"-moz-animation-name"                : { multi: "none | <ident>", comma: true },
"-moz-animation-play-state"          : { multi: "running | paused", comma: true },

"-ms-animation-delay"               : { multi: "<time>", comma: true },
"-ms-animation-direction"           : { multi: "normal | alternate", comma: true },
"-ms-animation-duration"            : { multi: "<time>", comma: true },
"-ms-animation-iteration-count"     : { multi: "<number> | infinite", comma: true },
"-ms-animation-name"                : { multi: "none | <ident>", comma: true },
"-ms-animation-play-state"          : { multi: "running | paused", comma: true },

"-webkit-animation-delay"               : { multi: "<time>", comma: true },
"-webkit-animation-direction"           : { multi: "normal | alternate", comma: true },
"-webkit-animation-duration"            : { multi: "<time>", comma: true },
"-webkit-animation-fill-mode"           : { multi: "none | forwards | backwards | both", comma: true },
"-webkit-animation-iteration-count"     : { multi: "<number> | infinite", comma: true },
"-webkit-animation-name"                : { multi: "none | <ident>", comma: true },
"-webkit-animation-play-state"          : { multi: "running | paused", comma: true },

"-o-animation-delay"               : { multi: "<time>", comma: true },
"-o-animation-direction"           : { multi: "normal | alternate", comma: true },
"-o-animation-duration"            : { multi: "<time>", comma: true },
"-o-animation-iteration-count"     : { multi: "<number> | infinite", comma: true },
"-o-animation-name"                : { multi: "none | <ident>", comma: true },
"-o-animation-play-state"          : { multi: "running | paused", comma: true },

"appearance"                    : "icon | window | desktop | workspace | document | tooltip | dialog | button | push-button | hyperlink | 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 | none | inherit",
"azimuth"                       : function (expression) {
    var simple      = "<angle> | leftwards | rightwards | inherit",
        direction   = "left-side | far-left | left | center-left | center | center-right | right | far-right | right-side",
        behind      = false,
        valid       = false,
        part;

    if (!ValidationTypes.isAny(expression, simple)) {
        if (ValidationTypes.isAny(expression, "behind")) {
            behind = true;
            valid = true;
        }

        if (ValidationTypes.isAny(expression, direction)) {
            valid = true;
            if (!behind) {
                ValidationTypes.isAny(expression, "behind");
            }
        }
    }

    if (expression.hasNext()) {
        part = expression.next();
        if (valid) {
            throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
        } else {
            throw new ValidationError("Expected (<'azimuth'>) but found '" + part + "'.", part.line, part.col);
        }
    }
},
"backface-visibility"           : "visible | hidden",
"background"                    : 1,
"background-attachment"         : { multi: "<attachment>", comma: true },
"background-clip"               : { multi: "<box>", comma: true },
"background-color"              : "<color> | inherit",
"background-image"              : { multi: "<bg-image>", comma: true },
"background-origin"             : { multi: "<box>", comma: true },
"background-position"           : { multi: "<bg-position>", comma: true },
"background-repeat"             : { multi: "<repeat-style>" },
"background-size"               : { multi: "<bg-size>", comma: true },
"baseline-shift"                : "baseline | sub | super | <percentage> | <length>",
"behavior"                      : 1,
"binding"                       : 1,
"bleed"                         : "<length>",
"bookmark-label"                : "<content> | <attr> | <string>",
"bookmark-level"                : "none | <integer>",
"bookmark-state"                : "open | closed",
"bookmark-target"               : "none | <uri> | <attr>",
"border"                        : "<border-width> || <border-style> || <color>",
"border-bottom"                 : "<border-width> || <border-style> || <color>",
"border-bottom-color"           : "<color> | inherit",
"border-bottom-left-radius"     :  "<x-one-radius>",
"border-bottom-right-radius"    :  "<x-one-radius>",
"border-bottom-style"           : "<border-style>",
"border-bottom-width"           : "<border-width>",
"border-collapse"               : "collapse | separate | inherit",
"border-color"                  : { multi: "<color> | inherit", max: 4 },
"border-image"                  : 1,
"border-image-outset"           : { multi: "<length> | <number>", max: 4 },
"border-image-repeat"           : { multi: "stretch | repeat | round", max: 2 },
"border-image-slice"            : function(expression) {

    var valid   = false,
        numeric = "<number> | <percentage>",
        fill    = false,
        count   = 0,
        max     = 4,
        part;

    if (ValidationTypes.isAny(expression, "fill")) {
        fill = true;
        valid = true;
    }

    while (expression.hasNext() && count < max) {
        valid = ValidationTypes.isAny(expression, numeric);
        if (!valid) {
            break;
        }
        count++;
    }

    if (!fill) {
        ValidationTypes.isAny(expression, "fill");
    } else {
        valid = true;
    }

    if (expression.hasNext()) {
        part = expression.next();
        if (valid) {
            throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
        } else {
            throw new ValidationError("Expected ([<number> | <percentage>]{1,4} && fill?) but found '" + part + "'.", part.line, part.col);
        }
    }
},
"border-image-source"           : "<image> | none",
"border-image-width"            : { multi: "<length> | <percentage> | <number> | auto", max: 4 },
"border-left"                   : "<border-width> || <border-style> || <color>",
"border-left-color"             : "<color> | inherit",
"border-left-style"             : "<border-style>",
"border-left-width"             : "<border-width>",
"border-radius"                 : function(expression) {

    var valid   = false,
        simple = "<length> | <percentage> | inherit",
        slash   = false,
        fill    = false,
        count   = 0,
        max     = 8,
        part;

    while (expression.hasNext() && count < max) {
        valid = ValidationTypes.isAny(expression, simple);
        if (!valid) {

            if (expression.peek() == "/" && count > 0 && !slash) {
                slash = true;
                max = count + 5;
                expression.next();
            } else {
                break;
            }
        }
        count++;
    }

    if (expression.hasNext()) {
        part = expression.next();
        if (valid) {
            throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
        } else {
            throw new ValidationError("Expected (<'border-radius'>) but found '" + part + "'.", part.line, part.col);
        }
    }
},
"border-right"                  : "<border-width> || <border-style> || <color>",
"border-right-color"            : "<color> | inherit",
"border-right-style"            : "<border-style>",
"border-right-width"            : "<border-width>",
"border-spacing"                : { multi: "<length> | inherit", max: 2 },
"border-style"                  : { multi: "<border-style>", max: 4 },
"border-top"                    : "<border-width> || <border-style> || <color>",
"border-top-color"              : "<color> | inherit",
"border-top-left-radius"        : "<x-one-radius>",
"border-top-right-radius"       : "<x-one-radius>",
"border-top-style"              : "<border-style>",
"border-top-width"              : "<border-width>",
"border-width"                  : { multi: "<border-width>", max: 4 },
"bottom"                        : "<margin-width> | inherit",
"-moz-box-align"                : "start | end | center | baseline | stretch",
"-moz-box-decoration-break"     : "slice |clone",
"-moz-box-direction"            : "normal | reverse | inherit",
"-moz-box-flex"                 : "<number>",
"-moz-box-flex-group"           : "<integer>",
"-moz-box-lines"                : "single | multiple",
"-moz-box-ordinal-group"        : "<integer>",
"-moz-box-orient"               : "horizontal | vertical | inline-axis | block-axis | inherit",
"-moz-box-pack"                 : "start | end | center | justify",
"-webkit-box-align"             : "start | end | center | baseline | stretch",
"-webkit-box-decoration-break"  : "slice |clone",
"-webkit-box-direction"         : "normal | reverse | inherit",
"-webkit-box-flex"              : "<number>",
"-webkit-box-flex-group"        : "<integer>",
"-webkit-box-lines"             : "single | multiple",
"-webkit-box-ordinal-group"     : "<integer>",
"-webkit-box-orient"            : "horizontal | vertical | inline-axis | block-axis | inherit",
"-webkit-box-pack"              : "start | end | center | justify",
"box-shadow"                    : function (expression) {
    var result      = false,
        part;

    if (!ValidationTypes.isAny(expression, "none")) {
        Validation.multiProperty("<shadow>", expression, true, Infinity);
    } else {
        if (expression.hasNext()) {
            part = expression.next();
            throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
        }
    }
},
"box-sizing"                    : "content-box | border-box | inherit",
"break-after"                   : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column",
"break-before"                  : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column",
"break-inside"                  : "auto | avoid | avoid-page | avoid-column",
"caption-side"                  : "top | bottom | inherit",
"clear"                         : "none | right | left | both | inherit",
"clip"                          : 1,
"color"                         : "<color> | inherit",
"color-profile"                 : 1,
"column-count"                  : "<integer> | auto",                      //http://www.w3.org/TR/css3-multicol/
"column-fill"                   : "auto | balance",
"column-gap"                    : "<length> | normal",
"column-rule"                   : "<border-width> || <border-style> || <color>",
"column-rule-color"             : "<color>",
"column-rule-style"             : "<border-style>",
"column-rule-width"             : "<border-width>",
"column-span"                   : "none | all",
"column-width"                  : "<length> | auto",
"columns"                       : 1,
"content"                       : 1,
"counter-increment"             : 1,
"counter-reset"                 : 1,
"crop"                          : "<shape> | auto",
"cue"                           : "cue-after | cue-before | inherit",
"cue-after"                     : 1,
"cue-before"                    : 1,
"cursor"                        : 1,
"direction"                     : "ltr | rtl | inherit",
"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 | none | inherit | -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",
"dominant-baseline"             : 1,
"drop-initial-after-adjust"     : "central | middle | after-edge | text-after-edge | ideographic | alphabetic | mathematical | <percentage> | <length>",
"drop-initial-after-align"      : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
"drop-initial-before-adjust"    : "before-edge | text-before-edge | central | middle | hanging | mathematical | <percentage> | <length>",
"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",
"drop-initial-size"             : "auto | line | <length> | <percentage>",
"drop-initial-value"            : "initial | <integer>",
"elevation"                     : "<angle> | below | level | above | higher | lower | inherit",
"empty-cells"                   : "show | hide | inherit",
"filter"                        : 1,
"fit"                           : "fill | hidden | meet | slice",
"fit-position"                  : 1,
"flex"                          : "<flex>",
"flex-basis"                    : "<width>",
"flex-direction"                : "row | row-reverse | column | column-reverse",
"flex-flow"                     : "<flex-direction> || <flex-wrap>",
"flex-grow"                     : "<number>",
"flex-shrink"                   : "<number>",
"flex-wrap"                     : "nowrap | wrap | wrap-reverse",
"-webkit-flex"                  : "<flex>",
"-webkit-flex-basis"            : "<width>",
"-webkit-flex-direction"        : "row | row-reverse | column | column-reverse",
"-webkit-flex-flow"             : "<flex-direction> || <flex-wrap>",
"-webkit-flex-grow"             : "<number>",
"-webkit-flex-shrink"           : "<number>",
"-webkit-flex-wrap"             : "nowrap | wrap | wrap-reverse",
"-ms-flex"                      : "<flex>",
"-ms-flex-align"                : "start | end | center | stretch | baseline",
"-ms-flex-direction"            : "row | row-reverse | column | column-reverse | inherit",
"-ms-flex-order"                : "<number>",
"-ms-flex-pack"                 : "start | end | center | justify",
"-ms-flex-wrap"                 : "nowrap | wrap | wrap-reverse",
"float"                         : "left | right | none | inherit",
"float-offset"                  : 1,
"font"                          : 1,
"font-family"                   : 1,
"font-size"                     : "<absolute-size> | <relative-size> | <length> | <percentage> | inherit",
"font-size-adjust"              : "<number> | none | inherit",
"font-stretch"                  : "normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | inherit",
"font-style"                    : "normal | italic | oblique | inherit",
"font-variant"                  : "normal | small-caps | inherit",
"font-weight"                   : "normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit",
"grid-cell-stacking"            : "columns | rows | layer",
"grid-column"                   : 1,
"grid-columns"                  : 1,
"grid-column-align"             : "start | end | center | stretch",
"grid-column-sizing"            : 1,
"grid-column-span"              : "<integer>",
"grid-flow"                     : "none | rows | columns",
"grid-layer"                    : "<integer>",
"grid-row"                      : 1,
"grid-rows"                     : 1,
"grid-row-align"                : "start | end | center | stretch",
"grid-row-span"                 : "<integer>",
"grid-row-sizing"               : 1,
"hanging-punctuation"           : 1,
"height"                        : "<margin-width> | <content-sizing> | inherit",
"hyphenate-after"               : "<integer> | auto",
"hyphenate-before"              : "<integer> | auto",
"hyphenate-character"           : "<string> | auto",
"hyphenate-lines"               : "no-limit | <integer>",
"hyphenate-resource"            : 1,
"hyphens"                       : "none | manual | auto",
"icon"                          : 1,
"image-orientation"             : "angle | auto",
"image-rendering"               : 1,
"image-resolution"              : 1,
"inline-box-align"              : "initial | last | <integer>",
"justify-content"               : "flex-start | flex-end | center | space-between | space-around",
"-webkit-justify-content"       : "flex-start | flex-end | center | space-between | space-around",
"left"                          : "<margin-width> | inherit",
"letter-spacing"                : "<length> | normal | inherit",
"line-height"                   : "<number> | <length> | <percentage> | normal | inherit",
"line-break"                    : "auto | loose | normal | strict",
"line-stacking"                 : 1,
"line-stacking-ruby"            : "exclude-ruby | include-ruby",
"line-stacking-shift"           : "consider-shifts | disregard-shifts",
"line-stacking-strategy"        : "inline-line-height | block-line-height | max-height | grid-height",
"list-style"                    : 1,
"list-style-image"              : "<uri> | none | inherit",
"list-style-position"           : "inside | outside | inherit",
"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 | inherit",
"margin"                        : { multi: "<margin-width> | inherit", max: 4 },
"margin-bottom"                 : "<margin-width> | inherit",
"margin-left"                   : "<margin-width> | inherit",
"margin-right"                  : "<margin-width> | inherit",
"margin-top"                    : "<margin-width> | inherit",
"mark"                          : 1,
"mark-after"                    : 1,
"mark-before"                   : 1,
"marks"                         : 1,
"marquee-direction"             : 1,
"marquee-play-count"            : 1,
"marquee-speed"                 : 1,
"marquee-style"                 : 1,
"max-height"                    : "<length> | <percentage> | <content-sizing> | none | inherit",
"max-width"                     : "<length> | <percentage> | <content-sizing> | none | inherit",
"min-height"                    : "<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit",
"min-width"                     : "<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit",
"move-to"                       : 1,
"nav-down"                      : 1,
"nav-index"                     : 1,
"nav-left"                      : 1,
"nav-right"                     : 1,
"nav-up"                        : 1,
"opacity"                       : "<number> | inherit",
"order"                         : "<integer>",
"-webkit-order"                 : "<integer>",
"orphans"                       : "<integer> | inherit",
"outline"                       : 1,
"outline-color"                 : "<color> | invert | inherit",
"outline-offset"                : 1,
"outline-style"                 : "<border-style> | inherit",
"outline-width"                 : "<border-width> | inherit",
"overflow"                      : "visible | hidden | scroll | auto | inherit",
"overflow-style"                : 1,
"overflow-wrap"                 : "normal | break-word",
"overflow-x"                    : 1,
"overflow-y"                    : 1,
"padding"                       : { multi: "<padding-width> | inherit", max: 4 },
"padding-bottom"                : "<padding-width> | inherit",
"padding-left"                  : "<padding-width> | inherit",
"padding-right"                 : "<padding-width> | inherit",
"padding-top"                   : "<padding-width> | inherit",
"page"                          : 1,
"page-break-after"              : "auto | always | avoid | left | right | inherit",
"page-break-before"             : "auto | always | avoid | left | right | inherit",
"page-break-inside"             : "auto | avoid | inherit",
"page-policy"                   : 1,
"pause"                         : 1,
"pause-after"                   : 1,
"pause-before"                  : 1,
"perspective"                   : 1,
"perspective-origin"            : 1,
"phonemes"                      : 1,
"pitch"                         : 1,
"pitch-range"                   : 1,
"play-during"                   : 1,
"pointer-events"                : "auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit",
"position"                      : "static | relative | absolute | fixed | inherit",
"presentation-level"            : 1,
"punctuation-trim"              : 1,
"quotes"                        : 1,
"rendering-intent"              : 1,
"resize"                        : 1,
"rest"                          : 1,
"rest-after"                    : 1,
"rest-before"                   : 1,
"richness"                      : 1,
"right"                         : "<margin-width> | inherit",
"rotation"                      : 1,
"rotation-point"                : 1,
"ruby-align"                    : 1,
"ruby-overhang"                 : 1,
"ruby-position"                 : 1,
"ruby-span"                     : 1,
"size"                          : 1,
"speak"                         : "normal | none | spell-out | inherit",
"speak-header"                  : "once | always | inherit",
"speak-numeral"                 : "digits | continuous | inherit",
"speak-punctuation"             : "code | none | inherit",
"speech-rate"                   : 1,
"src"                           : 1,
"stress"                        : 1,
"string-set"                    : 1,

"table-layout"                  : "auto | fixed | inherit",
"tab-size"                      : "<integer> | <length>",
"target"                        : 1,
"target-name"                   : 1,
"target-new"                    : 1,
"target-position"               : 1,
"text-align"                    : "left | right | center | justify | inherit" ,
"text-align-last"               : 1,
"text-decoration"               : 1,
"text-emphasis"                 : 1,
"text-height"                   : 1,
"text-indent"                   : "<length> | <percentage> | inherit",
"text-justify"                  : "auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida",
"text-outline"                  : 1,
"text-overflow"                 : 1,
"text-rendering"                : "auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit",
"text-shadow"                   : 1,
"text-transform"                : "capitalize | uppercase | lowercase | none | inherit",
"text-wrap"                     : "normal | none | avoid",
"top"                           : "<margin-width> | inherit",
"-ms-touch-action"              : "auto | none | pan-x | pan-y",
"touch-action"                  : "auto | none | pan-x | pan-y",
"transform"                     : 1,
"transform-origin"              : 1,
"transform-style"               : 1,
"transition"                    : 1,
"transition-delay"              : 1,
"transition-duration"           : 1,
"transition-property"           : 1,
"transition-timing-function"    : 1,
"unicode-bidi"                  : "normal | embed | isolate | bidi-override | isolate-override | plaintext | inherit",
"user-modify"                   : "read-only | read-write | write-only | inherit",
"user-select"                   : "none | text | toggle | element | elements | all | inherit",
"vertical-align"                : "auto | use-script | baseline | sub | super | top | text-top | central | middle | bottom | text-bottom | <percentage> | <length>",
"visibility"                    : "visible | hidden | collapse | inherit",
"voice-balance"                 : 1,
"voice-duration"                : 1,
"voice-family"                  : 1,
"voice-pitch"                   : 1,
"voice-pitch-range"             : 1,
"voice-rate"                    : 1,
"voice-stress"                  : 1,
"voice-volume"                  : 1,
"volume"                        : 1,
"white-space"                   : "normal | pre | nowrap | pre-wrap | pre-line | inherit | -pre-wrap | -o-pre-wrap | -moz-pre-wrap | -hp-pre-wrap", //http://perishablepress.com/wrapping-content/
"white-space-collapse"          : 1,
"widows"                        : "<integer> | inherit",
"width"                         : "<length> | <percentage> | <content-sizing> | auto | inherit",
"word-break"                    : "normal | keep-all | break-all",
"word-spacing"                  : "<length> | normal | inherit",
"word-wrap"                     : "normal | break-word",
"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 | inherit",
"z-index"                       : "<integer> | auto | inherit",
"zoom"                          : "<number> | <percentage> | normal"

}; function PropertyName(text, hack, line, col){

SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_NAME_TYPE);
this.hack = hack;

}

PropertyName.prototype = new SyntaxUnit(); PropertyName.prototype.constructor = PropertyName; PropertyName.prototype.toString = function(){

return (this.hack ? this.hack : "") + this.text;

}; function PropertyValue(parts, line, col){

SyntaxUnit.call(this, parts.join(" "), line, col, Parser.PROPERTY_VALUE_TYPE);
this.parts = parts;

}

PropertyValue.prototype = new SyntaxUnit(); PropertyValue.prototype.constructor = PropertyValue; function PropertyValueIterator(value){

this._i = 0;
this._parts = value.parts;
this._marks = [];
this.value = value;

} PropertyValueIterator.prototype.count = function(){

return this._parts.length;

}; PropertyValueIterator.prototype.isFirst = function(){

return this._i === 0;

}; PropertyValueIterator.prototype.hasNext = function(){

return (this._i < this._parts.length);

}; PropertyValueIterator.prototype.mark = function(){

this._marks.push(this._i);

}; PropertyValueIterator.prototype.peek = function(count){

return this.hasNext() ? this._parts[this._i + (count || 0)] : null;

}; PropertyValueIterator.prototype.next = function(){

return this.hasNext() ? this._parts[this._i++] : null;

}; PropertyValueIterator.prototype.previous = function(){

return this._i > 0 ? this._parts[--this._i] : null;

}; PropertyValueIterator.prototype.restore = function(){

if (this._marks.length){
    this._i = this._marks.pop();
}

}; function PropertyValuePart(text, line, col){

SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_VALUE_PART_TYPE);
this.type = "unknown";

var temp;
if (/^([+\-]?[\d\.]+)([a-z]+)$/i.test(text)){  //dimension
    this.type = "dimension";
    this.value = +RegExp.$1;
    this.units = RegExp.$2;
    switch(this.units.toLowerCase()){

        case "em":
        case "rem":
        case "ex":
        case "px":
        case "cm":
        case "mm":
        case "in":
        case "pt":
        case "pc":
        case "ch":
        case "vh":
        case "vw":
        case "vmax":
        case "vmin":
            this.type = "length";
            break;

        case "deg":
        case "rad":
        case "grad":
            this.type = "angle";
            break;

        case "ms":
        case "s":
            this.type = "time";
            break;

        case "hz":
        case "khz":
            this.type = "frequency";
            break;

        case "dpi":
        case "dpcm":
            this.type = "resolution";
            break;

    }

} else if (/^([+\-]?[\d\.]+)%$/i.test(text)){  //percentage
    this.type = "percentage";
    this.value = +RegExp.$1;
} else if (/^([+\-]?\d+)$/i.test(text)){  //integer
    this.type = "integer";
    this.value = +RegExp.$1;
} else if (/^([+\-]?[\d\.]+)$/i.test(text)){  //number
    this.type = "number";
    this.value = +RegExp.$1;

} else if (/^#([a-f0-9]{3,6})/i.test(text)){  //hexcolor
    this.type = "color";
    temp = RegExp.$1;
    if (temp.length == 3){
        this.red    = parseInt(temp.charAt(0)+temp.charAt(0),16);
        this.green  = parseInt(temp.charAt(1)+temp.charAt(1),16);
        this.blue   = parseInt(temp.charAt(2)+temp.charAt(2),16);
    } else {
        this.red    = parseInt(temp.substring(0,2),16);
        this.green  = parseInt(temp.substring(2,4),16);
        this.blue   = parseInt(temp.substring(4,6),16);
    }
} else if (/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i.test(text)){ //rgb() color with absolute numbers
    this.type   = "color";
    this.red    = +RegExp.$1;
    this.green  = +RegExp.$2;
    this.blue   = +RegExp.$3;
} else if (/^rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){ //rgb() color with percentages
    this.type   = "color";
    this.red    = +RegExp.$1 * 255 / 100;
    this.green  = +RegExp.$2 * 255 / 100;
    this.blue   = +RegExp.$3 * 255 / 100;
} else if (/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with absolute numbers
    this.type   = "color";
    this.red    = +RegExp.$1;
    this.green  = +RegExp.$2;
    this.blue   = +RegExp.$3;
    this.alpha  = +RegExp.$4;
} else if (/^rgba\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with percentages
    this.type   = "color";
    this.red    = +RegExp.$1 * 255 / 100;
    this.green  = +RegExp.$2 * 255 / 100;
    this.blue   = +RegExp.$3 * 255 / 100;
    this.alpha  = +RegExp.$4;
} else if (/^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){ //hsl()
    this.type   = "color";
    this.hue    = +RegExp.$1;
    this.saturation = +RegExp.$2 / 100;
    this.lightness  = +RegExp.$3 / 100;
} else if (/^hsla\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //hsla() color with percentages
    this.type   = "color";
    this.hue    = +RegExp.$1;
    this.saturation = +RegExp.$2 / 100;
    this.lightness  = +RegExp.$3 / 100;
    this.alpha  = +RegExp.$4;
} else if (/^url\(["']?([^\)"']+)["']?\)/i.test(text)){ //URI
    this.type   = "uri";
    this.uri    = RegExp.$1;
} else if (/^([^\(]+)\(/i.test(text)){
    this.type   = "function";
    this.name   = RegExp.$1;
    this.value  = text;
} else if (/^["'][^"']*["']/.test(text)){    //string
    this.type   = "string";
    this.value  = eval(text);
} else if (Colors[text.toLowerCase()]){  //named color
    this.type   = "color";
    temp        = Colors[text.toLowerCase()].substring(1);
    this.red    = parseInt(temp.substring(0,2),16);
    this.green  = parseInt(temp.substring(2,4),16);
    this.blue   = parseInt(temp.substring(4,6),16);
} else if (/^[\,\/]$/.test(text)){
    this.type   = "operator";
    this.value  = text;
} else if (/^[a-z\-_\u0080-\uFFFF][a-z0-9\-_\u0080-\uFFFF]*$/i.test(text)){
    this.type   = "identifier";
    this.value  = text;
}

}

PropertyValuePart.prototype = new SyntaxUnit(); PropertyValuePart.prototype.constructor = PropertyValuePart; PropertyValuePart.fromToken = function(token){

return new PropertyValuePart(token.value, token.startLine, token.startCol);

}; var Pseudos = {

":first-letter": 1,
":first-line":   1,
":before":       1,
":after":        1

};

Pseudos.ELEMENT = 1; Pseudos.CLASS = 2;

Pseudos.isElement = function(pseudo){

return pseudo.indexOf("::") === 0 || Pseudos[pseudo.toLowerCase()] == Pseudos.ELEMENT;

}; function Selector(parts, line, col){

SyntaxUnit.call(this, parts.join(" "), line, col, Parser.SELECTOR_TYPE);
this.parts = parts;
this.specificity = Specificity.calculate(this);

}

Selector.prototype = new SyntaxUnit(); Selector.prototype.constructor = Selector; function SelectorPart(elementName, modifiers, text, line, col){

SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_PART_TYPE);
this.elementName = elementName;
this.modifiers = modifiers;

}

SelectorPart.prototype = new SyntaxUnit(); SelectorPart.prototype.constructor = SelectorPart; function SelectorSubPart(text, type, line, col){

SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_SUB_PART_TYPE);
this.type = type;
this.args = [];

}

SelectorSubPart.prototype = new SyntaxUnit(); SelectorSubPart.prototype.constructor = SelectorSubPart; function Specificity(a, b, c, d){

this.a = a;
this.b = b;
this.c = c;
this.d = d;

}

Specificity.prototype = {

constructor: Specificity,
compare: function(other){
    var comps = ["a", "b", "c", "d"],
        i, len;

    for (i=0, len=comps.length; i < len; i++){
        if (this[comps[i]] < other[comps[i]]){
            return -1;
        } else if (this[comps[i]] > other[comps[i]]){
            return 1;
        }
    }

    return 0;
},
valueOf: function(){
    return (this.a * 1000) + (this.b * 100) + (this.c * 10) + this.d;
},
toString: function(){
    return this.a + "," + this.b + "," + this.c + "," + this.d;
}

}; Specificity.calculate = function(selector){

var i, len,
    part,
    b=0, c=0, d=0;

function updateValues(part){

    var i, j, len, num,
        elementName = part.elementName ? part.elementName.text : "",
        modifier;

    if (elementName && elementName.charAt(elementName.length-1) != "*") {
        d++;
    }

    for (i=0, len=part.modifiers.length; i < len; i++){
        modifier = part.modifiers[i];
        switch(modifier.type){
            case "class":
            case "attribute":
                c++;
                break;

            case "id":
                b++;
                break;

            case "pseudo":
                if (Pseudos.isElement(modifier.text)){
                    d++;
                } else {
                    c++;
                }
                break;

            case "not":
                for (j=0, num=modifier.args.length; j < num; j++){
                    updateValues(modifier.args[j]);
                }
        }
     }
}

for (i=0, len=selector.parts.length; i < len; i++){
    part = selector.parts[i];

    if (part instanceof SelectorPart){
        updateValues(part);
    }
}

return new Specificity(0, b, c, d);

};

var h = /^[0-9a-fA-F]$/,

nonascii = /^[\u0080-\uFFFF]$/,
nl = /\n|\r\n|\r|\f/;

function isHexDigit©{

return c !== null && h.test(c);

}

function isDigit©{

return c !== null && /\d/.test(c);

}

function isWhitespace©{

return c !== null && /\s/.test(c);

}

function isNewLine©{

return c !== null && nl.test(c);

}

function isNameStart©{

return c !== null && (/[a-z_\u0080-\uFFFF\\]/i.test(c));

}

function isNameChar©{

return c !== null && (isNameStart(c) || /[0-9\-\\]/.test(c));

}

function isIdentStart©{

return c !== null && (isNameStart(c) || /\-\\/.test(c));

}

function mix(receiver, supplier){

for (var prop in supplier){
        if (supplier.hasOwnProperty(prop)){
                receiver[prop] = supplier[prop];
        }
}
return receiver;

} function TokenStream(input){

TokenStreamBase.call(this, input, Tokens);

}

TokenStream.prototype = mix(new TokenStreamBase(), {

_getToken: function(channel){

    var c,
        reader = this._reader,
        token   = null,
        startLine   = reader.getLine(),
        startCol    = reader.getCol();

    c = reader.read();

    while(c){
        switch(c){
            case "/":

                if(reader.peek() == "*"){
                    token = this.commentToken(c, startLine, startCol);
                } else {
                    token = this.charToken(c, startLine, startCol);
                }
                break;
            case "|":
            case "~":
            case "^":
            case "$":
            case "*":
                if(reader.peek() == "="){
                    token = this.comparisonToken(c, startLine, startCol);
                } else {
                    token = this.charToken(c, startLine, startCol);
                }
                break;
            case "\"":
            case "'":
                token = this.stringToken(c, startLine, startCol);
                break;
            case "#":
                if (isNameChar(reader.peek())){
                    token = this.hashToken(c, startLine, startCol);
                } else {
                    token = this.charToken(c, startLine, startCol);
                }
                break;
            case ".":
                if (isDigit(reader.peek())){
                    token = this.numberToken(c, startLine, startCol);
                } else {
                    token = this.charToken(c, startLine, startCol);
                }
                break;
            case "-":
                if (reader.peek() == "-"){  //could be closing HTML-style comment
                    token = this.htmlCommentEndToken(c, startLine, startCol);
                } else if (isNameStart(reader.peek())){
                    token = this.identOrFunctionToken(c, startLine, startCol);
                } else {
                    token = this.charToken(c, startLine, startCol);
                }
                break;
            case "!":
                token = this.importantToken(c, startLine, startCol);
                break;
            case "@":
                token = this.atRuleToken(c, startLine, startCol);
                break;
            case ":":
                token = this.notToken(c, startLine, startCol);
                break;
            case "<":
                token = this.htmlCommentStartToken(c, startLine, startCol);
                break;
            case "U":
            case "u":
                if (reader.peek() == "+"){
                    token = this.unicodeRangeToken(c, startLine, startCol);
                    break;
                }
            default:
                if (isDigit(c)){
                    token = this.numberToken(c, startLine, startCol);
                } else
                if (isWhitespace(c)){
                    token = this.whitespaceToken(c, startLine, startCol);
                } else
                if (isIdentStart(c)){
                    token = this.identOrFunctionToken(c, startLine, startCol);
                } else
                {
                    token = this.charToken(c, startLine, startCol);
                }

        }
        break;
    }

    if (!token && c === null){
        token = this.createToken(Tokens.EOF,null,startLine,startCol);
    }

    return token;
},
createToken: function(tt, value, startLine, startCol, options){
    var reader = this._reader;
    options = options || {};

    return {
        value:      value,
        type:       tt,
        channel:    options.channel,
        endChar:    options.endChar,
        hide:       options.hide || false,
        startLine:  startLine,
        startCol:   startCol,
        endLine:    reader.getLine(),
        endCol:     reader.getCol()
    };
},
atRuleToken: function(first, startLine, startCol){
    var rule    = first,
        reader  = this._reader,
        tt      = Tokens.CHAR,
        valid   = false,
        ident,
        c;
    reader.mark();
    ident = this.readName();
    rule = first + ident;
    tt = Tokens.type(rule.toLowerCase());
    if (tt == Tokens.CHAR || tt == Tokens.UNKNOWN){
        if (rule.length > 1){
            tt = Tokens.UNKNOWN_SYM;
        } else {
            tt = Tokens.CHAR;
            rule = first;
            reader.reset();
        }
    }

    return this.createToken(tt, rule, startLine, startCol);
},
charToken: function(c, startLine, startCol){
    var tt = Tokens.type(c);
    var opts = {};

    if (tt == -1){
        tt = Tokens.CHAR;
    } else {
        opts.endChar = Tokens[tt].endChar;
    }

    return this.createToken(tt, c, startLine, startCol, opts);
},
commentToken: function(first, startLine, startCol){
    var reader  = this._reader,
        comment = this.readComment(first);

    return this.createToken(Tokens.COMMENT, comment, startLine, startCol);
},
comparisonToken: function(c, startLine, startCol){
    var reader  = this._reader,
        comparison  = c + reader.read(),
        tt      = Tokens.type(comparison) || Tokens.CHAR;

    return this.createToken(tt, comparison, startLine, startCol);
},
hashToken: function(first, startLine, startCol){
    var reader  = this._reader,
        name    = this.readName(first);

    return this.createToken(Tokens.HASH, name, startLine, startCol);
},
htmlCommentStartToken: function(first, startLine, startCol){
    var reader      = this._reader,
        text        = first;

    reader.mark();
    text += reader.readCount(3);

    if (text == "<!--"){
        return this.createToken(Tokens.CDO, text, startLine, startCol);
    } else {
        reader.reset();
        return this.charToken(first, startLine, startCol);
    }
},
htmlCommentEndToken: function(first, startLine, startCol){
    var reader      = this._reader,
        text        = first;

    reader.mark();
    text += reader.readCount(2);

    if (text == "-->"){
        return this.createToken(Tokens.CDC, text, startLine, startCol);
    } else {
        reader.reset();
        return this.charToken(first, startLine, startCol);
    }
},
identOrFunctionToken: function(first, startLine, startCol){
    var reader  = this._reader,
        ident   = this.readName(first),
        tt      = Tokens.IDENT;
    if (reader.peek() == "("){
        ident += reader.read();
        if (ident.toLowerCase() == "url("){
            tt = Tokens.URI;
            ident = this.readURI(ident);
            if (ident.toLowerCase() == "url("){
                tt = Tokens.FUNCTION;
            }
        } else {
            tt = Tokens.FUNCTION;
        }
    } else if (reader.peek() == ":"){  //might be an IE function
        if (ident.toLowerCase() == "progid"){
            ident += reader.readTo("(");
            tt = Tokens.IE_FUNCTION;
        }
    }

    return this.createToken(tt, ident, startLine, startCol);
},
importantToken: function(first, startLine, startCol){
    var reader      = this._reader,
        important   = first,
        tt          = Tokens.CHAR,
        temp,
        c;

    reader.mark();
    c = reader.read();

    while(c){
        if (c == "/"){
            if (reader.peek() != "*"){
                break;
            } else {
                temp = this.readComment(c);
                if (temp === ""){    //broken!
                    break;
                }
            }
        } else if (isWhitespace(c)){
            important += c + this.readWhitespace();
        } else if (/i/i.test(c)){
            temp = reader.readCount(8);
            if (/mportant/i.test(temp)){
                important += c + temp;
                tt = Tokens.IMPORTANT_SYM;

            }
            break;  //we're done
        } else {
            break;
        }

        c = reader.read();
    }

    if (tt == Tokens.CHAR){
        reader.reset();
        return this.charToken(first, startLine, startCol);
    } else {
        return this.createToken(tt, important, startLine, startCol);
    }

},
notToken: function(first, startLine, startCol){
    var reader      = this._reader,
        text        = first;

    reader.mark();
    text += reader.readCount(4);

    if (text.toLowerCase() == ":not("){
        return this.createToken(Tokens.NOT, text, startLine, startCol);
    } else {
        reader.reset();
        return this.charToken(first, startLine, startCol);
    }
},
numberToken: function(first, startLine, startCol){
    var reader  = this._reader,
        value   = this.readNumber(first),
        ident,
        tt      = Tokens.NUMBER,
        c       = reader.peek();

    if (isIdentStart(c)){
        ident = this.readName(reader.read());
        value += ident;

        if (/^em$|^ex$|^px$|^gd$|^rem$|^vw$|^vh$|^vmax$|^vmin$|^ch$|^cm$|^mm$|^in$|^pt$|^pc$/i.test(ident)){
            tt = Tokens.LENGTH;
        } else if (/^deg|^rad$|^grad$/i.test(ident)){
            tt = Tokens.ANGLE;
        } else if (/^ms$|^s$/i.test(ident)){
            tt = Tokens.TIME;
        } else if (/^hz$|^khz$/i.test(ident)){
            tt = Tokens.FREQ;
        } else if (/^dpi$|^dpcm$/i.test(ident)){
            tt = Tokens.RESOLUTION;
        } else {
            tt = Tokens.DIMENSION;
        }

    } else if (c == "%"){
        value += reader.read();
        tt = Tokens.PERCENTAGE;
    }

    return this.createToken(tt, value, startLine, startCol);
},
stringToken: function(first, startLine, startCol){
    var delim   = first,
        string  = first,
        reader  = this._reader,
        prev    = first,
        tt      = Tokens.STRING,
        c       = reader.read();

    while(c){
        string += c;
        if (c == delim && prev != "\\"){
            break;
        }
        if (isNewLine(reader.peek()) && c != "\\"){
            tt = Tokens.INVALID;
            break;
        }
        prev = c;
        c = reader.read();
    }
    if (c === null){
        tt = Tokens.INVALID;
    }

    return this.createToken(tt, string, startLine, startCol);
},

unicodeRangeToken: function(first, startLine, startCol){
    var reader  = this._reader,
        value   = first,
        temp,
        tt      = Tokens.CHAR;
    if (reader.peek() == "+"){
        reader.mark();
        value += reader.read();
        value += this.readUnicodeRangePart(true);
        if (value.length == 2){
            reader.reset();
        } else {

            tt = Tokens.UNICODE_RANGE;
            if (value.indexOf("?") == -1){

                if (reader.peek() == "-"){
                    reader.mark();
                    temp = reader.read();
                    temp += this.readUnicodeRangePart(false);
                    if (temp.length == 1){
                        reader.reset();
                    } else {
                        value += temp;
                    }
                }

            }
        }
    }

    return this.createToken(tt, value, startLine, startCol);
},
whitespaceToken: function(first, startLine, startCol){
    var reader  = this._reader,
        value   = first + this.readWhitespace();
    return this.createToken(Tokens.S, value, startLine, startCol);
},

readUnicodeRangePart: function(allowQuestionMark){
    var reader  = this._reader,
        part = "",
        c       = reader.peek();
    while(isHexDigit(c) && part.length < 6){
        reader.read();
        part += c;
        c = reader.peek();
    }
    if (allowQuestionMark){
        while(c == "?" && part.length < 6){
            reader.read();
            part += c;
            c = reader.peek();
        }
    }

    return part;
},

readWhitespace: function(){
    var reader  = this._reader,
        whitespace = "",
        c       = reader.peek();

    while(isWhitespace(c)){
        reader.read();
        whitespace += c;
        c = reader.peek();
    }

    return whitespace;
},
readNumber: function(first){
    var reader  = this._reader,
        number  = first,
        hasDot  = (first == "."),
        c       = reader.peek();

    while(c){
        if (isDigit(c)){
            number += reader.read();
        } else if (c == "."){
            if (hasDot){
                break;
            } else {
                hasDot = true;
                number += reader.read();
            }
        } else {
            break;
        }

        c = reader.peek();
    }

    return number;
},
readString: function(){
    var reader  = this._reader,
        delim   = reader.read(),
        string  = delim,
        prev    = delim,
        c       = reader.peek();

    while(c){
        c = reader.read();
        string += c;
        if (c == delim && prev != "\\"){
            break;
        }
        if (isNewLine(reader.peek()) && c != "\\"){
            string = "";
            break;
        }
        prev = c;
        c = reader.peek();
    }
    if (c === null){
        string = "";
    }

    return string;
},
readURI: function(first){
    var reader  = this._reader,
        uri     = first,
        inner   = "",
        c       = reader.peek();

    reader.mark();
    while(c && isWhitespace(c)){
        reader.read();
        c = reader.peek();
    }
    if (c == "'" || c == "\""){
        inner = this.readString();
    } else {
        inner = this.readURL();
    }

    c = reader.peek();
    while(c && isWhitespace(c)){
        reader.read();
        c = reader.peek();
    }
    if (inner === "" || c != ")"){
        uri = first;
        reader.reset();
    } else {
        uri += inner + reader.read();
    }

    return uri;
},
readURL: function(){
    var reader  = this._reader,
        url     = "",
        c       = reader.peek();
    while (/^[!#$%&\\*-~]$/.test(c)){
        url += reader.read();
        c = reader.peek();
    }

    return url;

},
readName: function(first){
    var reader  = this._reader,
        ident   = first || "",
        c       = reader.peek();

    while(true){
        if (c == "\\"){
            ident += this.readEscape(reader.read());
            c = reader.peek();
        } else if(c && isNameChar(c)){
            ident += reader.read();
            c = reader.peek();
        } else {
            break;
        }
    }

    return ident;
},

readEscape: function(first){
    var reader  = this._reader,
        cssEscape = first || "",
        i       = 0,
        c       = reader.peek();

    if (isHexDigit(c)){
        do {
            cssEscape += reader.read();
            c = reader.peek();
        } while(c && isHexDigit(c) && ++i < 6);
    }

    if (cssEscape.length == 3 && /\s/.test(c) ||
        cssEscape.length == 7 || cssEscape.length == 1){
            reader.read();
    } else {
        c = "";
    }

    return cssEscape + c;
},

readComment: function(first){
    var reader  = this._reader,
        comment = first || "",
        c       = reader.read();

    if (c == "*"){
        while(c){
            comment += c;
            if (comment.length > 2 && c == "*" && reader.peek() == "/"){
                comment += reader.read();
                break;
            }

            c = reader.read();
        }

        return comment;
    } else {
        return "";
    }

}

});

var Tokens = [

{ name: "CDO"},
{ name: "CDC"},
{ name: "S", whitespace: true/*, channel: "ws"*/},
{ name: "COMMENT", comment: true, hide: true, channel: "comment" },
{ name: "INCLUDES", text: "~="},
{ name: "DASHMATCH", text: "|="},
{ name: "PREFIXMATCH", text: "^="},
{ name: "SUFFIXMATCH", text: "$="},
{ name: "SUBSTRINGMATCH", text: "*="},
{ name: "STRING"},
{ name: "IDENT"},
{ name: "HASH"},
{ name: "IMPORT_SYM", text: "@import"},
{ name: "PAGE_SYM", text: "@page"},
{ name: "MEDIA_SYM", text: "@media"},
{ name: "FONT_FACE_SYM", text: "@font-face"},
{ name: "CHARSET_SYM", text: "@charset"},
{ name: "NAMESPACE_SYM", text: "@namespace"},
{ name: "VIEWPORT_SYM", text: ["@viewport", "@-ms-viewport"]},
{ name: "UNKNOWN_SYM" },
{ name: "KEYFRAMES_SYM", text: [ "@keyframes", "@-webkit-keyframes", "@-moz-keyframes", "@-o-keyframes" ] },
{ name: "IMPORTANT_SYM"},
{ name: "LENGTH"},
{ name: "ANGLE"},
{ name: "TIME"},
{ name: "FREQ"},
{ name: "DIMENSION"},
{ name: "PERCENTAGE"},
{ name: "NUMBER"},
{ name: "URI"},
{ name: "FUNCTION"},
{ name: "UNICODE_RANGE"},
{ name: "INVALID"},
{ name: "PLUS", text: "+" },
{ name: "GREATER", text: ">"},
{ name: "COMMA", text: ","},
{ name: "TILDE", text: "~"},
{ name: "NOT"},
{ name: "TOPLEFTCORNER_SYM", text: "@top-left-corner"},
{ name: "TOPLEFT_SYM", text: "@top-left"},
{ name: "TOPCENTER_SYM", text: "@top-center"},
{ name: "TOPRIGHT_SYM", text: "@top-right"},
{ name: "TOPRIGHTCORNER_SYM", text: "@top-right-corner"},
{ name: "BOTTOMLEFTCORNER_SYM", text: "@bottom-left-corner"},
{ name: "BOTTOMLEFT_SYM", text: "@bottom-left"},
{ name: "BOTTOMCENTER_SYM", text: "@bottom-center"},
{ name: "BOTTOMRIGHT_SYM", text: "@bottom-right"},
{ name: "BOTTOMRIGHTCORNER_SYM", text: "@bottom-right-corner"},
{ name: "LEFTTOP_SYM", text: "@left-top"},
{ name: "LEFTMIDDLE_SYM", text: "@left-middle"},
{ name: "LEFTBOTTOM_SYM", text: "@left-bottom"},
{ name: "RIGHTTOP_SYM", text: "@right-top"},
{ name: "RIGHTMIDDLE_SYM", text: "@right-middle"},
{ name: "RIGHTBOTTOM_SYM", text: "@right-bottom"},
{ name: "RESOLUTION", state: "media"},
{ name: "IE_FUNCTION" },
{ name: "CHAR" },
{
    name: "PIPE",
    text: "|"
},
{
    name: "SLASH",
    text: "/"
},
{
    name: "MINUS",
    text: "-"
},
{
    name: "STAR",
    text: "*"
},

{
    name: "LBRACE",
    endChar: "}",
    text: "{"
},
{
    name: "RBRACE",
    text: "}"
},
{
    name: "LBRACKET",
    endChar: "]",
    text: "["
},
{
    name: "RBRACKET",
    text: "]"
},
{
    name: "EQUALS",
    text: "="
},
{
    name: "COLON",
    text: ":"
},
{
    name: "SEMICOLON",
    text: ";"
},

{
    name: "LPAREN",
    endChar: ")",
    text: "("
},
{
    name: "RPAREN",
    text: ")"
},
{
    name: "DOT",
    text: "."
}

];

(function(){

var nameMap = [],
    typeMap = {};

Tokens.UNKNOWN = -1;
Tokens.unshift({name:"EOF"});
for (var i=0, len = Tokens.length; i < len; i++){
    nameMap.push(Tokens[i].name);
    Tokens[Tokens[i].name] = i;
    if (Tokens[i].text){
        if (Tokens[i].text instanceof Array){
            for (var j=0; j < Tokens[i].text.length; j++){
                typeMap[Tokens[i].text[j]] = i;
            }
        } else {
            typeMap[Tokens[i].text] = i;
        }
    }
}

Tokens.name = function(tt){
    return nameMap[tt];
};

Tokens.type = function(c){
    return typeMap[c] || -1;
};

})(); var Validation = {

validate: function(property, value){
    var name        = property.toString().toLowerCase(),
        parts       = value.parts,
        expression  = new PropertyValueIterator(value),
        spec        = Properties[name],
        part,
        valid,
        j, count,
        msg,
        types,
        last,
        literals,
        max, multi, group;

    if (!spec) {
        if (name.indexOf("-") !== 0){    //vendor prefixed are ok
            throw new ValidationError("Unknown property '" + property + "'.", property.line, property.col);
        }
    } else if (typeof spec != "number"){
        if (typeof spec == "string"){
            if (spec.indexOf("||") > -1) {
                this.groupProperty(spec, expression);
            } else {
                this.singleProperty(spec, expression, 1);
            }

        } else if (spec.multi) {
            this.multiProperty(spec.multi, expression, spec.comma, spec.max || Infinity);
        } else if (typeof spec == "function") {
            spec(expression);
        }

    }

},

singleProperty: function(types, expression, max, partial) {

    var result      = false,
        value       = expression.value,
        count       = 0,
        part;

    while (expression.hasNext() && count < max) {
        result = ValidationTypes.isAny(expression, types);
        if (!result) {
            break;
        }
        count++;
    }

    if (!result) {
        if (expression.hasNext() && !expression.isFirst()) {
            part = expression.peek();
            throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
        } else {
             throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col);
        }
    } else if (expression.hasNext()) {
        part = expression.next();
        throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
    }

},

multiProperty: function (types, expression, comma, max) {

    var result      = false,
        value       = expression.value,
        count       = 0,
        sep         = false,
        part;

    while(expression.hasNext() && !result && count < max) {
        if (ValidationTypes.isAny(expression, types)) {
            count++;
            if (!expression.hasNext()) {
                result = true;

            } else if (comma) {
                if (expression.peek() == ",") {
                    part = expression.next();
                } else {
                    break;
                }
            }
        } else {
            break;

        }
    }

    if (!result) {
        if (expression.hasNext() && !expression.isFirst()) {
            part = expression.peek();
            throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
        } else {
            part = expression.previous();
            if (comma && part == ",") {
                throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
            } else {
                throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col);
            }
        }

    } else if (expression.hasNext()) {
        part = expression.next();
        throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
    }

},

groupProperty: function (types, expression, comma) {

    var result      = false,
        value       = expression.value,
        typeCount   = types.split("||").length,
        groups      = { count: 0 },
        partial     = false,
        name,
        part;

    while(expression.hasNext() && !result) {
        name = ValidationTypes.isAnyOfGroup(expression, types);
        if (name) {
            if (groups[name]) {
                break;
            } else {
                groups[name] = 1;
                groups.count++;
                partial = true;

                if (groups.count == typeCount || !expression.hasNext()) {
                    result = true;
                }
            }
        } else {
            break;
        }
    }

    if (!result) {
        if (partial && expression.hasNext()) {
                part = expression.peek();
                throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
        } else {
            throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col);
        }
    } else if (expression.hasNext()) {
        part = expression.next();
        throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
    }
}

}; function ValidationError(message, line, col){

this.col = col;
this.line = line;
this.message = message;

} ValidationError.prototype = new Error(); var ValidationTypes = {

isLiteral: function (part, literals) {
    var text = part.text.toString().toLowerCase(),
        args = literals.split(" | "),
        i, len, found = false;

    for (i=0,len=args.length; i < len && !found; i++){
        if (text == args[i].toLowerCase()){
            found = true;
        }
    }

    return found;
},

isSimple: function(type) {
    return !!this.simple[type];
},

isComplex: function(type) {
    return !!this.complex[type];
},
isAny: function (expression, types) {
    var args = types.split(" | "),
        i, len, found = false;

    for (i=0,len=args.length; i < len && !found && expression.hasNext(); i++){
        found = this.isType(expression, args[i]);
    }

    return found;
},
isAnyOfGroup: function(expression, types) {
    var args = types.split(" || "),
        i, len, found = false;

    for (i=0,len=args.length; i < len && !found; i++){
        found = this.isType(expression, args[i]);
    }

    return found ? args[i-1] : false;
},
isType: function (expression, type) {
    var part = expression.peek(),
        result = false;

    if (type.charAt(0) != "<") {
        result = this.isLiteral(part, type);
        if (result) {
            expression.next();
        }
    } else if (this.simple[type]) {
        result = this.simple[type](part);
        if (result) {
            expression.next();
        }
    } else {
        result = this.complex[type](expression);
    }

    return result;
},

simple: {

    "<absolute-size>": function(part){
        return ValidationTypes.isLiteral(part, "xx-small | x-small | small | medium | large | x-large | xx-large");
    },

    "<attachment>": function(part){
        return ValidationTypes.isLiteral(part, "scroll | fixed | local");
    },

    "<attr>": function(part){
        return part.type == "function" && part.name == "attr";
    },

    "<bg-image>": function(part){
        return this["<image>"](part) || this["<gradient>"](part) ||  part == "none";
    },

    "<gradient>": function(part) {
        return part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?(?:repeating\-)?(?:radial\-|linear\-)?gradient/i.test(part);
    },

    "<box>": function(part){
        return ValidationTypes.isLiteral(part, "padding-box | border-box | content-box");
    },

    "<content>": function(part){
        return part.type == "function" && part.name == "content";
    },

    "<relative-size>": function(part){
        return ValidationTypes.isLiteral(part, "smaller | larger");
    },
    "<ident>": function(part){
        return part.type == "identifier";
    },

    "<length>": function(part){
        if (part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?calc/i.test(part)){
            return true;
        }else{
            return part.type == "length" || part.type == "number" || part.type == "integer" || part == "0";
        }
    },

    "<color>": function(part){
        return part.type == "color" || part == "transparent";
    },

    "<number>": function(part){
        return part.type == "number" || this["<integer>"](part);
    },

    "<integer>": function(part){
        return part.type == "integer";
    },

    "<line>": function(part){
        return part.type == "integer";
    },

    "<angle>": function(part){
        return part.type == "angle";
    },

    "<uri>": function(part){
        return part.type == "uri";
    },

    "<image>": function(part){
        return this["<uri>"](part);
    },

    "<percentage>": function(part){
        return part.type == "percentage" || part == "0";
    },

    "<border-width>": function(part){
        return this["<length>"](part) || ValidationTypes.isLiteral(part, "thin | medium | thick");
    },

    "<border-style>": function(part){
        return ValidationTypes.isLiteral(part, "none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset");
    },

    "<content-sizing>": function(part){ // http://www.w3.org/TR/css3-sizing/#width-height-keywords
        return ValidationTypes.isLiteral(part, "fill-available | -moz-available | -webkit-fill-available | max-content | -moz-max-content | -webkit-max-content | min-content | -moz-min-content | -webkit-min-content | fit-content | -moz-fit-content | -webkit-fit-content");
    },

    "<margin-width>": function(part){
        return this["<length>"](part) || this["<percentage>"](part) || ValidationTypes.isLiteral(part, "auto");
    },

    "<padding-width>": function(part){
        return this["<length>"](part) || this["<percentage>"](part);
    },

    "<shape>": function(part){
        return part.type == "function" && (part.name == "rect" || part.name == "inset-rect");
    },

    "<time>": function(part) {
        return part.type == "time";
    },

    "<flex-grow>": function(part){
        return this["<number>"](part);
    },

    "<flex-shrink>": function(part){
        return this["<number>"](part);
    },

    "<width>": function(part){
        return this["<margin-width>"](part);
    },

    "<flex-basis>": function(part){
        return this["<width>"](part);
    },

    "<flex-direction>": function(part){
        return ValidationTypes.isLiteral(part, "row | row-reverse | column | column-reverse");
    },

    "<flex-wrap>": function(part){
        return ValidationTypes.isLiteral(part, "nowrap | wrap | wrap-reverse");
    }
},

complex: {

    "<bg-position>": function(expression){
        var types   = this,
            result  = false,
            numeric = "<percentage> | <length>",
            xDir    = "left | right",
            yDir    = "top | bottom",
            count = 0,
            hasNext = function() {
                return expression.hasNext() && expression.peek() != ",";
            };

        while (expression.peek(count) && expression.peek(count) != ",") {
            count++;
        }

        if (count < 3) {
            if (ValidationTypes.isAny(expression, xDir + " | center | " + numeric)) {
                    result = true;
                    ValidationTypes.isAny(expression, yDir + " | center | " + numeric);
            } else if (ValidationTypes.isAny(expression, yDir)) {
                    result = true;
                    ValidationTypes.isAny(expression, xDir + " | center");
            }
        } else {
            if (ValidationTypes.isAny(expression, xDir)) {
                if (ValidationTypes.isAny(expression, yDir)) {
                    result = true;
                    ValidationTypes.isAny(expression, numeric);
                } else if (ValidationTypes.isAny(expression, numeric)) {
                    if (ValidationTypes.isAny(expression, yDir)) {
                        result = true;
                        ValidationTypes.isAny(expression, numeric);
                    } else if (ValidationTypes.isAny(expression, "center")) {
                        result = true;
                    }
                }
            } else if (ValidationTypes.isAny(expression, yDir)) {
                if (ValidationTypes.isAny(expression, xDir)) {
                    result = true;
                    ValidationTypes.isAny(expression, numeric);
                } else if (ValidationTypes.isAny(expression, numeric)) {
                    if (ValidationTypes.isAny(expression, xDir)) {
                            result = true;
                            ValidationTypes.isAny(expression, numeric);
                    } else if (ValidationTypes.isAny(expression, "center")) {
                        result = true;
                    }
                }
            } else if (ValidationTypes.isAny(expression, "center")) {
                if (ValidationTypes.isAny(expression, xDir + " | " + yDir)) {
                    result = true;
                    ValidationTypes.isAny(expression, numeric);
                }
            }
        }

        return result;
    },

    "<bg-size>": function(expression){
        var types   = this,
            result  = false,
            numeric = "<percentage> | <length> | auto",
            part,
            i, len;

        if (ValidationTypes.isAny(expression, "cover | contain")) {
            result = true;
        } else if (ValidationTypes.isAny(expression, numeric)) {
            result = true;
            ValidationTypes.isAny(expression, numeric);
        }

        return result;
    },

    "<repeat-style>": function(expression){
        var result  = false,
            values  = "repeat | space | round | no-repeat",
            part;

        if (expression.hasNext()){
            part = expression.next();

            if (ValidationTypes.isLiteral(part, "repeat-x | repeat-y")) {
                result = true;
            } else if (ValidationTypes.isLiteral(part, values)) {
                result = true;

                if (expression.hasNext() && ValidationTypes.isLiteral(expression.peek(), values)) {
                    expression.next();
                }
            }
        }

        return result;

    },

    "<shadow>": function(expression) {
        var result  = false,
            count   = 0,
            inset   = false,
            color   = false,
            part;

        if (expression.hasNext()) {

            if (ValidationTypes.isAny(expression, "inset")){
                inset = true;
            }

            if (ValidationTypes.isAny(expression, "<color>")) {
                color = true;
            }

            while (ValidationTypes.isAny(expression, "<length>") && count < 4) {
                count++;
            }

            if (expression.hasNext()) {
                if (!color) {
                    ValidationTypes.isAny(expression, "<color>");
                }

                if (!inset) {
                    ValidationTypes.isAny(expression, "inset");
                }

            }

            result = (count >= 2 && count <= 4);

        }

        return result;
    },

    "<x-one-radius>": function(expression) {
        var result  = false,
            simple = "<length> | <percentage> | inherit";

        if (ValidationTypes.isAny(expression, simple)){
            result = true;
            ValidationTypes.isAny(expression, simple);
        }

        return result;
    },

    "<flex>": function(expression) {
        var part,
            result = false;
        if (ValidationTypes.isAny(expression, "none | inherit")) {
            result = true;
        } else {
            if (ValidationTypes.isType(expression, "<flex-grow>")) {
                if (expression.peek()) {
                    if (ValidationTypes.isType(expression, "<flex-shrink>")) {
                        if (expression.peek()) {
                            result = ValidationTypes.isType(expression, "<flex-basis>");
                        } else {
                            result = true;
                        }
                    } else if (ValidationTypes.isType(expression, "<flex-basis>")) {
                        result = expression.peek() === null;
                    }
                } else {
                    result = true;
                }
            } else if (ValidationTypes.isType(expression, "<flex-basis>")) {
                result = true;
            }
        }

        if (!result) {
            part = expression.peek();
            throw new ValidationError("Expected (none | [ <flex-grow> <flex-shrink>? || <flex-basis> ]) but found '" + expression.value.text + "'.", part.line, part.col);
        }

        return result;
    }
}

};

parserlib.css = { Colors :Colors, Combinator :Combinator, Parser :Parser, PropertyName :PropertyName, PropertyValue :PropertyValue, PropertyValuePart :PropertyValuePart, MediaFeature :MediaFeature, MediaQuery :MediaQuery, Selector :Selector, SelectorPart :SelectorPart, SelectorSubPart :SelectorSubPart, Specificity :Specificity, TokenStream :TokenStream, Tokens :Tokens, ValidationError :ValidationError }; })();

(function(){ for(var prop in parserlib){ exports = parserlib; } })();

function objectToString(o) {

return Object.prototype.toString.call(o);

} var util = {

isArray: function (ar) {
  return Array.isArray(ar) || (typeof ar === 'object' && objectToString(ar) === '[object Array]');
},
isDate: function (d) {
  return typeof d === 'object' && objectToString(d) === '[object Date]';
},
isRegExp: function (re) {
  return typeof re === 'object' && objectToString(re) === '[object RegExp]';
},
getRegExpFlags: function (re) {
  var flags = '';
  re.global && (flags += 'g');
  re.ignoreCase && (flags += 'i');
  re.multiline && (flags += 'm');
  return flags;
}

};

if (typeof module === 'object')

module.exports = clone;

function clone(parent, circular, depth, prototype) {

var allParents = [];
var allChildren = [];

var useBuffer = typeof Buffer != 'undefined';

if (typeof circular == 'undefined')
  circular = true;

if (typeof depth == 'undefined')
  depth = Infinity;
function _clone(parent, depth) {
  if (parent === null)
    return null;

  if (depth == 0)
    return parent;

  var child;
  if (typeof parent != 'object') {
    return parent;
  }

  if (util.isArray(parent)) {
    child = [];
  } else if (util.isRegExp(parent)) {
    child = new RegExp(parent.source, util.getRegExpFlags(parent));
    if (parent.lastIndex) child.lastIndex = parent.lastIndex;
  } else if (util.isDate(parent)) {
    child = new Date(parent.getTime());
  } else if (useBuffer && Buffer.isBuffer(parent)) {
    child = new Buffer(parent.length);
    parent.copy(child);
    return child;
  } else {
    if (typeof prototype == 'undefined') child = Object.create(Object.getPrototypeOf(parent));
    else child = Object.create(prototype);
  }

  if (circular) {
    var index = allParents.indexOf(parent);

    if (index != -1) {
      return allChildren[index];
    }
    allParents.push(parent);
    allChildren.push(child);
  }

  for (var i in parent) {
    child[i] = _clone(parent[i], depth - 1);
  }

  return child;
}

return _clone(parent, depth);

} clone.clonePrototype = function(parent) {

if (parent === null)
  return null;

var c = function () {};
c.prototype = parent;
return new c();

};

var CSSLint = (function(){

var rules           = [],
    formatters      = [],
    embeddedRuleset = /\/\*csslint([^\*]*)\*\//,
    api             = new parserlib.util.EventTarget();

api.version = "@VERSION@";
api.addRule = function(rule){
    rules.push(rule);
    rules[rule.id] = rule;
};
api.clearRules = function(){
    rules = [];
};
api.getRules = function(){
    return [].concat(rules).sort(function(a,b){
        return a.id > b.id ? 1 : 0;
    });
};
api.getRuleset = function() {
    var ruleset = {},
        i = 0,
        len = rules.length;

    while (i < len){
        ruleset[rules[i++].id] = 1;    //by default, everything is a warning
    }

    return ruleset;
};
function applyEmbeddedRuleset(text, ruleset){
    var valueMap,
        embedded = text && text.match(embeddedRuleset),
        rules = embedded && embedded[1];

    if (rules) {
        valueMap = {
            "true": 2,  // true is error
            "": 1,      // blank is warning
            "false": 0, // false is ignore

            "2": 2,     // explicit error
            "1": 1,     // explicit warning
            "0": 0      // explicit ignore
        };

        rules.toLowerCase().split(",").forEach(function(rule){
            var pair = rule.split(":"),
                property = pair[0] || "",
                value = pair[1] || "";

            ruleset[property.trim()] = valueMap[value.trim()];
        });
    }

    return ruleset;
}
api.addFormatter = function(formatter) {
    formatters[formatter.id] = formatter;
};
api.getFormatter = function(formatId){
    return formatters[formatId];
};
api.format = function(results, filename, formatId, options) {
    var formatter = this.getFormatter(formatId),
        result = null;

    if (formatter){
        result = formatter.startFormat();
        result += formatter.formatResults(results, filename, options || {});
        result += formatter.endFormat();
    }

    return result;
};
api.hasFormat = function(formatId){
    return formatters.hasOwnProperty(formatId);
};
api.verify = function(text, ruleset){

    var i = 0,
        reporter,
        lines,
        report,
        parser = new parserlib.css.Parser({ starHack: true, ieFilters: true,
                                            underscoreHack: true, strict: false });
    lines = text.replace(/\n\r?/g, "$split$").split("$split$");

    if (!ruleset){
        ruleset = this.getRuleset();
    }

    if (embeddedRuleset.test(text)){
        ruleset = clone(ruleset);
        ruleset = applyEmbeddedRuleset(text, ruleset);
    }

    reporter = new Reporter(lines, ruleset);

    ruleset.errors = 2;       //always report parsing errors as errors
    for (i in ruleset){
        if(ruleset.hasOwnProperty(i) && ruleset[i]){
            if (rules[i]){
                rules[i].init(parser, reporter);
            }
        }
    }
    try {
        parser.parse(text);
    } catch (ex) {
        reporter.error("Fatal error, cannot continue: " + ex.message, ex.line, ex.col, {});
    }

    report = {
        messages    : reporter.messages,
        stats       : reporter.stats,
        ruleset     : reporter.ruleset
    };
    report.messages.sort(function (a, b){
        if (a.rollup && !b.rollup){
            return 1;
        } else if (!a.rollup && b.rollup){
            return -1;
        } else {
            return a.line - b.line;
        }
    });

    return report;
};

return api;

})(); function Reporter(lines, ruleset){

this.messages = [];
this.stats = [];
this.lines = lines;
this.ruleset = ruleset;

}

Reporter.prototype = {

constructor: Reporter,
error: function(message, line, col, rule){
    this.messages.push({
        type    : "error",
        line    : line,
        col     : col,
        message : message,
        evidence: this.lines[line-1],
        rule    : rule || {}
    });
},
warn: function(message, line, col, rule){
    this.report(message, line, col, rule);
},
report: function(message, line, col, rule){
    this.messages.push({
        type    : this.ruleset[rule.id] === 2 ? "error" : "warning",
        line    : line,
        col     : col,
        message : message,
        evidence: this.lines[line-1],
        rule    : rule
    });
},
info: function(message, line, col, rule){
    this.messages.push({
        type    : "info",
        line    : line,
        col     : col,
        message : message,
        evidence: this.lines[line-1],
        rule    : rule
    });
},
rollupError: function(message, rule){
    this.messages.push({
        type    : "error",
        rollup  : true,
        message : message,
        rule    : rule
    });
},
rollupWarn: function(message, rule){
    this.messages.push({
        type    : "warning",
        rollup  : true,
        message : message,
        rule    : rule
    });
},
stat: function(name, value){
    this.stats[name] = value;
}

}; CSSLint._Reporter = Reporter; CSSLint.Util = {

mix: function(receiver, supplier){
    var prop;

    for (prop in supplier){
        if (supplier.hasOwnProperty(prop)){
            receiver[prop] = supplier[prop];
        }
    }

    return prop;
},
indexOf: function(values, value){
    if (values.indexOf){
        return values.indexOf(value);
    } else {
        for (var i=0, len=values.length; i < len; i++){
            if (values[i] === value){
                return i;
            }
        }
        return -1;
    }
},
forEach: function(values, func) {
    if (values.forEach){
        return values.forEach(func);
    } else {
        for (var i=0, len=values.length; i < len; i++){
            func(values[i], i, values);
        }
    }
}

};

CSSLint.addRule({

id: "adjoining-classes",
name: "Disallow adjoining classes",
desc: "Don't use adjoining classes.",
browsers: "IE6",
init: function(parser, reporter){
    var rule = this;
    parser.addListener("startrule", function(event){
        var selectors = event.selectors,
            selector,
            part,
            modifier,
            classCount,
            i, j, k;

        for (i=0; i < selectors.length; i++){
            selector = selectors[i];
            for (j=0; j < selector.parts.length; j++){
                part = selector.parts[j];
                if (part.type === parser.SELECTOR_PART_TYPE){
                    classCount = 0;
                    for (k=0; k < part.modifiers.length; k++){
                        modifier = part.modifiers[k];
                        if (modifier.type === "class"){
                            classCount++;
                        }
                        if (classCount > 1){
                            reporter.report("Don't use adjoining classes.", part.line, part.col, rule);
                        }
                    }
                }
            }
        }
    });
}

}); CSSLint.addRule({

id: "box-model",
name: "Beware of broken box size",
desc: "Don't use width or height when using padding or border.",
browsers: "All",
init: function(parser, reporter){
    var rule = this,
        widthProperties = {
            border: 1,
            "border-left": 1,
            "border-right": 1,
            padding: 1,
            "padding-left": 1,
            "padding-right": 1
        },
        heightProperties = {
            border: 1,
            "border-bottom": 1,
            "border-top": 1,
            padding: 1,
            "padding-bottom": 1,
            "padding-top": 1
        },
        properties,
        boxSizing = false;

    function startRule(){
        properties = {};
        boxSizing = false;
    }

    function endRule(){
        var prop, value;

        if (!boxSizing) {
            if (properties.height){
                for (prop in heightProperties){
                    if (heightProperties.hasOwnProperty(prop) && properties[prop]){
                        value = properties[prop].value;
                        if (!(prop === "padding" && value.parts.length === 2 && value.parts[0].value === 0)){
                            reporter.report("Using height with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
                        }
                    }
                }
            }

            if (properties.width){
                for (prop in widthProperties){
                    if (widthProperties.hasOwnProperty(prop) && properties[prop]){
                        value = properties[prop].value;

                        if (!(prop === "padding" && value.parts.length === 2 && value.parts[1].value === 0)){
                            reporter.report("Using width with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
                        }
                    }
                }
            }
        }
    }

    parser.addListener("startrule", startRule);
    parser.addListener("startfontface", startRule);
    parser.addListener("startpage", startRule);
    parser.addListener("startpagemargin", startRule);
    parser.addListener("startkeyframerule", startRule);

    parser.addListener("property", function(event){
        var name = event.property.text.toLowerCase();

        if (heightProperties[name] || widthProperties[name]){
            if (!/^0\S*$/.test(event.value) && !(name === "border" && event.value.toString() === "none")){
                properties[name] = { line: event.property.line, col: event.property.col, value: event.value };
            }
        } else {
            if (/^(width|height)/i.test(name) && /^(length|percentage)/.test(event.value.parts[0].type)){
                properties[name] = 1;
            } else if (name === "box-sizing") {
                boxSizing = true;
            }
        }

    });

    parser.addListener("endrule", endRule);
    parser.addListener("endfontface", endRule);
    parser.addListener("endpage", endRule);
    parser.addListener("endpagemargin", endRule);
    parser.addListener("endkeyframerule", endRule);
}

});

CSSLint.addRule({

id: "box-sizing",
name: "Disallow use of box-sizing",
desc: "The box-sizing properties isn't supported in IE6 and IE7.",
browsers: "IE6, IE7",
tags: ["Compatibility"],
init: function(parser, reporter){
    var rule = this;

    parser.addListener("property", function(event){
        var name = event.property.text.toLowerCase();

        if (name === "box-sizing"){
            reporter.report("The box-sizing property isn't supported in IE6 and IE7.", event.line, event.col, rule);
        }
    });
}

});

CSSLint.addRule({

id: "bulletproof-font-face",
name: "Use the bulletproof @font-face syntax",
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).",
browsers: "All",
init: function(parser, reporter){
    var rule = this,
        fontFaceRule = false,
        firstSrc     = true,
        ruleFailed    = false,
        line, col;
    parser.addListener("startfontface", function(){
        fontFaceRule = true;
    });

    parser.addListener("property", function(event){
        if (!fontFaceRule) {
            return;
        }

        var propertyName = event.property.toString().toLowerCase(),
            value        = event.value.toString();
        line = event.line;
        col  = event.col;
        if (propertyName === "src") {
            var regex = /^\s?url\(['"].+\.eot\?.*['"]\)\s*format\(['"]embedded-opentype['"]\).*$/i;
            if (!value.match(regex) && firstSrc) {
                ruleFailed = true;
                firstSrc = false;
            } else if (value.match(regex) && !firstSrc) {
                ruleFailed = false;
            }
        }

    });
    parser.addListener("endfontface", function(){
        fontFaceRule = false;

        if (ruleFailed) {
            reporter.report("@font-face declaration doesn't follow the fontspring bulletproof syntax.", line, col, rule);
        }
    });
}

});

CSSLint.addRule({

id: "compatible-vendor-prefixes",
name: "Require compatible vendor prefixes",
desc: "Include all compatible vendor prefixes to reach a wider range of users.",
browsers: "All",
init: function (parser, reporter) {
    var rule = this,
        compatiblePrefixes,
        properties,
        prop,
        variations,
        prefixed,
        i,
        len,
        inKeyFrame = false,
        arrayPush = Array.prototype.push,
        applyTo = [];
    compatiblePrefixes = {
        "animation"                  : "webkit moz",
        "animation-delay"            : "webkit moz",
        "animation-direction"        : "webkit moz",
        "animation-duration"         : "webkit moz",
        "animation-fill-mode"        : "webkit moz",
        "animation-iteration-count"  : "webkit moz",
        "animation-name"             : "webkit moz",
        "animation-play-state"       : "webkit moz",
        "animation-timing-function"  : "webkit moz",
        "appearance"                 : "webkit moz",
        "border-end"                 : "webkit moz",
        "border-end-color"           : "webkit moz",
        "border-end-style"           : "webkit moz",
        "border-end-width"           : "webkit moz",
        "border-image"               : "webkit moz o",
        "border-radius"              : "webkit",
        "border-start"               : "webkit moz",
        "border-start-color"         : "webkit moz",
        "border-start-style"         : "webkit moz",
        "border-start-width"         : "webkit moz",
        "box-align"                  : "webkit moz ms",
        "box-direction"              : "webkit moz ms",
        "box-flex"                   : "webkit moz ms",
        "box-lines"                  : "webkit ms",
        "box-ordinal-group"          : "webkit moz ms",
        "box-orient"                 : "webkit moz ms",
        "box-pack"                   : "webkit moz ms",
        "box-sizing"                 : "webkit moz",
        "box-shadow"                 : "webkit moz",
        "column-count"               : "webkit moz ms",
        "column-gap"                 : "webkit moz ms",
        "column-rule"                : "webkit moz ms",
        "column-rule-color"          : "webkit moz ms",
        "column-rule-style"          : "webkit moz ms",
        "column-rule-width"          : "webkit moz ms",
        "column-width"               : "webkit moz ms",
        "hyphens"                    : "epub moz",
        "line-break"                 : "webkit ms",
        "margin-end"                 : "webkit moz",
        "margin-start"               : "webkit moz",
        "marquee-speed"              : "webkit wap",
        "marquee-style"              : "webkit wap",
        "padding-end"                : "webkit moz",
        "padding-start"              : "webkit moz",
        "tab-size"                   : "moz o",
        "text-size-adjust"           : "webkit ms",
        "transform"                  : "webkit moz ms o",
        "transform-origin"           : "webkit moz ms o",
        "transition"                 : "webkit moz o",
        "transition-delay"           : "webkit moz o",
        "transition-duration"        : "webkit moz o",
        "transition-property"        : "webkit moz o",
        "transition-timing-function" : "webkit moz o",
        "user-modify"                : "webkit moz",
        "user-select"                : "webkit moz ms",
        "word-break"                 : "epub ms",
        "writing-mode"               : "epub ms"
    };

    for (prop in compatiblePrefixes) {
        if (compatiblePrefixes.hasOwnProperty(prop)) {
            variations = [];
            prefixed = compatiblePrefixes[prop].split(" ");
            for (i = 0, len = prefixed.length; i < len; i++) {
                variations.push("-" + prefixed[i] + "-" + prop);
            }
            compatiblePrefixes[prop] = variations;
            arrayPush.apply(applyTo, variations);
        }
    }

    parser.addListener("startrule", function () {
        properties = [];
    });

    parser.addListener("startkeyframes", function (event) {
        inKeyFrame = event.prefix || true;
    });

    parser.addListener("endkeyframes", function () {
        inKeyFrame = false;
    });

    parser.addListener("property", function (event) {
        var name = event.property;
        if (CSSLint.Util.indexOf(applyTo, name.text) > -1) {
            if (!inKeyFrame || typeof inKeyFrame !== "string" ||
                    name.text.indexOf("-" + inKeyFrame + "-") !== 0) {
                properties.push(name);
            }
        }
    });

    parser.addListener("endrule", function () {
        if (!properties.length) {
            return;
        }

        var propertyGroups = {},
            i,
            len,
            name,
            prop,
            variations,
            value,
            full,
            actual,
            item,
            propertiesSpecified;

        for (i = 0, len = properties.length; i < len; i++) {
            name = properties[i];

            for (prop in compatiblePrefixes) {
                if (compatiblePrefixes.hasOwnProperty(prop)) {
                    variations = compatiblePrefixes[prop];
                    if (CSSLint.Util.indexOf(variations, name.text) > -1) {
                        if (!propertyGroups[prop]) {
                            propertyGroups[prop] = {
                                full : variations.slice(0),
                                actual : [],
                                actualNodes: []
                            };
                        }
                        if (CSSLint.Util.indexOf(propertyGroups[prop].actual, name.text) === -1) {
                            propertyGroups[prop].actual.push(name.text);
                            propertyGroups[prop].actualNodes.push(name);
                        }
                    }
                }
            }
        }

        for (prop in propertyGroups) {
            if (propertyGroups.hasOwnProperty(prop)) {
                value = propertyGroups[prop];
                full = value.full;
                actual = value.actual;

                if (full.length > actual.length) {
                    for (i = 0, len = full.length; i < len; i++) {
                        item = full[i];
                        if (CSSLint.Util.indexOf(actual, item) === -1) {
                            propertiesSpecified = (actual.length === 1) ? actual[0] : (actual.length === 2) ? actual.join(" and ") : actual.join(", ");
                            reporter.report("The property " + item + " is compatible with " + propertiesSpecified + " and should be included as well.", value.actualNodes[0].line, value.actualNodes[0].col, rule);
                        }
                    }

                }
            }
        }
    });
}

});

CSSLint.addRule({

id: "display-property-grouping",
name: "Require properties appropriate for display",
desc: "Certain properties shouldn't be used with certain display property values.",
browsers: "All",
init: function(parser, reporter){
    var rule = this;

    var propertiesToCheck = {
            display: 1,
            "float": "none",
            height: 1,
            width: 1,
            margin: 1,
            "margin-left": 1,
            "margin-right": 1,
            "margin-bottom": 1,
            "margin-top": 1,
            padding: 1,
            "padding-left": 1,
            "padding-right": 1,
            "padding-bottom": 1,
            "padding-top": 1,
            "vertical-align": 1
        },
        properties;

    function reportProperty(name, display, msg){
        if (properties[name]){
            if (typeof propertiesToCheck[name] !== "string" || properties[name].value.toLowerCase() !== propertiesToCheck[name]){
                reporter.report(msg || name + " can't be used with display: " + display + ".", properties[name].line, properties[name].col, rule);
            }
        }
    }

    function startRule(){
        properties = {};
    }

    function endRule(){

        var display = properties.display ? properties.display.value : null;
        if (display){
            switch(display){

                case "inline":
                    reportProperty("height", display);
                    reportProperty("width", display);
                    reportProperty("margin", display);
                    reportProperty("margin-top", display);
                    reportProperty("margin-bottom", display);
                    reportProperty("float", display, "display:inline has no effect on floated elements (but may be used to fix the IE6 double-margin bug).");
                    break;

                case "block":
                    reportProperty("vertical-align", display);
                    break;

                case "inline-block":
                    reportProperty("float", display);
                    break;

                default:
                    if (display.indexOf("table-") === 0){
                        reportProperty("margin", display);
                        reportProperty("margin-left", display);
                        reportProperty("margin-right", display);
                        reportProperty("margin-top", display);
                        reportProperty("margin-bottom", display);
                        reportProperty("float", display);
                    }
            }
        }

    }

    parser.addListener("startrule", startRule);
    parser.addListener("startfontface", startRule);
    parser.addListener("startkeyframerule", startRule);
    parser.addListener("startpagemargin", startRule);
    parser.addListener("startpage", startRule);

    parser.addListener("property", function(event){
        var name = event.property.text.toLowerCase();

        if (propertiesToCheck[name]){
            properties[name] = { value: event.value.text, line: event.property.line, col: event.property.col };
        }
    });

    parser.addListener("endrule", endRule);
    parser.addListener("endfontface", endRule);
    parser.addListener("endkeyframerule", endRule);
    parser.addListener("endpagemargin", endRule);
    parser.addListener("endpage", endRule);

}

});

CSSLint.addRule({

id: "duplicate-background-images",
name: "Disallow duplicate background images",
desc: "Every background-image should be unique. Use a common class for e.g. sprites.",
browsers: "All",
init: function(parser, reporter){
    var rule = this,
        stack = {};

    parser.addListener("property", function(event){
        var name = event.property.text,
            value = event.value,
            i, len;

        if (name.match(/background/i)) {
            for (i=0, len=value.parts.length; i < len; i++) {
                if (value.parts[i].type === "uri") {
                    if (typeof stack[value.parts[i].uri] === "undefined") {
                        stack[value.parts[i].uri] = event;
                    }
                    else {
                        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);
                    }
                }
            }
        }
    });
}

});

CSSLint.addRule({

id: "duplicate-properties",
name: "Disallow duplicate properties",
desc: "Duplicate properties must appear one after the other.",
browsers: "All",
init: function(parser, reporter){
    var rule = this,
        properties,
        lastProperty;

    function startRule(){
        properties = {};
    }

    parser.addListener("startrule", startRule);
    parser.addListener("startfontface", startRule);
    parser.addListener("startpage", startRule);
    parser.addListener("startpagemargin", startRule);
    parser.addListener("startkeyframerule", startRule);

    parser.addListener("property", function(event){
        var property = event.property,
            name = property.text.toLowerCase();

        if (properties[name] && (lastProperty !== name || properties[name] === event.value.text)){
            reporter.report("Duplicate property '" + event.property + "' found.", event.line, event.col, rule);
        }

        properties[name] = event.value.text;
        lastProperty = name;

    });

}

});

CSSLint.addRule({

id: "empty-rules",
name: "Disallow empty rules",
desc: "Rules without any properties specified should be removed.",
browsers: "All",
init: function(parser, reporter){
    var rule = this,
        count = 0;

    parser.addListener("startrule", function(){
        count=0;
    });

    parser.addListener("property", function(){
        count++;
    });

    parser.addListener("endrule", function(event){
        var selectors = event.selectors;
        if (count === 0){
            reporter.report("Rule is empty.", selectors[0].line, selectors[0].col, rule);
        }
    });
}

});

CSSLint.addRule({

id: "errors",
name: "Parsing Errors",
desc: "This rule looks for recoverable syntax errors.",
browsers: "All",
init: function(parser, reporter){
    var rule = this;

    parser.addListener("error", function(event){
        reporter.error(event.message, event.line, event.col, rule);
    });

}

});

CSSLint.addRule({

id: "fallback-colors",
name: "Require fallback colors",
desc: "For older browsers that don't support RGBA, HSL, or HSLA, provide a fallback color.",
browsers: "IE6,IE7,IE8",
init: function(parser, reporter){
    var rule = this,
        lastProperty,
        propertiesToCheck = {
            color: 1,
            background: 1,
            "border-color": 1,
            "border-top-color": 1,
            "border-right-color": 1,
            "border-bottom-color": 1,
            "border-left-color": 1,
            border: 1,
            "border-top": 1,
            "border-right": 1,
            "border-bottom": 1,
            "border-left": 1,
            "background-color": 1
        },
        properties;

    function startRule(){
        properties = {};
        lastProperty = null;
    }

    parser.addListener("startrule", startRule);
    parser.addListener("startfontface", startRule);
    parser.addListener("startpage", startRule);
    parser.addListener("startpagemargin", startRule);
    parser.addListener("startkeyframerule", startRule);

    parser.addListener("property", function(event){
        var property = event.property,
            name = property.text.toLowerCase(),
            parts = event.value.parts,
            i = 0,
            colorType = "",
            len = parts.length;

        if(propertiesToCheck[name]){
            while(i < len){
                if (parts[i].type === "color"){
                    if ("alpha" in parts[i] || "hue" in parts[i]){

                        if (/([^\)]+)\(/.test(parts[i])){
                            colorType = RegExp.$1.toUpperCase();
                        }

                        if (!lastProperty || (lastProperty.property.text.toLowerCase() !== name || lastProperty.colorType !== "compat")){
                            reporter.report("Fallback " + name + " (hex or RGB) should precede " + colorType + " " + name + ".", event.line, event.col, rule);
                        }
                    } else {
                        event.colorType = "compat";
                    }
                }

                i++;
            }
        }

        lastProperty = event;
    });

}

});

CSSLint.addRule({

id: "floats",
name: "Disallow too many floats",
desc: "This rule tests if the float property is used too many times",
browsers: "All",
init: function(parser, reporter){
    var rule = this;
    var count = 0;
    parser.addListener("property", function(event){
        if (event.property.text.toLowerCase() === "float" &&
                event.value.text.toLowerCase() !== "none"){
            count++;
        }
    });
    parser.addListener("endstylesheet", function(){
        reporter.stat("floats", count);
        if (count >= 10){
            reporter.rollupWarn("Too many floats (" + count + "), you're probably using them for layout. Consider using a grid system instead.", rule);
        }
    });
}

});

CSSLint.addRule({

id: "font-faces",
name: "Don't use too many web fonts",
desc: "Too many different web fonts in the same stylesheet.",
browsers: "All",
init: function(parser, reporter){
    var rule = this,
        count = 0;

    parser.addListener("startfontface", function(){
        count++;
    });

    parser.addListener("endstylesheet", function(){
        if (count > 5){
            reporter.rollupWarn("Too many @font-face declarations (" + count + ").", rule);
        }
    });
}

});

CSSLint.addRule({

id: "font-sizes",
name: "Disallow too many font sizes",
desc: "Checks the number of font-size declarations.",
browsers: "All",
init: function(parser, reporter){
    var rule = this,
        count = 0;
    parser.addListener("property", function(event){
        if (event.property.toString() === "font-size"){
            count++;
        }
    });
    parser.addListener("endstylesheet", function(){
        reporter.stat("font-sizes", count);
        if (count >= 10){
            reporter.rollupWarn("Too many font-size declarations (" + count + "), abstraction needed.", rule);
        }
    });
}

});

CSSLint.addRule({

id: "gradients",
name: "Require all gradient definitions",
desc: "When using a vendor-prefixed gradient, make sure to use them all.",
browsers: "All",
init: function(parser, reporter){
    var rule = this,
        gradients;

    parser.addListener("startrule", function(){
        gradients = {
            moz: 0,
            webkit: 0,
            oldWebkit: 0,
            o: 0
        };
    });

    parser.addListener("property", function(event){

        if (/\-(moz|o|webkit)(?:\-(?:linear|radial))\-gradient/i.test(event.value)){
            gradients[RegExp.$1] = 1;
        } else if (/\-webkit\-gradient/i.test(event.value)){
            gradients.oldWebkit = 1;
        }

    });

    parser.addListener("endrule", function(event){
        var missing = [];

        if (!gradients.moz){
            missing.push("Firefox 3.6+");
        }

        if (!gradients.webkit){
            missing.push("Webkit (Safari 5+, Chrome)");
        }

        if (!gradients.oldWebkit){
            missing.push("Old Webkit (Safari 4+, Chrome)");
        }

        if (!gradients.o){
            missing.push("Opera 11.1+");
        }

        if (missing.length && missing.length < 4){
            reporter.report("Missing vendor-prefixed CSS gradients for " + missing.join(", ") + ".", event.selectors[0].line, event.selectors[0].col, rule);
        }

    });

}

});

CSSLint.addRule({

id: "ids",
name: "Disallow IDs in selectors",
desc: "Selectors should not contain IDs.",
browsers: "All",
init: function(parser, reporter){
    var rule = this;
    parser.addListener("startrule", function(event){
        var selectors = event.selectors,
            selector,
            part,
            modifier,
            idCount,
            i, j, k;

        for (i=0; i < selectors.length; i++){
            selector = selectors[i];
            idCount = 0;

            for (j=0; j < selector.parts.length; j++){
                part = selector.parts[j];
                if (part.type === parser.SELECTOR_PART_TYPE){
                    for (k=0; k < part.modifiers.length; k++){
                        modifier = part.modifiers[k];
                        if (modifier.type === "id"){
                            idCount++;
                        }
                    }
                }
            }

            if (idCount === 1){
                reporter.report("Don't use IDs in selectors.", selector.line, selector.col, rule);
            } else if (idCount > 1){
                reporter.report(idCount + " IDs in the selector, really?", selector.line, selector.col, rule);
            }
        }

    });
}

});

CSSLint.addRule({

id: "import",
name: "Disallow @import",
desc: "Don't use @import, use <link> instead.",
browsers: "All",
init: function(parser, reporter){
    var rule = this;

    parser.addListener("import", function(event){
        reporter.report("@import prevents parallel downloads, use <link> instead.", event.line, event.col, rule);
    });

}

});

CSSLint.addRule({

id: "important",
name: "Disallow !important",
desc: "Be careful when using !important declaration",
browsers: "All",
init: function(parser, reporter){
    var rule = this,
        count = 0;
    parser.addListener("property", function(event){
        if (event.important === true){
            count++;
            reporter.report("Use of !important", event.line, event.col, rule);
        }
    });
    parser.addListener("endstylesheet", function(){
        reporter.stat("important", count);
        if (count >= 10){
            reporter.rollupWarn("Too many !important declarations (" + count + "), try to use less than 10 to avoid specificity issues.", rule);
        }
    });
}

});

CSSLint.addRule({

id: "known-properties",
name: "Require use of known properties",
desc: "Properties should be known (listed in CSS3 specification) or be a vendor-prefixed property.",
browsers: "All",
init: function(parser, reporter){
    var rule = this;

    parser.addListener("property", function(event){
        if (event.invalid) {
            reporter.report(event.invalid.message, event.line, event.col, rule);
        }

    });
}

}); CSSLint.addRule({

id: "order-alphabetical",
name: "Alphabetical order",
desc: "Assure properties are in alphabetical order",
browsers: "All",
init: function(parser, reporter){
    var rule = this,
        properties;

    var startRule = function () {
        properties = [];
    };

    parser.addListener("startrule", startRule);
    parser.addListener("startfontface", startRule);
    parser.addListener("startpage", startRule);
    parser.addListener("startpagemargin", startRule);
    parser.addListener("startkeyframerule", startRule);

    parser.addListener("property", function(event){
        var name = event.property.text,
            lowerCasePrefixLessName = name.toLowerCase().replace(/^-.*?-/, "");

        properties.push(lowerCasePrefixLessName);
    });

    parser.addListener("endrule", function(event){
        var currentProperties = properties.join(","),
            expectedProperties = properties.sort().join(",");

        if (currentProperties !== expectedProperties){
            reporter.report("Rule doesn't have all its properties in alphabetical ordered.", event.line, event.col, rule);
        }
    });
}

});

CSSLint.addRule({

id: "outline-none",
name: "Disallow outline: none",
desc: "Use of outline: none or outline: 0 should be limited to :focus rules.",
browsers: "All",
tags: ["Accessibility"],
init: function(parser, reporter){
    var rule = this,
        lastRule;

    function startRule(event){
        if (event.selectors){
            lastRule = {
                line: event.line,
                col: event.col,
                selectors: event.selectors,
                propCount: 0,
                outline: false
            };
        } else {
            lastRule = null;
        }
    }

    function endRule(){
        if (lastRule){
            if (lastRule.outline){
                if (lastRule.selectors.toString().toLowerCase().indexOf(":focus") === -1){
                    reporter.report("Outlines should only be modified using :focus.", lastRule.line, lastRule.col, rule);
                } else if (lastRule.propCount === 1) {
                    reporter.report("Outlines shouldn't be hidden unless other visual changes are made.", lastRule.line, lastRule.col, rule);
                }
            }
        }
    }

    parser.addListener("startrule", startRule);
    parser.addListener("startfontface", startRule);
    parser.addListener("startpage", startRule);
    parser.addListener("startpagemargin", startRule);
    parser.addListener("startkeyframerule", startRule);

    parser.addListener("property", function(event){
        var name = event.property.text.toLowerCase(),
            value = event.value;

        if (lastRule){
            lastRule.propCount++;
            if (name === "outline" && (value.toString() === "none" || value.toString() === "0")){
                lastRule.outline = true;
            }
        }

    });

    parser.addListener("endrule", endRule);
    parser.addListener("endfontface", endRule);
    parser.addListener("endpage", endRule);
    parser.addListener("endpagemargin", endRule);
    parser.addListener("endkeyframerule", endRule);

}

});

CSSLint.addRule({

id: "overqualified-elements",
name: "Disallow overqualified elements",
desc: "Don't use classes or IDs with elements (a.foo or a#foo).",
browsers: "All",
init: function(parser, reporter){
    var rule = this,
        classes = {};

    parser.addListener("startrule", function(event){
        var selectors = event.selectors,
            selector,
            part,
            modifier,
            i, j, k;

        for (i=0; i < selectors.length; i++){
            selector = selectors[i];

            for (j=0; j < selector.parts.length; j++){
                part = selector.parts[j];
                if (part.type === parser.SELECTOR_PART_TYPE){
                    for (k=0; k < part.modifiers.length; k++){
                        modifier = part.modifiers[k];
                        if (part.elementName && modifier.type === "id"){
                            reporter.report("Element (" + part + ") is overqualified, just use " + modifier + " without element name.", part.line, part.col, rule);
                        } else if (modifier.type === "class"){

                            if (!classes[modifier]){
                                classes[modifier] = [];
                            }
                            classes[modifier].push({ modifier: modifier, part: part });
                        }
                    }
                }
            }
        }
    });

    parser.addListener("endstylesheet", function(){

        var prop;
        for (prop in classes){
            if (classes.hasOwnProperty(prop)){
                if (classes[prop].length === 1 && classes[prop][0].part.elementName){
                    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);
                }
            }
        }
    });
}

});

CSSLint.addRule({

id: "qualified-headings",
name: "Disallow qualified headings",
desc: "Headings should not be qualified (namespaced).",
browsers: "All",
init: function(parser, reporter){
    var rule = this;

    parser.addListener("startrule", function(event){
        var selectors = event.selectors,
            selector,
            part,
            i, j;

        for (i=0; i < selectors.length; i++){
            selector = selectors[i];

            for (j=0; j < selector.parts.length; j++){
                part = selector.parts[j];
                if (part.type === parser.SELECTOR_PART_TYPE){
                    if (part.elementName && /h[1-6]/.test(part.elementName.toString()) && j > 0){
                        reporter.report("Heading (" + part.elementName + ") should not be qualified.", part.line, part.col, rule);
                    }
                }
            }
        }
    });
}

});

CSSLint.addRule({

id: "regex-selectors",
name: "Disallow selectors that look like regexs",
desc: "Selectors that look like regular expressions are slow and should be avoided.",
browsers: "All",
init: function(parser, reporter){
    var rule = this;

    parser.addListener("startrule", function(event){
        var selectors = event.selectors,
            selector,
            part,
            modifier,
            i, j, k;

        for (i=0; i < selectors.length; i++){
            selector = selectors[i];
            for (j=0; j < selector.parts.length; j++){
                part = selector.parts[j];
                if (part.type === parser.SELECTOR_PART_TYPE){
                    for (k=0; k < part.modifiers.length; k++){
                        modifier = part.modifiers[k];
                        if (modifier.type === "attribute"){
                            if (/([\~\|\^\$\*]=)/.test(modifier)){
                                reporter.report("Attribute selectors with " + RegExp.$1 + " are slow!", modifier.line, modifier.col, rule);
                            }
                        }

                    }
                }
            }
        }
    });
}

});

CSSLint.addRule({

id: "rules-count",
name: "Rules Count",
desc: "Track how many rules there are.",
browsers: "All",
init: function(parser, reporter){
    var count = 0;
    parser.addListener("startrule", function(){
        count++;
    });

    parser.addListener("endstylesheet", function(){
        reporter.stat("rule-count", count);
    });
}

});

CSSLint.addRule({

id: "selector-max-approaching",
name: "Warn when approaching the 4095 selector limit for IE",
desc: "Will warn when selector count is >= 3800 selectors.",
browsers: "IE",
init: function(parser, reporter) {
    var rule = this, count = 0;

    parser.addListener("startrule", function(event) {
        count += event.selectors.length;
    });

    parser.addListener("endstylesheet", function() {
        if (count >= 3800) {
            reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,rule);
        }
    });
}

});

CSSLint.addRule({

id: "selector-max",
name: "Error when past the 4095 selector limit for IE",
desc: "Will error when selector count is > 4095.",
browsers: "IE",
init: function(parser, reporter){
    var rule = this, count = 0;

    parser.addListener("startrule", function(event) {
        count += event.selectors.length;
    });

    parser.addListener("endstylesheet", function() {
        if (count > 4095) {
            reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,rule);
        }
    });
}

});

CSSLint.addRule({

id: "selector-newline",
name: "Disallow new-line characters in selectors",
desc: "New-line characters in selectors are usually a forgotten comma and not a descendant combinator.",
browsers: "All",
init: function(parser, reporter) {
    var rule = this;

    function startRule(event) {
        var i, len, selector, p, n, pLen, part, part2, type, currentLine, nextLine,
            selectors = event.selectors;

        for (i = 0, len = selectors.length; i < len; i++) {
            selector = selectors[i];
            for (p = 0, pLen = selector.parts.length; p < pLen; p++) {
                for (n = p + 1; n < pLen; n++) {
                    part = selector.parts[p];
                    part2 = selector.parts[n];
                    type = part.type;
                    currentLine = part.line;
                    nextLine = part2.line;

                    if (type === "descendant" && nextLine > currentLine) {
                        reporter.report("newline character found in selector (forgot a comma?)", currentLine, selectors[i].parts[0].col, rule);
                    }
                }
            }

        }
    }

    parser.addListener("startrule", startRule);

}

});

CSSLint.addRule({

id: "shorthand",
name: "Require shorthand properties",
desc: "Use shorthand properties where possible.",
browsers: "All",
init: function(parser, reporter){
    var rule = this,
        prop, i, len,
        propertiesToCheck = {},
        properties,
        mapping = {
            "margin": [
                "margin-top",
                "margin-bottom",
                "margin-left",
                "margin-right"
            ],
            "padding": [
                "padding-top",
                "padding-bottom",
                "padding-left",
                "padding-right"
            ]
        };
    for (prop in mapping){
        if (mapping.hasOwnProperty(prop)){
            for (i=0, len=mapping[prop].length; i < len; i++){
                propertiesToCheck[mapping[prop][i]] = prop;
            }
        }
    }

    function startRule(){
        properties = {};
    }
    function endRule(event){

        var prop, i, len, total;
        for (prop in mapping){
            if (mapping.hasOwnProperty(prop)){
                total=0;

                for (i=0, len=mapping[prop].length; i < len; i++){
                    total += properties[mapping[prop][i]] ? 1 : 0;
                }

                if (total === mapping[prop].length){
                    reporter.report("The properties " + mapping[prop].join(", ") + " can be replaced by " + prop + ".", event.line, event.col, rule);
                }
            }
        }
    }

    parser.addListener("startrule", startRule);
    parser.addListener("startfontface", startRule);
    parser.addListener("property", function(event){
        var name = event.property.toString().toLowerCase();

        if (propertiesToCheck[name]){
            properties[name] = 1;
        }
    });

    parser.addListener("endrule", endRule);
    parser.addListener("endfontface", endRule);

}

});

CSSLint.addRule({

id: "star-property-hack",
name: "Disallow properties with a star prefix",
desc: "Checks for the star property hack (targets IE6/7)",
browsers: "All",
init: function(parser, reporter){
    var rule = this;
    parser.addListener("property", function(event){
        var property = event.property;

        if (property.hack === "*") {
            reporter.report("Property with star prefix found.", event.property.line, event.property.col, rule);
        }
    });
}

});

CSSLint.addRule({

id: "text-indent",
name: "Disallow negative text-indent",
desc: "Checks for text indent less than -99px",
browsers: "All",
init: function(parser, reporter){
    var rule = this,
        textIndent,
        direction;

    function startRule(){
        textIndent = false;
        direction = "inherit";
    }
    function endRule(){
        if (textIndent && direction !== "ltr"){
            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);
        }
    }

    parser.addListener("startrule", startRule);
    parser.addListener("startfontface", startRule);
    parser.addListener("property", function(event){
        var name = event.property.toString().toLowerCase(),
            value = event.value;

        if (name === "text-indent" && value.parts[0].value < -99){
            textIndent = event.property;
        } else if (name === "direction" && value.toString() === "ltr"){
            direction = "ltr";
        }
    });

    parser.addListener("endrule", endRule);
    parser.addListener("endfontface", endRule);

}

});

CSSLint.addRule({

id: "underscore-property-hack",
name: "Disallow properties with an underscore prefix",
desc: "Checks for the underscore property hack (targets IE6)",
browsers: "All",
init: function(parser, reporter){
    var rule = this;
    parser.addListener("property", function(event){
        var property = event.property;

        if (property.hack === "_") {
            reporter.report("Property with underscore prefix found.", event.property.line, event.property.col, rule);
        }
    });
}

});

CSSLint.addRule({

id: "unique-headings",
name: "Headings should only be defined once",
desc: "Headings should be defined only once.",
browsers: "All",
init: function(parser, reporter){
    var rule = this;

    var headings = {
            h1: 0,
            h2: 0,
            h3: 0,
            h4: 0,
            h5: 0,
            h6: 0
        };

    parser.addListener("startrule", function(event){
        var selectors = event.selectors,
            selector,
            part,
            pseudo,
            i, j;

        for (i=0; i < selectors.length; i++){
            selector = selectors[i];
            part = selector.parts[selector.parts.length-1];

            if (part.elementName && /(h[1-6])/i.test(part.elementName.toString())){

                for (j=0; j < part.modifiers.length; j++){
                    if (part.modifiers[j].type === "pseudo"){
                        pseudo = true;
                        break;
                    }
                }

                if (!pseudo){
                    headings[RegExp.$1]++;
                    if (headings[RegExp.$1] > 1) {
                        reporter.report("Heading (" + part.elementName + ") has already been defined.", part.line, part.col, rule);
                    }
                }
            }
        }
    });

    parser.addListener("endstylesheet", function(){
        var prop,
            messages = [];

        for (prop in headings){
            if (headings.hasOwnProperty(prop)){
                if (headings[prop] > 1){
                    messages.push(headings[prop] + " " + prop + "s");
                }
            }
        }

        if (messages.length){
            reporter.rollupWarn("You have " + messages.join(", ") + " defined in this stylesheet.", rule);
        }
    });
}

});

CSSLint.addRule({

id: "universal-selector",
name: "Disallow universal selector",
desc: "The universal selector (*) is known to be slow.",
browsers: "All",
init: function(parser, reporter){
    var rule = this;

    parser.addListener("startrule", function(event){
        var selectors = event.selectors,
            selector,
            part,
            i;

        for (i=0; i < selectors.length; i++){
            selector = selectors[i];

            part = selector.parts[selector.parts.length-1];
            if (part.elementName === "*"){
                reporter.report(rule.desc, part.line, part.col, rule);
            }
        }
    });
}

});

CSSLint.addRule({

id: "unqualified-attributes",
name: "Disallow unqualified attribute selectors",
desc: "Unqualified attribute selectors are known to be slow.",
browsers: "All",
init: function(parser, reporter){
    var rule = this;

    parser.addListener("startrule", function(event){

        var selectors = event.selectors,
            selector,
            part,
            modifier,
            i, k;

        for (i=0; i < selectors.length; i++){
            selector = selectors[i];

            part = selector.parts[selector.parts.length-1];
            if (part.type === parser.SELECTOR_PART_TYPE){
                for (k=0; k < part.modifiers.length; k++){
                    modifier = part.modifiers[k];
                    if (modifier.type === "attribute" && (!part.elementName || part.elementName === "*")){
                        reporter.report(rule.desc, part.line, part.col, rule);
                    }
                }
            }

        }
    });
}

});

CSSLint.addRule({

id: "vendor-prefix",
name: "Require standard property with vendor prefix",
desc: "When using a vendor-prefixed property, make sure to include the standard one.",
browsers: "All",
init: function(parser, reporter){
    var rule = this,
        properties,
        num,
        propertiesToCheck = {
            "-webkit-border-radius": "border-radius",
            "-webkit-border-top-left-radius": "border-top-left-radius",
            "-webkit-border-top-right-radius": "border-top-right-radius",
            "-webkit-border-bottom-left-radius": "border-bottom-left-radius",
            "-webkit-border-bottom-right-radius": "border-bottom-right-radius",

            "-o-border-radius": "border-radius",
            "-o-border-top-left-radius": "border-top-left-radius",
            "-o-border-top-right-radius": "border-top-right-radius",
            "-o-border-bottom-left-radius": "border-bottom-left-radius",
            "-o-border-bottom-right-radius": "border-bottom-right-radius",

            "-moz-border-radius": "border-radius",
            "-moz-border-radius-topleft": "border-top-left-radius",
            "-moz-border-radius-topright": "border-top-right-radius",
            "-moz-border-radius-bottomleft": "border-bottom-left-radius",
            "-moz-border-radius-bottomright": "border-bottom-right-radius",

            "-moz-column-count": "column-count",
            "-webkit-column-count": "column-count",

            "-moz-column-gap": "column-gap",
            "-webkit-column-gap": "column-gap",

            "-moz-column-rule": "column-rule",
            "-webkit-column-rule": "column-rule",

            "-moz-column-rule-style": "column-rule-style",
            "-webkit-column-rule-style": "column-rule-style",

            "-moz-column-rule-color": "column-rule-color",
            "-webkit-column-rule-color": "column-rule-color",

            "-moz-column-rule-width": "column-rule-width",
            "-webkit-column-rule-width": "column-rule-width",

            "-moz-column-width": "column-width",
            "-webkit-column-width": "column-width",

            "-webkit-column-span": "column-span",
            "-webkit-columns": "columns",

            "-moz-box-shadow": "box-shadow",
            "-webkit-box-shadow": "box-shadow",

            "-moz-transform" : "transform",
            "-webkit-transform" : "transform",
            "-o-transform" : "transform",
            "-ms-transform" : "transform",

            "-moz-transform-origin" : "transform-origin",
            "-webkit-transform-origin" : "transform-origin",
            "-o-transform-origin" : "transform-origin",
            "-ms-transform-origin" : "transform-origin",

            "-moz-box-sizing" : "box-sizing",
            "-webkit-box-sizing" : "box-sizing"
        };
    function startRule(){
        properties = {};
        num = 1;
    }
    function endRule(){
        var prop,
            i,
            len,
            needed,
            actual,
            needsStandard = [];

        for (prop in properties){
            if (propertiesToCheck[prop]){
                needsStandard.push({ actual: prop, needed: propertiesToCheck[prop]});
            }
        }

        for (i=0, len=needsStandard.length; i < len; i++){
            needed = needsStandard[i].needed;
            actual = needsStandard[i].actual;

            if (!properties[needed]){
                reporter.report("Missing standard property '" + needed + "' to go along with '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);
            } else {
                if (properties[needed][0].pos < properties[actual][0].pos){
                    reporter.report("Standard property '" + needed + "' should come after vendor-prefixed property '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);
                }
            }
        }

    }

    parser.addListener("startrule", startRule);
    parser.addListener("startfontface", startRule);
    parser.addListener("startpage", startRule);
    parser.addListener("startpagemargin", startRule);
    parser.addListener("startkeyframerule", startRule);

    parser.addListener("property", function(event){
        var name = event.property.text.toLowerCase();

        if (!properties[name]){
            properties[name] = [];
        }

        properties[name].push({ name: event.property, value : event.value, pos:num++ });
    });

    parser.addListener("endrule", endRule);
    parser.addListener("endfontface", endRule);
    parser.addListener("endpage", endRule);
    parser.addListener("endpagemargin", endRule);
    parser.addListener("endkeyframerule", endRule);
}

});

CSSLint.addRule({

id: "zero-units",
name: "Disallow units for 0 values",
desc: "You don't need to specify units when a value is 0.",
browsers: "All",
init: function(parser, reporter){
    var rule = this;
    parser.addListener("property", function(event){
        var parts = event.value.parts,
            i = 0,
            len = parts.length;

        while(i < len){
            if ((parts[i].units || parts[i].type === "percentage") && parts[i].value === 0 && parts[i].type !== "time"){
                reporter.report("Values of 0 shouldn't have units specified.", parts[i].line, parts[i].col, rule);
            }
            i++;
        }

    });

}

});

(function() {

var xmlEscape = function(str) {
    if (!str || str.constructor !== String) {
        return "";
    }

    return str.replace(/[\"&><]/g, function(match) {
        switch (match) {
            case "\"":
                return "&quot;";
            case "&":
                return "&amp;";
            case "<":
                return "&lt;";
            case ">":
                return "&gt;";
        }
    });
};

CSSLint.addFormatter({
    id: "checkstyle-xml",
    name: "Checkstyle XML format",
    startFormat: function(){
        return "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>";
    },
    endFormat: function(){
        return "</checkstyle>";
    },
    readError: function(filename, message) {
        return "<file name=\"" + xmlEscape(filename) + "\"><error line=\"0\" column=\"0\" severty=\"error\" message=\"" + xmlEscape(message) + "\"></error></file>";
    },
    formatResults: function(results, filename/*, options*/) {
        var messages = results.messages,
            output = [];
        var generateSource = function(rule) {
            if (!rule || !("name" in rule)) {
                return "";
            }
            return "net.csslint." + rule.name.replace(/\s/g,"");
        };

        if (messages.length > 0) {
            output.push("<file name=\""+filename+"\">");
            CSSLint.Util.forEach(messages, function (message) {
                if (!message.rollup) {
                    output.push("<error line=\"" + message.line + "\" column=\"" + message.col + "\" severity=\"" + message.type + "\"" +
                      " message=\"" + xmlEscape(message.message) + "\" source=\"" + generateSource(message.rule) +"\"/>");
                }
            });
            output.push("</file>");
        }

        return output.join("");
    }
});

}());

CSSLint.addFormatter({

id: "compact",
name: "Compact, 'porcelain' format",
startFormat: function() {
    return "";
},
endFormat: function() {
    return "";
},
formatResults: function(results, filename, options) {
    var messages = results.messages,
        output = "";
    options = options || {};
    var capitalize = function(str) {
        return str.charAt(0).toUpperCase() + str.slice(1);
    };

    if (messages.length === 0) {
          return options.quiet ? "" : filename + ": Lint Free!";
    }

    CSSLint.Util.forEach(messages, function(message) {
        if (message.rollup) {
            output += filename + ": " + capitalize(message.type) + " - " + message.message + "\n";
        } else {
            output += filename + ": " + "line " + message.line +
                ", col " + message.col + ", " + capitalize(message.type) + " - " + message.message + " (" + message.rule.id + ")\n";
        }
    });

    return output;
}

});

CSSLint.addFormatter({

id: "csslint-xml",
name: "CSSLint XML format",
startFormat: function(){
    return "<?xml version=\"1.0\" encoding=\"utf-8\"?><csslint>";
},
endFormat: function(){
    return "</csslint>";
},
formatResults: function(results, filename/*, options*/) {
    var messages = results.messages,
        output = [];
    var escapeSpecialCharacters = function(str) {
        if (!str || str.constructor !== String) {
            return "";
        }
        return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
    };

    if (messages.length > 0) {
        output.push("<file name=\""+filename+"\">");
        CSSLint.Util.forEach(messages, function (message) {
            if (message.rollup) {
                output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
            } else {
                output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" +
                    " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
            }
        });
        output.push("</file>");
    }

    return output.join("");
}

});

CSSLint.addFormatter({

id: "junit-xml",
name: "JUNIT XML format",
startFormat: function(){
    return "<?xml version=\"1.0\" encoding=\"utf-8\"?><testsuites>";
},
endFormat: function() {
    return "</testsuites>";
},
formatResults: function(results, filename/*, options*/) {

    var messages = results.messages,
        output = [],
        tests = {
            "error": 0,
            "failure": 0
        };
    var generateSource = function(rule) {
        if (!rule || !("name" in rule)) {
            return "";
        }
        return "net.csslint." + rule.name.replace(/\s/g,"");
    };
    var escapeSpecialCharacters = function(str) {

        if (!str || str.constructor !== String) {
            return "";
        }

        return str.replace(/\"/g, "'").replace(/</g, "&lt;").replace(/>/g, "&gt;");

    };

    if (messages.length > 0) {

        messages.forEach(function (message) {
            var type = message.type === "warning" ? "error" : message.type;
            if (!message.rollup) {
                output.push("<testcase time=\"0\" name=\"" + generateSource(message.rule) + "\">");
                output.push("<" + type + " message=\"" + escapeSpecialCharacters(message.message) + "\"><![CDATA[" + message.line + ":" + message.col + ":" + escapeSpecialCharacters(message.evidence)  + "]]></" + type + ">");
                output.push("</testcase>");

                tests[type] += 1;

            }

        });

        output.unshift("<testsuite time=\"0\" tests=\"" + messages.length + "\" skipped=\"0\" errors=\"" + tests.error + "\" failures=\"" + tests.failure + "\" package=\"net.csslint\" name=\"" + filename + "\">");
        output.push("</testsuite>");

    }

    return output.join("");

}

});

CSSLint.addFormatter({

id: "lint-xml",
name: "Lint XML format",
startFormat: function(){
    return "<?xml version=\"1.0\" encoding=\"utf-8\"?><lint>";
},
endFormat: function(){
    return "</lint>";
},
formatResults: function(results, filename/*, options*/) {
    var messages = results.messages,
        output = [];
    var escapeSpecialCharacters = function(str) {
        if (!str || str.constructor !== String) {
            return "";
        }
        return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
    };

    if (messages.length > 0) {

        output.push("<file name=\""+filename+"\">");
        CSSLint.Util.forEach(messages, function (message) {
            if (message.rollup) {
                output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
            } else {
                output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" +
                    " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
            }
        });
        output.push("</file>");
    }

    return output.join("");
}

});

CSSLint.addFormatter({

id: "text",
name: "Plain Text",
startFormat: function() {
    return "";
},
endFormat: function() {
    return "";
},
formatResults: function(results, filename, options) {
    var messages = results.messages,
        output = "";
    options = options || {};

    if (messages.length === 0) {
        return options.quiet ? "" : "\n\ncsslint: No errors in " + filename + ".";
    }

    output = "\n\ncsslint: There ";
    if (messages.length === 1) {
        output += "is 1 problem";
    } else {
        output += "are " + messages.length  +  " problems";
    }
    output += " in " + filename + ".";

    var pos = filename.lastIndexOf("/"),
        shortFilename = filename;

    if (pos === -1){
        pos = filename.lastIndexOf("\\");
    }
    if (pos > -1){
        shortFilename = filename.substring(pos+1);
    }

    CSSLint.Util.forEach(messages, function (message, i) {
        output = output + "\n\n" + shortFilename;
        if (message.rollup) {
            output += "\n" + (i+1) + ": " + message.type;
            output += "\n" + message.message;
        } else {
            output += "\n" + (i+1) + ": " + message.type + " at line " + message.line + ", col " + message.col;
            output += "\n" + message.message;
            output += "\n" + message.evidence;
        }
    });

    return output;
}

});

module.exports.CSSLint = CSSLint;

});

ace.define(“ace/mode/css_worker”,, function(require, exports, module) { “use strict”;

var oop = require(“../lib/oop”); var lang = require(“../lib/lang”); var Mirror = require(“../worker/mirror”).Mirror; var CSSLint = require(“./css/csslint”).CSSLint;

var Worker = exports.Worker = function(sender) {

Mirror.call(this, sender);
this.setTimeout(400);
this.ruleset = null;
this.setDisabledRules("ids|order-alphabetical");
this.setInfoRules(
  "adjoining-classes|qualified-headings|zero-units|gradients|" +
  "import|outline-none|vendor-prefix"
);

};

oop.inherits(Worker, Mirror);

(function() {

this.setInfoRules = function(ruleNames) {
    if (typeof ruleNames == "string")
        ruleNames = ruleNames.split("|");
    this.infoRules = lang.arrayToMap(ruleNames);
    this.doc.getValue() && this.deferredUpdate.schedule(100);
};

this.setDisabledRules = function(ruleNames) {
    if (!ruleNames) {
        this.ruleset = null;
    } else {
        if (typeof ruleNames == "string")
            ruleNames = ruleNames.split("|");
        var all = {};

        CSSLint.getRules().forEach(function(x){
            all[x.id] = true;
        });
        ruleNames.forEach(function(x) {
            delete all[x];
        });

        this.ruleset = all;
    }
    this.doc.getValue() && this.deferredUpdate.schedule(100);
};

this.onUpdate = function() {
    var value = this.doc.getValue();
    if (!value)
        return this.sender.emit("csslint", []);
    var infoRules = this.infoRules;

    var result = CSSLint.verify(value, this.ruleset);
    this.sender.emit("csslint", result.messages.map(function(msg) {
        return {
            row: msg.line - 1,
            column: msg.col - 1,
            text: msg.message,
            type: infoRules[msg.rule.id] ? "info" : msg.type,
            rule: msg.rule.name
        }
    }));
};

}).call(Worker.prototype);

});

ace.define(“ace/lib/es5-shim”,, function(require, exports, module) {

function Empty() {}

if (!Function.prototype.bind) {

Function.prototype.bind = function bind(that) { // .length is 1
    var target = this;
    if (typeof target != "function") {
        throw new TypeError("Function.prototype.bind called on incompatible " + target);
    }
    var args = slice.call(arguments, 1); // for normal call
    var bound = function () {

        if (this instanceof bound) {

            var result = target.apply(
                this,
                args.concat(slice.call(arguments))
            );
            if (Object(result) === result) {
                return result;
            }
            return this;

        } else {
            return target.apply(
                that,
                args.concat(slice.call(arguments))
            );

        }

    };
    if(target.prototype) {
        Empty.prototype = target.prototype;
        bound.prototype = new Empty();
        Empty.prototype = null;
    }
    return bound;
};

} var call = Function.prototype.call; var prototypeOfArray = Array.prototype; var prototypeOfObject = Object.prototype; var slice = prototypeOfArray.slice; var _toString = call.bind(prototypeOfObject.toString); var owns = call.bind(prototypeOfObject.hasOwnProperty); var defineGetter; var defineSetter; var lookupGetter; var lookupSetter; var supportsAccessors; if ((supportsAccessors = owns(prototypeOfObject, “__defineGetter__”))) {

defineGetter = call.bind(prototypeOfObject.__defineGetter__);
defineSetter = call.bind(prototypeOfObject.__defineSetter__);
lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);

} if ([1,2].splice(0).length != 2) {

if(function() { // test IE < 9 to splice bug - see issue #138
    function makeArray(l) {
        var a = new Array(l+2);
        a[0] = a[1] = 0;
        return a;
    }
    var array = [], lengthBefore;

    array.splice.apply(array, makeArray(20));
    array.splice.apply(array, makeArray(26));

    lengthBefore = array.length; //46
    array.splice(5, 0, "XXX"); // add one element

    lengthBefore + 1 == array.length

    if (lengthBefore + 1 == array.length) {
        return true;// has right splice implementation without bugs
    }
}()) {//IE 6/7
    var array_splice = Array.prototype.splice;
    Array.prototype.splice = function(start, deleteCount) {
        if (!arguments.length) {
            return [];
        } else {
            return array_splice.apply(this, [
                start === void 0 ? 0 : start,
                deleteCount === void 0 ? (this.length - start) : deleteCount
            ].concat(slice.call(arguments, 2)))
        }
    };
} else {//IE8
    Array.prototype.splice = function(pos, removeCount){
        var length = this.length;
        if (pos > 0) {
            if (pos > length)
                pos = length;
        } else if (pos == void 0) {
            pos = 0;
        } else if (pos < 0) {
            pos = Math.max(length + pos, 0);
        }

        if (!(pos+removeCount < length))
            removeCount = length - pos;

        var removed = this.slice(pos, pos+removeCount);
        var insert = slice.call(arguments, 2);
        var add = insert.length;            
        if (pos === length) {
            if (add) {
                this.push.apply(this, insert);
            }
        } else {
            var remove = Math.min(removeCount, length - pos);
            var tailOldPos = pos + remove;
            var tailNewPos = tailOldPos + add - remove;
            var tailCount = length - tailOldPos;
            var lengthAfterRemove = length - remove;

            if (tailNewPos < tailOldPos) { // case A
                for (var i = 0; i < tailCount; ++i) {
                    this[tailNewPos+i] = this[tailOldPos+i];
                }
            } else if (tailNewPos > tailOldPos) { // case B
                for (i = tailCount; i--; ) {
                    this[tailNewPos+i] = this[tailOldPos+i];
                }
            } // else, add == remove (nothing to do)

            if (add && pos === lengthAfterRemove) {
                this.length = lengthAfterRemove; // truncate array
                this.push.apply(this, insert);
            } else {
                this.length = lengthAfterRemove + add; // reserves space
                for (i = 0; i < add; ++i) {
                    this[pos+i] = insert[i];
                }
            }
        }
        return removed;
    };
}

} if (!Array.isArray) {

Array.isArray = function isArray(obj) {
    return _toString(obj) == "[object Array]";
};

} var boxedString = Object(“a”),

splitString = boxedString[0] != "a" || !(0 in boxedString);

if (!Array.prototype.forEach) {

Array.prototype.forEach = function forEach(fun /*, thisp*/) {
    var object = toObject(this),
        self = splitString && _toString(this) == "[object String]" ?
            this.split("") :
            object,
        thisp = arguments[1],
        i = -1,
        length = self.length >>> 0;
    if (_toString(fun) != "[object Function]") {
        throw new TypeError(); // TODO message
    }

    while (++i < length) {
        if (i in self) {
            fun.call(thisp, self[i], i, object);
        }
    }
};

} if (!Array.prototype.map) {

Array.prototype.map = function map(fun /*, thisp*/) {
    var object = toObject(this),
        self = splitString && _toString(this) == "[object String]" ?
            this.split("") :
            object,
        length = self.length >>> 0,
        result = Array(length),
        thisp = arguments[1];
    if (_toString(fun) != "[object Function]") {
        throw new TypeError(fun + " is not a function");
    }

    for (var i = 0; i < length; i++) {
        if (i in self)
            result[i] = fun.call(thisp, self[i], i, object);
    }
    return result;
};

} if (!Array.prototype.filter) {

Array.prototype.filter = function filter(fun /*, thisp */) {
    var object = toObject(this),
        self = splitString && _toString(this) == "[object String]" ?
            this.split("") :
                object,
        length = self.length >>> 0,
        result = [],
        value,
        thisp = arguments[1];
    if (_toString(fun) != "[object Function]") {
        throw new TypeError(fun + " is not a function");
    }

    for (var i = 0; i < length; i++) {
        if (i in self) {
            value = self[i];
            if (fun.call(thisp, value, i, object)) {
                result.push(value);
            }
        }
    }
    return result;
};

} if (!Array.prototype.every) {

Array.prototype.every = function every(fun /*, thisp */) {
    var object = toObject(this),
        self = splitString && _toString(this) == "[object String]" ?
            this.split("") :
            object,
        length = self.length >>> 0,
        thisp = arguments[1];
    if (_toString(fun) != "[object Function]") {
        throw new TypeError(fun + " is not a function");
    }

    for (var i = 0; i < length; i++) {
        if (i in self && !fun.call(thisp, self[i], i, object)) {
            return false;
        }
    }
    return true;
};

} if (!Array.prototype.some) {

Array.prototype.some = function some(fun /*, thisp */) {
    var object = toObject(this),
        self = splitString && _toString(this) == "[object String]" ?
            this.split("") :
            object,
        length = self.length >>> 0,
        thisp = arguments[1];
    if (_toString(fun) != "[object Function]") {
        throw new TypeError(fun + " is not a function");
    }

    for (var i = 0; i < length; i++) {
        if (i in self && fun.call(thisp, self[i], i, object)) {
            return true;
        }
    }
    return false;
};

} if (!Array.prototype.reduce) {

Array.prototype.reduce = function reduce(fun /*, initial*/) {
    var object = toObject(this),
        self = splitString && _toString(this) == "[object String]" ?
            this.split("") :
            object,
        length = self.length >>> 0;
    if (_toString(fun) != "[object Function]") {
        throw new TypeError(fun + " is not a function");
    }
    if (!length && arguments.length == 1) {
        throw new TypeError("reduce of empty array with no initial value");
    }

    var i = 0;
    var result;
    if (arguments.length >= 2) {
        result = arguments[1];
    } else {
        do {
            if (i in self) {
                result = self[i++];
                break;
            }
            if (++i >= length) {
                throw new TypeError("reduce of empty array with no initial value");
            }
        } while (true);
    }

    for (; i < length; i++) {
        if (i in self) {
            result = fun.call(void 0, result, self[i], i, object);
        }
    }

    return result;
};

} if (!Array.prototype.reduceRight) {

Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) {
    var object = toObject(this),
        self = splitString && _toString(this) == "[object String]" ?
            this.split("") :
            object,
        length = self.length >>> 0;
    if (_toString(fun) != "[object Function]") {
        throw new TypeError(fun + " is not a function");
    }
    if (!length && arguments.length == 1) {
        throw new TypeError("reduceRight of empty array with no initial value");
    }

    var result, i = length - 1;
    if (arguments.length >= 2) {
        result = arguments[1];
    } else {
        do {
            if (i in self) {
                result = self[i--];
                break;
            }
            if (--i < 0) {
                throw new TypeError("reduceRight of empty array with no initial value");
            }
        } while (true);
    }

    do {
        if (i in this) {
            result = fun.call(void 0, result, self[i], i, object);
        }
    } while (i--);

    return result;
};

} if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) {

Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
    var self = splitString && _toString(this) == "[object String]" ?
            this.split("") :
            toObject(this),
        length = self.length >>> 0;

    if (!length) {
        return -1;
    }

    var i = 0;
    if (arguments.length > 1) {
        i = toInteger(arguments[1]);
    }
    i = i >= 0 ? i : Math.max(0, length + i);
    for (; i < length; i++) {
        if (i in self && self[i] === sought) {
            return i;
        }
    }
    return -1;
};

} if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) {

Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) {
    var self = splitString && _toString(this) == "[object String]" ?
            this.split("") :
            toObject(this),
        length = self.length >>> 0;

    if (!length) {
        return -1;
    }
    var i = length - 1;
    if (arguments.length > 1) {
        i = Math.min(i, toInteger(arguments[1]));
    }
    i = i >= 0 ? i : length - Math.abs(i);
    for (; i >= 0; i--) {
        if (i in self && sought === self[i]) {
            return i;
        }
    }
    return -1;
};

} if (!Object.getPrototypeOf) {

Object.getPrototypeOf = function getPrototypeOf(object) {
    return object.__proto__ || (
        object.constructor ?
        object.constructor.prototype :
        prototypeOfObject
    );
};

} if (!Object.getOwnPropertyDescriptor) {

var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " +
                     "non-object: ";
Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) {
    if ((typeof object != "object" && typeof object != "function") || object === null)
        throw new TypeError(ERR_NON_OBJECT + object);
    if (!owns(object, property))
        return;

    var descriptor, getter, setter;
    descriptor =  { enumerable: true, configurable: true };
    if (supportsAccessors) {
        var prototype = object.__proto__;
        object.__proto__ = prototypeOfObject;

        var getter = lookupGetter(object, property);
        var setter = lookupSetter(object, property);
        object.__proto__ = prototype;

        if (getter || setter) {
            if (getter) descriptor.get = getter;
            if (setter) descriptor.set = setter;
            return descriptor;
        }
    }
    descriptor.value = object[property];
    return descriptor;
};

} if (!Object.getOwnPropertyNames) {

Object.getOwnPropertyNames = function getOwnPropertyNames(object) {
    return Object.keys(object);
};

} if (!Object.create) {

var createEmpty;
if (Object.prototype.__proto__ === null) {
    createEmpty = function () {
        return { "__proto__": null };
    };
} else {
    createEmpty = function () {
        var empty = {};
        for (var i in empty)
            empty[i] = null;
        empty.constructor =
        empty.hasOwnProperty =
        empty.propertyIsEnumerable =
        empty.isPrototypeOf =
        empty.toLocaleString =
        empty.toString =
        empty.valueOf =
        empty.__proto__ = null;
        return empty;
    }
}

Object.create = function create(prototype, properties) {
    var object;
    if (prototype === null) {
        object = createEmpty();
    } else {
        if (typeof prototype != "object")
            throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'");
        var Type = function () {};
        Type.prototype = prototype;
        object = new Type();
        object.__proto__ = prototype;
    }
    if (properties !== void 0)
        Object.defineProperties(object, properties);
    return object;
};

}

function doesDefinePropertyWork(object) {

try {
    Object.defineProperty(object, "sentinel", {});
    return "sentinel" in object;
} catch (exception) {
}

} if (Object.defineProperty) {

var definePropertyWorksOnObject = doesDefinePropertyWork({});
var definePropertyWorksOnDom = typeof document == "undefined" ||
    doesDefinePropertyWork(document.createElement("div"));
if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) {
    var definePropertyFallback = Object.defineProperty;
}

}

if (!Object.defineProperty || definePropertyFallback) {

var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: ";
var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: "
var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " +
                                  "on this javascript engine";

Object.defineProperty = function defineProperty(object, property, descriptor) {
    if ((typeof object != "object" && typeof object != "function") || object === null)
        throw new TypeError(ERR_NON_OBJECT_TARGET + object);
    if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null)
        throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);
    if (definePropertyFallback) {
        try {
            return definePropertyFallback.call(Object, object, property, descriptor);
        } catch (exception) {
        }
    }
    if (owns(descriptor, "value")) {

        if (supportsAccessors && (lookupGetter(object, property) ||
                                  lookupSetter(object, property)))
        {
            var prototype = object.__proto__;
            object.__proto__ = prototypeOfObject;
            delete object[property];
            object[property] = descriptor.value;
            object.__proto__ = prototype;
        } else {
            object[property] = descriptor.value;
        }
    } else {
        if (!supportsAccessors)
            throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
        if (owns(descriptor, "get"))
            defineGetter(object, property, descriptor.get);
        if (owns(descriptor, "set"))
            defineSetter(object, property, descriptor.set);
    }

    return object;
};

} if (!Object.defineProperties) {

Object.defineProperties = function defineProperties(object, properties) {
    for (var property in properties) {
        if (owns(properties, property))
            Object.defineProperty(object, property, properties[property]);
    }
    return object;
};

} if (!Object.seal) {

Object.seal = function seal(object) {
    return object;
};

} if (!Object.freeze) {

Object.freeze = function freeze(object) {
    return object;
};

} try {

Object.freeze(function () {});

} catch (exception) {

Object.freeze = (function freeze(freezeObject) {
    return function freeze(object) {
        if (typeof object == "function") {
            return object;
        } else {
            return freezeObject(object);
        }
    };
})(Object.freeze);

} if (!Object.preventExtensions) {

Object.preventExtensions = function preventExtensions(object) {
    return object;
};

} if (!Object.isSealed) {

Object.isSealed = function isSealed(object) {
    return false;
};

} if (!Object.isFrozen) {

Object.isFrozen = function isFrozen(object) {
    return false;
};

} if (!Object.isExtensible) {

Object.isExtensible = function isExtensible(object) {
    if (Object(object) === object) {
        throw new TypeError(); // TODO message
    }
    var name = '';
    while (owns(object, name)) {
        name += '?';
    }
    object[name] = true;
    var returnValue = owns(object, name);
    delete object[name];
    return returnValue;
};

} if (!Object.keys) {

var hasDontEnumBug = true,
    dontEnums = [
        "toString",
        "toLocaleString",
        "valueOf",
        "hasOwnProperty",
        "isPrototypeOf",
        "propertyIsEnumerable",
        "constructor"
    ],
    dontEnumsLength = dontEnums.length;

for (var key in {"toString": null}) {
    hasDontEnumBug = false;
}

Object.keys = function keys(object) {

    if (
        (typeof object != "object" && typeof object != "function") ||
        object === null
    ) {
        throw new TypeError("Object.keys called on a non-object");
    }

    var keys = [];
    for (var name in object) {
        if (owns(object, name)) {
            keys.push(name);
        }
    }

    if (hasDontEnumBug) {
        for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
            var dontEnum = dontEnums[i];
            if (owns(object, dontEnum)) {
                keys.push(dontEnum);
            }
        }
    }
    return keys;
};

} if (!Date.now) {

Date.now = function now() {
    return new Date().getTime();
};

} var ws = “x09x0Ax0Bx0Cx0Dx20xA0u1680u180Eu2000u2001u2002u2003” +

"\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
"\u2029\uFEFF";

if (!String.prototype.trim || ws.trim()) {

ws = "[" + ws + "]";
var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
    trimEndRegexp = new RegExp(ws + ws + "*$");
String.prototype.trim = function trim() {
    return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
};

}

function toInteger(n) {

n = +n;
if (n !== n) { // isNaN
    n = 0;
} else if (n !== 0 && n !== (1/0) && n !== -(1/0)) {
    n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
return n;

}

function isPrimitive(input) {

var type = typeof input;
return (
    input === null ||
    type === "undefined" ||
    type === "boolean" ||
    type === "number" ||
    type === "string"
);

}

function toPrimitive(input) {

var val, valueOf, toString;
if (isPrimitive(input)) {
    return input;
}
valueOf = input.valueOf;
if (typeof valueOf === "function") {
    val = valueOf.call(input);
    if (isPrimitive(val)) {
        return val;
    }
}
toString = input.toString;
if (typeof toString === "function") {
    val = toString.call(input);
    if (isPrimitive(val)) {
        return val;
    }
}
throw new TypeError();

} var toObject = function (o) {

if (o == null) { // this matches both null and undefined
    throw new TypeError("can't convert "+o+" to object");
}
return Object(o);

};

});