/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: a11andoh
  • Date: 2013-05-24 11:28:43 UTC
  • mto: This revision was merged to the branch mainline in revision 97.
  • Revision ID: a11andoh@student.his.se-20130524112843-360je7hu7q13r171
added the cms controller to load all content pages.
added first time registration controller to load the views for the registration
pages.
added and fixed temporarypages for the controllers 
and edited the models to be able to get active courses.

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