/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: Erik Wikström
  • Date: 2013-03-28 07:43:18 UTC
  • mto: This revision was merged to the branch mainline in revision 7.
  • Revision ID: wikxen@gmail.com-20130328074318-9v6krijkyap59nct
Removed trunk folder and moved its contents to the root

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
 
});