Commits

Joey Smith committed 4018929 Merge

Merge pull request #76 from tml/danbeam-master

Fix danbeam's PR

Comments (0)

Files changed (13)

ports/js/cssmin.js

 /**
  * cssmin.js
  * Author: Stoyan Stefanov - http://phpied.com/
+ * Contributor: Dan Beam - http://danbeam.org/
  * This is a JavaScript port of the CSS minification tool
  * distributed with YUICompressor, itself a port
  * of the cssmin utility by Isaac Schlueter - http://foohack.com/
 * YUI Compressor
 * http://developer.yahoo.com/yui/compressor/
 * Author: Julien Lecomte - http://www.julienlecomte.net/
-* Copyright (c) 2011 Yahoo! Inc. All rights reserved.
+* Copyright (c) 2013 Yahoo! Inc. All rights reserved.
 * The copyrights embodied in the content of this file are licensed
 * by Yahoo! Inc. under the BSD (revised) open source license.
 */
         m,
         preserver,
         token,
-        pattern = /url\(\s*(["']?)data\:/g;
+        pattern = /url\(\s*(["']?)data\:/gi;
 
     // Since we need to account for non-base64 data urls, we need to handle 
     // ' and ) being part of the data string. Hence switching to indexOf,
     css = css.replace(/\s+([!{};:>+\(\)\],])/g, '$1');
     css = css.replace(/___YUICSSMIN_PSEUDOCLASSCOLON___/g, ":");
 
-    // retain space for special IE6 cases
-    css = css.replace(/:first-(line|letter)(\{|,)/g, ":first-$1 $2");
+    // retain space for special IE6 cases and lowercase
+    css = css.replace(/:first-(line|letter)(\{|,)/gi, function(all, $1, $2) {
+        return ":first-" + $1.toLowerCase() + " " + $2;
+    });
 
     // no space after the end of a preserved comment
     css = css.replace(/\*\/ /g, '*/');
 
-
-    // If there is a @charset, then only allow one, and push to the top of the file.
-    css = css.replace(/^(.*)(@charset "[^"]*";)/gi, '$2$1');
-    css = css.replace(/^(\s*@charset [^;]+;\s*)+/gi, '$1');
+    // If there is a @charset, then only allow one, and push to the top of the file (and make lowercase).
+    css = css.replace(/^(.*)(@charset)( "[^"]*";)/gi, function(all, $1, $2, $3) {
+        return $2.toLowerCase() + $3 + $1;
+    });
+    css = css.replace(/^((\s*)(@charset)( [^;]+;\s*))+/gi, function(all, $1, $2, $3, $4) {
+        return $2 + $3.toLowerCase() + $4;
+    });
 
     // Put the space back in some cases, to support stuff like
     // @media screen and (-webkit-min-device-pixel-ratio:0){
     css = css.replace(/\band\(/gi, "and (");
 
+    // lowercase some popular @directives (@charset is done right above)
+    css = css.replace(/@(font-face|import|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?keyframe|media|page|namespace)/gi, function(all, $1) {
+        return '@' + $1.toLowerCase();
+    });
+
+    // lowercase some more common pseudo-elements
+    css = css.replace(/:(active|after|before|checked|disabled|empty|enabled|first-(?:child|of-type)|focus|hover|last-(?:child|of-type)|link|only-(?:child|of-type)|root|:selection|target|visited)/gi, function(all, $1) {
+        return ':' + $1.toLowerCase();
+    });
+
+    // lowercase some more common functions
+    css = css.replace(/:(lang|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|(?:-(?:moz|webkit)-)?any)\(/gi, function(all, $1) {
+        return ':' + $1.toLowerCase() + '(';
+    });
+
+    // lower case some common function that can be values
+    // NOTE: rgb() isn't useful as we replace with #hex later, as well as and() is already done for us
+    css = css.replace(/([:,\( ]\s*)(attr|color-stop|from|rgba|to|url|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?(?:calc|max|min|(?:repeating-)?(?:linear|radial)-gradient)|-webkit-gradient)/gi, function(all, $1, $2) {
+        return $1 + $2.toLowerCase();
+    });
 
     // Remove the spaces after the things that should not have spaces after them.
     css = css.replace(/([!{}:;>+\(\[,])\s+/g, '$1');
     css = css.replace(/;+\}/g, "}");
 
     // Replace 0(px,em,%) with 0.
-    css = css.replace(/([\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)/gi, "$1$2");
+    css = css.replace(/(^|[^0-9])(?:0?\.)?0(?:px|em|%|in|cm|mm|pc|pt|ex|deg|g?rad|m?s|k?hz)/gi, "$10");
 
     // Replace 0 0 0 0; with 0.
     css = css.replace(/:0 0 0 0(;|\})/g, ":0$1");

src/com/yahoo/platform/yui/compressor/CssCompressor.java

  * Author: Julien Lecomte -  http://www.julienlecomte.net/
  * Author: Isaac Schlueter - http://foohack.com/
  * Author: Stoyan Stefanov - http://phpied.com/
- * Copyright (c) 2011 Yahoo! Inc.  All rights reserved.
+ * Contributor: Dan Beam - http://danbeam.org/
+ * Copyright (c) 2013 Yahoo! Inc.  All rights reserved.
  * The copyrights embodied in the content of this file are licensed
  * by Yahoo! Inc. under the BSD (revised) open source license.
  */
     // Leave data urls alone to increase parse performance.
     protected String extractDataUrls(String css, ArrayList preservedTokens) {
 
-    	int maxIndex = css.length() - 1;
+        int maxIndex = css.length() - 1;
         int appendIndex = 0;
 
-    	StringBuffer sb = new StringBuffer();
+        StringBuffer sb = new StringBuffer();
 
-        Pattern p = Pattern.compile("url\\(\\s*([\"']?)data\\:");
+        Pattern p = Pattern.compile("(?i)url\\(\\s*([\"']?)data\\:");
         Matcher m = p.matcher(css);
-        
-        /* 
-         * Since we need to account for non-base64 data urls, we need to handle 
+
+        /*
+         * Since we need to account for non-base64 data urls, we need to handle
          * ' and ) being part of the data string. Hence switching to indexOf,
          * to determine whether or not we have matching string terminators and
          * handling sb appends directly, instead of using matcher.append* methods.
 
         while (m.find()) {
 
-        	int startIndex = m.start() + 4;  	// "url(".length()
-    		String terminator = m.group(1);     // ', " or empty (not quoted)
-    		
-    		if (terminator.length() == 0) {
-    		 	terminator = ")";
-    		}
-
-    		boolean foundTerminator = false;
-
-    		int endIndex = m.end() - 1;
-    		while(foundTerminator == false && endIndex+1 <= maxIndex) {
-    			endIndex = css.indexOf(terminator, endIndex+1);
-
-    			if ((endIndex > 0) && (css.charAt(endIndex-1) != '\\')) {
-    				foundTerminator = true;
-    				if (!")".equals(terminator)) {
-    					endIndex = css.indexOf(")", endIndex); 
-    				}
-    			}
-    		}
-
-    		// Enough searching, start moving stuff over to the buffer
-			sb.append(css.substring(appendIndex, m.start()));
-
-    		if (foundTerminator) {
-    			String token = css.substring(startIndex, endIndex);
-    			token = token.replaceAll("\\s+", "");
-	    		preservedTokens.add(token);
-
-	    		String preserver = "url(___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___)";
-	    		sb.append(preserver);
-
-	    		appendIndex = endIndex + 1;
-    		} else {
-    			// No end terminator found, re-add the whole match. Should we throw/warn here?
-    			sb.append(css.substring(m.start(), m.end()));
-    			appendIndex = m.end();
-    		}
+            int startIndex = m.start() + 4;      // "url(".length()
+            String terminator = m.group(1);     // ', " or empty (not quoted)
+
+            if (terminator.length() == 0) {
+                 terminator = ")";
+            }
+
+            boolean foundTerminator = false;
+
+            int endIndex = m.end() - 1;
+            while(foundTerminator == false && endIndex+1 <= maxIndex) {
+                endIndex = css.indexOf(terminator, endIndex+1);
+
+                if ((endIndex > 0) && (css.charAt(endIndex-1) != '\\')) {
+                    foundTerminator = true;
+                    if (!")".equals(terminator)) {
+                        endIndex = css.indexOf(")", endIndex);
+                    }
+                }
+            }
+
+            // Enough searching, start moving stuff over to the buffer
+            sb.append(css.substring(appendIndex, m.start()));
+
+            if (foundTerminator) {
+                String token = css.substring(startIndex, endIndex);
+                token = token.replaceAll("\\s+", "");
+                preservedTokens.add(token);
+
+                String preserver = "url(___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___)";
+                sb.append(preserver);
+
+                appendIndex = endIndex + 1;
+            } else {
+                // No end terminator found, re-add the whole match. Should we throw/warn here?
+                sb.append(css.substring(m.start(), m.end()));
+                appendIndex = m.end();
+            }
         }
 
         sb.append(css.substring(appendIndex));
         css = css.replaceAll("___YUICSSMIN_PSEUDOCLASSCOLON___", ":");
 
         // retain space for special IE6 cases
-        css = css.replaceAll(":first\\-(line|letter)(\\{|,)", ":first-$1 $2");
+        sb = new StringBuffer();
+        p = Pattern.compile("(?i):first\\-(line|letter)(\\{|,)");
+        m = p.matcher(css);
+        while (m.find()) {
+            m.appendReplacement(sb, ":first-" + m.group(1).toLowerCase() + " " + m.group(2));
+        }
+        m.appendTail(sb);
+        css = sb.toString();
 
         // no space after the end of a preserved comment
         css = css.replaceAll("\\*/ ", "*/");
 
-        // If there is a @charset, then only allow one, and push to the top of the file.
-        css = css.replaceAll("^(.*)(@charset \"[^\"]*\";)", "$2$1");
-        css = css.replaceAll("^(\\s*@charset [^;]+;\\s*)+", "$1");
+        // If there are multiple @charset directives, push them to the top of the file.
+        sb = new StringBuffer();
+        p = Pattern.compile("(?i)^(.*)(@charset)( \"[^\"]*\";)");
+        m = p.matcher(css);
+        while (m.find()) {
+            m.appendReplacement(sb, m.group(2).toLowerCase() + m.group(3) + m.group(1));
+        }
+        m.appendTail(sb);
+        css = sb.toString();
+
+        // When all @charset are at the top, remove the second and after (as they are completely ignored).
+        sb = new StringBuffer();
+        p = Pattern.compile("(?i)^((\\s*)(@charset)( [^;]+;\\s*))+");
+        m = p.matcher(css);
+        while (m.find()) {
+            m.appendReplacement(sb, m.group(2) + m.group(3).toLowerCase() + m.group(4));
+        }
+        m.appendTail(sb);
+        css = sb.toString();
+
+        // lowercase some popular @directives (@charset is done right above)
+        sb = new StringBuffer();
+        p = Pattern.compile("(?i)@(font-face|import|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?keyframe|media|page|namespace)");
+        m = p.matcher(css);
+        while (m.find()) {
+            m.appendReplacement(sb, '@' + m.group(1).toLowerCase());
+        }
+        m.appendTail(sb);
+        css = sb.toString();
+    
+        // lowercase some more common pseudo-elements
+        sb = new StringBuffer();
+        p = Pattern.compile("(?i):(active|after|before|checked|disabled|empty|enabled|first-(?:child|of-type)|focus|hover|last-(?:child|of-type)|link|only-(?:child|of-type)|root|:selection|target|visited)");
+        m = p.matcher(css);
+        while (m.find()) {
+            m.appendReplacement(sb, ':' + m.group(1).toLowerCase());
+        }
+        m.appendTail(sb);
+        css = sb.toString();
+    
+        // lowercase some more common functions
+        sb = new StringBuffer();
+        p = Pattern.compile("(?i):(lang|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|(?:-(?:moz|webkit)-)?any)\\(");
+        m = p.matcher(css);
+        while (m.find()) {
+            m.appendReplacement(sb, ':' + m.group(1).toLowerCase() + '(');
+        }
+        m.appendTail(sb);
+        css = sb.toString();
+    
+        // lower case some common function that can be values
+        // NOTE: rgb() isn't useful as we replace with #hex later, as well as and() is already done for us right after this
+        sb = new StringBuffer();
+        p = Pattern.compile("(?i)([:,\\( ]\\s*)(attr|color-stop|from|rgba|to|url|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?(?:calc|max|min|(?:repeating-)?(?:linear|radial)-gradient)|-webkit-gradient)");
+        m = p.matcher(css);
+        while (m.find()) {
+            m.appendReplacement(sb, m.group(1) + m.group(2).toLowerCase());
+        }
+        m.appendTail(sb);
+        css = sb.toString();
 
         // Put the space back in some cases, to support stuff like
         // @media screen and (-webkit-min-device-pixel-ratio:0){
-        css = css.replaceAll("\\band\\(", "and (");
+        css = css.replaceAll("(?i)\\band\\(", "and (");
 
         // Remove the spaces after the things that should not have spaces after them.
         css = css.replaceAll("([!{}:;>+\\(\\[,])\\s+", "$1");
         css = css.replaceAll(";+}", "}");
 
         // Replace 0(px,em,%) with 0.
-        css = css.replaceAll("([\\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)", "$1$2");
+        css = css.replaceAll("(?i)(^|[^0-9])(?:0?\\.)?0(?:px|em|%|in|cm|mm|pc|pt|ex|deg|g?rad|m?s|k?hz)", "$10");
 
         // Replace 0 0 0 0; with 0.
         css = css.replaceAll(":0 0 0 0(;|})", ":0$1");
 
         while (m.find(index)) {
 
-        	sb.append(css.substring(index, m.start()));
+            sb.append(css.substring(index, m.start()));
 
-        	boolean isFilter = (m.group(1) != null && !"".equals(m.group(1))); 
+            boolean isFilter = (m.group(1) != null && !"".equals(m.group(1))); 
 
-        	if (isFilter) {
-        		// Restore, as is. Compression will break filters
-        		sb.append(m.group(1) + "#" + m.group(2) + m.group(3) + m.group(4) + m.group(5) + m.group(6) + m.group(7));
-        	} else {
-        		if( m.group(2).equalsIgnoreCase(m.group(3)) &&
+            if (isFilter) {
+                // Restore, as is. Compression will break filters
+                sb.append(m.group(1) + "#" + m.group(2) + m.group(3) + m.group(4) + m.group(5) + m.group(6) + m.group(7));
+            } else {
+                if( m.group(2).equalsIgnoreCase(m.group(3)) &&
                     m.group(4).equalsIgnoreCase(m.group(5)) &&
                     m.group(6).equalsIgnoreCase(m.group(7))) {
 
-	        		// #AABBCC pattern
-	                sb.append("#" + (m.group(3) + m.group(5) + m.group(7)).toLowerCase());
+                    // #AABBCC pattern
+                    sb.append("#" + (m.group(3) + m.group(5) + m.group(7)).toLowerCase());
 
-        		} else {
+                } else {
 
-        			// Non-compressible color, restore, but lower case.
-        			sb.append("#" + (m.group(2) + m.group(3) + m.group(4) + m.group(5) + m.group(6) + m.group(7)).toLowerCase());
-        		}
+                    // Non-compressible color, restore, but lower case.
+                    sb.append("#" + (m.group(2) + m.group(3) + m.group(4) + m.group(5) + m.group(6) + m.group(7)).toLowerCase());
+                }
             }
 
-        	index = m.end(7);
+            index = m.end(7);
         }
 
         sb.append(css.substring(index));
   filter: chroma(color="#FFFFFF");
   background: none repeat scroll 0 0 rgb(255, 0,0);
   alpha: rgba(1, 2, 3, 4);
+  border-color: RGBA(1,2,3,4); /* tests uppercase RGBA() */
   color:#1122aa
 }
 

tests/color.css.min

-.color{me:#7b7b7b;impressed:#fed;again:#abcdef;andagain:#a6c;background-color:#aa66ccc;filter:chroma(color="#FFFFFF");background:none repeat scroll 0 0 red;alpha:rgba(1,2,3,4);color:#12a}#AABBCC{background-color:#fe1;filter:chroma(color = #FFFFFF);color:#412;foo:#0f1 #ABC #abc #123344;border-color:#aa66ccC}.foo #AABBCC{background-color:#fe1;color:#412;border-color:#AbC;filter:chroma(color= #FFFFFF)}.bar,#AABBCC{background-color:#fe1;border-color:#0f1 #abcdef;filter:chroma(color=#11FFFFFF);color:#412}.foo,#AABBCC.foobar{background-color:#fe1;border-color:#0f1 #abcdef #abc;color:#412}@media screen{.bar,#AABBCC{background-color:#fe1;color:#412}}
+.color{me:#7b7b7b;impressed:#fed;again:#abcdef;andagain:#a6c;background-color:#aa66ccc;filter:chroma(color="#FFFFFF");background:none repeat scroll 0 0 red;alpha:rgba(1,2,3,4);border-color:rgba(1,2,3,4);color:#12a}#AABBCC{background-color:#fe1;filter:chroma(color = #FFFFFF);color:#412;foo:#0f1 #ABC #abc #123344;border-color:#aa66ccC}.foo #AABBCC{background-color:#fe1;color:#412;border-color:#AbC;filter:chroma(color= #FFFFFF)}.bar,#AABBCC{background-color:#fe1;border-color:#0f1 #abcdef;filter:chroma(color=#11FFFFFF);color:#412}.foo,#AABBCC.foobar{background-color:#fe1;border-color:#0f1 #abcdef #abc;color:#412}@media screen{.bar,#AABBCC{background-color:#fe1;color:#412}}

tests/concat-charset.css

 /* This is invalid CSS, but frequently happens as a result of concatenation. */
-@charset "utf-8";
+@CHARSET "utf-8";
 #foo {
 	border-width:1px;
 }
 @charset "another one";
 #bar {
 	border-width:10px;
-}
+}

tests/dataurl-singlequote-font.css

 
 @font-face {
     font-family: "Foo Bar";
-    src: url('data:font/truetype;base64,gRbIUFAIrsQNGditEWbAUKwAA') format("truetype"),
+    src: URL('data:font/truetype;base64,gRbIUFAIrsQNGditEWbAUKwAA') format("truetype"),
          url("http://yuilibrary.com/fonts/foo-bar.svg#webfontse22fewwr") format("svg");
     font-weight: normal;
     font-style: normal;

tests/lowercasing.css

+@CHARSET "UTF-8";
+
+@FONT-FACE {
+    FONT-FAMILY: "YOUR FACE";
+}
+
+@IMPORT "HTTP://DOMAIN.TLD/OTHER.CSS";
+
+@MEDIA print {
+    BACKGROUND: NONE;
+    BACKGROUND-POSITION: 0 0;
+}
+
+@PAGE {
+    CONTENT: ATTR(HREF);
+    HEIGHT: MAX(0, MIN(10, 20));
+    WIDTH: CALC(50% - 10PX);
+}
+
+@NAMESPACE XHTML "HTTP://WWW.W3.ORG/1999/XHTML";
+
+/* pseudos */
+a:ACTIVE,
+a:AFTER,
+a:BEFORE,
+a:CHECKED,
+a:DISABLED,
+a:EMPTY,
+a:ENABLED,
+a:FIRST-CHILD,
+a:FIRST-LETTER,
+a:FIRST-LINE,
+a:FIRST-OF-TYPE,
+a:FOCUS,
+a:HOVER,
+a:LAST-CHILD,
+a:LAST-OF-TYPE,
+a:LINK,
+a:ONLY-CHILD,
+a:ONLY-OF-TYPE,
+a:ROOT,
+a::SELECTION,
+a:TARGET,
+a:VISITED,
+
+/* pseudo functions */
+a:ANY(A, B, I) STRONG,
+a:LANG(FR),
+a:NOT([HIDDEN]),
+a:NTH-CHILD(2),
+a:NTH-LAST-CHILD(2),
+a:NTH-LAST-OF-TYPE(2),
+a:NTH-OF-TYPE(2) {
+    BACKGROUND: URL(PROTO://DOMAIN.TLD/PATH),
+                REPEATING-LINEAR-GRADIENT(20DEG, GRAY, GREEN, 20PX, WHITE 40PX),
+                -ATSC-LINEAR-GRADIENT(LEFT, BLACK, WHITE),
+                -KHTML-RADIAL-GRADIENT(CENTER 50DEG, CIRCLE CLOSEST-SIDE, BLACK 0, GREEN 100%),
+                -MOZ-RADIAL-GRADIENT(CENTER 45DEG, CIRCLE CLOSEST-SIDE, ORANGE 0%, RED 100%),
+                -MS-LINEAR-GRaDiEnT(LEFT, BLUE, BLACK),
+                -O-REPEATING-RADIAL-GRADIENT(CENTER, CIRCLE CLOSEST-SIDE, PAPAYAWHIP, RED 50%, GAINSBORO),
+                -WAP-LINEAR-GRADIENT(LEFT, BLACK, WHITE),
+                -WEBKIT-GRADIENT(LINEAR, LEFT, FROM(WHITE), TO(RGBA(1,2,3,.4)));
+}

tests/lowercasing.css.min

+@charset "UTF-8";@font-face{FONT-FAMILY:"YOUR FACE"}@import "HTTP://DOMAIN.TLD/OTHER.CSS";@media print{background:0;background-position:0 0}@page{CONTENT:attr(HREF);HEIGHT:max(0,min(10,20));WIDTH:calc(50% - 10PX)}@namespace XHTML "HTTP://WWW.W3.ORG/1999/XHTML";a:active,a:after,a:before,a:checked,a:disabled,a:empty,a:enabled,a:first-child,a:first-letter ,a:first-line ,a:first-of-type,a:focus,a:hover,a:last-child,a:last-of-type,a:link,a:only-child,a:only-of-type,a:root,a::selection,a:target,a:visited,a:any(A,B,I) STRONG,a:lang(FR),a:not([HIDDEN]),a:nth-child(2),a:nth-last-child(2),a:nth-last-of-type(2),a:nth-of-type(2){BACKGROUND:url(PROTO://DOMAIN.TLD/PATH),repeating-linear-gradient(20DEG,GRAY,GREEN,20PX,WHITE 40PX),-atsc-linear-gradient(LEFT,BLACK,WHITE),-khtml-radial-gradient(CENTER 50DEG,CIRCLE CLOSEST-SIDE,BLACK 0,GREEN 100%),-moz-radial-gradient(CENTER 45DEG,CIRCLE CLOSEST-SIDE,ORANGE 0,RED 100%),-ms-linear-gradient(LEFT,BLUE,BLACK),-o-repeating-radial-gradient(CENTER,CIRCLE CLOSEST-SIDE,PAPAYAWHIP,RED 50%,GAINSBORO),-wap-linear-gradient(LEFT,BLACK,WHITE),-webkit-gradient(LINEAR,LEFT,from(WHITE),to(rgba(1,2,3,.4)))}

tests/media-test.css

-@media screen and (-webkit-min-device-pixel-ratio:0) {
+@media screen AND (-webkit-min-device-pixel-ratio:0) {
   some-css : here
-}
+}

tests/pseudo-first.css

 p:first-letter{
   buh: hum;
 }
-p:first-line{
+p:FIRST-LINE{
   baa: 1;
 }
 
 p:first-line,a,p:first-letter,b{
   color: red;
-}
+}
 }
 
 
-ls *.FAIL | while read failtest; do
+ls *.FAIL 2>/dev/null | while read failtest; do
 	echo "Failing test: " $failtest > /dev/stderr
 	runtest $failtest && echo "Test passed, please remove the '.FAIL' from the filename"
 done
   margin: 0px 0pt 0em 0%;
   _padding-top: 0ex;
   background-position: 0 0;
-  padding: 0in 0cm 0mm 0pc
+  padding: 0in 0cm 0mm 0pc;
+  transition: opacity .0s;
+  transition-delay: 0.0ms;
+  transform: rotate3d(0grad, 0rad, 0deg);
+  pitch: 0KHZ;
+  pitch:
+0hz; /* intentionally on next line */
 }

tests/zeros.css.min

-a{margin:0;_padding-top:0;background-position:0 0;padding:0}
+a{margin:0;_padding-top:0;background-position:0 0;padding:0;transition:opacity 0;transition-delay:0;transform:rotate3d(0,0,0);pitch:0;pitch:0}