123

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

            
              <html>
<html lang="en" class="no-js">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 
		<meta name="viewport" content="width=device-width, initial-scale=1.0"> 
		<title>Nifty Modal Window Effects</title>
		<meta name="description" content="Nifty Modal Window Effects with CSS Transitions and Animations" />
		<meta name="keywords" content="modal, window, overlay, modern, box, css transition, css animation, effect, 3d, perspective" />
		<meta name="author" content="Codrops" />
		<link rel="shortcut icon" href="../favicon.ico"> 
		<link rel="stylesheet" type="text/css" href="css/default.css" />
		<link rel="stylesheet" type="text/css" href="css/component.css" />
		<script src="js/modernizr.custom.js"></script>
	</head>
	<body>
		<!-- All modals added here for the demo. You would of course just have one, dynamically created -->
		<div class="md-modal md-effect-1" id="modal-1">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-2" id="modal-2">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-3" id="modal-3">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-4" id="modal-4">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-5" id="modal-5">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-6" id="modal-6">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-7" id="modal-7">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-8" id="modal-8">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-9" id="modal-9">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-10" id="modal-10">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-11" id="modal-11">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-12" id="modal-12">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-13" id="modal-13">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-14" id="modal-14">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-15" id="modal-15">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-16" id="modal-16">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-17" id="modal-17">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-18" id="modal-18">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-19" id="modal-19">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="md-modal md-effect-20" id="modal-20">
			<div class="md-content">
				<h3>Modal Dialog</h3>
				<div>
					<p>This is a modal window. You can do the following things with it:</p>
					<ul>
						<li><strong>Read:</strong> modal windows will probably tell you something important so don't forget to read what they say.</li>
						<li><strong>Look:</strong> a modal window enjoys a certain kind of attention; just look at it and appreciate its presence.</li>
						<li><strong>Close:</strong> click on the button below to close the modal.</li>
					</ul>
					<button class="md-close">Close me!</button>
				</div>
			</div>
		</div>
		<div class="container">
			<!-- Top Navigation -->
			
			<header>
				<h1>Nifty Modal Window Effects <span>Some inspiration for different modal window appearances</span></h1>
			</header>
			<div class="main clearfix">
				<div class="column">
					<p>There are many possibilities for modal overlays to appear. Here are some modern ways of showing them using CSS transitions and animations.</p>
				</div>
				<div class="column">
					<button class="md-trigger" data-modal="modal-1">Fade in &amp; Scale</button>
					<button class="md-trigger" data-modal="modal-2">Slide in (right)</button>
					<button class="md-trigger" data-modal="modal-3">Slide in (bottom)</button>
					<button class="md-trigger" data-modal="modal-4">Newspaper</button>
					<button class="md-trigger" data-modal="modal-5">Fall</button>
					<button class="md-trigger" data-modal="modal-6">Side Fall</button>
					<button class="md-trigger" data-modal="modal-7">Sticky Up</button>
					<button class="md-trigger" data-modal="modal-8">3D Flip (horizontal)</button>
					<button class="md-trigger" data-modal="modal-9">3D Flip (vertical)</button>
					<button class="md-trigger" data-modal="modal-10">3D Sign</button>
					<button class="md-trigger" data-modal="modal-11">Super Scaled</button>
					<button class="md-trigger" data-modal="modal-12">Just Me</button>
					<button class="md-trigger" data-modal="modal-13">3D Slit</button>
					<button class="md-trigger" data-modal="modal-14">3D Rotate Bottom</button>
					<button class="md-trigger" data-modal="modal-15">3D Rotate In Left</button>
					<button class="md-trigger" data-modal="modal-16">Blur</button>
					<!-- special modal that will add a perspective class to the html element -->
					<button class="md-trigger md-setperspective" data-modal="modal-17">Let me in</button>
					<button class="md-trigger md-setperspective" data-modal="modal-18">Make way!</button>
					<button class="md-trigger md-setperspective" data-modal="modal-19">Slip from top</button>
          
          <button> <span> Thank TO tympanus.net</span></button>
          
				</div>
			</div>
		</div><!-- /container -->
		<div class="md-overlay"></div><!-- the overlay element -->

		<!-- classie.js by @desandro: https://github.com/desandro/classie -->
		<script src="js/classie.js"></script>
		<script src="js/modalEffects.js"></script>

		<!-- for the blur effect -->
		<!-- by @derSchepp https://github.com/Schepp/CSS-Filters-Polyfill -->
		<script>
			// this is important for IEs
			var polyfilter_scriptpath = '/js/';
		</script>
		<script src="js/cssParser.js"></script>
		<script src="js/css-filters-polyfill.js"></script>
	</body>
</html>
            
          
!
            
              /* General Demo Style */
@import url(https://fonts.googleapis.com/css?family=Lato:300,400,700);

@font-face {
	font-family: 'codropsicons';
	src:url('../fonts/codropsicons/codropsicons.eot');
	src:url('../fonts/codropsicons/codropsicons.eot?#iefix') format('embedded-opentype'),
		url('../fonts/codropsicons/codropsicons.woff') format('woff'),
		url('../fonts/codropsicons/codropsicons.ttf') format('truetype'),
		url('../fonts/codropsicons/codropsicons.svg#codropsicons') format('svg');
	font-weight: normal;
	font-style: normal;
}

*, *:after, *:before { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; }
body, html { font-size: 100%; padding: 0; margin: 0; }

/* Clearfix hack by Nicolas Gallagher: http://nicolasgallagher.com/micro-clearfix-hack/ */
.clearfix:before, .clearfix:after { content: " "; display: table; }
.clearfix:after { clear: both; }

body {
	font-family: 'Lato', Calibri, Arial, sans-serif;
	color: #fff;
	background: #e74c3c;
}

a {
	color: #c0392b;
	text-decoration: none;
}

a:hover,
a:active {
	color: #333;
}

/* Header Style */
.main,
.container > header {
	margin: 0 auto;
	padding: 2em;
}

.container > header {
	text-align: center;
	background: #d94839;
	padding: 3em;
}

.container > header h1 {
	font-size: 2.625em;
	line-height: 1.3;
	margin: 0;
	font-weight: 300;
}

.container > header span {
	display: block;
	font-size: 60%;
	opacity: 0.7;
	padding: 0 0 0.6em 0.1em;
}

/* Main Content */
.main {
	max-width: 69em;
}

.column {
	float: left;
	width: 50%;
	padding: 0 2em;
	min-height: 300px;
	position: relative;
}

.column:nth-child(2) {
	box-shadow: -1px 0 0 rgba(0,0,0,0.1);
}

.column p {
	font-weight: 300;
	font-size: 2em;
	padding: 0;
	margin: 0;
	text-align: right;
	line-height: 1.5;
}

/* To Navigation Style */
.codrops-top {
	background: #fff;
	background: rgba(255, 255, 255, 0.2);
	text-transform: uppercase;
	width: 100%;
	font-size: 0.69em;
	line-height: 2.2;
}

.codrops-top a {
	padding: 0 1em;
	letter-spacing: 0.1em;
	display: inline-block;
}

.codrops-top a:hover {
	color: #e74c3c;
	background: rgba(255,255,255,0.6);
}

.codrops-top span.right {
	float: right;
}

.codrops-top span.right a {
	float: left;
	display: block;
}

.codrops-icon:before {
	font-family: 'codropsicons';
	margin: 0 4px;
	speak: none;
	font-style: normal;
	font-weight: normal;
	font-variant: normal;
	text-transform: none;
	line-height: 1;
	-webkit-font-smoothing: antialiased;
}

.codrops-icon-drop:before {
	content: "\e001";
}

.codrops-icon-prev:before {
	content: "\e004";
}

button {
	border: none;
	padding: 0.6em 1.2em;
	background: #c0392b;
	color: #fff;
	font-family: 'Lato', Calibri, Arial, sans-serif;
	font-size: 1em;
	letter-spacing: 1px;
	text-transform: uppercase;
	cursor: pointer;
	display: inline-block;
	margin: 3px 2px;
	border-radius: 2px;
}

button:hover {
	background: #A5281B;
}

@media screen and (max-width: 46.0625em) {
	.column {
		width: 100%;
		min-width: auto;
		min-height: auto;
		padding: 1em; 
	}

	.column p {
		text-align: left;
		font-size: 1.5em;
	}

	.column:nth-child(2) {
		box-shadow: 0 -1px 0 rgba(0,0,0,0.1);
	}
}

@media screen and (max-width: 25em) {

	.codrops-icon span {
		display: none;
	}

}


/* General styles for the modal */

/* 
Styles for the html/body for special modal where we want 3d effects
Note that we need a container wrapping all content on the page for the 
perspective effects (not including the modals and the overlay).
*/
.md-perspective,
.md-perspective body {
	height: 100%;
	overflow: hidden;
}

.md-perspective body  {
	background: #222;
	-webkit-perspective: 600px;
	-moz-perspective: 600px;
	perspective: 600px;
}

.container {
	background: #e74c3c;
	min-height: 100%;
}

.md-modal {
	position: fixed;
	top: 50%;
	left: 50%;
	width: 50%;
	max-width: 630px;
	min-width: 320px;
	height: auto;
	z-index: 2000;
	visibility: hidden;
	-webkit-backface-visibility: hidden;
	-moz-backface-visibility: hidden;
	backface-visibility: hidden;
	-webkit-transform: translateX(-50%) translateY(-50%);
	-moz-transform: translateX(-50%) translateY(-50%);
	-ms-transform: translateX(-50%) translateY(-50%);
	transform: translateX(-50%) translateY(-50%);
}

.md-show {
	visibility: visible;
}

.md-overlay {
	position: fixed;
	width: 100%;
	height: 100%;
	visibility: hidden;
	top: 0;
	left: 0;
	z-index: 1000;
	opacity: 0;
	background: rgba(143,27,15,0.8);
	-webkit-transition: all 0.3s;
	-moz-transition: all 0.3s;
	transition: all 0.3s;
}

.md-show ~ .md-overlay {
	opacity: 1;
	visibility: visible;
}

/* Content styles */
.md-content {
	color: #fff;
	background: #e74c3c;
	position: relative;
	border-radius: 3px;
	margin: 0 auto;
}

.md-content h3 {
	margin: 0;
	padding: 0.4em;
	text-align: center;
	font-size: 2.4em;
	font-weight: 300;
	opacity: 0.8;
	background: rgba(0,0,0,0.1);
	border-radius: 3px 3px 0 0;
}

.md-content > div {
	padding: 15px 40px 30px;
	margin: 0;
	font-weight: 300;
	font-size: 1.15em;
}

.md-content > div p {
	margin: 0;
	padding: 10px 0;
}

.md-content > div ul {
	margin: 0;
	padding: 0 0 30px 20px;
}

.md-content > div ul li {
	padding: 5px 0;
}

.md-content button {
	display: block;
	margin: 0 auto;
	font-size: 0.8em;
}

/* Individual modal styles with animations/transitions */

/* Effect 1: Fade in and scale up */
.md-effect-1 .md-content {
	-webkit-transform: scale(0.7);
	-moz-transform: scale(0.7);
	-ms-transform: scale(0.7);
	transform: scale(0.7);
	opacity: 0;
	-webkit-transition: all 0.3s;
	-moz-transition: all 0.3s;
	transition: all 0.3s;
}

.md-show.md-effect-1 .md-content {
	-webkit-transform: scale(1);
	-moz-transform: scale(1);
	-ms-transform: scale(1);
	transform: scale(1);
	opacity: 1;
}

/* Effect 2: Slide from the right */
.md-effect-2 .md-content {
	-webkit-transform: translateX(20%);
	-moz-transform: translateX(20%);
	-ms-transform: translateX(20%);
	transform: translateX(20%);
	opacity: 0;
	-webkit-transition: all 0.3s cubic-bezier(0.25, 0.5, 0.5, 0.9);
	-moz-transition: all 0.3s cubic-bezier(0.25, 0.5, 0.5, 0.9);
	transition: all 0.3s cubic-bezier(0.25, 0.5, 0.5, 0.9);
}

.md-show.md-effect-2 .md-content {
	-webkit-transform: translateX(0);
	-moz-transform: translateX(0);
	-ms-transform: translateX(0);
	transform: translateX(0);
	opacity: 1;
}

/* Effect 3: Slide from the bottom */
.md-effect-3 .md-content {
	-webkit-transform: translateY(20%);
	-moz-transform: translateY(20%);
	-ms-transform: translateY(20%);
	transform: translateY(20%);
	opacity: 0;
	-webkit-transition: all 0.3s;
	-moz-transition: all 0.3s;
	transition: all 0.3s;
}

.md-show.md-effect-3 .md-content {
	-webkit-transform: translateY(0);
	-moz-transform: translateY(0);
	-ms-transform: translateY(0);
	transform: translateY(0);
	opacity: 1;
}

/* Effect 4: Newspaper */
.md-effect-4 .md-content {
	-webkit-transform: scale(0) rotate(720deg);
	-moz-transform: scale(0) rotate(720deg);
	-ms-transform: scale(0) rotate(720deg);
	transform: scale(0) rotate(720deg);
	opacity: 0;
}

.md-show.md-effect-4 ~ .md-overlay,
.md-effect-4 .md-content {
	-webkit-transition: all 0.5s;
	-moz-transition: all 0.5s;
	transition: all 0.5s;
}

.md-show.md-effect-4 .md-content {
	-webkit-transform: scale(1) rotate(0deg);
	-moz-transform: scale(1) rotate(0deg);
	-ms-transform: scale(1) rotate(0deg);
	transform: scale(1) rotate(0deg);
	opacity: 1;
}

/* Effect 5: fall */
.md-effect-5.md-modal {
	-webkit-perspective: 1300px;
	-moz-perspective: 1300px;
	perspective: 1300px;
}

.md-effect-5 .md-content {
	-webkit-transform-style: preserve-3d;
	-moz-transform-style: preserve-3d;
	transform-style: preserve-3d;
	-webkit-transform: translateZ(600px) rotateX(20deg); 
	-moz-transform: translateZ(600px) rotateX(20deg); 
	-ms-transform: translateZ(600px) rotateX(20deg); 
	transform: translateZ(600px) rotateX(20deg); 
	opacity: 0;
}

.md-show.md-effect-5 .md-content {
	-webkit-transition: all 0.3s ease-in;
	-moz-transition: all 0.3s ease-in;
	transition: all 0.3s ease-in;
	-webkit-transform: translateZ(0px) rotateX(0deg);
	-moz-transform: translateZ(0px) rotateX(0deg);
	-ms-transform: translateZ(0px) rotateX(0deg);
	transform: translateZ(0px) rotateX(0deg); 
	opacity: 1;
}

/* Effect 6: side fall */
.md-effect-6.md-modal {
	-webkit-perspective: 1300px;
	-moz-perspective: 1300px;
	perspective: 1300px;
}

.md-effect-6 .md-content {
	-webkit-transform-style: preserve-3d;
	-moz-transform-style: preserve-3d;
	transform-style: preserve-3d;
	-webkit-transform: translate(30%) translateZ(600px) rotate(10deg); 
	-moz-transform: translate(30%) translateZ(600px) rotate(10deg);
	-ms-transform: translate(30%) translateZ(600px) rotate(10deg);
	transform: translate(30%) translateZ(600px) rotate(10deg); 
	opacity: 0;
}

.md-show.md-effect-6 .md-content {
	-webkit-transition: all 0.3s ease-in;
	-moz-transition: all 0.3s ease-in;
	transition: all 0.3s ease-in;
	-webkit-transform: translate(0%) translateZ(0) rotate(0deg);
	-moz-transform: translate(0%) translateZ(0) rotate(0deg);
	-ms-transform: translate(0%) translateZ(0) rotate(0deg);
	transform: translate(0%) translateZ(0) rotate(0deg);
	opacity: 1;
}

/* Effect 7:  slide and stick to top */
.md-effect-7{
	top: 0;
	-webkit-transform: translateX(-50%);
	-moz-transform: translateX(-50%);
	-ms-transform: translateX(-50%);
	transform: translateX(-50%);
}

.md-effect-7 .md-content {
	-webkit-transform: translateY(-200%);
	-moz-transform: translateY(-200%);
	-ms-transform: translateY(-200%);
	transform: translateY(-200%);
	-webkit-transition: all .3s;
	-moz-transition: all .3s;
	transition: all .3s;
	opacity: 0;
}

.md-show.md-effect-7 .md-content {
	-webkit-transform: translateY(0%);
	-moz-transform: translateY(0%);
	-ms-transform: translateY(0%);
	transform: translateY(0%);
	border-radius: 0 0 3px 3px;
	opacity: 1;
}

/* Effect 8: 3D flip horizontal */
.md-effect-8.md-modal {
	-webkit-perspective: 1300px;
	-moz-perspective: 1300px;
	perspective: 1300px;
}

.md-effect-8 .md-content {
	-webkit-transform-style: preserve-3d;
	-moz-transform-style: preserve-3d;
	transform-style: preserve-3d;
	-webkit-transform: rotateY(-70deg);
	-moz-transform: rotateY(-70deg);
	-ms-transform: rotateY(-70deg);
	transform: rotateY(-70deg);
	-webkit-transition: all 0.3s;
	-moz-transition: all 0.3s;
	transition: all 0.3s;
	opacity: 0;
}

.md-show.md-effect-8 .md-content {
	-webkit-transform: rotateY(0deg);
	-moz-transform: rotateY(0deg);
	-ms-transform: rotateY(0deg);
	transform: rotateY(0deg);
	opacity: 1;
}

/* Effect 9: 3D flip vertical */
.md-effect-9.md-modal {
	-webkit-perspective: 1300px;
	-moz-perspective: 1300px;
	perspective: 1300px;
}

.md-effect-9 .md-content {
	-webkit-transform-style: preserve-3d;
	-moz-transform-style: preserve-3d;
	transform-style: preserve-3d;
	-webkit-transform: rotateX(-70deg);
	-moz-transform: rotateX(-70deg);
	-ms-transform: rotateX(-70deg);
	transform: rotateX(-70deg);
	-webkit-transition: all 0.3s;
	-moz-transition: all 0.3s;
	transition: all 0.3s;
	opacity: 0;
}

.md-show.md-effect-9 .md-content {
	-webkit-transform: rotateX(0deg);
	-moz-transform: rotateX(0deg);
	-ms-transform: rotateX(0deg);
	transform: rotateX(0deg);
	opacity: 1;
}

/* Effect 10: 3D sign */
.md-effect-10.md-modal {
	-webkit-perspective: 1300px;
	-moz-perspective: 1300px;
	perspective: 1300px;
}

.md-effect-10 .md-content {
	-webkit-transform-style: preserve-3d;
	-moz-transform-style: preserve-3d;
	transform-style: preserve-3d;
	-webkit-transform: rotateX(-60deg);
	-moz-transform: rotateX(-60deg);
	-ms-transform: rotateX(-60deg);
	transform: rotateX(-60deg);
	-webkit-transform-origin: 50% 0;
	-moz-transform-origin: 50% 0;
	transform-origin: 50% 0;
	opacity: 0;
	-webkit-transition: all 0.3s;
	-moz-transition: all 0.3s;
	transition: all 0.3s;
}

.md-show.md-effect-10 .md-content {
	-webkit-transform: rotateX(0deg);
	-moz-transform: rotateX(0deg);
	-ms-transform: rotateX(0deg);
	transform: rotateX(0deg);
	opacity: 1;
}

/* Effect 11: Super scaled */
.md-effect-11 .md-content {
	-webkit-transform: scale(2);
	-moz-transform: scale(2);
	-ms-transform: scale(2);
	transform: scale(2);
	opacity: 0;
	-webkit-transition: all 0.3s;
	-moz-transition: all 0.3s;
	transition: all 0.3s;
}

.md-show.md-effect-11 .md-content {
	-webkit-transform: scale(1);
	-moz-transform: scale(1);
	-ms-transform: scale(1);
	transform: scale(1);
	opacity: 1;
}

/* Effect 12:  Just me */
.md-effect-12 .md-content {
	-webkit-transform: scale(0.8);
	-moz-transform: scale(0.8);
	-ms-transform: scale(0.8);
	transform: scale(0.8);
	opacity: 0;
	-webkit-transition: all 0.3s;
	-moz-transition: all 0.3s;
	transition: all 0.3s;
}

.md-show.md-effect-12 ~ .md-overlay {
	background: #e74c3c;
} 

.md-effect-12 .md-content h3,
.md-effect-12 .md-content {
	background: transparent;
}

.md-show.md-effect-12 .md-content {
	-webkit-transform: scale(1);
	-moz-transform: scale(1);
	-ms-transform: scale(1);
	transform: scale(1);
	opacity: 1;
}

/* Effect 13: 3D slit */
.md-effect-13.md-modal {
	-webkit-perspective: 1300px;
	-moz-perspective: 1300px;
	perspective: 1300px;
}

.md-effect-13 .md-content {
	-webkit-transform-style: preserve-3d;
	-moz-transform-style: preserve-3d;
	transform-style: preserve-3d;
	-webkit-transform: translateZ(-3000px) rotateY(90deg);
	-moz-transform: translateZ(-3000px) rotateY(90deg);
	-ms-transform: translateZ(-3000px) rotateY(90deg);
	transform: translateZ(-3000px) rotateY(90deg);
	opacity: 0;
}

.md-show.md-effect-13 .md-content {
	-webkit-animation: slit .7s forwards ease-out;
	-moz-animation: slit .7s forwards ease-out;
	animation: slit .7s forwards ease-out;
}

@-webkit-keyframes slit {
	50% { -webkit-transform: translateZ(-250px) rotateY(89deg); opacity: .5; -webkit-animation-timing-function: ease-out;}
	100% { -webkit-transform: translateZ(0) rotateY(0deg); opacity: 1; }
}

@-moz-keyframes slit {
	50% { -moz-transform: translateZ(-250px) rotateY(89deg); opacity: .5; -moz-animation-timing-function: ease-out;}
	100% { -moz-transform: translateZ(0) rotateY(0deg); opacity: 1; }
}

@keyframes slit {
	50% { transform: translateZ(-250px) rotateY(89deg); opacity: 1; animation-timing-function: ease-in;}
	100% { transform: translateZ(0) rotateY(0deg); opacity: 1; }
}

/* Effect 14:  3D Rotate from bottom */
.md-effect-14.md-modal {
	-webkit-perspective: 1300px;
	-moz-perspective: 1300px;
	perspective: 1300px;
}

.md-effect-14 .md-content {
	-webkit-transform-style: preserve-3d;
	-moz-transform-style: preserve-3d;
	transform-style: preserve-3d;
	-webkit-transform: translateY(100%) rotateX(90deg);
	-moz-transform: translateY(100%) rotateX(90deg);
	-ms-transform: translateY(100%) rotateX(90deg);
	transform: translateY(100%) rotateX(90deg);
	-webkit-transform-origin: 0 100%;
	-moz-transform-origin: 0 100%;
	transform-origin: 0 100%;
	opacity: 0;
	-webkit-transition: all 0.3s ease-out;
	-moz-transition: all 0.3s ease-out;
	transition: all 0.3s ease-out;
}

.md-show.md-effect-14 .md-content {
	-webkit-transform: translateY(0%) rotateX(0deg);
	-moz-transform: translateY(0%) rotateX(0deg);
	-ms-transform: translateY(0%) rotateX(0deg);
	transform: translateY(0%) rotateX(0deg);
	opacity: 1;
}

/* Effect 15:  3D Rotate in from left */
.md-effect-15.md-modal {
	-webkit-perspective: 1300px;
	-moz-perspective: 1300px;
	perspective: 1300px;
}

.md-effect-15 .md-content {
	-webkit-transform-style: preserve-3d;
	-moz-transform-style: preserve-3d;
	transform-style: preserve-3d;
	-webkit-transform: translateZ(100px) translateX(-30%) rotateY(90deg);
	-moz-transform: translateZ(100px) translateX(-30%) rotateY(90deg);
	-ms-transform: translateZ(100px) translateX(-30%) rotateY(90deg);
	transform: translateZ(100px) translateX(-30%) rotateY(90deg);
	-webkit-transform-origin: 0 100%;
	-moz-transform-origin: 0 100%;
	transform-origin: 0 100%;
	opacity: 0;
	-webkit-transition: all 0.3s;
	-moz-transition: all 0.3s;
	transition: all 0.3s;
}

.md-show.md-effect-15 .md-content {
	-webkit-transform: translateZ(0px) translateX(0%) rotateY(0deg);
	-moz-transform: translateZ(0px) translateX(0%) rotateY(0deg);
	-ms-transform: translateZ(0px) translateX(0%) rotateY(0deg);
	transform: translateZ(0px) translateX(0%) rotateY(0deg);
	opacity: 1;
}

/* Effect 16:  Blur */
.md-show.md-effect-16 ~ .md-overlay {
	background: rgba(180,46,32,0.5);
}

.md-show.md-effect-16 ~ .container {
	-webkit-filter: blur(3px);
	-moz-filter: blur(3px);
	filter: blur(3px);
}

.md-effect-16 .md-content {
	-webkit-transform: translateY(-5%);
	-moz-transform: translateY(-5%);
	-ms-transform: translateY(-5%);
	transform: translateY(-5%);
	opacity: 0;
}

.md-show.md-effect-16 ~ .container,
.md-effect-16 .md-content {
	-webkit-transition: all 0.3s;
	-moz-transition: all 0.3s;
	transition: all 0.3s;
}

.md-show.md-effect-16 .md-content {
	-webkit-transform: translateY(0);
	-moz-transform: translateY(0);
	-ms-transform: translateY(0);
	transform: translateY(0);
	opacity: 1;
}

/* Effect 17:  Slide in from bottom with perspective on container */
.md-show.md-effect-17 ~ .container {
	height: 100%;
	overflow: hidden;
	-webkit-transition: -webkit-transform 0.3s;
	-moz-transition: -moz-transform 0.3s;
	transition: transform 0.3s;
}	

.md-show.md-effect-17 ~ .container,
.md-show.md-effect-17 ~ .md-overlay  {
	-webkit-transform: rotateX(-2deg);
	-moz-transform: rotateX(-2deg);
	-ms-transform: rotateX(-2deg);
	transform: rotateX(-2deg);
	-webkit-transform-origin: 50% 0%;
	-moz-transform-origin: 50% 0%;
	transform-origin: 50% 0%;
	-webkit-transform-style: preserve-3d;
	-moz-transform-style: preserve-3d;
	transform-style: preserve-3d;
}

.md-effect-17 .md-content {
	opacity: 0;
	-webkit-transform: translateY(200%);
	-moz-transform: translateY(200%);
	-ms-transform: translateY(200%);
	transform: translateY(200%);
}

.md-show.md-effect-17 .md-content {
	-webkit-transform: translateY(0);
	-moz-transform: translateY(0);
	-ms-transform: translateY(0);
	transform: translateY(0);
	opacity: 1;
	-webkit-transition: all 0.3s 0.2s;
	-moz-transition: all 0.3s 0.2s;
	transition: all 0.3s 0.2s;
}

/* Effect 18:  Slide from right with perspective on container */
.md-show.md-effect-18 ~ .container {
	height: 100%;
	overflow: hidden;
}

.md-show.md-effect-18 ~ .md-overlay {
	background: rgba(143,27,15,0.8);
	-webkit-transition: all 0.5s;
	-moz-transition: all 0.5s;
	transition: all 0.5s;
}

.md-show.md-effect-18 ~ .container,
.md-show.md-effect-18 ~ .md-overlay {
	-webkit-transform-style: preserve-3d;
	-webkit-transform-origin: 0% 50%;
	-webkit-animation: rotateRightSideFirst 0.5s forwards ease-in;
	-moz-transform-style: preserve-3d;
	-moz-transform-origin: 0% 50%;
	-moz-animation: rotateRightSideFirst 0.5s forwards ease-in;
	transform-style: preserve-3d;
	transform-origin: 0% 50%;
	animation: rotateRightSideFirst 0.5s forwards ease-in;
}

@-webkit-keyframes rotateRightSideFirst {
	50% { -webkit-transform: translateZ(-50px) rotateY(5deg); -webkit-animation-timing-function: ease-out; }
	100% { -webkit-transform: translateZ(-200px); }
}

@-moz-keyframes rotateRightSideFirst {
	50% { -moz-transform: translateZ(-50px) rotateY(5deg); -moz-animation-timing-function: ease-out; }
	100% { -moz-transform: translateZ(-200px); }
}

@keyframes rotateRightSideFirst {
	50% { transform: translateZ(-50px) rotateY(5deg); animation-timing-function: ease-out; }
	100% { transform: translateZ(-200px); }
}

.md-effect-18 .md-content {
	-webkit-transform: translateX(200%);
	-moz-transform: translateX(200%);
	-ms-transform: translateX(200%);
	transform: translateX(200%);
	opacity: 0;
}

.md-show.md-effect-18 .md-content {
	-webkit-transform: translateX(0);
	-moz-transform: translateX(0);
	-ms-transform: translateX(0);
	transform: translateX(0);
	opacity: 1;
	-webkit-transition: all 0.5s 0.1s;
	-moz-transition: all 0.5s 0.1s;
	transition: all 0.5s 0.1s;
}

/* Effect 19:  Slip in from the top with perspective on container */
.md-show.md-effect-19 ~ .container {
	height: 100%;
	overflow: hidden;
}

.md-show.md-effect-19 ~ .md-overlay {
	-webkit-transition: all 0.5s;
	-moz-transition: all 0.5s;
	transition: all 0.5s;
}

.md-show.md-effect-19 ~ .container,
.md-show.md-effect-19 ~ .md-overlay {
	-webkit-transform-style: preserve-3d;
	-webkit-transform-origin: 50% 100%;
	-webkit-animation: OpenTop 0.5s forwards ease-in;
	-moz-transform-style: preserve-3d;
	-moz-transform-origin: 50% 100%;
	-moz-animation: OpenTop 0.5s forwards ease-in;
	transform-style: preserve-3d;
	transform-origin: 50% 100%;
	animation: OpenTop 0.5s forwards ease-in;
}

@-webkit-keyframes OpenTop {
	50% { 
		-webkit-transform: rotateX(10deg); 
		-webkit-animation-timing-function: ease-out; 
	}
}

@-moz-keyframes OpenTop {
	50% { 
		-moz-transform: rotateX(10deg); 
		-moz-animation-timing-function: ease-out; 
	}
}

@keyframes OpenTop {
	50% { 
		transform: rotateX(10deg); 
		animation-timing-function: ease-out; 
	}
}

.md-effect-19 .md-content {
	-webkit-transform: translateY(-200%);
	-moz-transform: translateY(-200%);
	-ms-transform: translateY(-200%);
	transform: translateY(-200%);
	opacity: 0;
}

.md-show.md-effect-19 .md-content {
	-webkit-transform: translateY(0);
	-moz-transform: translateY(0);
	-ms-transform: translateY(0);
	transform: translateY(0);
	opacity: 1;
	-webkit-transition: all 0.5s 0.1s;
	-moz-transition: all 0.5s 0.1s;
	transition: all 0.5s 0.1s;
}

@media screen and (max-width: 32em) {
	body { font-size: 75%; }
}
            
          
!
            
              

( function( window ) {

'use strict';

// class helper functions from bonzo https://github.com/ded/bonzo

function classReg( className ) {
  return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
}

// classList support for class management
// altho to be fair, the api sucks because it won't accept multiple classes at once
var hasClass, addClass, removeClass;

if ( 'classList' in document.documentElement ) {
  hasClass = function( elem, c ) {
    return elem.classList.contains( c );
  };
  addClass = function( elem, c ) {
    elem.classList.add( c );
  };
  removeClass = function( elem, c ) {
    elem.classList.remove( c );
  };
}
else {
  hasClass = function( elem, c ) {
    return classReg( c ).test( elem.className );
  };
  addClass = function( elem, c ) {
    if ( !hasClass( elem, c ) ) {
      elem.className = elem.className + ' ' + c;
    }
  };
  removeClass = function( elem, c ) {
    elem.className = elem.className.replace( classReg( c ), ' ' );
  };
}

function toggleClass( elem, c ) {
  var fn = hasClass( elem, c ) ? removeClass : addClass;
  fn( elem, c );
}

var classie = {
  // full names
  hasClass: hasClass,
  addClass: addClass,
  removeClass: removeClass,
  toggleClass: toggleClass,
  // short names
  has: hasClass,
  add: addClass,
  remove: removeClass,
  toggle: toggleClass
};

// transport
if ( typeof define === 'function' && define.amd ) {
  // AMD
  define( classie );
} else {
  // browser global
  window.classie = classie;
}

})( window );

/*!
 * css-filters-polyfill.js
 *
 * Author: Christian Schepp Schaefer
 * Summary: A polyfill for CSS filter effects
 * License: MIT
 * Version: 0.22
 *
 * URL:
 * https://github.com/Schepp/
 *
 */
;(function(window){
	var polyfilter = {
		// Detect if we are dealing with IE <= 9
		// http://james.padolsey.com/javascript/detect-_ie-in-js-using-conditional-comments/
		_ie:			(function(){
			var undef,
			v = 3,
			div = document.createElement('div'),
			all = div.getElementsByTagName('i');
			
			while(
				div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
				all[0]
			);
			
			return v > 4 ? v : undef;
		}()),
		
		_svg_cache: 		{},
		
		_create_svg_element: function(tagname,attributes){
			var xmlns = 'http://www.w3.org/2000/svg';
			var elem = document.createElementNS(xmlns,tagname);
			for(key in attributes){
				elem.setAttributeNS(null,key,attributes[key]);
			}
			
			return elem;
		},
		
		_create_svg:	function(id,filterelements){
			var xmlns = 'http://www.w3.org/2000/svg';
			var svg = document.createElementNS(xmlns,'svg');
			svg.setAttributeNS(null,'width','0');
			svg.setAttributeNS(null,'height','0');
			svg.setAttributeNS(null,'style','position:absolute');
			
			var svg_filter = document.createElementNS(xmlns,'filter');
			svg_filter.setAttributeNS(null,'id',id);
			svg.appendChild(svg_filter);
			
			for(var i = 0; i < filterelements.length; i++){
				svg_filter.appendChild(filterelements[i]);
			}
			
			return svg;
		},
		
		_pending_stylesheets: 0,
	
		_stylesheets: 		[],
		
		_development_mode: (function(){
			if(location.hostname === 'localhost' || location.hostname.search(/.local$/) !== -1 || location.hostname.search(/\d+\.\d+\.\d+\.\d+/) !== -1){
				if(window.console) console.log('Detected localhost or IP address. Assuming you are a developer. Caching of stylesheets is disabled.');
				return true;
			}
			if(window.console) console.log('Caching of stylesheets is enabled. You need to refresh twice to see any changes.');
			return false;
		})(),
		
		process_stylesheets: function(){
			var xmlHttp = [];
			
			// Check if path to library is correct, do that 2 secs. after this to not disturb initial processing
			window.setTimeout(function(){
				if (window.XMLHttpRequest) {
					var xmlHttpCheck = new XMLHttpRequest();
				} else if (window.ActiveXObject) {
					var xmlHttpCheck = new ActiveXObject("Microsoft.XMLHTTP");
				}
				xmlHttpCheck.open('GET', window.polyfilter_scriptpath + 'htc/sepia.htc', true);
				xmlHttpCheck.onreadystatechange = function(){
					if(xmlHttp.readyState == 4 && xmlHttp.status != 200){
						alert('The configured path \r\rvar polyfilter_scriptpath = "' + window.polyfilter_scriptpath + '"\r\rseems wrong!\r\rConfigure the polyfill\'s correct absolute(!) script path before referencing the css-filters-polyfill.js, like so:\r\rvar polyfilter_scriptpath = "/js/css-filters-polyfill/";\r\rLeaving IE dead in the water is no option. You damn Mac user... ;)');
					}
				};
				try{
					xmlHttpCheck.send(null);
				} catch(e){}
			},2000);
			
			
			var stylesheets = document.querySelectorAll ? document.querySelectorAll('style,link[rel="stylesheet"]') : document.getElementsByTagName('*');
			
			for(var i = 0; i < stylesheets.length; i++){
				(function(i){
					switch(stylesheets[i].nodeName){
						default:
						break;
						
						case 'STYLE':
							polyfilter._stylesheets.push({
								media:		stylesheets[i].media || 'all',
								content: 	stylesheets[i].innerHTML
							});
						break;
						
						case 'LINK':
							if(stylesheets[i].rel === 'stylesheet'){
								var index = polyfilter._stylesheets.length;
							
								polyfilter._stylesheets.push({
									media:		stylesheets[i].media || 'all'
								});
								
								polyfilter._pending_stylesheets++;
								
								// Fetch external stylesheet
								var href = stylesheets[i].href;
								
								// Use localStorage as cache for stylesheets, if available
								if(!polyfilter._development_mode && window.localStorage && window.localStorage.getItem('polyfilter_' + href)){
									polyfilter._pending_stylesheets--;
									polyfilter._stylesheets[index].content = localStorage.getItem('polyfilter_' + href);
									if(polyfilter._pending_stylesheets === 0){
										polyfilter.process();
									}
								}
	
								// Always fetch stylesheets to reflect possible changes
								try{
									if(window.XMLHttpRequest) {
										var xmlHttp = new XMLHttpRequest();
									} else if(window.ActiveXObject) {
										var xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
									}
									xmlHttp.open('GET', href, true);
									xmlHttp.onreadystatechange = function(){
										if(xmlHttp.readyState === 4){
											if(xmlHttp.status === 0){
												if(window.console) console.log('Could not fetch external CSS via HTTP-Request ' + href + '. Probably because of cross origin.');
												if(!polyfilter._stylesheets[index].content){
													polyfilter._pending_stylesheets--;
													polyfilter._stylesheets[index].content = xmlHttp.responseText;
													if(polyfilter._pending_stylesheets === 0){
														polyfilter.process();
													}
												}
											} else {
												if(!polyfilter._stylesheets[index].content){
													polyfilter._pending_stylesheets--;
													polyfilter._stylesheets[index].content = xmlHttp.responseText;
													if(polyfilter._pending_stylesheets === 0){
														polyfilter.process();
													}
												}
												// Cache stylesheet in localStorage, if available
												if(!polyfilter._development_mode && window.localStorage){
													try{
														window.localStorage.setItem('polyfilter_' + href,polyfilter._stylesheets[index].content)
													}
													catch(e){
														if(window.console) console.log('Local storage quota have been exceeded. Caching of stylesheet ' + href + ' is not possible');
													}
												}
											}
										}
									};
									try{
										xmlHttp.send(null);
									} catch(e){
										if(window.console) console.log('Could not fetch external CSS via HTTP-Request ' + href + '. Are you maybe testing using the file://-protocol?');
										if(!polyfilter._stylesheets[index].content){
											polyfilter._pending_stylesheets--;
											if(polyfilter._pending_stylesheets === 0){
												polyfilter.process();
											}
										}
									}
								} catch(e){}
							}
						break;
					}
				})(i);
			}
			if(this._pending_stylesheets === 0){
				this.process();
			}
		},
	
		_processDeclarations:	function(rule){
			var newstyles = '';
			for(var k in rule.declarations){
				var declaration = rule.declarations[k];
			
				if(declaration.property === 'filter'){
					
					if(document.querySelectorAll){
						var elems = document.querySelectorAll(rule.mSelectorText);
						for(var k = 0; k < elems.length; k++){
							elems[k].style.polyfilterStore = declaration.valueText;
						}
					}
					
					var gluedvalues = declaration.valueText;
					var values = gluedvalues.split(/\)\s+/),
						properties = {
							filtersW3C:		[],
							filtersWebKit: 	[],
							filtersSVG:		[],
							filtersIE:		[],
							behaviorsIE:	[]
						};
					
					for(idx in values){
						var value = values[idx] + ')';
						
						currentproperties = polyfilter.convert(value);
		
						for(key in currentproperties){
							if(typeof properties[key] !== 'undefined'){
								properties[key] = properties[key].concat(currentproperties[key]);
							}
						}
					}
					
					newstyles += rule.mSelectorText + '{';
					if(properties['filtersW3C'].length > 0){
						var filter = 
						webkitFilter = 
						mozFilter = 
						oFilter = 
						msFilter = 
						properties['filtersW3C'].join(' ');
		
						if(properties['filtersWebKit'] && properties['filtersWebKit'].length > 0){
							webkitFilter = properties['filtersWebKit'].join(' ');
						}

						if(typeof this._ie === 'undefined'){
							newstyles += '-ms-filter:' + msFilter + ';';
						}
						
						newstyles += '-webkit-filter:' + webkitFilter + ';';
						newstyles += '-moz-filter:' + mozFilter + ';';
						newstyles += '-o-filter:' + oFilter + ';';
					}
					if(properties['filtersSVG'].length > 0){
						if(properties['filtersSVG'][0] != 'none'){
							var id = gluedvalues.replace(/[^a-z0-9]/g,'');

							if(typeof this._svg_cache[id] === 'undefined'){
								this._svg_cache[id] = this._create_svg(id,properties['filtersSVG']);

								if(typeof XMLSerializer === 'undefined'){
									document.body.appendChild(this._svg_cache[id]);
								}
								else {
									var s = new XMLSerializer();
									var svgString = s.serializeToString(this._svg_cache[id]);
									if(svgString.search('SourceGraphic') != -1){
										document.body.appendChild(this._svg_cache[id]);
									}
								}
							}
		
							if(typeof XMLSerializer === 'undefined'){
								newstyles += 'filter: url(#' + id + ')';
							}
							else {
								var s = new XMLSerializer();
								var svgString = s.serializeToString(this._svg_cache[id]);
								
								if(svgString.search('SourceGraphic') != -1){
									newstyles += 'filter: url(#' + id + ')';
								}
								else {
									newstyles += 'filter: url(\'data:image/svg+xml;utf8,' + svgString + '#' + id + '\')';
								}
							}
						}
						else {
							newstyles += 'filter: none;';
						}
					}
					if(typeof this._ie !== 'undefined'){
						if(properties['filtersIE'].length > 0){
							var filtersIE = properties['filtersIE'].join(' ');
							
							newstyles += 'filter:' + filtersIE + ';';
						}
						if(properties['behaviorsIE'].length > 0){
							var behaviorsIE = properties['behaviorsIE'].join(' ');
							
							newstyles += 'behavior:' + behaviorsIE + ';';
						}
					}
					newstyles += '}\r\n';
				}
			}
			return newstyles;
		},
		
		// Absolute path to the .htc-files
		scriptpath:		
			window.polyfilter_scriptpath ? window.polyfilter_scriptpath : (function(){
				alert('Please configure the polyfill\'s absolute(!) script path before referencing the css-filters-polyfill.js, like so:\r\nvar polyfilter_scriptpath = "/js/css-filters-polyfill/";');
				return './'
			})(),
		
		// process stylesheets
		process:		function(){
			var parser = new CSSParser();
	
			for(var i = 0; i < this._stylesheets.length; i++){
				var newstyles = '';
				var sheet = parser.parse(this._stylesheets[i].content, false, true);
				if(sheet !== null) for(var j in sheet.cssRules){
					var rule = sheet.cssRules[j];
					
					switch(rule.type){
						default:
						break;
						
						case 1:
							newstyles += this._processDeclarations(rule);
						break;
						
						case 4:
							newstyles += '@media ' + rule.media.join(',') + '{';
							for(var k in rule.cssRules){
								var mediarule = rule.cssRules[k];
								
								newstyles += this._processDeclarations(mediarule);
							}
							newstyles += '}';
						break;
					}
				}
				var newstylesheet = document.createElement('style');
				newstylesheet.setAttribute('media',this._stylesheets[i].media);
				
				if(typeof polyfilter._ie === 'undefined'){
					newstylesheet.innerHTML = newstyles;
					document.getElementsByTagName('head')[0].appendChild(newstylesheet);
				}
				else {
					document.getElementsByTagName('head')[0].appendChild(newstylesheet);
					newstylesheet.styleSheet.cssText = newstyles;
				}
			}
		},
		
		init:				function(){
			if(Object.defineProperty){
				Object.defineProperty(CSSStyleDeclaration.prototype, 'polyfilter', {
					get:	function(){
						return this.polyfilterStore;
					},
					set:	function(gluedvalues){
						values = gluedvalues.split(/\)\s+/);
						var properties = {
							filtersW3C:		[],
							filtersWebKit: 	[],
							filtersSVG:		[],
							filtersIE:		[],
							behaviorsIE:	[]
						}
				
						for(idx in values){
							var value = values[idx] + ')';
							
							currentproperties = polyfilter.convert(value);
							
							for(key in currentproperties){
								if(typeof properties[key] !== 'undefined'){
									properties[key] = properties[key].concat(currentproperties[key]);
								}
							}
						}
			
						if(properties['filtersW3C'].length > 0){
							if(typeof polyfilter._ie === 'undefined'){
								this.msFilter = 
									properties['filtersW3C'].join(' ');
							}
							
							this.webkitFilter = 
							this.mozFilter = 
							this.oFilter = 
								properties['filtersW3C'].join(' ');
						}
						if(properties['filtersWebKit'].length > 0){
							this.webkitFilter = properties['filtersWebKit'].join(' ');
						}
						if(properties['filtersSVG'].length > 0){
							if(properties['filtersSVG'][0] != 'none'){
								var id = gluedvalues.replace(/[^a-z0-9]/g,'');
					
								if(typeof polyfilter._svg_cache[id] === 'undefined'){
									polyfilter._svg_cache[id] = polyfilter._create_svg(id,properties['filtersSVG']);

									if(typeof XMLSerializer === 'undefined'){
										document.body.appendChild(polyfilter._svg_cache[id]);
									}
									else {
										var s = new XMLSerializer();
										var svgString = s.serializeToString(polyfilter._svg_cache[id]);
										if(svgString.search('SourceGraphic') != -1){
											document.body.appendChild(polyfilter._svg_cache[id]);
										}
									}
								}
			
								if(typeof XMLSerializer === 'undefined'){
									this.filter = 'url(#' + id + ')';
								}
								else {
									var s = new XMLSerializer();
									var svgString = s.serializeToString(polyfilter._svg_cache[id]);
									if(svgString.search('SourceGraphic') != -1){
										this.filter = 'url(#' + id + ')';
									}
									else {
										this.filter = 'url(\'data:image/svg+xml;utf8,' + svgString + '#' + id + '\')';
									}
								}
							}
							else {
								this.filter = 'none';
							}
						}
						if(typeof polyfilter._ie !== 'undefined'){
							if(properties['filtersIE'].length > 0){
								this.filter = 
									properties['filtersIE'].join(' ');
							}
							else {
								this.filter = '';
							}
							if(properties['behaviorsIE'].length > 0){
								this.behavior = 
									properties['behaviorsIE'].join(' ');
							}
							else {
								this.behavior = '';
							}
						}
						this.polyfilterStore = gluedvalues;
					}
				});
			}
		},
		
		convert:			function(value){
			// None
			var fmatch = value.match(/none/i);
			if(fmatch !== null){
				var properties = this.filters.none();
			}
			// Grayscale
			var fmatch = value.match(/(grayscale)\(([0-9\.]+)\)/i);
			if(fmatch !== null){
				var amount = parseFloat(fmatch[2],10),
					properties = this.filters.grayscale(amount);
			}
			// Sepia
			var fmatch = value.match(/(sepia)\(([0-9\.]+)\)/i);
			if(fmatch !== null){
				var amount = parseFloat(fmatch[2],10),
					properties = this.filters.sepia(amount);
			}
			// Blur
			var fmatch = value.match(/(blur)\(([0-9]+)[px]*\)/i);
			if(fmatch !== null){
				var amount = parseInt(fmatch[2],10),
					properties = this.filters.blur(amount);
			}
			// Invert
			var fmatch = value.match(/(invert)\(([0-9\.]+)\)/i);
			if(fmatch !== null){
				var amount = parseFloat(fmatch[2],10),
					properties = this.filters.invert(amount);
			}
			// Brightness
			var fmatch = value.match(/(brightness)\(([0-9\.]+)%\)/i);
			if(fmatch !== null){
				var amount = parseFloat(fmatch[2],10),
					properties = this.filters.brightness(amount);
			}
			// Drop Shadow
			var fmatch = value.match(/(drop\-shadow)\(([0-9]+)[px]*\s+([0-9]+)[px]*\s+([0-9]+)[px]*\s+([#0-9]+)\)/i);
			if(fmatch !== null){
				var offsetX = parseInt(fmatch[2],10),
					offsetY = parseInt(fmatch[3],10),
					radius = parseInt(fmatch[4],10),
					color = fmatch[5],
					properties = this.filters.dropShadow(offsetX,offsetY,radius,color);
			}
			
			return properties;
		},
		
		// EFFECTS SECTION -------------------------------------------------------------------------------------------------------------
		
		filters: 		{
			// None
			none:			function(){
				var properties = {};
				
				if(typeof polyfilter._ie === 'undefined'){
					// Proposed spec
					properties['filtersW3C'] = ['none'];
					
					// Firefox
					properties['filtersSVG'] = ['none'];
				}
				else {
					// IE
					properties['filtersIE'] = ['none'];
				}
				
				return properties;
			},
			
			// Grayscale
			grayscale:			function(amount){
				amount = amount || 0;
				
				var properties = {};
				
				if(typeof polyfilter._ie === 'undefined'){
					// Proposed spec
					properties['filtersW3C'] = ['grayscale(' + amount + ')'];
					
					// Firefox
					// https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
					var svg_fe1 = polyfilter._create_svg_element('feColorMatrix',{
						type:	'matrix',
						values:	(0.2126 + 0.7874 * (1 - amount)) + ' ' 
							+ (0.7152 - 0.7152 * (1 - amount)) + ' ' 
							+ (0.0722 - 0.0722 * (1 - amount)) + ' 0 0 ' 
							+ (0.2126 - 0.2126 * (1 - amount)) + ' ' 
							+ (0.7152 + 0.2848 * (1 - amount)) + ' ' 
							+ (0.0722 - 0.0722 * (1 - amount)) + ' 0 0 ' 
							+ (0.2126 - 0.2126 * (1 - amount)) + ' ' 
							+ (0.7152 - 0.7152 * (1 - amount)) + ' ' 
							+ (0.0722 + 0.9278 * (1 - amount)) + ' 0 0 0 0 0 1 0'
					});
					properties['filtersSVG'] = [svg_fe1];
				}
				else {
					// IE
					properties['filtersIE'] = amount >= 0.5 ? ['gray'] : [];
				}
				
				return properties;
			},
			
			// Sepia
			sepia:			function(amount){
				amount = amount || 0;
		
				var properties = {};
		
				if(typeof polyfilter._ie === 'undefined'){
				
					// Proposed spec
					properties['filtersW3C'] = ['sepia(' + amount + ')'];
					
					// Firefox
					// https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
					var svg_fe1 = polyfilter._create_svg_element('feColorMatrix',{
						type:	'matrix',
						values:	(0.393 + 0.607 * (1 - amount)) + ' ' 
							+ (0.769 - 0.769 * (1 - amount)) + ' ' 
							+ (0.189 - 0.189 * (1 - amount)) + ' 0 0 ' 
							+ (0.349 - 0.349 * (1 - amount)) + ' ' 
							+ (0.686 + 0.314 * (1 - amount)) + ' ' 
							+ (0.168 - 0.168 * (1 - amount)) + ' 0 0 '
							+ (0.272 - 0.272 * (1 - amount)) + ' ' 
							+ (0.534 - 0.534 * (1 - amount)) + ' ' 
							+ (0.131 + 0.869 * (1 - amount)) + ' 0 0 0 0 0 1 0'
					});
					properties['filtersSVG'] = [svg_fe1];
				}
				else {
					// IE
					properties['filtersIE'] = amount >= 0.5 ? ['gray','progid:DXImageTransform.Microsoft.Light()'] : [];
					properties['behaviorsIE'] = amount >= 0.5 ? ['url("' + polyfilter.scriptpath + 'htc/sepia.htc")'] : [];
				}
				
				return properties;
			},
			
			// Blur
			blur:			function(amount){
				amount = Math.round(amount) || 0;
				
				var properties = {};
				
				if(typeof polyfilter._ie === 'undefined'){
					// Proposed spec
					properties['filtersW3C'] = ['blur(' + amount + 'px)'];
					
					// Firefox
					// https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
					var svg_fe1 = polyfilter._create_svg_element('feGaussianBlur',{
						'in':			'SourceGraphic',
						stdDeviation: amount
					});
					properties['filtersSVG'] = [svg_fe1];
				}
				else {
					// IE
					properties['filtersIE'] = ['progid:DXImageTransform.Microsoft.Blur(pixelradius=' + amount + ')'];
				}
				
				return properties;
			},
			
			// Invert
			invert:			function(amount){
				amount = amount || 0;
				
				var properties = {};
				
				if(typeof polyfilter._ie === 'undefined'){
					// Proposed spec
					properties['filtersW3C'] = ['invert(' + amount + ')'];
					
					// Firefox
					// https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
					var svg_fe1 = polyfilter._create_svg_element('feComponentTransfer',{});
					var svg_fe1sub = polyfilter._create_svg_element('feFuncR',{
						type:	'table',
						tableValues: amount + ' ' + (1 - amount)
					});
					svg_fe1.appendChild(svg_fe1sub);
					var svg_fe1sub = polyfilter._create_svg_element('feFuncG',{
						type:	'table',
						tableValues: amount + ' ' + (1 - amount)
					});
					svg_fe1.appendChild(svg_fe1sub);
					var svg_fe1sub = polyfilter._create_svg_element('feFuncB',{
						type:	'table',
						tableValues: amount + ' ' + (1 - amount)
					});
					svg_fe1.appendChild(svg_fe1sub);
					properties['filtersSVG'] = [svg_fe1];
				}
				else {
					// IE
					properties['filtersIE'] = amount >= 0.5 ? ['invert'] : [];
				}
				
				return properties;
			},
				
			// Brightness
			brightness:			function(amount){
				amount = amount || 0;
				
				var properties = {};
				
				if(typeof polyfilter._ie === 'undefined'){
					// Proposed spec
					properties['filtersW3C'] = ['brightness(' + amount + '%)'];
	
					// WebKit "specialty"
					properties['filtersWebKit'] = ['brightness(' + (amount - 100) + '%)'];
					
					// Firefox
					// https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
					var svg_fe1 = polyfilter._create_svg_element('feComponentTransfer',{});
					var svg_fe1sub = polyfilter._create_svg_element('feFuncR',{
						type:	'linear',
						slope: 	amount / 100
					});
					svg_fe1.appendChild(svg_fe1sub);
					var svg_fe1sub = polyfilter._create_svg_element('feFuncG',{
						type:	'linear',
						slope: 	amount / 100
					});
					svg_fe1.appendChild(svg_fe1sub);
					var svg_fe1sub = polyfilter._create_svg_element('feFuncB',{
						type:	'linear',
						slope: 	amount / 100 
					});
					svg_fe1.appendChild(svg_fe1sub);
					properties['filtersSVG'] = [svg_fe1];
				}
				else {
					// IE
					properties['filtersIE'] = ['progid:DXImageTransform.Microsoft.Light()'];
					properties['behaviorsIE'] = ['url("' + polyfilter.scriptpath + 'htc/brightness.htc")'];
				}
				
				return properties;
			},
				
			// Drop Shadow
			dropShadow:			function(offsetX,offsetY,radius,color){
				offsetX = Math.round(offsetX) || 0;
				offsetY = Math.round(offsetY) || 0;
				radius = Math.round(radius) || 0;
				color = color || '#000000';
				
				var properties = {};
				
				if(typeof polyfilter._ie === 'undefined'){
					// Proposed spec
					properties['filtersW3C'] = ['drop-shadow(' + offsetX + 'px ' + offsetY + 'px ' + radius + 'px ' + color + ')'];
					
					// Firefox
					// https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
					var svg_fe1 = polyfilter._create_svg_element('feGaussianBlur',{
						'in':		'SourceAlpha',
						stdDeviation: radius
					});
					var svg_fe2 = polyfilter._create_svg_element('feOffset',{
						dx:		offsetX + 1,
						dy:		offsetY + 1,
						result:	'offsetblur'
					});
					var svg_fe3 = polyfilter._create_svg_element('feFlood',{
						'flood-color': color
					});
					var svg_fe4 = polyfilter._create_svg_element('feComposite',{
						in2:	'offsetblur',
						operator: 'in'
					});
					var svg_fe5 = polyfilter._create_svg_element('feMerge',{});
					var svg_fe5sub = polyfilter._create_svg_element('feMergeNode',{});
					svg_fe5.appendChild(svg_fe5sub);
					var svg_fe5sub = polyfilter._create_svg_element('feMergeNode',{
						'in':		'SourceGraphic'
					});
					svg_fe5.appendChild(svg_fe5sub);
					properties['filtersSVG'] = [svg_fe1,svg_fe2,svg_fe3,svg_fe4,svg_fe5];
				}
				else {
					// IE
					properties['filtersIE'] = ['progid:DXImageTransform.Microsoft.Glow(color=' + color + ',strength=0)','progid:DXImageTransform.Microsoft.Shadow(color=' + color + ',strength=0)'];
					properties['behaviorsIE'] = ['url("' + polyfilter.scriptpath + 'htc/drop-shadow.htc")'];
				}
				
				return properties;
			}
		}
	}

	// Inialize, either via jQuery...
	if(window.jQuery){
		window.jQuery(document).ready(function(e) {
			polyfilter.process_stylesheets();
		});
	}
	// or via contentLoaded...
	else if(window.contentLoaded){
		contentLoaded(window,function(){
			polyfilter.process_stylesheets();
		});
	}
	// or on DOM ready / load
	else {
		if(window.addEventListener) // W3C standard
		{
			document.addEventListener('DOMContentLoaded', function(){
				polyfilter.process_stylesheets();
			}, false);
		} 
		else if(window.attachEvent) // Microsoft
		{
			window.attachEvent('onload', function(){
				polyfilter.process_stylesheets();
			});
		}
	}
	
	// Install style setters and getters
	polyfilter.init();
})(window);

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * https://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is mozilla.org code.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1998
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   emk <VYV03354@nifty.ne.jp>
 *   Daniel Glazman <glazman@netscape.com>
 *   L. David Baron <dbaron@dbaron.org>
 *   Boris Zbarsky <bzbarsky@mit.edu>
 *   Mats Palmgren <mats.palmgren@bredband.net>
 *   Christian Biesinger <cbiesinger@web.de>
 *   Jeff Walden <jwalden+code@mit.edu>
 *   Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>, Collabora Ltd.
 *   Siraj Razick <siraj.razick@collabora.co.uk>, Collabora Ltd.
 *   Daniel Glazman <daniel.glazman@disruptive-innovations.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

;
var kCHARSET_RULE_MISSING_SEMICOLON = "Missing semicolon at the end of @charset rule";
var kCHARSET_RULE_CHARSET_IS_STRING = "The charset in the @charset rule should be a string";
var kCHARSET_RULE_MISSING_WS = "Missing mandatory whitespace after @charset";
var kIMPORT_RULE_MISSING_URL = "Missing URL in @import rule";
var kURL_EOF = "Unexpected end of stylesheet";
var kURL_WS_INSIDE = "Multiple tokens inside a url() notation";
var kVARIABLES_RULE_POSITION = "@variables rule invalid at this position in the stylesheet";
var kIMPORT_RULE_POSITION = "@import rule invalid at this position in the stylesheet";
var kNAMESPACE_RULE_POSITION = "@namespace rule invalid at this position in the stylesheet";
var kCHARSET_RULE_CHARSET_SOF = "@charset rule invalid at this position in the stylesheet";
var kUNKNOWN_AT_RULE = "Unknow @-rule";

/* FROM http://peter.sh/data/vendor-prefixed-css.php?js=1 */

var kENGINES = [
  "webkit",
  "presto",
  "trident",
  "generic"
];

var kCSS_VENDOR_VALUES = {
  "-moz-box":             {"webkit": "-webkit-box",        "presto": "", "trident": "", "generic": "box" },
  "-moz-inline-box":      {"webkit": "-webkit-inline-box", "presto": "", "trident": "", "generic": "inline-box" },
  "-moz-initial":         {"webkit": "",                   "presto": "", "trident": "", "generic": "initial" },
  "-moz-linear-gradient": {"webkit20110101": FilterLinearGradientForOutput,
                           "webkit": FilterLinearGradientForOutput,
                           "presto": "",
                           "trident": "",
                           "generic": FilterLinearGradientForOutput },
  "-moz-radial-gradient": {"webkit20110101": FilterRadialGradientForOutput,
                           "webkit": FilterRadialGradientForOutput,
                           "presto": "",
                           "trident": "",
                           "generic": FilterRadialGradientForOutput },
  "-moz-repeating-linear-gradient": {"webkit20110101": "",
                           "webkit": FilterRepeatingGradientForOutput,
                           "presto": "",
                           "trident": "",
                           "generic": FilterRepeatingGradientForOutput },
  "-moz-repeating-radial-gradient": {"webkit20110101": "",
                           "webkit": FilterRepeatingGradientForOutput,
                           "presto": "",
                           "trident": "",
                           "generic": FilterRepeatingGradientForOutput }
};

var kCSS_VENDOR_PREFIXES = {"lastUpdate":1304175007,"properties":[{"gecko":"","webkit":"","presto":"","trident":"-ms-accelerator","status":"P"},
{"gecko":"","webkit":"","presto":"-wap-accesskey","trident":"","status":""},
{"gecko":"-moz-animation","webkit":"-webkit-animation","presto":"","trident":"","status":"WD"},
{"gecko":"-moz-animation-delay","webkit":"-webkit-animation-delay","presto":"","trident":"","status":"WD"},
{"gecko":"-moz-animation-direction","webkit":"-webkit-animation-direction","presto":"","trident":"","status":"WD"},
{"gecko":"-moz-animation-duration","webkit":"-webkit-animation-duration","presto":"","trident":"","status":"WD"},
{"gecko":"-moz-animation-fill-mode","webkit":"-webkit-animation-fill-mode","presto":"","trident":"","status":"ED"},
{"gecko":"-moz-animation-iteration-count","webkit":"-webkit-animation-iteration-count","presto":"","trident":"","status":"WD"},
{"gecko":"-moz-animation-name","webkit":"-webkit-animation-name","presto":"","trident":"","status":"WD"},
{"gecko":"-moz-animation-play-state","webkit":"-webkit-animation-play-state","presto":"","trident":"","status":"WD"},
{"gecko":"-moz-animation-timing-function","webkit":"-webkit-animation-timing-function","presto":"","trident":"","status":"WD"},
{"gecko":"-moz-appearance","webkit":"-webkit-appearance","presto":"","trident":"","status":"CR"},
{"gecko":"","webkit":"-webkit-backface-visibility","presto":"","trident":"","status":"WD"},
{"gecko":"background-clip","webkit":"-webkit-background-clip","presto":"background-clip","trident":"background-clip","status":"WD"},
{"gecko":"","webkit":"-webkit-background-composite","presto":"","trident":"","status":""},
{"gecko":"-moz-background-inline-policy","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"background-origin","webkit":"-webkit-background-origin","presto":"background-origin","trident":"background-origin","status":"WD"},
{"gecko":"","webkit":"background-position-x","presto":"","trident":"-ms-background-position-x","status":""},
{"gecko":"","webkit":"background-position-y","presto":"","trident":"-ms-background-position-y","status":""},
{"gecko":"background-size","webkit":"-webkit-background-size","presto":"background-size","trident":"background-size","status":"WD"},
{"gecko":"","webkit":"","presto":"","trident":"-ms-behavior","status":""},
{"gecko":"-moz-binding","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"","webkit":"","presto":"","trident":"-ms-block-progression","status":""},
{"gecko":"","webkit":"-webkit-border-after","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-border-after-color","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-border-after-style","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-border-after-width","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-border-before","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-border-before-color","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-border-before-style","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-border-before-width","presto":"","trident":"","status":"ED"},
{"gecko":"-moz-border-bottom-colors","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"border-bottom-left-radius","webkit":"-webkit-border-bottom-left-radius","presto":"border-bottom-left-radius","trident":"border-bottom-left-radius","status":"WD"},
{"gecko":"","webkit":"-webkit-border-bottom-left-radius = border-bottom-left-radius","presto":"","trident":"","status":""},
{"gecko":"border-bottom-right-radius","webkit":"-webkit-border-bottom-right-radius","presto":"border-bottom-right-radius","trident":"border-bottom-right-radius","status":"WD"},
{"gecko":"","webkit":"-webkit-border-bottom-right-radius = border-bottom-right-radius","presto":"","trident":"","status":""},
{"gecko":"-moz-border-end","webkit":"-webkit-border-end","presto":"","trident":"","status":"ED"},
{"gecko":"-moz-border-end-color","webkit":"-webkit-border-end-color","presto":"","trident":"","status":"ED"},
{"gecko":"-moz-border-end-style","webkit":"-webkit-border-end-style","presto":"","trident":"","status":"ED"},
{"gecko":"-moz-border-end-width","webkit":"-webkit-border-end-width","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-border-fit","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-border-horizontal-spacing","presto":"","trident":"","status":""},
{"gecko":"-moz-border-image","webkit":"-webkit-border-image","presto":"-o-border-image","trident":"","status":"WD"},
{"gecko":"-moz-border-left-colors","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"border-radius","webkit":"-webkit-border-radius","presto":"border-radius","trident":"border-radius","status":"WD"},
{"gecko":"-moz-border-right-colors","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"-moz-border-start","webkit":"-webkit-border-start","presto":"","trident":"","status":"ED"},
{"gecko":"-moz-border-start-color","webkit":"-webkit-border-start-color","presto":"","trident":"","status":"ED"},
{"gecko":"-moz-border-start-style","webkit":"-webkit-border-start-style","presto":"","trident":"","status":"ED"},
{"gecko":"-moz-border-start-width","webkit":"-webkit-border-start-width","presto":"","trident":"","status":"ED"},
{"gecko":"-moz-border-top-colors","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"border-top-left-radius","webkit":"-webkit-border-top-left-radius","presto":"border-top-left-radius","trident":"border-top-left-radius","status":"WD"},
{"gecko":"","webkit":"-webkit-border-top-left-radius = border-top-left-radius","presto":"","trident":"","status":""},
{"gecko":"border-top-right-radius","webkit":"-webkit-border-top-right-radius","presto":"border-top-right-radius","trident":"border-top-right-radius","status":"WD"},
{"gecko":"","webkit":"-webkit-border-top-right-radius = border-top-right-radius","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-border-vertical-spacing","presto":"","trident":"","status":""},
{"gecko":"-moz-box-align","webkit":"-webkit-box-align","presto":"","trident":"-ms-box-align","status":"WD"},
{"gecko":"-moz-box-direction","webkit":"-webkit-box-direction","presto":"","trident":"-ms-box-direction","status":"WD"},
{"gecko":"-moz-box-flex","webkit":"-webkit-box-flex","presto":"","trident":"-ms-box-flex","status":"WD"},
{"gecko":"","webkit":"-webkit-box-flex-group","presto":"","trident":"","status":"WD"},
{"gecko":"","webkit":"","presto":"","trident":"-ms-box-line-progression","status":""},
{"gecko":"","webkit":"-webkit-box-lines","presto":"","trident":"-ms-box-lines","status":"WD"},
{"gecko":"-moz-box-ordinal-group","webkit":"-webkit-box-ordinal-group","presto":"","trident":"-ms-box-ordinal-group","status":"WD"},
{"gecko":"-moz-box-orient","webkit":"-webkit-box-orient","presto":"","trident":"-ms-box-orient","status":"WD"},
{"gecko":"-moz-box-pack","webkit":"-webkit-box-pack","presto":"","trident":"-ms-box-pack","status":"WD"},
{"gecko":"","webkit":"-webkit-box-reflect","presto":"","trident":"","status":""},
{"gecko":"box-shadow","webkit":"-webkit-box-shadow","presto":"box-shadow","trident":"box-shadow","status":"WD"},
{"gecko":"-moz-box-sizing","webkit":"box-sizing","presto":"box-sizing","trident":"","status":"CR"},
{"gecko":"","webkit":"-webkit-box-sizing = box-sizing","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-epub-caption-side = caption-side","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-color-correction","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-column-break-after","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-column-break-before","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-column-break-inside","presto":"","trident":"","status":""},
{"gecko":"-moz-column-count","webkit":"-webkit-column-count","presto":"column-count","trident":"column-count","status":"CR"},
{"gecko":"-moz-column-gap","webkit":"-webkit-column-gap","presto":"column-gap","trident":"column-gap","status":"CR"},
{"gecko":"-moz-column-rule","webkit":"-webkit-column-rule","presto":"column-rule","trident":"column-rule","status":"CR"},
{"gecko":"-moz-column-rule-color","webkit":"-webkit-column-rule-color","presto":"column-rule-color","trident":"column-rule-color","status":"CR"},
{"gecko":"-moz-column-rule-style","webkit":"-webkit-column-rule-style","presto":"column-rule-style","trident":"column-rule-style","status":"CR"},
{"gecko":"-moz-column-rule-width","webkit":"-webkit-column-rule-width","presto":"column-rule-width","trident":"column-rule-width","status":"CR"},
{"gecko":"","webkit":"-webkit-column-span","presto":"column-span","trident":"column-span","status":"CR"},
{"gecko":"-moz-column-width","webkit":"-webkit-column-width","presto":"column-width","trident":"column-width","status":"CR"},
{"gecko":"","webkit":"-webkit-columns","presto":"columns","trident":"columns","status":"CR"},
{"gecko":"","webkit":"-webkit-dashboard-region","presto":"-apple-dashboard-region","trident":"","status":""},
{"gecko":"filter","webkit":"","presto":"filter","trident":"-ms-filter","status":""},
{"gecko":"-moz-float-edge","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"","webkit":"","presto":"-o-focus-opacity","trident":"","status":""},
{"gecko":"-moz-font-feature-settings","webkit":"","presto":"","trident":"","status":""},
{"gecko":"-moz-font-language-override","webkit":"","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-font-size-delta","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-font-smoothing","presto":"","trident":"","status":""},
{"gecko":"-moz-force-broken-image-icon","webkit":"","presto":"","trident":"","status":""},
{"gecko":"","webkit":"","presto":"","trident":"-ms-grid-column","status":"WD"},
{"gecko":"","webkit":"","presto":"","trident":"-ms-grid-column-align","status":"WD"},
{"gecko":"","webkit":"","presto":"","trident":"-ms-grid-column-span","status":"WD"},
{"gecko":"","webkit":"","presto":"","trident":"-ms-grid-columns","status":"WD"},
{"gecko":"","webkit":"","presto":"","trident":"-ms-grid-layer","status":"WD"},
{"gecko":"","webkit":"","presto":"","trident":"-ms-grid-row","status":"WD"},
{"gecko":"","webkit":"","presto":"","trident":"-ms-grid-row-align","status":"WD"},
{"gecko":"","webkit":"","presto":"","trident":"-ms-grid-row-span","status":"WD"},
{"gecko":"","webkit":"","presto":"","trident":"-ms-grid-rows","status":"WD"},
{"gecko":"","webkit":"-webkit-highlight","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-hyphenate-character","presto":"","trident":"","status":"WD"},
{"gecko":"","webkit":"-webkit-hyphenate-limit-after","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-hyphenate-limit-before","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-hyphens","presto":"","trident":"","status":"WD"},
{"gecko":"","webkit":"-epub-hyphens = -webkit-hyphens","presto":"","trident":"","status":""},
{"gecko":"-moz-image-region","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"ime-mode","webkit":"","presto":"","trident":"-ms-ime-mode","status":""},
{"gecko":"","webkit":"","presto":"-wap-input-format","trident":"","status":""},
{"gecko":"","webkit":"","presto":"-wap-input-required","trident":"","status":""},
{"gecko":"","webkit":"","presto":"","trident":"-ms-interpolation-mode","status":""},
{"gecko":"","webkit":"","presto":"-xv-interpret-as","trident":"","status":""},
{"gecko":"","webkit":"","presto":"","trident":"-ms-layout-flow","status":""},
{"gecko":"","webkit":"","presto":"","trident":"-ms-layout-grid","status":""},
{"gecko":"","webkit":"","presto":"","trident":"-ms-layout-grid-char","status":""},
{"gecko":"","webkit":"","presto":"","trident":"-ms-layout-grid-line","status":""},
{"gecko":"","webkit":"","presto":"","trident":"-ms-layout-grid-mode","status":""},
{"gecko":"","webkit":"","presto":"","trident":"-ms-layout-grid-type","status":""},
{"gecko":"","webkit":"-webkit-line-box-contain","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-line-break","presto":"","trident":"-ms-line-break","status":""},
{"gecko":"","webkit":"-webkit-line-clamp","presto":"","trident":"","status":""},
{"gecko":"","webkit":"","presto":"","trident":"-ms-line-grid-mode","status":""},
{"gecko":"","webkit":"","presto":"-o-link","trident":"","status":""},
{"gecko":"","webkit":"","presto":"-o-link-source","trident":"","status":""},
{"gecko":"","webkit":"-webkit-locale","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-logical-height","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-logical-width","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-margin-after","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-margin-after-collapse","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-margin-before","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-margin-before-collapse","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-margin-bottom-collapse","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-margin-collapse","presto":"","trident":"","status":""},
{"gecko":"-moz-margin-end","webkit":"-webkit-margin-end","presto":"","trident":"","status":"ED"},
{"gecko":"-moz-margin-start","webkit":"-webkit-margin-start","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-margin-top-collapse","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-marquee","presto":"","trident":"","status":""},
{"gecko":"","webkit":"","presto":"-wap-marquee-dir","trident":"","status":""},
{"gecko":"","webkit":"-webkit-marquee-direction","presto":"","trident":"","status":"WD"},
{"gecko":"","webkit":"-webkit-marquee-increment","presto":"","trident":"","status":""},
{"gecko":"","webkit":"","presto":"-wap-marquee-loop","trident":"","status":"WD"},
{"gecko":"","webkit":"-webkit-marquee-repetition","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-marquee-speed","presto":"-wap-marquee-speed","trident":"","status":"WD"},
{"gecko":"","webkit":"-webkit-marquee-style","presto":"-wap-marquee-style","trident":"","status":"WD"},
{"gecko":"mask","webkit":"-webkit-mask","presto":"mask","trident":"","status":""},
{"gecko":"","webkit":"-webkit-mask-attachment","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-mask-box-image","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-mask-clip","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-mask-composite","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-mask-image","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-mask-origin","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-mask-position","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-mask-position-x","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-mask-position-y","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-mask-repeat","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-mask-repeat-x","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-mask-repeat-y","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-mask-size","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-match-nearest-mail-blockquote-color","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-max-logical-height","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-max-logical-width","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-min-logical-height","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-min-logical-width","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"","presto":"-o-mini-fold","trident":"","status":""},
{"gecko":"","webkit":"-webkit-nbsp-mode","presto":"","trident":"","status":"P"},
{"gecko":"","webkit":"","presto":"-o-object-fit","trident":"","status":"ED"},
{"gecko":"","webkit":"","presto":"-o-object-position","trident":"","status":"ED"},
{"gecko":"opacity","webkit":"-webkit-opacity","presto":"opacity","trident":"opacity","status":"WD"},
{"gecko":"","webkit":"-webkit-opacity = opacity","presto":"","trident":"","status":""},
{"gecko":"-moz-outline-radius","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"-moz-outline-radius-bottomleft","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"-moz-outline-radius-bottomright","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"-moz-outline-radius-topleft","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"-moz-outline-radius-topright","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"overflow-x","webkit":"overflow-x","presto":"overflow-x","trident":"-ms-overflow-x","status":"WD"},
{"gecko":"overflow-y","webkit":"overflow-y","presto":"overflow-y","trident":"-ms-overflow-y","status":"WD"},
{"gecko":"","webkit":"-webkit-padding-after","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-padding-before","presto":"","trident":"","status":"ED"},
{"gecko":"-moz-padding-end","webkit":"-webkit-padding-end","presto":"","trident":"","status":"ED"},
{"gecko":"-moz-padding-start","webkit":"-webkit-padding-start","presto":"","trident":"","status":"ED"},
{"gecko":"","webkit":"-webkit-perspective","presto":"","trident":"","status":"WD"},
{"gecko":"","webkit":"-webkit-perspective-origin","presto":"","trident":"","status":"WD"},
{"gecko":"","webkit":"-webkit-perspective-origin-x","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-perspective-origin-y","presto":"","trident":"","status":""},
{"gecko":"","webkit":"","presto":"-xv-phonemes","trident":"","status":""},
{"gecko":"","webkit":"-webkit-rtl-ordering","presto":"","trident":"","status":"P"},
{"gecko":"-moz-script-level","webkit":"","presto":"","trident":"","status":""},
{"gecko":"-moz-script-min-size","webkit":"","presto":"","trident":"","status":""},
{"gecko":"-moz-script-size-multiplier","webkit":"","presto":"","trident":"","status":""},
{"gecko":"","webkit":"","presto":"scrollbar-3dlight-color","trident":"-ms-scrollbar-3dlight-color","status":"P"},
{"gecko":"","webkit":"","presto":"scrollbar-arrow-color","trident":"-ms-scrollbar-arrow-color","status":"P"},
{"gecko":"","webkit":"","presto":"scrollbar-base-color","trident":"-ms-scrollbar-base-color","status":"P"},
{"gecko":"","webkit":"","presto":"scrollbar-darkshadow-color","trident":"-ms-scrollbar-darkshadow-color","status":"P"},
{"gecko":"","webkit":"","presto":"scrollbar-face-color","trident":"-ms-scrollbar-face-color","status":"P"},
{"gecko":"","webkit":"","presto":"scrollbar-highlight-color","trident":"-ms-scrollbar-highlight-color","status":"P"},
{"gecko":"","webkit":"","presto":"scrollbar-shadow-color","trident":"-ms-scrollbar-shadow-color","status":"P"},
{"gecko":"","webkit":"","presto":"scrollbar-track-color","trident":"-ms-scrollbar-track-color","status":"P"},
{"gecko":"-moz-stack-sizing","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"","webkit":"-webkit-svg-shadow","presto":"","trident":"","status":""},
{"gecko":"-moz-tab-size","webkit":"","presto":"-o-tab-size","trident":"","status":""},
{"gecko":"","webkit":"","presto":"-o-table-baseline","trident":"","status":""},
{"gecko":"","webkit":"-webkit-tap-highlight-color","presto":"","trident":"","status":"P"},
{"gecko":"","webkit":"","presto":"","trident":"-ms-text-align-last","status":"WD"},
{"gecko":"","webkit":"","presto":"","trident":"-ms-text-autospace","status":"WD"},
{"gecko":"-moz-text-blink","webkit":"","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-text-combine","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-epub-text-combine = -webkit-text-combine","presto":"","trident":"","status":""},
{"gecko":"-moz-text-decoration-color","webkit":"","presto":"","trident":"","status":""},
{"gecko":"-moz-text-decoration-line","webkit":"","presto":"","trident":"","status":""},
{"gecko":"-moz-text-decoration-style","webkit":"","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-text-decorations-in-effect","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-text-emphasis","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-epub-text-emphasis = -webkit-text-emphasis","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-text-emphasis-color","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-epub-text-emphasis-color = -webkit-text-emphasis-color","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-text-emphasis-position","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-text-emphasis-style","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-epub-text-emphasis-style = -webkit-text-emphasis-style","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-webkit-text-fill-color","presto":"","trident":"","status":"P"},
{"gecko":"","webkit":"","presto":"","trident":"-ms-text-justify","status":"WD"},
{"gecko":"","webkit":"","presto":"","trident":"-ms-text-kashida-space","status":"P"},
{"gecko":"","webkit":"-webkit-text-orientation","presto":"","trident":"","status":""},
{"gecko":"","webkit":"-epub-text-orientation = -webkit-text-orientation","presto":"","trident":"","status":""},
{"gecko":"","webkit":"text-overflow","presto":"text-overflow","trident":"-ms-text-overflow","status":"WD"},
{"gecko":"","webkit":"-webkit-text-security","presto":"","trident":"","status":"P"},
{"gecko":"","webkit":"-webkit-text-size-adjust","presto":"","trident":"-ms-text-size-adjust","status":""},
{"gecko":"","webkit":"-webkit-text-stroke","presto":"","trident":"","status":"P"},
{"gecko":"","webkit":"-webkit-text-stroke-color","presto":"","trident":"","status":"P"},
{"gecko":"","webkit":"-webkit-text-stroke-width","presto":"","trident":"","status":"P"},
{"gecko":"","webkit":"-epub-text-transform = text-transform","presto":"","trident":"","status":""},
{"gecko":"","webkit":"","presto":"","trident":"-ms-text-underline-position","status":"P"},
{"gecko":"","webkit":"-webkit-touch-callout","presto":"","trident":"","status":"P"},
{"gecko":"-moz-transform","webkit":"-webkit-transform","presto":"-o-transform","trident":"-ms-transform","status":"WD"},
{"gecko":"-moz-transform-origin","webkit":"-webkit-transform-origin","presto":"-o-transform-origin","trident":"-ms-transform-origin","status":"WD"},
{"gecko":"","webkit":"-webkit-transform-origin-x","presto":"","trident":"","status":"P"},
{"gecko":"","webkit":"-webkit-transform-origin-y","presto":"","trident":"","status":"P"},
{"gecko":"","webkit":"-webkit-transform-origin-z","presto":"","trident":"","status":"P"},
{"gecko":"","webkit":"-webkit-transform-style","presto":"","trident":"","status":"WD"},
{"gecko":"-moz-transition","webkit":"-webkit-transition","presto":"-o-transition","trident":"","status":"WD"},
{"gecko":"-moz-transition-delay","webkit":"-webkit-transition-delay","presto":"-o-transition-delay","trident":"","status":"WD"},
{"gecko":"-moz-transition-duration","webkit":"-webkit-transition-duration","presto":"-o-transition-duration","trident":"","status":"WD"},
{"gecko":"-moz-transition-property","webkit":"-webkit-transition-property","presto":"-o-transition-property","trident":"","status":"WD"},
{"gecko":"-moz-transition-timing-function","webkit":"-webkit-transition-timing-function","presto":"-o-transition-timing-function","trident":"","status":"WD"},
{"gecko":"","webkit":"-webkit-user-drag","presto":"","trident":"","status":"P"},
{"gecko":"-moz-user-focus","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"-moz-user-input","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"-moz-user-modify","webkit":"-webkit-user-modify","presto":"","trident":"","status":"P"},
{"gecko":"-moz-user-select","webkit":"-webkit-user-select","presto":"","trident":"","status":"P"},
{"gecko":"","webkit":"","presto":"-xv-voice-balance","trident":"","status":""},
{"gecko":"","webkit":"","presto":"-xv-voice-duration","trident":"","status":""},
{"gecko":"","webkit":"","presto":"-xv-voice-pitch","trident":"","status":""},
{"gecko":"","webkit":"","presto":"-xv-voice-pitch-range","trident":"","status":""},
{"gecko":"","webkit":"","presto":"-xv-voice-rate","trident":"","status":""},
{"gecko":"","webkit":"","presto":"-xv-voice-stress","trident":"","status":""},
{"gecko":"","webkit":"","presto":"-xv-voice-volume","trident":"","status":""},
{"gecko":"-moz-window-shadow","webkit":"","presto":"","trident":"","status":"P"},
{"gecko":"","webkit":"word-break","presto":"","trident":"-ms-word-break","status":"WD"},
{"gecko":"","webkit":"-epub-word-break = word-break","presto":"","trident":"","status":""},
{"gecko":"word-wrap","webkit":"word-wrap","presto":"word-wrap","trident":"-ms-word-wrap","status":"WD"},
{"gecko":"","webkit":"-webkit-writing-mode","presto":"writing-mode","trident":"-ms-writing-mode","status":"ED"},
{"gecko":"","webkit":"-epub-writing-mode = -webkit-writing-mode","presto":"","trident":"","status":""},
{"gecko":"","webkit":"zoom","presto":"","trident":"-ms-zoom","status":""}]};

var kCSS_PREFIXED_VALUE = [
  {"gecko": "-moz-box", "webkit": "-moz-box", "presto": "", "trident": "", "generic": "box"}
];

var CssInspector = {

  mVENDOR_PREFIXES: null,

  kEXPORTS_FOR_GECKO:   true,
  kEXPORTS_FOR_WEBKIT:  true,
  kEXPORTS_FOR_PRESTO:  true,
  kEXPORTS_FOR_TRIDENT: true,

  cleanPrefixes: function()
  {
    this.mVENDOR_PREFIXES = null;
  },

  prefixesForProperty: function(aProperty)
  {
    if (!this.mVENDOR_PREFIXES) {

      this.mVENDOR_PREFIXES = {};
      for (var i = 0; i < kCSS_VENDOR_PREFIXES.properties.length; i++) {
        var p = kCSS_VENDOR_PREFIXES.properties[i];
        if (p.gecko && (p.webkit || p.presto || p.trident)) {
          var o = {};
          if (this.kEXPORTS_FOR_GECKO) o[p.gecko] = true;
          if (this.kEXPORTS_FOR_WEBKIT && p.webkit)  o[p.webkit] = true;
          if (this.kEXPORTS_FOR_PRESTO && p.presto)  o[p.presto] = true;
          if (this.kEXPORTS_FOR_TRIDENT && p.trident) o[p.trident] = true;
          this.mVENDOR_PREFIXES[p.gecko] = [];
          for (var j in o)
            this.mVENDOR_PREFIXES[p.gecko].push(j)
        }
      }
    }
    if (aProperty in this.mVENDOR_PREFIXES)
      return this.mVENDOR_PREFIXES[aProperty].sort();
    return null;
  },

  parseColorStop: function(parser, token)
  {
    var color = parser.parseColor(token);
    var position = "";
    if (!color)
      return null;
    token = parser.getToken(true, true);
    if (token.isPercentage() ||
        token.isDimensionOfUnit("cm") ||
        token.isDimensionOfUnit("mm") ||
        token.isDimensionOfUnit("in") ||
        token.isDimensionOfUnit("pc") ||
        token.isDimensionOfUnit("px") ||
        token.isDimensionOfUnit("em") ||
        token.isDimensionOfUnit("ex") ||
        token.isDimensionOfUnit("pt")) {
      position = token.value;
      token = parser.getToken(true, true);
    }
    return { color: color, position: position }
  },

  parseGradient: function (parser, token)
  {
    var isRadial = false;
    var gradient = { isRepeating: false };
    if (token.isNotNull()) {
      if (token.isFunction("-moz-linear-gradient(") ||
          token.isFunction("-moz-radial-gradient(") ||
          token.isFunction("-moz-repeating-linear-gradient(") ||
          token.isFunction("-moz-repeating-radial-gradient(")) {
        if (token.isFunction("-moz-radial-gradient(") ||
            token.isFunction("-moz-repeating-radial-gradient(")) {
          gradient.isRadial = true;
        }
        if (token.isFunction("-moz-repeating-linear-gradient(") ||
            token.isFunction("-moz-repeating-radial-gradient(")) {
          gradient.isRepeating = true;
        }
        

        token = parser.getToken(true, true);
        var haveGradientLine = false;
        var foundHorizPosition = false;
        var haveAngle = false;

        if (token.isAngle()) {
          gradient.angle = token.value;
          haveGradientLine = true;
          haveAngle = true;
          token = parser.getToken(true, true);
        }

        if (token.isLength()
            || token.isIdent("top")
            || token.isIdent("center")
            || token.isIdent("bottom")
            || token.isIdent("left")
            || token.isIdent("right")) {
          haveGradientLine = true;
          if (token.isLength()
            || token.isIdent("left")
            || token.isIdent("right")) {
            foundHorizPosition = true;
          }
          gradient.position = token.value;
          token = parser.getToken(true, true);
        }

        if (haveGradientLine) {
          if (!haveAngle && token.isAngle()) { // we have an angle here
            gradient.angle = token.value;
            haveAngle = true;
            token = parser.getToken(true, true);
          }

          else if (token.isLength()
                  || (foundHorizPosition && (token.isIdent("top")
                                             || token.isIdent("center")
                                             || token.isIdent("bottom")))
                  || (!foundHorizPosition && (token.isLength()
                                              || token.isIdent("top")
                                              || token.isIdent("center")
                                              || token.isIdent("bottom")
                                              || token.isIdent("left")
                                              || token.isIdent("right")))) {
            gradient.position = ("position" in gradient) ? gradient.position + " ": "";
            gradient.position += token.value;
            token = parser.getToken(true, true);
          }

          if (!haveAngle && token.isAngle()) { // we have an angle here
            gradient.angle = token.value;
            haveAngle = true;
            token = parser.getToken(true, true);
          }

          // we must find a comma here
          if (!token.isSymbol(","))
            return null;
          token = parser.getToken(true, true);
        }

        // ok... Let's deal with the rest now
        if (gradient.isRadial) {
          if (token.isIdent("circle") ||
              token.isIdent("ellipse")) {
            gradient.shape = token.value;
            token = parser.getToken(true, true);
          }
          if (token.isIdent("closest-side") ||
                   token.isIdent("closest-corner") ||
                   token.isIdent("farthest-side") ||
                   token.isIdent("farthest-corner") ||
                   token.isIdent("contain") ||
                   token.isIdent("cover")) {
            gradient.size = token.value;
            token = parser.getToken(true, true);
          }
          if (!("shape" in gradient) &&
              (token.isIdent("circle") ||
               token.isIdent("ellipse"))) {
            // we can still have the second value...
            gradient.shape = token.value;
            token = parser.getToken(true, true);
          }
          if ((("shape" in gradient) || ("size" in gradient)) && !token.isSymbol(","))
            return null;
          else if (("shape" in gradient) || ("size" in gradient))
            token = parser.getToken(true, true);
        }

        // now color stops...
        var stop1 = this.parseColorStop(parser, token);
        if (!stop1)
          return null;
        token = parser.currentToken();
        if (!token.isSymbol(","))
          return null;
        token = parser.getToken(true, true);
        var stop2 = this.parseColorStop(parser, token);
        if (!stop2)
          return null;
        token = parser.currentToken();
        if (token.isSymbol(",")) {
          token = parser.getToken(true, true);
        }
        // ok we have at least two color stops
        gradient.stops = [stop1, stop2];
        while (!token.isSymbol(")")) {
          var colorstop = this.parseColorStop(parser, token);
          if (!colorstop)
            return null;
          token = parser.currentToken();
          if (!token.isSymbol(")") && !token.isSymbol(","))
            return null;
          if (token.isSymbol(","))
            token = parser.getToken(true, true);
          gradient.stops.push(colorstop);
        }
        return gradient;
      }
    }
    return null;
  },

  parseBoxShadows: function(aString)
  {
    var parser = new CSSParser();
    parser._init();
    parser.mPreserveWS       = false;
    parser.mPreserveComments = false;
    parser.mPreservedTokens = [];
    parser.mScanner.init(aString);

    var shadows = [];
    var token = parser.getToken(true, true);
    var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px", spreadRadius = "0px";
    var inset = false;
    while (token.isNotNull()) {
      if (token.isIdent("none")) {
        shadows.push( { none: true } );
        token = parser.getToken(true, true);
      }
      else {
        if (token.isIdent('inset')) {
          inset = true;
          token = parser.getToken(true, true);
        }

        if (token.isPercentage() ||
            token.isDimensionOfUnit("cm") ||
            token.isDimensionOfUnit("mm") ||
            token.isDimensionOfUnit("in") ||
            token.isDimensionOfUnit("pc") ||
            token.isDimensionOfUnit("px") ||
            token.isDimensionOfUnit("em") ||
            token.isDimensionOfUnit("ex") ||
            token.isDimensionOfUnit("pt")) {
          var offsetX = token.value;
          token = parser.getToken(true, true);
        }
        else
          return [];

        if (!inset && token.isIdent('inset')) {
          inset = true;
          token = parser.getToken(true, true);
        }

        if (token.isPercentage() ||
            token.isDimensionOfUnit("cm") ||
            token.isDimensionOfUnit("mm") ||
            token.isDimensionOfUnit("in") ||
            token.isDimensionOfUnit("pc") ||
            token.isDimensionOfUnit("px") ||
            token.isDimensionOfUnit("em") ||
            token.isDimensionOfUnit("ex") ||
            token.isDimensionOfUnit("pt")) {
          var offsetX = token.value;
          token = parser.getToken(true, true);
        }
        else
          return [];

        if (!inset && token.isIdent('inset')) {
          inset = true;
          token = parser.getToken(true, true);
        }

        if (token.isPercentage() ||
            token.isDimensionOfUnit("cm") ||
            token.isDimensionOfUnit("mm") ||
            token.isDimensionOfUnit("in") ||
            token.isDimensionOfUnit("pc") ||
            token.isDimensionOfUnit("px") ||
            token.isDimensionOfUnit("em") ||
            token.isDimensionOfUnit("ex") ||
            token.isDimensionOfUnit("pt")) {
          var blurRadius = token.value;
          token = parser.getToken(true, true);
        }

        if (!inset && token.isIdent('inset')) {
          inset = true;
          token = parser.getToken(true, true);
        }

        if (token.isPercentage() ||
            token.isDimensionOfUnit("cm") ||
            token.isDimensionOfUnit("mm") ||
            token.isDimensionOfUnit("in") ||
            token.isDimensionOfUnit("pc") ||
            token.isDimensionOfUnit("px") ||
            token.isDimensionOfUnit("em") ||
            token.isDimensionOfUnit("ex") ||
            token.isDimensionOfUnit("pt")) {
          var spreadRadius = token.value;
          token = parser.getToken(true, true);
        }

        if (!inset && token.isIdent('inset')) {
          inset = true;
          token = parser.getToken(true, true);
        }

        if (token.isFunction("rgb(") ||
            token.isFunction("rgba(") ||
            token.isFunction("hsl(") ||
            token.isFunction("hsla(") ||
            token.isSymbol("#") ||
            token.isIdent()) {
          var color = parser.parseColor(token);
          token = parser.getToken(true, true);
        }

        if (!inset && token.isIdent('inset')) {
          inset = true;
          token = parser.getToken(true, true);
        }

        shadows.push( { none: false,
                        color: color,
                        offsetX: offsetX, offsetY: offsetY,
                        blurRadius: blurRadius,
                        spreadRadius: spreadRadius } );

        if (token.isSymbol(",")) {
          inset = false;
          color = "";
          blurRadius = "0px";
          spreadRadius = "0px"
          offsetX = "0px";
          offsetY = "0px"; 
          token = parser.getToken(true, true);
        }
        else if (!token.isNotNull())
          return shadows;
        else
          return [];
      }
    }
    return shadows;
  },

  parseTextShadows: function(aString)
  {
    var parser = new CSSParser();
    parser._init();
    parser.mPreserveWS       = false;
    parser.mPreserveComments = false;
    parser.mPreservedTokens = [];
    parser.mScanner.init(aString);

    var shadows = [];
    var token = parser.getToken(true, true);
    var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px"; 
    while (token.isNotNull()) {
      if (token.isIdent("none")) {
        shadows.push( { none: true } );
        token = parser.getToken(true, true);
      }
      else {
        if (token.isFunction("rgb(") ||
            token.isFunction("rgba(") ||
            token.isFunction("hsl(") ||
            token.isFunction("hsla(") ||
            token.isSymbol("#") ||
            token.isIdent()) {
          var color = parser.parseColor(token);
          token = parser.getToken(true, true);
        }
        if (token.isPercentage() ||
            token.isDimensionOfUnit("cm") ||
            token.isDimensionOfUnit("mm") ||
            token.isDimensionOfUnit("in") ||
            token.isDimensionOfUnit("pc") ||
            token.isDimensionOfUnit("px") ||
            token.isDimensionOfUnit("em") ||
            token.isDimensionOfUnit("ex") ||
            token.isDimensionOfUnit("pt")) {
          var offsetX = token.value;
          token = parser.getToken(true, true);
        }
        else
          return [];
        if (token.isPercentage() ||
            token.isDimensionOfUnit("cm") ||
            token.isDimensionOfUnit("mm") ||
            token.isDimensionOfUnit("in") ||
            token.isDimensionOfUnit("pc") ||
            token.isDimensionOfUnit("px") ||
            token.isDimensionOfUnit("em") ||
            token.isDimensionOfUnit("ex") ||
            token.isDimensionOfUnit("pt")) {
          var offsetY = token.value;
          token = parser.getToken(true, true);
        }
        else
          return [];
        if (token.isPercentage() ||
            token.isDimensionOfUnit("cm") ||
            token.isDimensionOfUnit("mm") ||
            token.isDimensionOfUnit("in") ||
            token.isDimensionOfUnit("pc") ||
            token.isDimensionOfUnit("px") ||
            token.isDimensionOfUnit("em") ||
            token.isDimensionOfUnit("ex") ||
            token.isDimensionOfUnit("pt")) {
          var blurRadius = token.value;
          token = parser.getToken(true, true);
        }
        if (!color &&
            (token.isFunction("rgb(") ||
             token.isFunction("rgba(") ||
             token.isFunction("hsl(") ||
             token.isFunction("hsla(") ||
             token.isSymbol("#") ||
             token.isIdent())) {
          var color = parser.parseColor(token);
          token = parser.getToken(true, true);
        }

        shadows.push( { none: false,
                        color: color,
                        offsetX: offsetX, offsetY: offsetY,
                        blurRadius: blurRadius } );

        if (token.isSymbol(",")) {
          color = "";
          blurRadius = "0px";
          offsetX = "0px";
          offsetY = "0px"; 
          token = parser.getToken(true, true);
        }
        else if (!token.isNotNull())
          return shadows;
        else
          return [];
      }
    }
    return shadows;
  },

  parseBackgroundImages: function(aString)
  {
    var parser = new CSSParser();
    parser._init();
    parser.mPreserveWS       = false;
    parser.mPreserveComments = false;
    parser.mPreservedTokens = [];
    parser.mScanner.init(aString);

    var backgrounds = [];
    var token = parser.getToken(true, true);
    while (token.isNotNull()) {
      /*if (token.isFunction("rgb(") ||
          token.isFunction("rgba(") ||
          token.isFunction("hsl(") ||
          token.isFunction("hsla(") ||
          token.isSymbol("#") ||
          token.isIdent()) {
        var color = parser.parseColor(token);
        backgrounds.push( { type: "color", value: color });
        token = parser.getToken(true, true);
      }
      else */
      if (token.isFunction("url(")) {
        token = parser.getToken(true, true);
        var urlContent = parser.parseURL(token);
        backgrounds.push( { type: "image", value: "url(" + urlContent });
        token = parser.getToken(true, true);
      }
      else if (token.isFunction("-moz-linear-gradient(") ||
               token.isFunction("-moz-radial-gradient(") ||
               token.isFunction("-moz-repeating-linear-gradient(") ||
               token.isFunction("-moz-repeating-radial-gradient(")) {
        var gradient = this.parseGradient(parser, token);
        backgrounds.push( { type: gradient.isRadial ? "radial-gradient" : "linear-gradient", value: gradient });
        token = parser.getToken(true, true);
      }
      else
        return null;
      if (token.isSymbol(",")) {
        token = parser.getToken(true, true);
        if (!token.isNotNull())
          return null;
      }
    }
    return backgrounds;
  },

  serializeGradient: function(gradient)
  {
    var s = gradient.isRadial
              ? (gradient.isRepeating ? "-moz-repeating-radial-gradient(" : "-moz-radial-gradient(" )
              : (gradient.isRepeating ? "-moz-repeating-linear-gradient(" : "-moz-linear-gradient(" );
    if (gradient.angle || gradient.position)
      s += (gradient.angle ? gradient.angle + " ": "") +
           (gradient.position ? gradient.position : "") +
           ", ";
    if (gradient.isRadial && (gradient.shape || gradient.size))
      s += (gradient.shape ? gradient.shape : "") +
           " " +
           (gradient.size ? gradient.size : "") +
           ", ";
    for (var i = 0; i < gradient.stops.length; i++) {
      var colorstop = gradient.stops[i];
      s += colorstop.color + (colorstop.position ? " " + colorstop.position : "");
      if (i != gradient.stops.length -1)
        s += ", ";
    }
    s += ")";
    return s;
  },

  parseBorderImage: function(aString)
  {
    var parser = new CSSParser();
    parser._init();
    parser.mPreserveWS       = false;
    parser.mPreserveComments = false;
    parser.mPreservedTokens = [];
    parser.mScanner.init(aString);

    var borderImage = {url: "", offsets: [], widths: [], sizes: []};
    var token = parser.getToken(true, true);
    if (token.isFunction("url(")) {
      token = parser.getToken(true, true);
      var urlContent = parser.parseURL(token);
      if (urlContent) {
        borderImage.url = urlContent.substr(0, urlContent.length - 1).trim();
        if ((borderImage.url[0] == '"' && borderImage.url[borderImage.url.length - 1] == '"') ||
             (borderImage.url[0] == "'" && borderImage.url[borderImage.url.length - 1] == "'"))
        borderImage.url = borderImage.url.substr(1, borderImage.url.length - 2);
      }
      else
        return null;
    }
    else
      return null; 

    token = parser.getToken(true, true);
    if (token.isNumber() || token.isPercentage())
      borderImage.offsets.push(token.value);
    else
      return null;
    var i;
    for (i= 0; i < 3; i++) {
      token = parser.getToken(true, true);
      if (token.isNumber() || token.isPercentage())
        borderImage.offsets.push(token.value);
      else
        break;
    }
    if (i == 3)
      token = parser.getToken(true, true);

    if (token.isSymbol("/")) {
      token = parser.getToken(true, true);
      if (token.isDimension()
          || token.isNumber("0")
          || (token.isIdent() && token.value in parser.kBORDER_WIDTH_NAMES))
        borderImage.widths.push(token.value);
      else
        return null;

      for (var i = 0; i < 3; i++) {
        token = parser.getToken(true, true);
        if (token.isDimension()
            || token.isNumber("0")
            || (token.isIdent() && token.value in parser.kBORDER_WIDTH_NAMES))
          borderImage.widths.push(token.value);
        else
          break;
      }
      if (i == 3)
        token = parser.getToken(true, true);
    }

    for (var i = 0; i < 2; i++) {
      if (token.isIdent("stretch")
          || token.isIdent("repeat")
          || token.isIdent("round"))
        borderImage.sizes.push(token.value);
      else if (!token.isNotNull())
        return borderImage;
      else
        return null;
      token = parser.getToken(true, true);
    }
    if (!token.isNotNull())
      return borderImage;

    return null;
  },

  parseMediaQuery: function(aString)
  {
    var kCONSTRAINTS = {
      "width": true,
      "min-width": true,
      "max-width": true,
      "height": true,
      "min-height": true,
      "max-height": true,
      "device-width": true,
      "min-device-width": true,
      "max-device-width": true,
      "device-height": true,
      "min-device-height": true,
      "max-device-height": true,
      "orientation": true,
      "aspect-ratio": true,
      "min-aspect-ratio": true,
      "max-aspect-ratio": true,
      "device-aspect-ratio": true,
      "min-device-aspect-ratio": true,
      "max-device-aspect-ratio": true,
      "color": true,
      "min-color": true,
      "max-color": true,
      "color-index": true,
      "min-color-index": true,
      "max-color-index": true,
      "monochrome": true,
      "min-monochrome": true,
      "max-monochrome": true,
      "resolution": true,
      "min-resolution": true,
      "max-resolution": true,
      "scan": true,
      "grid": true
    };
    var parser = new CSSParser();
    parser._init();
    parser.mPreserveWS       = false;
    parser.mPreserveComments = false;
    parser.mPreservedTokens = [];
    parser.mScanner.init(aString);

    var m = {amplifier: "", medium: "", constraints: []};
    var token = parser.getToken(true, true);

    if (token.isIdent("all") ||
        token.isIdent("aural") ||
        token.isIdent("braille") ||
        token.isIdent("handheld") ||
        token.isIdent("print") ||
        token.isIdent("projection") ||
        token.isIdent("screen") ||
        token.isIdent("tty") ||
        token.isIdent("tv")) {
       m.medium = token.value;
       token = parser.getToken(true, true);
    }
    else if (token.isIdent("not") || token.isIdent("only")) {
      m.amplifier = token.value;
      token = parser.getToken(true, true);
      if (token.isIdent("all") ||
          token.isIdent("aural") ||
          token.isIdent("braille") ||
          token.isIdent("handheld") ||
          token.isIdent("print") ||
          token.isIdent("projection") ||
          token.isIdent("screen") ||
          token.isIdent("tty") ||
          token.isIdent("tv")) {
         m.medium = token.value;
         token = parser.getToken(true, true);
      }
      else
        return null;
    }

    if (m.medium) {
      if (!token.isNotNull())
        return m;
      if (token.isIdent("and")) {
        token = parser.getToken(true, true);
      }
      else
        return null;
    }

    while (token.isSymbol("(")) {
      token = parser.getToken(true, true);
      if (token.isIdent() && (token.value in kCONSTRAINTS)) {
        var constraint = token.value;
        token = parser.getToken(true, true);
        if (token.isSymbol(":")) {
          token = parser.getToken(true, true);
          var values = [];
          while (!token.isSymbol(")")) {
            values.push(token.value);
            token = parser.getToken(true, true);
          }
          if (token.isSymbol(")")) {
            m.constraints.push({constraint: constraint, value: values});
            token = parser.getToken(true, true);
            if (token.isNotNull()) {
              if (token.isIdent("and")) {
                token = parser.getToken(true, true);
              }
              else
                return null;
            }
            else
              return m;
          }
          else
            return null;
        }
        else if (token.isSymbol(")")) {
          m.constraints.push({constraint: constraint, value: null});
          token = parser.getToken(true, true);
          if (token.isNotNull()) {
            if (token.isIdent("and")) {
              token = parser.getToken(true, true);
            }
            else
              return null;
          }
          else
            return m;
        }
        else
          return null;
      }
      else
        return null;
    }
    return m;
  }

};


/************************************************************/
/************************** JSCSSP **************************/
/************************************************************/

var CSS_ESCAPE  = '\\';

var IS_HEX_DIGIT  = 1;
var START_IDENT   = 2;
var IS_IDENT      = 4;
var IS_WHITESPACE = 8;

var W   = IS_WHITESPACE;
var I   = IS_IDENT;
var S   =          START_IDENT;
var SI  = IS_IDENT|START_IDENT;
var XI  = IS_IDENT            |IS_HEX_DIGIT;
var XSI = IS_IDENT|START_IDENT|IS_HEX_DIGIT;

function CSSScanner(aString)
{
  this.init(aString);
}

CSSScanner.prototype = {

  kLexTable: [
  //                                     TAB LF      FF  CR
     0,  0,  0,  0,  0,  0,  0,  0,  0,  W,  W,  0,  W,  W,  0,  0,
  //
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  // SPC !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
     W,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  I,  0,  0,
  // 0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
     XI, XI, XI, XI, XI, XI, XI, XI, XI, XI, 0,  0,  0,  0,  0,  0,
  // @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
     0,  XSI,XSI,XSI,XSI,XSI,XSI,SI, SI, SI, SI, SI, SI, SI, SI, SI,
  // P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _
     SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, 0,  S,  0,  0,  SI,
  // `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
     0,  XSI,XSI,XSI,XSI,XSI,XSI,SI, SI, SI, SI, SI, SI, SI, SI, SI,
  // p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~
     SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, 0,  0,  0,  0,  0,
  //
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  //
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  //     ¡   ¢   £   ¤   ¥   ¦   §   ¨   ©   ª   «   ¬   ­   ®   ¯
     0,  SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI,
  // °   ±   ²   ³   ´   µ   ¶   ·   ¸   ¹   º   »   ¼   ½   ¾   ¿
     SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI,
  // À   Á   Â   Ã   Ä   Å   Æ   Ç   È   É   Ê   Ë   Ì   Í   Î   Ï
     SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI,
  // Ð   Ñ   Ò   Ó   Ô   Õ   Ö   ×   Ø   Ù   Ú   Û   Ü   Ý   Þ   ß
     SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI,
  // à   á   â   ã   ä   å   æ   ç   è   é   ê   ë   ì   í   î   ï
     SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI,
  // ð   ñ   ò   ó   ô   õ   ö   ÷   ø   ù   ú   û   ü   ý   þ   ÿ
     SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI
  ],

  kHexValues: {
    "0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9,
    "a": 10, "b": 11, "c": 12, "d": 13, "e": 14, "f": 15
  },

  mString : "",
  mPos : 0,
  mPreservedPos : [],

  init: function(aString) {
    this.mString = aString;
    this.mPos = 0;
    this.mPreservedPos = [];
  },

  getCurrentPos: function() {
    return this.mPos;
  },

  getAlreadyScanned: function()
  {
    return this.mString.substr(0, this.mPos);
  },

  preserveState: function() {
    this.mPreservedPos.push(this.mPos);
  },

  restoreState: function() {
    if (this.mPreservedPos.length) {
      this.mPos = this.mPreservedPos.pop();
    }
  },

  forgetState: function() {
    if (this.mPreservedPos.length) {
      this.mPreservedPos.pop();
    }
  },

  read: function() {
    if (this.mPos < this.mString.length)
      return this.mString.charAt(this.mPos++);
    return -1;
  },

  peek: function() {
    if (this.mPos < this.mString.length)
      return this.mString.charAt(this.mPos);
    return -1;
  },

  isHexDigit: function(c) {
    var code = c.charCodeAt(0);
    return (code < 256 && (this.kLexTable[code] & IS_HEX_DIGIT) != 0);
  },

  isIdentStart: function(c) {
    var code = c.charCodeAt(0);
    return (code >= 256 || (this.kLexTable[code] & START_IDENT) != 0);
  },

  startsWithIdent: function(aFirstChar, aSecondChar) {
    var code = aFirstChar.charCodeAt(0);
    return this.isIdentStart(aFirstChar) ||
           (aFirstChar == "-" && this.isIdentStart(aSecondChar));
  },

  isIdent: function(c) {
    var code = c.charCodeAt(0);
    return (code >= 256 || (this.kLexTable[code] & IS_IDENT) != 0);
  },

  isSymbol: function(c) {
    var code = c.charCodeAt(0);
    return (this.kLexTable[code] & IS_IDENT) != 1;
  },

  pushback: function() {
    this.mPos--;
  },

  nextHexValue: function() {
    var c = this.read();
    if (c == -1 || !this.isHexDigit(c))
      return new jscsspToken(jscsspToken.NULL_TYPE, null);
    var s = c;
    c = this.read();
    while (c != -1 && this.isHexDigit(c)) {
      s += c;
      c = this.read();
    }
    if (c != -1)
      this.pushback();
    return new jscsspToken(jscsspToken.HEX_TYPE, s);
  },

  gatherEscape: function() {
    var c = this.peek();
    if (c == -1)
      return "";
    if (this.isHexDigit(c)) {
      var code = 0;
      for (var i = 0; i < 6; i++) {
        c = this.read();
        if (this.isHexDigit(c))
          code = code * 16 + this.kHexValues[c.toLowerCase()];
        else if (!this.isHexDigit(c) && !this.isWhiteSpace(c)) {
          this.pushback();
          break;
        }
        else
          break;
      }
      if (i == 6) {
        c = this.peek();
        if (this.isWhiteSpace(c))
          this.read();
      }
      return String.fromCharCode(code);
    }
    c = this.read();
    if (c != "\n")
      return c;
    return "";
  },

  gatherIdent: function(c) {
    var s = "";
    if (c == CSS_ESCAPE)
      s += this.gatherEscape();
    else
      s += c;
    c = this.read();
	if(!this.mMediaQueryMode){
		while (c != -1
			   && (this.isIdent(c) || c == CSS_ESCAPE)) {
		  if (c == CSS_ESCAPE)
			s += this.gatherEscape();
		  else
			s += c;
		  c = this.read();
		}
	}
	else {
		while (c != -1
			   && c != '{' 
			   && c != ',') {
			s += c;
		  c = this.read();
		}
	}
    if (c != -1)
      this.pushback();
	  this.mMediaQueryMode = false;
    return s;
  },

  parseIdent: function(c) {
	var value = this.gatherIdent(c);
    var nextChar = this.peek();
    if (nextChar == "(") {
      value += this.read();
      return new jscsspToken(jscsspToken.FUNCTION_TYPE, value);
    }
    return new jscsspToken(jscsspToken.IDENT_TYPE, value);
  },

  isDigit: function(c) {
    return (c >= '0') && (c <= '9');
  },

  parseComment: function(c) {
    var s = c;
    while ((c = this.read()) != -1) {
      s += c;
      if (c == "*") {
        c = this.read();
        if (c == -1)
          break;
        if (c == "/") {
          s += c;
          break;
        }
        this.pushback();
      }
    }
    return new jscsspToken(jscsspToken.COMMENT_TYPE, s);
  },

  parseNumber: function(c) {
    var s = c;
    var foundDot = false;
    while ((c = this.read()) != -1) {
      if (c == ".") {
        if (foundDot)
          break;
        else {
          s += c;
          foundDot = true;
        }
      } else if (this.isDigit(c))
        s += c;
      else
        break;
    }

    if (c != -1 && this.startsWithIdent(c, this.peek())) { // DIMENSION
      var unit = this.gatherIdent(c);
      s += unit;
      return new jscsspToken(jscsspToken.DIMENSION_TYPE, s, unit);
    }
    else if (c == "%") {
      s += "%";
      return new jscsspToken(jscsspToken.PERCENTAGE_TYPE, s);
    }
    else if (c != -1)
      this.pushback();
    return new jscsspToken(jscsspToken.NUMBER_TYPE, s);
  },

  parseString: function(aStop) {
    var s = aStop;
    var previousChar = aStop;
    var c;
    while ((c = this.read()) != -1) {
      if (c == aStop && previousChar != CSS_ESCAPE) {
        s += c;
        break;
      }
      else if (c == CSS_ESCAPE) {
        c = this.peek();
        if (c == -1)
          break;
        else if (c == "\n" || c == "\r" || c == "\f") {
          d = c;
          c = this.read();
          // special for Opera that preserves \r\n...
          if (d == "\r") {
            c = this.peek();
            if (c == "\n")
              c = this.read();
          }
        }
        else {
          s += this.gatherEscape();
          c = this.peek();
        }
      }
      else if (c == "\n" || c == "\r" || c == "\f") {
        break;
      }
      else
        s += c;

      previousChar = c;
    }
    return new jscsspToken(jscsspToken.STRING_TYPE, s);
  },

  isWhiteSpace: function(c) {
    var code = c.charCodeAt(0);
    return code < 256 && (this.kLexTable[code] & IS_WHITESPACE) != 0;
  },

  eatWhiteSpace: function(c) {
    var s = c;
    while ((c = this.read()) != -1) {
      if (!this.isWhiteSpace(c))
        break;
      s += c;
    }
    if (c != -1)
      this.pushback();
    return s;
  },

  parseAtKeyword: function(c) {
    return new jscsspToken(jscsspToken.ATRULE_TYPE, this.gatherIdent(c));
  },

  nextToken: function() {
    var c = this.read();
    if (c == -1)
      return new jscsspToken(jscsspToken.NULL_TYPE, null);

    if (this.startsWithIdent(c, this.peek()))
      return this.parseIdent(c);

    if (c == '@') {
      var nextChar = this.read();
      if (nextChar != -1) {
        var followingChar = this.peek();
        this.pushback();
        if (this.startsWithIdent(nextChar, followingChar))
          return this.parseAtKeyword(c);
      }
    }

    if (c == "." || c == "+" || c == "-") {
      var nextChar = this.peek();
      if (this.isDigit(nextChar))
        return this.parseNumber(c);
      else if (nextChar == "." && c != ".") {
        firstChar = this.read();
        var secondChar = this.peek();
        this.pushback();
        if (this.isDigit(secondChar))
          return this.parseNumber(c);
      }
    }
    if (this.isDigit(c)) {
      return this.parseNumber(c);
    }

    if (c == "'" || c == '"')
      return this.parseString(c);

    if (this.isWhiteSpace(c)) {
      var s = this.eatWhiteSpace(c);
      
      return new jscsspToken(jscsspToken.WHITESPACE_TYPE, s);
    }

    if (c == "|" || c == "~" || c == "^" || c == "$" || c == "*") {
      var nextChar = this.read();
      if (nextChar == "=") {
        switch (c) {
          case "~" :
            return new jscsspToken(jscsspToken.INCLUDES_TYPE, "~=");
          case "|" :
            return new jscsspToken(jscsspToken.DASHMATCH_TYPE, "|=");
          case "^" :
            return new jscsspToken(jscsspToken.BEGINSMATCH_TYPE, "^=");
          case "$" :
            return new jscsspToken(jscsspToken.ENDSMATCH_TYPE, "$=");
          case "*" :
            return new jscsspToken(jscsspToken.CONTAINSMATCH_TYPE, "*=");
          default :
            break;
        }
      } else if (nextChar != -1)
        this.pushback();
    }

    if (c == "/" && this.peek() == "*")
      return this.parseComment(c);

    return new jscsspToken(jscsspToken.SYMBOL_TYPE, c);
  }
};

function CSSParser(aString)
{
  this.mToken = null;
  this.mLookAhead = null;
  this.mScanner = new CSSScanner(aString);

  this.mPreserveWS = true;
  this.mPreserveComments = true;

  this.mPreservedTokens = [];
  
  this.mError = null;
}

CSSParser.prototype = {

  _init:function() {
    this.mToken = null;
    this.mLookAhead = null;
    this.mMediaQueryMode = false;
  },

  kINHERIT: "inherit",

  kBORDER_WIDTH_NAMES: {
      "thin": true,
      "medium": true,
      "thick": true
  },

  kBORDER_STYLE_NAMES: {
    "none": true,
    "hidden": true,
    "dotted": true,
    "dashed": true,
    "solid": true,
    "double": true,
    "groove": true,
    "ridge": true,
    "inset": true,
    "outset": true
  },

  kCOLOR_NAMES: {
    "transparent": true,
  
    "black": true,
    "silver": true,
    "gray": true,
    "white": true,
    "maroon": true,
    "red": true,
    "purple": true,
    "fuchsia": true,
    "green": true,
    "lime": true,
    "olive": true,
    "yellow": true,
    "navy": true,
    "blue": true,
    "teal": true,
    "aqua": true,
    
    "aliceblue": true,
    "antiquewhite": true,
    "aqua": true,
    "aquamarine": true,
    "azure": true,
    "beige": true,
    "bisque": true,
    "black": true,
    "blanchedalmond": true,
    "blue": true,
    "blueviolet": true,
    "brown": true,
    "burlywood": true,
    "cadetblue": true,
    "chartreuse": true,
    "chocolate": true,
    "coral": true,
    "cornflowerblue": true,
    "cornsilk": true,
    "crimson": true,
    "cyan": true,
    "darkblue": true,
    "darkcyan": true,
    "darkgoldenrod": true,
    "darkgray": true,
    "darkgreen": true,
    "darkgrey": true,
    "darkkhaki": true,
    "darkmagenta": true,
    "darkolivegreen": true,
    "darkorange": true,
    "darkorchid": true,
    "darkred": true,
    "darksalmon": true,
    "darkseagreen": true,
    "darkslateblue": true,
    "darkslategray": true,
    "darkslategrey": true,
    "darkturquoise": true,
    "darkviolet": true,
    "deeppink": true,
    "deepskyblue": true,
    "dimgray": true,
    "dimgrey": true,
    "dodgerblue": true,
    "firebrick": true,
    "floralwhite": true,
    "forestgreen": true,
    "fuchsia": true,
    "gainsboro": true,
    "ghostwhite": true,
    "gold": true,
    "goldenrod": true,
    "gray": true,
    "green": true,
    "greenyellow": true,
    "grey": true,
    "honeydew": true,
    "hotpink": true,
    "indianred": true,
    "indigo": true,
    "ivory": true,
    "khaki": true,
    "lavender": true,
    "lavenderblush": true,
    "lawngreen": true,
    "lemonchiffon": true,
    "lightblue": true,
    "lightcoral": true,
    "lightcyan": true,
    "lightgoldenrodyellow": true,
    "lightgray": true,
    "lightgreen": true,
    "lightgrey": true,
    "lightpink": true,
    "lightsalmon": true,
    "lightseagreen": true,
    "lightskyblue": true,
    "lightslategray": true,
    "lightslategrey": true,
    "lightsteelblue": true,
    "lightyellow": true,
    "lime": true,
    "limegreen": true,
    "linen": true,
    "magenta": true,
    "maroon": true,
    "mediumaquamarine": true,
    "mediumblue": true,
    "mediumorchid": true,
    "mediumpurple": true,
    "mediumseagreen": true,
    "mediumslateblue": true,
    "mediumspringgreen": true,
    "mediumturquoise": true,
    "mediumvioletred": true,
    "midnightblue": true,
    "mintcream": true,
    "mistyrose": true,
    "moccasin": true,
    "navajowhite": true,
    "navy": true,
    "oldlace": true,
    "olive": true,
    "olivedrab": true,
    "orange": true,
    "orangered": true,
    "orchid": true,
    "palegoldenrod": true,
    "palegreen": true,
    "paleturquoise": true,
    "palevioletred": true,
    "papayawhip": true,
    "peachpuff": true,
    "peru": true,
    "pink": true,
    "plum": true,
    "powderblue": true,
    "purple": true,
    "red": true,
    "rosybrown": true,
    "royalblue": true,
    "saddlebrown": true,
    "salmon": true,
    "sandybrown": true,
    "seagreen": true,
    "seashell": true,
    "sienna": true,
    "silver": true,
    "skyblue": true,
    "slateblue": true,
    "slategray": true,
    "slategrey": true,
    "snow": true,
    "springgreen": true,
    "steelblue": true,
    "tan": true,
    "teal": true,
    "thistle": true,
    "tomato": true,
    "turquoise": true,
    "violet": true,
    "wheat": true,
    "white": true,
    "whitesmoke": true,
    "yellow": true,
    "yellowgreen": true,
  
    "activeborder": true,
    "activecaption": true,
    "appworkspace": true,
    "background": true,
    "buttonface": true,
    "buttonhighlight": true,
    "buttonshadow": true,
    "buttontext": true,
    "captiontext": true,
    "graytext": true,
    "highlight": true,
    "highlighttext": true,
    "inactiveborder": true,
    "inactivecaption": true,
    "inactivecaptiontext": true,
    "infobackground": true,
    "infotext": true,
    "menu": true,
    "menutext": true,
    "scrollbar": true,
    "threeddarkshadow": true,
    "threedface": true,
    "threedhighlight": true,
    "threedlightshadow": true,
    "threedshadow": true,
    "window": true,
    "windowframe": true,
    "windowtext": true
  },

  kLIST_STYLE_TYPE_NAMES: {
    "decimal": true,
    "decimal-leading-zero": true,
    "lower-roman": true,
    "upper-roman": true,
    "georgian": true,
    "armenian": true,
    "lower-latin": true,
    "lower-alpha": true,
    "upper-latin": true,
    "upper-alpha": true,
    "lower-greek": true,

    "disc": true,
    "circle": true,
    "square": true,
    "none": true,
    
    /* CSS 3 */
    "box": true,
    "check": true,
    "diamond": true,
    "hyphen": true,

    "lower-armenian": true,
    "cjk-ideographic": true,
    "ethiopic-numeric": true,
    "hebrew": true,
    "japanese-formal": true,
    "japanese-informal": true,
    "simp-chinese-formal": true,
    "simp-chinese-informal": true,
    "syriac": true,
    "tamil": true,
    "trad-chinese-formal": true,
    "trad-chinese-informal": true,
    "upper-armenian": true,
    "arabic-indic": true,
    "binary": true,
    "bengali": true,
    "cambodian": true,
    "khmer": true,
    "devanagari": true,
    "gujarati": true,
    "gurmukhi": true,
    "kannada": true,
    "lower-hexadecimal": true,
    "lao": true,
    "malayalam": true,
    "mongolian": true,
    "myanmar": true,
    "octal": true,
    "oriya": true,
    "persian": true,
    "urdu": true,
    "telugu": true,
    "tibetan": true,
    "upper-hexadecimal": true,
    "afar": true,
    "ethiopic-halehame-aa-et": true,
    "ethiopic-halehame-am-et": true,
    "amharic-abegede": true,
    "ehiopic-abegede-am-et": true,
    "cjk-earthly-branch": true,
    "cjk-heavenly-stem": true,
    "ethiopic": true,
    "ethiopic-abegede": true,
    "ethiopic-abegede-gez": true,
    "hangul-consonant": true,
    "hangul": true,
    "hiragana-iroha": true,
    "hiragana": true,
    "katakana-iroha": true,
    "katakana": true,
    "lower-norwegian": true,
    "oromo": true,
    "ethiopic-halehame-om-et": true,
    "sidama": true,
    "ethiopic-halehame-sid-et": true,
    "somali": true,
    "ethiopic-halehame-so-et": true,
    "tigre": true,
    "ethiopic-halehame-tig": true,
    "tigrinya-er-abegede": true,
    "ethiopic-abegede-ti-er": true,
    "tigrinya-et": true,
    "ethiopic-halehame-ti-et": true,
    "upper-greek": true,
    "asterisks": true,
    "footnotes": true,
    "circled-decimal": true,
    "circled-lower-latin": true,
    "circled-upper-latin": true,
    "dotted-decimal": true,
    "double-circled-decimal": true,
    "filled-circled-decimal": true,
    "parenthesised-decimal": true,
    "parenthesised-lower-latin": true
  },

  reportError: function(aMsg) {
    this.mError = aMsg;
  },

  consumeError: function() {
    var e = this.mError;
    this.mError = null;
    return e;
  },

  currentToken: function() {
    return this.mToken;
  },

  getHexValue: function() {
    this.mToken = this.mScanner.nextHexValue();
    return this.mToken;
  },

  getToken: function(aSkipWS, aSkipComment) {
    if (this.mLookAhead) {
      this.mToken = this.mLookAhead;
      this.mLookAhead = null;
      return this.mToken;
    }

    this.mToken = this.mScanner.nextToken();
    while (this.mToken &&
           ((aSkipWS && this.mToken.isWhiteSpace()) ||
            (aSkipComment && this.mToken.isComment())))
      this.mToken = this.mScanner.nextToken();
	return this.mToken;
  },

  lookAhead: function(aSkipWS, aSkipComment) {
    var preservedToken = this.mToken;
    this.mScanner.preserveState();
    var token = this.getToken(aSkipWS, aSkipComment);
    this.mScanner.restoreState();
    this.mToken = preservedToken;

    return token;
  },

  ungetToken: function() {
    this.mLookAhead = this.mToken;
  },

  addUnknownAtRule: function(aSheet, aString) {
    var currentLine = CountLF(this.mScanner.getAlreadyScanned());
    var blocks = [];
    var token = this.getToken(false, false);
    while (token.isNotNull()) {
      aString += token.value;
      if (token.isSymbol(";") && !blocks.length)
        break;
      else if (token.isSymbol("{")
               || token.isSymbol("(")
               || token.isSymbol("[")
               || token.type == "function") {
        blocks.push(token.isFunction() ? "(" : token.value);
      } else if (token.isSymbol("}")
                 || token.isSymbol(")")
                 || token.isSymbol("]")) {
        if (blocks.length) {
          var ontop = blocks[blocks.length - 1];
          if ((token.isSymbol("}") && ontop == "{")
              || (token.isSymbol(")") && ontop == "(")
              || (token.isSymbol("]") && ontop == "[")) {
            blocks.pop();
            if (!blocks.length && token.isSymbol("}"))
              break;
          }
        }
      }
      token = this.getToken(false, false);
    }

    this.addUnknownRule(aSheet, aString, currentLine);
  },

  addUnknownRule: function(aSheet, aString, aCurrentLine) {
    var errorMsg = this.consumeError();
    var rule = new jscsspErrorRule(errorMsg);
    rule.currentLine = aCurrentLine;
    rule.parsedCssText = aString;
    rule.parentStyleSheet = aSheet;
    aSheet.cssRules.push(rule);
  },

  addWhitespace: function(aSheet, aString) {
    var rule = new jscsspWhitespace();
    rule.parsedCssText = aString;
    rule.parentStyleSheet = aSheet;
    aSheet.cssRules.push(rule);
  },

  addComment: function(aSheet, aString) {
    var rule = new jscsspComment();
    rule.parsedCssText = aString;
    rule.parentStyleSheet = aSheet;
    aSheet.cssRules.push(rule);
  },

  parseCharsetRule: function(aToken, aSheet) {
    var s = aToken.value;
    var token = this.getToken(false, false);
    s += token.value;
    if (token.isWhiteSpace(" ")) {
      token = this.getToken(false, false);
      s += token.value;
      if (token.isString()) {
        var encoding = token.value;
        token = this.getToken(false, false);
        s += token.value;
        if (token.isSymbol(";")) {
          var rule = new jscsspCharsetRule();
          rule.encoding = encoding;
          rule.parsedCssText = s;
          rule.parentStyleSheet = aSheet;
          aSheet.cssRules.push(rule);
          return true;
        }
        else
          this.reportError(kCHARSET_RULE_MISSING_SEMICOLON);
      }
      else
        this.reportError(kCHARSET_RULE_CHARSET_IS_STRING);
    }
    else
      this.reportError(kCHARSET_RULE_MISSING_WS);

    this.addUnknownAtRule(aSheet, s);
    return false;
  },

  parseImportRule: function(aToken, aSheet) {
    var currentLine = CountLF(this.mScanner.getAlreadyScanned());
    var s = aToken.value;
    this.preserveState();
    var token = this.getToken(true, true);
    var media = [];
    var href = "";
    if (token.isString()) {
      href = token.value;
      s += " " + href;
    }
    else if (token.isFunction("url(")) {
      token = this.getToken(true, true);
      var urlContent = this.parseURL(token);
      if (urlContent) {
        href = "url(" + urlContent;
        s += " " + href;
      }
    }
    else
      this.reportError(kIMPORT_RULE_MISSING_URL);

    if (href) {
      token = this.getToken(true, true);
      while (token.isIdent()) {
        s += " " + token.value;
        media.push(token.value);
        token = this.getToken(true, true);
        if (!token)
          break;
        if (token.isSymbol(",")) {
          s += ",";
        } else if (token.isSymbol(";")) {
          break;
        } else
          break;
        token = this.getToken(true, true);
      }

      if (!media.length) {
        media.push("all");
      }
  
      if (token.isSymbol(";")) {
        s += ";"
        this.forgetState();
        var rule = new jscsspImportRule();
        rule.currentLine = currentLine;
        rule.parsedCssText = s;
        rule.href = href;
        rule.media = media;
        rule.parentStyleSheet = aSheet;
        aSheet.cssRules.push(rule);
        return true;
      }
    }

    this.restoreState();
    this.addUnknownAtRule(aSheet, "@import");
    return false;
  },

  parseVariablesRule: function(token, aSheet) {
    var currentLine = CountLF(this.mScanner.getAlreadyScanned());
    var s = token.value;
    var declarations = [];
    var valid = false;
    this.preserveState();
    token = this.getToken(true, true);
    var media = [];
    var foundMedia = false;
    while (token.isNotNull()) {
      if (token.isIdent()) {
        foundMedia = true;
        s += " " + token.value;
        media.push(token.value);
        token = this.getToken(true, true);
        if (token.isSymbol(",")) {
          s += ",";
        } else {
          if (token.isSymbol("{"))
            this.ungetToken();
          else {
            // error...
            token.type = jscsspToken.NULL_TYPE;
            break;
          }
        }
      } else if (token.isSymbol("{"))
        break;
      else if (foundMedia) {
        token.type = jscsspToken.NULL_TYPE;
        // not a media list
        break;
      }
      token = this.getToken(true, true);
    }

    if (token.isSymbol("{")) {
      s += " {";
      token = this.getToken(true, true);
      while (true) {
        if (!token.isNotNull()) {
          valid = true;
          break;
        }
        if (token.isSymbol("}")) {
          s += "}";
          valid = true;
          break;
        } else {
          var d = this.parseDeclaration(token, declarations, true, false, aSheet);
          s += ((d && declarations.length) ? " " : "") + d;
        }
        token = this.getToken(true, false);
      }
    }
    if (valid) {
      this.forgetState();
      var rule = new jscsspVariablesRule();
      rule.currentLine = currentLine;
      rule.parsedCssText = s;
      rule.declarations = declarations;
      rule.media = media;
      rule.parentStyleSheet = aSheet;
      aSheet.cssRules.push(rule)
      return true;
    }
    this.restoreState();
    return false;
  },

  parseNamespaceRule: function(aToken, aSheet) {
    var currentLine = CountLF(this.mScanner.getAlreadyScanned());
    var s = aToken.value;
    var valid = false;
    this.preserveState();
    var token = this.getToken(true, true);
    if (token.isNotNull()) {
      var prefix = "";
      var url = "";
      if (token.isIdent()) {
        prefix = token.value;
        s += " " + prefix;
        token = this.getToken(true, true);
      }
      if (token) {
        var foundURL = false;
        if (token.isString()) {
          foundURL = true;
          url = token.value;
          s += " " + url;
        } else if (token.isFunction("url(")) {
          // get a url here...
          token = this.getToken(true, true);
          var urlContent = this.parseURL(token);
          if (urlContent) {
            url += "url(" + urlContent;
            foundURL = true;
            s += " " + urlContent;
          }
        }
      }
      if (foundURL) {
        token = this.getToken(true, true);
        if (token.isSymbol(";")) {
          s += ";";
          this.forgetState();
          var rule = new jscsspNamespaceRule();
          rule.currentLine = currentLine;
          rule.parsedCssText = s;
          rule.prefix = prefix;
          rule.url = url;
          rule.parentStyleSheet = aSheet;
          aSheet.cssRules.push(rule);
          return true;
        }
      }

    }
    this.restoreState();
    this.addUnknownAtRule(aSheet, "@namespace");
    return false;
  },

  parseFontFaceRule: function(aToken, aSheet) {
    var currentLine = CountLF(this.mScanner.getAlreadyScanned());
    var s = aToken.value;
    var valid = false;
    var descriptors = [];
    this.preserveState();
    var token = this.getToken(true, true);
    if (token.isNotNull()) {
      // expecting block start
      if (token.isSymbol("{")) {
        s += " " + token.value;
        var token = this.getToken(true, false);
        while (true) {
          if (token.isSymbol("}")) {
            s += "}";
            valid = true;
            break;
          } else {
            var d = this.parseDeclaration(token, descriptors, false, false, aSheet);
            s += ((d && descriptors.length) ? " " : "") + d;
          }
          token = this.getToken(true, false);
        }
      }
    }
    if (valid) {
      this.forgetState();
      var rule = new jscsspFontFaceRule();
      rule.currentLine = currentLine;
      rule.parsedCssText = s;
      rule.descriptors = descriptors;
      rule.parentStyleSheet = aSheet;
      aSheet.cssRules.push(rule)
      return true;
    }
    this.restoreState();
    return false;
  },

  parsePageRule: function(aToken, aSheet) {
    var currentLine = CountLF(this.mScanner.getAlreadyScanned());
    var s = aToken.value;
    var valid = false;
    var declarations = [];
    this.preserveState();
    var token = this.getToken(true, true);
    var pageSelector = "";
    if (token.isSymbol(":") || token.isIdent()) {
      if (token.isSymbol(":")) {
        pageSelector = ":";
        token = this.getToken(false, false);
      }
      if (token.isIdent()) {
        pageSelector += token.value;
        s += " " + pageSelector;
        token = this.getToken(true, true);
      }
    }
    if (token.isNotNull()) {
      // expecting block start
      if (token.isSymbol("{")) {
        s += " " + token.value;
        var token = this.getToken(true, false);
        while (true) {
          if (token.isSymbol("}")) {
            s += "}";
            valid = true;
            break;
          } else {
            var d = this.parseDeclaration(token, declarations, true, true, aSheet);
            s += ((d && declarations.length) ? " " : "") + d;
          }
          token = this.getToken(true, false);
        }
      }
    }
    if (valid) {
      this.forgetState();
      var rule = new jscsspPageRule();
      rule.currentLine = currentLine;
      rule.parsedCssText = s;
      rule.pageSelector = pageSelector;
      rule.declarations = declarations;
      rule.parentStyleSheet = aSheet;
      aSheet.cssRules.push(rule)
      return true;
    }
    this.restoreState();
    return false;
  },

  parseDefaultPropertyValue: function(token, aDecl, aAcceptPriority, descriptor, aSheet) {
    var valueText = "";
    var blocks = [];
    var foundPriority = false;
    var values = [];
    while (token.isNotNull()) {

      if ((token.isSymbol(";")
           || token.isSymbol("}")
           || token.isSymbol("!"))
          && !blocks.length) {
        if (token.isSymbol("}"))
          this.ungetToken();
        break;
      }
  
      if (token.isIdent(this.kINHERIT)) {
        if (values.length) {
          return "";
        }
        else {
          valueText = this.kINHERIT;
          var value = new jscsspVariable(kJscsspINHERIT_VALUE, aSheet);
          values.push(value);
          token = this.getToken(true, true);
          break;
        }
      }
      else if (token.isSymbol("{")
                 || token.isSymbol("(")
                 || token.isSymbol("[")) {
        blocks.push(token.value);
      }
      else if (token.isSymbol("}")
                 || token.isSymbol("]")) {
        if (blocks.length) {
          var ontop = blocks[blocks.length - 1];
          if ((token.isSymbol("}") && ontop == "{")
              || (token.isSymbol(")") && ontop == "(")
              || (token.isSymbol("]") && ontop == "[")) {
            blocks.pop();
          }
        }
      }
      // XXX must find a better way to store individual values
      // probably a |values: []| field holding dimensions, percentages
      // functions, idents, numbers and symbols, in that order.
      if (token.isFunction()) {
        if (token.isFunction("var(")) {
          token = this.getToken(true, true);
          if (token.isIdent()) {
            var name = token.value;
            token = this.getToken(true, true);
            if (token.isSymbol(")")) {
              var value = new jscsspVariable(kJscsspVARIABLE_VALUE, aSheet);
              valueText += "var(" + name + ")";
              value.name = name;
              values.push(value);
            }
            else
              return "";
          }
          else
            return "";
        }
        else {
          var fn = token.value;
          token = this.getToken(false, true);
          var arg = this.parseFunctionArgument(token);
          if (arg) {
            valueText += fn + arg;
            var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet);
            value.value = fn + arg;
            values.push(value);
          }
          else
            return "";
        }
      }
      else if (token.isSymbol("#")) {
        var color = this.parseColor(token);
        if (color) {
          valueText += color;
          var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet);
          value.value = color;
          values.push(value);
        }
        else
          return "";
      }
      else if (!token.isWhiteSpace() && !token.isSymbol(",")) {
        var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet);
        value.value = token.value;
        values.push(value);
        valueText += token.value;
      }
      else
        valueText += token.value;
      token = this.getToken(false, true);
    }
    if (values.length && valueText) {
      this.forgetState();
      aDecl.push(this._createJscsspDeclarationFromValuesArray(descriptor, values, valueText));
      return valueText;
    }
    return "";
  },

  parseMarginOrPaddingShorthand: function(token, aDecl, aAcceptPriority, aProperty)
  {
    var top = null;
    var bottom = null;
    var left = null;
    var right = null;

    var values = [];
    while (true) {

      if (!token.isNotNull())
        break;

      if (token.isSymbol(";")
          || (aAcceptPriority && token.isSymbol("!"))
          || token.isSymbol("}")) {
        if (token.isSymbol("}"))
          this.ungetToken();
        break;
      }

      else if (!values.length && token.isIdent(this.kINHERIT)) {
        values.push(token.value);
        token = this.getToken(true, true);
        break;
      }

      else if (token.isDimension()
              || token.isNumber("0")
              || token.isPercentage()
              || token.isIdent("auto")) {
        values.push(token.value);
      }
      else
        return "";

      token = this.getToken(true, true);
    }

    var count = values.length;
    switch (count) {
      case 1:
        top = values[0];
        bottom = top;
        left = top;
        right = top;
        break;
      case 2:
        top = values[0];
        bottom = top;
        left = values[1];
        right = left;
        break;
      case 3:
        top = values[0];
        left = values[1];
        right = left;
        bottom = values[2];
        break;
      case 4:
        top = values[0];
        right = values[1];
        bottom = values[2];
        left = values[3];
        break;
      default:
        return "";
    }
    this.forgetState();
    aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-top", top));
    aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-right", right));
    aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-bottom", bottom));
    aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-left", left));
   return top + " " + right + " " + bottom + " " + left;
  },

  parseBorderColorShorthand: function(token, aDecl, aAcceptPriority)
  {
    var top = null;
    var bottom = null;
    var left = null;
    var right = null;

    var values = [];
    while (true) {

      if (!token.isNotNull())
        break;

      if (token.isSymbol(";")
          || (aAcceptPriority && token.isSymbol("!"))
          || token.isSymbol("}")) {
        if (token.isSymbol("}"))
          this.ungetToken();
        break;
      }

      else if (!values.length && token.isIdent(this.kINHERIT)) {
        values.push(token.value);
        token = this.getToken(true, true);
        break;
      }
      
      else {
        var color = this.parseColor(token);
        if (color)
          values.push(color);
        else
          return "";
      }

      token = this.getToken(true, true);
    }

    var count = values.length;
    switch (count) {
      case 1:
        top = values[0];
        bottom = top;
        left = top;
        right = top;
        break;
      case 2:
        top = values[0];
        bottom = top;
        left = values[1];
        right = left;
        break;
      case 3:
        top = values[0];
        left = values[1];
        right = left;
        bottom = values[2];
        break;
      case 4:
        top = values[0];
        right = values[1];
        bottom = values[2];
        left = values[3];
        break;
      default:
        return "";
    }
    this.forgetState();
    aDecl.push(this._createJscsspDeclarationFromValue("border-top-color", top));
    aDecl.push(this._createJscsspDeclarationFromValue("border-right-color", right));
    aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-color", bottom));
    aDecl.push(this._createJscsspDeclarationFromValue("border-left-color", left));
    return top + " " + right + " " + bottom + " " + left;
  },

  parseCueShorthand: function(token, declarations, aAcceptPriority)
  {
    var before = "";
    var after = "";

    var values = [];
    var values = [];
    while (true) {

      if (!token.isNotNull())
        break;

      if (token.isSymbol(";")
          || (aAcceptPriority && token.isSymbol("!"))
          || token.isSymbol("}")) {
        if (token.isSymbol("}"))
          this.ungetToken();
        break;
      }

      else if (!values.length && token.isIdent(this.kINHERIT)) {
        values.push(token.value);
      }

      else if (token.isIdent("none"))
        values.push(token.value);

        else if (token.isFunction("url(")) {
        var token = this.getToken(true, true);
        var urlContent = this.parseURL(token);
        if (urlContent)
          values.push("url(" + urlContent);
        else
          return "";
      }
      else
        return "";

      token = this.getToken(true, true);
    }

    var count = values.length;
    switch (count) {
      case 1:
        before = values[0];
        after = before;
        break;
      case 2:
        before = values[0];
        after = values[1];
        break;
      default:
        return "";
    }
    this.forgetState();
    aDecl.push(this._createJscsspDeclarationFromValue("cue-before", before));
    aDecl.push(this._createJscsspDeclarationFromValue("cue-after", after));
    return before + " " + after;
  },

  parsePauseShorthand: function(token, declarations, aAcceptPriority)
  {
    var before = "";
    var after = "";

    var values = [];
    var values = [];
    while (true) {

      if (!token.isNotNull())
        break;

      if (token.isSymbol(";")
          || (aAcceptPriority && token.isSymbol("!"))
          || token.isSymbol("}")) {
        if (token.isSymbol("}"))
          this.ungetToken();
        break;
      }

      else if (!values.length && token.isIdent(this.kINHERIT)) {
        values.push(token.value);
      }

      else if (token.isDimensionOfUnit("ms")
               || token.isDimensionOfUnit("s")
               || token.isPercentage()
               || token.isNumber("0"))
        values.push(token.value);
      else
        return "";

      token = this.getToken(true, true);
    }

    var count = values.length;
    switch (count) {
      case 1:
        before = values[0];
        after = before;
        break;
      case 2:
        before = values[0];
        after = values[1];
        break;
      default:
        return "";
    }
    this.forgetState();
    aDecl.push(this._createJscsspDeclarationFromValue("pause-before", before));
    aDecl.push(this._createJscsspDeclarationFromValue("pause-after", after));
    return before + " " + after;
  },

  parseBorderWidthShorthand: function(token, aDecl, aAcceptPriority)
  {
    var top = null;
    var bottom = null;
    var left = null;
    var right = null;

    var values = [];
    while (true) {

      if (!token.isNotNull())
        break;

      if (token.isSymbol(";")
          || (aAcceptPriority && token.isSymbol("!"))
          || token.isSymbol("}")) {
        if (token.isSymbol("}"))
          this.ungetToken();
        break;
      }

      else if (!values.length && token.isIdent(this.kINHERIT)) {
        values.push(token.value);
      }
      
      else if (token.isDimension()
               || token.isNumber("0")
               || (token.isIdent() && token.value in this.kBORDER_WIDTH_NAMES)) {
        values.push(token.value);
      }
      else
        return "";

      token = this.getToken(true, true);
    }

    var count = values.length;
    switch (count) {
      case 1:
        top = values[0];
        bottom = top;
        left = top;
        right = top;
        break;
      case 2:
        top = values[0];
        bottom = top;
        left = values[1];
        right = left;
        break;
      case 3:
        top = values[0];
        left = values[1];
        right = left;
        bottom = values[2];
        break;
      case 4:
        top = values[0];
        right = values[1];
        bottom = values[2];
        left = values[3];
        break;
      default:
        return "";
    }
    this.forgetState();
    aDecl.push(this._createJscsspDeclarationFromValue("border-top-width", top));
    aDecl.push(this._createJscsspDeclarationFromValue("border-right-width", right));
    aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-width", bottom));
    aDecl.push(this._createJscsspDeclarationFromValue("border-left-width", left));
    return top + " " + right + " " + bottom + " " + left;
  },

  parseBorderStyleShorthand: function(token, aDecl, aAcceptPriority)
  {
    var top = null;
    var bottom = null;
    var left = null;
    var right = null;

    var values = [];
    while (true) {

      if (!token.isNotNull())
        break;

      if (token.isSymbol(";")
          || (aAcceptPriority && token.isSymbol("!"))
          || token.isSymbol("}")) {
        if (token.isSymbol("}"))
          this.ungetToken();
        break;
      }

      else if (!values.length && token.isIdent(this.kINHERIT)) {
        values.push(token.value);
      }
      
      else if (token.isIdent() && token.value in this.kBORDER_STYLE_NAMES) {
        values.push(token.value);
      }
      else
        return "";

      token = this.getToken(true, true);
    }

    var count = values.length;
    switch (count) {
      case 1:
        top = values[0];
        bottom = top;
        left = top;
        right = top;
        break;
      case 2:
        top = values[0];
        bottom = top;
        left = values[1];
        right = left;
        break;
      case 3:
        top = values[0];
        left = values[1];
        right = left;
        bottom = values[2];
        break;
      case 4:
        top = values[0];
        right = values[1];
        bottom = values[2];
        left = values[3];
        break;
      default:
        return "";
    }
    this.forgetState();
    aDecl.push(this._createJscsspDeclarationFromValue("border-top-style", top));
    aDecl.push(this._createJscsspDeclarationFromValue("border-right-style", right));
    aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-style", bottom));
    aDecl.push(this._createJscsspDeclarationFromValue("border-left-style", left));
    return top + " " + right + " " + bottom + " " + left;
  },

  parseBorderEdgeOrOutlineShorthand: function(token, aDecl, aAcceptPriority, aProperty)
  {
    var bWidth = null;
    var bStyle = null;
    var bColor = null;

    while (true) {
      if (!token.isNotNull())
        break;

      if (token.isSymbol(";")
          || (aAcceptPriority && token.isSymbol("!"))
          || token.isSymbol("}")) {
        if (token.isSymbol("}"))
          this.ungetToken();
        break;
      }

      else if (!bWidth && !bStyle && !bColor
               && token.isIdent(this.kINHERIT)) {
        bWidth = this.kINHERIT;
        bStyle = this.kINHERIT;
        bColor = this.kINHERIT;
      }

      else if (!bWidth &&
               (token.isDimension()
                || (token.isIdent() && token.value in this.kBORDER_WIDTH_NAMES)
                || token.isNumber("0"))) {
        bWidth = token.value;
      }

      else if (!bStyle &&
               (token.isIdent() && token.value in this.kBORDER_STYLE_NAMES)) {
        bStyle = token.value;
      }

      else {
        var color = (aProperty == "outline" && token.isIdent("invert"))
                    ? "invert" : this.parseColor(token);
        if (!bColor && color)
          bColor = color;
        else
          return "";
      }
      token = this.getToken(true, true);
    }

    // create the declarations
    this.forgetState();
    bWidth = bWidth ? bWidth : "medium";
    bStyle = bStyle ? bStyle : "none";
    bColor = bColor ? bColor : "-moz-initial";

    function addPropertyToDecl(aSelf, aDecl, property, w, s, c) {
      aDecl.push(aSelf._createJscsspDeclarationFromValue(property + "-width", w));
      aDecl.push(aSelf._createJscsspDeclarationFromValue(property + "-style", s));
      aDecl.push(aSelf._createJscsspDeclarationFromValue(property + "-color", c));
    }

    if (aProperty == "border") {
      addPropertyToDecl(this, aDecl, "border-top", bWidth, bStyle, bColor);
      addPropertyToDecl(this, aDecl, "border-right", bWidth, bStyle, bColor);
      addPropertyToDecl(this, aDecl, "border-bottom", bWidth, bStyle, bColor);
      addPropertyToDecl(this, aDecl, "border-left", bWidth, bStyle, bColor);
    }
    else
      addPropertyToDecl(this, aDecl, aProperty, bWidth, bStyle, bColor);
    return bWidth + " " + bStyle + " " + bColor;
  },

  parseBackgroundShorthand: function(token, aDecl, aAcceptPriority)
  {
    var kHPos = {"left": true, "right": true };

    var kVPos = {"top": true, "bottom": true };
    var kPos = {"left": true, "right": true, "top": true, "bottom": true, "center": true};

    var bgColor = null;
    var bgRepeat = null;
    var bgAttachment = null;
    var bgImage = null;
    var bgPosition = null;

    while (true) {

      if (!token.isNotNull())
        break;

      if (token.isSymbol(";")
          || (aAcceptPriority && token.isSymbol("!"))
          || token.isSymbol("}")) {
        if (token.isSymbol("}"))
          this.ungetToken();
        break;
      }

      else if (!bgColor && !bgRepeat && !bgAttachment && !bgImage && !bgPosition
               && token.isIdent(this.kINHERIT)) {
        bgColor = this.kINHERIT;
        bgRepeat = this.kINHERIT;
        bgAttachment = this.kINHERIT;
        bgImage = this.kINHERIT;
        bgPosition = this.kINHERIT;
      }

      else {
        if (!bgAttachment &&
            (token.isIdent("scroll")
             || token.isIdent("fixed"))) {
          bgAttachment = token.value;
        }

        else if (!bgPosition &&
                 ((token.isIdent() && token.value in kPos)
                  || token.isDimension()
                  || token.isNumber("0")
                  || token.isPercentage())) {
          bgPosition = token.value;
          token = this.getToken(true, true);
          if (token.isDimension() || token.isNumber("0") || token.isPercentage()) {
            bgPosition += " " + token.value;
          }
          else if (token.isIdent() && token.value in kPos) {
            if ((bgPosition in kHPos && token.value in kHPos) ||
                (bgPosition in kVPos && token.value in kVPos))
              return "";
            bgPosition += " " + token.value;
          }
          else {
            this.ungetToken();
            bgPosition += " center";
          }
        }

        else if (!bgRepeat &&
                 (token.isIdent("repeat")
                  || token.isIdent("repeat-x")
                  || token.isIdent("repeat-y")
                  || token.isIdent("no-repeat"))) {
          bgRepeat = token.value;
        }

        else if (!bgImage &&
                 (token.isFunction("url(")
                  || token.isIdent("none"))) {
          bgImage = token.value;
          if (token.isFunction("url(")) {
            token = this.getToken(true, true);
            var url = this.parseURL(token); // TODO
            if (url)
              bgImage += url;
            else
              return "";
          }
        }

        else if (!bgImage &&
                 (token.isFunction("-moz-linear-gradient(")
                  || token.isFunction("-moz-radial-gradient(")
                  || token.isFunction("-moz-repeating-linear-gradient(")
                  || token.isFunction("-moz-repeating-radial-gradient("))) {
          var gradient = CssInspector.parseGradient(this, token);
          if (gradient)
            bgImage = CssInspector.serializeGradient(gradient);
          else
            return "";
        }

        else {
          var color = this.parseColor(token);
          if (!bgColor && color)
            bgColor = color;
          else
            return "";
        }

      }

      token = this.getToken(true, true);
    }

    // create the declarations
    this.forgetState();
    bgColor = bgColor ? bgColor : "transparent";
    bgImage = bgImage ? bgImage : "none";
    bgRepeat = bgRepeat ? bgRepeat : "repeat";
    bgAttachment = bgAttachment ? bgAttachment : "scroll";
    bgPosition = bgPosition ? bgPosition : "top left";

    aDecl.push(this._createJscsspDeclarationFromValue("background-color", bgColor));
    aDecl.push(this._createJscsspDeclarationFromValue("background-image", bgImage));
    aDecl.push(this._createJscsspDeclarationFromValue("background-repeat", bgRepeat));
    aDecl.push(this._createJscsspDeclarationFromValue("background-attachment", bgAttachment));
    aDecl.push(this._createJscsspDeclarationFromValue("background-position", bgPosition));
    return bgColor + " " + bgImage + " " + bgRepeat + " " + bgAttachment + " " + bgPosition;
  },

  parseListStyleShorthand: function(token, aDecl, aAcceptPriority)
  {
    var kPosition = { "inside": true, "outside": true };

    var lType = null;
    var lPosition = null;
    var lImage = null;

    while (true) {

      if (!token.isNotNull())
        break;

      if (token.isSymbol(";")
          || (aAcceptPriority && token.isSymbol("!"))
          || token.isSymbol("}")) {
        if (token.isSymbol("}"))
          this.ungetToken();
        break;
      }

      else if (!lType && !lPosition && ! lImage
               && token.isIdent(this.kINHERIT)) {
        lType = this.kINHERIT;
        lPosition = this.kINHERIT;
        lImage = this.kINHERIT;
      }

      else if (!lType &&
               (token.isIdent() && token.value in this.kLIST_STYLE_TYPE_NAMES)) {
        lType = token.value;
      }

      else if (!lPosition &&
               (token.isIdent() && token.value in kPosition)) {
        lPosition = token.value;
      }

      else if (!lImage && token.isFunction("url")) {
        token = this.getToken(true, true);
        var urlContent = this.parseURL(token);
        if (urlContent) {
          lImage = "url(" + urlContent;
        }
        else
          return "";
      }
      else if (!token.isIdent("none"))
        return "";

      token = this.getToken(true, true);
    }

    // create the declarations
    this.forgetState();
    lType = lType ? lType : "none";
    lImage = lImage ? lImage : "none";
    lPosition = lPosition ? lPosition : "outside";

    aDecl.push(this._createJscsspDeclarationFromValue("list-style-type", lType));
    aDecl.push(this._createJscsspDeclarationFromValue("list-style-position", lPosition));
    aDecl.push(this._createJscsspDeclarationFromValue("list-style-image", lImage));
    return lType + " " + lPosition + " " + lImage;
  },

  parseFontShorthand: function(token, aDecl, aAcceptPriority)
  {
    var kStyle = {"italic": true, "oblique": true };
    var kVariant = {"small-caps": true };
    var kWeight = { "bold": true, "bolder": true, "lighter": true,
                      "100": true, "200": true, "300": true, "400": true,
                      "500": true, "600": true, "700": true, "800": true,
                      "900": true };
    var kSize = { "xx-small": true, "x-small": true, "small": true, "medium": true,
                    "large": true, "x-large": true, "xx-large": true,
                    "larger": true, "smaller": true };
    var kValues = { "caption": true, "icon": true, "menu": true, "message-box": true, "small-caption": true, "status-bar": true };
    var kFamily = { "serif": true, "sans-serif": true, "cursive": true, "fantasy": true, "monospace": true };

    var fStyle = null;
    var fVariant = null;
    var fWeight = null;
    var fSize = null;
    var fLineHeight = null;
    var fFamily = "";
    var fSystem = null;
    var fFamilyValues = [];

    var normalCount = 0;
    while (true) {

      if (!token.isNotNull())
        break;

      if (token.isSymbol(";")
          || (aAcceptPriority && token.isSymbol("!"))
          || token.isSymbol("}")) {
        if (token.isSymbol("}"))
          this.ungetToken();
        break;
      }

      else if (!fStyle && !fVariant && !fWeight
               && !fSize && !fLineHeight && !fFamily
               && !fSystem
               && token.isIdent(this.kINHERIT)) {
        fStyle = this.kINHERIT;
        fVariant = this.kINHERIT;
        fWeight = this.kINHERIT;
        fSize = this.kINHERIT;
        fLineHeight = this.kINHERIT;
        fFamily = this.kINHERIT;
        fSystem = this.kINHERIT;
      }

      else {
        if (!fSystem && (token.isIdent() && token.value in kValues)) {
          fSystem = token.value;
          break;
        }

        else {
          if (!fStyle
                   && token.isIdent()
                   && (token.value in kStyle)) {
            fStyle = token.value;
          }
  
          else if (!fVariant
                   && token.isIdent()
                   && (token.value in kVariant)) {
            fVariant = token.value;
          }
  
          else if (!fWeight
                   && (token.isIdent() || token.isNumber())
                   && (token.value in kWeight)) {
            fWeight = token.value;
          }
  
          else if (!fSize
                   && ((token.isIdent() && (token.value in kSize))
                       || token.isDimension()
                       || token.isPercentage())) {
            fSize = token.value;
            var token = this.getToken(false, false);
            if (token.isSymbol("/")) {
              token = this.getToken(false, false);
              if (!fLineHeight &&
                  (token.isDimension() || token.isNumber() || token.isPercentage())) {
                fLineHeight = token.value;
              }
              else
                return "";
            }
            else
              this.ungetToken();
          }

          else if (token.isIdent("normal")) {
            normalCount++;
            if (normalCount > 3)
              return "";
          }

          else if (!fFamily && // *MUST* be last to be tested here
                   (token.isString()
                    || token.isIdent())) {
            var lastWasComma = false;
            while (true) {
              if (!token.isNotNull())
                break;
              else if (token.isSymbol(";")
                  || (aAcceptPriority && token.isSymbol("!"))
                  || token.isSymbol("}")) {
                this.ungetToken();
                break;
              }
              else if (token.isIdent() && token.value in kFamily) {
                var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, null);
                value.value = token.value;
                fFamilyValues.push(value);
                fFamily += token.value;
                break;
              }
              else if (token.isString() || token.isIdent()) {
                var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, null);
                value.value = token.value;
                fFamilyValues.push(value);
                fFamily += token.value;
                lastWasComma = false;
              }
              else if (!lastWasComma && token.isSymbol(",")) {
                fFamily += ", ";
                lastWasComma = true;
              }
              else
                return "";
              token = this.getToken(true, true);
            }
          }

          else {
            return "";
          }
        }

      }

      token = this.getToken(true, true);
    }

    // create the declarations
    this.forgetState();
    if (fSystem) {
      aDecl.push(this._createJscsspDeclarationFromValue("font", fSystem));
      return fSystem;
    }
    fStyle = fStyle ? fStyle : "normal";
    fVariant = fVariant ? fVariant : "normal";
    fWeight = fWeight ? fWeight : "normal";
    fSize = fSize ? fSize : "medium";
    fLineHeight = fLineHeight ? fLineHeight : "normal";
    fFamily = fFamily ? fFamily : "-moz-initial";

    aDecl.push(this._createJscsspDeclarationFromValue("font-style", fStyle));
    aDecl.push(this._createJscsspDeclarationFromValue("font-variant", fVariant));
    aDecl.push(this._createJscsspDeclarationFromValue("font-weight", fWeight));
    aDecl.push(this._createJscsspDeclarationFromValue("font-size", fSize));
    aDecl.push(this._createJscsspDeclarationFromValue("line-height", fLineHeight));
    aDecl.push(this._createJscsspDeclarationFromValuesArray("font-family", fFamilyValues, fFamily));
    return fStyle + " " + fVariant + " " + fWeight + " " + fSize + "/" + fLineHeight + " " + fFamily;
  },

  _createJscsspDeclaration: function(property, value)
  {
    var decl = new jscsspDeclaration();
    decl.property = property;
    decl.value = this.trim11(value);
    decl.parsedCssText = property + ": " + value + ";";
    return decl;
  },

  _createJscsspDeclarationFromValue: function(property, valueText)
  {
    var decl = new jscsspDeclaration();
    decl.property = property;
    var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, null);
    value.value = valueText;
    decl.values = [value];
    decl.valueText = valueText;
    decl.parsedCssText = property + ": " + valueText + ";";
    return decl;
  },

  _createJscsspDeclarationFromValuesArray: function(property, values, valueText)
  {
    var decl = new jscsspDeclaration();
    decl.property = property;
    decl.values = values;
    decl.valueText = valueText;
    decl.parsedCssText = property + ": " + valueText + ";";
    return decl;
  },

  parseURL: function(token)
  {
    var value = "";
    if (token.isString())
    {
      value += token.value;
      token = this.getToken(true, true);
    }
    else
      while (true)
      {
        if (!token.isNotNull()) {
          this.reportError(kURL_EOF);
          return "";
        }
        if (token.isWhiteSpace()) {
          nextToken = this.lookAhead(true, true);
          // if next token is not a closing parenthesis, that's an error
          if (!nextToken.isSymbol(")")) {
            this.reportError(kURL_WS_INSIDE);
            token = this.currentToken();
            break;
          }
        }
        if (token.isSymbol(")")) {
          break;
        }
        value += token.value;
        token = this.getToken(false, false);
      }

    if (token.isSymbol(")")) {
      return value + ")";
    }
    return "";
  },

  parseFunctionArgument: function(token)
  {
    var value = "";
    if (token.isString())
    {
      value += token.value;
      token = this.getToken(true, true);
    }
    else {
      var parenthesis = 1;
      while (true)
      {
        if (!token.isNotNull())
          return "";
        if (token.isFunction() || token.isSymbol("("))
          parenthesis++;
        if (token.isSymbol(")")) {
          parenthesis--;
          if (!parenthesis)
            break;
        }
        value += token.value;
        token = this.getToken(false, false);
      }
    }

    if (token.isSymbol(")"))
      return value + ")";
    return "";
  },

  parseColor: function(token)
  {
    var color = "";
    if (token.isFunction("rgb(")
        || token.isFunction("rgba(")) {
      color = token.value;
      var isRgba = token.isFunction("rgba(")
      token = this.getToken(true, true);
      if (!token.isNumber() && !token.isPercentage())
        return "";
      color += token.value;
      token = this.getToken(true, true);
      if (!token.isSymbol(","))
        return "";
      color += ", ";
  
      token = this.getToken(true, true);
      if (!token.isNumber() && !token.isPercentage())
        return "";
      color += token.value;
      token = this.getToken(true, true);
      if (!token.isSymbol(","))
        return "";
      color += ", ";
  
      token = this.getToken(true, true);
      if (!token.isNumber() && !token.isPercentage())
        return "";
      color += token.value;
  
      if (isRgba) {
        token = this.getToken(true, true);
        if (!token.isSymbol(","))
          return "";
        color += ", ";
  
        token = this.getToken(true, true);
        if (!token.isNumber())
          return "";
        color += token.value;
      }
  
      token = this.getToken(true, true);
      if (!token.isSymbol(")"))
        return "";
      color += token.value;
    }
  
    else if (token.isFunction("hsl(")
             || token.isFunction("hsla(")) {
      color = token.value;
      var isHsla = token.isFunction("hsla(")
      token = this.getToken(true, true);
      if (!token.isNumber())
        return "";
      color += token.value;
      token = this.getToken(true, true);
      if (!token.isSymbol(","))
        return "";
      color += ", ";
  
      token = this.getToken(true, true);
      if (!token.isPercentage())
        return "";
      color += token.value;
      token = this.getToken(true, true);
      if (!token.isSymbol(","))
        return "";
      color += ", ";
  
      token = this.getToken(true, true);
      if (!token.isPercentage())
        return "";
      color += token.value;
  
      if (isHsla) {
        token = this.getToken(true, true);
        if (!token.isSymbol(","))
          return "";
        color += ", ";
  
        token = this.getToken(true, true);
        if (!token.isNumber())
          return "";
        color += token.value;
      }
  
      token = this.getToken(true, true);
      if (!token.isSymbol(")"))
        return "";
      color += token.value;
    }

    else if (token.isIdent()
             && (token.value in this.kCOLOR_NAMES))
      color = token.value;

    else if (token.isSymbol("#")) {
      token = this.getHexValue();
      if (!token.isHex())
        return "";
      var length = token.value.length;
      if (length != 3 && length != 6)
        return "";
      if (token.value.match( /[a-fA-F0-9]/g ).length != length)
        return "";
      color = "#" + token.value;
    }
    return color;
  },

  parseDeclaration: function(aToken, aDecl, aAcceptPriority, aExpandShorthands, aSheet) {
    this.preserveState();
    var blocks = [];
    if (aToken.isIdent()) {
      var descriptor = aToken.value.toLowerCase();
      var token = this.getToken(true, true);
      if (token.isSymbol(":")) {
        var token = this.getToken(true, true);

        var value = "";
        var declarations = [];
        if (aExpandShorthands)
          switch (descriptor) {
            case "background":
              value = this.parseBackgroundShorthand(token, declarations, aAcceptPriority);
              break;
            case "margin":
            case "padding":
              value = this.parseMarginOrPaddingShorthand(token, declarations, aAcceptPriority, descriptor);
              break;
            case "border-color":
              value = this.parseBorderColorShorthand(token, declarations, aAcceptPriority);
              break;
            case "border-style":
              value = this.parseBorderStyleShorthand(token, declarations, aAcceptPriority);
              break;
            case "border-width":
              value = this.parseBorderWidthShorthand(token, declarations, aAcceptPriority);
              break;
            case "border-top":
            case "border-right":
            case "border-bottom":
            case "border-left":
            case "border":
            case "outline":
              value = this.parseBorderEdgeOrOutlineShorthand(token, declarations, aAcceptPriority, descriptor);
              break;
            case "cue":
              value = this.parseCueShorthand(token, declarations, aAcceptPriority);
              break;
            case "pause":
              value = this.parsePauseShorthand(token, declarations, aAcceptPriority);
              break;
            case "font":
              value = this.parseFontShorthand(token, declarations, aAcceptPriority);
              break;
            case "list-style":
              value = this.parseListStyleShorthand(token, declarations, aAcceptPriority);
              break;
            default:
              value = this.parseDefaultPropertyValue(token, declarations, aAcceptPriority, descriptor, aSheet);
              break;
          }
        else
          value = this.parseDefaultPropertyValue(token, declarations, aAcceptPriority, descriptor, aSheet);
        token = this.currentToken();
        if (value) // no error above
        {
          var priority = false;
          if (token.isSymbol("!")) {
            token = this.getToken(true, true);
            if (token.isIdent("important")) {
              priority = true;
              token = this.getToken(true, true);
              if (token.isSymbol(";") || token.isSymbol("}")) {
                if (token.isSymbol("}"))
                  this.ungetToken();
              }
              else return "";
            }
            else return "";
          }
          else if  (token.isNotNull() && !token.isSymbol(";") && !token.isSymbol("}"))
            return "";
          for (var i = 0; i < declarations.length; i++) {
            declarations[i].priority = priority;
            aDecl.push(declarations[i]);
          }
          return descriptor + ": " + value + ";";
        }
      }
    }
    else if (aToken.isComment()) {
      if (this.mPreserveComments) {
        this.forgetState();
        var comment = new jscsspComment();
        comment.parsedCssText = aToken.value;
        aDecl.push(comment);
      }
      return aToken.value;
    }

    // we have an error here, let's skip it
    this.restoreState();
    var s = aToken.value;
    blocks = [];
    var token = this.getToken(false, false);
    while (token.isNotNull()) {
      s += token.value;
      if ((token.isSymbol(";") || token.isSymbol("}")) && !blocks.length) {
        if (token.isSymbol("}"))
          this.ungetToken();
        break;
      } else if (token.isSymbol("{")
                 || token.isSymbol("(")
                 || token.isSymbol("[")
                 || token.isFunction()) {
        blocks.push(token.isFunction() ? "(" : token.value);
      } else if (token.isSymbol("}")
                 || token.isSymbol(")")
                 || token.isSymbol("]")) {
        if (blocks.length) {
          var ontop = blocks[blocks.length - 1];
          if ((token.isSymbol("}") && ontop == "{")
              || (token.isSymbol(")") && ontop == "(")
              || (token.isSymbol("]") && ontop == "[")) {
            blocks.pop();
          }
        }
      }
      token = this.getToken(false, false);
    }
    return "";
  },

  parseKeyframesRule: function(aToken, aSheet) {
    var currentLine = CountLF(this.mScanner.getAlreadyScanned());
    var s = aToken.value;
    var valid = false;
    var keyframesRule = new jscsspKeyframesRule();
    keyframesRule.currentLine = currentLine;
    this.preserveState();
    var token = this.getToken(true, true);
    var foundName = false;
    while (token.isNotNull()) {
      if (token.isIdent()) {
        // should be the keyframes' name
        foundName = true;
        s += " " + token.value;
        keyframesRule.name = token.value;
        token = this.getToken(true, true);
        if (token.isSymbol("{"))
          this.ungetToken();
        else {
          // error...
          token.type = jscsspToken.NULL_TYPE;
          break;
        }
      }
      else if (token.isSymbol("{")) {
        if (!foundName) {
          token.type = jscsspToken.NULL_TYPE;
          // not a valid keyframes at-rule
        }
        break;
      }
      else {
        token.type = jscsspToken.NULL_TYPE;
        // not a valid keyframes at-rule
        break;
      }
      token = this.getToken(true, true);
    }

    if (token.isSymbol("{") && keyframesRule.name) {
      // ok let's parse keyframe rules now...
      s += " { ";
      token = this.getToken(true, false);
      while (token.isNotNull()) {
        if (token.isComment() && this.mPreserveComments) {
          s += " " + token.value;
          var comment = new jscsspComment();
          comment.parsedCssText = token.value;
          keyframesRule.cssRules.push(comment);
        } else if (token.isSymbol("}")) {
          valid = true;
          break;
        } else {
          var r = this.parseKeyframeRule(token, keyframesRule, true);
          if (r)
            s += r;
        }
        token = this.getToken(true, false);
      }
    }
    if (valid) {
      this.forgetState();
      keyframesRule.currentLine = currentLine;
      keyframesRule.parsedCssText = s;
      aSheet.cssRules.push(keyframesRule);
      return true;
    }
    this.restoreState();
    return false;
  },

  parseKeyframeRule: function(aToken, aOwner) {
    var currentLine = CountLF(this.mScanner.getAlreadyScanned());
    this.preserveState();
    var token = aToken;

    // find the keyframe keys
    var key = "";
    while (token.isNotNull()) {
      if (token.isIdent() || token.isPercentage()) {
        if (token.isIdent()
            && !token.isIdent("from")
            && !token.isIdent("to")) {
          key = "";
          break;
        }
        key += token.value;
        token = this.getToken(true, true);
        if (token.isSymbol("{")) {
          this.ungetToken();
          break;
        }
        else 
          if (token.isSymbol(",")) {
            key += ", ";
          }
          else {
            key = "";
            break;
          }
      }
      else {
        key = "";
        break;
      }
      token = this.getToken(true, true);
    }

    var valid = false;
    var declarations = [];
    if (key) {
      var s = key;
      token = this.getToken(true, true);
      if (token.isSymbol("{")) {
        s += " { ";
        token = this.getToken(true, false);
        while (true) {
          if (!token.isNotNull()) {
            valid = true;
            break;
          }
          if (token.isSymbol("}")) {
            s += "}";
            valid = true;
            break;
          } else {
            var d = this.parseDeclaration(token, declarations, true, true, aOwner);
            s += ((d && declarations.length) ? " " : "") + d;
          }
          token = this.getToken(true, false);
        }
      }
    }
    else {
      // key is invalid so the whole rule is invalid with it
    }

    if (valid) {
      var rule = new jscsspKeyframeRule();
      rule.currentLine = currentLine;
      rule.parsedCssText = s;
      rule.declarations = declarations;
      rule.keyText = key;
      rule.parentRule = aOwner;
      aOwner.cssRules.push(rule);
      return s;
    }
    this.restoreState();
    s = this.currentToken().value;
    this.addUnknownAtRule(aOwner, s);
    return "";
  },

  parseMediaRule: function(aToken, aSheet) {
	this.mScanner.mMediaQueryMode = true;
	var currentLine = CountLF(this.mScanner.getAlreadyScanned());
    var s = aToken.value;
    var valid = false;
    var mediaRule = new jscsspMediaRule();
    mediaRule.currentLine = currentLine;
    this.preserveState();
    var token = this.getToken(true, true);
    var foundMedia = false;
    while (token.isNotNull()) {
      if (token.isIdent()) {
        foundMedia = true;
        s += " " + token.value;
  		mediaRule.media.push(token.value);
        token = this.getToken(true, true);
        if (token.isSymbol(",")) {
          s += ",";
        } else {
          if (token.isSymbol("{"))
            this.ungetToken();
          else {
            // error...
            token.type = jscsspToken.NULL_TYPE;
            break;
          }
        }
      }
      else if (token.isSymbol("{"))
        break;
      else if (foundMedia) {
        token.type = jscsspToken.NULL_TYPE;
        // not a media list
        break;
      }
      token = this.getToken(true, true);
    }
    if (token.isSymbol("{") && mediaRule.media.length) {
      // ok let's parse style rules now...
      s += " { ";
      token = this.getToken(true, false);
      while (token.isNotNull()) {
        if (token.isComment() && this.mPreserveComments) {
          s += " " + token.value;
          var comment = new jscsspComment();
          comment.parsedCssText = token.value;
          mediaRule.cssRules.push(comment);
        } else if (token.isSymbol("}")) {
          valid = true;
          break;
        } else {
          var r = this.parseStyleRule(token, mediaRule, true);
          if (r)
            s += r;
        }
        token = this.getToken(true, false);
      }
    }
	if (valid) {
      this.forgetState();
      mediaRule.parsedCssText = s;
      aSheet.cssRules.push(mediaRule);
      return true;
    }
    this.restoreState();
    return false;
  },


  trim11: function(str) {
    str = str.replace(/^\s+/, '');
    for (var i = str.length - 1; i >= 0; i--) {
      if (/\S/.test( str.charAt(i) )) { // XXX charat
        str = str.substring(0, i + 1);
        break;
      }
    }
    return str;
  },

  parseStyleRule: function(aToken, aOwner, aIsInsideMediaRule)
  {
    var currentLine = CountLF(this.mScanner.getAlreadyScanned());
    this.preserveState();
    // first let's see if we have a selector here...
    var selector = this.parseSelector(aToken, false);
    var valid = false;
    var declarations = [];
    if (selector) {
      selector = this.trim11(selector.selector);
      var s = selector;
      var token = this.getToken(true, true);
      if (token.isSymbol("{")) {
        s += " { ";
        var token = this.getToken(true, false);
        while (true) {
          if (!token.isNotNull()) {
            valid = true;
            break;
          }
          if (token.isSymbol("}")) {
            s += "}";
            valid = true;
            break;
          } else {
            var d = this.parseDeclaration(token, declarations, true, true, aOwner);
            s += ((d && declarations.length) ? " " : "") + d;
          }
          token = this.getToken(true, false);
        }
      }
    }
    else {
      // selector is invalid so the whole rule is invalid with it
    }

    if (valid) {
      var rule = new jscsspStyleRule();
      rule.currentLine = currentLine;
      rule.parsedCssText = s;
      rule.declarations = declarations;
      rule.mSelectorText = selector;
      if (aIsInsideMediaRule)
        rule.parentRule = aOwner;
      else
        rule.parentStyleSheet = aOwner;
      aOwner.cssRules.push(rule);
      return s;
    }
    this.restoreState();
    s = this.currentToken().value;
    this.addUnknownAtRule(aOwner, s);
    return "";
  },

  parseSelector: function(aToken, aParseSelectorOnly) {
    var s = "";
    var specificity = {a: 0, b: 0, c: 0, d: 0}; // CSS 2.1 section 6.4.3
    var isFirstInChain = true;
    var token = aToken;
    var valid = false;
    var combinatorFound = false;
    while (true) {
      if (!token.isNotNull()) {
        if (aParseSelectorOnly)
          return {selector: s, specificity: specificity };
        return "";
      }

      if (!aParseSelectorOnly && token.isSymbol("{")) {
        // end of selector
        valid = !combinatorFound;
	if (valid) this.ungetToken();
        break;
      }

      if (token.isSymbol(",")) { // group of selectors
        s += token.value;
        isFirstInChain = true;
        combinatorFound = false;
        token = this.getToken(false, true);
        continue;
      }
      // now combinators and grouping...
      else if (!combinatorFound
	       && (token.isWhiteSpace()
		    || token.isSymbol(">")
                    || token.isSymbol("+")
                    || token.isSymbol("~"))) {
	if (token.isWhiteSpace()) {
          s += " ";
	  var nextToken = this.lookAhead(true, true);
	  if (!nextToken.isNotNull()) {
            if (aParseSelectorOnly)
              return {selector: s, specificity: specificity };
	    return "";
	  }
	  if (nextToken.isSymbol(">")
	      || nextToken.isSymbol("+")
	      || nextToken.isSymbol("~")) {
            token = this.getToken(true, true);
	    s += token.value + " ";
	    combinatorFound = true;
	  }
	}
        else {
          s += token.value;
	  combinatorFound = true;
	}
	isFirstInChain = true;
        token = this.getToken(true, true);
        continue;
      }
      else {
        var simpleSelector = this.parseSimpleSelector(token, isFirstInChain, true);
        if (!simpleSelector)
          break; // error
        s += simpleSelector.selector;
        specificity.b += simpleSelector.specificity.b;
        specificity.c += simpleSelector.specificity.c;
        specificity.d += simpleSelector.specificity.d;
	isFirstInChain = false;
	combinatorFound = false;
      }

      token = this.getToken(false, true);
    }

    if (valid) {
      return {selector: s, specificity: specificity };
    }
    return "";
  },

  isPseudoElement: function(aIdent)
  {
    switch (aIdent) {
      case "first-letter":
      case "first-line":
      case "before":
      case "after":
      case "marker":
        return true;
        break;
      default: return false;
        break;
    }
  },

  parseSimpleSelector: function(token, isFirstInChain, canNegate)
  {
    var s = "";
    var specificity = {a: 0, b: 0, c: 0, d: 0}; // CSS 2.1 section 6.4.3
    
    if (isFirstInChain
        && (token.isSymbol("*") || token.isSymbol("|") || token.isIdent())) {
      // type or universal selector
      if (token.isSymbol("*") || token.isIdent()) {
        // we don't know yet if it's a prefix or a universal
        // selector
        s += token.value;
        var isIdent = token.isIdent();
        token = this.getToken(false, true);
        if (token.isSymbol("|")) {
          // it's a prefix
          s += token.value;
          token = this.getToken(false, true);
          if (token.isIdent() || token.isSymbol("*")) {
            // ok we now have a type element or universal
            // selector
            s += token.value;
            if (token.isIdent())
              specificity.d++;
          } else
            // oops that's an error...
            return null;
        } else {
          this.ungetToken();
          if (isIdent)
            specificity.d++;
        }
      } else if (token.isSymbol("|")) {
        s += token.value;
        token = this.getToken(false, true);
        if (token.isIdent() || token.isSymbol("*")) {
          s += token.value;
          if (token.isIdent())
            specificity.d++;
        } else
          // oops that's an error
          return null;
      }
    }
  
    else if (token.isSymbol(".") || token.isSymbol("#")) {
      var isClass = token.isSymbol(".");
      s += token.value;
      token = this.getToken(false, true);
      if (token.isIdent()) {
        s += token.value;
        if (isClass)
          specificity.c++;
        else
          specificity.b++;
      }
      else
        return null;
    }

    else if (token.isSymbol(":")) {
      s += token.value;
      token = this.getToken(false, true);
      if (token.isSymbol(":")) {
        s += token.value;
        token = this.getToken(false, true);
      }
      if (token.isIdent()) {
        s += token.value;
        if (this.isPseudoElement(token.value))
          specificity.d++;
        else
          specificity.c++;
      }
      else if (token.isFunction()) {
        s += token.value;
        if (token.isFunction(":not(")) {
          if (!canNegate)
            return null;
          token = this.getToken(true, true);
          var simpleSelector = this.parseSimpleSelector(token, isFirstInChain, false);
          if (!simpleSelector)
            return null;
          else {
            s += simpleSelector.selector;
            token = this.getToken(true, true);
            if (token.isSymbol(")"))
              s += ")";
            else
              return null;
          }
          specificity.c++;
        }
        else {
          while (true) {
            token = this.getToken(false, true);
            if (token.isSymbol(")")) {
              s += ")";
              break;
            } else
              s += token.value;
          }
          specificity.c++;
        }
      } else
        return null;
  
    } else if (token.isSymbol("[")) {
      s += "[";
      token = this.getToken(true, true);
      if (token.isIdent() || token.isSymbol("*")) {
        s += token.value;
        var nextToken = this.getToken(true, true);
        if (token.isSymbol("|")) {
          s += "|";
          token = this.getToken(true, true);
          if (token.isIdent())
            s += token.value;
          else
            return null;
        } else
          this.ungetToken();
      } else if (token.isSymbol("|")) {
        s += "|";
        token = this.getToken(true, true);
        if (token.isIdent())
          s += token.value;
        else
          return null;
      }
      else
        return null;
  
      // nothing, =, *=, $=, ^=, |=
      token = this.getToken(true, true);
      if (token.isIncludes()
          || token.isDashmatch()
          || token.isBeginsmatch()
          || token.isEndsmatch()
          || token.isContainsmatch()
          || token.isSymbol("=")) {
        s += token.value;
        token = this.getToken(true, true);
        if (token.isString() || token.isIdent()) {
          s += token.value;
          token = this.getToken(true, true);
        }
        else
          return null;
    
        if (token.isSymbol("]")) {
          s += token.value;
          specificity.c++;
        }
        else
          return null;
      }
      else if (token.isSymbol("]")) {
        s += token.value;
        specificity.c++;
      }
      else
        return null;
        
    }
    else if (token.isWhiteSpace()) {
      var t = this.lookAhead(true, true);
      if (t.isSymbol('{'))
        return ""
    }
    if (s)
      return {selector: s, specificity: specificity };
    return null;
  },

  preserveState: function() {
    this.mPreservedTokens.push(this.currentToken());
    this.mScanner.preserveState();
  },

  restoreState: function() {
    if (this.mPreservedTokens.length) {
      this.mScanner.restoreState();
      this.mToken = this.mPreservedTokens.pop();
    }
  },

  forgetState: function() {
    if (this.mPreservedTokens.length) {
      this.mScanner.forgetState();
      this.mPreservedTokens.pop();
    }
  },

  parse: function(aString, aTryToPreserveWhitespaces, aTryToPreserveComments) {
    if (!aString)
      return null; // early way out if we can

    this.mPreserveWS       = aTryToPreserveWhitespaces;
    this.mPreserveComments = aTryToPreserveComments;
    this.mPreservedTokens = [];
    this.mScanner.init(aString);
    var sheet = new jscsspStylesheet();

    // @charset can only appear at first char of the stylesheet
    var token = this.getToken(false, false);
    if (!token.isNotNull())
      return;
    if (token.isAtRule("@charset")) {
      this.parseCharsetRule(token, sheet);
      token = this.getToken(false, false);
    }

    var foundStyleRules = false;
    var foundImportRules = false;
    var foundNameSpaceRules = false;
    while (true) {
      if (!token.isNotNull())
        break;
      if (token.isWhiteSpace())
      {
        if (aTryToPreserveWhitespaces)
          this.addWhitespace(sheet, token.value);
      }

      else if (token.isComment())
      {
        if (this.mPreserveComments)
          this.addComment(sheet, token.value);
      }

      else if (token.isAtRule()) {
        if (token.isAtRule("@variables")) {
          if (!foundImportRules && !foundStyleRules)
            this.parseVariablesRule(token, sheet);
          else {
            this.reportError(kVARIABLES_RULE_POSITION);
            this.addUnknownAtRule(sheet, token.value);
          }
        }
        else if (token.isAtRule("@import")) {
          // @import rules MUST occur before all style and namespace
          // rules
          if (!foundStyleRules && !foundNameSpaceRules)
            foundImportRules = this.parseImportRule(token, sheet);
          else {
            this.reportError(kIMPORT_RULE_POSITION);
            this.addUnknownAtRule(sheet, token.value);
          }
        }
        else if (token.isAtRule("@namespace")) {
          // @namespace rules MUST occur before all style rule and
          // after all @import rules
          if (!foundStyleRules)
            foundNameSpaceRules = this.parseNamespaceRule(token, sheet);
          else {
            this.reportError(kNAMESPACE_RULE_POSITION);
            this.addUnknownAtRule(sheet, token.value);
          }
        }
        else if (token.isAtRule("@font-face")) {
          if (this.parseFontFaceRule(token, sheet))
            foundStyleRules = true;
          else
            this.addUnknownAtRule(sheet, token.value);
        }
        else if (token.isAtRule("@page")) {
          if (this.parsePageRule(token, sheet))
            foundStyleRules = true;
          else
            this.addUnknownAtRule(sheet, token.value);
        }
        else if (token.isAtRule("@media")) {
          if (this.parseMediaRule(token, sheet))
            foundStyleRules = true;
          else
            this.addUnknownAtRule(sheet, token.value);
        }
        else if (token.isAtRule("@keyframes")) {
          if (!this.parseKeyframesRule(token, sheet))
            this.addUnknownAtRule(sheet, token.value);
        }
        else if (token.isAtRule("@charset")) {
          this.reportError(kCHARSET_RULE_CHARSET_SOF);
          this.addUnknownAtRule(sheet, token.value);
        }
        else {
          this.reportError(kUNKNOWN_AT_RULE);
          this.addUnknownAtRule(sheet, token.value);
        }
      }

      else // plain style rules
      {
        var ruleText = this.parseStyleRule(token, sheet, false);
        if (ruleText)
          foundStyleRules = true;
      }
      token = this.getToken(false);
    }

    return sheet;
  }

};


function jscsspToken(aType, aValue, aUnit)
{
  this.type = aType;
  this.value = aValue;
  this.unit = aUnit;
}

jscsspToken.NULL_TYPE = 0;

jscsspToken.WHITESPACE_TYPE = 1;
jscsspToken.STRING_TYPE = 2;
jscsspToken.COMMENT_TYPE = 3;
jscsspToken.NUMBER_TYPE = 4;
jscsspToken.IDENT_TYPE = 5;
jscsspToken.FUNCTION_TYPE = 6;
jscsspToken.ATRULE_TYPE = 7;
jscsspToken.INCLUDES_TYPE = 8;
jscsspToken.DASHMATCH_TYPE = 9;
jscsspToken.BEGINSMATCH_TYPE = 10;
jscsspToken.ENDSMATCH_TYPE = 11;
jscsspToken.CONTAINSMATCH_TYPE = 12;
jscsspToken.SYMBOL_TYPE = 13;
jscsspToken.DIMENSION_TYPE = 14;
jscsspToken.PERCENTAGE_TYPE = 15;
jscsspToken.HEX_TYPE = 16;

jscsspToken.prototype = {

  isNotNull: function ()
  {
    return this.type;
  },

  _isOfType: function (aType, aValue)
  {
    return (this.type == aType && (!aValue || this.value.toLowerCase() == aValue));
  },

  isWhiteSpace: function(w)
  {
    return this._isOfType(jscsspToken.WHITESPACE_TYPE, w);
  },

  isString: function()
  {
    return this._isOfType(jscsspToken.STRING_TYPE);
  },

  isComment: function()
  {
    return this._isOfType(jscsspToken.COMMENT_TYPE);
  },

  isNumber: function(n)
  {
    return this._isOfType(jscsspToken.NUMBER_TYPE, n);
  },

  isSymbol: function(c)
  {
    return this._isOfType(jscsspToken.SYMBOL_TYPE, c);
  },

  isIdent: function(i)
  {
    return this._isOfType(jscsspToken.IDENT_TYPE, i);
  },

  isFunction: function(f)
  {
    return this._isOfType(jscsspToken.FUNCTION_TYPE, f);
  },

  isAtRule: function(a)
  {
    return this._isOfType(jscsspToken.ATRULE_TYPE, a);
  },

  isIncludes: function()
  {
    return this._isOfType(jscsspToken.INCLUDES_TYPE);
  },

  isDashmatch: function()
  {
    return this._isOfType(jscsspToken.DASHMATCH_TYPE);
  },

  isBeginsmatch: function()
  {
    return this._isOfType(jscsspToken.BEGINSMATCH_TYPE);
  },

  isEndsmatch: function()
  {
    return this._isOfType(jscsspToken.ENDSMATCH_TYPE);
  },

  isContainsmatch: function()
  {
    return this._isOfType(jscsspToken.CONTAINSMATCH_TYPE);
  },

  isSymbol: function(c)
  {
    return this._isOfType(jscsspToken.SYMBOL_TYPE, c);
  },

  isDimension: function()
  {
    return this._isOfType(jscsspToken.DIMENSION_TYPE);
  },

  isPercentage: function()
  {
    return this._isOfType(jscsspToken.PERCENTAGE_TYPE);
  },

  isHex: function()
  {
    return this._isOfType(jscsspToken.HEX_TYPE);
  },

  isDimensionOfUnit: function(aUnit)
  {
    return (this.isDimension() && this.unit == aUnit);
  },

  isLength: function()
  {
    return (this.isPercentage() ||
            this.isDimensionOfUnit("cm") ||
            this.isDimensionOfUnit("mm") ||
            this.isDimensionOfUnit("in") ||
            this.isDimensionOfUnit("pc") ||
            this.isDimensionOfUnit("px") ||
            this.isDimensionOfUnit("em") ||
            this.isDimensionOfUnit("ex") ||
            this.isDimensionOfUnit("pt"));
  },

  isAngle: function()
  {
    return (this.isDimensionOfUnit("deg") ||
            this.isDimensionOfUnit("rad") ||
            this.isDimensionOfUnit("grad"));
  }
}

var kJscsspUNKNOWN_RULE   = 0;
var kJscsspSTYLE_RULE     = 1
var kJscsspCHARSET_RULE   = 2;
var kJscsspIMPORT_RULE    = 3;
var kJscsspMEDIA_RULE     = 4;
var kJscsspFONT_FACE_RULE = 5;
var kJscsspPAGE_RULE      = 6;

var kJscsspKEYFRAMES_RULE = 7;
var kJscsspKEYFRAME_RULE  = 8;

var kJscsspNAMESPACE_RULE = 100;
var kJscsspCOMMENT        = 101;
var kJscsspWHITE_SPACE    = 102;

var kJscsspVARIABLES_RULE = 200;

var kJscsspSTYLE_DECLARATION = 1000;

var gTABS = "";

function jscsspStylesheet()
{
  this.cssRules = [];
  this.variables = {};
}

jscsspStylesheet.prototype = {
  insertRule: function(aRule, aIndex) {
    try {
     this.cssRules.splice(aIndex, 1, aRule);
    }
    catch(e) {
    }
  },

  deleteRule: function(aIndex) {
    try {
      this.cssRules.splice(aIndex);
    }
    catch(e) {
    }
  },

  cssText: function() {
    var rv = "";
    for (var i = 0; i < this.cssRules.length; i++)
      rv += this.cssRules[i].cssText() + "\n";
    return rv;
  },

  resolveVariables: function(aMedium) {

    function ItemFoundInArray(aArray, aItem) {
      for (var i = 0; i < aArray.length; i++)
        if (aItem == aArray[i])
          return true;
      return false;
    }
    
    for (var i = 0; i < this.cssRules.length; i++)
    {
      var rule = this.cssRules[i];
      if (rule.type == kJscsspSTYLE_RULE || rule.type == kJscsspIMPORT_RULE)
        break;
      else if (rule.type == kJscsspVARIABLES_RULE &&
               (!rule.media.length || ItemFoundInArray(rule.media, aMedium))) {
        
        for (var j = 0; j < rule.declarations.length; j++) {
          var valueText = "";
          for (var k = 0; k < rule.declarations[j].values.length; k++)
            valueText += (k ? " " : "") + rule.declarations[j].values[k].value;
          this.variables[rule.declarations[j].property] = valueText;
        }
      }
    }
  }
};

/* kJscsspCHARSET_RULE */

function jscsspCharsetRule()
{
  this.type = kJscsspCHARSET_RULE;
  this.encoding = null;
  this.parsedCssText = null;
  this.parentStyleSheet = null;
  this.parentRule = null;
}

jscsspCharsetRule.prototype = {

  cssText: function() {
    return "@charset " + this.encoding + ";";
  },

  setCssText: function(val) {
    var sheet = {cssRules: []};
    var parser = new CSSParser(val);
    var token = parser.getToken(false, false);
    if (token.isAtRule("@charset")) {
      if (parser.parseCharsetRule(token, sheet)) {
        var newRule = sheet.cssRules[0];
        this.encoding = newRule.encoding;
        this.parsedCssText = newRule.parsedCssText;
        return;
      }
    }
    throw DOMException.SYNTAX_ERR;
  }
};

/* kJscsspUNKNOWN_RULE */

function jscsspErrorRule(aErrorMsg)
{
  this.error = aErrorMsg ? aErrorMsg : "INVALID"; 
  this.type = kJscsspUNKNOWN_RULE;
  this.parsedCssText = null;
  this.parentStyleSheet = null;
  this.parentRule = null;
}

jscsspErrorRule.prototype = {
  cssText: function() {
    return this.parsedCssText;
  }
};

/* kJscsspCOMMENT */

function jscsspComment()
{
  this.type = kJscsspCOMMENT;
  this.parsedCssText = null;
  this.parentStyleSheet = null;
  this.parentRule = null;
}

jscsspComment.prototype = {
  cssText: function() {
    return this.parsedCssText;
  },

  setCssText: function(val) {
    var parser = new CSSParser(val);
    var token = parser.getToken(true, false);
    if (token.isComment())
      this.parsedCssText = token.value;
    else
      throw DOMException.SYNTAX_ERR;
  }
};

/* kJscsspWHITE_SPACE */

function jscsspWhitespace()
{
  this.type = kJscsspWHITE_SPACE;
  this.parsedCssText = null;
  this.parentStyleSheet = null;
  this.parentRule = null;
}

jscsspWhitespace.prototype = {
  cssText: function() {
    return this.parsedCssText;
  }
};

/* kJscsspIMPORT_RULE */

function jscsspImportRule()
{
  this.type = kJscsspIMPORT_RULE;
  this.parsedCssText = null;
  this.href = null;
  this.media = []; 
  this.parentStyleSheet = null;
  this.parentRule = null;
}

jscsspImportRule.prototype = {
  cssText: function() {
    var mediaString = this.media.join(", ");
    return "@import " + this.href
                      + ((mediaString && mediaString != "all") ? mediaString + " " : "")
                      + ";";
  },

  setCssText: function(val) {
    var sheet = {cssRules: []};
    var parser = new CSSParser(val);
    var token = parser.getToken(true, true);
    if (token.isAtRule("@import")) {
      if (parser.parseImportRule(token, sheet)) {
        var newRule = sheet.cssRules[0];
        this.href = newRule.href;
        this.media = newRule.media;
        this.parsedCssText = newRule.parsedCssText;
        return;
      }
    }
    throw DOMException.SYNTAX_ERR;
  }
};

/* kJscsspNAMESPACE_RULE */

function jscsspNamespaceRule()
{
  this.type = kJscsspNAMESPACE_RULE;
  this.parsedCssText = null;
  this.prefix = null;
  this.url = null;
  this.parentStyleSheet = null;
  this.parentRule = null;
}

jscsspNamespaceRule.prototype = {
  cssText: function() {
    return "@namespace " + (this.prefix ? this.prefix + " ": "")
                        + this.url
                        + ";";
  },

  setCssText: function(val) {
    var sheet = {cssRules: []};
    var parser = new CSSParser(val);
    var token = parser.getToken(true, true);
    if (token.isAtRule("@namespace")) {
      if (parser.parseNamespaceRule(token, sheet)) {
        var newRule = sheet.cssRules[0];
        this.url = newRule.url;
        this.prefix = newRule.prefix;
        this.parsedCssText = newRule.parsedCssText;
        return;
      }
    }
    throw DOMException.SYNTAX_ERR;
  }
};

/* kJscsspSTYLE_DECLARATION */

function jscsspDeclaration()
{
  this.type = kJscsspSTYLE_DECLARATION;
  this.property = null;
  this.values = [];
  this.valueText = null;
  this.priority = null;
  this.parsedCssText = null;
  this.parentStyleSheet = null;
  this.parentRule = null;
}

jscsspDeclaration.prototype = {
  kCOMMA_SEPARATED: {
    "cursor": true,
    "font-family": true,
    "voice-family": true,
    "background-image": true
  },

  kUNMODIFIED_COMMA_SEPARATED_PROPERTIES: {
    "text-shadow": true,
    "box-shadow": true,
    "-moz-transition": true,
    "-moz-transition-property": true,
    "-moz-transition-duration": true,
    "-moz-transition-timing-function": true,
    "-moz-transition-delay": true
  },

  cssText: function() {
    var prefixes = CssInspector.prefixesForProperty(this.property);

    if (this.property in this.kUNMODIFIED_COMMA_SEPARATED_PROPERTIES) {
      if (prefixes) {
        var rv = "";
        for (var propertyIndex = 0; propertyIndex < prefixes.length; propertyIndex++) {
          var property = prefixes[propertyIndex];
          rv += (propertyIndex ? gTABS : "") + property + ": ";
          rv += this.valueText + (this.priority ? " !important" : "") + ";";
          rv += ((prefixes.length > 1 && propertyIndex != prefixes.length -1) ? "\n" : "");
        }
        return rv;
      }
      return this.property + ": " + this.valueText +
             (this.priority ? " !important" : "") + ";"
    }

    if (prefixes) {
      var rv = "";
      for (var propertyIndex = 0; propertyIndex < prefixes.length; propertyIndex++) {
        var property = prefixes[propertyIndex];
        rv += (propertyIndex ? gTABS : "") + property + ": ";
        var separator = (property in this.kCOMMA_SEPARATED) ? ", " : " ";
        for (var i = 0; i < this.values.length; i++)
          if (this.values[i].cssText() != null)
            rv += (i ? separator : "") + this.values[i].cssText();
          else
            return null;
        rv += (this.priority ? " !important" : "") + ";" +
              ((prefixes.length > 1 && propertyIndex != prefixes.length -1) ? "\n" : "");
      }
      return rv;
    }

    var rv = this.property + ": ";
    var separator = (this.property in this.kCOMMA_SEPARATED) ? ", " : " ";
    var extras = {"webkit": false, "presto": false, "trident": false, "generic": false }
    for (var i = 0; i < this.values.length; i++) {
      var v = this.values[i].cssText();
      if (v != null) {
        var paren = v.indexOf("(");
        var kwd = v;
        if (paren != -1)
          kwd = v.substr(0, paren);
        if (kwd in kCSS_VENDOR_VALUES) {
          for (var j in kCSS_VENDOR_VALUES[kwd]) {
            extras[j] = extras[j] || (kCSS_VENDOR_VALUES[kwd][j] != "");
          }
        }
        rv += (i ? separator : "") + v;
      }
      else
        return null;
    }
    rv += (this.priority ? " !important" : "") + ";";

    for (var j in extras) {
      if (extras[j]) {
        var str = "\n" + gTABS +  this.property + ": ";
        for (var i = 0; i < this.values.length; i++) {
          var v = this.values[i].cssText();
          if (v != null) {
            var paren = v.indexOf("(");
            var kwd = v;
            if (paren != -1)
              kwd = v.substr(0, paren);
            if (kwd in kCSS_VENDOR_VALUES) {
              functor = kCSS_VENDOR_VALUES[kwd][j];
              if (functor) {
                v = (typeof functor == "string") ? functor : functor(v, j);
                if (!v) {
                  str = null;
                  break;
                }
              }
            }
            str += (i ? separator : "") + v;
          }
          else
            return null;
        }
        if (str)
          rv += str + ";"
        else
          rv += "\n" + gTABS + "/* Impossible to translate property " + this.property + " for " + j + " */";
      }
    }
    return rv;
  },

  setCssText: function(val) {
    var declarations = [];
    var parser = new CSSParser(val);
    var token = parser.getToken(true, true);
    if (parser.parseDeclaration(token, declarations, true, true, null)
        && declarations.length
        && declarations[0].type == kJscsspSTYLE_DECLARATION) {
      var newDecl = declarations.cssRules[0];
      this.property = newDecl.property;
      this.value = newDecl.value;
      this.priority = newDecl.priority;
      this.parsedCssText = newRule.parsedCssText;
      return;
    }
    throw DOMException.SYNTAX_ERR;
  }
};

/* kJscsspFONT_FACE_RULE */

function jscsspFontFaceRule()
{
  this.type = kJscsspFONT_FACE_RULE;
  this.parsedCssText = null;
  this.descriptors = [];
  this.parentStyleSheet = null;
  this.parentRule = null;
}

jscsspFontFaceRule.prototype = {
  cssText: function() {
    var rv = gTABS + "@font-face {\n";
    var preservedGTABS = gTABS;
    gTABS += "  ";
    for (var i = 0; i < this.descriptors.length; i++)
      rv += gTABS + this.descriptors[i].cssText() + "\n";
    gTABS = preservedGTABS;
    return rv + gTABS + "}";
  },

  setCssText: function(val) {
    var sheet = {cssRules: []};
    var parser = new CSSParser(val);
    var token = parser.getToken(true, true);
    if (token.isAtRule("@font-face")) {
      if (parser.parseFontFaceRule(token, sheet)) {
        var newRule = sheet.cssRules[0];
        this.descriptors = newRule.descriptors;
        this.parsedCssText = newRule.parsedCssText;
        return;
      }
    }
    throw DOMException.SYNTAX_ERR;
  }
};

/* kJscsspKEYFRAMES_RULE */
function jscsspKeyframesRule()
{
  this.type = kJscsspKEYFRAMES_RULE;
  this.parsedCssText = null;
  this.cssRules = [];
  this.name = null;
  this.parentStyleSheet = null;
  this.parentRule = null;
}

jscsspKeyframesRule.prototype = {
  cssText: function() {
    var rv = gTABS
               + "@keyframes "
               + this.name + " {\n";
    var preservedGTABS = gTABS;
    gTABS += "  ";
    for (var i = 0; i < this.cssRules.length; i++)
      rv += gTABS + this.cssRules[i].cssText() + "\n";
    gTABS = preservedGTABS;
    rv += gTABS + "}\n";
    return rv;
  },

  setCssText: function(val) {
    var sheet = {cssRules: []};
    var parser = new CSSParser(val);
    var token = parser.getToken(true, true);
    if (token.isAtRule("@keyframes")) {
      if (parser.parseKeyframesRule(token, sheet)) {
        var newRule = sheet.cssRules[0];
        this.cssRules = newRule.cssRules;
        this.name = newRule.name;
        this.parsedCssText = newRule.parsedCssText;
        return;
      }
    }
    throw DOMException.SYNTAX_ERR;
  }
};

/* kJscsspKEYFRAME_RULE */
function jscsspKeyframeRule()
{
  this.type = kJscsspKEYFRAME_RULE;
  this.parsedCssText = null;
  this.declarations = []
  this.keyText = null;
  this.parentStyleSheet = null;
  this.parentRule = null;
}

jscsspKeyframeRule.prototype = {
  cssText: function() {
    var rv = this.keyText + " {\n";
    var preservedGTABS = gTABS;
    gTABS += "  ";
    for (var i = 0; i < this.declarations.length; i++) {
      var declText = this.declarations[i].cssText();
      if (declText)
        rv += gTABS + this.declarations[i].cssText() + "\n";
    }
    gTABS = preservedGTABS;
    return rv + gTABS + "}";
  },

  setCssText: function(val) {
    var sheet = {cssRules: []};
    var parser = new CSSParser(val);
    var token = parser.getToken(true, true);
    if (!token.isNotNull()) {
      if (parser.parseKeyframeRule(token, sheet, false)) {
        var newRule = sheet.cssRules[0];
        this.keyText = newRule.keyText;
        this.declarations = newRule.declarations;
        this.parsedCssText = newRule.parsedCssText;
        return;
      }
    }
    throw DOMException.SYNTAX_ERR;
  }
};

/* kJscsspMEDIA_RULE */

function jscsspMediaRule()
{
  this.type = kJscsspMEDIA_RULE;
  this.parsedCssText = null;
  this.cssRules = [];
  this.media = [];
  this.parentStyleSheet = null;
  this.parentRule = null;
}

jscsspMediaRule.prototype = {
  cssText: function() {
    var rv = gTABS + "@media " + this.media.join(", ") + " {\n";
    var preservedGTABS = gTABS;
    gTABS += "  ";
    for (var i = 0; i < this.cssRules.length; i++)
      rv += gTABS + this.cssRules[i].cssText() + "\n";
    gTABS = preservedGTABS;
    return rv + gTABS + "}";
  },

  setCssText: function(val) {
    var sheet = {cssRules: []};
    var parser = new CSSParser(val);
    var token = parser.getToken(true, true);
    if (token.isAtRule("@media")) {
      if (parser.parseMediaRule(token, sheet)) {
        var newRule = sheet.cssRules[0];
        this.cssRules = newRule.cssRules;
        this.media = newRule.media;
        this.parsedCssText = newRule.parsedCssText;
        return;
      }
    }
    throw DOMException.SYNTAX_ERR;
  }
};

/* kJscsspSTYLE_RULE */

function jscsspStyleRule()
{
  this.type = kJscsspSTYLE_RULE;
  this.parsedCssText = null;
  this.declarations = []
  this.mSelectorText = null;
  this.parentStyleSheet = null;
  this.parentRule = null;
}

jscsspStyleRule.prototype = {
  cssText: function() {
    var rv = this.mSelectorText + " {\n";
    var preservedGTABS = gTABS;
    gTABS += "  ";
    for (var i = 0; i < this.declarations.length; i++) {
      var declText = this.declarations[i].cssText();
      if (declText)
        rv += gTABS + this.declarations[i].cssText() + "\n";
    }
    gTABS = preservedGTABS;
    return rv + gTABS + "}";
  },

  setCssText: function(val) {
    var sheet = {cssRules: []};
    var parser = new CSSParser(val);
    var token = parser.getToken(true, true);
    if (!token.isNotNull()) {
      if (parser.parseStyleRule(token, sheet, false)) {
        var newRule = sheet.cssRules[0];
        this.mSelectorText = newRule.mSelectorText;
        this.declarations = newRule.declarations;
        this.parsedCssText = newRule.parsedCssText;
        return;
      }
    }
    throw DOMException.SYNTAX_ERR;
  },

  selectorText: function() {
    return this.mSelectorText;
  },

  setSelectorText: function(val) {
    var parser = new CSSParser(val);
    var token = parser.getToken(true, true);
    if (!token.isNotNull()) {
      var s = parser.parseSelector(token, true);
      if (s) {
        this.mSelectorText = s.selector;
        return;
      }
    }
    throw DOMException.SYNTAX_ERR;
  }
};

/* kJscsspPAGE_RULE */

function jscsspPageRule()
{
  this.type = kJscsspPAGE_RULE;
  this.parsedCssText = null;
  this.pageSelector = null;
  this.declarations = [];
  this.parentStyleSheet = null;
  this.parentRule = null;
}

jscsspPageRule.prototype = {
  cssText: function() {
    var rv = gTABS + "@page "
                   + (this.pageSelector ? this.pageSelector + " ": "")
                   + "{\n";
    var preservedGTABS = gTABS;
    gTABS += "  ";
    for (var i = 0; i < this.declarations.length; i++)
      rv += gTABS + this.declarations[i].cssText() + "\n";
    gTABS = preservedGTABS;
    return rv + gTABS + "}";
  },

  setCssText: function(val) {
    var sheet = {cssRules: []};
    var parser = new CSSParser(val);
    var token = parser.getToken(true, true);
    if (token.isAtRule("@page")) {
      if (parser.parsePageRule(token, sheet)) {
        var newRule = sheet.cssRules[0];
        this.pageSelector = newRule.pageSelector;
        this.declarations = newRule.declarations;
        this.parsedCssText = newRule.parsedCssText;
        return;
      }
    }
    throw DOMException.SYNTAX_ERR;
  }
};

/* kJscsspVARIABLES_RULE */

function jscsspVariablesRule()
{
  this.type = kJscsspVARIABLES_RULE;
  this.parsedCssText = null;
  this.declarations = [];
  this.parentStyleSheet = null;
  this.parentRule = null;
  this.media = null;
}

jscsspVariablesRule.prototype = {
  cssText: function() {
    var rv = gTABS + "@variables " +
                     (this.media.length ? this.media.join(", ") + " " : "") +
                     "{\n";
    var preservedGTABS = gTABS;
    gTABS += "  ";
    for (var i = 0; i < this.declarations.length; i++)
      rv += gTABS + this.declarations[i].cssText() + "\n";
    gTABS = preservedGTABS;
    return rv + gTABS + "}";
  },

  setCssText: function(val) {
    var sheet = {cssRules: []};
    var parser = new CSSParser(val);
    var token = parser.getToken(true, true);
    if (token.isAtRule("@variables")) {
      if (parser.parseVariablesRule(token, sheet)) {
        var newRule = sheet.cssRules[0];
        this.declarations = newRule.declarations;
        this.parsedCssText = newRule.parsedCssText;
        return;
      }
    }
    throw DOMException.SYNTAX_ERR;
  }
};

var kJscsspINHERIT_VALUE = 0;
var kJscsspPRIMITIVE_VALUE = 1;
var kJscsspVARIABLE_VALUE = 4;

function jscsspVariable(aType, aSheet)
{
  this.value = "";
  this.type = aType;
  this.name  = null;
  this.parentRule = null;
  this.parentStyleSheet = aSheet;
}

jscsspVariable.prototype = {
  cssText: function() {
    if (this.type == kJscsspVARIABLE_VALUE)
      return this.resolveVariable(this.name, this.parentRule, this.parentStyleSheet);
    else
      return this.value;
  },

  setCssText: function(val) {
    if (this.type == kJscsspVARIABLE_VALUE)
      throw DOMException.SYNTAX_ERR;
    else
      this.value = val;
  },

  resolveVariable: function(aName, aRule, aSheet)
  {
    if (aName.toLowerCase() in aSheet.variables)
      return aSheet.variables[aName.toLowerCase()];
    return null;
  }
};

function ParseURL(buffer) {
  var result = { };
  result.protocol = "";
  result.user = "";
  result.password = "";
  result.host = "";
  result.port = "";
  result.path = "";
  result.query = "";

  var section = "PROTOCOL";
  var start = 0;
  var wasSlash = false;

  while(start < buffer.length) {
    if(section == "PROTOCOL") {
      if(buffer.charAt(start) == ':') {
        section = "AFTER_PROTOCOL";
        start++;
      } else if(buffer.charAt(start) == '/' && result.protocol.length() == 0) { 
        section = PATH;
      } else {
        result.protocol += buffer.charAt(start++);
      }
    } else if(section == "AFTER_PROTOCOL") {
      if(buffer.charAt(start) == '/') {
    if(!wasSlash) {
          wasSlash = true;
    } else {
          wasSlash = false;
          section = "USER";
    }
        start ++;
      } else {
        throw new ParseException("Protocol shell be separated with 2 slashes");
      }       
    } else if(section == "USER") {
      if(buffer.charAt(start) == '/') {
        result.host = result.user;
        result.user = "";
        section = "PATH";
      } else if(buffer.charAt(start) == '?') {
        result.host = result.user;
        result.user = "";
        section = "QUERY";
        start++;
      } else if(buffer.charAt(start) == ':') {
        section = "PASSWORD";
        start++;
      } else if(buffer.charAt(start) == '@') {
        section = "HOST";
        start++;
      } else {
        result.user += buffer.charAt(start++);
      }
    } else if(section == "PASSWORD") {
      if(buffer.charAt(start) == '/') {
        result.host = result.user;
        result.port = result.password;
        result.user = "";
        result.password = "";
        section = "PATH";
      } else if(buffer.charAt(start) == '?') {
        result.host = result.user;
        result.port = result.password;
        result.user = "";
        result.password = "";
        section = "QUERY";
        start ++;
      } else if(buffer.charAt(start) == '@') {
        section = "HOST";
        start++;
      } else {
        result.password += buffer.charAt(start++);
      }
    } else if(section == "HOST") {
      if(buffer.charAt(start) == '/') {
        section = "PATH";
      } else if(buffer.charAt(start) == ':') {
        section = "PORT";
        start++;
      } else if(buffer.charAt(start) == '?') {
        section = "QUERY";
        start++;
      } else {
        result.host += buffer.charAt(start++);
      }
    } else if(section == "PORT") {
      if(buffer.charAt(start) == '/') {
        section = "PATH";
      } else if(buffer.charAt(start) == '?') {
        section = "QUERY";
        start++;
      } else {
        result.port += buffer.charAt(start++);
      }
    } else if(section == "PATH") {
      if(buffer.charAt(start) == '?') {
    section = "QUERY";
    start ++;
      } else {
    result.path += buffer.charAt(start++);
      }
    } else if(section == "QUERY") {
      result.query += buffer.charAt(start++);
    }
  }

  if(section == "PROTOCOL") {
    result.host = result.protocol;
    result.protocol = "http";
  } else if(section == "AFTER_PROTOCOL") {
    throw new ParseException("Invalid url");
  } else if(section == "USER") {
    result.host = result.user;
    result.user = "";
  } else if(section == "PASSWORD") {
    result.host = result.user;
    result.port = result.password;
    result.user = "";
    result.password = "";
  }

  return result;
}

function ParseException(description) {
    this.description = description;
}

function CountLF(s)
{
  var nCR = s.match( /\n/g );
  return nCR ? nCR.length + 1 : 1;
}


function FilterLinearGradientForOutput(aValue, aEngine)
{
  if (aEngine == "generic")
    return aValue.substr(5);

  if (aEngine == "webkit")
    return aValue.replace( /\-moz\-/g , "-webkit-")

  if (aEngine != "webkit20110101")
    return "";

  var g = CssInspector.parseBackgroundImages(aValue)[0];

  var cancelled = false;
  var str = "-webkit-gradient(linear, ";
  var position = ("position" in g.value) ? g.value.position.toLowerCase() : "";
  var angle    = ("angle" in g.value) ? g.value.angle.toLowerCase() : "";
  // normalize angle
  if (angle) {
    var match = angle.match(/^([0-9\-\.\\+]+)([a-z]*)/);
    var angle = parseFloat(match[1]);
    var unit  = match[2];
    switch (unit) {
      case "grad": angle = angle * 90 / 100; break;
      case "rad":  angle = angle * 180 / Math.PI; break;
      default: break;
    }
    while (angle < 0)
      angle += 360;
    while (angle >= 360)
      angle -= 360;
  }
  // get startpoint w/o keywords
  var startpoint = [];
  var endpoint = [];
  if (position != "") {
    if (position == "center")
      position = "center center";
    startpoint = position.split(" ");
    if (angle == "" && angle != 0) {
      // no angle, then we just turn the point 180 degrees around center
      switch (startpoint[0]) {
        case "left":   endpoint.push("right"); break;
        case "center": endpoint.push("center"); break;
        case "right":  endpoint.push("left"); break;
        default: {
            var match = startpoint[0].match(/^([0-9\-\.\\+]+)([a-z]*)/);
            var v     = parseFloat(match[0]);
            var unit  = match[1];
            if (unit == "%") {
              endpoint.push((100-v) + "%");
            }
            else
              cancelled = true;
          }
          break;
      }
      if (!cancelled)
        switch (startpoint[1]) {
          case "top":    endpoint.push("bottom"); break;
          case "center": endpoint.push("center"); break;
          case "bottom": endpoint.push("top"); break;
          default: {
              var match = startpoint[1].match(/^([0-9\-\.\\+]+)([a-z]*)/);
              var v     = parseFloat(match[0]);
              var unit  = match[1];
              if (unit == "%") {
                endpoint.push((100-v) + "%");
              }
              else
                cancelled = true;
            }
            break;
        }
    }
    else {
      switch (angle) {
        case 0:    endpoint.push("right"); endpoint.push(startpoint[1]); break;
        case 90:   endpoint.push(startpoint[0]); endpoint.push("top"); break;
        case 180:  endpoint.push("left"); endpoint.push(startpoint[1]); break;
        case 270:  endpoint.push(startpoint[0]); endpoint.push("bottom"); break;
        default:     cancelled = true; break;
      }
    }
  }
  else {
    // no position defined, we accept only vertical and horizontal
    if (angle == "")
      angle = 270;
    switch (angle) {
      case 0:    startpoint= ["left", "center"];   endpoint = ["right", "center"]; break;
      case 90:   startpoint= ["center", "bottom"]; endpoint = ["center", "top"]; break;
      case 180:  startpoint= ["right", "center"];  endpoint = ["left", "center"]; break;
      case 270:  startpoint= ["center", "top"];    endpoint = ["center", "bottom"]; break;
      default:     cancelled = true; break;
    }
  }

  if (cancelled)
    return "";

  str += startpoint.join(" ") + ", " + endpoint.join(" ");
  if (!g.value.stops[0].position)
    g.value.stops[0].position = "0%";
  if (!g.value.stops[g.value.stops.length-1].position)
    g.value.stops[g.value.stops.length-1].position = "100%";
  var current = 0;
  for (var i = 0; i < g.value.stops.length && !cancelled; i++) {
    var s = g.value.stops[i];
    if (s.position) {
      if (s.position.indexOf("%") == -1) {
        cancelled = true;
        break;
      }
    }
    else {
      var j = i + 1;
      while (j < g.value.stops.length && !g.value.stops[j].position)
        j++;
      var inc = parseFloat(g.value.stops[j].position) - current;
      for (var k = i; k < j; k++) {
        g.value.stops[k].position = (current + inc * (k - i + 1) / (j - i + 1)) + "%";
      }
    }
    current = parseFloat(s.position);
    str += ", color-stop(" + (parseFloat(current) / 100) + ", " + s.color + ")";
  }

  if (cancelled)
    return "";
  return str + ")";
}

function FilterRadialGradientForOutput(aValue, aEngine)
{
  if (aEngine == "generic")
    return aValue.substr(5);

  else if (aEngine == "webkit")
    return aValue.replace( /\-moz\-/g , "-webkit-")

  else if (aEngine != "webkit20110101")
    return "";

  var g = CssInspector.parseBackgroundImages(aValue)[0];

  var shape = ("shape" in g.value) ? g.value.shape : "";
  var size  = ("size"  in g.value) ? g.value.size : "";
  if (shape != "circle"
      || (size != "farthest-corner" && size != "cover"))
    return "";

  if (g.value.stops.length < 2
      || !("position" in g.value.stops[0])
      || !g.value.stops[g.value.stops.length - 1].position
      || !("position" in g.value.stops[0])
      || !g.value.stops[g.value.stops.length - 1].position)
    return "";

  for (var i = 0; i < g.value.stops.length; i++) {
    var s = g.value.stops[i];
    if (("position" in s) && s.position && s.position.indexOf("px") == -1)
      return "";
  }

  var str = "-webkit-gradient(radial, ";
  var position  = ("position"  in g.value) ? g.value.position : "center center";
  str += position + ", " +  parseFloat(g.value.stops[0].position) + ", ";
  str += position + ", " +  parseFloat(g.value.stops[g.value.stops.length - 1].position);

  // at this point we're sure to deal with pixels
  var current = parseFloat(g.value.stops[0].position);
  for (var i = 0; i < g.value.stops.length; i++) {
    var s = g.value.stops[i];
    if (!("position" in s) || !s.position) {
      var j = i + 1;
      while (j < g.value.stops.length && !g.value.stops[j].position)
        j++;
      var inc = parseFloat(g.value.stops[j].position) - current;
      for (var k = i; k < j; k++) {
        g.value.stops[k].position = (current + inc * (k - i + 1) / (j - i + 1)) + "px";
      }
    }
    current = parseFloat(s.position);
    var c = (current - parseFloat(g.value.stops[0].position)) /
            (parseFloat(g.value.stops[g.value.stops.length - 1].position) - parseFloat(g.value.stops[0].position));
    str += ", color-stop(" + c + ", " + s.color + ")";
  }
  str += ")"
  return str;
}

function FilterRepeatingGradientForOutput(aValue, aEngine)
{
  if (aEngine == "generic")
    return aValue.substr(5);

  else if (aEngine == "webkit")
    return aValue.replace( /\-moz\-/g , "-webkit-")

  return "";
}

/**
 * modalEffects.js v1.0.0
 * http://www.codrops.com
 *
 * Licensed under the MIT license.
 * https://www.opensource.org/licenses/mit-license.php
 * 
 * Copyright 2013, Codrops
 * http://www.codrops.com
 */
var ModalEffects = (function() {

	function init() {

		var overlay = document.querySelector( '.md-overlay' );

		[].slice.call( document.querySelectorAll( '.md-trigger' ) ).forEach( function( el, i ) {

			var modal = document.querySelector( '#' + el.getAttribute( 'data-modal' ) ),
				close = modal.querySelector( '.md-close' );

			function removeModal( hasPerspective ) {
				classie.remove( modal, 'md-show' );

				if( hasPerspective ) {
					classie.remove( document.documentElement, 'md-perspective' );
				}
			}

			function removeModalHandler() {
				removeModal( classie.has( el, 'md-setperspective' ) ); 
			}

			el.addEventListener( 'click', function( ev ) {
				classie.add( modal, 'md-show' );
				overlay.removeEventListener( 'click', removeModalHandler );
				overlay.addEventListener( 'click', removeModalHandler );

				if( classie.has( el, 'md-setperspective' ) ) {
					setTimeout( function() {
						classie.add( document.documentElement, 'md-perspective' );
					}, 25 );
				}
			});

			close.addEventListener( 'click', function( ev ) {
				ev.stopPropagation();
				removeModalHandler();
			});

		} );

	}

	init();

})();



            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.

Console