/lenasys/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/lenasys/trunk

« back to all changes in this revision

Viewing changes to codeigniter/js/ace/worker-css.js

  • Committer: galaxyAbstractor
  • Date: 2013-04-10 15:49:32 UTC
  • mto: (19.1.5 lenasys)
  • mto: This revision was merged to the branch mainline in revision 23.
  • Revision ID: galaxyabstractor@gmail.com-20130410154932-4vizlzk0ar5gykvi
* Added an simple admin panel to the codeviewer-cmssy stuff
* Redesigned a bit like the mockups - still stuff to come
* Implemented the codeviewer + admin panel again using the Framework CodeIgniter instead 

Show diffs side-by-side

added added

removed removed

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