corrade-nucleus-nucleons – Blame information for rev 20

Subversion Repositories:
Rev:
Rev Author Line No. Line
20 office 1 "no use strict";
2 ;(function(window) {
3 if (typeof window.window != "undefined" && window.document)
4 return;
5 if (window.require && window.define)
6 return;
7  
8 if (!window.console) {
9 window.console = function() {
10 var msgs = Array.prototype.slice.call(arguments, 0);
11 postMessage({type: "log", data: msgs});
12 };
13 window.console.error =
14 window.console.warn =
15 window.console.log =
16 window.console.trace = window.console;
17 }
18 window.window = window;
19 window.ace = window;
20  
21 window.onerror = function(message, file, line, col, err) {
22 postMessage({type: "error", data: {
23 message: message,
24 data: err.data,
25 file: file,
26 line: line,
27 col: col,
28 stack: err.stack
29 }});
30 };
31  
32 window.normalizeModule = function(parentId, moduleName) {
33 // normalize plugin requires
34 if (moduleName.indexOf("!") !== -1) {
35 var chunks = moduleName.split("!");
36 return window.normalizeModule(parentId, chunks[0]) + "!" + window.normalizeModule(parentId, chunks[1]);
37 }
38 // normalize relative requires
39 if (moduleName.charAt(0) == ".") {
40 var base = parentId.split("/").slice(0, -1).join("/");
41 moduleName = (base ? base + "/" : "") + moduleName;
42  
43 while (moduleName.indexOf(".") !== -1 && previous != moduleName) {
44 var previous = moduleName;
45 moduleName = moduleName.replace(/^\.\//, "").replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, "");
46 }
47 }
48  
49 return moduleName;
50 };
51  
52 window.require = function require(parentId, id) {
53 if (!id) {
54 id = parentId;
55 parentId = null;
56 }
57 if (!id.charAt)
58 throw new Error("worker.js require() accepts only (parentId, id) as arguments");
59  
60 id = window.normalizeModule(parentId, id);
61  
62 var module = window.require.modules[id];
63 if (module) {
64 if (!module.initialized) {
65 module.initialized = true;
66 module.exports = module.factory().exports;
67 }
68 return module.exports;
69 }
70  
71 if (!window.require.tlns)
72 return console.log("unable to load " + id);
73  
74 var path = resolveModuleId(id, window.require.tlns);
75 if (path.slice(-3) != ".js") path += ".js";
76  
77 window.require.id = id;
78 window.require.modules[id] = {}; // prevent infinite loop on broken modules
79 importScripts(path);
80 return window.require(parentId, id);
81 };
82 function resolveModuleId(id, paths) {
83 var testPath = id, tail = "";
84 while (testPath) {
85 var alias = paths[testPath];
86 if (typeof alias == "string") {
87 return alias + tail;
88 } else if (alias) {
89 return alias.location.replace(/\/*$/, "/") + (tail || alias.main || alias.name);
90 } else if (alias === false) {
91 return "";
92 }
93 var i = testPath.lastIndexOf("/");
94 if (i === -1) break;
95 tail = testPath.substr(i) + tail;
96 testPath = testPath.slice(0, i);
97 }
98 return id;
99 }
100 window.require.modules = {};
101 window.require.tlns = {};
102  
103 window.define = function(id, deps, factory) {
104 if (arguments.length == 2) {
105 factory = deps;
106 if (typeof id != "string") {
107 deps = id;
108 id = window.require.id;
109 }
110 } else if (arguments.length == 1) {
111 factory = id;
112 deps = [];
113 id = window.require.id;
114 }
115  
116 if (typeof factory != "function") {
117 window.require.modules[id] = {
118 exports: factory,
119 initialized: true
120 };
121 return;
122 }
123  
124 if (!deps.length)
125 // If there is no dependencies, we inject "require", "exports" and
126 // "module" as dependencies, to provide CommonJS compatibility.
127 deps = ["require", "exports", "module"];
128  
129 var req = function(childId) {
130 return window.require(id, childId);
131 };
132  
133 window.require.modules[id] = {
134 exports: {},
135 factory: function() {
136 var module = this;
137 var returnExports = factory.apply(this, deps.map(function(dep) {
138 switch (dep) {
139 // Because "require", "exports" and "module" aren't actual
140 // dependencies, we must handle them seperately.
141 case "require": return req;
142 case "exports": return module.exports;
143 case "module": return module;
144 // But for all other dependencies, we can just go ahead and
145 // require them.
146 default: return req(dep);
147 }
148 }));
149 if (returnExports)
150 module.exports = returnExports;
151 return module;
152 }
153 };
154 };
155 window.define.amd = {};
156 require.tlns = {};
157 window.initBaseUrls = function initBaseUrls(topLevelNamespaces) {
158 for (var i in topLevelNamespaces)
159 require.tlns[i] = topLevelNamespaces[i];
160 };
161  
162 window.initSender = function initSender() {
163  
164 var EventEmitter = window.require("ace/lib/event_emitter").EventEmitter;
165 var oop = window.require("ace/lib/oop");
166  
167 var Sender = function() {};
168  
169 (function() {
170  
171 oop.implement(this, EventEmitter);
172  
173 this.callback = function(data, callbackId) {
174 postMessage({
175 type: "call",
176 id: callbackId,
177 data: data
178 });
179 };
180  
181 this.emit = function(name, data) {
182 postMessage({
183 type: "event",
184 name: name,
185 data: data
186 });
187 };
188  
189 }).call(Sender.prototype);
190  
191 return new Sender();
192 };
193  
194 var main = window.main = null;
195 var sender = window.sender = null;
196  
197 window.onmessage = function(e) {
198 var msg = e.data;
199 if (msg.event && sender) {
200 sender._signal(msg.event, msg.data);
201 }
202 else if (msg.command) {
203 if (main[msg.command])
204 main[msg.command].apply(main, msg.args);
205 else if (window[msg.command])
206 window[msg.command].apply(window, msg.args);
207 else
208 throw new Error("Unknown command:" + msg.command);
209 }
210 else if (msg.init) {
211 window.initBaseUrls(msg.tlns);
212 require("ace/lib/es5-shim");
213 sender = window.sender = window.initSender();
214 var clazz = require(msg.module)[msg.classname];
215 main = window.main = new clazz(sender);
216 }
217 };
218 })(this);
219  
220 ace.define("ace/lib/oop",["require","exports","module"], function(require, exports, module) {
221 "use strict";
222  
223 exports.inherits = function(ctor, superCtor) {
224 ctor.super_ = superCtor;
225 ctor.prototype = Object.create(superCtor.prototype, {
226 constructor: {
227 value: ctor,
228 enumerable: false,
229 writable: true,
230 configurable: true
231 }
232 });
233 };
234  
235 exports.mixin = function(obj, mixin) {
236 for (var key in mixin) {
237 obj[key] = mixin[key];
238 }
239 return obj;
240 };
241  
242 exports.implement = function(proto, mixin) {
243 exports.mixin(proto, mixin);
244 };
245  
246 });
247  
248 ace.define("ace/lib/lang",["require","exports","module"], function(require, exports, module) {
249 "use strict";
250  
251 exports.last = function(a) {
252 return a[a.length - 1];
253 };
254  
255 exports.stringReverse = function(string) {
256 return string.split("").reverse().join("");
257 };
258  
259 exports.stringRepeat = function (string, count) {
260 var result = '';
261 while (count > 0) {
262 if (count & 1)
263 result += string;
264  
265 if (count >>= 1)
266 string += string;
267 }
268 return result;
269 };
270  
271 var trimBeginRegexp = /^\s\s*/;
272 var trimEndRegexp = /\s\s*$/;
273  
274 exports.stringTrimLeft = function (string) {
275 return string.replace(trimBeginRegexp, '');
276 };
277  
278 exports.stringTrimRight = function (string) {
279 return string.replace(trimEndRegexp, '');
280 };
281  
282 exports.copyObject = function(obj) {
283 var copy = {};
284 for (var key in obj) {
285 copy[key] = obj[key];
286 }
287 return copy;
288 };
289  
290 exports.copyArray = function(array){
291 var copy = [];
292 for (var i=0, l=array.length; i<l; i++) {
293 if (array[i] && typeof array[i] == "object")
294 copy[i] = this.copyObject(array[i]);
295 else
296 copy[i] = array[i];
297 }
298 return copy;
299 };
300  
301 exports.deepCopy = function deepCopy(obj) {
302 if (typeof obj !== "object" || !obj)
303 return obj;
304 var copy;
305 if (Array.isArray(obj)) {
306 copy = [];
307 for (var key = 0; key < obj.length; key++) {
308 copy[key] = deepCopy(obj[key]);
309 }
310 return copy;
311 }
312 if (Object.prototype.toString.call(obj) !== "[object Object]")
313 return obj;
314  
315 copy = {};
316 for (var key in obj)
317 copy[key] = deepCopy(obj[key]);
318 return copy;
319 };
320  
321 exports.arrayToMap = function(arr) {
322 var map = {};
323 for (var i=0; i<arr.length; i++) {
324 map[arr[i]] = 1;
325 }
326 return map;
327  
328 };
329  
330 exports.createMap = function(props) {
331 var map = Object.create(null);
332 for (var i in props) {
333 map[i] = props[i];
334 }
335 return map;
336 };
337 exports.arrayRemove = function(array, value) {
338 for (var i = 0; i <= array.length; i++) {
339 if (value === array[i]) {
340 array.splice(i, 1);
341 }
342 }
343 };
344  
345 exports.escapeRegExp = function(str) {
346 return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
347 };
348  
349 exports.escapeHTML = function(str) {
350 return str.replace(/&/g, "&#38;").replace(/"/g, "&#34;").replace(/'/g, "&#39;").replace(/g, "&#60;");
351 };
352  
353 exports.getMatchOffsets = function(string, regExp) {
354 var matches = [];
355  
356 string.replace(regExp, function(str) {
357 matches.push({
358 offset: arguments[arguments.length-2],
359 length: str.length
360 });
361 });
362  
363 return matches;
364 };
365 exports.deferredCall = function(fcn) {
366 var timer = null;
367 var callback = function() {
368 timer = null;
369 fcn();
370 };
371  
372 var deferred = function(timeout) {
373 deferred.cancel();
374 timer = setTimeout(callback, timeout || 0);
375 return deferred;
376 };
377  
378 deferred.schedule = deferred;
379  
380 deferred.call = function() {
381 this.cancel();
382 fcn();
383 return deferred;
384 };
385  
386 deferred.cancel = function() {
387 clearTimeout(timer);
388 timer = null;
389 return deferred;
390 };
391  
392 deferred.isPending = function() {
393 return timer;
394 };
395  
396 return deferred;
397 };
398  
399  
400 exports.delayedCall = function(fcn, defaultTimeout) {
401 var timer = null;
402 var callback = function() {
403 timer = null;
404 fcn();
405 };
406  
407 var _self = function(timeout) {
408 if (timer == null)
409 timer = setTimeout(callback, timeout || defaultTimeout);
410 };
411  
412 _self.delay = function(timeout) {
413 timer && clearTimeout(timer);
414 timer = setTimeout(callback, timeout || defaultTimeout);
415 };
416 _self.schedule = _self;
417  
418 _self.call = function() {
419 this.cancel();
420 fcn();
421 };
422  
423 _self.cancel = function() {
424 timer && clearTimeout(timer);
425 timer = null;
426 };
427  
428 _self.isPending = function() {
429 return timer;
430 };
431  
432 return _self;
433 };
434 });
435  
436 ace.define("ace/range",["require","exports","module"], function(require, exports, module) {
437 "use strict";
438 var comparePoints = function(p1, p2) {
439 return p1.row - p2.row || p1.column - p2.column;
440 };
441 var Range = function(startRow, startColumn, endRow, endColumn) {
442 this.start = {
443 row: startRow,
444 column: startColumn
445 };
446  
447 this.end = {
448 row: endRow,
449 column: endColumn
450 };
451 };
452  
453 (function() {
454 this.isEqual = function(range) {
455 return this.start.row === range.start.row &&
456 this.end.row === range.end.row &&
457 this.start.column === range.start.column &&
458 this.end.column === range.end.column;
459 };
460 this.toString = function() {
461 return ("Range: [" + this.start.row + "/" + this.start.column +
462 "] -> [" + this.end.row + "/" + this.end.column + "]");
463 };
464  
465 this.contains = function(row, column) {
466 return this.compare(row, column) == 0;
467 };
468 this.compareRange = function(range) {
469 var cmp,
470 end = range.end,
471 start = range.start;
472  
473 cmp = this.compare(end.row, end.column);
474 if (cmp == 1) {
475 cmp = this.compare(start.row, start.column);
476 if (cmp == 1) {
477 return 2;
478 } else if (cmp == 0) {
479 return 1;
480 } else {
481 return 0;
482 }
483 } else if (cmp == -1) {
484 return -2;
485 } else {
486 cmp = this.compare(start.row, start.column);
487 if (cmp == -1) {
488 return -1;
489 } else if (cmp == 1) {
490 return 42;
491 } else {
492 return 0;
493 }
494 }
495 };
496 this.comparePoint = function(p) {
497 return this.compare(p.row, p.column);
498 };
499 this.containsRange = function(range) {
500 return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0;
501 };
502 this.intersects = function(range) {
503 var cmp = this.compareRange(range);
504 return (cmp == -1 || cmp == 0 || cmp == 1);
505 };
506 this.isEnd = function(row, column) {
507 return this.end.row == row && this.end.column == column;
508 };
509 this.isStart = function(row, column) {
510 return this.start.row == row && this.start.column == column;
511 };
512 this.setStart = function(row, column) {
513 if (typeof row == "object") {
514 this.start.column = row.column;
515 this.start.row = row.row;
516 } else {
517 this.start.row = row;
518 this.start.column = column;
519 }
520 };
521 this.setEnd = function(row, column) {
522 if (typeof row == "object") {
523 this.end.column = row.column;
524 this.end.row = row.row;
525 } else {
526 this.end.row = row;
527 this.end.column = column;
528 }
529 };
530 this.inside = function(row, column) {
531 if (this.compare(row, column) == 0) {
532 if (this.isEnd(row, column) || this.isStart(row, column)) {
533 return false;
534 } else {
535 return true;
536 }
537 }
538 return false;
539 };
540 this.insideStart = function(row, column) {
541 if (this.compare(row, column) == 0) {
542 if (this.isEnd(row, column)) {
543 return false;
544 } else {
545 return true;
546 }
547 }
548 return false;
549 };
550 this.insideEnd = function(row, column) {
551 if (this.compare(row, column) == 0) {
552 if (this.isStart(row, column)) {
553 return false;
554 } else {
555 return true;
556 }
557 }
558 return false;
559 };
560 this.compare = function(row, column) {
561 if (!this.isMultiLine()) {
562 if (row === this.start.row) {
563 return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0);
564 }
565 }
566  
567 if (row < this.start.row)
568 return -1;
569  
570 if (row > this.end.row)
571 return 1;
572  
573 if (this.start.row === row)
574 return column >= this.start.column ? 0 : -1;
575  
576 if (this.end.row === row)
577 return column <= this.end.column ? 0 : 1;
578  
579 return 0;
580 };
581 this.compareStart = function(row, column) {
582 if (this.start.row == row && this.start.column == column) {
583 return -1;
584 } else {
585 return this.compare(row, column);
586 }
587 };
588 this.compareEnd = function(row, column) {
589 if (this.end.row == row && this.end.column == column) {
590 return 1;
591 } else {
592 return this.compare(row, column);
593 }
594 };
595 this.compareInside = function(row, column) {
596 if (this.end.row == row && this.end.column == column) {
597 return 1;
598 } else if (this.start.row == row && this.start.column == column) {
599 return -1;
600 } else {
601 return this.compare(row, column);
602 }
603 };
604 this.clipRows = function(firstRow, lastRow) {
605 if (this.end.row > lastRow)
606 var end = {row: lastRow + 1, column: 0};
607 else if (this.end.row < firstRow)
608 var end = {row: firstRow, column: 0};
609  
610 if (this.start.row > lastRow)
611 var start = {row: lastRow + 1, column: 0};
612 else if (this.start.row < firstRow)
613 var start = {row: firstRow, column: 0};
614  
615 return Range.fromPoints(start || this.start, end || this.end);
616 };
617 this.extend = function(row, column) {
618 var cmp = this.compare(row, column);
619  
620 if (cmp == 0)
621 return this;
622 else if (cmp == -1)
623 var start = {row: row, column: column};
624 else
625 var end = {row: row, column: column};
626  
627 return Range.fromPoints(start || this.start, end || this.end);
628 };
629  
630 this.isEmpty = function() {
631 return (this.start.row === this.end.row && this.start.column === this.end.column);
632 };
633 this.isMultiLine = function() {
634 return (this.start.row !== this.end.row);
635 };
636 this.clone = function() {
637 return Range.fromPoints(this.start, this.end);
638 };
639 this.collapseRows = function() {
640 if (this.end.column == 0)
641 return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0)
642 else
643 return new Range(this.start.row, 0, this.end.row, 0)
644 };
645 this.toScreenRange = function(session) {
646 var screenPosStart = session.documentToScreenPosition(this.start);
647 var screenPosEnd = session.documentToScreenPosition(this.end);
648  
649 return new Range(
650 screenPosStart.row, screenPosStart.column,
651 screenPosEnd.row, screenPosEnd.column
652 );
653 };
654 this.moveBy = function(row, column) {
655 this.start.row += row;
656 this.start.column += column;
657 this.end.row += row;
658 this.end.column += column;
659 };
660  
661 }).call(Range.prototype);
662 Range.fromPoints = function(start, end) {
663 return new Range(start.row, start.column, end.row, end.column);
664 };
665 Range.comparePoints = comparePoints;
666  
667 Range.comparePoints = function(p1, p2) {
668 return p1.row - p2.row || p1.column - p2.column;
669 };
670  
671  
672 exports.Range = Range;
673 });
674  
675 ace.define("ace/apply_delta",["require","exports","module"], function(require, exports, module) {
676 "use strict";
677  
678 function throwDeltaError(delta, errorText){
679 console.log("Invalid Delta:", delta);
680 throw "Invalid Delta: " + errorText;
681 }
682  
683 function positionInDocument(docLines, position) {
684 return position.row >= 0 && position.row < docLines.length &&
685 position.column >= 0 && position.column <= docLines[position.row].length;
686 }
687  
688 function validateDelta(docLines, delta) {
689 if (delta.action != "insert" && delta.action != "remove")
690 throwDeltaError(delta, "delta.action must be 'insert' or 'remove'");
691 if (!(delta.lines instanceof Array))
692 throwDeltaError(delta, "delta.lines must be an Array");
693 if (!delta.start || !delta.end)
694 throwDeltaError(delta, "delta.start/end must be an present");
695 var start = delta.start;
696 if (!positionInDocument(docLines, delta.start))
697 throwDeltaError(delta, "delta.start must be contained in document");
698 var end = delta.end;
699 if (delta.action == "remove" && !positionInDocument(docLines, end))
700 throwDeltaError(delta, "delta.end must contained in document for 'remove' actions");
701 var numRangeRows = end.row - start.row;
702 var numRangeLastLineChars = (end.column - (numRangeRows == 0 ? start.column : 0));
703 if (numRangeRows != delta.lines.length - 1 || delta.lines[numRangeRows].length != numRangeLastLineChars)
704 throwDeltaError(delta, "delta.range must match delta lines");
705 }
706  
707 exports.applyDelta = function(docLines, delta, doNotValidate) {
708  
709 var row = delta.start.row;
710 var startColumn = delta.start.column;
711 var line = docLines[row] || "";
712 switch (delta.action) {
713 case "insert":
714 var lines = delta.lines;
715 if (lines.length === 1) {
716 docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn);
717 } else {
718 var args = [row, 1].concat(delta.lines);
719 docLines.splice.apply(docLines, args);
720 docLines[row] = line.substring(0, startColumn) + docLines[row];
721 docLines[row + delta.lines.length - 1] += line.substring(startColumn);
722 }
723 break;
724 case "remove":
725 var endColumn = delta.end.column;
726 var endRow = delta.end.row;
727 if (row === endRow) {
728 docLines[row] = line.substring(0, startColumn) + line.substring(endColumn);
729 } else {
730 docLines.splice(
731 row, endRow - row + 1,
732 line.substring(0, startColumn) + docLines[endRow].substring(endColumn)
733 );
734 }
735 break;
736 }
737 }
738 });
739  
740 ace.define("ace/lib/event_emitter",["require","exports","module"], function(require, exports, module) {
741 "use strict";
742  
743 var EventEmitter = {};
744 var stopPropagation = function() { this.propagationStopped = true; };
745 var preventDefault = function() { this.defaultPrevented = true; };
746  
747 EventEmitter._emit =
748 EventEmitter._dispatchEvent = function(eventName, e) {
749 this._eventRegistry || (this._eventRegistry = {});
750 this._defaultHandlers || (this._defaultHandlers = {});
751  
752 var listeners = this._eventRegistry[eventName] || [];
753 var defaultHandler = this._defaultHandlers[eventName];
754 if (!listeners.length && !defaultHandler)
755 return;
756  
757 if (typeof e != "object" || !e)
758 e = {};
759  
760 if (!e.type)
761 e.type = eventName;
762 if (!e.stopPropagation)
763 e.stopPropagation = stopPropagation;
764 if (!e.preventDefault)
765 e.preventDefault = preventDefault;
766  
767 listeners = listeners.slice();
768 for (var i=0; i<listeners.length; i++) {
769 listeners[i](e, this);
770 if (e.propagationStopped)
771 break;
772 }
773  
774 if (defaultHandler && !e.defaultPrevented)
775 return defaultHandler(e, this);
776 };
777  
778  
779 EventEmitter._signal = function(eventName, e) {
780 var listeners = (this._eventRegistry || {})[eventName];
781 if (!listeners)
782 return;
783 listeners = listeners.slice();
784 for (var i=0; i<listeners.length; i++)
785 listeners[i](e, this);
786 };
787  
788 EventEmitter.once = function(eventName, callback) {
789 var _self = this;
790 callback && this.addEventListener(eventName, function newCallback() {
791 _self.removeEventListener(eventName, newCallback);
792 callback.apply(null, arguments);
793 });
794 };
795  
796  
797 EventEmitter.setDefaultHandler = function(eventName, callback) {
798 var handlers = this._defaultHandlers
799 if (!handlers)
800 handlers = this._defaultHandlers = {_disabled_: {}};
801  
802 if (handlers[eventName]) {
803 var old = handlers[eventName];
804 var disabled = handlers._disabled_[eventName];
805 if (!disabled)
806 handlers._disabled_[eventName] = disabled = [];
807 disabled.push(old);
808 var i = disabled.indexOf(callback);
809 if (i != -1)
810 disabled.splice(i, 1);
811 }
812 handlers[eventName] = callback;
813 };
814 EventEmitter.removeDefaultHandler = function(eventName, callback) {
815 var handlers = this._defaultHandlers
816 if (!handlers)
817 return;
818 var disabled = handlers._disabled_[eventName];
819  
820 if (handlers[eventName] == callback) {
821 var old = handlers[eventName];
822 if (disabled)
823 this.setDefaultHandler(eventName, disabled.pop());
824 } else if (disabled) {
825 var i = disabled.indexOf(callback);
826 if (i != -1)
827 disabled.splice(i, 1);
828 }
829 };
830  
831 EventEmitter.on =
832 EventEmitter.addEventListener = function(eventName, callback, capturing) {
833 this._eventRegistry = this._eventRegistry || {};
834  
835 var listeners = this._eventRegistry[eventName];
836 if (!listeners)
837 listeners = this._eventRegistry[eventName] = [];
838  
839 if (listeners.indexOf(callback) == -1)
840 listeners[capturing ? "unshift" : "push"](callback);
841 return callback;
842 };
843  
844 EventEmitter.off =
845 EventEmitter.removeListener =
846 EventEmitter.removeEventListener = function(eventName, callback) {
847 this._eventRegistry = this._eventRegistry || {};
848  
849 var listeners = this._eventRegistry[eventName];
850 if (!listeners)
851 return;
852  
853 var index = listeners.indexOf(callback);
854 if (index !== -1)
855 listeners.splice(index, 1);
856 };
857  
858 EventEmitter.removeAllListeners = function(eventName) {
859 if (this._eventRegistry) this._eventRegistry[eventName] = [];
860 };
861  
862 exports.EventEmitter = EventEmitter;
863  
864 });
865  
866 ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"], function(require, exports, module) {
867 "use strict";
868  
869 var oop = require("./lib/oop");
870 var EventEmitter = require("./lib/event_emitter").EventEmitter;
871  
872 var Anchor = exports.Anchor = function(doc, row, column) {
873 this.$onChange = this.onChange.bind(this);
874 this.attach(doc);
875  
876 if (typeof column == "undefined")
877 this.setPosition(row.row, row.column);
878 else
879 this.setPosition(row, column);
880 };
881  
882 (function() {
883  
884 oop.implement(this, EventEmitter);
885 this.getPosition = function() {
886 return this.$clipPositionToDocument(this.row, this.column);
887 };
888 this.getDocument = function() {
889 return this.document;
890 };
891 this.$insertRight = false;
892 this.onChange = function(delta) {
893 if (delta.start.row == delta.end.row && delta.start.row != this.row)
894 return;
895  
896 if (delta.start.row > this.row)
897 return;
898  
899 var point = $getTransformedPoint(delta, {row: this.row, column: this.column}, this.$insertRight);
900 this.setPosition(point.row, point.column, true);
901 };
902  
903 function $pointsInOrder(point1, point2, equalPointsInOrder) {
904 var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column;
905 return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter);
906 }
907  
908 function $getTransformedPoint(delta, point, moveIfEqual) {
909 var deltaIsInsert = delta.action == "insert";
910 var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.end.row - delta.start.row);
911 var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.end.column - delta.start.column);
912 var deltaStart = delta.start;
913 var deltaEnd = deltaIsInsert ? deltaStart : delta.end; // Collapse insert range.
914 if ($pointsInOrder(point, deltaStart, moveIfEqual)) {
915 return {
916 row: point.row,
917 column: point.column
918 };
919 }
920 if ($pointsInOrder(deltaEnd, point, !moveIfEqual)) {
921 return {
922 row: point.row + deltaRowShift,
923 column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0)
924 };
925 }
926  
927 return {
928 row: deltaStart.row,
929 column: deltaStart.column
930 };
931 }
932 this.setPosition = function(row, column, noClip) {
933 var pos;
934 if (noClip) {
935 pos = {
936 row: row,
937 column: column
938 };
939 } else {
940 pos = this.$clipPositionToDocument(row, column);
941 }
942  
943 if (this.row == pos.row && this.column == pos.column)
944 return;
945  
946 var old = {
947 row: this.row,
948 column: this.column
949 };
950  
951 this.row = pos.row;
952 this.column = pos.column;
953 this._signal("change", {
954 old: old,
955 value: pos
956 });
957 };
958 this.detach = function() {
959 this.document.removeEventListener("change", this.$onChange);
960 };
961 this.attach = function(doc) {
962 this.document = doc || this.document;
963 this.document.on("change", this.$onChange);
964 };
965 this.$clipPositionToDocument = function(row, column) {
966 var pos = {};
967  
968 if (row >= this.document.getLength()) {
969 pos.row = Math.max(0, this.document.getLength() - 1);
970 pos.column = this.document.getLine(pos.row).length;
971 }
972 else if (row < 0) {
973 pos.row = 0;
974 pos.column = 0;
975 }
976 else {
977 pos.row = row;
978 pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column));
979 }
980  
981 if (column < 0)
982 pos.column = 0;
983  
984 return pos;
985 };
986  
987 }).call(Anchor.prototype);
988  
989 });
990  
991 ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"], function(require, exports, module) {
992 "use strict";
993  
994 var oop = require("./lib/oop");
995 var applyDelta = require("./apply_delta").applyDelta;
996 var EventEmitter = require("./lib/event_emitter").EventEmitter;
997 var Range = require("./range").Range;
998 var Anchor = require("./anchor").Anchor;
999  
1000 var Document = function(textOrLines) {
1001 this.$lines = [""];
1002 if (textOrLines.length === 0) {
1003 this.$lines = [""];
1004 } else if (Array.isArray(textOrLines)) {
1005 this.insertMergedLines({row: 0, column: 0}, textOrLines);
1006 } else {
1007 this.insert({row: 0, column:0}, textOrLines);
1008 }
1009 };
1010  
1011 (function() {
1012  
1013 oop.implement(this, EventEmitter);
1014 this.setValue = function(text) {
1015 var len = this.getLength() - 1;
1016 this.remove(new Range(0, 0, len, this.getLine(len).length));
1017 this.insert({row: 0, column: 0}, text);
1018 };
1019 this.getValue = function() {
1020 return this.getAllLines().join(this.getNewLineCharacter());
1021 };
1022 this.createAnchor = function(row, column) {
1023 return new Anchor(this, row, column);
1024 };
1025 if ("aaa".split(/a/).length === 0) {
1026 this.$split = function(text) {
1027 return text.replace(/\r\n|\r/g, "\n").split("\n");
1028 };
1029 } else {
1030 this.$split = function(text) {
1031 return text.split(/\r\n|\r|\n/);
1032 };
1033 }
1034  
1035  
1036 this.$detectNewLine = function(text) {
1037 var match = text.match(/^.*?(\r\n|\r|\n)/m);
1038 this.$autoNewLine = match ? match[1] : "\n";
1039 this._signal("changeNewLineMode");
1040 };
1041 this.getNewLineCharacter = function() {
1042 switch (this.$newLineMode) {
1043 case "windows":
1044 return "\r\n";
1045 case "unix":
1046 return "\n";
1047 default:
1048 return this.$autoNewLine || "\n";
1049 }
1050 };
1051  
1052 this.$autoNewLine = "";
1053 this.$newLineMode = "auto";
1054 this.setNewLineMode = function(newLineMode) {
1055 if (this.$newLineMode === newLineMode)
1056 return;
1057  
1058 this.$newLineMode = newLineMode;
1059 this._signal("changeNewLineMode");
1060 };
1061 this.getNewLineMode = function() {
1062 return this.$newLineMode;
1063 };
1064 this.isNewLine = function(text) {
1065 return (text == "\r\n" || text == "\r" || text == "\n");
1066 };
1067 this.getLine = function(row) {
1068 return this.$lines[row] || "";
1069 };
1070 this.getLines = function(firstRow, lastRow) {
1071 return this.$lines.slice(firstRow, lastRow + 1);
1072 };
1073 this.getAllLines = function() {
1074 return this.getLines(0, this.getLength());
1075 };
1076 this.getLength = function() {
1077 return this.$lines.length;
1078 };
1079 this.getTextRange = function(range) {
1080 return this.getLinesForRange(range).join(this.getNewLineCharacter());
1081 };
1082 this.getLinesForRange = function(range) {
1083 var lines;
1084 if (range.start.row === range.end.row) {
1085 lines = [this.getLine(range.start.row).substring(range.start.column, range.end.column)];
1086 } else {
1087 lines = this.getLines(range.start.row, range.end.row);
1088 lines[0] = (lines[0] || "").substring(range.start.column);
1089 var l = lines.length - 1;
1090 if (range.end.row - range.start.row == l)
1091 lines[l] = lines[l].substring(0, range.end.column);
1092 }
1093 return lines;
1094 };
1095 this.insertLines = function(row, lines) {
1096 console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead.");
1097 return this.insertFullLines(row, lines);
1098 };
1099 this.removeLines = function(firstRow, lastRow) {
1100 console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead.");
1101 return this.removeFullLines(firstRow, lastRow);
1102 };
1103 this.insertNewLine = function(position) {
1104 console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead.");
1105 return this.insertMergedLines(position, ["", ""]);
1106 };
1107 this.insert = function(position, text) {
1108 if (this.getLength() <= 1)
1109 this.$detectNewLine(text);
1110  
1111 return this.insertMergedLines(position, this.$split(text));
1112 };
1113 this.insertInLine = function(position, text) {
1114 var start = this.clippedPos(position.row, position.column);
1115 var end = this.pos(position.row, position.column + text.length);
1116  
1117 this.applyDelta({
1118 start: start,
1119 end: end,
1120 action: "insert",
1121 lines: [text]
1122 }, true);
1123  
1124 return this.clonePos(end);
1125 };
1126  
1127 this.clippedPos = function(row, column) {
1128 var length = this.getLength();
1129 if (row === undefined) {
1130 row = length;
1131 } else if (row < 0) {
1132 row = 0;
1133 } else if (row >= length) {
1134 row = length - 1;
1135 column = undefined;
1136 }
1137 var line = this.getLine(row);
1138 if (column == undefined)
1139 column = line.length;
1140 column = Math.min(Math.max(column, 0), line.length);
1141 return {row: row, column: column};
1142 };
1143  
1144 this.clonePos = function(pos) {
1145 return {row: pos.row, column: pos.column};
1146 };
1147  
1148 this.pos = function(row, column) {
1149 return {row: row, column: column};
1150 };
1151  
1152 this.$clipPosition = function(position) {
1153 var length = this.getLength();
1154 if (position.row >= length) {
1155 position.row = Math.max(0, length - 1);
1156 position.column = this.getLine(length - 1).length;
1157 } else {
1158 position.row = Math.max(0, position.row);
1159 position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length);
1160 }
1161 return position;
1162 };
1163 this.insertFullLines = function(row, lines) {
1164 row = Math.min(Math.max(row, 0), this.getLength());
1165 var column = 0;
1166 if (row < this.getLength()) {
1167 lines = lines.concat([""]);
1168 column = 0;
1169 } else {
1170 lines = [""].concat(lines);
1171 row--;
1172 column = this.$lines[row].length;
1173 }
1174 this.insertMergedLines({row: row, column: column}, lines);
1175 };
1176 this.insertMergedLines = function(position, lines) {
1177 var start = this.clippedPos(position.row, position.column);
1178 var end = {
1179 row: start.row + lines.length - 1,
1180 column: (lines.length == 1 ? start.column : 0) + lines[lines.length - 1].length
1181 };
1182  
1183 this.applyDelta({
1184 start: start,
1185 end: end,
1186 action: "insert",
1187 lines: lines
1188 });
1189  
1190 return this.clonePos(end);
1191 };
1192 this.remove = function(range) {
1193 var start = this.clippedPos(range.start.row, range.start.column);
1194 var end = this.clippedPos(range.end.row, range.end.column);
1195 this.applyDelta({
1196 start: start,
1197 end: end,
1198 action: "remove",
1199 lines: this.getLinesForRange({start: start, end: end})
1200 });
1201 return this.clonePos(start);
1202 };
1203 this.removeInLine = function(row, startColumn, endColumn) {
1204 var start = this.clippedPos(row, startColumn);
1205 var end = this.clippedPos(row, endColumn);
1206  
1207 this.applyDelta({
1208 start: start,
1209 end: end,
1210 action: "remove",
1211 lines: this.getLinesForRange({start: start, end: end})
1212 }, true);
1213  
1214 return this.clonePos(start);
1215 };
1216 this.removeFullLines = function(firstRow, lastRow) {
1217 firstRow = Math.min(Math.max(0, firstRow), this.getLength() - 1);
1218 lastRow = Math.min(Math.max(0, lastRow ), this.getLength() - 1);
1219 var deleteFirstNewLine = lastRow == this.getLength() - 1 && firstRow > 0;
1220 var deleteLastNewLine = lastRow < this.getLength() - 1;
1221 var startRow = ( deleteFirstNewLine ? firstRow - 1 : firstRow );
1222 var startCol = ( deleteFirstNewLine ? this.getLine(startRow).length : 0 );
1223 var endRow = ( deleteLastNewLine ? lastRow + 1 : lastRow );
1224 var endCol = ( deleteLastNewLine ? 0 : this.getLine(endRow).length );
1225 var range = new Range(startRow, startCol, endRow, endCol);
1226 var deletedLines = this.$lines.slice(firstRow, lastRow + 1);
1227  
1228 this.applyDelta({
1229 start: range.start,
1230 end: range.end,
1231 action: "remove",
1232 lines: this.getLinesForRange(range)
1233 });
1234 return deletedLines;
1235 };
1236 this.removeNewLine = function(row) {
1237 if (row < this.getLength() - 1 && row >= 0) {
1238 this.applyDelta({
1239 start: this.pos(row, this.getLine(row).length),
1240 end: this.pos(row + 1, 0),
1241 action: "remove",
1242 lines: ["", ""]
1243 });
1244 }
1245 };
1246 this.replace = function(range, text) {
1247 if (!(range instanceof Range))
1248 range = Range.fromPoints(range.start, range.end);
1249 if (text.length === 0 && range.isEmpty())
1250 return range.start;
1251 if (text == this.getTextRange(range))
1252 return range.end;
1253  
1254 this.remove(range);
1255 var end;
1256 if (text) {
1257 end = this.insert(range.start, text);
1258 }
1259 else {
1260 end = range.start;
1261 }
1262  
1263 return end;
1264 };
1265 this.applyDeltas = function(deltas) {
1266 for (var i=0; i<deltas.length; i++) {
1267 this.applyDelta(deltas[i]);
1268 }
1269 };
1270 this.revertDeltas = function(deltas) {
1271 for (var i=deltas.length-1; i>=0; i--) {
1272 this.revertDelta(deltas[i]);
1273 }
1274 };
1275 this.applyDelta = function(delta, doNotValidate) {
1276 var isInsert = delta.action == "insert";
1277 if (isInsert ? delta.lines.length <= 1 && !delta.lines[0]
1278 : !Range.comparePoints(delta.start, delta.end)) {
1279 return;
1280 }
1281  
1282 if (isInsert && delta.lines.length > 20000)
1283 this.$splitAndapplyLargeDelta(delta, 20000);
1284 applyDelta(this.$lines, delta, doNotValidate);
1285 this._signal("change", delta);
1286 };
1287  
1288 this.$splitAndapplyLargeDelta = function(delta, MAX) {
1289 var lines = delta.lines;
1290 var l = lines.length;
1291 var row = delta.start.row;
1292 var column = delta.start.column;
1293 var from = 0, to = 0;
1294 do {
1295 from = to;
1296 to += MAX - 1;
1297 var chunk = lines.slice(from, to);
1298 if (to > l) {
1299 delta.lines = chunk;
1300 delta.start.row = row + from;
1301 delta.start.column = column;
1302 break;
1303 }
1304 chunk.push("");
1305 this.applyDelta({
1306 start: this.pos(row + from, column),
1307 end: this.pos(row + to, column = 0),
1308 action: delta.action,
1309 lines: chunk
1310 }, true);
1311 } while(true);
1312 };
1313 this.revertDelta = function(delta) {
1314 this.applyDelta({
1315 start: this.clonePos(delta.start),
1316 end: this.clonePos(delta.end),
1317 action: (delta.action == "insert" ? "remove" : "insert"),
1318 lines: delta.lines.slice()
1319 });
1320 };
1321 this.indexToPosition = function(index, startRow) {
1322 var lines = this.$lines || this.getAllLines();
1323 var newlineLength = this.getNewLineCharacter().length;
1324 for (var i = startRow || 0, l = lines.length; i < l; i++) {
1325 index -= lines[i].length + newlineLength;
1326 if (index < 0)
1327 return {row: i, column: index + lines[i].length + newlineLength};
1328 }
1329 return {row: l-1, column: lines[l-1].length};
1330 };
1331 this.positionToIndex = function(pos, startRow) {
1332 var lines = this.$lines || this.getAllLines();
1333 var newlineLength = this.getNewLineCharacter().length;
1334 var index = 0;
1335 var row = Math.min(pos.row, lines.length);
1336 for (var i = startRow || 0; i < row; ++i)
1337 index += lines[i].length + newlineLength;
1338  
1339 return index + pos.column;
1340 };
1341  
1342 }).call(Document.prototype);
1343  
1344 exports.Document = Document;
1345 });
1346  
1347 ace.define("ace/worker/mirror",["require","exports","module","ace/range","ace/document","ace/lib/lang"], function(require, exports, module) {
1348 "use strict";
1349  
1350 var Range = require("../range").Range;
1351 var Document = require("../document").Document;
1352 var lang = require("../lib/lang");
1353  
1354 var Mirror = exports.Mirror = function(sender) {
1355 this.sender = sender;
1356 var doc = this.doc = new Document("");
1357  
1358 var deferredUpdate = this.deferredUpdate = lang.delayedCall(this.onUpdate.bind(this));
1359  
1360 var _self = this;
1361 sender.on("change", function(e) {
1362 var data = e.data;
1363 if (data[0].start) {
1364 doc.applyDeltas(data);
1365 } else {
1366 for (var i = 0; i < data.length; i += 2) {
1367 if (Array.isArray(data[i+1])) {
1368 var d = {action: "insert", start: data[i], lines: data[i+1]};
1369 } else {
1370 var d = {action: "remove", start: data[i], end: data[i+1]};
1371 }
1372 doc.applyDelta(d, true);
1373 }
1374 }
1375 if (_self.$timeout)
1376 return deferredUpdate.schedule(_self.$timeout);
1377 _self.onUpdate();
1378 });
1379 };
1380  
1381 (function() {
1382  
1383 this.$timeout = 500;
1384  
1385 this.setTimeout = function(timeout) {
1386 this.$timeout = timeout;
1387 };
1388  
1389 this.setValue = function(value) {
1390 this.doc.setValue(value);
1391 this.deferredUpdate.schedule(this.$timeout);
1392 };
1393  
1394 this.getValue = function(callbackId) {
1395 this.sender.callback(this.doc.getValue(), callbackId);
1396 };
1397  
1398 this.onUpdate = function() {
1399 };
1400  
1401 this.isPending = function() {
1402 return this.deferredUpdate.isPending();
1403 };
1404  
1405 }).call(Mirror.prototype);
1406  
1407 });
1408  
1409 ace.define("ace/mode/css/csslint",["require","exports","module"], function(require, exports, module) {
1410 var parserlib = {};
1411 (function(){
1412 function EventTarget(){
1413 this._listeners = {};
1414 }
1415  
1416 EventTarget.prototype = {
1417 constructor: EventTarget,
1418 addListener: function(type, listener){
1419 if (!this._listeners[type]){
1420 this._listeners[type] = [];
1421 }
1422  
1423 this._listeners[type].push(listener);
1424 },
1425 fire: function(event){
1426 if (typeof event == "string"){
1427 event = { type: event };
1428 }
1429 if (typeof event.target != "undefined"){
1430 event.target = this;
1431 }
1432  
1433 if (typeof event.type == "undefined"){
1434 throw new Error("Event object missing 'type' property.");
1435 }
1436  
1437 if (this._listeners[event.type]){
1438 var listeners = this._listeners[event.type].concat();
1439 for (var i=0, len=listeners.length; i < len; i++){
1440 listeners[i].call(this, event);
1441 }
1442 }
1443 },
1444 removeListener: function(type, listener){
1445 if (this._listeners[type]){
1446 var listeners = this._listeners[type];
1447 for (var i=0, len=listeners.length; i < len; i++){
1448 if (listeners[i] === listener){
1449 listeners.splice(i, 1);
1450 break;
1451 }
1452 }
1453  
1454  
1455 }
1456 }
1457 };
1458 function StringReader(text){
1459 this._input = text.replace(/\n\r?/g, "\n");
1460 this._line = 1;
1461 this._col = 1;
1462 this._cursor = 0;
1463 }
1464  
1465 StringReader.prototype = {
1466 constructor: StringReader,
1467 getCol: function(){
1468 return this._col;
1469 },
1470 getLine: function(){
1471 return this._line ;
1472 },
1473 eof: function(){
1474 return (this._cursor == this._input.length);
1475 },
1476 peek: function(count){
1477 var c = null;
1478 count = (typeof count == "undefined" ? 1 : count);
1479 if (this._cursor < this._input.length){
1480 c = this._input.charAt(this._cursor + count - 1);
1481 }
1482  
1483 return c;
1484 },
1485 read: function(){
1486 var c = null;
1487 if (this._cursor < this._input.length){
1488 if (this._input.charAt(this._cursor) == "\n"){
1489 this._line++;
1490 this._col=1;
1491 } else {
1492 this._col++;
1493 }
1494 c = this._input.charAt(this._cursor++);
1495 }
1496  
1497 return c;
1498 },
1499 mark: function(){
1500 this._bookmark = {
1501 cursor: this._cursor,
1502 line: this._line,
1503 col: this._col
1504 };
1505 },
1506  
1507 reset: function(){
1508 if (this._bookmark){
1509 this._cursor = this._bookmark.cursor;
1510 this._line = this._bookmark.line;
1511 this._col = this._bookmark.col;
1512 delete this._bookmark;
1513 }
1514 },
1515 readTo: function(pattern){
1516  
1517 var buffer = "",
1518 c;
1519 while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) != buffer.length - pattern.length){
1520 c = this.read();
1521 if (c){
1522 buffer += c;
1523 } else {
1524 throw new Error("Expected \"" + pattern + "\" at line " + this._line + ", col " + this._col + ".");
1525 }
1526 }
1527  
1528 return buffer;
1529  
1530 },
1531 readWhile: function(filter){
1532  
1533 var buffer = "",
1534 c = this.read();
1535  
1536 while(c !== null && filter(c)){
1537 buffer += c;
1538 c = this.read();
1539 }
1540  
1541 return buffer;
1542  
1543 },
1544 readMatch: function(matcher){
1545  
1546 var source = this._input.substring(this._cursor),
1547 value = null;
1548 if (typeof matcher == "string"){
1549 if (source.indexOf(matcher) === 0){
1550 value = this.readCount(matcher.length);
1551 }
1552 } else if (matcher instanceof RegExp){
1553 if (matcher.test(source)){
1554 value = this.readCount(RegExp.lastMatch.length);
1555 }
1556 }
1557  
1558 return value;
1559 },
1560 readCount: function(count){
1561 var buffer = "";
1562  
1563 while(count--){
1564 buffer += this.read();
1565 }
1566  
1567 return buffer;
1568 }
1569  
1570 };
1571 function SyntaxError(message, line, col){
1572 this.col = col;
1573 this.line = line;
1574 this.message = message;
1575  
1576 }
1577 SyntaxError.prototype = new Error();
1578 function SyntaxUnit(text, line, col, type){
1579 this.col = col;
1580 this.line = line;
1581 this.text = text;
1582 this.type = type;
1583 }
1584 SyntaxUnit.fromToken = function(token){
1585 return new SyntaxUnit(token.value, token.startLine, token.startCol);
1586 };
1587  
1588 SyntaxUnit.prototype = {
1589 constructor: SyntaxUnit,
1590 valueOf: function(){
1591 return this.text;
1592 },
1593 toString: function(){
1594 return this.text;
1595 }
1596  
1597 };
1598 function TokenStreamBase(input, tokenData){
1599 this._reader = input ? new StringReader(input.toString()) : null;
1600 this._token = null;
1601 this._tokenData = tokenData;
1602 this._lt = [];
1603 this._ltIndex = 0;
1604  
1605 this._ltIndexCache = [];
1606 }
1607 TokenStreamBase.createTokenData = function(tokens){
1608  
1609 var nameMap = [],
1610 typeMap = {},
1611 tokenData = tokens.concat([]),
1612 i = 0,
1613 len = tokenData.length+1;
1614  
1615 tokenData.UNKNOWN = -1;
1616 tokenData.unshift({name:"EOF"});
1617  
1618 for (; i < len; i++){
1619 nameMap.push(tokenData[i].name);
1620 tokenData[tokenData[i].name] = i;
1621 if (tokenData[i].text){
1622 typeMap[tokenData[i].text] = i;
1623 }
1624 }
1625  
1626 tokenData.name = function(tt){
1627 return nameMap[tt];
1628 };
1629  
1630 tokenData.type = function(c){
1631 return typeMap[c];
1632 };
1633  
1634 return tokenData;
1635 };
1636  
1637 TokenStreamBase.prototype = {
1638 constructor: TokenStreamBase,
1639 match: function(tokenTypes, channel){
1640 if (!(tokenTypes instanceof Array)){
1641 tokenTypes = [tokenTypes];
1642 }
1643  
1644 var tt = this.get(channel),
1645 i = 0,
1646 len = tokenTypes.length;
1647  
1648 while(i < len){
1649 if (tt == tokenTypes[i++]){
1650 return true;
1651 }
1652 }
1653 this.unget();
1654 return false;
1655 },
1656 mustMatch: function(tokenTypes, channel){
1657  
1658 var token;
1659 if (!(tokenTypes instanceof Array)){
1660 tokenTypes = [tokenTypes];
1661 }
1662  
1663 if (!this.match.apply(this, arguments)){
1664 token = this.LT(1);
1665 throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name +
1666 " at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
1667 }
1668 },
1669 advance: function(tokenTypes, channel){
1670  
1671 while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){
1672 this.get();
1673 }
1674  
1675 return this.LA(0);
1676 },
1677 get: function(channel){
1678  
1679 var tokenInfo = this._tokenData,
1680 reader = this._reader,
1681 value,
1682 i =0,
1683 len = tokenInfo.length,
1684 found = false,
1685 token,
1686 info;
1687 if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length){
1688  
1689 i++;
1690 this._token = this._lt[this._ltIndex++];
1691 info = tokenInfo[this._token.type];
1692 while((info.channel !== undefined && channel !== info.channel) &&
1693 this._ltIndex < this._lt.length){
1694 this._token = this._lt[this._ltIndex++];
1695 info = tokenInfo[this._token.type];
1696 i++;
1697 }
1698 if ((info.channel === undefined || channel === info.channel) &&
1699 this._ltIndex <= this._lt.length){
1700 this._ltIndexCache.push(i);
1701 return this._token.type;
1702 }
1703 }
1704 token = this._getToken();
1705 if (token.type > -1 && !tokenInfo[token.type].hide){
1706 token.channel = tokenInfo[token.type].channel;
1707 this._token = token;
1708 this._lt.push(token);
1709 this._ltIndexCache.push(this._lt.length - this._ltIndex + i);
1710 if (this._lt.length > 5){
1711 this._lt.shift();
1712 }
1713 if (this._ltIndexCache.length > 5){
1714 this._ltIndexCache.shift();
1715 }
1716 this._ltIndex = this._lt.length;
1717 }
1718 info = tokenInfo[token.type];
1719 if (info &&
1720 (info.hide ||
1721 (info.channel !== undefined && channel !== info.channel))){
1722 return this.get(channel);
1723 } else {
1724 return token.type;
1725 }
1726 },
1727 LA: function(index){
1728 var total = index,
1729 tt;
1730 if (index > 0){
1731 if (index > 5){
1732 throw new Error("Too much lookahead.");
1733 }
1734 while(total){
1735 tt = this.get();
1736 total--;
1737 }
1738 while(total < index){
1739 this.unget();
1740 total++;
1741 }
1742 } else if (index < 0){
1743  
1744 if(this._lt[this._ltIndex+index]){
1745 tt = this._lt[this._ltIndex+index].type;
1746 } else {
1747 throw new Error("Too much lookbehind.");
1748 }
1749  
1750 } else {
1751 tt = this._token.type;
1752 }
1753  
1754 return tt;
1755  
1756 },
1757 LT: function(index){
1758 this.LA(index);
1759 return this._lt[this._ltIndex+index-1];
1760 },
1761 peek: function(){
1762 return this.LA(1);
1763 },
1764 token: function(){
1765 return this._token;
1766 },
1767 tokenName: function(tokenType){
1768 if (tokenType < 0 || tokenType > this._tokenData.length){
1769 return "UNKNOWN_TOKEN";
1770 } else {
1771 return this._tokenData[tokenType].name;
1772 }
1773 },
1774 tokenType: function(tokenName){
1775 return this._tokenData[tokenName] || -1;
1776 },
1777 unget: function(){
1778 if (this._ltIndexCache.length){
1779 this._ltIndex -= this._ltIndexCache.pop();//--;
1780 this._token = this._lt[this._ltIndex - 1];
1781 } else {
1782 throw new Error("Too much lookahead.");
1783 }
1784 }
1785  
1786 };
1787  
1788  
1789 parserlib.util = {
1790 StringReader: StringReader,
1791 SyntaxError : SyntaxError,
1792 SyntaxUnit : SyntaxUnit,
1793 EventTarget : EventTarget,
1794 TokenStreamBase : TokenStreamBase
1795 };
1796 })();
1797 (function(){
1798 var EventTarget = parserlib.util.EventTarget,
1799 TokenStreamBase = parserlib.util.TokenStreamBase,
1800 StringReader = parserlib.util.StringReader,
1801 SyntaxError = parserlib.util.SyntaxError,
1802 SyntaxUnit = parserlib.util.SyntaxUnit;
1803  
1804 var Colors = {
1805 aliceblue :"#f0f8ff",
1806 antiquewhite :"#faebd7",
1807 aqua :"#00ffff",
1808 aquamarine :"#7fffd4",
1809 azure :"#f0ffff",
1810 beige :"#f5f5dc",
1811 bisque :"#ffe4c4",
1812 black :"#000000",
1813 blanchedalmond :"#ffebcd",
1814 blue :"#0000ff",
1815 blueviolet :"#8a2be2",
1816 brown :"#a52a2a",
1817 burlywood :"#deb887",
1818 cadetblue :"#5f9ea0",
1819 chartreuse :"#7fff00",
1820 chocolate :"#d2691e",
1821 coral :"#ff7f50",
1822 cornflowerblue :"#6495ed",
1823 cornsilk :"#fff8dc",
1824 crimson :"#dc143c",
1825 cyan :"#00ffff",
1826 darkblue :"#00008b",
1827 darkcyan :"#008b8b",
1828 darkgoldenrod :"#b8860b",
1829 darkgray :"#a9a9a9",
1830 darkgrey :"#a9a9a9",
1831 darkgreen :"#006400",
1832 darkkhaki :"#bdb76b",
1833 darkmagenta :"#8b008b",
1834 darkolivegreen :"#556b2f",
1835 darkorange :"#ff8c00",
1836 darkorchid :"#9932cc",
1837 darkred :"#8b0000",
1838 darksalmon :"#e9967a",
1839 darkseagreen :"#8fbc8f",
1840 darkslateblue :"#483d8b",
1841 darkslategray :"#2f4f4f",
1842 darkslategrey :"#2f4f4f",
1843 darkturquoise :"#00ced1",
1844 darkviolet :"#9400d3",
1845 deeppink :"#ff1493",
1846 deepskyblue :"#00bfff",
1847 dimgray :"#696969",
1848 dimgrey :"#696969",
1849 dodgerblue :"#1e90ff",
1850 firebrick :"#b22222",
1851 floralwhite :"#fffaf0",
1852 forestgreen :"#228b22",
1853 fuchsia :"#ff00ff",
1854 gainsboro :"#dcdcdc",
1855 ghostwhite :"#f8f8ff",
1856 gold :"#ffd700",
1857 goldenrod :"#daa520",
1858 gray :"#808080",
1859 grey :"#808080",
1860 green :"#008000",
1861 greenyellow :"#adff2f",
1862 honeydew :"#f0fff0",
1863 hotpink :"#ff69b4",
1864 indianred :"#cd5c5c",
1865 indigo :"#4b0082",
1866 ivory :"#fffff0",
1867 khaki :"#f0e68c",
1868 lavender :"#e6e6fa",
1869 lavenderblush :"#fff0f5",
1870 lawngreen :"#7cfc00",
1871 lemonchiffon :"#fffacd",
1872 lightblue :"#add8e6",
1873 lightcoral :"#f08080",
1874 lightcyan :"#e0ffff",
1875 lightgoldenrodyellow :"#fafad2",
1876 lightgray :"#d3d3d3",
1877 lightgrey :"#d3d3d3",
1878 lightgreen :"#90ee90",
1879 lightpink :"#ffb6c1",
1880 lightsalmon :"#ffa07a",
1881 lightseagreen :"#20b2aa",
1882 lightskyblue :"#87cefa",
1883 lightslategray :"#778899",
1884 lightslategrey :"#778899",
1885 lightsteelblue :"#b0c4de",
1886 lightyellow :"#ffffe0",
1887 lime :"#00ff00",
1888 limegreen :"#32cd32",
1889 linen :"#faf0e6",
1890 magenta :"#ff00ff",
1891 maroon :"#800000",
1892 mediumaquamarine:"#66cdaa",
1893 mediumblue :"#0000cd",
1894 mediumorchid :"#ba55d3",
1895 mediumpurple :"#9370d8",
1896 mediumseagreen :"#3cb371",
1897 mediumslateblue :"#7b68ee",
1898 mediumspringgreen :"#00fa9a",
1899 mediumturquoise :"#48d1cc",
1900 mediumvioletred :"#c71585",
1901 midnightblue :"#191970",
1902 mintcream :"#f5fffa",
1903 mistyrose :"#ffe4e1",
1904 moccasin :"#ffe4b5",
1905 navajowhite :"#ffdead",
1906 navy :"#000080",
1907 oldlace :"#fdf5e6",
1908 olive :"#808000",
1909 olivedrab :"#6b8e23",
1910 orange :"#ffa500",
1911 orangered :"#ff4500",
1912 orchid :"#da70d6",
1913 palegoldenrod :"#eee8aa",
1914 palegreen :"#98fb98",
1915 paleturquoise :"#afeeee",
1916 palevioletred :"#d87093",
1917 papayawhip :"#ffefd5",
1918 peachpuff :"#ffdab9",
1919 peru :"#cd853f",
1920 pink :"#ffc0cb",
1921 plum :"#dda0dd",
1922 powderblue :"#b0e0e6",
1923 purple :"#800080",
1924 red :"#ff0000",
1925 rosybrown :"#bc8f8f",
1926 royalblue :"#4169e1",
1927 saddlebrown :"#8b4513",
1928 salmon :"#fa8072",
1929 sandybrown :"#f4a460",
1930 seagreen :"#2e8b57",
1931 seashell :"#fff5ee",
1932 sienna :"#a0522d",
1933 silver :"#c0c0c0",
1934 skyblue :"#87ceeb",
1935 slateblue :"#6a5acd",
1936 slategray :"#708090",
1937 slategrey :"#708090",
1938 snow :"#fffafa",
1939 springgreen :"#00ff7f",
1940 steelblue :"#4682b4",
1941 tan :"#d2b48c",
1942 teal :"#008080",
1943 thistle :"#d8bfd8",
1944 tomato :"#ff6347",
1945 turquoise :"#40e0d0",
1946 violet :"#ee82ee",
1947 wheat :"#f5deb3",
1948 white :"#ffffff",
1949 whitesmoke :"#f5f5f5",
1950 yellow :"#ffff00",
1951 yellowgreen :"#9acd32",
1952 activeBorder :"Active window border.",
1953 activecaption :"Active window caption.",
1954 appworkspace :"Background color of multiple document interface.",
1955 background :"Desktop background.",
1956 buttonface :"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.",
1957 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.",
1958 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.",
1959 buttontext :"Text on push buttons.",
1960 captiontext :"Text in caption, size box, and scrollbar arrow box.",
1961 graytext :"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.",
1962 greytext :"Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color.",
1963 highlight :"Item(s) selected in a control.",
1964 highlighttext :"Text of item(s) selected in a control.",
1965 inactiveborder :"Inactive window border.",
1966 inactivecaption :"Inactive window caption.",
1967 inactivecaptiontext :"Color of text in an inactive caption.",
1968 infobackground :"Background color for tooltip controls.",
1969 infotext :"Text color for tooltip controls.",
1970 menu :"Menu background.",
1971 menutext :"Text in menus.",
1972 scrollbar :"Scroll bar gray area.",
1973 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.",
1974 threedface :"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
1975 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.",
1976 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.",
1977 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.",
1978 window :"Window background.",
1979 windowframe :"Window frame.",
1980 windowtext :"Text in windows."
1981 };
1982 function Combinator(text, line, col){
1983  
1984 SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE);
1985 this.type = "unknown";
1986 if (/^\s+$/.test(text)){
1987 this.type = "descendant";
1988 } else if (text == ">"){
1989 this.type = "child";
1990 } else if (text == "+"){
1991 this.type = "adjacent-sibling";
1992 } else if (text == "~"){
1993 this.type = "sibling";
1994 }
1995  
1996 }
1997  
1998 Combinator.prototype = new SyntaxUnit();
1999 Combinator.prototype.constructor = Combinator;
2000 function MediaFeature(name, value){
2001  
2002 SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE);
2003 this.name = name;
2004 this.value = value;
2005 }
2006  
2007 MediaFeature.prototype = new SyntaxUnit();
2008 MediaFeature.prototype.constructor = MediaFeature;
2009 function MediaQuery(modifier, mediaType, features, line, col){
2010  
2011 SyntaxUnit.call(this, (modifier ? modifier + " ": "") + (mediaType ? mediaType : "") + (mediaType && features.length > 0 ? " and " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE);
2012 this.modifier = modifier;
2013 this.mediaType = mediaType;
2014 this.features = features;
2015  
2016 }
2017  
2018 MediaQuery.prototype = new SyntaxUnit();
2019 MediaQuery.prototype.constructor = MediaQuery;
2020 function Parser(options){
2021 EventTarget.call(this);
2022  
2023  
2024 this.options = options || {};
2025  
2026 this._tokenStream = null;
2027 }
2028 Parser.DEFAULT_TYPE = 0;
2029 Parser.COMBINATOR_TYPE = 1;
2030 Parser.MEDIA_FEATURE_TYPE = 2;
2031 Parser.MEDIA_QUERY_TYPE = 3;
2032 Parser.PROPERTY_NAME_TYPE = 4;
2033 Parser.PROPERTY_VALUE_TYPE = 5;
2034 Parser.PROPERTY_VALUE_PART_TYPE = 6;
2035 Parser.SELECTOR_TYPE = 7;
2036 Parser.SELECTOR_PART_TYPE = 8;
2037 Parser.SELECTOR_SUB_PART_TYPE = 9;
2038  
2039 Parser.prototype = function(){
2040  
2041 var proto = new EventTarget(), //new prototype
2042 prop,
2043 additions = {
2044 constructor: Parser,
2045 DEFAULT_TYPE : 0,
2046 COMBINATOR_TYPE : 1,
2047 MEDIA_FEATURE_TYPE : 2,
2048 MEDIA_QUERY_TYPE : 3,
2049 PROPERTY_NAME_TYPE : 4,
2050 PROPERTY_VALUE_TYPE : 5,
2051 PROPERTY_VALUE_PART_TYPE : 6,
2052 SELECTOR_TYPE : 7,
2053 SELECTOR_PART_TYPE : 8,
2054 SELECTOR_SUB_PART_TYPE : 9,
2055  
2056 _stylesheet: function(){
2057  
2058 var tokenStream = this._tokenStream,
2059 charset = null,
2060 count,
2061 token,
2062 tt;
2063  
2064 this.fire("startstylesheet");
2065 this._charset();
2066  
2067 this._skipCruft();
2068 while (tokenStream.peek() == Tokens.IMPORT_SYM){
2069 this._import();
2070 this._skipCruft();
2071 }
2072 while (tokenStream.peek() == Tokens.NAMESPACE_SYM){
2073 this._namespace();
2074 this._skipCruft();
2075 }
2076 tt = tokenStream.peek();
2077 while(tt > Tokens.EOF){
2078  
2079 try {
2080  
2081 switch(tt){
2082 case Tokens.MEDIA_SYM:
2083 this._media();
2084 this._skipCruft();
2085 break;
2086 case Tokens.PAGE_SYM:
2087 this._page();
2088 this._skipCruft();
2089 break;
2090 case Tokens.FONT_FACE_SYM:
2091 this._font_face();
2092 this._skipCruft();
2093 break;
2094 case Tokens.KEYFRAMES_SYM:
2095 this._keyframes();
2096 this._skipCruft();
2097 break;
2098 case Tokens.VIEWPORT_SYM:
2099 this._viewport();
2100 this._skipCruft();
2101 break;
2102 case Tokens.UNKNOWN_SYM: //unknown @ rule
2103 tokenStream.get();
2104 if (!this.options.strict){
2105 this.fire({
2106 type: "error",
2107 error: null,
2108 message: "Unknown @ rule: " + tokenStream.LT(0).value + ".",
2109 line: tokenStream.LT(0).startLine,
2110 col: tokenStream.LT(0).startCol
2111 });
2112 count=0;
2113 while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){
2114 count++; //keep track of nesting depth
2115 }
2116  
2117 while(count){
2118 tokenStream.advance([Tokens.RBRACE]);
2119 count--;
2120 }
2121  
2122 } else {
2123 throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol);
2124 }
2125 break;
2126 case Tokens.S:
2127 this._readWhitespace();
2128 break;
2129 default:
2130 if(!this._ruleset()){
2131 switch(tt){
2132 case Tokens.CHARSET_SYM:
2133 token = tokenStream.LT(1);
2134 this._charset(false);
2135 throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol);
2136 case Tokens.IMPORT_SYM:
2137 token = tokenStream.LT(1);
2138 this._import(false);
2139 throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol);
2140 case Tokens.NAMESPACE_SYM:
2141 token = tokenStream.LT(1);
2142 this._namespace(false);
2143 throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol);
2144 default:
2145 tokenStream.get(); //get the last token
2146 this._unexpectedToken(tokenStream.token());
2147 }
2148  
2149 }
2150 }
2151 } catch(ex) {
2152 if (ex instanceof SyntaxError && !this.options.strict){
2153 this.fire({
2154 type: "error",
2155 error: ex,
2156 message: ex.message,
2157 line: ex.line,
2158 col: ex.col
2159 });
2160 } else {
2161 throw ex;
2162 }
2163 }
2164  
2165 tt = tokenStream.peek();
2166 }
2167  
2168 if (tt != Tokens.EOF){
2169 this._unexpectedToken(tokenStream.token());
2170 }
2171  
2172 this.fire("endstylesheet");
2173 },
2174  
2175 _charset: function(emit){
2176 var tokenStream = this._tokenStream,
2177 charset,
2178 token,
2179 line,
2180 col;
2181  
2182 if (tokenStream.match(Tokens.CHARSET_SYM)){
2183 line = tokenStream.token().startLine;
2184 col = tokenStream.token().startCol;
2185  
2186 this._readWhitespace();
2187 tokenStream.mustMatch(Tokens.STRING);
2188  
2189 token = tokenStream.token();
2190 charset = token.value;
2191  
2192 this._readWhitespace();
2193 tokenStream.mustMatch(Tokens.SEMICOLON);
2194  
2195 if (emit !== false){
2196 this.fire({
2197 type: "charset",
2198 charset:charset,
2199 line: line,
2200 col: col
2201 });
2202 }
2203 }
2204 },
2205  
2206 _import: function(emit){
2207  
2208 var tokenStream = this._tokenStream,
2209 tt,
2210 uri,
2211 importToken,
2212 mediaList = [];
2213 tokenStream.mustMatch(Tokens.IMPORT_SYM);
2214 importToken = tokenStream.token();
2215 this._readWhitespace();
2216  
2217 tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);
2218 uri = tokenStream.token().value.replace(/^(?:url\()?["']?([^"']+?)["']?\)?$/, "$1");
2219  
2220 this._readWhitespace();
2221  
2222 mediaList = this._media_query_list();
2223 tokenStream.mustMatch(Tokens.SEMICOLON);
2224 this._readWhitespace();
2225  
2226 if (emit !== false){
2227 this.fire({
2228 type: "import",
2229 uri: uri,
2230 media: mediaList,
2231 line: importToken.startLine,
2232 col: importToken.startCol
2233 });
2234 }
2235  
2236 },
2237  
2238 _namespace: function(emit){
2239  
2240 var tokenStream = this._tokenStream,
2241 line,
2242 col,
2243 prefix,
2244 uri;
2245 tokenStream.mustMatch(Tokens.NAMESPACE_SYM);
2246 line = tokenStream.token().startLine;
2247 col = tokenStream.token().startCol;
2248 this._readWhitespace();
2249 if (tokenStream.match(Tokens.IDENT)){
2250 prefix = tokenStream.token().value;
2251 this._readWhitespace();
2252 }
2253  
2254 tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);
2255 uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1");
2256  
2257 this._readWhitespace();
2258 tokenStream.mustMatch(Tokens.SEMICOLON);
2259 this._readWhitespace();
2260  
2261 if (emit !== false){
2262 this.fire({
2263 type: "namespace",
2264 prefix: prefix,
2265 uri: uri,
2266 line: line,
2267 col: col
2268 });
2269 }
2270  
2271 },
2272  
2273 _media: function(){
2274 var tokenStream = this._tokenStream,
2275 line,
2276 col,
2277 mediaList;// = [];
2278 tokenStream.mustMatch(Tokens.MEDIA_SYM);
2279 line = tokenStream.token().startLine;
2280 col = tokenStream.token().startCol;
2281  
2282 this._readWhitespace();
2283  
2284 mediaList = this._media_query_list();
2285  
2286 tokenStream.mustMatch(Tokens.LBRACE);
2287 this._readWhitespace();
2288  
2289 this.fire({
2290 type: "startmedia",
2291 media: mediaList,
2292 line: line,
2293 col: col
2294 });
2295  
2296 while(true) {
2297 if (tokenStream.peek() == Tokens.PAGE_SYM){
2298 this._page();
2299 } else if (tokenStream.peek() == Tokens.FONT_FACE_SYM){
2300 this._font_face();
2301 } else if (tokenStream.peek() == Tokens.VIEWPORT_SYM){
2302 this._viewport();
2303 } else if (!this._ruleset()){
2304 break;
2305 }
2306 }
2307  
2308 tokenStream.mustMatch(Tokens.RBRACE);
2309 this._readWhitespace();
2310  
2311 this.fire({
2312 type: "endmedia",
2313 media: mediaList,
2314 line: line,
2315 col: col
2316 });
2317 },
2318 _media_query_list: function(){
2319 var tokenStream = this._tokenStream,
2320 mediaList = [];
2321  
2322  
2323 this._readWhitespace();
2324  
2325 if (tokenStream.peek() == Tokens.IDENT || tokenStream.peek() == Tokens.LPAREN){
2326 mediaList.push(this._media_query());
2327 }
2328  
2329 while(tokenStream.match(Tokens.COMMA)){
2330 this._readWhitespace();
2331 mediaList.push(this._media_query());
2332 }
2333  
2334 return mediaList;
2335 },
2336 _media_query: function(){
2337 var tokenStream = this._tokenStream,
2338 type = null,
2339 ident = null,
2340 token = null,
2341 expressions = [];
2342  
2343 if (tokenStream.match(Tokens.IDENT)){
2344 ident = tokenStream.token().value.toLowerCase();
2345 if (ident != "only" && ident != "not"){
2346 tokenStream.unget();
2347 ident = null;
2348 } else {
2349 token = tokenStream.token();
2350 }
2351 }
2352  
2353 this._readWhitespace();
2354  
2355 if (tokenStream.peek() == Tokens.IDENT){
2356 type = this._media_type();
2357 if (token === null){
2358 token = tokenStream.token();
2359 }
2360 } else if (tokenStream.peek() == Tokens.LPAREN){
2361 if (token === null){
2362 token = tokenStream.LT(1);
2363 }
2364 expressions.push(this._media_expression());
2365 }
2366  
2367 if (type === null && expressions.length === 0){
2368 return null;
2369 } else {
2370 this._readWhitespace();
2371 while (tokenStream.match(Tokens.IDENT)){
2372 if (tokenStream.token().value.toLowerCase() != "and"){
2373 this._unexpectedToken(tokenStream.token());
2374 }
2375  
2376 this._readWhitespace();
2377 expressions.push(this._media_expression());
2378 }
2379 }
2380  
2381 return new MediaQuery(ident, type, expressions, token.startLine, token.startCol);
2382 },
2383 _media_type: function(){
2384 return this._media_feature();
2385 },
2386 _media_expression: function(){
2387 var tokenStream = this._tokenStream,
2388 feature = null,
2389 token,
2390 expression = null;
2391  
2392 tokenStream.mustMatch(Tokens.LPAREN);
2393  
2394 feature = this._media_feature();
2395 this._readWhitespace();
2396  
2397 if (tokenStream.match(Tokens.COLON)){
2398 this._readWhitespace();
2399 token = tokenStream.LT(1);
2400 expression = this._expression();
2401 }
2402  
2403 tokenStream.mustMatch(Tokens.RPAREN);
2404 this._readWhitespace();
2405  
2406 return new MediaFeature(feature, (expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null));
2407 },
2408 _media_feature: function(){
2409 var tokenStream = this._tokenStream;
2410  
2411 tokenStream.mustMatch(Tokens.IDENT);
2412  
2413 return SyntaxUnit.fromToken(tokenStream.token());
2414 },
2415 _page: function(){
2416 var tokenStream = this._tokenStream,
2417 line,
2418 col,
2419 identifier = null,
2420 pseudoPage = null;
2421 tokenStream.mustMatch(Tokens.PAGE_SYM);
2422 line = tokenStream.token().startLine;
2423 col = tokenStream.token().startCol;
2424  
2425 this._readWhitespace();
2426  
2427 if (tokenStream.match(Tokens.IDENT)){
2428 identifier = tokenStream.token().value;
2429 if (identifier.toLowerCase() === "auto"){
2430 this._unexpectedToken(tokenStream.token());
2431 }
2432 }
2433 if (tokenStream.peek() == Tokens.COLON){
2434 pseudoPage = this._pseudo_page();
2435 }
2436  
2437 this._readWhitespace();
2438  
2439 this.fire({
2440 type: "startpage",
2441 id: identifier,
2442 pseudo: pseudoPage,
2443 line: line,
2444 col: col
2445 });
2446  
2447 this._readDeclarations(true, true);
2448  
2449 this.fire({
2450 type: "endpage",
2451 id: identifier,
2452 pseudo: pseudoPage,
2453 line: line,
2454 col: col
2455 });
2456  
2457 },
2458 _margin: function(){
2459 var tokenStream = this._tokenStream,
2460 line,
2461 col,
2462 marginSym = this._margin_sym();
2463  
2464 if (marginSym){
2465 line = tokenStream.token().startLine;
2466 col = tokenStream.token().startCol;
2467  
2468 this.fire({
2469 type: "startpagemargin",
2470 margin: marginSym,
2471 line: line,
2472 col: col
2473 });
2474  
2475 this._readDeclarations(true);
2476  
2477 this.fire({
2478 type: "endpagemargin",
2479 margin: marginSym,
2480 line: line,
2481 col: col
2482 });
2483 return true;
2484 } else {
2485 return false;
2486 }
2487 },
2488 _margin_sym: function(){
2489  
2490 var tokenStream = this._tokenStream;
2491  
2492 if(tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM,
2493 Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM,
2494 Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM,
2495 Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM,
2496 Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM,
2497 Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM,
2498 Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM]))
2499 {
2500 return SyntaxUnit.fromToken(tokenStream.token());
2501 } else {
2502 return null;
2503 }
2504  
2505 },
2506  
2507 _pseudo_page: function(){
2508  
2509 var tokenStream = this._tokenStream;
2510  
2511 tokenStream.mustMatch(Tokens.COLON);
2512 tokenStream.mustMatch(Tokens.IDENT);
2513  
2514 return tokenStream.token().value;
2515 },
2516  
2517 _font_face: function(){
2518 var tokenStream = this._tokenStream,
2519 line,
2520 col;
2521 tokenStream.mustMatch(Tokens.FONT_FACE_SYM);
2522 line = tokenStream.token().startLine;
2523 col = tokenStream.token().startCol;
2524  
2525 this._readWhitespace();
2526  
2527 this.fire({
2528 type: "startfontface",
2529 line: line,
2530 col: col
2531 });
2532  
2533 this._readDeclarations(true);
2534  
2535 this.fire({
2536 type: "endfontface",
2537 line: line,
2538 col: col
2539 });
2540 },
2541  
2542 _viewport: function(){
2543 var tokenStream = this._tokenStream,
2544 line,
2545 col;
2546  
2547 tokenStream.mustMatch(Tokens.VIEWPORT_SYM);
2548 line = tokenStream.token().startLine;
2549 col = tokenStream.token().startCol;
2550  
2551 this._readWhitespace();
2552  
2553 this.fire({
2554 type: "startviewport",
2555 line: line,
2556 col: col
2557 });
2558  
2559 this._readDeclarations(true);
2560  
2561 this.fire({
2562 type: "endviewport",
2563 line: line,
2564 col: col
2565 });
2566  
2567 },
2568  
2569 _operator: function(inFunction){
2570  
2571 var tokenStream = this._tokenStream,
2572 token = null;
2573  
2574 if (tokenStream.match([Tokens.SLASH, Tokens.COMMA]) ||
2575 (inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS]))){
2576 token = tokenStream.token();
2577 this._readWhitespace();
2578 }
2579 return token ? PropertyValuePart.fromToken(token) : null;
2580  
2581 },
2582  
2583 _combinator: function(){
2584  
2585 var tokenStream = this._tokenStream,
2586 value = null,
2587 token;
2588  
2589 if(tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])){
2590 token = tokenStream.token();
2591 value = new Combinator(token.value, token.startLine, token.startCol);
2592 this._readWhitespace();
2593 }
2594  
2595 return value;
2596 },
2597  
2598 _unary_operator: function(){
2599  
2600 var tokenStream = this._tokenStream;
2601  
2602 if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])){
2603 return tokenStream.token().value;
2604 } else {
2605 return null;
2606 }
2607 },
2608  
2609 _property: function(){
2610  
2611 var tokenStream = this._tokenStream,
2612 value = null,
2613 hack = null,
2614 tokenValue,
2615 token,
2616 line,
2617 col;
2618 if (tokenStream.peek() == Tokens.STAR && this.options.starHack){
2619 tokenStream.get();
2620 token = tokenStream.token();
2621 hack = token.value;
2622 line = token.startLine;
2623 col = token.startCol;
2624 }
2625  
2626 if(tokenStream.match(Tokens.IDENT)){
2627 token = tokenStream.token();
2628 tokenValue = token.value;
2629 if (tokenValue.charAt(0) == "_" && this.options.underscoreHack){
2630 hack = "_";
2631 tokenValue = tokenValue.substring(1);
2632 }
2633  
2634 value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol));
2635 this._readWhitespace();
2636 }
2637  
2638 return value;
2639 },
2640 _ruleset: function(){
2641  
2642 var tokenStream = this._tokenStream,
2643 tt,
2644 selectors;
2645 try {
2646 selectors = this._selectors_group();
2647 } catch (ex){
2648 if (ex instanceof SyntaxError && !this.options.strict){
2649 this.fire({
2650 type: "error",
2651 error: ex,
2652 message: ex.message,
2653 line: ex.line,
2654 col: ex.col
2655 });
2656 tt = tokenStream.advance([Tokens.RBRACE]);
2657 if (tt == Tokens.RBRACE){
2658 } else {
2659 throw ex;
2660 }
2661  
2662 } else {
2663 throw ex;
2664 }
2665 return true;
2666 }
2667 if (selectors){
2668  
2669 this.fire({
2670 type: "startrule",
2671 selectors: selectors,
2672 line: selectors[0].line,
2673 col: selectors[0].col
2674 });
2675  
2676 this._readDeclarations(true);
2677  
2678 this.fire({
2679 type: "endrule",
2680 selectors: selectors,
2681 line: selectors[0].line,
2682 col: selectors[0].col
2683 });
2684  
2685 }
2686  
2687 return selectors;
2688  
2689 },
2690 _selectors_group: function(){
2691 var tokenStream = this._tokenStream,
2692 selectors = [],
2693 selector;
2694  
2695 selector = this._selector();
2696 if (selector !== null){
2697  
2698 selectors.push(selector);
2699 while(tokenStream.match(Tokens.COMMA)){
2700 this._readWhitespace();
2701 selector = this._selector();
2702 if (selector !== null){
2703 selectors.push(selector);
2704 } else {
2705 this._unexpectedToken(tokenStream.LT(1));
2706 }
2707 }
2708 }
2709  
2710 return selectors.length ? selectors : null;
2711 },
2712 _selector: function(){
2713  
2714 var tokenStream = this._tokenStream,
2715 selector = [],
2716 nextSelector = null,
2717 combinator = null,
2718 ws = null;
2719 nextSelector = this._simple_selector_sequence();
2720 if (nextSelector === null){
2721 return null;
2722 }
2723  
2724 selector.push(nextSelector);
2725  
2726 do {
2727 combinator = this._combinator();
2728  
2729 if (combinator !== null){
2730 selector.push(combinator);
2731 nextSelector = this._simple_selector_sequence();
2732 if (nextSelector === null){
2733 this._unexpectedToken(tokenStream.LT(1));
2734 } else {
2735 selector.push(nextSelector);
2736 }
2737 } else {
2738 if (this._readWhitespace()){
2739 ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol);
2740 combinator = this._combinator();
2741 nextSelector = this._simple_selector_sequence();
2742 if (nextSelector === null){
2743 if (combinator !== null){
2744 this._unexpectedToken(tokenStream.LT(1));
2745 }
2746 } else {
2747  
2748 if (combinator !== null){
2749 selector.push(combinator);
2750 } else {
2751 selector.push(ws);
2752 }
2753  
2754 selector.push(nextSelector);
2755 }
2756 } else {
2757 break;
2758 }
2759  
2760 }
2761 } while(true);
2762  
2763 return new Selector(selector, selector[0].line, selector[0].col);
2764 },
2765 _simple_selector_sequence: function(){
2766  
2767 var tokenStream = this._tokenStream,
2768 elementName = null,
2769 modifiers = [],
2770 selectorText= "",
2771 components = [
2772 function(){
2773 return tokenStream.match(Tokens.HASH) ?
2774 new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) :
2775 null;
2776 },
2777 this._class,
2778 this._attrib,
2779 this._pseudo,
2780 this._negation
2781 ],
2782 i = 0,
2783 len = components.length,
2784 component = null,
2785 found = false,
2786 line,
2787 col;
2788 line = tokenStream.LT(1).startLine;
2789 col = tokenStream.LT(1).startCol;
2790  
2791 elementName = this._type_selector();
2792 if (!elementName){
2793 elementName = this._universal();
2794 }
2795  
2796 if (elementName !== null){
2797 selectorText += elementName;
2798 }
2799  
2800 while(true){
2801 if (tokenStream.peek() === Tokens.S){
2802 break;
2803 }
2804 while(i < len && component === null){
2805 component = components[i++].call(this);
2806 }
2807  
2808 if (component === null){
2809 if (selectorText === ""){
2810 return null;
2811 } else {
2812 break;
2813 }
2814 } else {
2815 i = 0;
2816 modifiers.push(component);
2817 selectorText += component.toString();
2818 component = null;
2819 }
2820 }
2821  
2822  
2823 return selectorText !== "" ?
2824 new SelectorPart(elementName, modifiers, selectorText, line, col) :
2825 null;
2826 },
2827 _type_selector: function(){
2828  
2829 var tokenStream = this._tokenStream,
2830 ns = this._namespace_prefix(),
2831 elementName = this._element_name();
2832  
2833 if (!elementName){
2834 if (ns){
2835 tokenStream.unget();
2836 if (ns.length > 1){
2837 tokenStream.unget();
2838 }
2839 }
2840  
2841 return null;
2842 } else {
2843 if (ns){
2844 elementName.text = ns + elementName.text;
2845 elementName.col -= ns.length;
2846 }
2847 return elementName;
2848 }
2849 },
2850 _class: function(){
2851  
2852 var tokenStream = this._tokenStream,
2853 token;
2854  
2855 if (tokenStream.match(Tokens.DOT)){
2856 tokenStream.mustMatch(Tokens.IDENT);
2857 token = tokenStream.token();
2858 return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1);
2859 } else {
2860 return null;
2861 }
2862  
2863 },
2864 _element_name: function(){
2865  
2866 var tokenStream = this._tokenStream,
2867 token;
2868  
2869 if (tokenStream.match(Tokens.IDENT)){
2870 token = tokenStream.token();
2871 return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol);
2872  
2873 } else {
2874 return null;
2875 }
2876 },
2877 _namespace_prefix: function(){
2878 var tokenStream = this._tokenStream,
2879 value = "";
2880 if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE){
2881  
2882 if(tokenStream.match([Tokens.IDENT, Tokens.STAR])){
2883 value += tokenStream.token().value;
2884 }
2885  
2886 tokenStream.mustMatch(Tokens.PIPE);
2887 value += "|";
2888  
2889 }
2890  
2891 return value.length ? value : null;
2892 },
2893 _universal: function(){
2894 var tokenStream = this._tokenStream,
2895 value = "",
2896 ns;
2897  
2898 ns = this._namespace_prefix();
2899 if(ns){
2900 value += ns;
2901 }
2902  
2903 if(tokenStream.match(Tokens.STAR)){
2904 value += "*";
2905 }
2906  
2907 return value.length ? value : null;
2908  
2909 },
2910 _attrib: function(){
2911  
2912 var tokenStream = this._tokenStream,
2913 value = null,
2914 ns,
2915 token;
2916  
2917 if (tokenStream.match(Tokens.LBRACKET)){
2918 token = tokenStream.token();
2919 value = token.value;
2920 value += this._readWhitespace();
2921  
2922 ns = this._namespace_prefix();
2923  
2924 if (ns){
2925 value += ns;
2926 }
2927  
2928 tokenStream.mustMatch(Tokens.IDENT);
2929 value += tokenStream.token().value;
2930 value += this._readWhitespace();
2931  
2932 if(tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH,
2933 Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])){
2934  
2935 value += tokenStream.token().value;
2936 value += this._readWhitespace();
2937  
2938 tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);
2939 value += tokenStream.token().value;
2940 value += this._readWhitespace();
2941 }
2942  
2943 tokenStream.mustMatch(Tokens.RBRACKET);
2944  
2945 return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol);
2946 } else {
2947 return null;
2948 }
2949 },
2950 _pseudo: function(){
2951  
2952 var tokenStream = this._tokenStream,
2953 pseudo = null,
2954 colons = ":",
2955 line,
2956 col;
2957  
2958 if (tokenStream.match(Tokens.COLON)){
2959  
2960 if (tokenStream.match(Tokens.COLON)){
2961 colons += ":";
2962 }
2963  
2964 if (tokenStream.match(Tokens.IDENT)){
2965 pseudo = tokenStream.token().value;
2966 line = tokenStream.token().startLine;
2967 col = tokenStream.token().startCol - colons.length;
2968 } else if (tokenStream.peek() == Tokens.FUNCTION){
2969 line = tokenStream.LT(1).startLine;
2970 col = tokenStream.LT(1).startCol - colons.length;
2971 pseudo = this._functional_pseudo();
2972 }
2973  
2974 if (pseudo){
2975 pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col);
2976 }
2977 }
2978  
2979 return pseudo;
2980 },
2981 _functional_pseudo: function(){
2982  
2983 var tokenStream = this._tokenStream,
2984 value = null;
2985  
2986 if(tokenStream.match(Tokens.FUNCTION)){
2987 value = tokenStream.token().value;
2988 value += this._readWhitespace();
2989 value += this._expression();
2990 tokenStream.mustMatch(Tokens.RPAREN);
2991 value += ")";
2992 }
2993  
2994 return value;
2995 },
2996 _expression: function(){
2997  
2998 var tokenStream = this._tokenStream,
2999 value = "";
3000  
3001 while(tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION,
3002 Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH,
3003 Tokens.FREQ, Tokens.ANGLE, Tokens.TIME,
3004 Tokens.RESOLUTION, Tokens.SLASH])){
3005  
3006 value += tokenStream.token().value;
3007 value += this._readWhitespace();
3008 }
3009  
3010 return value.length ? value : null;
3011  
3012 },
3013 _negation: function(){
3014  
3015 var tokenStream = this._tokenStream,
3016 line,
3017 col,
3018 value = "",
3019 arg,
3020 subpart = null;
3021  
3022 if (tokenStream.match(Tokens.NOT)){
3023 value = tokenStream.token().value;
3024 line = tokenStream.token().startLine;
3025 col = tokenStream.token().startCol;
3026 value += this._readWhitespace();
3027 arg = this._negation_arg();
3028 value += arg;
3029 value += this._readWhitespace();
3030 tokenStream.match(Tokens.RPAREN);
3031 value += tokenStream.token().value;
3032  
3033 subpart = new SelectorSubPart(value, "not", line, col);
3034 subpart.args.push(arg);
3035 }
3036  
3037 return subpart;
3038 },
3039 _negation_arg: function(){
3040  
3041 var tokenStream = this._tokenStream,
3042 args = [
3043 this._type_selector,
3044 this._universal,
3045 function(){
3046 return tokenStream.match(Tokens.HASH) ?
3047 new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) :
3048 null;
3049 },
3050 this._class,
3051 this._attrib,
3052 this._pseudo
3053 ],
3054 arg = null,
3055 i = 0,
3056 len = args.length,
3057 elementName,
3058 line,
3059 col,
3060 part;
3061  
3062 line = tokenStream.LT(1).startLine;
3063 col = tokenStream.LT(1).startCol;
3064  
3065 while(i < len && arg === null){
3066  
3067 arg = args[i].call(this);
3068 i++;
3069 }
3070 if (arg === null){
3071 this._unexpectedToken(tokenStream.LT(1));
3072 }
3073 if (arg.type == "elementName"){
3074 part = new SelectorPart(arg, [], arg.toString(), line, col);
3075 } else {
3076 part = new SelectorPart(null, [arg], arg.toString(), line, col);
3077 }
3078  
3079 return part;
3080 },
3081  
3082 _declaration: function(){
3083  
3084 var tokenStream = this._tokenStream,
3085 property = null,
3086 expr = null,
3087 prio = null,
3088 error = null,
3089 invalid = null,
3090 propertyName= "";
3091  
3092 property = this._property();
3093 if (property !== null){
3094  
3095 tokenStream.mustMatch(Tokens.COLON);
3096 this._readWhitespace();
3097  
3098 expr = this._expr();
3099 if (!expr || expr.length === 0){
3100 this._unexpectedToken(tokenStream.LT(1));
3101 }
3102  
3103 prio = this._prio();
3104 propertyName = property.toString();
3105 if (this.options.starHack && property.hack == "*" ||
3106 this.options.underscoreHack && property.hack == "_") {
3107  
3108 propertyName = property.text;
3109 }
3110  
3111 try {
3112 this._validateProperty(propertyName, expr);
3113 } catch (ex) {
3114 invalid = ex;
3115 }
3116  
3117 this.fire({
3118 type: "property",
3119 property: property,
3120 value: expr,
3121 important: prio,
3122 line: property.line,
3123 col: property.col,
3124 invalid: invalid
3125 });
3126  
3127 return true;
3128 } else {
3129 return false;
3130 }
3131 },
3132  
3133 _prio: function(){
3134  
3135 var tokenStream = this._tokenStream,
3136 result = tokenStream.match(Tokens.IMPORTANT_SYM);
3137  
3138 this._readWhitespace();
3139 return result;
3140 },
3141  
3142 _expr: function(inFunction){
3143  
3144 var tokenStream = this._tokenStream,
3145 values = [],
3146 value = null,
3147 operator = null;
3148  
3149 value = this._term(inFunction);
3150 if (value !== null){
3151  
3152 values.push(value);
3153  
3154 do {
3155 operator = this._operator(inFunction);
3156 if (operator){
3157 values.push(operator);
3158 } /*else {
3159 values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col));
3160 valueParts = [];
3161 }*/
3162  
3163 value = this._term(inFunction);
3164  
3165 if (value === null){
3166 break;
3167 } else {
3168 values.push(value);
3169 }
3170 } while(true);
3171 }
3172  
3173 return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null;
3174 },
3175  
3176 _term: function(inFunction){
3177  
3178 var tokenStream = this._tokenStream,
3179 unary = null,
3180 value = null,
3181 endChar = null,
3182 token,
3183 line,
3184 col;
3185 unary = this._unary_operator();
3186 if (unary !== null){
3187 line = tokenStream.token().startLine;
3188 col = tokenStream.token().startCol;
3189 }
3190 if (tokenStream.peek() == Tokens.IE_FUNCTION && this.options.ieFilters){
3191  
3192 value = this._ie_function();
3193 if (unary === null){
3194 line = tokenStream.token().startLine;
3195 col = tokenStream.token().startCol;
3196 }
3197 } else if (inFunction && tokenStream.match([Tokens.LPAREN, Tokens.LBRACE, Tokens.LBRACKET])){
3198  
3199 token = tokenStream.token();
3200 endChar = token.endChar;
3201 value = token.value + this._expr(inFunction).text;
3202 if (unary === null){
3203 line = tokenStream.token().startLine;
3204 col = tokenStream.token().startCol;
3205 }
3206 tokenStream.mustMatch(Tokens.type(endChar));
3207 value += endChar;
3208 this._readWhitespace();
3209 } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH,
3210 Tokens.ANGLE, Tokens.TIME,
3211 Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])){
3212  
3213 value = tokenStream.token().value;
3214 if (unary === null){
3215 line = tokenStream.token().startLine;
3216 col = tokenStream.token().startCol;
3217 }
3218 this._readWhitespace();
3219 } else {
3220 token = this._hexcolor();
3221 if (token === null){
3222 if (unary === null){
3223 line = tokenStream.LT(1).startLine;
3224 col = tokenStream.LT(1).startCol;
3225 }
3226 if (value === null){
3227 if (tokenStream.LA(3) == Tokens.EQUALS && this.options.ieFilters){
3228 value = this._ie_function();
3229 } else {
3230 value = this._function();
3231 }
3232 }
3233  
3234 } else {
3235 value = token.value;
3236 if (unary === null){
3237 line = token.startLine;
3238 col = token.startCol;
3239 }
3240 }
3241  
3242 }
3243  
3244 return value !== null ?
3245 new PropertyValuePart(unary !== null ? unary + value : value, line, col) :
3246 null;
3247  
3248 },
3249  
3250 _function: function(){
3251  
3252 var tokenStream = this._tokenStream,
3253 functionText = null,
3254 expr = null,
3255 lt;
3256  
3257 if (tokenStream.match(Tokens.FUNCTION)){
3258 functionText = tokenStream.token().value;
3259 this._readWhitespace();
3260 expr = this._expr(true);
3261 functionText += expr;
3262 if (this.options.ieFilters && tokenStream.peek() == Tokens.EQUALS){
3263 do {
3264  
3265 if (this._readWhitespace()){
3266 functionText += tokenStream.token().value;
3267 }
3268 if (tokenStream.LA(0) == Tokens.COMMA){
3269 functionText += tokenStream.token().value;
3270 }
3271  
3272 tokenStream.match(Tokens.IDENT);
3273 functionText += tokenStream.token().value;
3274  
3275 tokenStream.match(Tokens.EQUALS);
3276 functionText += tokenStream.token().value;
3277 lt = tokenStream.peek();
3278 while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){
3279 tokenStream.get();
3280 functionText += tokenStream.token().value;
3281 lt = tokenStream.peek();
3282 }
3283 } while(tokenStream.match([Tokens.COMMA, Tokens.S]));
3284 }
3285  
3286 tokenStream.match(Tokens.RPAREN);
3287 functionText += ")";
3288 this._readWhitespace();
3289 }
3290  
3291 return functionText;
3292 },
3293  
3294 _ie_function: function(){
3295  
3296 var tokenStream = this._tokenStream,
3297 functionText = null,
3298 expr = null,
3299 lt;
3300 if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])){
3301 functionText = tokenStream.token().value;
3302  
3303 do {
3304  
3305 if (this._readWhitespace()){
3306 functionText += tokenStream.token().value;
3307 }
3308 if (tokenStream.LA(0) == Tokens.COMMA){
3309 functionText += tokenStream.token().value;
3310 }
3311  
3312 tokenStream.match(Tokens.IDENT);
3313 functionText += tokenStream.token().value;
3314  
3315 tokenStream.match(Tokens.EQUALS);
3316 functionText += tokenStream.token().value;
3317 lt = tokenStream.peek();
3318 while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){
3319 tokenStream.get();
3320 functionText += tokenStream.token().value;
3321 lt = tokenStream.peek();
3322 }
3323 } while(tokenStream.match([Tokens.COMMA, Tokens.S]));
3324  
3325 tokenStream.match(Tokens.RPAREN);
3326 functionText += ")";
3327 this._readWhitespace();
3328 }
3329  
3330 return functionText;
3331 },
3332  
3333 _hexcolor: function(){
3334  
3335 var tokenStream = this._tokenStream,
3336 token = null,
3337 color;
3338  
3339 if(tokenStream.match(Tokens.HASH)){
3340  
3341 token = tokenStream.token();
3342 color = token.value;
3343 if (!/#[a-f0-9]{3,6}/i.test(color)){
3344 throw new SyntaxError("Expected a hex color but found '" + color + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
3345 }
3346 this._readWhitespace();
3347 }
3348  
3349 return token;
3350 },
3351  
3352 _keyframes: function(){
3353 var tokenStream = this._tokenStream,
3354 token,
3355 tt,
3356 name,
3357 prefix = "";
3358  
3359 tokenStream.mustMatch(Tokens.KEYFRAMES_SYM);
3360 token = tokenStream.token();
3361 if (/^@\-([^\-]+)\-/.test(token.value)) {
3362 prefix = RegExp.$1;
3363 }
3364  
3365 this._readWhitespace();
3366 name = this._keyframe_name();
3367  
3368 this._readWhitespace();
3369 tokenStream.mustMatch(Tokens.LBRACE);
3370  
3371 this.fire({
3372 type: "startkeyframes",
3373 name: name,
3374 prefix: prefix,
3375 line: token.startLine,
3376 col: token.startCol
3377 });
3378  
3379 this._readWhitespace();
3380 tt = tokenStream.peek();
3381 while(tt == Tokens.IDENT || tt == Tokens.PERCENTAGE) {
3382 this._keyframe_rule();
3383 this._readWhitespace();
3384 tt = tokenStream.peek();
3385 }
3386  
3387 this.fire({
3388 type: "endkeyframes",
3389 name: name,
3390 prefix: prefix,
3391 line: token.startLine,
3392 col: token.startCol
3393 });
3394  
3395 this._readWhitespace();
3396 tokenStream.mustMatch(Tokens.RBRACE);
3397  
3398 },
3399  
3400 _keyframe_name: function(){
3401 var tokenStream = this._tokenStream,
3402 token;
3403  
3404 tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);
3405 return SyntaxUnit.fromToken(tokenStream.token());
3406 },
3407  
3408 _keyframe_rule: function(){
3409 var tokenStream = this._tokenStream,
3410 token,
3411 keyList = this._key_list();
3412  
3413 this.fire({
3414 type: "startkeyframerule",
3415 keys: keyList,
3416 line: keyList[0].line,
3417 col: keyList[0].col
3418 });
3419  
3420 this._readDeclarations(true);
3421  
3422 this.fire({
3423 type: "endkeyframerule",
3424 keys: keyList,
3425 line: keyList[0].line,
3426 col: keyList[0].col
3427 });
3428  
3429 },
3430  
3431 _key_list: function(){
3432 var tokenStream = this._tokenStream,
3433 token,
3434 key,
3435 keyList = [];
3436 keyList.push(this._key());
3437  
3438 this._readWhitespace();
3439  
3440 while(tokenStream.match(Tokens.COMMA)){
3441 this._readWhitespace();
3442 keyList.push(this._key());
3443 this._readWhitespace();
3444 }
3445  
3446 return keyList;
3447 },
3448  
3449 _key: function(){
3450  
3451 var tokenStream = this._tokenStream,
3452 token;
3453  
3454 if (tokenStream.match(Tokens.PERCENTAGE)){
3455 return SyntaxUnit.fromToken(tokenStream.token());
3456 } else if (tokenStream.match(Tokens.IDENT)){
3457 token = tokenStream.token();
3458  
3459 if (/from|to/i.test(token.value)){
3460 return SyntaxUnit.fromToken(token);
3461 }
3462  
3463 tokenStream.unget();
3464 }
3465 this._unexpectedToken(tokenStream.LT(1));
3466 },
3467 _skipCruft: function(){
3468 while(this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])){
3469 }
3470 },
3471 _readDeclarations: function(checkStart, readMargins){
3472 var tokenStream = this._tokenStream,
3473 tt;
3474  
3475  
3476 this._readWhitespace();
3477  
3478 if (checkStart){
3479 tokenStream.mustMatch(Tokens.LBRACE);
3480 }
3481  
3482 this._readWhitespace();
3483  
3484 try {
3485  
3486 while(true){
3487  
3488 if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())){
3489 } else if (this._declaration()){
3490 if (!tokenStream.match(Tokens.SEMICOLON)){
3491 break;
3492 }
3493 } else {
3494 break;
3495 }
3496 this._readWhitespace();
3497 }
3498  
3499 tokenStream.mustMatch(Tokens.RBRACE);
3500 this._readWhitespace();
3501  
3502 } catch (ex) {
3503 if (ex instanceof SyntaxError && !this.options.strict){
3504 this.fire({
3505 type: "error",
3506 error: ex,
3507 message: ex.message,
3508 line: ex.line,
3509 col: ex.col
3510 });
3511 tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]);
3512 if (tt == Tokens.SEMICOLON){
3513 this._readDeclarations(false, readMargins);
3514 } else if (tt != Tokens.RBRACE){
3515 throw ex;
3516 }
3517  
3518 } else {
3519 throw ex;
3520 }
3521 }
3522  
3523 },
3524 _readWhitespace: function(){
3525  
3526 var tokenStream = this._tokenStream,
3527 ws = "";
3528  
3529 while(tokenStream.match(Tokens.S)){
3530 ws += tokenStream.token().value;
3531 }
3532  
3533 return ws;
3534 },
3535 _unexpectedToken: function(token){
3536 throw new SyntaxError("Unexpected token '" + token.value + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
3537 },
3538 _verifyEnd: function(){
3539 if (this._tokenStream.LA(1) != Tokens.EOF){
3540 this._unexpectedToken(this._tokenStream.LT(1));
3541 }
3542 },
3543 _validateProperty: function(property, value){
3544 Validation.validate(property, value);
3545 },
3546  
3547 parse: function(input){
3548 this._tokenStream = new TokenStream(input, Tokens);
3549 this._stylesheet();
3550 },
3551  
3552 parseStyleSheet: function(input){
3553 return this.parse(input);
3554 },
3555  
3556 parseMediaQuery: function(input){
3557 this._tokenStream = new TokenStream(input, Tokens);
3558 var result = this._media_query();
3559 this._verifyEnd();
3560 return result;
3561 },
3562 parsePropertyValue: function(input){
3563  
3564 this._tokenStream = new TokenStream(input, Tokens);
3565 this._readWhitespace();
3566  
3567 var result = this._expr();
3568 this._readWhitespace();
3569 this._verifyEnd();
3570 return result;
3571 },
3572 parseRule: function(input){
3573 this._tokenStream = new TokenStream(input, Tokens);
3574 this._readWhitespace();
3575  
3576 var result = this._ruleset();
3577 this._readWhitespace();
3578 this._verifyEnd();
3579 return result;
3580 },
3581 parseSelector: function(input){
3582  
3583 this._tokenStream = new TokenStream(input, Tokens);
3584 this._readWhitespace();
3585  
3586 var result = this._selector();
3587 this._readWhitespace();
3588 this._verifyEnd();
3589 return result;
3590 },
3591 parseStyleAttribute: function(input){
3592 input += "}"; // for error recovery in _readDeclarations()
3593 this._tokenStream = new TokenStream(input, Tokens);
3594 this._readDeclarations();
3595 }
3596 };
3597 for (prop in additions){
3598 if (additions.hasOwnProperty(prop)){
3599 proto[prop] = additions[prop];
3600 }
3601 }
3602  
3603 return proto;
3604 }();
3605 var Properties = {
3606 "align-items" : "flex-start | flex-end | center | baseline | stretch",
3607 "align-content" : "flex-start | flex-end | center | space-between | space-around | stretch",
3608 "align-self" : "auto | flex-start | flex-end | center | baseline | stretch",
3609 "-webkit-align-items" : "flex-start | flex-end | center | baseline | stretch",
3610 "-webkit-align-content" : "flex-start | flex-end | center | space-between | space-around | stretch",
3611 "-webkit-align-self" : "auto | flex-start | flex-end | center | baseline | stretch",
3612 "alignment-adjust" : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>",
3613 "alignment-baseline" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
3614 "animation" : 1,
3615 "animation-delay" : { multi: "<time>", comma: true },
3616 "animation-direction" : { multi: "normal | reverse | alternate | alternate-reverse", comma: true },
3617 "animation-duration" : { multi: "<time>", comma: true },
3618 "animation-fill-mode" : { multi: "none | forwards | backwards | both", comma: true },
3619 "animation-iteration-count" : { multi: "<number> | infinite", comma: true },
3620 "animation-name" : { multi: "none | <ident>", comma: true },
3621 "animation-play-state" : { multi: "running | paused", comma: true },
3622 "animation-timing-function" : 1,
3623 "-moz-animation-delay" : { multi: "<time>", comma: true },
3624 "-moz-animation-direction" : { multi: "normal | reverse | alternate | alternate-reverse", comma: true },
3625 "-moz-animation-duration" : { multi: "<time>", comma: true },
3626 "-moz-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
3627 "-moz-animation-name" : { multi: "none | <ident>", comma: true },
3628 "-moz-animation-play-state" : { multi: "running | paused", comma: true },
3629  
3630 "-ms-animation-delay" : { multi: "<time>", comma: true },
3631 "-ms-animation-direction" : { multi: "normal | reverse | alternate | alternate-reverse", comma: true },
3632 "-ms-animation-duration" : { multi: "<time>", comma: true },
3633 "-ms-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
3634 "-ms-animation-name" : { multi: "none | <ident>", comma: true },
3635 "-ms-animation-play-state" : { multi: "running | paused", comma: true },
3636  
3637 "-webkit-animation-delay" : { multi: "<time>", comma: true },
3638 "-webkit-animation-direction" : { multi: "normal | reverse | alternate | alternate-reverse", comma: true },
3639 "-webkit-animation-duration" : { multi: "<time>", comma: true },
3640 "-webkit-animation-fill-mode" : { multi: "none | forwards | backwards | both", comma: true },
3641 "-webkit-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
3642 "-webkit-animation-name" : { multi: "none | <ident>", comma: true },
3643 "-webkit-animation-play-state" : { multi: "running | paused", comma: true },
3644  
3645 "-o-animation-delay" : { multi: "<time>", comma: true },
3646 "-o-animation-direction" : { multi: "normal | reverse | alternate | alternate-reverse", comma: true },
3647 "-o-animation-duration" : { multi: "<time>", comma: true },
3648 "-o-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
3649 "-o-animation-name" : { multi: "none | <ident>", comma: true },
3650 "-o-animation-play-state" : { multi: "running | paused", comma: true },
3651  
3652 "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",
3653 "azimuth" : function (expression) {
3654 var simple = "<angle> | leftwards | rightwards | inherit",
3655 direction = "left-side | far-left | left | center-left | center | center-right | right | far-right | right-side",
3656 behind = false,
3657 valid = false,
3658 part;
3659  
3660 if (!ValidationTypes.isAny(expression, simple)) {
3661 if (ValidationTypes.isAny(expression, "behind")) {
3662 behind = true;
3663 valid = true;
3664 }
3665  
3666 if (ValidationTypes.isAny(expression, direction)) {
3667 valid = true;
3668 if (!behind) {
3669 ValidationTypes.isAny(expression, "behind");
3670 }
3671 }
3672 }
3673  
3674 if (expression.hasNext()) {
3675 part = expression.next();
3676 if (valid) {
3677 throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
3678 } else {
3679 throw new ValidationError("Expected (<'azimuth'>) but found '" + part + "'.", part.line, part.col);
3680 }
3681 }
3682 },
3683 "backface-visibility" : "visible | hidden",
3684 "background" : 1,
3685 "background-attachment" : { multi: "<attachment>", comma: true },
3686 "background-clip" : { multi: "<box>", comma: true },
3687 "background-color" : "<color> | inherit",
3688 "background-image" : { multi: "<bg-image>", comma: true },
3689 "background-origin" : { multi: "<box>", comma: true },
3690 "background-position" : { multi: "<bg-position>", comma: true },
3691 "background-repeat" : { multi: "<repeat-style>" },
3692 "background-size" : { multi: "<bg-size>", comma: true },
3693 "baseline-shift" : "baseline | sub | super | <percentage> | <length>",
3694 "behavior" : 1,
3695 "binding" : 1,
3696 "bleed" : "<length>",
3697 "bookmark-label" : "<content> | <attr> | <string>",
3698 "bookmark-level" : "none | <integer>",
3699 "bookmark-state" : "open | closed",
3700 "bookmark-target" : "none | <uri> | <attr>",
3701 "border" : "<border-width> || <border-style> || <color>",
3702 "border-bottom" : "<border-width> || <border-style> || <color>",
3703 "border-bottom-color" : "<color> | inherit",
3704 "border-bottom-left-radius" : "<x-one-radius>",
3705 "border-bottom-right-radius" : "<x-one-radius>",
3706 "border-bottom-style" : "<border-style>",
3707 "border-bottom-width" : "<border-width>",
3708 "border-collapse" : "collapse | separate | inherit",
3709 "border-color" : { multi: "<color> | inherit", max: 4 },
3710 "border-image" : 1,
3711 "border-image-outset" : { multi: "<length> | <number>", max: 4 },
3712 "border-image-repeat" : { multi: "stretch | repeat | round", max: 2 },
3713 "border-image-slice" : function(expression) {
3714  
3715 var valid = false,
3716 numeric = "<number> | <percentage>",
3717 fill = false,
3718 count = 0,
3719 max = 4,
3720 part;
3721  
3722 if (ValidationTypes.isAny(expression, "fill")) {
3723 fill = true;
3724 valid = true;
3725 }
3726  
3727 while (expression.hasNext() && count < max) {
3728 valid = ValidationTypes.isAny(expression, numeric);
3729 if (!valid) {
3730 break;
3731 }
3732 count++;
3733 }
3734  
3735  
3736 if (!fill) {
3737 ValidationTypes.isAny(expression, "fill");
3738 } else {
3739 valid = true;
3740 }
3741  
3742 if (expression.hasNext()) {
3743 part = expression.next();
3744 if (valid) {
3745 throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
3746 } else {
3747 throw new ValidationError("Expected ([<number> | <percentage>]{1,4} && fill?) but found '" + part + "'.", part.line, part.col);
3748 }
3749 }
3750 },
3751 "border-image-source" : "<image> | none",
3752 "border-image-width" : { multi: "<length> | <percentage> | <number> | auto", max: 4 },
3753 "border-left" : "<border-width> || <border-style> || <color>",
3754 "border-left-color" : "<color> | inherit",
3755 "border-left-style" : "<border-style>",
3756 "border-left-width" : "<border-width>",
3757 "border-radius" : function(expression) {
3758  
3759 var valid = false,
3760 simple = "<length> | <percentage> | inherit",
3761 slash = false,
3762 fill = false,
3763 count = 0,
3764 max = 8,
3765 part;
3766  
3767 while (expression.hasNext() && count < max) {
3768 valid = ValidationTypes.isAny(expression, simple);
3769 if (!valid) {
3770  
3771 if (expression.peek() == "/" && count > 0 && !slash) {
3772 slash = true;
3773 max = count + 5;
3774 expression.next();
3775 } else {
3776 break;
3777 }
3778 }
3779 count++;
3780 }
3781  
3782 if (expression.hasNext()) {
3783 part = expression.next();
3784 if (valid) {
3785 throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
3786 } else {
3787 throw new ValidationError("Expected (<'border-radius'>) but found '" + part + "'.", part.line, part.col);
3788 }
3789 }
3790 },
3791 "border-right" : "<border-width> || <border-style> || <color>",
3792 "border-right-color" : "<color> | inherit",
3793 "border-right-style" : "<border-style>",
3794 "border-right-width" : "<border-width>",
3795 "border-spacing" : { multi: "<length> | inherit", max: 2 },
3796 "border-style" : { multi: "<border-style>", max: 4 },
3797 "border-top" : "<border-width> || <border-style> || <color>",
3798 "border-top-color" : "<color> | inherit",
3799 "border-top-left-radius" : "<x-one-radius>",
3800 "border-top-right-radius" : "<x-one-radius>",
3801 "border-top-style" : "<border-style>",
3802 "border-top-width" : "<border-width>",
3803 "border-width" : { multi: "<border-width>", max: 4 },
3804 "bottom" : "<margin-width> | inherit",
3805 "-moz-box-align" : "start | end | center | baseline | stretch",
3806 "-moz-box-decoration-break" : "slice |clone",
3807 "-moz-box-direction" : "normal | reverse | inherit",
3808 "-moz-box-flex" : "<number>",
3809 "-moz-box-flex-group" : "<integer>",
3810 "-moz-box-lines" : "single | multiple",
3811 "-moz-box-ordinal-group" : "<integer>",
3812 "-moz-box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit",
3813 "-moz-box-pack" : "start | end | center | justify",
3814 "-webkit-box-align" : "start | end | center | baseline | stretch",
3815 "-webkit-box-decoration-break" : "slice |clone",
3816 "-webkit-box-direction" : "normal | reverse | inherit",
3817 "-webkit-box-flex" : "<number>",
3818 "-webkit-box-flex-group" : "<integer>",
3819 "-webkit-box-lines" : "single | multiple",
3820 "-webkit-box-ordinal-group" : "<integer>",
3821 "-webkit-box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit",
3822 "-webkit-box-pack" : "start | end | center | justify",
3823 "box-shadow" : function (expression) {
3824 var result = false,
3825 part;
3826  
3827 if (!ValidationTypes.isAny(expression, "none")) {
3828 Validation.multiProperty("<shadow>", expression, true, Infinity);
3829 } else {
3830 if (expression.hasNext()) {
3831 part = expression.next();
3832 throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
3833 }
3834 }
3835 },
3836 "box-sizing" : "content-box | border-box | inherit",
3837 "break-after" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column",
3838 "break-before" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column",
3839 "break-inside" : "auto | avoid | avoid-page | avoid-column",
3840 "caption-side" : "top | bottom | inherit",
3841 "clear" : "none | right | left | both | inherit",
3842 "clip" : 1,
3843 "color" : "<color> | inherit",
3844 "color-profile" : 1,
3845 "column-count" : "<integer> | auto", //http://www.w3.org/TR/css3-multicol/
3846 "column-fill" : "auto | balance",
3847 "column-gap" : "<length> | normal",
3848 "column-rule" : "<border-width> || <border-style> || <color>",
3849 "column-rule-color" : "<color>",
3850 "column-rule-style" : "<border-style>",
3851 "column-rule-width" : "<border-width>",
3852 "column-span" : "none | all",
3853 "column-width" : "<length> | auto",
3854 "columns" : 1,
3855 "content" : 1,
3856 "counter-increment" : 1,
3857 "counter-reset" : 1,
3858 "crop" : "<shape> | auto",
3859 "cue" : "cue-after | cue-before | inherit",
3860 "cue-after" : 1,
3861 "cue-before" : 1,
3862 "cursor" : 1,
3863 "direction" : "ltr | rtl | inherit",
3864 "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",
3865 "dominant-baseline" : 1,
3866 "drop-initial-after-adjust" : "central | middle | after-edge | text-after-edge | ideographic | alphabetic | mathematical | <percentage> | <length>",
3867 "drop-initial-after-align" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
3868 "drop-initial-before-adjust" : "before-edge | text-before-edge | central | middle | hanging | mathematical | <percentage> | <length>",
3869 "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",
3870 "drop-initial-size" : "auto | line | <length> | <percentage>",
3871 "drop-initial-value" : "initial | <integer>",
3872 "elevation" : "<angle> | below | level | above | higher | lower | inherit",
3873 "empty-cells" : "show | hide | inherit",
3874 "filter" : 1,
3875 "fit" : "fill | hidden | meet | slice",
3876 "fit-position" : 1,
3877 "flex" : "<flex>",
3878 "flex-basis" : "<width>",
3879 "flex-direction" : "row | row-reverse | column | column-reverse",
3880 "flex-flow" : "<flex-direction> || <flex-wrap>",
3881 "flex-grow" : "<number>",
3882 "flex-shrink" : "<number>",
3883 "flex-wrap" : "nowrap | wrap | wrap-reverse",
3884 "-webkit-flex" : "<flex>",
3885 "-webkit-flex-basis" : "<width>",
3886 "-webkit-flex-direction" : "row | row-reverse | column | column-reverse",
3887 "-webkit-flex-flow" : "<flex-direction> || <flex-wrap>",
3888 "-webkit-flex-grow" : "<number>",
3889 "-webkit-flex-shrink" : "<number>",
3890 "-webkit-flex-wrap" : "nowrap | wrap | wrap-reverse",
3891 "-ms-flex" : "<flex>",
3892 "-ms-flex-align" : "start | end | center | stretch | baseline",
3893 "-ms-flex-direction" : "row | row-reverse | column | column-reverse | inherit",
3894 "-ms-flex-order" : "<number>",
3895 "-ms-flex-pack" : "start | end | center | justify",
3896 "-ms-flex-wrap" : "nowrap | wrap | wrap-reverse",
3897 "float" : "left | right | none | inherit",
3898 "float-offset" : 1,
3899 "font" : 1,
3900 "font-family" : 1,
3901 "font-size" : "<absolute-size> | <relative-size> | <length> | <percentage> | inherit",
3902 "font-size-adjust" : "<number> | none | inherit",
3903 "font-stretch" : "normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | inherit",
3904 "font-style" : "normal | italic | oblique | inherit",
3905 "font-variant" : "normal | small-caps | inherit",
3906 "font-weight" : "normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit",
3907 "grid-cell-stacking" : "columns | rows | layer",
3908 "grid-column" : 1,
3909 "grid-columns" : 1,
3910 "grid-column-align" : "start | end | center | stretch",
3911 "grid-column-sizing" : 1,
3912 "grid-column-span" : "<integer>",
3913 "grid-flow" : "none | rows | columns",
3914 "grid-layer" : "<integer>",
3915 "grid-row" : 1,
3916 "grid-rows" : 1,
3917 "grid-row-align" : "start | end | center | stretch",
3918 "grid-row-span" : "<integer>",
3919 "grid-row-sizing" : 1,
3920 "hanging-punctuation" : 1,
3921 "height" : "<margin-width> | <content-sizing> | inherit",
3922 "hyphenate-after" : "<integer> | auto",
3923 "hyphenate-before" : "<integer> | auto",
3924 "hyphenate-character" : "<string> | auto",
3925 "hyphenate-lines" : "no-limit | <integer>",
3926 "hyphenate-resource" : 1,
3927 "hyphens" : "none | manual | auto",
3928 "icon" : 1,
3929 "image-orientation" : "angle | auto",
3930 "image-rendering" : 1,
3931 "image-resolution" : 1,
3932 "inline-box-align" : "initial | last | <integer>",
3933 "justify-content" : "flex-start | flex-end | center | space-between | space-around",
3934 "-webkit-justify-content" : "flex-start | flex-end | center | space-between | space-around",
3935 "left" : "<margin-width> | inherit",
3936 "letter-spacing" : "<length> | normal | inherit",
3937 "line-height" : "<number> | <length> | <percentage> | normal | inherit",
3938 "line-break" : "auto | loose | normal | strict",
3939 "line-stacking" : 1,
3940 "line-stacking-ruby" : "exclude-ruby | include-ruby",
3941 "line-stacking-shift" : "consider-shifts | disregard-shifts",
3942 "line-stacking-strategy" : "inline-line-height | block-line-height | max-height | grid-height",
3943 "list-style" : 1,
3944 "list-style-image" : "<uri> | none | inherit",
3945 "list-style-position" : "inside | outside | inherit",
3946 "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",
3947 "margin" : { multi: "<margin-width> | inherit", max: 4 },
3948 "margin-bottom" : "<margin-width> | inherit",
3949 "margin-left" : "<margin-width> | inherit",
3950 "margin-right" : "<margin-width> | inherit",
3951 "margin-top" : "<margin-width> | inherit",
3952 "mark" : 1,
3953 "mark-after" : 1,
3954 "mark-before" : 1,
3955 "marks" : 1,
3956 "marquee-direction" : 1,
3957 "marquee-play-count" : 1,
3958 "marquee-speed" : 1,
3959 "marquee-style" : 1,
3960 "max-height" : "<length> | <percentage> | <content-sizing> | none | inherit",
3961 "max-width" : "<length> | <percentage> | <content-sizing> | none | inherit",
3962 "min-height" : "<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit",
3963 "min-width" : "<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit",
3964 "move-to" : 1,
3965 "nav-down" : 1,
3966 "nav-index" : 1,
3967 "nav-left" : 1,
3968 "nav-right" : 1,
3969 "nav-up" : 1,
3970 "opacity" : "<number> | inherit",
3971 "order" : "<integer>",
3972 "-webkit-order" : "<integer>",
3973 "orphans" : "<integer> | inherit",
3974 "outline" : 1,
3975 "outline-color" : "<color> | invert | inherit",
3976 "outline-offset" : 1,
3977 "outline-style" : "<border-style> | inherit",
3978 "outline-width" : "<border-width> | inherit",
3979 "overflow" : "visible | hidden | scroll | auto | inherit",
3980 "overflow-style" : 1,
3981 "overflow-wrap" : "normal | break-word",
3982 "overflow-x" : 1,
3983 "overflow-y" : 1,
3984 "padding" : { multi: "<padding-width> | inherit", max: 4 },
3985 "padding-bottom" : "<padding-width> | inherit",
3986 "padding-left" : "<padding-width> | inherit",
3987 "padding-right" : "<padding-width> | inherit",
3988 "padding-top" : "<padding-width> | inherit",
3989 "page" : 1,
3990 "page-break-after" : "auto | always | avoid | left | right | inherit",
3991 "page-break-before" : "auto | always | avoid | left | right | inherit",
3992 "page-break-inside" : "auto | avoid | inherit",
3993 "page-policy" : 1,
3994 "pause" : 1,
3995 "pause-after" : 1,
3996 "pause-before" : 1,
3997 "perspective" : 1,
3998 "perspective-origin" : 1,
3999 "phonemes" : 1,
4000 "pitch" : 1,
4001 "pitch-range" : 1,
4002 "play-during" : 1,
4003 "pointer-events" : "auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit",
4004 "position" : "static | relative | absolute | fixed | inherit",
4005 "presentation-level" : 1,
4006 "punctuation-trim" : 1,
4007 "quotes" : 1,
4008 "rendering-intent" : 1,
4009 "resize" : 1,
4010 "rest" : 1,
4011 "rest-after" : 1,
4012 "rest-before" : 1,
4013 "richness" : 1,
4014 "right" : "<margin-width> | inherit",
4015 "rotation" : 1,
4016 "rotation-point" : 1,
4017 "ruby-align" : 1,
4018 "ruby-overhang" : 1,
4019 "ruby-position" : 1,
4020 "ruby-span" : 1,
4021 "size" : 1,
4022 "speak" : "normal | none | spell-out | inherit",
4023 "speak-header" : "once | always | inherit",
4024 "speak-numeral" : "digits | continuous | inherit",
4025 "speak-punctuation" : "code | none | inherit",
4026 "speech-rate" : 1,
4027 "src" : 1,
4028 "stress" : 1,
4029 "string-set" : 1,
4030  
4031 "table-layout" : "auto | fixed | inherit",
4032 "tab-size" : "<integer> | <length>",
4033 "target" : 1,
4034 "target-name" : 1,
4035 "target-new" : 1,
4036 "target-position" : 1,
4037 "text-align" : "left | right | center | justify | inherit" ,
4038 "text-align-last" : 1,
4039 "text-decoration" : 1,
4040 "text-emphasis" : 1,
4041 "text-height" : 1,
4042 "text-indent" : "<length> | <percentage> | inherit",
4043 "text-justify" : "auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida",
4044 "text-outline" : 1,
4045 "text-overflow" : 1,
4046 "text-rendering" : "auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit",
4047 "text-shadow" : 1,
4048 "text-transform" : "capitalize | uppercase | lowercase | none | inherit",
4049 "text-wrap" : "normal | none | avoid",
4050 "top" : "<margin-width> | inherit",
4051 "-ms-touch-action" : "auto | none | pan-x | pan-y",
4052 "touch-action" : "auto | none | pan-x | pan-y",
4053 "transform" : 1,
4054 "transform-origin" : 1,
4055 "transform-style" : 1,
4056 "transition" : 1,
4057 "transition-delay" : 1,
4058 "transition-duration" : 1,
4059 "transition-property" : 1,
4060 "transition-timing-function" : 1,
4061 "unicode-bidi" : "normal | embed | isolate | bidi-override | isolate-override | plaintext | inherit",
4062 "user-modify" : "read-only | read-write | write-only | inherit",
4063 "user-select" : "none | text | toggle | element | elements | all | inherit",
4064 "vertical-align" : "auto | use-script | baseline | sub | super | top | text-top | central | middle | bottom | text-bottom | <percentage> | <length>",
4065 "visibility" : "visible | hidden | collapse | inherit",
4066 "voice-balance" : 1,
4067 "voice-duration" : 1,
4068 "voice-family" : 1,
4069 "voice-pitch" : 1,
4070 "voice-pitch-range" : 1,
4071 "voice-rate" : 1,
4072 "voice-stress" : 1,
4073 "voice-volume" : 1,
4074 "volume" : 1,
4075 "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/
4076 "white-space-collapse" : 1,
4077 "widows" : "<integer> | inherit",
4078 "width" : "<length> | <percentage> | <content-sizing> | auto | inherit",
4079 "word-break" : "normal | keep-all | break-all",
4080 "word-spacing" : "<length> | normal | inherit",
4081 "word-wrap" : "normal | break-word",
4082 "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",
4083 "z-index" : "<integer> | auto | inherit",
4084 "zoom" : "<number> | <percentage> | normal"
4085 };
4086 function PropertyName(text, hack, line, col){
4087  
4088 SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_NAME_TYPE);
4089 this.hack = hack;
4090  
4091 }
4092  
4093 PropertyName.prototype = new SyntaxUnit();
4094 PropertyName.prototype.constructor = PropertyName;
4095 PropertyName.prototype.toString = function(){
4096 return (this.hack ? this.hack : "") + this.text;
4097 };
4098 function PropertyValue(parts, line, col){
4099  
4100 SyntaxUnit.call(this, parts.join(" "), line, col, Parser.PROPERTY_VALUE_TYPE);
4101 this.parts = parts;
4102  
4103 }
4104  
4105 PropertyValue.prototype = new SyntaxUnit();
4106 PropertyValue.prototype.constructor = PropertyValue;
4107 function PropertyValueIterator(value){
4108 this._i = 0;
4109 this._parts = value.parts;
4110 this._marks = [];
4111 this.value = value;
4112  
4113 }
4114 PropertyValueIterator.prototype.count = function(){
4115 return this._parts.length;
4116 };
4117 PropertyValueIterator.prototype.isFirst = function(){
4118 return this._i === 0;
4119 };
4120 PropertyValueIterator.prototype.hasNext = function(){
4121 return (this._i < this._parts.length);
4122 };
4123 PropertyValueIterator.prototype.mark = function(){
4124 this._marks.push(this._i);
4125 };
4126 PropertyValueIterator.prototype.peek = function(count){
4127 return this.hasNext() ? this._parts[this._i + (count || 0)] : null;
4128 };
4129 PropertyValueIterator.prototype.next = function(){
4130 return this.hasNext() ? this._parts[this._i++] : null;
4131 };
4132 PropertyValueIterator.prototype.previous = function(){
4133 return this._i > 0 ? this._parts[--this._i] : null;
4134 };
4135 PropertyValueIterator.prototype.restore = function(){
4136 if (this._marks.length){
4137 this._i = this._marks.pop();
4138 }
4139 };
4140 function PropertyValuePart(text, line, col){
4141  
4142 SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_VALUE_PART_TYPE);
4143 this.type = "unknown";
4144  
4145 var temp;
4146 if (/^([+\-]?[\d\.]+)([a-z]+)$/i.test(text)){ //dimension
4147 this.type = "dimension";
4148 this.value = +RegExp.$1;
4149 this.units = RegExp.$2;
4150 switch(this.units.toLowerCase()){
4151  
4152 case "em":
4153 case "rem":
4154 case "ex":
4155 case "px":
4156 case "cm":
4157 case "mm":
4158 case "in":
4159 case "pt":
4160 case "pc":
4161 case "ch":
4162 case "vh":
4163 case "vw":
4164 case "vmax":
4165 case "vmin":
4166 this.type = "length";
4167 break;
4168  
4169 case "deg":
4170 case "rad":
4171 case "grad":
4172 this.type = "angle";
4173 break;
4174  
4175 case "ms":
4176 case "s":
4177 this.type = "time";
4178 break;
4179  
4180 case "hz":
4181 case "khz":
4182 this.type = "frequency";
4183 break;
4184  
4185 case "dpi":
4186 case "dpcm":
4187 this.type = "resolution";
4188 break;
4189  
4190 }
4191  
4192 } else if (/^([+\-]?[\d\.]+)%$/i.test(text)){ //percentage
4193 this.type = "percentage";
4194 this.value = +RegExp.$1;
4195 } else if (/^([+\-]?\d+)$/i.test(text)){ //integer
4196 this.type = "integer";
4197 this.value = +RegExp.$1;
4198 } else if (/^([+\-]?[\d\.]+)$/i.test(text)){ //number
4199 this.type = "number";
4200 this.value = +RegExp.$1;
4201  
4202 } else if (/^#([a-f0-9]{3,6})/i.test(text)){ //hexcolor
4203 this.type = "color";
4204 temp = RegExp.$1;
4205 if (temp.length == 3){
4206 this.red = parseInt(temp.charAt(0)+temp.charAt(0),16);
4207 this.green = parseInt(temp.charAt(1)+temp.charAt(1),16);
4208 this.blue = parseInt(temp.charAt(2)+temp.charAt(2),16);
4209 } else {
4210 this.red = parseInt(temp.substring(0,2),16);
4211 this.green = parseInt(temp.substring(2,4),16);
4212 this.blue = parseInt(temp.substring(4,6),16);
4213 }
4214 } else if (/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i.test(text)){ //rgb() color with absolute numbers
4215 this.type = "color";
4216 this.red = +RegExp.$1;
4217 this.green = +RegExp.$2;
4218 this.blue = +RegExp.$3;
4219 } else if (/^rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){ //rgb() color with percentages
4220 this.type = "color";
4221 this.red = +RegExp.$1 * 255 / 100;
4222 this.green = +RegExp.$2 * 255 / 100;
4223 this.blue = +RegExp.$3 * 255 / 100;
4224 } else if (/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with absolute numbers
4225 this.type = "color";
4226 this.red = +RegExp.$1;
4227 this.green = +RegExp.$2;
4228 this.blue = +RegExp.$3;
4229 this.alpha = +RegExp.$4;
4230 } else if (/^rgba\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with percentages
4231 this.type = "color";
4232 this.red = +RegExp.$1 * 255 / 100;
4233 this.green = +RegExp.$2 * 255 / 100;
4234 this.blue = +RegExp.$3 * 255 / 100;
4235 this.alpha = +RegExp.$4;
4236 } else if (/^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){ //hsl()
4237 this.type = "color";
4238 this.hue = +RegExp.$1;
4239 this.saturation = +RegExp.$2 / 100;
4240 this.lightness = +RegExp.$3 / 100;
4241 } else if (/^hsla\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //hsla() color with percentages
4242 this.type = "color";
4243 this.hue = +RegExp.$1;
4244 this.saturation = +RegExp.$2 / 100;
4245 this.lightness = +RegExp.$3 / 100;
4246 this.alpha = +RegExp.$4;
4247 } else if (/^url\(["']?([^\)"']+)["']?\)/i.test(text)){ //URI
4248 this.type = "uri";
4249 this.uri = RegExp.$1;
4250 } else if (/^([^\(]+)\(/i.test(text)){
4251 this.type = "function";
4252 this.name = RegExp.$1;
4253 this.value = text;
4254 } else if (/^["'][^"']*["']/.test(text)){ //string
4255 this.type = "string";
4256 this.value = eval(text);
4257 } else if (Colors[text.toLowerCase()]){ //named color
4258 this.type = "color";
4259 temp = Colors[text.toLowerCase()].substring(1);
4260 this.red = parseInt(temp.substring(0,2),16);
4261 this.green = parseInt(temp.substring(2,4),16);
4262 this.blue = parseInt(temp.substring(4,6),16);
4263 } else if (/^[\,\/]$/.test(text)){
4264 this.type = "operator";
4265 this.value = text;
4266 } else if (/^[a-z\-_\u0080-\uFFFF][a-z0-9\-_\u0080-\uFFFF]*$/i.test(text)){
4267 this.type = "identifier";
4268 this.value = text;
4269 }
4270  
4271 }
4272  
4273 PropertyValuePart.prototype = new SyntaxUnit();
4274 PropertyValuePart.prototype.constructor = PropertyValuePart;
4275 PropertyValuePart.fromToken = function(token){
4276 return new PropertyValuePart(token.value, token.startLine, token.startCol);
4277 };
4278 var Pseudos = {
4279 ":first-letter": 1,
4280 ":first-line": 1,
4281 ":before": 1,
4282 ":after": 1
4283 };
4284  
4285 Pseudos.ELEMENT = 1;
4286 Pseudos.CLASS = 2;
4287  
4288 Pseudos.isElement = function(pseudo){
4289 return pseudo.indexOf("::") === 0 || Pseudos[pseudo.toLowerCase()] == Pseudos.ELEMENT;
4290 };
4291 function Selector(parts, line, col){
4292  
4293 SyntaxUnit.call(this, parts.join(" "), line, col, Parser.SELECTOR_TYPE);
4294 this.parts = parts;
4295 this.specificity = Specificity.calculate(this);
4296  
4297 }
4298  
4299 Selector.prototype = new SyntaxUnit();
4300 Selector.prototype.constructor = Selector;
4301 function SelectorPart(elementName, modifiers, text, line, col){
4302  
4303 SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_PART_TYPE);
4304 this.elementName = elementName;
4305 this.modifiers = modifiers;
4306  
4307 }
4308  
4309 SelectorPart.prototype = new SyntaxUnit();
4310 SelectorPart.prototype.constructor = SelectorPart;
4311 function SelectorSubPart(text, type, line, col){
4312  
4313 SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_SUB_PART_TYPE);
4314 this.type = type;
4315 this.args = [];
4316  
4317 }
4318  
4319 SelectorSubPart.prototype = new SyntaxUnit();
4320 SelectorSubPart.prototype.constructor = SelectorSubPart;
4321 function Specificity(a, b, c, d){
4322 this.a = a;
4323 this.b = b;
4324 this.c = c;
4325 this.d = d;
4326 }
4327  
4328 Specificity.prototype = {
4329 constructor: Specificity,
4330 compare: function(other){
4331 var comps = ["a", "b", "c", "d"],
4332 i, len;
4333  
4334 for (i=0, len=comps.length; i < len; i++){
4335 if (this[comps[i]] < other[comps[i]]){
4336 return -1;
4337 } else if (this[comps[i]] > other[comps[i]]){
4338 return 1;
4339 }
4340 }
4341  
4342 return 0;
4343 },
4344 valueOf: function(){
4345 return (this.a * 1000) + (this.b * 100) + (this.c * 10) + this.d;
4346 },
4347 toString: function(){
4348 return this.a + "," + this.b + "," + this.c + "," + this.d;
4349 }
4350  
4351 };
4352 Specificity.calculate = function(selector){
4353  
4354 var i, len,
4355 part,
4356 b=0, c=0, d=0;
4357  
4358 function updateValues(part){
4359  
4360 var i, j, len, num,
4361 elementName = part.elementName ? part.elementName.text : "",
4362 modifier;
4363  
4364 if (elementName && elementName.charAt(elementName.length-1) != "*") {
4365 d++;
4366 }
4367  
4368 for (i=0, len=part.modifiers.length; i < len; i++){
4369 modifier = part.modifiers[i];
4370 switch(modifier.type){
4371 case "class":
4372 case "attribute":
4373 c++;
4374 break;
4375  
4376 case "id":
4377 b++;
4378 break;
4379  
4380 case "pseudo":
4381 if (Pseudos.isElement(modifier.text)){
4382 d++;
4383 } else {
4384 c++;
4385 }
4386 break;
4387  
4388 case "not":
4389 for (j=0, num=modifier.args.length; j < num; j++){
4390 updateValues(modifier.args[j]);
4391 }
4392 }
4393 }
4394 }
4395  
4396 for (i=0, len=selector.parts.length; i < len; i++){
4397 part = selector.parts[i];
4398  
4399 if (part instanceof SelectorPart){
4400 updateValues(part);
4401 }
4402 }
4403  
4404 return new Specificity(0, b, c, d);
4405 };
4406  
4407 var h = /^[0-9a-fA-F]$/,
4408 nonascii = /^[\u0080-\uFFFF]$/,
4409 nl = /\n|\r\n|\r|\f/;
4410  
4411  
4412 function isHexDigit(c){
4413 return c !== null && h.test(c);
4414 }
4415  
4416 function isDigit(c){
4417 return c !== null && /\d/.test(c);
4418 }
4419  
4420 function isWhitespace(c){
4421 return c !== null && /\s/.test(c);
4422 }
4423  
4424 function isNewLine(c){
4425 return c !== null && nl.test(c);
4426 }
4427  
4428 function isNameStart(c){
4429 return c !== null && (/[a-z_\u0080-\uFFFF\\]/i.test(c));
4430 }
4431  
4432 function isNameChar(c){
4433 return c !== null && (isNameStart(c) || /[0-9\-\\]/.test(c));
4434 }
4435  
4436 function isIdentStart(c){
4437 return c !== null && (isNameStart(c) || /\-\\/.test(c));
4438 }
4439  
4440 function mix(receiver, supplier){
4441 for (var prop in supplier){
4442 if (supplier.hasOwnProperty(prop)){
4443 receiver[prop] = supplier[prop];
4444 }
4445 }
4446 return receiver;
4447 }
4448 function TokenStream(input){
4449 TokenStreamBase.call(this, input, Tokens);
4450 }
4451  
4452 TokenStream.prototype = mix(new TokenStreamBase(), {
4453 _getToken: function(channel){
4454  
4455 var c,
4456 reader = this._reader,
4457 token = null,
4458 startLine = reader.getLine(),
4459 startCol = reader.getCol();
4460  
4461 c = reader.read();
4462  
4463  
4464 while(c){
4465 switch(c){
4466 case "/":
4467  
4468 if(reader.peek() == "*"){
4469 token = this.commentToken(c, startLine, startCol);
4470 } else {
4471 token = this.charToken(c, startLine, startCol);
4472 }
4473 break;
4474 case "|":
4475 case "~":
4476 case "^":
4477 case "$":
4478 case "*":
4479 if(reader.peek() == "="){
4480 token = this.comparisonToken(c, startLine, startCol);
4481 } else {
4482 token = this.charToken(c, startLine, startCol);
4483 }
4484 break;
4485 case "\"":
4486 case "'":
4487 token = this.stringToken(c, startLine, startCol);
4488 break;
4489 case "#":
4490 if (isNameChar(reader.peek())){
4491 token = this.hashToken(c, startLine, startCol);
4492 } else {
4493 token = this.charToken(c, startLine, startCol);
4494 }
4495 break;
4496 case ".":
4497 if (isDigit(reader.peek())){
4498 token = this.numberToken(c, startLine, startCol);
4499 } else {
4500 token = this.charToken(c, startLine, startCol);
4501 }
4502 break;
4503 case "-":
4504 if (reader.peek() == "-"){ //could be closing HTML-style comment
4505 token = this.htmlCommentEndToken(c, startLine, startCol);
4506 } else if (isNameStart(reader.peek())){
4507 token = this.identOrFunctionToken(c, startLine, startCol);
4508 } else {
4509 token = this.charToken(c, startLine, startCol);
4510 }
4511 break;
4512 case "!":
4513 token = this.importantToken(c, startLine, startCol);
4514 break;
4515 case "@":
4516 token = this.atRuleToken(c, startLine, startCol);
4517 break;
4518 case ":":
4519 token = this.notToken(c, startLine, startCol);
4520 break;
4521 case "<":
4522 token = this.htmlCommentStartToken(c, startLine, startCol);
4523 break;
4524 case "U":
4525 case "u":
4526 if (reader.peek() == "+"){
4527 token = this.unicodeRangeToken(c, startLine, startCol);
4528 break;
4529 }
4530 default:
4531 if (isDigit(c)){
4532 token = this.numberToken(c, startLine, startCol);
4533 } else
4534 if (isWhitespace(c)){
4535 token = this.whitespaceToken(c, startLine, startCol);
4536 } else
4537 if (isIdentStart(c)){
4538 token = this.identOrFunctionToken(c, startLine, startCol);
4539 } else
4540 {
4541 token = this.charToken(c, startLine, startCol);
4542 }
4543  
4544  
4545  
4546  
4547  
4548  
4549 }
4550 break;
4551 }
4552  
4553 if (!token && c === null){
4554 token = this.createToken(Tokens.EOF,null,startLine,startCol);
4555 }
4556  
4557 return token;
4558 },
4559 createToken: function(tt, value, startLine, startCol, options){
4560 var reader = this._reader;
4561 options = options || {};
4562  
4563 return {
4564 value: value,
4565 type: tt,
4566 channel: options.channel,
4567 endChar: options.endChar,
4568 hide: options.hide || false,
4569 startLine: startLine,
4570 startCol: startCol,
4571 endLine: reader.getLine(),
4572 endCol: reader.getCol()
4573 };
4574 },
4575 atRuleToken: function(first, startLine, startCol){
4576 var rule = first,
4577 reader = this._reader,
4578 tt = Tokens.CHAR,
4579 valid = false,
4580 ident,
4581 c;
4582 reader.mark();
4583 ident = this.readName();
4584 rule = first + ident;
4585 tt = Tokens.type(rule.toLowerCase());
4586 if (tt == Tokens.CHAR || tt == Tokens.UNKNOWN){
4587 if (rule.length > 1){
4588 tt = Tokens.UNKNOWN_SYM;
4589 } else {
4590 tt = Tokens.CHAR;
4591 rule = first;
4592 reader.reset();
4593 }
4594 }
4595  
4596 return this.createToken(tt, rule, startLine, startCol);
4597 },
4598 charToken: function(c, startLine, startCol){
4599 var tt = Tokens.type(c);
4600 var opts = {};
4601  
4602 if (tt == -1){
4603 tt = Tokens.CHAR;
4604 } else {
4605 opts.endChar = Tokens[tt].endChar;
4606 }
4607  
4608 return this.createToken(tt, c, startLine, startCol, opts);
4609 },
4610 commentToken: function(first, startLine, startCol){
4611 var reader = this._reader,
4612 comment = this.readComment(first);
4613  
4614 return this.createToken(Tokens.COMMENT, comment, startLine, startCol);
4615 },
4616 comparisonToken: function(c, startLine, startCol){
4617 var reader = this._reader,
4618 comparison = c + reader.read(),
4619 tt = Tokens.type(comparison) || Tokens.CHAR;
4620  
4621 return this.createToken(tt, comparison, startLine, startCol);
4622 },
4623 hashToken: function(first, startLine, startCol){
4624 var reader = this._reader,
4625 name = this.readName(first);
4626  
4627 return this.createToken(Tokens.HASH, name, startLine, startCol);
4628 },
4629 htmlCommentStartToken: function(first, startLine, startCol){
4630 var reader = this._reader,
4631 text = first;
4632  
4633 reader.mark();
4634 text += reader.readCount(3);
4635  
4636 if (text == "<!--"){
4637 return this.createToken(Tokens.CDO, text, startLine, startCol);
4638 } else {
4639 reader.reset();
4640 return this.charToken(first, startLine, startCol);
4641 }
4642 },
4643 htmlCommentEndToken: function(first, startLine, startCol){
4644 var reader = this._reader,
4645 text = first;
4646  
4647 reader.mark();
4648 text += reader.readCount(2);
4649  
4650 if (text == "-->"){
4651 return this.createToken(Tokens.CDC, text, startLine, startCol);
4652 } else {
4653 reader.reset();
4654 return this.charToken(first, startLine, startCol);
4655 }
4656 },
4657 identOrFunctionToken: function(first, startLine, startCol){
4658 var reader = this._reader,
4659 ident = this.readName(first),
4660 tt = Tokens.IDENT;
4661 if (reader.peek() == "("){
4662 ident += reader.read();
4663 if (ident.toLowerCase() == "url("){
4664 tt = Tokens.URI;
4665 ident = this.readURI(ident);
4666 if (ident.toLowerCase() == "url("){
4667 tt = Tokens.FUNCTION;
4668 }
4669 } else {
4670 tt = Tokens.FUNCTION;
4671 }
4672 } else if (reader.peek() == ":"){ //might be an IE function
4673 if (ident.toLowerCase() == "progid"){
4674 ident += reader.readTo("(");
4675 tt = Tokens.IE_FUNCTION;
4676 }
4677 }
4678  
4679 return this.createToken(tt, ident, startLine, startCol);
4680 },
4681 importantToken: function(first, startLine, startCol){
4682 var reader = this._reader,
4683 important = first,
4684 tt = Tokens.CHAR,
4685 temp,
4686 c;
4687  
4688 reader.mark();
4689 c = reader.read();
4690  
4691 while(c){
4692 if (c == "/"){
4693 if (reader.peek() != "*"){
4694 break;
4695 } else {
4696 temp = this.readComment(c);
4697 if (temp === ""){ //broken!
4698 break;
4699 }
4700 }
4701 } else if (isWhitespace(c)){
4702 important += c + this.readWhitespace();
4703 } else if (/i/i.test(c)){
4704 temp = reader.readCount(8);
4705 if (/mportant/i.test(temp)){
4706 important += c + temp;
4707 tt = Tokens.IMPORTANT_SYM;
4708  
4709 }
4710 break; //we're done
4711 } else {
4712 break;
4713 }
4714  
4715 c = reader.read();
4716 }
4717  
4718 if (tt == Tokens.CHAR){
4719 reader.reset();
4720 return this.charToken(first, startLine, startCol);
4721 } else {
4722 return this.createToken(tt, important, startLine, startCol);
4723 }
4724  
4725  
4726 },
4727 notToken: function(first, startLine, startCol){
4728 var reader = this._reader,
4729 text = first;
4730  
4731 reader.mark();
4732 text += reader.readCount(4);
4733  
4734 if (text.toLowerCase() == ":not("){
4735 return this.createToken(Tokens.NOT, text, startLine, startCol);
4736 } else {
4737 reader.reset();
4738 return this.charToken(first, startLine, startCol);
4739 }
4740 },
4741 numberToken: function(first, startLine, startCol){
4742 var reader = this._reader,
4743 value = this.readNumber(first),
4744 ident,
4745 tt = Tokens.NUMBER,
4746 c = reader.peek();
4747  
4748 if (isIdentStart(c)){
4749 ident = this.readName(reader.read());
4750 value += ident;
4751  
4752 if (/^em$|^ex$|^px$|^gd$|^rem$|^vw$|^vh$|^vmax$|^vmin$|^ch$|^cm$|^mm$|^in$|^pt$|^pc$/i.test(ident)){
4753 tt = Tokens.LENGTH;
4754 } else if (/^deg|^rad$|^grad$/i.test(ident)){
4755 tt = Tokens.ANGLE;
4756 } else if (/^ms$|^s$/i.test(ident)){
4757 tt = Tokens.TIME;
4758 } else if (/^hz$|^khz$/i.test(ident)){
4759 tt = Tokens.FREQ;
4760 } else if (/^dpi$|^dpcm$/i.test(ident)){
4761 tt = Tokens.RESOLUTION;
4762 } else {
4763 tt = Tokens.DIMENSION;
4764 }
4765  
4766 } else if (c == "%"){
4767 value += reader.read();
4768 tt = Tokens.PERCENTAGE;
4769 }
4770  
4771 return this.createToken(tt, value, startLine, startCol);
4772 },
4773 stringToken: function(first, startLine, startCol){
4774 var delim = first,
4775 string = first,
4776 reader = this._reader,
4777 prev = first,
4778 tt = Tokens.STRING,
4779 c = reader.read();
4780  
4781 while(c){
4782 string += c;
4783 if (c == delim && prev != "\\"){
4784 break;
4785 }
4786 if (isNewLine(reader.peek()) && c != "\\"){
4787 tt = Tokens.INVALID;
4788 break;
4789 }
4790 prev = c;
4791 c = reader.read();
4792 }
4793 if (c === null){
4794 tt = Tokens.INVALID;
4795 }
4796  
4797 return this.createToken(tt, string, startLine, startCol);
4798 },
4799  
4800 unicodeRangeToken: function(first, startLine, startCol){
4801 var reader = this._reader,
4802 value = first,
4803 temp,
4804 tt = Tokens.CHAR;
4805 if (reader.peek() == "+"){
4806 reader.mark();
4807 value += reader.read();
4808 value += this.readUnicodeRangePart(true);
4809 if (value.length == 2){
4810 reader.reset();
4811 } else {
4812  
4813 tt = Tokens.UNICODE_RANGE;
4814 if (value.indexOf("?") == -1){
4815  
4816 if (reader.peek() == "-"){
4817 reader.mark();
4818 temp = reader.read();
4819 temp += this.readUnicodeRangePart(false);
4820 if (temp.length == 1){
4821 reader.reset();
4822 } else {
4823 value += temp;
4824 }
4825 }
4826  
4827 }
4828 }
4829 }
4830  
4831 return this.createToken(tt, value, startLine, startCol);
4832 },
4833 whitespaceToken: function(first, startLine, startCol){
4834 var reader = this._reader,
4835 value = first + this.readWhitespace();
4836 return this.createToken(Tokens.S, value, startLine, startCol);
4837 },
4838  
4839 readUnicodeRangePart: function(allowQuestionMark){
4840 var reader = this._reader,
4841 part = "",
4842 c = reader.peek();
4843 while(isHexDigit(c) && part.length < 6){
4844 reader.read();
4845 part += c;
4846 c = reader.peek();
4847 }
4848 if (allowQuestionMark){
4849 while(c == "?" && part.length < 6){
4850 reader.read();
4851 part += c;
4852 c = reader.peek();
4853 }
4854 }
4855  
4856 return part;
4857 },
4858  
4859 readWhitespace: function(){
4860 var reader = this._reader,
4861 whitespace = "",
4862 c = reader.peek();
4863  
4864 while(isWhitespace(c)){
4865 reader.read();
4866 whitespace += c;
4867 c = reader.peek();
4868 }
4869  
4870 return whitespace;
4871 },
4872 readNumber: function(first){
4873 var reader = this._reader,
4874 number = first,
4875 hasDot = (first == "."),
4876 c = reader.peek();
4877  
4878  
4879 while(c){
4880 if (isDigit(c)){
4881 number += reader.read();
4882 } else if (c == "."){
4883 if (hasDot){
4884 break;
4885 } else {
4886 hasDot = true;
4887 number += reader.read();
4888 }
4889 } else {
4890 break;
4891 }
4892  
4893 c = reader.peek();
4894 }
4895  
4896 return number;
4897 },
4898 readString: function(){
4899 var reader = this._reader,
4900 delim = reader.read(),
4901 string = delim,
4902 prev = delim,
4903 c = reader.peek();
4904  
4905 while(c){
4906 c = reader.read();
4907 string += c;
4908 if (c == delim && prev != "\\"){
4909 break;
4910 }
4911 if (isNewLine(reader.peek()) && c != "\\"){
4912 string = "";
4913 break;
4914 }
4915 prev = c;
4916 c = reader.peek();
4917 }
4918 if (c === null){
4919 string = "";
4920 }
4921  
4922 return string;
4923 },
4924 readURI: function(first){
4925 var reader = this._reader,
4926 uri = first,
4927 inner = "",
4928 c = reader.peek();
4929  
4930 reader.mark();
4931 while(c && isWhitespace(c)){
4932 reader.read();
4933 c = reader.peek();
4934 }
4935 if (c == "'" || c == "\""){
4936 inner = this.readString();
4937 } else {
4938 inner = this.readURL();
4939 }
4940  
4941 c = reader.peek();
4942 while(c && isWhitespace(c)){
4943 reader.read();
4944 c = reader.peek();
4945 }
4946 if (inner === "" || c != ")"){
4947 uri = first;
4948 reader.reset();
4949 } else {
4950 uri += inner + reader.read();
4951 }
4952  
4953 return uri;
4954 },
4955 readURL: function(){
4956 var reader = this._reader,
4957 url = "",
4958 c = reader.peek();
4959 while (/^[!#$%&\\*-~]$/.test(c)){
4960 url += reader.read();
4961 c = reader.peek();
4962 }
4963  
4964 return url;
4965  
4966 },
4967 readName: function(first){
4968 var reader = this._reader,
4969 ident = first || "",
4970 c = reader.peek();
4971  
4972 while(true){
4973 if (c == "\\"){
4974 ident += this.readEscape(reader.read());
4975 c = reader.peek();
4976 } else if(c && isNameChar(c)){
4977 ident += reader.read();
4978 c = reader.peek();
4979 } else {
4980 break;
4981 }
4982 }
4983  
4984 return ident;
4985 },
4986  
4987 readEscape: function(first){
4988 var reader = this._reader,
4989 cssEscape = first || "",
4990 i = 0,
4991 c = reader.peek();
4992  
4993 if (isHexDigit(c)){
4994 do {
4995 cssEscape += reader.read();
4996 c = reader.peek();
4997 } while(c && isHexDigit(c) && ++i < 6);
4998 }
4999  
5000 if (cssEscape.length == 3 && /\s/.test(c) ||
5001 cssEscape.length == 7 || cssEscape.length == 1){
5002 reader.read();
5003 } else {
5004 c = "";
5005 }
5006  
5007 return cssEscape + c;
5008 },
5009  
5010 readComment: function(first){
5011 var reader = this._reader,
5012 comment = first || "",
5013 c = reader.read();
5014  
5015 if (c == "*"){
5016 while(c){
5017 comment += c;
5018 if (comment.length > 2 && c == "*" && reader.peek() == "/"){
5019 comment += reader.read();
5020 break;
5021 }
5022  
5023 c = reader.read();
5024 }
5025  
5026 return comment;
5027 } else {
5028 return "";
5029 }
5030  
5031 }
5032 });
5033  
5034 var Tokens = [
5035 { name: "CDO"},
5036 { name: "CDC"},
5037 { name: "S", whitespace: true/*, channel: "ws"*/},
5038 { name: "COMMENT", comment: true, hide: true, channel: "comment" },
5039 { name: "INCLUDES", text: "~="},
5040 { name: "DASHMATCH", text: "|="},
5041 { name: "PREFIXMATCH", text: "^="},
5042 { name: "SUFFIXMATCH", text: "$="},
5043 { name: "SUBSTRINGMATCH", text: "*="},
5044 { name: "STRING"},
5045 { name: "IDENT"},
5046 { name: "HASH"},
5047 { name: "IMPORT_SYM", text: "@import"},
5048 { name: "PAGE_SYM", text: "@page"},
5049 { name: "MEDIA_SYM", text: "@media"},
5050 { name: "FONT_FACE_SYM", text: "@font-face"},
5051 { name: "CHARSET_SYM", text: "@charset"},
5052 { name: "NAMESPACE_SYM", text: "@namespace"},
5053 { name: "VIEWPORT_SYM", text: ["@viewport", "@-ms-viewport"]},
5054 { name: "UNKNOWN_SYM" },
5055 { name: "KEYFRAMES_SYM", text: [ "@keyframes", "@-webkit-keyframes", "@-moz-keyframes", "@-o-keyframes" ] },
5056 { name: "IMPORTANT_SYM"},
5057 { name: "LENGTH"},
5058 { name: "ANGLE"},
5059 { name: "TIME"},
5060 { name: "FREQ"},
5061 { name: "DIMENSION"},
5062 { name: "PERCENTAGE"},
5063 { name: "NUMBER"},
5064 { name: "URI"},
5065 { name: "FUNCTION"},
5066 { name: "UNICODE_RANGE"},
5067 { name: "INVALID"},
5068 { name: "PLUS", text: "+" },
5069 { name: "GREATER", text: ">"},
5070 { name: "COMMA", text: ","},
5071 { name: "TILDE", text: "~"},
5072 { name: "NOT"},
5073 { name: "TOPLEFTCORNER_SYM", text: "@top-left-corner"},
5074 { name: "TOPLEFT_SYM", text: "@top-left"},
5075 { name: "TOPCENTER_SYM", text: "@top-center"},
5076 { name: "TOPRIGHT_SYM", text: "@top-right"},
5077 { name: "TOPRIGHTCORNER_SYM", text: "@top-right-corner"},
5078 { name: "BOTTOMLEFTCORNER_SYM", text: "@bottom-left-corner"},
5079 { name: "BOTTOMLEFT_SYM", text: "@bottom-left"},
5080 { name: "BOTTOMCENTER_SYM", text: "@bottom-center"},
5081 { name: "BOTTOMRIGHT_SYM", text: "@bottom-right"},
5082 { name: "BOTTOMRIGHTCORNER_SYM", text: "@bottom-right-corner"},
5083 { name: "LEFTTOP_SYM", text: "@left-top"},
5084 { name: "LEFTMIDDLE_SYM", text: "@left-middle"},
5085 { name: "LEFTBOTTOM_SYM", text: "@left-bottom"},
5086 { name: "RIGHTTOP_SYM", text: "@right-top"},
5087 { name: "RIGHTMIDDLE_SYM", text: "@right-middle"},
5088 { name: "RIGHTBOTTOM_SYM", text: "@right-bottom"},
5089 { name: "RESOLUTION", state: "media"},
5090 { name: "IE_FUNCTION" },
5091 { name: "CHAR" },
5092 {
5093 name: "PIPE",
5094 text: "|"
5095 },
5096 {
5097 name: "SLASH",
5098 text: "/"
5099 },
5100 {
5101 name: "MINUS",
5102 text: "-"
5103 },
5104 {
5105 name: "STAR",
5106 text: "*"
5107 },
5108  
5109 {
5110 name: "LBRACE",
5111 endChar: "}",
5112 text: "{"
5113 },
5114 {
5115 name: "RBRACE",
5116 text: "}"
5117 },
5118 {
5119 name: "LBRACKET",
5120 endChar: "]",
5121 text: "["
5122 },
5123 {
5124 name: "RBRACKET",
5125 text: "]"
5126 },
5127 {
5128 name: "EQUALS",
5129 text: "="
5130 },
5131 {
5132 name: "COLON",
5133 text: ":"
5134 },
5135 {
5136 name: "SEMICOLON",
5137 text: ";"
5138 },
5139  
5140 {
5141 name: "LPAREN",
5142 endChar: ")",
5143 text: "("
5144 },
5145 {
5146 name: "RPAREN",
5147 text: ")"
5148 },
5149 {
5150 name: "DOT",
5151 text: "."
5152 }
5153 ];
5154  
5155 (function(){
5156  
5157 var nameMap = [],
5158 typeMap = {};
5159  
5160 Tokens.UNKNOWN = -1;
5161 Tokens.unshift({name:"EOF"});
5162 for (var i=0, len = Tokens.length; i < len; i++){
5163 nameMap.push(Tokens[i].name);
5164 Tokens[Tokens[i].name] = i;
5165 if (Tokens[i].text){
5166 if (Tokens[i].text instanceof Array){
5167 for (var j=0; j < Tokens[i].text.length; j++){
5168 typeMap[Tokens[i].text[j]] = i;
5169 }
5170 } else {
5171 typeMap[Tokens[i].text] = i;
5172 }
5173 }
5174 }
5175  
5176 Tokens.name = function(tt){
5177 return nameMap[tt];
5178 };
5179  
5180 Tokens.type = function(c){
5181 return typeMap[c] || -1;
5182 };
5183  
5184 })();
5185 var Validation = {
5186  
5187 validate: function(property, value){
5188 var name = property.toString().toLowerCase(),
5189 parts = value.parts,
5190 expression = new PropertyValueIterator(value),
5191 spec = Properties[name],
5192 part,
5193 valid,
5194 j, count,
5195 msg,
5196 types,
5197 last,
5198 literals,
5199 max, multi, group;
5200  
5201 if (!spec) {
5202 if (name.indexOf("-") !== 0){ //vendor prefixed are ok
5203 throw new ValidationError("Unknown property '" + property + "'.", property.line, property.col);
5204 }
5205 } else if (typeof spec != "number"){
5206 if (typeof spec == "string"){
5207 if (spec.indexOf("||") > -1) {
5208 this.groupProperty(spec, expression);
5209 } else {
5210 this.singleProperty(spec, expression, 1);
5211 }
5212  
5213 } else if (spec.multi) {
5214 this.multiProperty(spec.multi, expression, spec.comma, spec.max || Infinity);
5215 } else if (typeof spec == "function") {
5216 spec(expression);
5217 }
5218  
5219 }
5220  
5221 },
5222  
5223 singleProperty: function(types, expression, max, partial) {
5224  
5225 var result = false,
5226 value = expression.value,
5227 count = 0,
5228 part;
5229  
5230 while (expression.hasNext() && count < max) {
5231 result = ValidationTypes.isAny(expression, types);
5232 if (!result) {
5233 break;
5234 }
5235 count++;
5236 }
5237  
5238 if (!result) {
5239 if (expression.hasNext() && !expression.isFirst()) {
5240 part = expression.peek();
5241 throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
5242 } else {
5243 throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col);
5244 }
5245 } else if (expression.hasNext()) {
5246 part = expression.next();
5247 throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
5248 }
5249  
5250 },
5251  
5252 multiProperty: function (types, expression, comma, max) {
5253  
5254 var result = false,
5255 value = expression.value,
5256 count = 0,
5257 sep = false,
5258 part;
5259  
5260 while(expression.hasNext() && !result && count < max) {
5261 if (ValidationTypes.isAny(expression, types)) {
5262 count++;
5263 if (!expression.hasNext()) {
5264 result = true;
5265  
5266 } else if (comma) {
5267 if (expression.peek() == ",") {
5268 part = expression.next();
5269 } else {
5270 break;
5271 }
5272 }
5273 } else {
5274 break;
5275  
5276 }
5277 }
5278  
5279 if (!result) {
5280 if (expression.hasNext() && !expression.isFirst()) {
5281 part = expression.peek();
5282 throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
5283 } else {
5284 part = expression.previous();
5285 if (comma && part == ",") {
5286 throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
5287 } else {
5288 throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col);
5289 }
5290 }
5291  
5292 } else if (expression.hasNext()) {
5293 part = expression.next();
5294 throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
5295 }
5296  
5297 },
5298  
5299 groupProperty: function (types, expression, comma) {
5300  
5301 var result = false,
5302 value = expression.value,
5303 typeCount = types.split("||").length,
5304 groups = { count: 0 },
5305 partial = false,
5306 name,
5307 part;
5308  
5309 while(expression.hasNext() && !result) {
5310 name = ValidationTypes.isAnyOfGroup(expression, types);
5311 if (name) {
5312 if (groups[name]) {
5313 break;
5314 } else {
5315 groups[name] = 1;
5316 groups.count++;
5317 partial = true;
5318  
5319 if (groups.count == typeCount || !expression.hasNext()) {
5320 result = true;
5321 }
5322 }
5323 } else {
5324 break;
5325 }
5326 }
5327  
5328 if (!result) {
5329 if (partial && expression.hasNext()) {
5330 part = expression.peek();
5331 throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
5332 } else {
5333 throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col);
5334 }
5335 } else if (expression.hasNext()) {
5336 part = expression.next();
5337 throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
5338 }
5339 }
5340  
5341  
5342  
5343 };
5344 function ValidationError(message, line, col){
5345 this.col = col;
5346 this.line = line;
5347 this.message = message;
5348  
5349 }
5350 ValidationError.prototype = new Error();
5351 var ValidationTypes = {
5352  
5353 isLiteral: function (part, literals) {
5354 var text = part.text.toString().toLowerCase(),
5355 args = literals.split(" | "),
5356 i, len, found = false;
5357  
5358 for (i=0,len=args.length; i < len && !found; i++){
5359 if (text == args[i].toLowerCase()){
5360 found = true;
5361 }
5362 }
5363  
5364 return found;
5365 },
5366  
5367 isSimple: function(type) {
5368 return !!this.simple[type];
5369 },
5370  
5371 isComplex: function(type) {
5372 return !!this.complex[type];
5373 },
5374 isAny: function (expression, types) {
5375 var args = types.split(" | "),
5376 i, len, found = false;
5377  
5378 for (i=0,len=args.length; i < len && !found && expression.hasNext(); i++){
5379 found = this.isType(expression, args[i]);
5380 }
5381  
5382 return found;
5383 },
5384 isAnyOfGroup: function(expression, types) {
5385 var args = types.split(" || "),
5386 i, len, found = false;
5387  
5388 for (i=0,len=args.length; i < len && !found; i++){
5389 found = this.isType(expression, args[i]);
5390 }
5391  
5392 return found ? args[i-1] : false;
5393 },
5394 isType: function (expression, type) {
5395 var part = expression.peek(),
5396 result = false;
5397  
5398 if (type.charAt(0) != "<") {
5399 result = this.isLiteral(part, type);
5400 if (result) {
5401 expression.next();
5402 }
5403 } else if (this.simple[type]) {
5404 result = this.simple[type](part);
5405 if (result) {
5406 expression.next();
5407 }
5408 } else {
5409 result = this.complex[type](expression);
5410 }
5411  
5412 return result;
5413 },
5414  
5415  
5416  
5417 simple: {
5418  
5419 "<absolute-size>": function(part){
5420 return ValidationTypes.isLiteral(part, "xx-small | x-small | small | medium | large | x-large | xx-large");
5421 },
5422  
5423 "<attachment>": function(part){
5424 return ValidationTypes.isLiteral(part, "scroll | fixed | local");
5425 },
5426  
5427 "<attr>": function(part){
5428 return part.type == "function" && part.name == "attr";
5429 },
5430  
5431 "<bg-image>": function(part){
5432 return this["<image>"](part) || this["<gradient>"](part) || part == "none";
5433 },
5434  
5435 "<gradient>": function(part) {
5436 return part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?(?:repeating\-)?(?:radial\-|linear\-)?gradient/i.test(part);
5437 },
5438  
5439 "<box>": function(part){
5440 return ValidationTypes.isLiteral(part, "padding-box | border-box | content-box");
5441 },
5442  
5443 "<content>": function(part){
5444 return part.type == "function" && part.name == "content";
5445 },
5446  
5447 "<relative-size>": function(part){
5448 return ValidationTypes.isLiteral(part, "smaller | larger");
5449 },
5450 "<ident>": function(part){
5451 return part.type == "identifier";
5452 },
5453  
5454 "<length>": function(part){
5455 if (part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?calc/i.test(part)){
5456 return true;
5457 }else{
5458 return part.type == "length" || part.type == "number" || part.type == "integer" || part == "0";
5459 }
5460 },
5461  
5462 "<color>": function(part){
5463 return part.type == "color" || part == "transparent";
5464 },
5465  
5466 "<number>": function(part){
5467 return part.type == "number" || this["<integer>"](part);
5468 },
5469  
5470 "<integer>": function(part){
5471 return part.type == "integer";
5472 },
5473  
5474 "<line>": function(part){
5475 return part.type == "integer";
5476 },
5477  
5478 "<angle>": function(part){
5479 return part.type == "angle";
5480 },
5481  
5482 "<uri>": function(part){
5483 return part.type == "uri";
5484 },
5485  
5486 "<image>": function(part){
5487 return this["<uri>"](part);
5488 },
5489  
5490 "<percentage>": function(part){
5491 return part.type == "percentage" || part == "0";
5492 },
5493  
5494 "<border-width>": function(part){
5495 return this["<length>"](part) || ValidationTypes.isLiteral(part, "thin | medium | thick");
5496 },
5497  
5498 "<border-style>": function(part){
5499 return ValidationTypes.isLiteral(part, "none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset");
5500 },
5501  
5502 "<content-sizing>": function(part){ // http://www.w3.org/TR/css3-sizing/#width-height-keywords
5503 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");
5504 },
5505  
5506 "<margin-width>": function(part){
5507 return this["<length>"](part) || this["<percentage>"](part) || ValidationTypes.isLiteral(part, "auto");
5508 },
5509  
5510 "<padding-width>": function(part){
5511 return this["<length>"](part) || this["<percentage>"](part);
5512 },
5513  
5514 "<shape>": function(part){
5515 return part.type == "function" && (part.name == "rect" || part.name == "inset-rect");
5516 },
5517  
5518 "<time>": function(part) {
5519 return part.type == "time";
5520 },
5521  
5522 "<flex-grow>": function(part){
5523 return this["<number>"](part);
5524 },
5525  
5526 "<flex-shrink>": function(part){
5527 return this["<number>"](part);
5528 },
5529  
5530 "<width>": function(part){
5531 return this["<margin-width>"](part);
5532 },
5533  
5534 "<flex-basis>": function(part){
5535 return this["<width>"](part);
5536 },
5537  
5538 "<flex-direction>": function(part){
5539 return ValidationTypes.isLiteral(part, "row | row-reverse | column | column-reverse");
5540 },
5541  
5542 "<flex-wrap>": function(part){
5543 return ValidationTypes.isLiteral(part, "nowrap | wrap | wrap-reverse");
5544 }
5545 },
5546  
5547 complex: {
5548  
5549 "<bg-position>": function(expression){
5550 var types = this,
5551 result = false,
5552 numeric = "<percentage> | <length>",
5553 xDir = "left | right",
5554 yDir = "top | bottom",
5555 count = 0,
5556 hasNext = function() {
5557 return expression.hasNext() && expression.peek() != ",";
5558 };
5559  
5560 while (expression.peek(count) && expression.peek(count) != ",") {
5561 count++;
5562 }
5563  
5564 if (count < 3) {
5565 if (ValidationTypes.isAny(expression, xDir + " | center | " + numeric)) {
5566 result = true;
5567 ValidationTypes.isAny(expression, yDir + " | center | " + numeric);
5568 } else if (ValidationTypes.isAny(expression, yDir)) {
5569 result = true;
5570 ValidationTypes.isAny(expression, xDir + " | center");
5571 }
5572 } else {
5573 if (ValidationTypes.isAny(expression, xDir)) {
5574 if (ValidationTypes.isAny(expression, yDir)) {
5575 result = true;
5576 ValidationTypes.isAny(expression, numeric);
5577 } else if (ValidationTypes.isAny(expression, numeric)) {
5578 if (ValidationTypes.isAny(expression, yDir)) {
5579 result = true;
5580 ValidationTypes.isAny(expression, numeric);
5581 } else if (ValidationTypes.isAny(expression, "center")) {
5582 result = true;
5583 }
5584 }
5585 } else if (ValidationTypes.isAny(expression, yDir)) {
5586 if (ValidationTypes.isAny(expression, xDir)) {
5587 result = true;
5588 ValidationTypes.isAny(expression, numeric);
5589 } else if (ValidationTypes.isAny(expression, numeric)) {
5590 if (ValidationTypes.isAny(expression, xDir)) {
5591 result = true;
5592 ValidationTypes.isAny(expression, numeric);
5593 } else if (ValidationTypes.isAny(expression, "center")) {
5594 result = true;
5595 }
5596 }
5597 } else if (ValidationTypes.isAny(expression, "center")) {
5598 if (ValidationTypes.isAny(expression, xDir + " | " + yDir)) {
5599 result = true;
5600 ValidationTypes.isAny(expression, numeric);
5601 }
5602 }
5603 }
5604  
5605 return result;
5606 },
5607  
5608 "<bg-size>": function(expression){
5609 var types = this,
5610 result = false,
5611 numeric = "<percentage> | <length> | auto",
5612 part,
5613 i, len;
5614  
5615 if (ValidationTypes.isAny(expression, "cover | contain")) {
5616 result = true;
5617 } else if (ValidationTypes.isAny(expression, numeric)) {
5618 result = true;
5619 ValidationTypes.isAny(expression, numeric);
5620 }
5621  
5622 return result;
5623 },
5624  
5625 "<repeat-style>": function(expression){
5626 var result = false,
5627 values = "repeat | space | round | no-repeat",
5628 part;
5629  
5630 if (expression.hasNext()){
5631 part = expression.next();
5632  
5633 if (ValidationTypes.isLiteral(part, "repeat-x | repeat-y")) {
5634 result = true;
5635 } else if (ValidationTypes.isLiteral(part, values)) {
5636 result = true;
5637  
5638 if (expression.hasNext() && ValidationTypes.isLiteral(expression.peek(), values)) {
5639 expression.next();
5640 }
5641 }
5642 }
5643  
5644 return result;
5645  
5646 },
5647  
5648 "<shadow>": function(expression) {
5649 var result = false,
5650 count = 0,
5651 inset = false,
5652 color = false,
5653 part;
5654  
5655 if (expression.hasNext()) {
5656  
5657 if (ValidationTypes.isAny(expression, "inset")){
5658 inset = true;
5659 }
5660  
5661 if (ValidationTypes.isAny(expression, "<color>")) {
5662 color = true;
5663 }
5664  
5665 while (ValidationTypes.isAny(expression, "<length>") && count < 4) {
5666 count++;
5667 }
5668  
5669  
5670 if (expression.hasNext()) {
5671 if (!color) {
5672 ValidationTypes.isAny(expression, "<color>");
5673 }
5674  
5675 if (!inset) {
5676 ValidationTypes.isAny(expression, "inset");
5677 }
5678  
5679 }
5680  
5681 result = (count >= 2 && count <= 4);
5682  
5683 }
5684  
5685 return result;
5686 },
5687  
5688 "<x-one-radius>": function(expression) {
5689 var result = false,
5690 simple = "<length> | <percentage> | inherit";
5691  
5692 if (ValidationTypes.isAny(expression, simple)){
5693 result = true;
5694 ValidationTypes.isAny(expression, simple);
5695 }
5696  
5697 return result;
5698 },
5699  
5700 "<flex>": function(expression) {
5701 var part,
5702 result = false;
5703 if (ValidationTypes.isAny(expression, "none | inherit")) {
5704 result = true;
5705 } else {
5706 if (ValidationTypes.isType(expression, "<flex-grow>")) {
5707 if (expression.peek()) {
5708 if (ValidationTypes.isType(expression, "<flex-shrink>")) {
5709 if (expression.peek()) {
5710 result = ValidationTypes.isType(expression, "<flex-basis>");
5711 } else {
5712 result = true;
5713 }
5714 } else if (ValidationTypes.isType(expression, "<flex-basis>")) {
5715 result = expression.peek() === null;
5716 }
5717 } else {
5718 result = true;
5719 }
5720 } else if (ValidationTypes.isType(expression, "<flex-basis>")) {
5721 result = true;
5722 }
5723 }
5724  
5725 if (!result) {
5726 part = expression.peek();
5727 throw new ValidationError("Expected (none | [ <flex-grow> <flex-shrink>? || <flex-basis> ]) but found '" + expression.value.text + "'.", part.line, part.col);
5728 }
5729  
5730 return result;
5731 }
5732 }
5733 };
5734  
5735 parserlib.css = {
5736 Colors :Colors,
5737 Combinator :Combinator,
5738 Parser :Parser,
5739 PropertyName :PropertyName,
5740 PropertyValue :PropertyValue,
5741 PropertyValuePart :PropertyValuePart,
5742 MediaFeature :MediaFeature,
5743 MediaQuery :MediaQuery,
5744 Selector :Selector,
5745 SelectorPart :SelectorPart,
5746 SelectorSubPart :SelectorSubPart,
5747 Specificity :Specificity,
5748 TokenStream :TokenStream,
5749 Tokens :Tokens,
5750 ValidationError :ValidationError
5751 };
5752 })();
5753  
5754 (function(){
5755 for(var prop in parserlib){
5756 exports[prop] = parserlib[prop];
5757 }
5758 })();
5759  
5760  
5761 function objectToString(o) {
5762 return Object.prototype.toString.call(o);
5763 }
5764 var util = {
5765 isArray: function (ar) {
5766 return Array.isArray(ar) || (typeof ar === 'object' && objectToString(ar) === '[object Array]');
5767 },
5768 isDate: function (d) {
5769 return typeof d === 'object' && objectToString(d) === '[object Date]';
5770 },
5771 isRegExp: function (re) {
5772 return typeof re === 'object' && objectToString(re) === '[object RegExp]';
5773 },
5774 getRegExpFlags: function (re) {
5775 var flags = '';
5776 re.global && (flags += 'g');
5777 re.ignoreCase && (flags += 'i');
5778 re.multiline && (flags += 'm');
5779 return flags;
5780 }
5781 };
5782  
5783  
5784 if (typeof module === 'object')
5785 module.exports = clone;
5786  
5787 function clone(parent, circular, depth, prototype) {
5788 var allParents = [];
5789 var allChildren = [];
5790  
5791 var useBuffer = typeof Buffer != 'undefined';
5792  
5793 if (typeof circular == 'undefined')
5794 circular = true;
5795  
5796 if (typeof depth == 'undefined')
5797 depth = Infinity;
5798 function _clone(parent, depth) {
5799 if (parent === null)
5800 return null;
5801  
5802 if (depth == 0)
5803 return parent;
5804  
5805 var child;
5806 if (typeof parent != 'object') {
5807 return parent;
5808 }
5809  
5810 if (util.isArray(parent)) {
5811 child = [];
5812 } else if (util.isRegExp(parent)) {
5813 child = new RegExp(parent.source, util.getRegExpFlags(parent));
5814 if (parent.lastIndex) child.lastIndex = parent.lastIndex;
5815 } else if (util.isDate(parent)) {
5816 child = new Date(parent.getTime());
5817 } else if (useBuffer && Buffer.isBuffer(parent)) {
5818 child = new Buffer(parent.length);
5819 parent.copy(child);
5820 return child;
5821 } else {
5822 if (typeof prototype == 'undefined') child = Object.create(Object.getPrototypeOf(parent));
5823 else child = Object.create(prototype);
5824 }
5825  
5826 if (circular) {
5827 var index = allParents.indexOf(parent);
5828  
5829 if (index != -1) {
5830 return allChildren[index];
5831 }
5832 allParents.push(parent);
5833 allChildren.push(child);
5834 }
5835  
5836 for (var i in parent) {
5837 child[i] = _clone(parent[i], depth - 1);
5838 }
5839  
5840 return child;
5841 }
5842  
5843 return _clone(parent, depth);
5844 }
5845 clone.clonePrototype = function(parent) {
5846 if (parent === null)
5847 return null;
5848  
5849 var c = function () {};
5850 c.prototype = parent;
5851 return new c();
5852 };
5853  
5854 var CSSLint = (function(){
5855  
5856 var rules = [],
5857 formatters = [],
5858 embeddedRuleset = /\/\*csslint([^\*]*)\*\//,
5859 api = new parserlib.util.EventTarget();
5860  
5861 api.version = "@VERSION@";
5862 api.addRule = function(rule){
5863 rules.push(rule);
5864 rules[rule.id] = rule;
5865 };
5866 api.clearRules = function(){
5867 rules = [];
5868 };
5869 api.getRules = function(){
5870 return [].concat(rules).sort(function(a,b){
5871 return a.id > b.id ? 1 : 0;
5872 });
5873 };
5874 api.getRuleset = function() {
5875 var ruleset = {},
5876 i = 0,
5877 len = rules.length;
5878  
5879 while (i < len){
5880 ruleset[rules[i++].id] = 1; //by default, everything is a warning
5881 }
5882  
5883 return ruleset;
5884 };
5885 function applyEmbeddedRuleset(text, ruleset){
5886 var valueMap,
5887 embedded = text && text.match(embeddedRuleset),
5888 rules = embedded && embedded[1];
5889  
5890 if (rules) {
5891 valueMap = {
5892 "true": 2, // true is error
5893 "": 1, // blank is warning
5894 "false": 0, // false is ignore
5895  
5896 "2": 2, // explicit error
5897 "1": 1, // explicit warning
5898 "0": 0 // explicit ignore
5899 };
5900  
5901 rules.toLowerCase().split(",").forEach(function(rule){
5902 var pair = rule.split(":"),
5903 property = pair[0] || "",
5904 value = pair[1] || "";
5905  
5906 ruleset[property.trim()] = valueMap[value.trim()];
5907 });
5908 }
5909  
5910 return ruleset;
5911 }
5912 api.addFormatter = function(formatter) {
5913 formatters[formatter.id] = formatter;
5914 };
5915 api.getFormatter = function(formatId){
5916 return formatters[formatId];
5917 };
5918 api.format = function(results, filename, formatId, options) {
5919 var formatter = this.getFormatter(formatId),
5920 result = null;
5921  
5922 if (formatter){
5923 result = formatter.startFormat();
5924 result += formatter.formatResults(results, filename, options || {});
5925 result += formatter.endFormat();
5926 }
5927  
5928 return result;
5929 };
5930 api.hasFormat = function(formatId){
5931 return formatters.hasOwnProperty(formatId);
5932 };
5933 api.verify = function(text, ruleset){
5934  
5935 var i = 0,
5936 reporter,
5937 lines,
5938 report,
5939 parser = new parserlib.css.Parser({ starHack: true, ieFilters: true,
5940 underscoreHack: true, strict: false });
5941 lines = text.replace(/\n\r?/g, "$split$").split("$split$");
5942  
5943 if (!ruleset){
5944 ruleset = this.getRuleset();
5945 }
5946  
5947 if (embeddedRuleset.test(text)){
5948 ruleset = clone(ruleset);
5949 ruleset = applyEmbeddedRuleset(text, ruleset);
5950 }
5951  
5952 reporter = new Reporter(lines, ruleset);
5953  
5954 ruleset.errors = 2; //always report parsing errors as errors
5955 for (i in ruleset){
5956 if(ruleset.hasOwnProperty(i) && ruleset[i]){
5957 if (rules[i]){
5958 rules[i].init(parser, reporter);
5959 }
5960 }
5961 }
5962 try {
5963 parser.parse(text);
5964 } catch (ex) {
5965 reporter.error("Fatal error, cannot continue: " + ex.message, ex.line, ex.col, {});
5966 }
5967  
5968 report = {
5969 messages : reporter.messages,
5970 stats : reporter.stats,
5971 ruleset : reporter.ruleset
5972 };
5973 report.messages.sort(function (a, b){
5974 if (a.rollup && !b.rollup){
5975 return 1;
5976 } else if (!a.rollup && b.rollup){
5977 return -1;
5978 } else {
5979 return a.line - b.line;
5980 }
5981 });
5982  
5983 return report;
5984 };
5985  
5986 return api;
5987  
5988 })();
5989 function Reporter(lines, ruleset){
5990 this.messages = [];
5991 this.stats = [];
5992 this.lines = lines;
5993 this.ruleset = ruleset;
5994 }
5995  
5996 Reporter.prototype = {
5997 constructor: Reporter,
5998 error: function(message, line, col, rule){
5999 this.messages.push({
6000 type : "error",
6001 line : line,
6002 col : col,
6003 message : message,
6004 evidence: this.lines[line-1],
6005 rule : rule || {}
6006 });
6007 },
6008 warn: function(message, line, col, rule){
6009 this.report(message, line, col, rule);
6010 },
6011 report: function(message, line, col, rule){
6012 this.messages.push({
6013 type : this.ruleset[rule.id] === 2 ? "error" : "warning",
6014 line : line,
6015 col : col,
6016 message : message,
6017 evidence: this.lines[line-1],
6018 rule : rule
6019 });
6020 },
6021 info: function(message, line, col, rule){
6022 this.messages.push({
6023 type : "info",
6024 line : line,
6025 col : col,
6026 message : message,
6027 evidence: this.lines[line-1],
6028 rule : rule
6029 });
6030 },
6031 rollupError: function(message, rule){
6032 this.messages.push({
6033 type : "error",
6034 rollup : true,
6035 message : message,
6036 rule : rule
6037 });
6038 },
6039 rollupWarn: function(message, rule){
6040 this.messages.push({
6041 type : "warning",
6042 rollup : true,
6043 message : message,
6044 rule : rule
6045 });
6046 },
6047 stat: function(name, value){
6048 this.stats[name] = value;
6049 }
6050 };
6051 CSSLint._Reporter = Reporter;
6052 CSSLint.Util = {
6053 mix: function(receiver, supplier){
6054 var prop;
6055  
6056 for (prop in supplier){
6057 if (supplier.hasOwnProperty(prop)){
6058 receiver[prop] = supplier[prop];
6059 }
6060 }
6061  
6062 return prop;
6063 },
6064 indexOf: function(values, value){
6065 if (values.indexOf){
6066 return values.indexOf(value);
6067 } else {
6068 for (var i=0, len=values.length; i < len; i++){
6069 if (values[i] === value){
6070 return i;
6071 }
6072 }
6073 return -1;
6074 }
6075 },
6076 forEach: function(values, func) {
6077 if (values.forEach){
6078 return values.forEach(func);
6079 } else {
6080 for (var i=0, len=values.length; i < len; i++){
6081 func(values[i], i, values);
6082 }
6083 }
6084 }
6085 };
6086  
6087 CSSLint.addRule({
6088 id: "adjoining-classes",
6089 name: "Disallow adjoining classes",
6090 desc: "Don't use adjoining classes.",
6091 browsers: "IE6",
6092 init: function(parser, reporter){
6093 var rule = this;
6094 parser.addListener("startrule", function(event){
6095 var selectors = event.selectors,
6096 selector,
6097 part,
6098 modifier,
6099 classCount,
6100 i, j, k;
6101  
6102 for (i=0; i < selectors.length; i++){
6103 selector = selectors[i];
6104 for (j=0; j < selector.parts.length; j++){
6105 part = selector.parts[j];
6106 if (part.type === parser.SELECTOR_PART_TYPE){
6107 classCount = 0;
6108 for (k=0; k < part.modifiers.length; k++){
6109 modifier = part.modifiers[k];
6110 if (modifier.type === "class"){
6111 classCount++;
6112 }
6113 if (classCount > 1){
6114 reporter.report("Don't use adjoining classes.", part.line, part.col, rule);
6115 }
6116 }
6117 }
6118 }
6119 }
6120 });
6121 }
6122  
6123 });
6124 CSSLint.addRule({
6125 id: "box-model",
6126 name: "Beware of broken box size",
6127 desc: "Don't use width or height when using padding or border.",
6128 browsers: "All",
6129 init: function(parser, reporter){
6130 var rule = this,
6131 widthProperties = {
6132 border: 1,
6133 "border-left": 1,
6134 "border-right": 1,
6135 padding: 1,
6136 "padding-left": 1,
6137 "padding-right": 1
6138 },
6139 heightProperties = {
6140 border: 1,
6141 "border-bottom": 1,
6142 "border-top": 1,
6143 padding: 1,
6144 "padding-bottom": 1,
6145 "padding-top": 1
6146 },
6147 properties,
6148 boxSizing = false;
6149  
6150 function startRule(){
6151 properties = {};
6152 boxSizing = false;
6153 }
6154  
6155 function endRule(){
6156 var prop, value;
6157  
6158 if (!boxSizing) {
6159 if (properties.height){
6160 for (prop in heightProperties){
6161 if (heightProperties.hasOwnProperty(prop) && properties[prop]){
6162 value = properties[prop].value;
6163 if (!(prop === "padding" && value.parts.length === 2 && value.parts[0].value === 0)){
6164 reporter.report("Using height with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
6165 }
6166 }
6167 }
6168 }
6169  
6170 if (properties.width){
6171 for (prop in widthProperties){
6172 if (widthProperties.hasOwnProperty(prop) && properties[prop]){
6173 value = properties[prop].value;
6174  
6175 if (!(prop === "padding" && value.parts.length === 2 && value.parts[1].value === 0)){
6176 reporter.report("Using width with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
6177 }
6178 }
6179 }
6180 }
6181 }
6182 }
6183  
6184 parser.addListener("startrule", startRule);
6185 parser.addListener("startfontface", startRule);
6186 parser.addListener("startpage", startRule);
6187 parser.addListener("startpagemargin", startRule);
6188 parser.addListener("startkeyframerule", startRule);
6189  
6190 parser.addListener("property", function(event){
6191 var name = event.property.text.toLowerCase();
6192  
6193 if (heightProperties[name] || widthProperties[name]){
6194 if (!/^0\S*$/.test(event.value) && !(name === "border" && event.value.toString() === "none")){
6195 properties[name] = { line: event.property.line, col: event.property.col, value: event.value };
6196 }
6197 } else {
6198 if (/^(width|height)/i.test(name) && /^(length|percentage)/.test(event.value.parts[0].type)){
6199 properties[name] = 1;
6200 } else if (name === "box-sizing") {
6201 boxSizing = true;
6202 }
6203 }
6204  
6205 });
6206  
6207 parser.addListener("endrule", endRule);
6208 parser.addListener("endfontface", endRule);
6209 parser.addListener("endpage", endRule);
6210 parser.addListener("endpagemargin", endRule);
6211 parser.addListener("endkeyframerule", endRule);
6212 }
6213  
6214 });
6215  
6216 CSSLint.addRule({
6217 id: "box-sizing",
6218 name: "Disallow use of box-sizing",
6219 desc: "The box-sizing properties isn't supported in IE6 and IE7.",
6220 browsers: "IE6, IE7",
6221 tags: ["Compatibility"],
6222 init: function(parser, reporter){
6223 var rule = this;
6224  
6225 parser.addListener("property", function(event){
6226 var name = event.property.text.toLowerCase();
6227  
6228 if (name === "box-sizing"){
6229 reporter.report("The box-sizing property isn't supported in IE6 and IE7.", event.line, event.col, rule);
6230 }
6231 });
6232 }
6233  
6234 });
6235  
6236 CSSLint.addRule({
6237 id: "bulletproof-font-face",
6238 name: "Use the bulletproof @font-face syntax",
6239 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).",
6240 browsers: "All",
6241 init: function(parser, reporter){
6242 var rule = this,
6243 fontFaceRule = false,
6244 firstSrc = true,
6245 ruleFailed = false,
6246 line, col;
6247 parser.addListener("startfontface", function(){
6248 fontFaceRule = true;
6249 });
6250  
6251 parser.addListener("property", function(event){
6252 if (!fontFaceRule) {
6253 return;
6254 }
6255  
6256 var propertyName = event.property.toString().toLowerCase(),
6257 value = event.value.toString();
6258 line = event.line;
6259 col = event.col;
6260 if (propertyName === "src") {
6261 var regex = /^\s?url\(['"].+\.eot\?.*['"]\)\s*format\(['"]embedded-opentype['"]\).*$/i;
6262 if (!value.match(regex) && firstSrc) {
6263 ruleFailed = true;
6264 firstSrc = false;
6265 } else if (value.match(regex) && !firstSrc) {
6266 ruleFailed = false;
6267 }
6268 }
6269  
6270  
6271 });
6272 parser.addListener("endfontface", function(){
6273 fontFaceRule = false;
6274  
6275 if (ruleFailed) {
6276 reporter.report("@font-face declaration doesn't follow the fontspring bulletproof syntax.", line, col, rule);
6277 }
6278 });
6279 }
6280 });
6281  
6282 CSSLint.addRule({
6283 id: "compatible-vendor-prefixes",
6284 name: "Require compatible vendor prefixes",
6285 desc: "Include all compatible vendor prefixes to reach a wider range of users.",
6286 browsers: "All",
6287 init: function (parser, reporter) {
6288 var rule = this,
6289 compatiblePrefixes,
6290 properties,
6291 prop,
6292 variations,
6293 prefixed,
6294 i,
6295 len,
6296 inKeyFrame = false,
6297 arrayPush = Array.prototype.push,
6298 applyTo = [];
6299 compatiblePrefixes = {
6300 "animation" : "webkit moz",
6301 "animation-delay" : "webkit moz",
6302 "animation-direction" : "webkit moz",
6303 "animation-duration" : "webkit moz",
6304 "animation-fill-mode" : "webkit moz",
6305 "animation-iteration-count" : "webkit moz",
6306 "animation-name" : "webkit moz",
6307 "animation-play-state" : "webkit moz",
6308 "animation-timing-function" : "webkit moz",
6309 "appearance" : "webkit moz",
6310 "border-end" : "webkit moz",
6311 "border-end-color" : "webkit moz",
6312 "border-end-style" : "webkit moz",
6313 "border-end-width" : "webkit moz",
6314 "border-image" : "webkit moz o",
6315 "border-radius" : "webkit",
6316 "border-start" : "webkit moz",
6317 "border-start-color" : "webkit moz",
6318 "border-start-style" : "webkit moz",
6319 "border-start-width" : "webkit moz",
6320 "box-align" : "webkit moz ms",
6321 "box-direction" : "webkit moz ms",
6322 "box-flex" : "webkit moz ms",
6323 "box-lines" : "webkit ms",
6324 "box-ordinal-group" : "webkit moz ms",
6325 "box-orient" : "webkit moz ms",
6326 "box-pack" : "webkit moz ms",
6327 "box-sizing" : "webkit moz",
6328 "box-shadow" : "webkit moz",
6329 "column-count" : "webkit moz ms",
6330 "column-gap" : "webkit moz ms",
6331 "column-rule" : "webkit moz ms",
6332 "column-rule-color" : "webkit moz ms",
6333 "column-rule-style" : "webkit moz ms",
6334 "column-rule-width" : "webkit moz ms",
6335 "column-width" : "webkit moz ms",
6336 "hyphens" : "epub moz",
6337 "line-break" : "webkit ms",
6338 "margin-end" : "webkit moz",
6339 "margin-start" : "webkit moz",
6340 "marquee-speed" : "webkit wap",
6341 "marquee-style" : "webkit wap",
6342 "padding-end" : "webkit moz",
6343 "padding-start" : "webkit moz",
6344 "tab-size" : "moz o",
6345 "text-size-adjust" : "webkit ms",
6346 "transform" : "webkit moz ms o",
6347 "transform-origin" : "webkit moz ms o",
6348 "transition" : "webkit moz o",
6349 "transition-delay" : "webkit moz o",
6350 "transition-duration" : "webkit moz o",
6351 "transition-property" : "webkit moz o",
6352 "transition-timing-function" : "webkit moz o",
6353 "user-modify" : "webkit moz",
6354 "user-select" : "webkit moz ms",
6355 "word-break" : "epub ms",
6356 "writing-mode" : "epub ms"
6357 };
6358  
6359  
6360 for (prop in compatiblePrefixes) {
6361 if (compatiblePrefixes.hasOwnProperty(prop)) {
6362 variations = [];
6363 prefixed = compatiblePrefixes[prop].split(" ");
6364 for (i = 0, len = prefixed.length; i < len; i++) {
6365 variations.push("-" + prefixed[i] + "-" + prop);
6366 }
6367 compatiblePrefixes[prop] = variations;
6368 arrayPush.apply(applyTo, variations);
6369 }
6370 }
6371  
6372 parser.addListener("startrule", function () {
6373 properties = [];
6374 });
6375  
6376 parser.addListener("startkeyframes", function (event) {
6377 inKeyFrame = event.prefix || true;
6378 });
6379  
6380 parser.addListener("endkeyframes", function () {
6381 inKeyFrame = false;
6382 });
6383  
6384 parser.addListener("property", function (event) {
6385 var name = event.property;
6386 if (CSSLint.Util.indexOf(applyTo, name.text) > -1) {
6387 if (!inKeyFrame || typeof inKeyFrame !== "string" ||
6388 name.text.indexOf("-" + inKeyFrame + "-") !== 0) {
6389 properties.push(name);
6390 }
6391 }
6392 });
6393  
6394 parser.addListener("endrule", function () {
6395 if (!properties.length) {
6396 return;
6397 }
6398  
6399 var propertyGroups = {},
6400 i,
6401 len,
6402 name,
6403 prop,
6404 variations,
6405 value,
6406 full,
6407 actual,
6408 item,
6409 propertiesSpecified;
6410  
6411 for (i = 0, len = properties.length; i < len; i++) {
6412 name = properties[i];
6413  
6414 for (prop in compatiblePrefixes) {
6415 if (compatiblePrefixes.hasOwnProperty(prop)) {
6416 variations = compatiblePrefixes[prop];
6417 if (CSSLint.Util.indexOf(variations, name.text) > -1) {
6418 if (!propertyGroups[prop]) {
6419 propertyGroups[prop] = {
6420 full : variations.slice(0),
6421 actual : [],
6422 actualNodes: []
6423 };
6424 }
6425 if (CSSLint.Util.indexOf(propertyGroups[prop].actual, name.text) === -1) {
6426 propertyGroups[prop].actual.push(name.text);
6427 propertyGroups[prop].actualNodes.push(name);
6428 }
6429 }
6430 }
6431 }
6432 }
6433  
6434 for (prop in propertyGroups) {
6435 if (propertyGroups.hasOwnProperty(prop)) {
6436 value = propertyGroups[prop];
6437 full = value.full;
6438 actual = value.actual;
6439  
6440 if (full.length > actual.length) {
6441 for (i = 0, len = full.length; i < len; i++) {
6442 item = full[i];
6443 if (CSSLint.Util.indexOf(actual, item) === -1) {
6444 propertiesSpecified = (actual.length === 1) ? actual[0] : (actual.length === 2) ? actual.join(" and ") : actual.join(", ");
6445 reporter.report("The property " + item + " is compatible with " + propertiesSpecified + " and should be included as well.", value.actualNodes[0].line, value.actualNodes[0].col, rule);
6446 }
6447 }
6448  
6449 }
6450 }
6451 }
6452 });
6453 }
6454 });
6455  
6456 CSSLint.addRule({
6457 id: "display-property-grouping",
6458 name: "Require properties appropriate for display",
6459 desc: "Certain properties shouldn't be used with certain display property values.",
6460 browsers: "All",
6461 init: function(parser, reporter){
6462 var rule = this;
6463  
6464 var propertiesToCheck = {
6465 display: 1,
6466 "float": "none",
6467 height: 1,
6468 width: 1,
6469 margin: 1,
6470 "margin-left": 1,
6471 "margin-right": 1,
6472 "margin-bottom": 1,
6473 "margin-top": 1,
6474 padding: 1,
6475 "padding-left": 1,
6476 "padding-right": 1,
6477 "padding-bottom": 1,
6478 "padding-top": 1,
6479 "vertical-align": 1
6480 },
6481 properties;
6482  
6483 function reportProperty(name, display, msg){
6484 if (properties[name]){
6485 if (typeof propertiesToCheck[name] !== "string" || properties[name].value.toLowerCase() !== propertiesToCheck[name]){
6486 reporter.report(msg || name + " can't be used with display: " + display + ".", properties[name].line, properties[name].col, rule);
6487 }
6488 }
6489 }
6490  
6491 function startRule(){
6492 properties = {};
6493 }
6494  
6495 function endRule(){
6496  
6497 var display = properties.display ? properties.display.value : null;
6498 if (display){
6499 switch(display){
6500  
6501 case "inline":
6502 reportProperty("height", display);
6503 reportProperty("width", display);
6504 reportProperty("margin", display);
6505 reportProperty("margin-top", display);
6506 reportProperty("margin-bottom", display);
6507 reportProperty("float", display, "display:inline has no effect on floated elements (but may be used to fix the IE6 double-margin bug).");
6508 break;
6509  
6510 case "block":
6511 reportProperty("vertical-align", display);
6512 break;
6513  
6514 case "inline-block":
6515 reportProperty("float", display);
6516 break;
6517  
6518 default:
6519 if (display.indexOf("table-") === 0){
6520 reportProperty("margin", display);
6521 reportProperty("margin-left", display);
6522 reportProperty("margin-right", display);
6523 reportProperty("margin-top", display);
6524 reportProperty("margin-bottom", display);
6525 reportProperty("float", display);
6526 }
6527 }
6528 }
6529  
6530 }
6531  
6532 parser.addListener("startrule", startRule);
6533 parser.addListener("startfontface", startRule);
6534 parser.addListener("startkeyframerule", startRule);
6535 parser.addListener("startpagemargin", startRule);
6536 parser.addListener("startpage", startRule);
6537  
6538 parser.addListener("property", function(event){
6539 var name = event.property.text.toLowerCase();
6540  
6541 if (propertiesToCheck[name]){
6542 properties[name] = { value: event.value.text, line: event.property.line, col: event.property.col };
6543 }
6544 });
6545  
6546 parser.addListener("endrule", endRule);
6547 parser.addListener("endfontface", endRule);
6548 parser.addListener("endkeyframerule", endRule);
6549 parser.addListener("endpagemargin", endRule);
6550 parser.addListener("endpage", endRule);
6551  
6552 }
6553  
6554 });
6555  
6556 CSSLint.addRule({
6557 id: "duplicate-background-images",
6558 name: "Disallow duplicate background images",
6559 desc: "Every background-image should be unique. Use a common class for e.g. sprites.",
6560 browsers: "All",
6561 init: function(parser, reporter){
6562 var rule = this,
6563 stack = {};
6564  
6565 parser.addListener("property", function(event){
6566 var name = event.property.text,
6567 value = event.value,
6568 i, len;
6569  
6570 if (name.match(/background/i)) {
6571 for (i=0, len=value.parts.length; i < len; i++) {
6572 if (value.parts[i].type === "uri") {
6573 if (typeof stack[value.parts[i].uri] === "undefined") {
6574 stack[value.parts[i].uri] = event;
6575 }
6576 else {
6577 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);
6578 }
6579 }
6580 }
6581 }
6582 });
6583 }
6584 });
6585  
6586 CSSLint.addRule({
6587 id: "duplicate-properties",
6588 name: "Disallow duplicate properties",
6589 desc: "Duplicate properties must appear one after the other.",
6590 browsers: "All",
6591 init: function(parser, reporter){
6592 var rule = this,
6593 properties,
6594 lastProperty;
6595  
6596 function startRule(){
6597 properties = {};
6598 }
6599  
6600 parser.addListener("startrule", startRule);
6601 parser.addListener("startfontface", startRule);
6602 parser.addListener("startpage", startRule);
6603 parser.addListener("startpagemargin", startRule);
6604 parser.addListener("startkeyframerule", startRule);
6605  
6606 parser.addListener("property", function(event){
6607 var property = event.property,
6608 name = property.text.toLowerCase();
6609  
6610 if (properties[name] && (lastProperty !== name || properties[name] === event.value.text)){
6611 reporter.report("Duplicate property '" + event.property + "' found.", event.line, event.col, rule);
6612 }
6613  
6614 properties[name] = event.value.text;
6615 lastProperty = name;
6616  
6617 });
6618  
6619  
6620 }
6621  
6622 });
6623  
6624 CSSLint.addRule({
6625 id: "empty-rules",
6626 name: "Disallow empty rules",
6627 desc: "Rules without any properties specified should be removed.",
6628 browsers: "All",
6629 init: function(parser, reporter){
6630 var rule = this,
6631 count = 0;
6632  
6633 parser.addListener("startrule", function(){
6634 count=0;
6635 });
6636  
6637 parser.addListener("property", function(){
6638 count++;
6639 });
6640  
6641 parser.addListener("endrule", function(event){
6642 var selectors = event.selectors;
6643 if (count === 0){
6644 reporter.report("Rule is empty.", selectors[0].line, selectors[0].col, rule);
6645 }
6646 });
6647 }
6648  
6649 });
6650  
6651 CSSLint.addRule({
6652 id: "errors",
6653 name: "Parsing Errors",
6654 desc: "This rule looks for recoverable syntax errors.",
6655 browsers: "All",
6656 init: function(parser, reporter){
6657 var rule = this;
6658  
6659 parser.addListener("error", function(event){
6660 reporter.error(event.message, event.line, event.col, rule);
6661 });
6662  
6663 }
6664  
6665 });
6666  
6667 CSSLint.addRule({
6668 id: "fallback-colors",
6669 name: "Require fallback colors",
6670 desc: "For older browsers that don't support RGBA, HSL, or HSLA, provide a fallback color.",
6671 browsers: "IE6,IE7,IE8",
6672 init: function(parser, reporter){
6673 var rule = this,
6674 lastProperty,
6675 propertiesToCheck = {
6676 color: 1,
6677 background: 1,
6678 "border-color": 1,
6679 "border-top-color": 1,
6680 "border-right-color": 1,
6681 "border-bottom-color": 1,
6682 "border-left-color": 1,
6683 border: 1,
6684 "border-top": 1,
6685 "border-right": 1,
6686 "border-bottom": 1,
6687 "border-left": 1,
6688 "background-color": 1
6689 },
6690 properties;
6691  
6692 function startRule(){
6693 properties = {};
6694 lastProperty = null;
6695 }
6696  
6697 parser.addListener("startrule", startRule);
6698 parser.addListener("startfontface", startRule);
6699 parser.addListener("startpage", startRule);
6700 parser.addListener("startpagemargin", startRule);
6701 parser.addListener("startkeyframerule", startRule);
6702  
6703 parser.addListener("property", function(event){
6704 var property = event.property,
6705 name = property.text.toLowerCase(),
6706 parts = event.value.parts,
6707 i = 0,
6708 colorType = "",
6709 len = parts.length;
6710  
6711 if(propertiesToCheck[name]){
6712 while(i < len){
6713 if (parts[i].type === "color"){
6714 if ("alpha" in parts[i] || "hue" in parts[i]){
6715  
6716 if (/([^\)]+)\(/.test(parts[i])){
6717 colorType = RegExp.$1.toUpperCase();
6718 }
6719  
6720 if (!lastProperty || (lastProperty.property.text.toLowerCase() !== name || lastProperty.colorType !== "compat")){
6721 reporter.report("Fallback " + name + " (hex or RGB) should precede " + colorType + " " + name + ".", event.line, event.col, rule);
6722 }
6723 } else {
6724 event.colorType = "compat";
6725 }
6726 }
6727  
6728 i++;
6729 }
6730 }
6731  
6732 lastProperty = event;
6733 });
6734  
6735 }
6736  
6737 });
6738  
6739 CSSLint.addRule({
6740 id: "floats",
6741 name: "Disallow too many floats",
6742 desc: "This rule tests if the float property is used too many times",
6743 browsers: "All",
6744 init: function(parser, reporter){
6745 var rule = this;
6746 var count = 0;
6747 parser.addListener("property", function(event){
6748 if (event.property.text.toLowerCase() === "float" &&
6749 event.value.text.toLowerCase() !== "none"){
6750 count++;
6751 }
6752 });
6753 parser.addListener("endstylesheet", function(){
6754 reporter.stat("floats", count);
6755 if (count >= 10){
6756 reporter.rollupWarn("Too many floats (" + count + "), you're probably using them for layout. Consider using a grid system instead.", rule);
6757 }
6758 });
6759 }
6760  
6761 });
6762  
6763 CSSLint.addRule({
6764 id: "font-faces",
6765 name: "Don't use too many web fonts",
6766 desc: "Too many different web fonts in the same stylesheet.",
6767 browsers: "All",
6768 init: function(parser, reporter){
6769 var rule = this,
6770 count = 0;
6771  
6772  
6773 parser.addListener("startfontface", function(){
6774 count++;
6775 });
6776  
6777 parser.addListener("endstylesheet", function(){
6778 if (count > 5){
6779 reporter.rollupWarn("Too many @font-face declarations (" + count + ").", rule);
6780 }
6781 });
6782 }
6783  
6784 });
6785  
6786 CSSLint.addRule({
6787 id: "font-sizes",
6788 name: "Disallow too many font sizes",
6789 desc: "Checks the number of font-size declarations.",
6790 browsers: "All",
6791 init: function(parser, reporter){
6792 var rule = this,
6793 count = 0;
6794 parser.addListener("property", function(event){
6795 if (event.property.toString() === "font-size"){
6796 count++;
6797 }
6798 });
6799 parser.addListener("endstylesheet", function(){
6800 reporter.stat("font-sizes", count);
6801 if (count >= 10){
6802 reporter.rollupWarn("Too many font-size declarations (" + count + "), abstraction needed.", rule);
6803 }
6804 });
6805 }
6806  
6807 });
6808  
6809 CSSLint.addRule({
6810 id: "gradients",
6811 name: "Require all gradient definitions",
6812 desc: "When using a vendor-prefixed gradient, make sure to use them all.",
6813 browsers: "All",
6814 init: function(parser, reporter){
6815 var rule = this,
6816 gradients;
6817  
6818 parser.addListener("startrule", function(){
6819 gradients = {
6820 moz: 0,
6821 webkit: 0,
6822 oldWebkit: 0,
6823 o: 0
6824 };
6825 });
6826  
6827 parser.addListener("property", function(event){
6828  
6829 if (/\-(moz|o|webkit)(?:\-(?:linear|radial))\-gradient/i.test(event.value)){
6830 gradients[RegExp.$1] = 1;
6831 } else if (/\-webkit\-gradient/i.test(event.value)){
6832 gradients.oldWebkit = 1;
6833 }
6834  
6835 });
6836  
6837 parser.addListener("endrule", function(event){
6838 var missing = [];
6839  
6840 if (!gradients.moz){
6841 missing.push("Firefox 3.6+");
6842 }
6843  
6844 if (!gradients.webkit){
6845 missing.push("Webkit (Safari 5+, Chrome)");
6846 }
6847  
6848 if (!gradients.oldWebkit){
6849 missing.push("Old Webkit (Safari 4+, Chrome)");
6850 }
6851  
6852 if (!gradients.o){
6853 missing.push("Opera 11.1+");
6854 }
6855  
6856 if (missing.length && missing.length < 4){
6857 reporter.report("Missing vendor-prefixed CSS gradients for " + missing.join(", ") + ".", event.selectors[0].line, event.selectors[0].col, rule);
6858 }
6859  
6860 });
6861  
6862 }
6863  
6864 });
6865  
6866 CSSLint.addRule({
6867 id: "ids",
6868 name: "Disallow IDs in selectors",
6869 desc: "Selectors should not contain IDs.",
6870 browsers: "All",
6871 init: function(parser, reporter){
6872 var rule = this;
6873 parser.addListener("startrule", function(event){
6874 var selectors = event.selectors,
6875 selector,
6876 part,
6877 modifier,
6878 idCount,
6879 i, j, k;
6880  
6881 for (i=0; i < selectors.length; i++){
6882 selector = selectors[i];
6883 idCount = 0;
6884  
6885 for (j=0; j < selector.parts.length; j++){
6886 part = selector.parts[j];
6887 if (part.type === parser.SELECTOR_PART_TYPE){
6888 for (k=0; k < part.modifiers.length; k++){
6889 modifier = part.modifiers[k];
6890 if (modifier.type === "id"){
6891 idCount++;
6892 }
6893 }
6894 }
6895 }
6896  
6897 if (idCount === 1){
6898 reporter.report("Don't use IDs in selectors.", selector.line, selector.col, rule);
6899 } else if (idCount > 1){
6900 reporter.report(idCount + " IDs in the selector, really?", selector.line, selector.col, rule);
6901 }
6902 }
6903  
6904 });
6905 }
6906  
6907 });
6908  
6909 CSSLint.addRule({
6910 id: "import",
6911 name: "Disallow @import",
6912 desc: "Don't use @import, use <link> instead.",
6913 browsers: "All",
6914 init: function(parser, reporter){
6915 var rule = this;
6916  
6917 parser.addListener("import", function(event){
6918 reporter.report("@import prevents parallel downloads, use <link> instead.", event.line, event.col, rule);
6919 });
6920  
6921 }
6922  
6923 });
6924  
6925 CSSLint.addRule({
6926 id: "important",
6927 name: "Disallow !important",
6928 desc: "Be careful when using !important declaration",
6929 browsers: "All",
6930 init: function(parser, reporter){
6931 var rule = this,
6932 count = 0;
6933 parser.addListener("property", function(event){
6934 if (event.important === true){
6935 count++;
6936 reporter.report("Use of !important", event.line, event.col, rule);
6937 }
6938 });
6939 parser.addListener("endstylesheet", function(){
6940 reporter.stat("important", count);
6941 if (count >= 10){
6942 reporter.rollupWarn("Too many !important declarations (" + count + "), try to use less than 10 to avoid specificity issues.", rule);
6943 }
6944 });
6945 }
6946  
6947 });
6948  
6949 CSSLint.addRule({
6950 id: "known-properties",
6951 name: "Require use of known properties",
6952 desc: "Properties should be known (listed in CSS3 specification) or be a vendor-prefixed property.",
6953 browsers: "All",
6954 init: function(parser, reporter){
6955 var rule = this;
6956  
6957 parser.addListener("property", function(event){
6958 if (event.invalid) {
6959 reporter.report(event.invalid.message, event.line, event.col, rule);
6960 }
6961  
6962 });
6963 }
6964  
6965 });
6966 CSSLint.addRule({
6967 id: "order-alphabetical",
6968 name: "Alphabetical order",
6969 desc: "Assure properties are in alphabetical order",
6970 browsers: "All",
6971 init: function(parser, reporter){
6972 var rule = this,
6973 properties;
6974  
6975 var startRule = function () {
6976 properties = [];
6977 };
6978  
6979 parser.addListener("startrule", startRule);
6980 parser.addListener("startfontface", startRule);
6981 parser.addListener("startpage", startRule);
6982 parser.addListener("startpagemargin", startRule);
6983 parser.addListener("startkeyframerule", startRule);
6984  
6985 parser.addListener("property", function(event){
6986 var name = event.property.text,
6987 lowerCasePrefixLessName = name.toLowerCase().replace(/^-.*?-/, "");
6988  
6989 properties.push(lowerCasePrefixLessName);
6990 });
6991  
6992 parser.addListener("endrule", function(event){
6993 var currentProperties = properties.join(","),
6994 expectedProperties = properties.sort().join(",");
6995  
6996 if (currentProperties !== expectedProperties){
6997 reporter.report("Rule doesn't have all its properties in alphabetical ordered.", event.line, event.col, rule);
6998 }
6999 });
7000 }
7001  
7002 });
7003  
7004 CSSLint.addRule({
7005 id: "outline-none",
7006 name: "Disallow outline: none",
7007 desc: "Use of outline: none or outline: 0 should be limited to :focus rules.",
7008 browsers: "All",
7009 tags: ["Accessibility"],
7010 init: function(parser, reporter){
7011 var rule = this,
7012 lastRule;
7013  
7014 function startRule(event){
7015 if (event.selectors){
7016 lastRule = {
7017 line: event.line,
7018 col: event.col,
7019 selectors: event.selectors,
7020 propCount: 0,
7021 outline: false
7022 };
7023 } else {
7024 lastRule = null;
7025 }
7026 }
7027  
7028 function endRule(){
7029 if (lastRule){
7030 if (lastRule.outline){
7031 if (lastRule.selectors.toString().toLowerCase().indexOf(":focus") === -1){
7032 reporter.report("Outlines should only be modified using :focus.", lastRule.line, lastRule.col, rule);
7033 } else if (lastRule.propCount === 1) {
7034 reporter.report("Outlines shouldn't be hidden unless other visual changes are made.", lastRule.line, lastRule.col, rule);
7035 }
7036 }
7037 }
7038 }
7039  
7040 parser.addListener("startrule", startRule);
7041 parser.addListener("startfontface", startRule);
7042 parser.addListener("startpage", startRule);
7043 parser.addListener("startpagemargin", startRule);
7044 parser.addListener("startkeyframerule", startRule);
7045  
7046 parser.addListener("property", function(event){
7047 var name = event.property.text.toLowerCase(),
7048 value = event.value;
7049  
7050 if (lastRule){
7051 lastRule.propCount++;
7052 if (name === "outline" && (value.toString() === "none" || value.toString() === "0")){
7053 lastRule.outline = true;
7054 }
7055 }
7056  
7057 });
7058  
7059 parser.addListener("endrule", endRule);
7060 parser.addListener("endfontface", endRule);
7061 parser.addListener("endpage", endRule);
7062 parser.addListener("endpagemargin", endRule);
7063 parser.addListener("endkeyframerule", endRule);
7064  
7065 }
7066  
7067 });
7068  
7069 CSSLint.addRule({
7070 id: "overqualified-elements",
7071 name: "Disallow overqualified elements",
7072 desc: "Don't use classes or IDs with elements (a.foo or a#foo).",
7073 browsers: "All",
7074 init: function(parser, reporter){
7075 var rule = this,
7076 classes = {};
7077  
7078 parser.addListener("startrule", function(event){
7079 var selectors = event.selectors,
7080 selector,
7081 part,
7082 modifier,
7083 i, j, k;
7084  
7085 for (i=0; i < selectors.length; i++){
7086 selector = selectors[i];
7087  
7088 for (j=0; j < selector.parts.length; j++){
7089 part = selector.parts[j];
7090 if (part.type === parser.SELECTOR_PART_TYPE){
7091 for (k=0; k < part.modifiers.length; k++){
7092 modifier = part.modifiers[k];
7093 if (part.elementName && modifier.type === "id"){
7094 reporter.report("Element (" + part + ") is overqualified, just use " + modifier + " without element name.", part.line, part.col, rule);
7095 } else if (modifier.type === "class"){
7096  
7097 if (!classes[modifier]){
7098 classes[modifier] = [];
7099 }
7100 classes[modifier].push({ modifier: modifier, part: part });
7101 }
7102 }
7103 }
7104 }
7105 }
7106 });
7107  
7108 parser.addListener("endstylesheet", function(){
7109  
7110 var prop;
7111 for (prop in classes){
7112 if (classes.hasOwnProperty(prop)){
7113 if (classes[prop].length === 1 && classes[prop][0].part.elementName){
7114 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);
7115 }
7116 }
7117 }
7118 });
7119 }
7120  
7121 });
7122  
7123 CSSLint.addRule({
7124 id: "qualified-headings",
7125 name: "Disallow qualified headings",
7126 desc: "Headings should not be qualified (namespaced).",
7127 browsers: "All",
7128 init: function(parser, reporter){
7129 var rule = this;
7130  
7131 parser.addListener("startrule", function(event){
7132 var selectors = event.selectors,
7133 selector,
7134 part,
7135 i, j;
7136  
7137 for (i=0; i < selectors.length; i++){
7138 selector = selectors[i];
7139  
7140 for (j=0; j < selector.parts.length; j++){
7141 part = selector.parts[j];
7142 if (part.type === parser.SELECTOR_PART_TYPE){
7143 if (part.elementName && /h[1-6]/.test(part.elementName.toString()) && j > 0){
7144 reporter.report("Heading (" + part.elementName + ") should not be qualified.", part.line, part.col, rule);
7145 }
7146 }
7147 }
7148 }
7149 });
7150 }
7151  
7152 });
7153  
7154 CSSLint.addRule({
7155 id: "regex-selectors",
7156 name: "Disallow selectors that look like regexs",
7157 desc: "Selectors that look like regular expressions are slow and should be avoided.",
7158 browsers: "All",
7159 init: function(parser, reporter){
7160 var rule = this;
7161  
7162 parser.addListener("startrule", function(event){
7163 var selectors = event.selectors,
7164 selector,
7165 part,
7166 modifier,
7167 i, j, k;
7168  
7169 for (i=0; i < selectors.length; i++){
7170 selector = selectors[i];
7171 for (j=0; j < selector.parts.length; j++){
7172 part = selector.parts[j];
7173 if (part.type === parser.SELECTOR_PART_TYPE){
7174 for (k=0; k < part.modifiers.length; k++){
7175 modifier = part.modifiers[k];
7176 if (modifier.type === "attribute"){
7177 if (/([\~\|\^\$\*]=)/.test(modifier)){
7178 reporter.report("Attribute selectors with " + RegExp.$1 + " are slow!", modifier.line, modifier.col, rule);
7179 }
7180 }
7181  
7182 }
7183 }
7184 }
7185 }
7186 });
7187 }
7188  
7189 });
7190  
7191 CSSLint.addRule({
7192 id: "rules-count",
7193 name: "Rules Count",
7194 desc: "Track how many rules there are.",
7195 browsers: "All",
7196 init: function(parser, reporter){
7197 var count = 0;
7198 parser.addListener("startrule", function(){
7199 count++;
7200 });
7201  
7202 parser.addListener("endstylesheet", function(){
7203 reporter.stat("rule-count", count);
7204 });
7205 }
7206  
7207 });
7208  
7209 CSSLint.addRule({
7210 id: "selector-max-approaching",
7211 name: "Warn when approaching the 4095 selector limit for IE",
7212 desc: "Will warn when selector count is >= 3800 selectors.",
7213 browsers: "IE",
7214 init: function(parser, reporter) {
7215 var rule = this, count = 0;
7216  
7217 parser.addListener("startrule", function(event) {
7218 count += event.selectors.length;
7219 });
7220  
7221 parser.addListener("endstylesheet", function() {
7222 if (count >= 3800) {
7223 reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,rule);
7224 }
7225 });
7226 }
7227  
7228 });
7229  
7230 CSSLint.addRule({
7231 id: "selector-max",
7232 name: "Error when past the 4095 selector limit for IE",
7233 desc: "Will error when selector count is > 4095.",
7234 browsers: "IE",
7235 init: function(parser, reporter){
7236 var rule = this, count = 0;
7237  
7238 parser.addListener("startrule", function(event) {
7239 count += event.selectors.length;
7240 });
7241  
7242 parser.addListener("endstylesheet", function() {
7243 if (count > 4095) {
7244 reporter.report("You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,rule);
7245 }
7246 });
7247 }
7248  
7249 });
7250  
7251 CSSLint.addRule({
7252 id: "selector-newline",
7253 name: "Disallow new-line characters in selectors",
7254 desc: "New-line characters in selectors are usually a forgotten comma and not a descendant combinator.",
7255 browsers: "All",
7256 init: function(parser, reporter) {
7257 var rule = this;
7258  
7259 function startRule(event) {
7260 var i, len, selector, p, n, pLen, part, part2, type, currentLine, nextLine,
7261 selectors = event.selectors;
7262  
7263 for (i = 0, len = selectors.length; i < len; i++) {
7264 selector = selectors[i];
7265 for (p = 0, pLen = selector.parts.length; p < pLen; p++) {
7266 for (n = p + 1; n < pLen; n++) {
7267 part = selector.parts[p];
7268 part2 = selector.parts[n];
7269 type = part.type;
7270 currentLine = part.line;
7271 nextLine = part2.line;
7272  
7273 if (type === "descendant" && nextLine > currentLine) {
7274 reporter.report("newline character found in selector (forgot a comma?)", currentLine, selectors[i].parts[0].col, rule);
7275 }
7276 }
7277 }
7278  
7279 }
7280 }
7281  
7282 parser.addListener("startrule", startRule);
7283  
7284 }
7285 });
7286  
7287 CSSLint.addRule({
7288 id: "shorthand",
7289 name: "Require shorthand properties",
7290 desc: "Use shorthand properties where possible.",
7291 browsers: "All",
7292 init: function(parser, reporter){
7293 var rule = this,
7294 prop, i, len,
7295 propertiesToCheck = {},
7296 properties,
7297 mapping = {
7298 "margin": [
7299 "margin-top",
7300 "margin-bottom",
7301 "margin-left",
7302 "margin-right"
7303 ],
7304 "padding": [
7305 "padding-top",
7306 "padding-bottom",
7307 "padding-left",
7308 "padding-right"
7309 ]
7310 };
7311 for (prop in mapping){
7312 if (mapping.hasOwnProperty(prop)){
7313 for (i=0, len=mapping[prop].length; i < len; i++){
7314 propertiesToCheck[mapping[prop][i]] = prop;
7315 }
7316 }
7317 }
7318  
7319 function startRule(){
7320 properties = {};
7321 }
7322 function endRule(event){
7323  
7324 var prop, i, len, total;
7325 for (prop in mapping){
7326 if (mapping.hasOwnProperty(prop)){
7327 total=0;
7328  
7329 for (i=0, len=mapping[prop].length; i < len; i++){
7330 total += properties[mapping[prop][i]] ? 1 : 0;
7331 }
7332  
7333 if (total === mapping[prop].length){
7334 reporter.report("The properties " + mapping[prop].join(", ") + " can be replaced by " + prop + ".", event.line, event.col, rule);
7335 }
7336 }
7337 }
7338 }
7339  
7340 parser.addListener("startrule", startRule);
7341 parser.addListener("startfontface", startRule);
7342 parser.addListener("property", function(event){
7343 var name = event.property.toString().toLowerCase();
7344  
7345 if (propertiesToCheck[name]){
7346 properties[name] = 1;
7347 }
7348 });
7349  
7350 parser.addListener("endrule", endRule);
7351 parser.addListener("endfontface", endRule);
7352  
7353 }
7354  
7355 });
7356  
7357 CSSLint.addRule({
7358 id: "star-property-hack",
7359 name: "Disallow properties with a star prefix",
7360 desc: "Checks for the star property hack (targets IE6/7)",
7361 browsers: "All",
7362 init: function(parser, reporter){
7363 var rule = this;
7364 parser.addListener("property", function(event){
7365 var property = event.property;
7366  
7367 if (property.hack === "*") {
7368 reporter.report("Property with star prefix found.", event.property.line, event.property.col, rule);
7369 }
7370 });
7371 }
7372 });
7373  
7374 CSSLint.addRule({
7375 id: "text-indent",
7376 name: "Disallow negative text-indent",
7377 desc: "Checks for text indent less than -99px",
7378 browsers: "All",
7379 init: function(parser, reporter){
7380 var rule = this,
7381 textIndent,
7382 direction;
7383  
7384  
7385 function startRule(){
7386 textIndent = false;
7387 direction = "inherit";
7388 }
7389 function endRule(){
7390 if (textIndent && direction !== "ltr"){
7391 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);
7392 }
7393 }
7394  
7395 parser.addListener("startrule", startRule);
7396 parser.addListener("startfontface", startRule);
7397 parser.addListener("property", function(event){
7398 var name = event.property.toString().toLowerCase(),
7399 value = event.value;
7400  
7401 if (name === "text-indent" && value.parts[0].value < -99){
7402 textIndent = event.property;
7403 } else if (name === "direction" && value.toString() === "ltr"){
7404 direction = "ltr";
7405 }
7406 });
7407  
7408 parser.addListener("endrule", endRule);
7409 parser.addListener("endfontface", endRule);
7410  
7411 }
7412  
7413 });
7414  
7415 CSSLint.addRule({
7416 id: "underscore-property-hack",
7417 name: "Disallow properties with an underscore prefix",
7418 desc: "Checks for the underscore property hack (targets IE6)",
7419 browsers: "All",
7420 init: function(parser, reporter){
7421 var rule = this;
7422 parser.addListener("property", function(event){
7423 var property = event.property;
7424  
7425 if (property.hack === "_") {
7426 reporter.report("Property with underscore prefix found.", event.property.line, event.property.col, rule);
7427 }
7428 });
7429 }
7430 });
7431  
7432 CSSLint.addRule({
7433 id: "unique-headings",
7434 name: "Headings should only be defined once",
7435 desc: "Headings should be defined only once.",
7436 browsers: "All",
7437 init: function(parser, reporter){
7438 var rule = this;
7439  
7440 var headings = {
7441 h1: 0,
7442 h2: 0,
7443 h3: 0,
7444 h4: 0,
7445 h5: 0,
7446 h6: 0
7447 };
7448  
7449 parser.addListener("startrule", function(event){
7450 var selectors = event.selectors,
7451 selector,
7452 part,
7453 pseudo,
7454 i, j;
7455  
7456 for (i=0; i < selectors.length; i++){
7457 selector = selectors[i];
7458 part = selector.parts[selector.parts.length-1];
7459  
7460 if (part.elementName && /(h[1-6])/i.test(part.elementName.toString())){
7461  
7462 for (j=0; j < part.modifiers.length; j++){
7463 if (part.modifiers[j].type === "pseudo"){
7464 pseudo = true;
7465 break;
7466 }
7467 }
7468  
7469 if (!pseudo){
7470 headings[RegExp.$1]++;
7471 if (headings[RegExp.$1] > 1) {
7472 reporter.report("Heading (" + part.elementName + ") has already been defined.", part.line, part.col, rule);
7473 }
7474 }
7475 }
7476 }
7477 });
7478  
7479 parser.addListener("endstylesheet", function(){
7480 var prop,
7481 messages = [];
7482  
7483 for (prop in headings){
7484 if (headings.hasOwnProperty(prop)){
7485 if (headings[prop] > 1){
7486 messages.push(headings[prop] + " " + prop + "s");
7487 }
7488 }
7489 }
7490  
7491 if (messages.length){
7492 reporter.rollupWarn("You have " + messages.join(", ") + " defined in this stylesheet.", rule);
7493 }
7494 });
7495 }
7496  
7497 });
7498  
7499 CSSLint.addRule({
7500 id: "universal-selector",
7501 name: "Disallow universal selector",
7502 desc: "The universal selector (*) is known to be slow.",
7503 browsers: "All",
7504 init: function(parser, reporter){
7505 var rule = this;
7506  
7507 parser.addListener("startrule", function(event){
7508 var selectors = event.selectors,
7509 selector,
7510 part,
7511 i;
7512  
7513 for (i=0; i < selectors.length; i++){
7514 selector = selectors[i];
7515  
7516 part = selector.parts[selector.parts.length-1];
7517 if (part.elementName === "*"){
7518 reporter.report(rule.desc, part.line, part.col, rule);
7519 }
7520 }
7521 });
7522 }
7523  
7524 });
7525  
7526 CSSLint.addRule({
7527 id: "unqualified-attributes",
7528 name: "Disallow unqualified attribute selectors",
7529 desc: "Unqualified attribute selectors are known to be slow.",
7530 browsers: "All",
7531 init: function(parser, reporter){
7532 var rule = this;
7533  
7534 parser.addListener("startrule", function(event){
7535  
7536 var selectors = event.selectors,
7537 selector,
7538 part,
7539 modifier,
7540 i, k;
7541  
7542 for (i=0; i < selectors.length; i++){
7543 selector = selectors[i];
7544  
7545 part = selector.parts[selector.parts.length-1];
7546 if (part.type === parser.SELECTOR_PART_TYPE){
7547 for (k=0; k < part.modifiers.length; k++){
7548 modifier = part.modifiers[k];
7549 if (modifier.type === "attribute" && (!part.elementName || part.elementName === "*")){
7550 reporter.report(rule.desc, part.line, part.col, rule);
7551 }
7552 }
7553 }
7554  
7555 }
7556 });
7557 }
7558  
7559 });
7560  
7561 CSSLint.addRule({
7562 id: "vendor-prefix",
7563 name: "Require standard property with vendor prefix",
7564 desc: "When using a vendor-prefixed property, make sure to include the standard one.",
7565 browsers: "All",
7566 init: function(parser, reporter){
7567 var rule = this,
7568 properties,
7569 num,
7570 propertiesToCheck = {
7571 "-webkit-border-radius": "border-radius",
7572 "-webkit-border-top-left-radius": "border-top-left-radius",
7573 "-webkit-border-top-right-radius": "border-top-right-radius",
7574 "-webkit-border-bottom-left-radius": "border-bottom-left-radius",
7575 "-webkit-border-bottom-right-radius": "border-bottom-right-radius",
7576  
7577 "-o-border-radius": "border-radius",
7578 "-o-border-top-left-radius": "border-top-left-radius",
7579 "-o-border-top-right-radius": "border-top-right-radius",
7580 "-o-border-bottom-left-radius": "border-bottom-left-radius",
7581 "-o-border-bottom-right-radius": "border-bottom-right-radius",
7582  
7583 "-moz-border-radius": "border-radius",
7584 "-moz-border-radius-topleft": "border-top-left-radius",
7585 "-moz-border-radius-topright": "border-top-right-radius",
7586 "-moz-border-radius-bottomleft": "border-bottom-left-radius",
7587 "-moz-border-radius-bottomright": "border-bottom-right-radius",
7588  
7589 "-moz-column-count": "column-count",
7590 "-webkit-column-count": "column-count",
7591  
7592 "-moz-column-gap": "column-gap",
7593 "-webkit-column-gap": "column-gap",
7594  
7595 "-moz-column-rule": "column-rule",
7596 "-webkit-column-rule": "column-rule",
7597  
7598 "-moz-column-rule-style": "column-rule-style",
7599 "-webkit-column-rule-style": "column-rule-style",
7600  
7601 "-moz-column-rule-color": "column-rule-color",
7602 "-webkit-column-rule-color": "column-rule-color",
7603  
7604 "-moz-column-rule-width": "column-rule-width",
7605 "-webkit-column-rule-width": "column-rule-width",
7606  
7607 "-moz-column-width": "column-width",
7608 "-webkit-column-width": "column-width",
7609  
7610 "-webkit-column-span": "column-span",
7611 "-webkit-columns": "columns",
7612  
7613 "-moz-box-shadow": "box-shadow",
7614 "-webkit-box-shadow": "box-shadow",
7615  
7616 "-moz-transform" : "transform",
7617 "-webkit-transform" : "transform",
7618 "-o-transform" : "transform",
7619 "-ms-transform" : "transform",
7620  
7621 "-moz-transform-origin" : "transform-origin",
7622 "-webkit-transform-origin" : "transform-origin",
7623 "-o-transform-origin" : "transform-origin",
7624 "-ms-transform-origin" : "transform-origin",
7625  
7626 "-moz-box-sizing" : "box-sizing",
7627 "-webkit-box-sizing" : "box-sizing"
7628 };
7629 function startRule(){
7630 properties = {};
7631 num = 1;
7632 }
7633 function endRule(){
7634 var prop,
7635 i,
7636 len,
7637 needed,
7638 actual,
7639 needsStandard = [];
7640  
7641 for (prop in properties){
7642 if (propertiesToCheck[prop]){
7643 needsStandard.push({ actual: prop, needed: propertiesToCheck[prop]});
7644 }
7645 }
7646  
7647 for (i=0, len=needsStandard.length; i < len; i++){
7648 needed = needsStandard[i].needed;
7649 actual = needsStandard[i].actual;
7650  
7651 if (!properties[needed]){
7652 reporter.report("Missing standard property '" + needed + "' to go along with '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);
7653 } else {
7654 if (properties[needed][0].pos < properties[actual][0].pos){
7655 reporter.report("Standard property '" + needed + "' should come after vendor-prefixed property '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);
7656 }
7657 }
7658 }
7659  
7660 }
7661  
7662 parser.addListener("startrule", startRule);
7663 parser.addListener("startfontface", startRule);
7664 parser.addListener("startpage", startRule);
7665 parser.addListener("startpagemargin", startRule);
7666 parser.addListener("startkeyframerule", startRule);
7667  
7668 parser.addListener("property", function(event){
7669 var name = event.property.text.toLowerCase();
7670  
7671 if (!properties[name]){
7672 properties[name] = [];
7673 }
7674  
7675 properties[name].push({ name: event.property, value : event.value, pos:num++ });
7676 });
7677  
7678 parser.addListener("endrule", endRule);
7679 parser.addListener("endfontface", endRule);
7680 parser.addListener("endpage", endRule);
7681 parser.addListener("endpagemargin", endRule);
7682 parser.addListener("endkeyframerule", endRule);
7683 }
7684  
7685 });
7686  
7687 CSSLint.addRule({
7688 id: "zero-units",
7689 name: "Disallow units for 0 values",
7690 desc: "You don't need to specify units when a value is 0.",
7691 browsers: "All",
7692 init: function(parser, reporter){
7693 var rule = this;
7694 parser.addListener("property", function(event){
7695 var parts = event.value.parts,
7696 i = 0,
7697 len = parts.length;
7698  
7699 while(i < len){
7700 if ((parts[i].units || parts[i].type === "percentage") && parts[i].value === 0 && parts[i].type !== "time"){
7701 reporter.report("Values of 0 shouldn't have units specified.", parts[i].line, parts[i].col, rule);
7702 }
7703 i++;
7704 }
7705  
7706 });
7707  
7708 }
7709  
7710 });
7711  
7712 (function() {
7713 var xmlEscape = function(str) {
7714 if (!str || str.constructor !== String) {
7715 return "";
7716 }
7717  
7718 return str.replace(/[\"&><]/g, function(match) {
7719 <]/ switch (match) {
7720 <]/ case "\"":
7721 <]/ return "&quot;";
7722 <]/ case "&":
7723 <]/ return "&amp;";
7724 <]/ case "<":
7725 <]/ return "&lt;";
7726 <]/ case ">":
7727 <]/ return "&gt;";
7728 <]/ }
7729 <]/ });
7730 <]/ };
7731  
7732 <]/ CSSLint.addFormatter({
7733 <]/ id: "checkstyle-xml",
7734 <]/ name: "Checkstyle XML format",
7735 <]/ startFormat: function(){
7736 <]/ return "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>";
7737 <]/ },
7738 <]/ endFormat: function(){
7739 <]/ return "</checkstyle>";
7740 <]/ },
7741 <]/ readError: function(filename, message) {
7742 <]/ return "<file name=\"" + xmlEscape(filename) + "\"><error line=\"0\" column=\"0\" severty=\"error\" message=\"" + xmlEscape(message) + "\"></error></file>";
7743 <]/ },
7744 <]/ formatResults: function(results, filename/*, options*/) {
7745 <]/ var messages = results.messages,
7746 <]/ output = [];
7747 <]/ var generateSource = function(rule) {
7748 <]/ if (!rule || !("name" in rule)) {
7749 <]/ return "";
7750 <]/ }
7751 <]/ return "net.csslint." + rule.name.replace(/\s/g,"");
7752 <]/ };
7753  
7754  
7755  
7756 <]/ if (messages.length > 0) {
7757 <]/ output.push("<file name=\""+filename+"\">");
7758 <]/ CSSLint.Util.forEach(messages, function (message) {
7759 <]/ if (!message.rollup) {
7760 <]/ output.push("<error line=\"" + message.line + "\" column=\"" + message.col + "\" severity=\"" + message.type + "\"" +
7761 <]/ " message=\"" + xmlEscape(message.message) + "\" source=\"" + generateSource(message.rule) +"\"/>");
7762 <]/ }
7763 <]/ });
7764 <]/ output.push("</file>");
7765 <]/ }
7766  
7767 <]/ return output.join("");
7768 <]/ }
7769 <]/ });
7770  
7771 <]/}());
7772  
7773 <]/CSSLint.addFormatter({
7774 <]/ id: "compact",
7775 <]/ name: "Compact, 'porcelain' format",
7776 <]/ startFormat: function() {
7777 <]/ return "";
7778 <]/ },
7779 <]/ endFormat: function() {
7780 <]/ return "";
7781 <]/ },
7782 <]/ formatResults: function(results, filename, options) {
7783 <]/ var messages = results.messages,
7784 <]/ output = "";
7785 <]/ options = options || {};
7786 <]/ var capitalize = function(str) {
7787 <]/ return str.charAt(0).toUpperCase() + str.slice(1);
7788 <]/ };
7789  
7790 <]/ if (messages.length === 0) {
7791 <]/ return options.quiet ? "" : filename + ": Lint Free!";
7792 <]/ }
7793  
7794 <]/ CSSLint.Util.forEach(messages, function(message) {
7795 <]/ if (message.rollup) {
7796 <]/ output += filename + ": " + capitalize(message.type) + " - " + message.message + "\n";
7797 <]/ } else {
7798 <]/ output += filename + ": " + "line " + message.line +
7799 <]/ ", col " + message.col + ", " + capitalize(message.type) + " - " + message.message + " (" + message.rule.id + ")\n";
7800 <]/ }
7801 <]/ });
7802  
7803 <]/ return output;
7804 <]/ }
7805 <]/});
7806  
7807 <]/CSSLint.addFormatter({
7808 <]/ id: "csslint-xml",
7809 <]/ name: "CSSLint XML format",
7810 <]/ startFormat: function(){
7811 <]/ return "<?xml version=\"1.0\" encoding=\"utf-8\"?><csslint>";
7812 <]/ },
7813 <]/ endFormat: function(){
7814 <]/ return "</csslint>";
7815 <]/ },
7816 <]/ formatResults: function(results, filename/*, options*/) {
7817 <]/ var messages = results.messages,
7818 <]/ output = [];
7819 <]/ var escapeSpecialCharacters = function(str) {
7820 <]/ if (!str || str.constructor !== String) {
7821 <]/ return "";
7822 <]/ }
7823 <]/ return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/g, "&lt;").replace(/>/g, "&gt;");
7824 <]/ };
7825  
7826 <]/ if (messages.length > 0) {
7827 <]/ output.push("<file name=\""+filename+"\">");
7828 <]/ CSSLint.Util.forEach(messages, function (message) {
7829 <]/ if (message.rollup) {
7830 <]/ output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
7831 <]/ } else {
7832 <]/ output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" +
7833 <]/ " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
7834 <]/ }
7835 <]/ });
7836 <]/ output.push("</file>");
7837 <]/ }
7838  
7839 <]/ return output.join("");
7840 <]/ }
7841 <]/});
7842  
7843 <]/CSSLint.addFormatter({
7844 <]/ id: "junit-xml",
7845 <]/ name: "JUNIT XML format",
7846 <]/ startFormat: function(){
7847 <]/ return "<?xml version=\"1.0\" encoding=\"utf-8\"?><testsuites>";
7848 <]/ },
7849 <]/ endFormat: function() {
7850 <]/ return "</testsuites>";
7851 <]/ },
7852 <]/ formatResults: function(results, filename/*, options*/) {
7853  
7854 <]/ var messages = results.messages,
7855 <]/ output = [],
7856 <]/ tests = {
7857 <]/ "error": 0,
7858 <]/ "failure": 0
7859 <]/ };
7860 <]/ var generateSource = function(rule) {
7861 <]/ if (!rule || !("name" in rule)) {
7862 <]/ return "";
7863 <]/ }
7864 <]/ return "net.csslint." + rule.name.replace(/\s/g,"");
7865 <]/ };
7866 <]/ var escapeSpecialCharacters = function(str) {
7867  
7868 <]/ if (!str || str.constructor !== String) {
7869 <]/ return "";
7870 <]/ }
7871  
7872 <]/ return str.replace(/\"/g, "'").replace(/g, "&lt;").replace(/>/g, "&gt;");
7873  
7874 <]/ };
7875  
7876 <]/ if (messages.length > 0) {
7877  
7878 <]/ messages.forEach(function (message) {
7879 <]/ var type = message.type === "warning" ? "error" : message.type;
7880 <]/ if (!message.rollup) {
7881 <]/ output.push("<testcase time=\"0\" name=\"" + generateSource(message.rule) + "\">");
7882 <]/ output.push("<" + type + " message=\"" + escapeSpecialCharacters(message.message) + "\"><![CDATA[" + message.line + ":" + message.col + ":" + escapeSpecialCharacters(message.evidence) + "]]></" + type + ">");
7883 <]/ output.push("</testcase>");
7884  
7885 <]/ tests[type] += 1;
7886  
7887 <]/ }
7888  
7889 <]/ });
7890  
7891 <]/ output.unshift("<testsuite time=\"0\" tests=\"" + messages.length + "\" skipped=\"0\" errors=\"" + tests.error + "\" failures=\"" + tests.failure + "\" package=\"net.csslint\" name=\"" + filename + "\">");
7892 <]/ output.push("</testsuite>");
7893  
7894 <]/ }
7895  
7896 <]/ return output.join("");
7897  
7898 <]/ }
7899 <]/});
7900  
7901 <]/CSSLint.addFormatter({
7902 <]/ id: "lint-xml",
7903 <]/ name: "Lint XML format",
7904 <]/ startFormat: function(){
7905 <]/ return "<?xml version=\"1.0\" encoding=\"utf-8\"?><lint>";
7906 <]/ },
7907 <]/ endFormat: function(){
7908 <]/ return "</lint>";
7909 <]/ },
7910 <]/ formatResults: function(results, filename/*, options*/) {
7911 <]/ var messages = results.messages,
7912 <]/ output = [];
7913 <]/ var escapeSpecialCharacters = function(str) {
7914 <]/ if (!str || str.constructor !== String) {
7915 <]/ return "";
7916 <]/ }
7917 <]/ return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/g, "&lt;").replace(/>/g, "&gt;");
7918 <]/ };
7919  
7920 <]/ if (messages.length > 0) {
7921  
7922 <]/ output.push("<file name=\""+filename+"\">");
7923 <]/ CSSLint.Util.forEach(messages, function (message) {
7924 <]/ if (message.rollup) {
7925 <]/ output.push("<issue severity=\"" + message.type + "\" reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
7926 <]/ } else {
7927 <]/ output.push("<issue line=\"" + message.line + "\" char=\"" + message.col + "\" severity=\"" + message.type + "\"" +
7928 <]/ " reason=\"" + escapeSpecialCharacters(message.message) + "\" evidence=\"" + escapeSpecialCharacters(message.evidence) + "\"/>");
7929 <]/ }
7930 <]/ });
7931 <]/ output.push("</file>");
7932 <]/ }
7933  
7934 <]/ return output.join("");
7935 <]/ }
7936 <]/});
7937  
7938 <]/CSSLint.addFormatter({
7939 <]/ id: "text",
7940 <]/ name: "Plain Text",
7941 <]/ startFormat: function() {
7942 <]/ return "";
7943 <]/ },
7944 <]/ endFormat: function() {
7945 <]/ return "";
7946 <]/ },
7947 <]/ formatResults: function(results, filename, options) {
7948 <]/ var messages = results.messages,
7949 <]/ output = "";
7950 <]/ options = options || {};
7951  
7952 <]/ if (messages.length === 0) {
7953 <]/ return options.quiet ? "" : "\n\ncsslint: No errors in " + filename + ".";
7954 <]/ }
7955  
7956 <]/ output = "\n\ncsslint: There ";
7957 <]/ if (messages.length === 1) {
7958 <]/ output += "is 1 problem";
7959 <]/ } else {
7960 <]/ output += "are " + messages.length + " problems";
7961 <]/ }
7962 <]/ output += " in " + filename + ".";
7963  
7964 <]/ var pos = filename.lastIndexOf("/"),
7965 <]/ shortFilename = filename;
7966  
7967 <]/ if (pos === -1){
7968 <]/ pos = filename.lastIndexOf("\\");
7969 <]/ }
7970 <]/ if (pos > -1){
7971 <]/ shortFilename = filename.substring(pos+1);
7972 <]/ }
7973  
7974 <]/ CSSLint.Util.forEach(messages, function (message, i) {
7975 <]/ output = output + "\n\n" + shortFilename;
7976 <]/ if (message.rollup) {
7977 <]/ output += "\n" + (i+1) + ": " + message.type;
7978 <]/ output += "\n" + message.message;
7979 <]/ } else {
7980 <]/ output += "\n" + (i+1) + ": " + message.type + " at line " + message.line + ", col " + message.col;
7981 <]/ output += "\n" + message.message;
7982 <]/ output += "\n" + message.evidence;
7983 <]/ }
7984 <]/ });
7985  
7986 <]/ return output;
7987 <]/ }
7988 <]/});
7989  
7990 <]/module.exports.CSSLint = CSSLint;
7991  
7992 <]/});
7993  
7994 <]/ace.define("ace/mode/css_worker",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/worker/mirror","ace/mode/css/csslint"], function(require, exports, module) {
7995 <]/"use strict";
7996  
7997 <]/var oop = require("../lib/oop");
7998 <]/var lang = require("../lib/lang");
7999 <]/var Mirror = require("../worker/mirror").Mirror;
8000 <]/var CSSLint = require("./css/csslint").CSSLint;
8001  
8002 <]/var Worker = exports.Worker = function(sender) {
8003 <]/ Mirror.call(this, sender);
8004 <]/ this.setTimeout(400);
8005 <]/ this.ruleset = null;
8006 <]/ this.setDisabledRules("ids|order-alphabetical");
8007 <]/ this.setInfoRules(
8008 <]/ "adjoining-classes|qualified-headings|zero-units|gradients|" +
8009 <]/ "import|outline-none|vendor-prefix"
8010 <]/ );
8011 <]/};
8012  
8013 <]/oop.inherits(Worker, Mirror);
8014  
8015 <]/(function() {
8016 <]/ this.setInfoRules = function(ruleNames) {
8017 <]/ if (typeof ruleNames == "string")
8018 <]/ ruleNames = ruleNames.split("|");
8019 <]/ this.infoRules = lang.arrayToMap(ruleNames);
8020 <]/ this.doc.getValue() && this.deferredUpdate.schedule(100);
8021 <]/ };
8022  
8023 <]/ this.setDisabledRules = function(ruleNames) {
8024 <]/ if (!ruleNames) {
8025 <]/ this.ruleset = null;
8026 <]/ } else {
8027 <]/ if (typeof ruleNames == "string")
8028 <]/ ruleNames = ruleNames.split("|");
8029 <]/ var all = {};
8030  
8031 <]/ CSSLint.getRules().forEach(function(x){
8032 <]/ all[x.id] = true;
8033 <]/ });
8034 <]/ ruleNames.forEach(function(x) {
8035 <]/ delete all[x];
8036 <]/ });
8037  
8038 <]/ this.ruleset = all;
8039 <]/ }
8040 <]/ this.doc.getValue() && this.deferredUpdate.schedule(100);
8041 <]/ };
8042  
8043 <]/ this.onUpdate = function() {
8044 <]/ var value = this.doc.getValue();
8045 <]/ if (!value)
8046 <]/ return this.sender.emit("annotate", []);
8047 <]/ var infoRules = this.infoRules;
8048  
8049 <]/ var result = CSSLint.verify(value, this.ruleset);
8050 <]/ this.sender.emit("annotate", result.messages.map(function(msg) {
8051 <]/ return {
8052 <]/ row: msg.line - 1,
8053 <]/ column: msg.col - 1,
8054 <]/ text: msg.message,
8055 <]/ type: infoRules[msg.rule.id] ? "info" : msg.type,
8056 <]/ rule: msg.rule.name
8057 <]/ }
8058 <]/ }));
8059 <]/ };
8060  
8061 <]/}).call(Worker.prototype);
8062  
8063 <]/});
8064  
8065 <]/ace.define("ace/lib/es5-shim",["require","exports","module"], function(require, exports, module) {
8066  
8067 <]/function Empty() {}
8068  
8069 <]/if (!Function.prototype.bind) {
8070 <]/ Function.prototype.bind = function bind(that) { // .length is 1
8071 <]/ var target = this;
8072 <]/ if (typeof target != "function") {
8073 <]/ throw new TypeError("Function.prototype.bind called on incompatible " + target);
8074 <]/ }
8075 <]/ var args = slice.call(arguments, 1); // for normal call
8076 <]/ var bound = function () {
8077  
8078 <]/ if (this instanceof bound) {
8079  
8080 <]/ var result = target.apply(
8081 <]/ this,
8082 <]/ args.concat(slice.call(arguments))
8083 <]/ );
8084 <]/ if (Object(result) === result) {
8085 <]/ return result;
8086 <]/ }
8087 <]/ return this;
8088  
8089 <]/ } else {
8090 <]/ return target.apply(
8091 <]/ that,
8092 <]/ args.concat(slice.call(arguments))
8093 <]/ );
8094  
8095 <]/ }
8096  
8097 <]/ };
8098 <]/ if(target.prototype) {
8099 <]/ Empty.prototype = target.prototype;
8100 <]/ bound.prototype = new Empty();
8101 <]/ Empty.prototype = null;
8102 <]/ }
8103 <]/ return bound;
8104 <]/ };
8105 <]/}
8106 <]/var call = Function.prototype.call;
8107 <]/var prototypeOfArray = Array.prototype;
8108 <]/var prototypeOfObject = Object.prototype;
8109 <]/var slice = prototypeOfArray.slice;
8110 <]/var _toString = call.bind(prototypeOfObject.toString);
8111 <]/var owns = call.bind(prototypeOfObject.hasOwnProperty);
8112 <]/var defineGetter;
8113 <]/var defineSetter;
8114 <]/var lookupGetter;
8115 <]/var lookupSetter;
8116 <]/var supportsAccessors;
8117 <]/if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) {
8118 <]/ defineGetter = call.bind(prototypeOfObject.__defineGetter__);
8119 <]/ defineSetter = call.bind(prototypeOfObject.__defineSetter__);
8120 <]/ lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
8121 <]/ lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
8122 <]/}
8123 <]/if ([1,2].splice(0).length != 2) {
8124 <]/ if(function() { // test IE < 9 to splice bug - see issue #138
8125 <]/ function makeArray(l) {
8126 <]/ var a = new Array(l+2);
8127 <]/ a[0] = a[1] = 0;
8128 <]/ return a;
8129 <]/ }
8130 <]/ var array = [], lengthBefore;
8131  
8132 <]/ array.splice.apply(array, makeArray(20));
8133 <]/ array.splice.apply(array, makeArray(26));
8134  
8135 <]/ lengthBefore = array.length; //46
8136 <]/ array.splice(5, 0, "XXX"); // add one element
8137  
8138 <]/ lengthBefore + 1 == array.length
8139  
8140 <]/ if (lengthBefore + 1 == array.length) {
8141 <]/ return true;// has right splice implementation without bugs
8142 <]/ }
8143 <]/ }()) {//IE 6/7
8144 <]/ var array_splice = Array.prototype.splice;
8145 <]/ Array.prototype.splice = function(start, deleteCount) {
8146 <]/ if (!arguments.length) {
8147 <]/ return [];
8148 <]/ } else {
8149 <]/ return array_splice.apply(this, [
8150 <]/ start === void 0 ? 0 : start,
8151 <]/ deleteCount === void 0 ? (this.length - start) : deleteCount
8152 <]/ ].concat(slice.call(arguments, 2)))
8153 <]/ }
8154 <]/ };
8155 <]/ } else {//IE8
8156 <]/ Array.prototype.splice = function(pos, removeCount){
8157 <]/ var length = this.length;
8158 <]/ if (pos > 0) {
8159 <]/ if (pos > length)
8160 <]/ pos = length;
8161 <]/ } else if (pos == void 0) {
8162 <]/ pos = 0;
8163 <]/ } else if (pos < 0) {
8164 <]/ pos = Math.max(length + pos, 0);
8165 <]/ }
8166  
8167 <]/ if (!(pos+removeCount < length))
8168 <]/ removeCount = length - pos;
8169  
8170 <]/ var removed = this.slice(pos, pos+removeCount);
8171 <]/ var insert = slice.call(arguments, 2);
8172 <]/ var add = insert.length;
8173 <]/ if (pos === length) {
8174 <]/ if (add) {
8175 <]/ this.push.apply(this, insert);
8176 <]/ }
8177 <]/ } else {
8178 <]/ var remove = Math.min(removeCount, length - pos);
8179 <]/ var tailOldPos = pos + remove;
8180 <]/ var tailNewPos = tailOldPos + add - remove;
8181 <]/ var tailCount = length - tailOldPos;
8182 <]/ var lengthAfterRemove = length - remove;
8183  
8184 <]/ if (tailNewPos < tailOldPos) { // case A
8185 <]/ for (var i = 0; i < tailCount; ++i) {
8186 <]/ this[tailNewPos+i] = this[tailOldPos+i];
8187 <]/ }
8188 <]/ } else if (tailNewPos > tailOldPos) { // case B
8189 <]/ for (i = tailCount; i--; ) {
8190 <]/ this[tailNewPos+i] = this[tailOldPos+i];
8191 <]/ }
8192 <]/ } // else, add == remove (nothing to do)
8193  
8194 <]/ if (add && pos === lengthAfterRemove) {
8195 <]/ this.length = lengthAfterRemove; // truncate array
8196 <]/ this.push.apply(this, insert);
8197 <]/ } else {
8198 <]/ this.length = lengthAfterRemove + add; // reserves space
8199 <]/ for (i = 0; i < add; ++i) {
8200 <]/ this[pos+i] = insert[i];
8201 <]/ }
8202 <]/ }
8203 <]/ }
8204 <]/ return removed;
8205 <]/ };
8206 <]/ }
8207 <]/}
8208 <]/if (!Array.isArray) {
8209 <]/ Array.isArray = function isArray(obj) {
8210 <]/ return _toString(obj) == "[object Array]";
8211 <]/ };
8212 <]/}
8213 <]/var boxedString = Object("a"),
8214 <]/ splitString = boxedString[0] != "a" || !(0 in boxedString);
8215  
8216 <]/if (!Array.prototype.forEach) {
8217 <]/ Array.prototype.forEach = function forEach(fun /*, thisp*/) {
8218 <]/ var object = toObject(this),
8219 <]/ self = splitString && _toString(this) == "[object String]" ?
8220 <]/ this.split("") :
8221 <]/ object,
8222 <]/ thisp = arguments[1],
8223 <]/ i = -1,
8224 <]/ length = self.length >>> 0;
8225 <]/ if (_toString(fun) != "[object Function]") {
8226 <]/ throw new TypeError(); // TODO message
8227 <]/ }
8228  
8229 <]/ while (++i < length) {
8230 <]/ if (i in self) {
8231 <]/ fun.call(thisp, self[i], i, object);
8232 <]/ }
8233 <]/ }
8234 <]/ };
8235 <]/}
8236 <]/if (!Array.prototype.map) {
8237 <]/ Array.prototype.map = function map(fun /*, thisp*/) {
8238 <]/ var object = toObject(this),
8239 <]/ self = splitString && _toString(this) == "[object String]" ?
8240 <]/ this.split("") :
8241 <]/ object,
8242 <]/ length = self.length >>> 0,
8243 <]/ result = Array(length),
8244 <]/ thisp = arguments[1];
8245 <]/ if (_toString(fun) != "[object Function]") {
8246 <]/ throw new TypeError(fun + " is not a function");
8247 <]/ }
8248  
8249 <]/ for (var i = 0; i < length; i++) {
8250 <]/ if (i in self)
8251 <]/ result[i] = fun.call(thisp, self[i], i, object);
8252 <]/ }
8253 <]/ return result;
8254 <]/ };
8255 <]/}
8256 <]/if (!Array.prototype.filter) {
8257 <]/ Array.prototype.filter = function filter(fun /*, thisp */) {
8258 <]/ var object = toObject(this),
8259 <]/ self = splitString && _toString(this) == "[object String]" ?
8260 <]/ this.split("") :
8261 <]/ object,
8262 <]/ length = self.length >>> 0,
8263 <]/ result = [],
8264 <]/ value,
8265 <]/ thisp = arguments[1];
8266 <]/ if (_toString(fun) != "[object Function]") {
8267 <]/ throw new TypeError(fun + " is not a function");
8268 <]/ }
8269  
8270 <]/ for (var i = 0; i < length; i++) {
8271 <]/ if (i in self) {
8272 <]/ value = self[i];
8273 <]/ if (fun.call(thisp, value, i, object)) {
8274 <]/ result.push(value);
8275 <]/ }
8276 <]/ }
8277 <]/ }
8278 <]/ return result;
8279 <]/ };
8280 <]/}
8281 <]/if (!Array.prototype.every) {
8282 <]/ Array.prototype.every = function every(fun /*, thisp */) {
8283 <]/ var object = toObject(this),
8284 <]/ self = splitString && _toString(this) == "[object String]" ?
8285 <]/ this.split("") :
8286 <]/ object,
8287 <]/ length = self.length >>> 0,
8288 <]/ thisp = arguments[1];
8289 <]/ if (_toString(fun) != "[object Function]") {
8290 <]/ throw new TypeError(fun + " is not a function");
8291 <]/ }
8292  
8293 <]/ for (var i = 0; i < length; i++) {
8294 <]/ if (i in self && !fun.call(thisp, self[i], i, object)) {
8295 <]/ return false;
8296 <]/ }
8297 <]/ }
8298 <]/ return true;
8299 <]/ };
8300 <]/}
8301 <]/if (!Array.prototype.some) {
8302 <]/ Array.prototype.some = function some(fun /*, thisp */) {
8303 <]/ var object = toObject(this),
8304 <]/ self = splitString && _toString(this) == "[object String]" ?
8305 <]/ this.split("") :
8306 <]/ object,
8307 <]/ length = self.length >>> 0,
8308 <]/ thisp = arguments[1];
8309 <]/ if (_toString(fun) != "[object Function]") {
8310 <]/ throw new TypeError(fun + " is not a function");
8311 <]/ }
8312  
8313 <]/ for (var i = 0; i < length; i++) {
8314 <]/ if (i in self && fun.call(thisp, self[i], i, object)) {
8315 <]/ return true;
8316 <]/ }
8317 <]/ }
8318 <]/ return false;
8319 <]/ };
8320 <]/}
8321 <]/if (!Array.prototype.reduce) {
8322 <]/ Array.prototype.reduce = function reduce(fun /*, initial*/) {
8323 <]/ var object = toObject(this),
8324 <]/ self = splitString && _toString(this) == "[object String]" ?
8325 <]/ this.split("") :
8326 <]/ object,
8327 <]/ length = self.length >>> 0;
8328 <]/ if (_toString(fun) != "[object Function]") {
8329 <]/ throw new TypeError(fun + " is not a function");
8330 <]/ }
8331 <]/ if (!length && arguments.length == 1) {
8332 <]/ throw new TypeError("reduce of empty array with no initial value");
8333 <]/ }
8334  
8335 <]/ var i = 0;
8336 <]/ var result;
8337 <]/ if (arguments.length >= 2) {
8338 <]/ result = arguments[1];
8339 <]/ } else {
8340 <]/ do {
8341 <]/ if (i in self) {
8342 <]/ result = self[i++];
8343 <]/ break;
8344 <]/ }
8345 <]/ if (++i >= length) {
8346 <]/ throw new TypeError("reduce of empty array with no initial value");
8347 <]/ }
8348 <]/ } while (true);
8349 <]/ }
8350  
8351 <]/ for (; i < length; i++) {
8352 <]/ if (i in self) {
8353 <]/ result = fun.call(void 0, result, self[i], i, object);
8354 <]/ }
8355 <]/ }
8356  
8357 <]/ return result;
8358 <]/ };
8359 <]/}
8360 <]/if (!Array.prototype.reduceRight) {
8361 <]/ Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) {
8362 <]/ var object = toObject(this),
8363 <]/ self = splitString && _toString(this) == "[object String]" ?
8364 <]/ this.split("") :
8365 <]/ object,
8366 <]/ length = self.length >>> 0;
8367 <]/ if (_toString(fun) != "[object Function]") {
8368 <]/ throw new TypeError(fun + " is not a function");
8369 <]/ }
8370 <]/ if (!length && arguments.length == 1) {
8371 <]/ throw new TypeError("reduceRight of empty array with no initial value");
8372 <]/ }
8373  
8374 <]/ var result, i = length - 1;
8375 <]/ if (arguments.length >= 2) {
8376 <]/ result = arguments[1];
8377 <]/ } else {
8378 <]/ do {
8379 <]/ if (i in self) {
8380 <]/ result = self[i--];
8381 <]/ break;
8382 <]/ }
8383 <]/ if (--i < 0) {
8384 <]/ throw new TypeError("reduceRight of empty array with no initial value");
8385 <]/ }
8386 <]/ } while (true);
8387 <]/ }
8388  
8389 <]/ do {
8390 <]/ if (i in this) {
8391 <]/ result = fun.call(void 0, result, self[i], i, object);
8392 <]/ }
8393 <]/ } while (i--);
8394  
8395 <]/ return result;
8396 <]/ };
8397 <]/}
8398 <]/if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) {
8399 <]/ Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
8400 <]/ var self = splitString && _toString(this) == "[object String]" ?
8401 <]/ this.split("") :
8402 <]/ toObject(this),
8403 <]/ length = self.length >>> 0;
8404  
8405 <]/ if (!length) {
8406 <]/ return -1;
8407 <]/ }
8408  
8409 <]/ var i = 0;
8410 <]/ if (arguments.length > 1) {
8411 <]/ i = toInteger(arguments[1]);
8412 <]/ }
8413 <]/ i = i >= 0 ? i : Math.max(0, length + i);
8414 <]/ for (; i < length; i++) {
8415 <]/ if (i in self && self[i] === sought) {
8416 <]/ return i;
8417 <]/ }
8418 <]/ }
8419 <]/ return -1;
8420 <]/ };
8421 <]/}
8422 <]/if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) {
8423 <]/ Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) {
8424 <]/ var self = splitString && _toString(this) == "[object String]" ?
8425 <]/ this.split("") :
8426 <]/ toObject(this),
8427 <]/ length = self.length >>> 0;
8428  
8429 <]/ if (!length) {
8430 <]/ return -1;
8431 <]/ }
8432 <]/ var i = length - 1;
8433 <]/ if (arguments.length > 1) {
8434 <]/ i = Math.min(i, toInteger(arguments[1]));
8435 <]/ }
8436 <]/ i = i >= 0 ? i : length - Math.abs(i);
8437 <]/ for (; i >= 0; i--) {
8438 <]/ if (i in self && sought === self[i]) {
8439 <]/ return i;
8440 <]/ }
8441 <]/ }
8442 <]/ return -1;
8443 <]/ };
8444 <]/}
8445 <]/if (!Object.getPrototypeOf) {
8446 <]/ Object.getPrototypeOf = function getPrototypeOf(object) {
8447 <]/ return object.__proto__ || (
8448 <]/ object.constructor ?
8449 <]/ object.constructor.prototype :
8450 <]/ prototypeOfObject
8451 <]/ );
8452 <]/ };
8453 <]/}
8454 <]/if (!Object.getOwnPropertyDescriptor) {
8455 <]/ var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " +
8456 <]/ "non-object: ";
8457 <]/ Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) {
8458 <]/ if ((typeof object != "object" && typeof object != "function") || object === null)
8459 <]/ throw new TypeError(ERR_NON_OBJECT + object);
8460 <]/ if (!owns(object, property))
8461 <]/ return;
8462  
8463 <]/ var descriptor, getter, setter;
8464 <]/ descriptor = { enumerable: true, configurable: true };
8465 <]/ if (supportsAccessors) {
8466 <]/ var prototype = object.__proto__;
8467 <]/ object.__proto__ = prototypeOfObject;
8468  
8469 <]/ var getter = lookupGetter(object, property);
8470 <]/ var setter = lookupSetter(object, property);
8471 <]/ object.__proto__ = prototype;
8472  
8473 <]/ if (getter || setter) {
8474 <]/ if (getter) descriptor.get = getter;
8475 <]/ if (setter) descriptor.set = setter;
8476 <]/ return descriptor;
8477 <]/ }
8478 <]/ }
8479 <]/ descriptor.value = object[property];
8480 <]/ return descriptor;
8481 <]/ };
8482 <]/}
8483 <]/if (!Object.getOwnPropertyNames) {
8484 <]/ Object.getOwnPropertyNames = function getOwnPropertyNames(object) {
8485 <]/ return Object.keys(object);
8486 <]/ };
8487 <]/}
8488 <]/if (!Object.create) {
8489 <]/ var createEmpty;
8490 <]/ if (Object.prototype.__proto__ === null) {
8491 <]/ createEmpty = function () {
8492 <]/ return { "__proto__": null };
8493 <]/ };
8494 <]/ } else {
8495 <]/ createEmpty = function () {
8496 <]/ var empty = {};
8497 <]/ for (var i in empty)
8498 <]/ empty[i] = null;
8499 <]/ empty.constructor =
8500 <]/ empty.hasOwnProperty =
8501 <]/ empty.propertyIsEnumerable =
8502 <]/ empty.isPrototypeOf =
8503 <]/ empty.toLocaleString =
8504 <]/ empty.toString =
8505 <]/ empty.valueOf =
8506 <]/ empty.__proto__ = null;
8507 <]/ return empty;
8508 <]/ }
8509 <]/ }
8510  
8511 <]/ Object.create = function create(prototype, properties) {
8512 <]/ var object;
8513 <]/ if (prototype === null) {
8514 <]/ object = createEmpty();
8515 <]/ } else {
8516 <]/ if (typeof prototype != "object")
8517 <]/ throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'");
8518 <]/ var Type = function () {};
8519 <]/ Type.prototype = prototype;
8520 <]/ object = new Type();
8521 <]/ object.__proto__ = prototype;
8522 <]/ }
8523 <]/ if (properties !== void 0)
8524 <]/ Object.defineProperties(object, properties);
8525 <]/ return object;
8526 <]/ };
8527 <]/}
8528  
8529 <]/function doesDefinePropertyWork(object) {
8530 <]/ try {
8531 <]/ Object.defineProperty(object, "sentinel", {});
8532 <]/ return "sentinel" in object;
8533 <]/ } catch (exception) {
8534 <]/ }
8535 <]/}
8536 <]/if (Object.defineProperty) {
8537 <]/ var definePropertyWorksOnObject = doesDefinePropertyWork({});
8538 <]/ var definePropertyWorksOnDom = typeof document == "undefined" ||
8539 <]/ doesDefinePropertyWork(document.createElement("div"));
8540 <]/ if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) {
8541 <]/ var definePropertyFallback = Object.defineProperty;
8542 <]/ }
8543 <]/}
8544  
8545 <]/if (!Object.defineProperty || definePropertyFallback) {
8546 <]/ var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: ";
8547 <]/ var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: "
8548 <]/ var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " +
8549 <]/ "on this javascript engine";
8550  
8551 <]/ Object.defineProperty = function defineProperty(object, property, descriptor) {
8552 <]/ if ((typeof object != "object" && typeof object != "function") || object === null)
8553 <]/ throw new TypeError(ERR_NON_OBJECT_TARGET + object);
8554 <]/ if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null)
8555 <]/ throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);
8556 <]/ if (definePropertyFallback) {
8557 <]/ try {
8558 <]/ return definePropertyFallback.call(Object, object, property, descriptor);
8559 <]/ } catch (exception) {
8560 <]/ }
8561 <]/ }
8562 <]/ if (owns(descriptor, "value")) {
8563  
8564 <]/ if (supportsAccessors && (lookupGetter(object, property) ||
8565 <]/ lookupSetter(object, property)))
8566 <]/ {
8567 <]/ var prototype = object.__proto__;
8568 <]/ object.__proto__ = prototypeOfObject;
8569 <]/ delete object[property];
8570 <]/ object[property] = descriptor.value;
8571 <]/ object.__proto__ = prototype;
8572 <]/ } else {
8573 <]/ object[property] = descriptor.value;
8574 <]/ }
8575 <]/ } else {
8576 <]/ if (!supportsAccessors)
8577 <]/ throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
8578 <]/ if (owns(descriptor, "get"))
8579 <]/ defineGetter(object, property, descriptor.get);
8580 <]/ if (owns(descriptor, "set"))
8581 <]/ defineSetter(object, property, descriptor.set);
8582 <]/ }
8583  
8584 <]/ return object;
8585 <]/ };
8586 <]/}
8587 <]/if (!Object.defineProperties) {
8588 <]/ Object.defineProperties = function defineProperties(object, properties) {
8589 <]/ for (var property in properties) {
8590 <]/ if (owns(properties, property))
8591 <]/ Object.defineProperty(object, property, properties[property]);
8592 <]/ }
8593 <]/ return object;
8594 <]/ };
8595 <]/}
8596 <]/if (!Object.seal) {
8597 <]/ Object.seal = function seal(object) {
8598 <]/ return object;
8599 <]/ };
8600 <]/}
8601 <]/if (!Object.freeze) {
8602 <]/ Object.freeze = function freeze(object) {
8603 <]/ return object;
8604 <]/ };
8605 <]/}
8606 <]/try {
8607 <]/ Object.freeze(function () {});
8608 <]/} catch (exception) {
8609 <]/ Object.freeze = (function freeze(freezeObject) {
8610 <]/ return function freeze(object) {
8611 <]/ if (typeof object == "function") {
8612 <]/ return object;
8613 <]/ } else {
8614 <]/ return freezeObject(object);
8615 <]/ }
8616 <]/ };
8617 <]/ })(Object.freeze);
8618 <]/}
8619 <]/if (!Object.preventExtensions) {
8620 <]/ Object.preventExtensions = function preventExtensions(object) {
8621 <]/ return object;
8622 <]/ };
8623 <]/}
8624 <]/if (!Object.isSealed) {
8625 <]/ Object.isSealed = function isSealed(object) {
8626 <]/ return false;
8627 <]/ };
8628 <]/}
8629 <]/if (!Object.isFrozen) {
8630 <]/ Object.isFrozen = function isFrozen(object) {
8631 <]/ return false;
8632 <]/ };
8633 <]/}
8634 <]/if (!Object.isExtensible) {
8635 <]/ Object.isExtensible = function isExtensible(object) {
8636 <]/ if (Object(object) === object) {
8637 <]/ throw new TypeError(); // TODO message
8638 <]/ }
8639 <]/ var name = '';
8640 <]/ while (owns(object, name)) {
8641 <]/ name += '?';
8642 <]/ }
8643 <]/ object[name] = true;
8644 <]/ var returnValue = owns(object, name);
8645 <]/ delete object[name];
8646 <]/ return returnValue;
8647 <]/ };
8648 <]/}
8649 <]/if (!Object.keys) {
8650 <]/ var hasDontEnumBug = true,
8651 <]/ dontEnums = [
8652 <]/ "toString",
8653 <]/ "toLocaleString",
8654 <]/ "valueOf",
8655 <]/ "hasOwnProperty",
8656 <]/ "isPrototypeOf",
8657 <]/ "propertyIsEnumerable",
8658 <]/ "constructor"
8659 <]/ ],
8660 <]/ dontEnumsLength = dontEnums.length;
8661  
8662 <]/ for (var key in {"toString": null}) {
8663 <]/ hasDontEnumBug = false;
8664 <]/ }
8665  
8666 <]/ Object.keys = function keys(object) {
8667  
8668 <]/ if (
8669 <]/ (typeof object != "object" && typeof object != "function") ||
8670 <]/ object === null
8671 <]/ ) {
8672 <]/ throw new TypeError("Object.keys called on a non-object");
8673 <]/ }
8674  
8675 <]/ var keys = [];
8676 <]/ for (var name in object) {
8677 <]/ if (owns(object, name)) {
8678 <]/ keys.push(name);
8679 <]/ }
8680 <]/ }
8681  
8682 <]/ if (hasDontEnumBug) {
8683 <]/ for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
8684 <]/ var dontEnum = dontEnums[i];
8685 <]/ if (owns(object, dontEnum)) {
8686 <]/ keys.push(dontEnum);
8687 <]/ }
8688 <]/ }
8689 <]/ }
8690 <]/ return keys;
8691 <]/ };
8692  
8693 <]/}
8694 <]/if (!Date.now) {
8695 <]/ Date.now = function now() {
8696 <]/ return new Date().getTime();
8697 <]/ };
8698 <]/}
8699 <]/var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
8700 <]/ "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
8701 <]/ "\u2029\uFEFF";
8702 <]/if (!String.prototype.trim || ws.trim()) {
8703 <]/ ws = "[" + ws + "]";
8704 <]/ var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
8705 <]/ trimEndRegexp = new RegExp(ws + ws + "*$");
8706 <]/ String.prototype.trim = function trim() {
8707 <]/ return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
8708 <]/ };
8709 <]/}
8710  
8711 <]/function toInteger(n) {
8712 <]/ n = +n;
8713 <]/ if (n !== n) { // isNaN
8714 <]/ n = 0;
8715 <]/ } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) {
8716 <]/ n = (n > 0 || -1) * Math.floor(Math.abs(n));
8717 <]/ }
8718 <]/ return n;
8719 <]/}
8720  
8721 <]/function isPrimitive(input) {
8722 <]/ var type = typeof input;
8723 <]/ return (
8724 <]/ input === null ||
8725 <]/ type === "undefined" ||
8726 <]/ type === "boolean" ||
8727 <]/ type === "number" ||
8728 <]/ type === "string"
8729 <]/ );
8730 <]/}
8731  
8732 <]/function toPrimitive(input) {
8733 <]/ var val, valueOf, toString;
8734 <]/ if (isPrimitive(input)) {
8735 <]/ return input;
8736 <]/ }
8737 <]/ valueOf = input.valueOf;
8738 <]/ if (typeof valueOf === "function") {
8739 <]/ val = valueOf.call(input);
8740 <]/ if (isPrimitive(val)) {
8741 <]/ return val;
8742 <]/ }
8743 <]/ }
8744 <]/ toString = input.toString;
8745 <]/ if (typeof toString === "function") {
8746 <]/ val = toString.call(input);
8747 <]/ if (isPrimitive(val)) {
8748 <]/ return val;
8749 <]/ }
8750 <]/ }
8751 <]/ throw new TypeError();
8752 <]/}
8753 <]/var toObject = function (o) {
8754 <]/ if (o == null) { // this matches both null and undefined
8755 <]/ throw new TypeError("can't convert "+o+" to object");
8756 <]/ }
8757 <]/ return Object(o);
8758 <]/};
8759  
8760 <]/});