From 85260798f95159e293ad3831131d06cdc37be55c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 6 Oct 2014 12:37:33 +0200 Subject: [PATCH 1/2] adding cssmin and jssmin(minify) --- autoload.php | 2 +- composer.json | 4 +- composer.lock | 95 +- composer/autoload_classmap.php | 119 + composer/autoload_real.php | 10 +- composer/installed.json | 91 + mrclay/minify/.editorconfig | 19 + mrclay/minify/.gitignore | 7 + mrclay/minify/HISTORY.txt | 141 + mrclay/minify/LICENSE.txt | 26 + mrclay/minify/MIN.txt | 181 + mrclay/minify/README.txt | 68 + mrclay/minify/UPGRADING.txt | 28 + mrclay/minify/composer.json | 32 + mrclay/minify/min/.htaccess | 13 + mrclay/minify/min/builder/.htaccess | 4 + mrclay/minify/min/builder/_index.js | 260 + mrclay/minify/min/builder/bm.js | 36 + mrclay/minify/min/builder/bm2.js | 15 + mrclay/minify/min/builder/index.php | 241 + mrclay/minify/min/builder/jquery-1.6.3.min.js | 4 + mrclay/minify/min/builder/ocCheck.php | 36 + mrclay/minify/min/builder/rewriteTest.js | 1 + mrclay/minify/min/builder/test.php | 43 + mrclay/minify/min/config-test.php | 10 + mrclay/minify/min/config.php | 191 + mrclay/minify/min/groupsConfig.php | 17 + mrclay/minify/min/index.php | 86 + mrclay/minify/min/lib/CSSmin.php | 777 +++ mrclay/minify/min/lib/DooDigestAuth.php | 121 + mrclay/minify/min/lib/FirePHP.php | 1370 +++++ mrclay/minify/min/lib/HTTP/ConditionalGet.php | 366 ++ mrclay/minify/min/lib/HTTP/Encoder.php | 335 ++ mrclay/minify/min/lib/JSMin.php | 449 ++ mrclay/minify/min/lib/JSMinPlus.php | 2086 +++++++ mrclay/minify/min/lib/Minify.php | 608 ++ mrclay/minify/min/lib/Minify/Build.php | 101 + mrclay/minify/min/lib/Minify/CSS.php | 99 + .../minify/min/lib/Minify/CSS/Compressor.php | 249 + .../minify/min/lib/Minify/CSS/UriRewriter.php | 307 + mrclay/minify/min/lib/Minify/CSSmin.php | 85 + mrclay/minify/min/lib/Minify/Cache/APC.php | 133 + mrclay/minify/min/lib/Minify/Cache/File.php | 197 + .../minify/min/lib/Minify/Cache/Memcache.php | 140 + .../minify/min/lib/Minify/Cache/WinCache.php | 130 + mrclay/minify/min/lib/Minify/Cache/XCache.php | 126 + .../min/lib/Minify/Cache/ZendPlatform.php | 142 + .../minify/min/lib/Minify/ClosureCompiler.php | 139 + .../min/lib/Minify/CommentPreserver.php | 89 + .../minify/min/lib/Minify/Controller/Base.php | 222 + .../min/lib/Minify/Controller/Files.php | 76 + .../min/lib/Minify/Controller/Groups.php | 91 + .../min/lib/Minify/Controller/MinApp.php | 237 + .../minify/min/lib/Minify/Controller/Page.php | 68 + .../min/lib/Minify/Controller/Version1.php | 119 + .../minify/min/lib/Minify/DebugDetector.php | 26 + mrclay/minify/min/lib/Minify/HTML.php | 255 + mrclay/minify/min/lib/Minify/HTML/Helper.php | 225 + .../minify/min/lib/Minify/ImportProcessor.php | 216 + .../min/lib/Minify/JS/ClosureCompiler.php | 230 + mrclay/minify/min/lib/Minify/Lines.php | 143 + mrclay/minify/min/lib/Minify/Loader.php | 28 + mrclay/minify/min/lib/Minify/Logger.php | 47 + mrclay/minify/min/lib/Minify/Packer.php | 37 + mrclay/minify/min/lib/Minify/Source.php | 187 + .../min/lib/Minify/YUI/CssCompressor.java | 382 ++ .../min/lib/Minify/YUI/CssCompressor.php | 171 + .../minify/min/lib/Minify/YUICompressor.php | 156 + mrclay/minify/min/lib/MrClay/Cli.php | 384 ++ mrclay/minify/min/lib/MrClay/Cli/Arg.php | 183 + mrclay/minify/min/quick-test.css | 30 + mrclay/minify/min/quick-test.js | 74 + mrclay/minify/min/utils.php | 81 + mrclay/minify/min_extras/README.txt | 11 + mrclay/minify/min_extras/cli/minify.php | 82 + mrclay/minify/min_extras/cli/rewrite-uris.php | 63 + mrclay/minify/min_extras/config.php | 12 + .../min_extras/tools/minifyTextarea.php | 175 + mrclay/minify/min_extras/tools/minifyUrl.php | 164 + .../min_extras/tools/testRewriteUri.php | 58 + mrclay/minify/min_unit_tests/.htaccess | 4 + .../min_unit_tests/HTTP_ConditionalGet/2.php | 44 + .../min_unit_tests/HTTP_ConditionalGet/3.php | 40 + .../min_unit_tests/HTTP_ConditionalGet/4.php | 49 + .../min_unit_tests/HTTP_ConditionalGet/5.php | 27 + .../HTTP_ConditionalGet/_include.php | 64 + .../HTTP_ConditionalGet/index.php | 36 + .../min_unit_tests/HTTP_Encoder/green.png | Bin 0 -> 202 bytes .../min_unit_tests/HTTP_Encoder/index.php | 60 + mrclay/minify/min_unit_tests/_inc.php | 62 + .../_test_files/css/comments.css | 9 + .../_test_files/css/comments.min.css | 3 + .../min_unit_tests/_test_files/css/hacks.css | 66 + .../_test_files/css/hacks.min.css | 4 + .../_test_files/css/issue210.css | 1 + .../_test_files/css/issue210.min.css | 1 + .../_test_files/css/issue62.css | 890 +++ .../_test_files/css/issue62.min.css | 25 + .../_test_files/css/paths_prepend.css | 12 + .../_test_files/css/paths_prepend.min.css | 1 + .../_test_files/css/paths_rewrite.css | 14 + .../_test_files/css/paths_rewrite.min.css | 1 + .../min_unit_tests/_test_files/css/readme.txt | 1 + .../_test_files/css/selectors.css | 42 + .../_test_files/css/selectors.min.css | 37 + .../min_unit_tests/_test_files/css/styles.css | 33 + .../_test_files/css/styles.min.css | 3 + .../_test_files/css/subsilver.css | 434 ++ .../_test_files/css/subsilver.min.css | 18 + .../_test_files/css/unusual_strings.css | 10 + .../_test_files/css/unusual_strings.min.css | 2 + .../_test_files/css/vladmirated.css | 658 +++ .../_test_files/css/vladmirated.min.css | 79 + .../_test_files/css_uriRewriter/exp.css | 17 + .../css_uriRewriter/exp_prepend.css | 17 + .../css_uriRewriter/exp_prepend2.css | 17 + .../_test_files/css_uriRewriter/in.css | 17 + .../_test_files/html/before.html | 96 + .../_test_files/html/before.min.html | 38 + .../_test_files/html/before2.html | 95 + .../_test_files/html/before2.min.html | 38 + .../_test_files/htmlHelper_groupsConfig.php | 8 + .../importProcessor/css/1/adjacent.css | 3 + .../_test_files/importProcessor/css/1/tv.css | 4 + .../importProcessor/css/adjacent.css | 4 + .../_test_files/importProcessor/css/input.css | 5 + .../importProcessor/css/output.css | 52 + .../importProcessor/lib/css/example.css | 1 + .../min_unit_tests/_test_files/js/before.js | 66 + .../_test_files/js/before.min.js | 27 + .../_test_files/js/before.min_plus.js | 22 + .../min_unit_tests/_test_files/js/condcomm.js | 14 + .../_test_files/js/condcomm.min_plus.js | 13 + .../min_unit_tests/_test_files/js/issue132.js | 7 + .../_test_files/js/issue132.min.js | 1 + .../_test_files/js/issue141.min.js | 3 + .../min_unit_tests/_test_files/js/issue144.js | 9 + .../_test_files/js/issue144.min.js | 1 + .../min_unit_tests/_test_files/js/issue256.js | 3 + .../_test_files/js/issue256.min.js | 2 + .../_test_files/js/jquery-1.2.3.js | 3408 +++++++++++ .../min_unit_tests/_test_files/js/regexes.js | 24 + .../_test_files/js/regexes.min.js | 3 + .../_test_files/minify/QueryString.js | 168 + .../_test_files/minify/email.js | 24 + .../_test_files/minify/issue143.js | 6 + .../_test_files/minify/issue73_1.js | 2 + .../_test_files/minify/issue73_2.js | 3 + .../_test_files/minify/issue89_1.css | 7 + .../_test_files/minify/issue89_2.css | 7 + .../_test_files/minify/issue89_out.min.css | 1 + .../_test_files/minify/lines_bugs.js | 10 + .../_test_files/minify/lines_output.js | 72 + .../_test_files/minify/minified.css | 5 + .../_test_files/minify/minified.js | 12 + .../test_HTTP_ConditionalGet.php | 135 + .../min_unit_tests/test_HTTP_Encoder.php | 314 + mrclay/minify/min_unit_tests/test_JSMin.php | 108 + .../minify/min_unit_tests/test_JSMinPlus.php | 49 + mrclay/minify/min_unit_tests/test_Minify.php | 222 + .../min_unit_tests/test_Minify_Build.php | 33 + .../minify/min_unit_tests/test_Minify_CSS.php | 51 + .../test_Minify_CSS_UriRewriter.php | 93 + .../min_unit_tests/test_Minify_Cache_APC.php | 31 + .../min_unit_tests/test_Minify_Cache_File.php | 50 + .../test_Minify_Cache_Memcache.php | 50 + .../test_Minify_Cache_WinCache.php | 31 + .../test_Minify_Cache_ZendPlatform.php | 31 + .../test_Minify_ClosureCompiler.php | 75 + .../test_Minify_CommentPreserver.php | 35 + .../min_unit_tests/test_Minify_HTML.php | 55 + .../test_Minify_HTML_Helper.php | 66 + .../test_Minify_ImportProcessor.php | 37 + .../test_Minify_JS_ClosureCompiler.php | 125 + .../min_unit_tests/test_Minify_Lines.php | 32 + .../min_unit_tests/test_Minify_YuiCSS.php | 56 + mrclay/minify/min_unit_tests/test_all.php | 23 + .../min_unit_tests/test_environment.php | 138 + .../min_unit_tests/test_js_in_browser.html | 4 + natxet/CssMin/README | 3 + natxet/CssMin/composer.json | 20 + natxet/CssMin/src/CssMin.php | 5110 +++++++++++++++++ 182 files changed, 28091 insertions(+), 10 deletions(-) create mode 100644 mrclay/minify/.editorconfig create mode 100644 mrclay/minify/.gitignore create mode 100644 mrclay/minify/HISTORY.txt create mode 100644 mrclay/minify/LICENSE.txt create mode 100644 mrclay/minify/MIN.txt create mode 100644 mrclay/minify/README.txt create mode 100644 mrclay/minify/UPGRADING.txt create mode 100644 mrclay/minify/composer.json create mode 100644 mrclay/minify/min/.htaccess create mode 100644 mrclay/minify/min/builder/.htaccess create mode 100644 mrclay/minify/min/builder/_index.js create mode 100644 mrclay/minify/min/builder/bm.js create mode 100644 mrclay/minify/min/builder/bm2.js create mode 100644 mrclay/minify/min/builder/index.php create mode 100644 mrclay/minify/min/builder/jquery-1.6.3.min.js create mode 100644 mrclay/minify/min/builder/ocCheck.php create mode 100644 mrclay/minify/min/builder/rewriteTest.js create mode 100644 mrclay/minify/min/builder/test.php create mode 100644 mrclay/minify/min/config-test.php create mode 100644 mrclay/minify/min/config.php create mode 100644 mrclay/minify/min/groupsConfig.php create mode 100644 mrclay/minify/min/index.php create mode 100644 mrclay/minify/min/lib/CSSmin.php create mode 100644 mrclay/minify/min/lib/DooDigestAuth.php create mode 100644 mrclay/minify/min/lib/FirePHP.php create mode 100644 mrclay/minify/min/lib/HTTP/ConditionalGet.php create mode 100644 mrclay/minify/min/lib/HTTP/Encoder.php create mode 100644 mrclay/minify/min/lib/JSMin.php create mode 100644 mrclay/minify/min/lib/JSMinPlus.php create mode 100644 mrclay/minify/min/lib/Minify.php create mode 100644 mrclay/minify/min/lib/Minify/Build.php create mode 100644 mrclay/minify/min/lib/Minify/CSS.php create mode 100644 mrclay/minify/min/lib/Minify/CSS/Compressor.php create mode 100644 mrclay/minify/min/lib/Minify/CSS/UriRewriter.php create mode 100644 mrclay/minify/min/lib/Minify/CSSmin.php create mode 100644 mrclay/minify/min/lib/Minify/Cache/APC.php create mode 100644 mrclay/minify/min/lib/Minify/Cache/File.php create mode 100644 mrclay/minify/min/lib/Minify/Cache/Memcache.php create mode 100644 mrclay/minify/min/lib/Minify/Cache/WinCache.php create mode 100644 mrclay/minify/min/lib/Minify/Cache/XCache.php create mode 100644 mrclay/minify/min/lib/Minify/Cache/ZendPlatform.php create mode 100644 mrclay/minify/min/lib/Minify/ClosureCompiler.php create mode 100644 mrclay/minify/min/lib/Minify/CommentPreserver.php create mode 100644 mrclay/minify/min/lib/Minify/Controller/Base.php create mode 100644 mrclay/minify/min/lib/Minify/Controller/Files.php create mode 100644 mrclay/minify/min/lib/Minify/Controller/Groups.php create mode 100644 mrclay/minify/min/lib/Minify/Controller/MinApp.php create mode 100644 mrclay/minify/min/lib/Minify/Controller/Page.php create mode 100644 mrclay/minify/min/lib/Minify/Controller/Version1.php create mode 100644 mrclay/minify/min/lib/Minify/DebugDetector.php create mode 100644 mrclay/minify/min/lib/Minify/HTML.php create mode 100644 mrclay/minify/min/lib/Minify/HTML/Helper.php create mode 100644 mrclay/minify/min/lib/Minify/ImportProcessor.php create mode 100644 mrclay/minify/min/lib/Minify/JS/ClosureCompiler.php create mode 100644 mrclay/minify/min/lib/Minify/Lines.php create mode 100644 mrclay/minify/min/lib/Minify/Loader.php create mode 100644 mrclay/minify/min/lib/Minify/Logger.php create mode 100644 mrclay/minify/min/lib/Minify/Packer.php create mode 100644 mrclay/minify/min/lib/Minify/Source.php create mode 100644 mrclay/minify/min/lib/Minify/YUI/CssCompressor.java create mode 100644 mrclay/minify/min/lib/Minify/YUI/CssCompressor.php create mode 100644 mrclay/minify/min/lib/Minify/YUICompressor.php create mode 100644 mrclay/minify/min/lib/MrClay/Cli.php create mode 100644 mrclay/minify/min/lib/MrClay/Cli/Arg.php create mode 100644 mrclay/minify/min/quick-test.css create mode 100644 mrclay/minify/min/quick-test.js create mode 100644 mrclay/minify/min/utils.php create mode 100644 mrclay/minify/min_extras/README.txt create mode 100755 mrclay/minify/min_extras/cli/minify.php create mode 100755 mrclay/minify/min_extras/cli/rewrite-uris.php create mode 100644 mrclay/minify/min_extras/config.php create mode 100644 mrclay/minify/min_extras/tools/minifyTextarea.php create mode 100644 mrclay/minify/min_extras/tools/minifyUrl.php create mode 100644 mrclay/minify/min_extras/tools/testRewriteUri.php create mode 100644 mrclay/minify/min_unit_tests/.htaccess create mode 100644 mrclay/minify/min_unit_tests/HTTP_ConditionalGet/2.php create mode 100644 mrclay/minify/min_unit_tests/HTTP_ConditionalGet/3.php create mode 100644 mrclay/minify/min_unit_tests/HTTP_ConditionalGet/4.php create mode 100644 mrclay/minify/min_unit_tests/HTTP_ConditionalGet/5.php create mode 100644 mrclay/minify/min_unit_tests/HTTP_ConditionalGet/_include.php create mode 100644 mrclay/minify/min_unit_tests/HTTP_ConditionalGet/index.php create mode 100644 mrclay/minify/min_unit_tests/HTTP_Encoder/green.png create mode 100644 mrclay/minify/min_unit_tests/HTTP_Encoder/index.php create mode 100644 mrclay/minify/min_unit_tests/_inc.php create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/comments.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/comments.min.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/hacks.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/hacks.min.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/issue210.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/issue210.min.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/issue62.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/issue62.min.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.min.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.min.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/readme.txt create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/selectors.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/selectors.min.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/styles.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/styles.min.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/subsilver.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/subsilver.min.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.min.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/vladmirated.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css/vladmirated.min.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend2.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/in.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/html/before.html create mode 100644 mrclay/minify/min_unit_tests/_test_files/html/before.min.html create mode 100644 mrclay/minify/min_unit_tests/_test_files/html/before2.html create mode 100644 mrclay/minify/min_unit_tests/_test_files/html/before2.min.html create mode 100644 mrclay/minify/min_unit_tests/_test_files/htmlHelper_groupsConfig.php create mode 100644 mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/adjacent.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/tv.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/importProcessor/css/adjacent.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/importProcessor/css/input.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/importProcessor/css/output.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/importProcessor/lib/css/example.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/js/before.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/js/before.min.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/js/before.min_plus.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/js/condcomm.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/js/condcomm.min_plus.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/js/issue132.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/js/issue132.min.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/js/issue141.min.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/js/issue144.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/js/issue144.min.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/js/issue256.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/js/issue256.min.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/js/jquery-1.2.3.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/js/regexes.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/js/regexes.min.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/QueryString.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/email.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/issue143.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/issue73_1.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/issue73_2.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/issue89_1.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/issue89_2.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/issue89_out.min.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/lines_bugs.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/lines_output.js create mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/minified.css create mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/minified.js create mode 100644 mrclay/minify/min_unit_tests/test_HTTP_ConditionalGet.php create mode 100644 mrclay/minify/min_unit_tests/test_HTTP_Encoder.php create mode 100644 mrclay/minify/min_unit_tests/test_JSMin.php create mode 100644 mrclay/minify/min_unit_tests/test_JSMinPlus.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_Build.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_CSS.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_CSS_UriRewriter.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_Cache_APC.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_Cache_File.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_Cache_Memcache.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_Cache_WinCache.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_Cache_ZendPlatform.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_ClosureCompiler.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_CommentPreserver.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_HTML.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_HTML_Helper.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_ImportProcessor.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_JS_ClosureCompiler.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_Lines.php create mode 100644 mrclay/minify/min_unit_tests/test_Minify_YuiCSS.php create mode 100644 mrclay/minify/min_unit_tests/test_all.php create mode 100644 mrclay/minify/min_unit_tests/test_environment.php create mode 100644 mrclay/minify/min_unit_tests/test_js_in_browser.html create mode 100644 natxet/CssMin/README create mode 100644 natxet/CssMin/composer.json create mode 100644 natxet/CssMin/src/CssMin.php diff --git a/autoload.php b/autoload.php index f3507c5a8f59..d21bd02ec1ad 100644 --- a/autoload.php +++ b/autoload.php @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer' . '/autoload_real.php'; -return ComposerAutoloaderInit96654a5746889b254811c7316da366d7::getLoader(); +return ComposerAutoloaderInit3669affcbbaeb5ccc4a88f42b228548d::getLoader(); diff --git a/composer.json b/composer.json index c6b77a94c166..fed2460d4b3d 100644 --- a/composer.json +++ b/composer.json @@ -28,6 +28,8 @@ "rackspace/php-opencloud": "v1.9.2", "james-heinrich/getid3": "dev-master", "ircmaxell/random-lib": "v1.0.0", - "bantu/ini-get-wrapper": "v1.0.1" + "bantu/ini-get-wrapper": "v1.0.1", + "natxet/CssMin": "dev-master", + "mrclay/minify": "dev-master" } } diff --git a/composer.lock b/composer.lock index af6a6656f6f0..cb0db0968f51 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "4e466ba02a23af88f97c10ff11a89c2d", + "hash": "454693699d7068f1fc2481b6b647e0c1", "packages": [ { "name": "bantu/ini-get-wrapper", @@ -446,7 +446,94 @@ "reference": "master" }, "type": "library", - "time": "2014-09-17 13:32:18" + "time": "2014-09-22 11:02:33" + }, + { + "name": "mrclay/minify", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/mrclay/minify.git", + "reference": "bd9a450694cda1b54c43a1784adabe36ad522d89" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mrclay/minify/zipball/bd9a450694cda1b54c43a1784adabe36ad522d89", + "reference": "bd9a450694cda1b54c43a1784adabe36ad522d89", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "php": ">=5.2.1" + }, + "require-dev": { + "tubalmartin/cssmin": "~2.4.8" + }, + "suggest": { + "tubalmartin/cssmin": "Support minify with CSSMin (YUI PHP port)" + }, + "type": "library", + "autoload": { + "classmap": [ + "min/lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Stephen Clay", + "email": "steve@mrclay.org", + "role": "Developer" + } + ], + "description": "Minify is a PHP5 app that helps you follow several rules for client-side performance. It combines multiple CSS or Javascript files, removes unnecessary whitespace and comments, and serves them with gzip encoding and optimal client-side cache headers", + "homepage": "http://code.google.com/p/minify/", + "time": "2014-09-25 11:40:53" + }, + { + "name": "natxet/CssMin", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/natxet/CssMin.git", + "reference": "003920e783c568c2d8fdf03999eebefb8479092a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/natxet/CssMin/zipball/003920e783c568c2d8fdf03999eebefb8479092a", + "reference": "003920e783c568c2d8fdf03999eebefb8479092a", + "shasum": "" + }, + "require": { + "php": ">=5.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Joe Scylla", + "email": "joe.scylla@gmail.com", + "homepage": "https://profiles.google.com/joe.scylla" + } + ], + "description": "Minifying CSS", + "homepage": "http://code.google.com/p/cssmin/", + "keywords": [ + "css", + "minify" + ], + "time": "2014-09-10 14:34:00" }, { "name": "phpmailer/phpmailer", @@ -891,7 +978,9 @@ "stability-flags": { "mcnetic/phpzipstreamer": 20, "kriswallsmith/assetic": 20, - "james-heinrich/getid3": 20 + "james-heinrich/getid3": 20, + "natxet/cssmin": 20, + "mrclay/minify": 20 }, "prefer-stable": false, "platform": [], diff --git a/composer/autoload_classmap.php b/composer/autoload_classmap.php index 879964af6d0d..ddf2515d8a2c 100644 --- a/composer/autoload_classmap.php +++ b/composer/autoload_classmap.php @@ -6,9 +6,128 @@ $baseDir = $vendorDir; return array( + 'CSSmin' => $vendorDir . '/mrclay/minify/min/lib/CSSmin.php', + 'CssAtCharsetParserPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtCharsetToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtFontFaceDeclarationToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtFontFaceEndToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtFontFaceParserPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtFontFaceStartToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtImportParserPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtImportToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtKeyframesEndToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtKeyframesParserPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtKeyframesRulesetDeclarationToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtKeyframesRulesetEndToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtKeyframesRulesetStartToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtKeyframesStartToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtMediaEndToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtMediaParserPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtMediaStartToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtPageDeclarationToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtPageEndToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtPageParserPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtPageStartToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtVariablesDeclarationToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtVariablesEndToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtVariablesParserPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssAtVariablesStartToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssCommentParserPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssCommentToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssCompressColorValuesMinifierPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssCompressExpressionValuesMinifierPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssCompressUnitValuesMinifierPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssConvertFontWeightMinifierPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssConvertHslColorsMinifierPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssConvertLevel3AtKeyframesMinifierFilter' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssConvertLevel3PropertiesMinifierFilter' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssConvertNamedColorsMinifierPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssConvertRgbColorsMinifierPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssError' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssExpressionParserPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssImportImportsMinifierFilter' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssMin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssMinifier' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssNullToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssOtbsFormatter' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssParser' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssRemoveCommentsMinifierFilter' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssRemoveEmptyAtBlocksMinifierFilter' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssRemoveEmptyRulesetsMinifierFilter' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssRemoveLastDelarationSemiColonMinifierFilter' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssRulesetDeclarationToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssRulesetEndToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssRulesetParserPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssRulesetStartToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssSortRulesetPropertiesMinifierFilter' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssStringParserPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssUrlParserPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssVariablesMinifierFilter' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssVariablesMinifierPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'CssWhitesmithsFormatter' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'DooDigestAuth' => $vendorDir . '/mrclay/minify/min/lib/DooDigestAuth.php', + 'FirePHP' => $vendorDir . '/mrclay/minify/min/lib/FirePHP.php', + 'HTTP_ConditionalGet' => $vendorDir . '/mrclay/minify/min/lib/HTTP/ConditionalGet.php', + 'HTTP_Encoder' => $vendorDir . '/mrclay/minify/min/lib/HTTP/Encoder.php', + 'JSCompilerContext' => $vendorDir . '/mrclay/minify/min/lib/JSMinPlus.php', + 'JSMin' => $vendorDir . '/mrclay/minify/min/lib/JSMin.php', + 'JSMinPlus' => $vendorDir . '/mrclay/minify/min/lib/JSMinPlus.php', + 'JSMin_UnterminatedCommentException' => $vendorDir . '/mrclay/minify/min/lib/JSMin.php', + 'JSMin_UnterminatedRegExpException' => $vendorDir . '/mrclay/minify/min/lib/JSMin.php', + 'JSMin_UnterminatedStringException' => $vendorDir . '/mrclay/minify/min/lib/JSMin.php', + 'JSNode' => $vendorDir . '/mrclay/minify/min/lib/JSMinPlus.php', + 'JSParser' => $vendorDir . '/mrclay/minify/min/lib/JSMinPlus.php', + 'JSToken' => $vendorDir . '/mrclay/minify/min/lib/JSMinPlus.php', + 'JSTokenizer' => $vendorDir . '/mrclay/minify/min/lib/JSMinPlus.php', + 'Minify' => $vendorDir . '/mrclay/minify/min/lib/Minify.php', + 'Minify_Build' => $vendorDir . '/mrclay/minify/min/lib/Minify/Build.php', + 'Minify_CSS' => $vendorDir . '/mrclay/minify/min/lib/Minify/CSS.php', + 'Minify_CSS_Compressor' => $vendorDir . '/mrclay/minify/min/lib/Minify/CSS/Compressor.php', + 'Minify_CSS_UriRewriter' => $vendorDir . '/mrclay/minify/min/lib/Minify/CSS/UriRewriter.php', + 'Minify_CSSmin' => $vendorDir . '/mrclay/minify/min/lib/Minify/CSSmin.php', + 'Minify_Cache_APC' => $vendorDir . '/mrclay/minify/min/lib/Minify/Cache/APC.php', + 'Minify_Cache_File' => $vendorDir . '/mrclay/minify/min/lib/Minify/Cache/File.php', + 'Minify_Cache_Memcache' => $vendorDir . '/mrclay/minify/min/lib/Minify/Cache/Memcache.php', + 'Minify_Cache_WinCache' => $vendorDir . '/mrclay/minify/min/lib/Minify/Cache/WinCache.php', + 'Minify_Cache_XCache' => $vendorDir . '/mrclay/minify/min/lib/Minify/Cache/XCache.php', + 'Minify_Cache_ZendPlatform' => $vendorDir . '/mrclay/minify/min/lib/Minify/Cache/ZendPlatform.php', + 'Minify_ClosureCompiler' => $vendorDir . '/mrclay/minify/min/lib/Minify/ClosureCompiler.php', + 'Minify_ClosureCompiler_Exception' => $vendorDir . '/mrclay/minify/min/lib/Minify/ClosureCompiler.php', + 'Minify_CommentPreserver' => $vendorDir . '/mrclay/minify/min/lib/Minify/CommentPreserver.php', + 'Minify_Controller_Base' => $vendorDir . '/mrclay/minify/min/lib/Minify/Controller/Base.php', + 'Minify_Controller_Files' => $vendorDir . '/mrclay/minify/min/lib/Minify/Controller/Files.php', + 'Minify_Controller_Groups' => $vendorDir . '/mrclay/minify/min/lib/Minify/Controller/Groups.php', + 'Minify_Controller_MinApp' => $vendorDir . '/mrclay/minify/min/lib/Minify/Controller/MinApp.php', + 'Minify_Controller_Page' => $vendorDir . '/mrclay/minify/min/lib/Minify/Controller/Page.php', + 'Minify_Controller_Version1' => $vendorDir . '/mrclay/minify/min/lib/Minify/Controller/Version1.php', + 'Minify_DebugDetector' => $vendorDir . '/mrclay/minify/min/lib/Minify/DebugDetector.php', + 'Minify_HTML' => $vendorDir . '/mrclay/minify/min/lib/Minify/HTML.php', + 'Minify_HTML_Helper' => $vendorDir . '/mrclay/minify/min/lib/Minify/HTML/Helper.php', + 'Minify_ImportProcessor' => $vendorDir . '/mrclay/minify/min/lib/Minify/ImportProcessor.php', + 'Minify_JS_ClosureCompiler' => $vendorDir . '/mrclay/minify/min/lib/Minify/JS/ClosureCompiler.php', + 'Minify_JS_ClosureCompiler_Exception' => $vendorDir . '/mrclay/minify/min/lib/Minify/JS/ClosureCompiler.php', + 'Minify_Lines' => $vendorDir . '/mrclay/minify/min/lib/Minify/Lines.php', + 'Minify_Loader' => $vendorDir . '/mrclay/minify/min/lib/Minify/Loader.php', + 'Minify_Logger' => $vendorDir . '/mrclay/minify/min/lib/Minify/Logger.php', + 'Minify_Packer' => $vendorDir . '/mrclay/minify/min/lib/Minify/Packer.php', + 'Minify_Source' => $vendorDir . '/mrclay/minify/min/lib/Minify/Source.php', + 'Minify_YUICompressor' => $vendorDir . '/mrclay/minify/min/lib/Minify/YUICompressor.php', + 'Minify_YUI_CssCompressor' => $vendorDir . '/mrclay/minify/min/lib/Minify/YUI/CssCompressor.php', + 'MrClay\\Cli' => $vendorDir . '/mrclay/minify/min/lib/MrClay/Cli.php', + 'MrClay\\Cli\\Arg' => $vendorDir . '/mrclay/minify/min/lib/MrClay/Cli/Arg.php', 'PHPMailer' => $vendorDir . '/phpmailer/phpmailer/class.phpmailer.php', 'POP3' => $vendorDir . '/phpmailer/phpmailer/class.pop3.php', 'SMTP' => $vendorDir . '/phpmailer/phpmailer/class.smtp.php', + 'aCssAtBlockEndToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'aCssAtBlockStartToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'aCssDeclarationToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'aCssFormatter' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'aCssMinifierFilter' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'aCssMinifierPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'aCssParserPlugin' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'aCssRulesetEndToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'aCssRulesetStartToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', + 'aCssToken' => $vendorDir . '/natxet/CssMin/src/CssMin.php', 'getID3' => $vendorDir . '/james-heinrich/getid3/getid3/getid3.php', 'getid3_exception' => $vendorDir . '/james-heinrich/getid3/getid3/getid3.php', 'getid3_handler' => $vendorDir . '/james-heinrich/getid3/getid3/getid3.php', diff --git a/composer/autoload_real.php b/composer/autoload_real.php index 27625f96da71..760e73fed4f9 100644 --- a/composer/autoload_real.php +++ b/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit96654a5746889b254811c7316da366d7 +class ComposerAutoloaderInit3669affcbbaeb5ccc4a88f42b228548d { private static $loader; @@ -19,9 +19,9 @@ public static function getLoader() return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInit96654a5746889b254811c7316da366d7', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInit3669affcbbaeb5ccc4a88f42b228548d', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); - spl_autoload_unregister(array('ComposerAutoloaderInit96654a5746889b254811c7316da366d7', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInit3669affcbbaeb5ccc4a88f42b228548d', 'loadClassLoader')); $includePaths = require __DIR__ . '/include_paths.php'; array_push($includePaths, get_include_path()); @@ -46,14 +46,14 @@ public static function getLoader() $includeFiles = require __DIR__ . '/autoload_files.php'; foreach ($includeFiles as $file) { - composerRequire96654a5746889b254811c7316da366d7($file); + composerRequire3669affcbbaeb5ccc4a88f42b228548d($file); } return $loader; } } -function composerRequire96654a5746889b254811c7316da366d7($file) +function composerRequire3669affcbbaeb5ccc4a88f42b228548d($file) { require $file; } diff --git a/composer/installed.json b/composer/installed.json index 9171c150674c..ad24666521bc 100644 --- a/composer/installed.json +++ b/composer/installed.json @@ -909,5 +909,96 @@ "php", "tags" ] + }, + { + "name": "natxet/CssMin", + "version": "dev-master", + "version_normalized": "9999999-dev", + "source": { + "type": "git", + "url": "https://github.com/natxet/CssMin.git", + "reference": "003920e783c568c2d8fdf03999eebefb8479092a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/natxet/CssMin/zipball/003920e783c568c2d8fdf03999eebefb8479092a", + "reference": "003920e783c568c2d8fdf03999eebefb8479092a", + "shasum": "" + }, + "require": { + "php": ">=5.0" + }, + "time": "2014-09-10 14:34:00", + "type": "library", + "installation-source": "source", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Joe Scylla", + "email": "joe.scylla@gmail.com", + "homepage": "https://profiles.google.com/joe.scylla" + } + ], + "description": "Minifying CSS", + "homepage": "http://code.google.com/p/cssmin/", + "keywords": [ + "css", + "minify" + ] + }, + { + "name": "mrclay/minify", + "version": "dev-master", + "version_normalized": "9999999-dev", + "source": { + "type": "git", + "url": "https://github.com/mrclay/minify.git", + "reference": "bd9a450694cda1b54c43a1784adabe36ad522d89" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mrclay/minify/zipball/bd9a450694cda1b54c43a1784adabe36ad522d89", + "reference": "bd9a450694cda1b54c43a1784adabe36ad522d89", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "php": ">=5.2.1" + }, + "require-dev": { + "tubalmartin/cssmin": "~2.4.8" + }, + "suggest": { + "tubalmartin/cssmin": "Support minify with CSSMin (YUI PHP port)" + }, + "time": "2014-09-25 11:40:53", + "type": "library", + "installation-source": "source", + "autoload": { + "classmap": [ + "min/lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Stephen Clay", + "email": "steve@mrclay.org", + "role": "Developer" + } + ], + "description": "Minify is a PHP5 app that helps you follow several rules for client-side performance. It combines multiple CSS or Javascript files, removes unnecessary whitespace and comments, and serves them with gzip encoding and optimal client-side cache headers", + "homepage": "http://code.google.com/p/minify/" } ] diff --git a/mrclay/minify/.editorconfig b/mrclay/minify/.editorconfig new file mode 100644 index 000000000000..09c610724ebe --- /dev/null +++ b/mrclay/minify/.editorconfig @@ -0,0 +1,19 @@ +# top-most EditorConfig file +root = true + +[*] +charset = utf-8 +end_of_line = lf + +; temporary +trim_trailing_whitespace = false + +[*.php] +indent_style = space +indent_size = 4 +insert_final_newline = true + +[vendor/**] +; Use editor default (possible autodetection). +indent_style = +indent_size = diff --git a/mrclay/minify/.gitignore b/mrclay/minify/.gitignore new file mode 100644 index 000000000000..76383dada768 --- /dev/null +++ b/mrclay/minify/.gitignore @@ -0,0 +1,7 @@ + +# / +/test +/docs +.idea/ +.DS_Store +vendor diff --git a/mrclay/minify/HISTORY.txt b/mrclay/minify/HISTORY.txt new file mode 100644 index 000000000000..9c44d164cd93 --- /dev/null +++ b/mrclay/minify/HISTORY.txt @@ -0,0 +1,141 @@ +Minify Release History + +(master) + * Builder styled with Bootstrap (thanks to help from acidvertigo) + +Version 2.2.0 + * Fix handling of RegEx in certain situations in JSMin + * Thanks to Vovan-VE for reporting this + * Update composer.json with support info + * Add ability to set ClosureCompiler URL + * Thanks Elan Ruusamäe for the pull request + * Better report of temp directory errors + * Also thanks to Elan Ruusamäe for anatoher pull request + * Updated CSSmin and added Minify_CSSmin wrapper + * Fix windows issue associated with long cache filenames + * Fix issue with web-based tool + * Fix bug in JSMin exceptions + * Fix "about:blank" bug in CSS_UriRewriter + * Cite is no longer a block element in HTML minification + * Allow for definition of custom config locations outside of the min directory + * Thanks Sam Bauers for the pull request + * Allow option for overriding the maximum byte size POST limit for ClosureCompiler and other additions + * Thanks Joscha Feth for the code + * Fixes to file-relative URL identification in UriRewriter + * Allow far-future expiration and file versioning with the "v" querystirng parameter in addition to existing method + * Lots of general code tidy ups + +Version 2.1.7 + * Fixes arbitrary file inclusion vulnerability on some systems + * Thanks to Matt Mecham for reporting this + +Version 2.1.6 + * JSMin fixes + * Prevents some Closure Compiler API failures + * Uses autoloading for all class loading + * Multiple group support in HTML Helper + * Cache adaptor for XCache + * Allow setting stack-size in YUI Compressor wrapper + * Adds jsCleanComments option to HTML minifier + * Upgrades CSSmin + * CLI script more portable + * Adds composer.json + +Version 2.1.5 + * Removed XSS vulnerability + * Disabled builder bby default + * command line tools to minify and rewrite URIs in CSS + * upgrade (optional) JSMin+ library + * more efficient JS minification when using CC/YUIC + * Closure Compiler uses cURL when allow_url_fopen is off + * Missing file notices when using groups + +Version 2.1.4 + * Option to minify JS with Closure Compiler API w/ JSMin failover + * Cookie/bookmarklet-based debug mode. No HTML editing! + * Allows 1 file to be missing w/o complete failure + * Combine multiple groups and files in single URI + * More useful HTML helpers for writing versioned URIs + * More detailed error logging, including minifier exceptions + * Builder offers more helpful messages/PHP environment warnings + * Bypass minification based on filename pattern. e.g. foo.min.js / foo-min.css + * JSMin won't choke on common Closure compiler syntaxes (i+ ++j) + * Better caching in IE6 + * Cache ids are influenced by group/file names + * Debug mode for Javascript doesn't break on common XPath strings (Prototype 1.6) + * Removed annoying maxFiles limit + * mbstring.func_overload usage is safer + +Version 2.1.3 + * HTTP fixes + * ETag generation now valid (different when gzipped) + * Vary header always sent when Accept-Encoding is sniffed + * Cache-Control no longer has "must-revalidate" due to webkit bug + See: http://mrclay.org/index.php/2009/02/24/safari-4-beta-cache-controlmust-revalidate-bug/ + * Dropped deflate encoding. Browser and proxy support could be buggy. + See: http://stackoverflow.com/questions/883841/ + * File cache now works w/o setting $min_cachePath + * Allow setting contentType in Minify_Source objects + * No more 5.3 deprecation warnings: split() removed + +Version 2.1.2 + * Javascript fixes + * Debug mode no longer confused by "*/*" in strings/RegExps (jQuery) + * quote characters inside RegExp literals no longer cause exception + * files ending in single-line comments no longer cause code loss + * CSS: data: URLs no longer mangled + * Optional error logging to Firefox's FirePHP extension + * Unit tests to check for common DOCUMENT_ROOT problems + * DOCUMENT_ROOT no longer overwritten on IIS servers + * Builder app doesn't fail on systems without gzdeflate() + * APC caching class included + +Version 2.1.1 + * Bug fix release + * Detection and workarounds for zlib.output_compression and non-PHP encoding modules + * Zlib not required (mod_rewrite, et.al., can still be used for encoding) + * HTML : More IE conditional comments preserved + * Minify_groupUri() utility fixed + +Version 2.1.0 + * "min" default application for quick deployment + * Minify URI Builder app & bookmarklet for quickly creating minify URIs + * Relative URIs in CSS file are fixed automatically by default + * "debug" mode for revealing original line #s in combined files + * Better IIS support + * Improved minifier classes: + * JS: preserves IE conditional comments + * CSS: smaller output, preserves more hacks and valid CSS syntax, + shorter line lengths, other bug fixes + * HTML: smaller output, shorter line lengths, other bug fixes + * Default Cache-Control: max-age of 30 minutes + * Conditional GETs supported even when max-age sent + * Experimental memcache cache class (default is files) + * Minify_Cache_File has flock()s (by default) + * Workaround for Windows mtime reporting bug + +Version 2.0.2 beta (2008-06-24) + * Fast new cache system. Cached files served almost 3x as fast. + * Dropped support of compress encoding (though HTTP_Encoder still supports it) + +Version 2.0.1 (2008-05-31) + * E_STRICT compliance (Cache_Lite_File). + +Version 2.0.0 (2008-05-22) + * Complete code overhaul. Minify is now a PEAR-style class and toolkit + for building customized minifying file servers. + * Content-Encoding: deflate/gzip/compress, based on request headers + * Expanded CSS and HTML minifiers with test cases + * Easily plug-in 3rd-party minifiers (like Packer) + * Plug-able front end controller allows changing the way files are chosen + * Compression & encoding modules lazy-loaded as needed (304 responses use + use minimal code) + * Separate utility classes for HTTP encoding and cache control + +Version 1.0.1 (2007-05-05) + * Fixed various problems resolving pathnames when hosted on an NFS mount. + * Fixed 'undefined constant' notice. + * Replaced old JSMin library with a much faster custom implementation. + +Version 1.0.0 (2007-05-02) + * First release. diff --git a/mrclay/minify/LICENSE.txt b/mrclay/minify/LICENSE.txt new file mode 100644 index 000000000000..8f008adb56a2 --- /dev/null +++ b/mrclay/minify/LICENSE.txt @@ -0,0 +1,26 @@ +Copyright (c) 2008 Ryan Grove +Copyright (c) 2008 Steve Clay +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of this project nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/mrclay/minify/MIN.txt b/mrclay/minify/MIN.txt new file mode 100644 index 000000000000..5aaf0fb8cd5b --- /dev/null +++ b/mrclay/minify/MIN.txt @@ -0,0 +1,181 @@ +The files in the /min/ directory represent the default Minify setup designed to ease +integration with your site. This app will combine and minify your Javascript or +CSS files and serve them with HTTP compression and cache headers. + + +RECOMMENDED + +It's recommended to edit /min/config.php to set $min_cachePath to a writeable +(by PHP) directory on your system. This will improve performance. + + +GETTING STARTED + +The quickest way to get started is to use the Minify URI Builder application +on your website: http://example.com/min/builder/ + + +MINIFYING A SINGLE FILE + +Let's say you want to serve this file: + http://example.com/wp-content/themes/default/default.css + +Here's the "Minify URL" for this file: + http://example.com/min/?f=wp-content/themes/default/default.css + +In other words, the "f" argument is set to the file path from root without the +initial "/". As CSS files may contain relative URIs, Minify will automatically +"fix" these by rewriting them as root relative. + + +COMBINING MULTIPLE FILES IN ONE DOWNLOAD + +Separate the paths given to "f" with commas. + +Let's say you have CSS files at these URLs: + http://example.com/scripts/jquery-1.2.6.js + http://example.com/scripts/site.js + +You can combine these files through Minify by requesting this URL: + http://example.com/min/?f=scripts/jquery-1.2.6.js,scripts/site.js + + +SIMPLIFYING URLS WITH A BASE PATH + +If you're combining files that share the same ancestor directory, you can use +the "b" argument to set the base directory for the "f" argument. Do not include +the leading or trailing "/" characters. + +E.g., the following URLs will serve the exact same content: + http://example.com/min/?f=scripts/jquery-1.2.6.js,scripts/site.js,scripts/home.js + http://example.com/min/?b=scripts&f=jquery-1.2.6.js,site.js,home.js + + +MINIFY URLS IN HTML + +In HTML files, don't forget to replace any "&" characters with "&". + + +SPECIFYING ALLOWED DIRECTORIES + +By default, Minify will serve any *.css/*.js files within the DOCUMENT_ROOT. If +you'd prefer to limit Minify's access to certain directories, set the +$min_serveOptions['minApp']['allowDirs'] array in config.php. E.g. to limit +to the /js and /themes/default directories, use: + +$min_serveOptions['minApp']['allowDirs'] = array('//js', '//themes/default'); + + +GROUPS: NICER URLS + +For nicer URLs, edit groupsConfig.php to pre-specify groups of files +to be combined under preset keys. E.g., here's an example configuration in +groupsConfig.php: + +return array( + 'js' => array('//js/Class.js', '//js/email.js') +); + +This pre-selects the following files to be combined under the key "js": + http://example.com/js/Class.js + http://example.com/js/email.js + +You can now serve these files with this simple URL: + http://example.com/min/?g=js + + +GROUPS: SPECIFYING FILES OUTSIDE THE DOC_ROOT + +In the groupsConfig.php array, the "//" in the file paths is a shortcut for +the DOCUMENT_ROOT, but you can also specify paths from the root of the filesystem +or relative to the DOC_ROOT: + +return array( + 'js' => array( + '//js/file.js' // file within DOC_ROOT + ,'//../file.js' // file in parent directory of DOC_ROOT + ,'C:/Users/Steve/file.js' // file anywhere on filesystem + ) +); + + +COMBINE MULTIPLE GROUPS AND FILES IN ONE URL + +E.g.: http://example.com/min/?g=js&f=more/scripts.js + +Separate group keys with commas: + http://example.com/min/?g=baseCss,css1&f=moreStyles.css + + +FAR-FUTURE EXPIRES HEADERS + +Minify can send far-future (one year) Expires headers. To enable this you must +add a number or the parameter "v" to the querystring (e.g. /min/?g=js&1234 or +/min/?g=js&v=1234) and alter it whenever a source file is changed. If you have a +build process you can use a build/source control revision number. + +You can alternately use the utility function Minify_getUri() to get a "versioned" +Minify URI for use in your HTML. E.g.: + +"; + +$cssUri = Minify_getUri(array( + '//css/styles1.css' + ,'//css/styles2.css' +)); // a list of files +echo ""; + + +STORING CONFIG FILES OUTSIDE THE MINIFY DIRECTORY + +It is possible to store config files (min/config.php, min/config-test.php, +min/groupsConfig.php) in a custom directory outside the Minify directory. This is +useful if you wish to include Minify as an external dependency inside another +project via SVN external or Git submodule inclusion. + +For example, let's assume you have a Minify directory "min" in your site root. Then +you could create a new directory called "min-configs" in the site root. Copy any +config files you wish to modify to "min-configs", and modify as desired. + +Then create a new file, for example "min.php" in your site root. The contents of +this file could look like this: + + $customConfigDirectory . '/config.php', + 'test' => $customConfigDirectory . '/config-test.php', + 'groups' => $customConfigDirectory . '/groupsConfig.php' +); + +include_once 'min/index.php'; + +You would then reference min.php in your JS and CSS links instead of min/index.php. + +This method will affect those using the Minify_getUri() function. You will need +to add options to calls to that function, e.g.: + + '/min.php')); +echo ""; + + +DEBUG MODE + +In debug mode, instead of compressing files, Minify sends combined files with +comments prepended to each line to show the line number in the original source +file. To enable this, set $min_allowDebugFlag to true in config.php and append +"&debug=1" to your URIs. E.g. /min/?f=script1.js,script2.js&debug=1 + +Known issue: files with comment-like strings/regexps can cause problems in this mode. + + +QUESTIONS? + +http://groups.google.com/group/minify diff --git a/mrclay/minify/README.txt b/mrclay/minify/README.txt new file mode 100644 index 000000000000..54b0690f832d --- /dev/null +++ b/mrclay/minify/README.txt @@ -0,0 +1,68 @@ +WELCOME TO MINIFY! + +Minify is an HTTP content server. It compresses sources of content +(usually files), combines the result and serves it with appropriate +HTTP headers. These headers can allow clients to perform conditional +GETs (serving content only when clients do not have a valid cache) +and tell clients to cache the file for a period of time. +More info: http://code.google.com/p/minify/ + + +WORDPRESS USER? + +These WP plugins integrate Minify into WordPress's style and script hooks to +get you set up faster. + http://wordpress.org/extend/plugins/bwp-minify/ + http://wordpress.org/extend/plugins/w3-total-cache/ + + +INSTALLATION + +Place the /min/ directory as a child of your DOCUMENT_ROOT +directory: i.e. you will have: /home/example/www/min + +You can see verify that it is working by visiting these two URLs: + http://example.org/min/?f=min/quick-test.js + http://example.org/min/?f=min/quick-test.css + +If your server supports mod_rewrite, this URL should also work: + http://example.org/min/f=min/quick-test.js + +CONFIGURATION & USAGE + +See the MIN.txt file and http://code.google.com/p/minify/wiki/UserGuide + +Minify also comes with a URI Builder application that can help you write URLs +for use with Minify or configure groups of files. See here for details: + http://code.google.com/p/minify/wiki/BuilderApp + +The cookbook also provides some more advanced options for minification: + http://code.google.com/p/minify/wiki/CookBook + +UPGRADING + +See UPGRADING.txt for instructions. + + +UNIT TESTING: + +1. Place the /min_unit_tests/ directory as a child of your DOCUMENT_ROOT +directory: i.e. you will have: /home/example/www/min_unit_tests + +2. To run unit tests, access: http://example.org/min_unit_tests/test_all.php + +(If you wish, the other test_*.php files can be run to test individual +components with more verbose output.) + +3. Remove /min_unit_tests/ from your DOCUMENT_ROOT when you are done. + + +FILE ENCODINGS + +Minify *should* work fine with files encoded in UTF-8 or other 8-bit +encodings like ISO 8859/Windows-1252. By default Minify appends +";charset=utf-8" to the Content-Type headers it sends. + +Leading UTF-8 BOMs are stripped from all sources to prevent +duplication in output files, and files are converted to Unix newlines. + diff --git a/mrclay/minify/UPGRADING.txt b/mrclay/minify/UPGRADING.txt new file mode 100644 index 000000000000..647b9cc31fd6 --- /dev/null +++ b/mrclay/minify/UPGRADING.txt @@ -0,0 +1,28 @@ +Minify Upgrade Guide + +UPGRADING FROM 2.1.* + +1. Rename the following files: + + /min/config.php --> /min/old_config.php + /min/groupsConfig.php --> /min/old_groupsConfig.php + +2. Overwrite all files in /min (and /min_unit_tests) with those from this zip. + +3. Delete /min/groupsConfig.php + +4. Rename /min/old_groupsConfig.php --> /min/groupsConfig.php + +5. Merge your settings in old_config.php into config.php. + +6. (optional) Delete /min/old_config.php. + + +INSTALLING FRESH + +See README.txt for instructions on installing this app for the first time. + + +SUPPORT + +Send a message to http://groups.google.com/group/minify \ No newline at end of file diff --git a/mrclay/minify/composer.json b/mrclay/minify/composer.json new file mode 100644 index 000000000000..bb6b8702a3fb --- /dev/null +++ b/mrclay/minify/composer.json @@ -0,0 +1,32 @@ +{ + "name": "mrclay/minify", + "type": "library", + "description": "Minify is a PHP5 app that helps you follow several rules for client-side performance. It combines multiple CSS or Javascript files, removes unnecessary whitespace and comments, and serves them with gzip encoding and optimal client-side cache headers", + "homepage": "http://code.google.com/p/minify/", + "license": "BSD-3-Clause", + "authors": [ + { + "name": "Stephen Clay", + "email": "steve@mrclay.org", + "role": "Developer" + } + ], + "support": { + "email": "minify@googlegroups.com", + "issues": "http://code.google.com/p/minify/issues/list", + "wiki": "http://code.google.com/p/minify/w/list" + }, + "autoload": { + "classmap": ["min/lib/"] + }, + "require": { + "php": ">=5.2.1", + "ext-pcre": "*" + }, + "require-dev": { + "tubalmartin/cssmin": "~2.4.8" + }, + "suggest": { + "tubalmartin/cssmin": "Support minify with CSSMin (YUI PHP port)" + } +} diff --git a/mrclay/minify/min/.htaccess b/mrclay/minify/min/.htaccess new file mode 100644 index 000000000000..06c1161ef37b --- /dev/null +++ b/mrclay/minify/min/.htaccess @@ -0,0 +1,13 @@ + +RewriteEngine on + +# You may need RewriteBase on some servers +#RewriteBase /min + +# rewrite URLs like "/min/f=..." to "/min/?f=..." +RewriteRule ^([bfg]=.*) index.php?$1 [L,NE] + + +# In case AddOutputFilterByType has been added +SetEnv no-gzip + diff --git a/mrclay/minify/min/builder/.htaccess b/mrclay/minify/min/builder/.htaccess new file mode 100644 index 000000000000..53cac3b13200 --- /dev/null +++ b/mrclay/minify/min/builder/.htaccess @@ -0,0 +1,4 @@ + +RewriteEngine on +RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] + \ No newline at end of file diff --git a/mrclay/minify/min/builder/_index.js b/mrclay/minify/min/builder/_index.js new file mode 100644 index 000000000000..de13fb389c8e --- /dev/null +++ b/mrclay/minify/min/builder/_index.js @@ -0,0 +1,260 @@ +/*! + * Minify URI Builder + */ +var MUB = { + _uid : 0, + _minRoot : '/min/?', + checkRewrite : function () { + var testUri = location.pathname.replace(/\/[^\/]*$/, '/rewriteTest.js').substr(1); + function fail() { + $('#minRewriteFailed')[0].className = 'topNote'; + } + $.ajax({ + url : '../f=' + testUri + '&' + (new Date()).getTime(), + success : function (data) { + if (data === '1') { + MUB._minRoot = '/min/'; + $('span.minRoot').html('/min/'); + } else + fail(); + }, + error : fail + }); + }, + /** + * Get markup for new source LI element + */ + newLi : function () { + return '
  • http://' + location.host + '/' + + ' ' + + '
  • '; + }, + /** + * Add new empty source LI and attach handlers to buttons + */ + addLi : function () { + $('#sources').append(MUB.newLi()); + var li = $('#li' + MUB._uid)[0]; + $('button[title=Remove]', li).click(function () { + $('#results').addClass('hide'); + var hadValue = !!$('input', li)[0].value; + $(li).remove(); + }); + $('button[title$=Earlier]', li).click(function () { + $(li).prev('li').find('input').each(function () { + $('#results').addClass('hide'); + // this = previous li input + var tmp = this.value; + this.value = $('input', li).val(); + $('input', li).val(tmp); + MUB.updateAllTestLinks(); + }); + }); + $('button[title$=Later]', li).click(function () { + $(li).next('li').find('input').each(function () { + $('#results').addClass('hide'); + // this = next li input + var tmp = this.value; + this.value = $('input', li).val(); + $('input', li).val(tmp); + MUB.updateAllTestLinks(); + }); + }); + ++MUB._uid; + }, + /** + * In the context of a source LI element, this will analyze the URI in + * the INPUT and check the URL on the site. + */ + liUpdateTestLink : function () { // call in context of li element + if (! $('input', this)[0].value) + return; + var li = this; + $('span', this).html(''); + var url = location.protocol + '//' + location.host + '/' + + $('input', this)[0].value.replace(/^\//, ''); + $.ajax({ + url : url, + complete : function (xhr, stat) { + if ('success' === stat) + $('span', li).html(''); + else { + $('span', li).html('') + .find('button').click(function () { + MUB.liUpdateTestLink.call(li); + }); + } + }, + dataType : 'text' + }); + }, + /** + * Check all source URLs + */ + updateAllTestLinks : function () { + $('#sources li').each(MUB.liUpdateTestLink); + }, + /** + * In a given array of strings, find the character they all have at + * a particular index + * @param Array arr array of strings + * @param Number pos index to check + * @return mixed a common char or '' if any do not match + */ + getCommonCharAtPos : function (arr, pos) { + var i, + l = arr.length, + c = arr[0].charAt(pos); + if (c === '' || l === 1) + return c; + for (i = 1; i < l; ++i) + if (arr[i].charAt(pos) !== c) + return ''; + return c; + }, + /** + * Get the shortest URI to minify the set of source files + * @param Array sources URIs + */ + getBestUri : function (sources) { + var pos = 0, + base = '', + c; + while (true) { + c = MUB.getCommonCharAtPos(sources, pos); + if (c === '') + break; + else + base += c; + ++pos; + } + base = base.replace(/[^\/]+$/, ''); + var uri = MUB._minRoot + 'f=' + sources.join(','); + if (base.charAt(base.length - 1) === '/') { + // we have a base dir! + var basedSources = sources, + i, + l = sources.length; + for (i = 0; i < l; ++i) { + basedSources[i] = sources[i].substr(base.length); + } + base = base.substr(0, base.length - 1); + var bUri = MUB._minRoot + 'b=' + base + '&f=' + basedSources.join(','); + //window.console && console.log([uri, bUri]); + uri = uri.length < bUri.length ? uri : bUri; + } + return uri; + }, + /** + * Create the Minify URI for the sources + */ + update : function () { + MUB.updateAllTestLinks(); + var sources = [], + ext = false, + fail = false, + markup; + $('#sources input').each(function () { + var m, val; + if (! fail && this.value && (m = this.value.match(/\.(css|js)$/))) { + var thisExt = m[1]; + if (ext === false) + ext = thisExt; + else if (thisExt !== ext) { + fail = true; + return alert('extensions must match!'); + } + this.value = this.value.replace(/^\//, ''); + if (-1 !== $.inArray(this.value, sources)) { + fail = true; + return alert('duplicate file!'); + } + sources.push(this.value); + } + }); + if (fail || ! sources.length) + return; + $('#groupConfig').val(" 'keyName' => array('//" + sources.join("', '//") + "'),"); + var uri = MUB.getBestUri(sources), + uriH = uri.replace(//, '>').replace(/&/, '&'); + $('#uriA').html(uriH)[0].href = uri; + if (ext === 'js') { + markup = ''; + } else { + markup = ''; + } + $('#uriHtml').val(markup); + $('#results').removeClass('hide'); + }, + /** + * Handler for the "Add file +" button + */ + addButtonClick : function () { + $('#results').addClass('hide'); + MUB.addLi(); + MUB.updateAllTestLinks(); + $('#update').removeClass('hide').click(MUB.update); + $('#sources li:last input')[0].focus(); + }, + /** + * Runs on DOMready + */ + init : function () { + $('#jsDidntLoad').remove(); + $('#app').removeClass('hide'); + $('#sources').html(''); + $('#add button').click(MUB.addButtonClick); + // make easier to copy text out of + $('#uriHtml, #groupConfig, #symlinkOpt').click(function () { + this.select(); + }).focus(function () { + this.select(); + }); + $('a.ext').attr({target:'_blank'}); + if (location.hash) { + // make links out of URIs from bookmarklet + $('#getBm').addClass('hide'); + var i = 0, found = location.hash.substr(1).split(','), l = found.length; + $('#bmUris').html('

    Found by bookmarklet: /

    '); + var $p = $('#bmUris p'); + for (; i < l; i++) { + $p.append($('').text(found[i])[0]); + if (i < (l - 1)) { + $p.append(', /'); + } + } + $('#bmUris a').click(function () { + MUB.addButtonClick(); + $('#sources li:last input').val(this.innerHTML); + MUB.liUpdateTestLink.call($('#sources li:last')[0]); + $('#results').addClass('hide'); + return false; + }).attr({title:'Add file +'}); + } else { + // setup bookmarklet 1 + $.ajax({ + url : '../?f=' + location.pathname.replace(/\/[^\/]*$/, '/bm.js').substr(1), + success : function (code) { + $('#bm')[0].href = code + .replace('%BUILDER_URL%', location.href) + .replace(/\n/g, ' '); + }, + dataType : 'text' + }); + if ($.browser.msie) { + $('#getBm p:last').append(' Sorry, not supported in MSIE!'); + } + MUB.addButtonClick(); + } + // setup bookmarklet 2 + $.ajax({ + url : '../?f=' + location.pathname.replace(/\/[^\/]*$/, '/bm2.js').substr(1), + success : function (code) { + $('#bm2')[0].href = code.replace(/\n/g, ' '); + }, + dataType : 'text' + }); + MUB.checkRewrite(); + } +}; +$(MUB.init); diff --git a/mrclay/minify/min/builder/bm.js b/mrclay/minify/min/builder/bm.js new file mode 100644 index 000000000000..10d19438143c --- /dev/null +++ b/mrclay/minify/min/builder/bm.js @@ -0,0 +1,36 @@ +javascript:(function() { + var d = document + ,uris = [] + ,i = 0 + ,o + ,home = (location + '').split('/').splice(0, 3).join('/') + '/'; + function add(uri) { + return (0 === uri.indexOf(home)) + && (!/[\?&]/.test(uri)) + && uris.push(escape(uri.substr(home.length))); + }; + function sheet(ss) { + // we must check the domain with add() before accessing ss.cssRules + // otherwise a security exception will be thrown + if (ss.href && add(ss.href) && ss.cssRules) { + var i = 0, r; + while (r = ss.cssRules[i++]) + r.styleSheet && sheet(r.styleSheet); + } + }; + while (o = d.getElementsByTagName('script')[i++]) + o.src && !(o.type && /vbs/i.test(o.type)) && add(o.src); + i = 0; + while (o = d.styleSheets[i++]) + /* http://www.w3.org/TR/DOM-Level-2-Style/stylesheets.html#StyleSheets-DocumentStyle-styleSheets + document.styleSheet is a list property where [0] accesses the 1st element and + [outOfRange] returns null. In IE, styleSheets is a function, and also throws an + exception when you check the out of bounds index. (sigh) */ + sheet(o); + if (uris.length) + window.open('%BUILDER_URL%#' + uris.join(',')); + else + alert('No js/css files found with URLs within "' + + home.split('/')[2] + + '".\n(This tool is limited to URLs with the same domain.)'); +})(); \ No newline at end of file diff --git a/mrclay/minify/min/builder/bm2.js b/mrclay/minify/min/builder/bm2.js new file mode 100644 index 000000000000..6b558ce0c1bb --- /dev/null +++ b/mrclay/minify/min/builder/bm2.js @@ -0,0 +1,15 @@ +javascript:(function(){ + var d = document + ,c = d.cookie + ,m = c.match(/\bminifyDebug=([^; ]+)/) + ,v = m ? decodeURIComponent(m[1]) : '' + ,p = prompt('Debug Minify URIs on ' + location.hostname + ' which contain:' + + '\n(empty for none, space = OR, * = any string, ? = any char)', v) + ; + if (p === null) return; + p = p.replace(/^\s+|\s+$/, ''); + v = (p === '') + ? 'minifyDebug=; expires=Fri, 27 Jul 2001 02:47:11 UTC; path=/' + : 'minifyDebug=' + encodeURIComponent(p) + '; path=/'; + d.cookie = v; +})(); \ No newline at end of file diff --git a/mrclay/minify/min/builder/index.php b/mrclay/minify/min/builder/index.php new file mode 100644 index 000000000000..78a533ba1801 --- /dev/null +++ b/mrclay/minify/min/builder/index.php @@ -0,0 +1,241 @@ + $min_builderPassword)); +} + +$cachePathCode = ''; +if (! isset($min_cachePath) && ! function_exists('sys_get_temp_dir')) { + $detectedTmp = Minify_Cache_File::tmp(); + $cachePathCode = "\$min_cachePath = " . var_export($detectedTmp, 1) . ';'; +} + +ob_start(); +?> + +Minify URI Builder + + + + + +
    Note: It looks like you're running Minify in a user + directory. You may need the following option in /min/config.php to have URIs + correctly rewritten in CSS output: +
    +
    + + +

    Uh Oh. Minify was unable to + serve Javascript for this app. To troubleshoot this, + enable FirePHP debugging + and request the Minify URL directly. Hopefully the + FirePHP console will report the cause of the error. +

    + + +

    Note: was discovered as a usable temp directory.
    To + slightly improve performance you can hardcode this in /min/config.php: +

    + + +

    Note: Your webserver does not seem to + support mod_rewrite (used in /min/.htaccess). Your Minify URIs will contain "?", which +may reduce the benefit of proxy cache servers.

    + +

    Minify URI Builder

    + + + +
    + +

    Create a list of Javascript or CSS files (or 1 is fine) you'd like to combine +and click [Update].

    + +
    +
    + +
    + +

    + +
    + +

    Minify URI

    +

    Place this URI in your HTML to serve the files above combined, minified, compressed and +with cache headers.

    + + + +
    URI/min (opens in new window)
    HTML
    + +

    How to serve these files as a group

    +

    For the best performance you can serve these files as a pre-defined group with a URI +like: /min/?g=keyName

    +

    To do this, add a line like this to /min/groupsConfig.php:

    + +
    return array(
    +    ... your existing groups here ...
    +
    +);
    + +

    Make sure to replace keyName with a unique key for this group.

    +
    + +
    +

    Find URIs on a Page

    +

    You can use the bookmarklet below to fetch all CSS & Javascript URIs from a page +on your site. When you active it, this page will open in a new window with a list of +available URIs to add.

    + +

    Create Minify URIs (right-click, add to bookmarks)

    +
    + +

    Combining CSS files that contain @import

    +

    If your CSS files contain @import declarations, Minify will not +remove them. Therefore, you will want to remove those that point to files already +in your list, and move any others to the top of the first file in your list +(imports below any styles will be ignored by browsers as invalid).

    +

    If you desire, you can use Minify URIs in imports and they will not be touched +by Minify. E.g. @import "/min/?g=css2";

    + +

    Debug Mode

    +

    When /min/config.php has $min_allowDebugFlag = true; + you can get debug output by appending &debug to a Minify URL, or + by sending the cookie minDebug=<match>, where <match> + should be a string in the Minify URIs you'd like to debug. This bookmarklet will allow you to + set this cookie.

    +

    Minify Debug (right-click, add to bookmarks)

    + +
    + +
    +

    Need help? Check the wiki, + or post to the discussion + list.

    +

    Powered by Minify

    + + + + + + $content + ,'id' => __FILE__ + ,'lastModifiedTime' => max( + // regenerate cache if any of these change + filemtime(__FILE__) + ,filemtime(dirname(__FILE__) . '/../config.php') + ,filemtime(dirname(__FILE__) . '/../lib/Minify.php') + ) + ,'minifyAll' => true + ,'encodeOutput' => $encodeOutput +)); diff --git a/mrclay/minify/min/builder/jquery-1.6.3.min.js b/mrclay/minify/min/builder/jquery-1.6.3.min.js new file mode 100644 index 000000000000..89b152163b05 --- /dev/null +++ b/mrclay/minify/min/builder/jquery-1.6.3.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.6.3 http://jquery.com/ | http://jquery.org/license */ +(function(a,b){function cu(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cr(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cq(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cp(){cn=b}function co(){setTimeout(cp,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bv(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bl(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bd,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bk(a){f.nodeName(a,"input")?bj(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bj)}function bj(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bi(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bh(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bg(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function U(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function M(a,b){return(a&&a!=="*"?a+".":"")+b.replace(y,"`").replace(z,"&")}function L(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function J(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function D(){return!0}function C(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function K(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(K,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+"").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.3",length:0,size:function(){return this.length},toArray:function(){return G.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?F.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),B.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(G.apply(this,arguments),"slice",G.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:F,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;B.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!B){B=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",C,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",C),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,"constructor")&&!E.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(x,"ms-").replace(w,y)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
    a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},m&&f.extend(p,{position:"absolute",left:"-1000px",top:"-1000px"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
    ",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
    t
    ",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i=f.expando,j=typeof c=="string",k=a.nodeType,l=k?f.cache:a,m=k?a[f.expando]:a[f.expando]&&f.expando;if((!m||e&&m&&l[m]&&!l[m][i])&&j&&d===b)return;m||(k?a[f.expando]=m=++f.uuid:m=f.expando),l[m]||(l[m]={},k||(l[m].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?l[m][i]=f.extend(l[m][i],c):l[m]=f.extend(l[m],c);g=l[m],e&&(g[i]||(g[i]={}),g=g[i]),d!==b&&(g[f.camelCase(c)]=d);if(c==="events"&&!g[c])return g[i]&&g[i].events;j?(h=g[c],h==null&&(h=g[f.camelCase(c)])):h=g;return h}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e=f.expando,g=a.nodeType,h=g?f.cache:a,i=g?a[f.expando]:f.expando;if(!h[i])return;if(b){d=c?h[i][e]:h[i];if(d){d[b]||(b=f.camelCase(b)),delete d[b];if(!l(d))return}}if(c){delete h[i][e];if(!l(h[i]))return}var j=h[i][e];f.support.deleteExpando||!h.setInterval?delete h[i]:h[i]=null,j?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=j):g&&(f.support.deleteExpando?delete a[f.expando]:a.removeAttribute?a.removeAttribute(f.expando):a[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=v:u&&(i=u)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.attr(a,b,""),a.removeAttribute(b),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(u&&f.nodeName(a,"button"))return u.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(u&&f.nodeName(a,"button"))return u.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==null?g:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabIndex=f.propHooks.tabIndex,v={get:function(a,c){var d;return f.prop(a,c)===!0||(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(u=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var w=/\.(.*)$/,x=/^(?:textarea|input|select)$/i,y=/\./g,z=/ /g,A=/[^\w\s.|`]/g,B=function(a){return a.replace(A,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=C;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=C);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),B).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},I=function(c){var d=c.target,e,g;if(!!x.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=H(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:I,beforedeactivate:I,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&I.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&I.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",H(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in G)f.event.add(this,c+".specialChange",G[c]);return x.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return x.test(this.nodeName)}},G=f.event.special.change.filters,G.focus=G.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

    ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
    ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=S.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(U(c[0])||U(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=R.call(arguments);N.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!T[a]?f.unique(e):e,(this.length>1||P.test(d))&&O.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]};be.optgroup=be.option,be.tbody=be.tfoot=be.colgroup=be.caption=be.thead,be.th=be.td,f.support.htmlSerialize||(be._default=[1,"div
    ","
    "]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!be[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bh(a,d),e=bi(a),g=bi(d);for(h=0;e[h];++h)g[h]&&bh(e[h],g[h])}if(b){bg(a,d);if(c){e=bi(a),g=bi(d);for(h=0;e[h];++h)bg(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=be[l]||be._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bn.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bm,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bm.test(g)?g.replace(bm,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bv(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bw=function(a,c){var d,e,g;c=c.replace(bo,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bx=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bp.test(d)&&bq.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bv=bw||bx,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bz=/%20/g,bA=/\[\]$/,bB=/\r?\n/g,bC=/#.*$/,bD=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bE=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bF=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bG=/^(?:GET|HEAD)$/,bH=/^\/\//,bI=/\?/,bJ=/)<[^<]*)*<\/script>/gi,bK=/^(?:select|textarea)/i,bL=/\s+/,bM=/([?&])_=[^&]*/,bN=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bO=f.fn.load,bP={},bQ={},bR,bS,bT=["*/"]+["*"];try{bR=e.href}catch(bU){bR=c.createElement("a"),bR.href="",bR=bR.href}bS=bN.exec(bR.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bO)return bO.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
    ").append(c.replace(bJ,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bK.test(this.nodeName)||bE.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bB,"\r\n")}}):{name:b.name,value:c.replace(bB,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?bX(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),bX(a,b);return a},ajaxSettings:{url:bR,isLocal:bF.test(bS[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bT},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bV(bP),ajaxTransport:bV(bQ),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?bZ(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=b$(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bD.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bC,"").replace(bH,bS[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bL),d.crossDomain==null&&(r=bN.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bS[1]&&r[2]==bS[2]&&(r[3]||(r[1]==="http:"?80:443))==(bS[3]||(bS[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bW(bP,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bG.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bI.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bM,"$1_="+x);d.url=y+(y===d.url?(bI.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bT+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bW(bQ,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){s<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bz,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cq("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
    ";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=ct.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!ct.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cu(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cu(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNaN(j)?i:j}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/mrclay/minify/min/builder/ocCheck.php b/mrclay/minify/min/builder/ocCheck.php new file mode 100644 index 000000000000..5c40e7471c78 --- /dev/null +++ b/mrclay/minify/min/builder/ocCheck.php @@ -0,0 +1,36 @@ + 'World!' + ,'method' => 'deflate' + )); + $he->encode(); + $he->sendAll(); + +} else { + // echo status "0" or "1" + header('Content-Type: text/plain'); + echo (int)$_oc; +} diff --git a/mrclay/minify/min/builder/rewriteTest.js b/mrclay/minify/min/builder/rewriteTest.js new file mode 100644 index 000000000000..56a6051ca2b0 --- /dev/null +++ b/mrclay/minify/min/builder/rewriteTest.js @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/mrclay/minify/min/builder/test.php b/mrclay/minify/min/builder/test.php new file mode 100644 index 000000000000..7f3e04be2090 --- /dev/null +++ b/mrclay/minify/min/builder/test.php @@ -0,0 +1,43 @@ +realpath(DOCUMENT_ROOT) failed. You may need " + . "to set \$min_documentRoot manually (hopefully realpath() is not " + . "broken in your environment).

    "; + } + if (0 !== strpos(realpath(__FILE__), realpath($_SERVER['DOCUMENT_ROOT']))) { + echo "

    DOCUMENT_ROOT doesn't contain this file. You may " + . " need to set \$min_documentRoot manually

    "; + } + if (isset($_SERVER['SUBDOMAIN_DOCUMENT_ROOT'])) { + echo "

    \$_SERVER['SUBDOMAIN_DOCUMENT_ROOT'] is set. " + . "You may need to set \$min_documentRoot to this in config.php

    "; + } + +} + +//*/ \ No newline at end of file diff --git a/mrclay/minify/min/config-test.php b/mrclay/minify/min/config-test.php new file mode 100644 index 000000000000..7524a3d11042 --- /dev/null +++ b/mrclay/minify/min/config-test.php @@ -0,0 +1,10 @@ + + * array('//symlink' => '/real/target/path') // unix + * array('//static' => 'D:\\staticStorage') // Windows + * + */ +$min_symlinks = array(); + + +/** + * If you upload files from Windows to a non-Windows server, Windows may report + * incorrect mtimes for the files. This may cause Minify to keep serving stale + * cache files when source file changes are made too frequently (e.g. more than + * once an hour). + * + * Immediately after modifying and uploading a file, use the touch command to + * update the mtime on the server. If the mtime jumps ahead by a number of hours, + * set this variable to that number. If the mtime moves back, this should not be + * needed. + * + * In the Windows SFTP client WinSCP, there's an option that may fix this + * issue without changing the variable below. Under login > environment, + * select the option "Adjust remote timestamp with DST". + * @link http://winscp.net/eng/docs/ui_login_environment#daylight_saving_time + */ +$min_uploaderHoursBehind = 0; + + +/** + * Path to Minify's lib folder. If you happen to move it, change + * this accordingly. + */ +$min_libPath = dirname(__FILE__) . '/lib'; + + +// try to disable output_compression (may not have an effect) +ini_set('zlib.output_compression', '0'); diff --git a/mrclay/minify/min/groupsConfig.php b/mrclay/minify/min/groupsConfig.php new file mode 100644 index 000000000000..c9007768381e --- /dev/null +++ b/mrclay/minify/min/groupsConfig.php @@ -0,0 +1,17 @@ + array('//js/file1.js', '//js/file2.js'), + // 'css' => array('//css/file1.css', '//css/file2.css'), +); \ No newline at end of file diff --git a/mrclay/minify/min/index.php b/mrclay/minify/min/index.php new file mode 100644 index 000000000000..a49ad0b688ef --- /dev/null +++ b/mrclay/minify/min/index.php @@ -0,0 +1,86 @@ + MINIFY_MIN_DIR . '/config.php', + 'test' => MINIFY_MIN_DIR . '/config-test.php', + 'groups' => MINIFY_MIN_DIR . '/groupsConfig.php' +); + +// check for custom config paths +if (!empty($min_customConfigPaths) && is_array($min_customConfigPaths)) { + $min_configPaths = array_merge($min_configPaths, $min_customConfigPaths); +} + +// load config +require $min_configPaths['base']; + +if (isset($_GET['test'])) { + include $min_configPaths['test']; +} + +require "$min_libPath/Minify/Loader.php"; +Minify_Loader::register(); + +Minify::$uploaderHoursBehind = $min_uploaderHoursBehind; +Minify::setCache( + isset($min_cachePath) ? $min_cachePath : '' + ,$min_cacheFileLocking +); + +if ($min_documentRoot) { + $_SERVER['DOCUMENT_ROOT'] = $min_documentRoot; + Minify::$isDocRootSet = true; +} + +$min_serveOptions['minifierOptions']['text/css']['symlinks'] = $min_symlinks; +// auto-add targets to allowDirs +foreach ($min_symlinks as $uri => $target) { + $min_serveOptions['minApp']['allowDirs'][] = $target; +} + +if ($min_allowDebugFlag) { + $min_serveOptions['debug'] = Minify_DebugDetector::shouldDebugRequest($_COOKIE, $_GET, $_SERVER['REQUEST_URI']); +} + +if ($min_errorLogger) { + if (true === $min_errorLogger) { + $min_errorLogger = FirePHP::getInstance(true); + } + Minify_Logger::setLogger($min_errorLogger); +} + +// check for URI versioning +if (preg_match('/&\\d/', $_SERVER['QUERY_STRING']) || isset($_GET['v'])) { + $min_serveOptions['maxAge'] = 31536000; +} + +// need groups config? +if (isset($_GET['g'])) { + // well need groups config + $min_serveOptions['minApp']['groups'] = (require $min_configPaths['groups']); +} + +// serve or redirect +if (isset($_GET['f']) || isset($_GET['g'])) { + if (! isset($min_serveController)) { + $min_serveController = new Minify_Controller_MinApp(); + } + Minify::serve($min_serveController, $min_serveOptions); + +} elseif ($min_enableBuilder) { + header('Location: builder/'); + exit; +} else { + header('Location: /'); + exit; +} diff --git a/mrclay/minify/min/lib/CSSmin.php b/mrclay/minify/min/lib/CSSmin.php new file mode 100644 index 000000000000..fab01028b23a --- /dev/null +++ b/mrclay/minify/min/lib/CSSmin.php @@ -0,0 +1,777 @@ +memory_limit = 128 * 1048576; // 128MB in bytes + $this->max_execution_time = 60; // 1 min + $this->pcre_backtrack_limit = 1000 * 1000; + $this->pcre_recursion_limit = 500 * 1000; + + $this->raise_php_limits = (bool) $raise_php_limits; + } + + /** + * Minify a string of CSS + * @param string $css + * @param int|bool $linebreak_pos + * @return string + */ + public function run($css = '', $linebreak_pos = FALSE) + { + if (empty($css)) { + return ''; + } + + if ($this->raise_php_limits) { + $this->do_raise_php_limits(); + } + + $this->comments = array(); + $this->preserved_tokens = array(); + + $start_index = 0; + $length = strlen($css); + + $css = $this->extract_data_urls($css); + + // collect all comment blocks... + while (($start_index = $this->index_of($css, '/*', $start_index)) >= 0) { + $end_index = $this->index_of($css, '*/', $start_index + 2); + if ($end_index < 0) { + $end_index = $length; + } + $comment_found = $this->str_slice($css, $start_index + 2, $end_index); + $this->comments[] = $comment_found; + $comment_preserve_string = self::COMMENT . (count($this->comments) - 1) . '___'; + $css = $this->str_slice($css, 0, $start_index + 2) . $comment_preserve_string . $this->str_slice($css, $end_index); + // Set correct start_index: Fixes issue #2528130 + $start_index = $end_index + 2 + strlen($comment_preserve_string) - strlen($comment_found); + } + + // preserve strings so their content doesn't get accidentally minified + $css = preg_replace_callback('/(?:"(?:[^\\\\"]|\\\\.|\\\\)*")|'."(?:'(?:[^\\\\']|\\\\.|\\\\)*')/S", array($this, 'replace_string'), $css); + + // Let's divide css code in chunks of 5.000 chars aprox. + // Reason: PHP's PCRE functions like preg_replace have a "backtrack limit" + // of 100.000 chars by default (php < 5.3.7) so if we're dealing with really + // long strings and a (sub)pattern matches a number of chars greater than + // the backtrack limit number (i.e. /(.*)/s) PCRE functions may fail silently + // returning NULL and $css would be empty. + $charset = ''; + $charset_regexp = '/(@charset)( [^;]+;)/i'; + $css_chunks = array(); + $css_chunk_length = 5000; // aprox size, not exact + $start_index = 0; + $i = $css_chunk_length; // save initial iterations + $l = strlen($css); + + + // if the number of characters is 5000 or less, do not chunk + if ($l <= $css_chunk_length) { + $css_chunks[] = $css; + } else { + // chunk css code securely + while ($i < $l) { + $i += 50; // save iterations + if ($l - $start_index <= $css_chunk_length || $i >= $l) { + $css_chunks[] = $this->str_slice($css, $start_index); + break; + } + if ($css[$i - 1] === '}' && $i - $start_index > $css_chunk_length) { + // If there are two ending curly braces }} separated or not by spaces, + // join them in the same chunk (i.e. @media blocks) + $next_chunk = substr($css, $i); + if (preg_match('/^\s*\}/', $next_chunk)) { + $i = $i + $this->index_of($next_chunk, '}') + 1; + } + + $css_chunks[] = $this->str_slice($css, $start_index, $i); + $start_index = $i; + } + } + } + + // Minify each chunk + for ($i = 0, $n = count($css_chunks); $i < $n; $i++) { + $css_chunks[$i] = $this->minify($css_chunks[$i], $linebreak_pos); + // Keep the first @charset at-rule found + if (empty($charset) && preg_match($charset_regexp, $css_chunks[$i], $matches)) { + $charset = strtolower($matches[1]) . $matches[2]; + } + // Delete all @charset at-rules + $css_chunks[$i] = preg_replace($charset_regexp, '', $css_chunks[$i]); + } + + // Update the first chunk and push the charset to the top of the file. + $css_chunks[0] = $charset . $css_chunks[0]; + + return implode('', $css_chunks); + } + + /** + * Sets the memory limit for this script + * @param int|string $limit + */ + public function set_memory_limit($limit) + { + $this->memory_limit = $this->normalize_int($limit); + } + + /** + * Sets the maximum execution time for this script + * @param int|string $seconds + */ + public function set_max_execution_time($seconds) + { + $this->max_execution_time = (int) $seconds; + } + + /** + * Sets the PCRE backtrack limit for this script + * @param int $limit + */ + public function set_pcre_backtrack_limit($limit) + { + $this->pcre_backtrack_limit = (int) $limit; + } + + /** + * Sets the PCRE recursion limit for this script + * @param int $limit + */ + public function set_pcre_recursion_limit($limit) + { + $this->pcre_recursion_limit = (int) $limit; + } + + /** + * Try to configure PHP to use at least the suggested minimum settings + */ + private function do_raise_php_limits() + { + $php_limits = array( + 'memory_limit' => $this->memory_limit, + 'max_execution_time' => $this->max_execution_time, + 'pcre.backtrack_limit' => $this->pcre_backtrack_limit, + 'pcre.recursion_limit' => $this->pcre_recursion_limit + ); + + // If current settings are higher respect them. + foreach ($php_limits as $name => $suggested) { + $current = $this->normalize_int(ini_get($name)); + // memory_limit exception: allow -1 for "no memory limit". + if ($current > -1 && ($suggested == -1 || $current < $suggested)) { + ini_set($name, $suggested); + } + } + } + + /** + * Does bulk of the minification + * @param string $css + * @param int|bool $linebreak_pos + * @return string + */ + private function minify($css, $linebreak_pos) + { + // strings are safe, now wrestle the comments + for ($i = 0, $max = count($this->comments); $i < $max; $i++) { + + $token = $this->comments[$i]; + $placeholder = '/' . self::COMMENT . $i . '___/'; + + // ! in the first position of the comment means preserve + // so push to the preserved tokens keeping the ! + if (substr($token, 0, 1) === '!') { + $this->preserved_tokens[] = $token; + $token_tring = self::TOKEN . (count($this->preserved_tokens) - 1) . '___'; + $css = preg_replace($placeholder, $token_tring, $css, 1); + // Preserve new lines for /*! important comments + $css = preg_replace('/\s*[\n\r\f]+\s*(\/\*'. $token_tring .')/S', self::NL.'$1', $css); + $css = preg_replace('/('. $token_tring .'\*\/)\s*[\n\r\f]+\s*/', '$1'.self::NL, $css); + continue; + } + + // \ in the last position looks like hack for Mac/IE5 + // shorten that to /*\*/ and the next one to /**/ + if (substr($token, (strlen($token) - 1), 1) === '\\') { + $this->preserved_tokens[] = '\\'; + $css = preg_replace($placeholder, self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1); + $i = $i + 1; // attn: advancing the loop + $this->preserved_tokens[] = ''; + $css = preg_replace('/' . self::COMMENT . $i . '___/', self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1); + continue; + } + + // keep empty comments after child selectors (IE7 hack) + // e.g. html >/**/ body + if (strlen($token) === 0) { + $start_index = $this->index_of($css, $this->str_slice($placeholder, 1, -1)); + if ($start_index > 2) { + if (substr($css, $start_index - 3, 1) === '>') { + $this->preserved_tokens[] = ''; + $css = preg_replace($placeholder, self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1); + } + } + } + + // in all other cases kill the comment + $css = preg_replace('/\/\*' . $this->str_slice($placeholder, 1, -1) . '\*\//', '', $css, 1); + } + + + // Normalize all whitespace strings to single spaces. Easier to work with that way. + $css = preg_replace('/\s+/', ' ', $css); + + // Fix IE7 issue on matrix filters which browser accept whitespaces between Matrix parameters + $css = preg_replace_callback('/\s*filter\:\s*progid:DXImageTransform\.Microsoft\.Matrix\(([^\)]+)\)/', array($this, 'preserve_old_IE_specific_matrix_definition'), $css); + + // Shorten & preserve calculations calc(...) since spaces are important + $css = preg_replace_callback('/calc(\(((?:[^\(\)]+|(?1))*)\))/i', array($this, 'replace_calc'), $css); + + // Replace positive sign from numbers preceded by : or a white-space before the leading space is removed + // +1.2em to 1.2em, +.8px to .8px, +2% to 2% + $css = preg_replace('/((? -9.0 to -9 + $css = preg_replace('/((?\+\(\)\]\~\=,])/', '$1', $css); + + // Restore spaces for !important + $css = preg_replace('/\!important/i', ' !important', $css); + + // bring back the colon + $css = preg_replace('/' . self::CLASSCOLON . '/', ':', $css); + + // retain space for special IE6 cases + $css = preg_replace_callback('/\:first\-(line|letter)(\{|,)/i', array($this, 'lowercase_pseudo_first'), $css); + + // no space after the end of a preserved comment + $css = preg_replace('/\*\/ /', '*/', $css); + + // lowercase some popular @directives + $css = preg_replace_callback('/@(font-face|import|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?keyframe|media|page|namespace)/i', array($this, 'lowercase_directives'), $css); + + // lowercase some more common pseudo-elements + $css = preg_replace_callback('/:(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)/i', array($this, 'lowercase_pseudo_elements'), $css); + + // lowercase some more common functions + $css = preg_replace_callback('/:(lang|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|(?:-(?:moz|webkit)-)?any)\(/i', array($this, 'lowercase_common_functions'), $css); + + // 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 = preg_replace_callback('/([:,\( ]\s*)(attr|color-stop|from|rgba|to|url|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?(?:calc|max|min|(?:repeating-)?(?:linear|radial)-gradient)|-webkit-gradient)/iS', array($this, 'lowercase_common_functions_values'), $css); + + // Put the space back in some cases, to support stuff like + // @media screen and (-webkit-min-device-pixel-ratio:0){ + $css = preg_replace('/\band\(/i', 'and (', $css); + + // Remove the spaces after the things that should not have spaces after them. + $css = preg_replace('/([\!\{\}\:;\>\+\(\[\~\=,])\s+/S', '$1', $css); + + // remove unnecessary semicolons + $css = preg_replace('/;+\}/', '}', $css); + + // Fix for issue: #2528146 + // Restore semicolon if the last property is prefixed with a `*` (lte IE7 hack) + // to avoid issues on Symbian S60 3.x browsers. + $css = preg_replace('/(\*[a-z0-9\-]+\s*\:[^;\}]+)(\})/', '$1;$2', $css); + + // Replace 0 and 0 values with 0. + // data type: https://developer.mozilla.org/en-US/docs/Web/CSS/length + // data type: https://developer.mozilla.org/en-US/docs/Web/CSS/percentage + $css = preg_replace('/([^\\\\]\:|\s)0(?:em|ex|ch|rem|vw|vh|vm|vmin|cm|mm|in|px|pt|pc|%)/iS', '${1}0', $css); + + // 0% step in a keyframe? restore the % unit + $css = preg_replace_callback('/(@[a-z\-]*?keyframes[^\{]+\{)(.*?)(\}\})/iS', array($this, 'replace_keyframe_zero'), $css); + + // Replace 0 0; or 0 0 0; or 0 0 0 0; with 0. + $css = preg_replace('/\:0(?: 0){1,3}(;|\}| \!)/', ':0$1', $css); + + // Fix for issue: #2528142 + // Replace text-shadow:0; with text-shadow:0 0 0; + $css = preg_replace('/(text-shadow\:0)(;|\}| \!)/i', '$1 0 0$2', $css); + + // Replace background-position:0; with background-position:0 0; + // same for transform-origin + // Changing -webkit-mask-position: 0 0 to just a single 0 will result in the second parameter defaulting to 50% (center) + $css = preg_replace('/(background\-position|webkit-mask-position|(?:webkit|moz|o|ms|)\-?transform\-origin)\:0(;|\}| \!)/iS', '$1:0 0$2', $css); + + // Shorten colors from rgb(51,102,153) to #336699, rgb(100%,0%,0%) to #ff0000 (sRGB color space) + // Shorten colors from hsl(0, 100%, 50%) to #ff0000 (sRGB color space) + // This makes it more likely that it'll get further compressed in the next step. + $css = preg_replace_callback('/rgb\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'rgb_to_hex'), $css); + $css = preg_replace_callback('/hsl\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'hsl_to_hex'), $css); + + // Shorten colors from #AABBCC to #ABC or short color name. + $css = $this->compress_hex_colors($css); + + // border: none to border:0, outline: none to outline:0 + $css = preg_replace('/(border\-?(?:top|right|bottom|left|)|outline)\:none(;|\}| \!)/iS', '$1:0$2', $css); + + // shorter opacity IE filter + $css = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $css); + + // Find a fraction that is used for Opera's -o-device-pixel-ratio query + // Add token to add the "\" back in later + $css = preg_replace('/\(([a-z\-]+):([0-9]+)\/([0-9]+)\)/i', '($1:$2'. self::QUERY_FRACTION .'$3)', $css); + + // Remove empty rules. + $css = preg_replace('/[^\};\{\/]+\{\}/S', '', $css); + + // Add "/" back to fix Opera -o-device-pixel-ratio query + $css = preg_replace('/'. self::QUERY_FRACTION .'/', '/', $css); + + // Replace multiple semi-colons in a row by a single one + // See SF bug #1980989 + $css = preg_replace('/;;+/', ';', $css); + + // Restore new lines for /*! important comments + $css = preg_replace('/'. self::NL .'/', "\n", $css); + + // Lowercase all uppercase properties + $css = preg_replace_callback('/(\{|\;)([A-Z\-]+)(\:)/', array($this, 'lowercase_properties'), $css); + + // Some source control tools don't like it when files containing lines longer + // than, say 8000 characters, are checked in. The linebreak option is used in + // that case to split long lines after a specific column. + if ($linebreak_pos !== FALSE && (int) $linebreak_pos >= 0) { + $linebreak_pos = (int) $linebreak_pos; + $start_index = $i = 0; + while ($i < strlen($css)) { + $i++; + if ($css[$i - 1] === '}' && $i - $start_index > $linebreak_pos) { + $css = $this->str_slice($css, 0, $i) . "\n" . $this->str_slice($css, $i); + $start_index = $i; + } + } + } + + // restore preserved comments and strings in reverse order + for ($i = count($this->preserved_tokens) - 1; $i >= 0; $i--) { + $css = preg_replace('/' . self::TOKEN . $i . '___/', $this->preserved_tokens[$i], $css, 1); + } + + // Trim the final string (for any leading or trailing white spaces) + return trim($css); + } + + /** + * Utility method to replace all data urls with tokens before we start + * compressing, to avoid performance issues running some of the subsequent + * regexes against large strings chunks. + * + * @param string $css + * @return string + */ + private function extract_data_urls($css) + { + // Leave data urls alone to increase parse performance. + $max_index = strlen($css) - 1; + $append_index = $index = $last_index = $offset = 0; + $sb = array(); + $pattern = '/url\(\s*(["\']?)data\:/i'; + + // 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 (preg_match($pattern, $css, $m, 0, $offset)) { + $index = $this->index_of($css, $m[0], $offset); + $last_index = $index + strlen($m[0]); + $start_index = $index + 4; // "url(".length() + $end_index = $last_index - 1; + $terminator = $m[1]; // ', " or empty (not quoted) + $found_terminator = FALSE; + + if (strlen($terminator) === 0) { + $terminator = ')'; + } + + while ($found_terminator === FALSE && $end_index+1 <= $max_index) { + $end_index = $this->index_of($css, $terminator, $end_index + 1); + + // endIndex == 0 doesn't really apply here + if ($end_index > 0 && substr($css, $end_index - 1, 1) !== '\\') { + $found_terminator = TRUE; + if (')' != $terminator) { + $end_index = $this->index_of($css, ')', $end_index); + } + } + } + + // Enough searching, start moving stuff over to the buffer + $sb[] = $this->str_slice($css, $append_index, $index); + + if ($found_terminator) { + $token = $this->str_slice($css, $start_index, $end_index); + $token = preg_replace('/\s+/', '', $token); + $this->preserved_tokens[] = $token; + + $preserver = 'url(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___)'; + $sb[] = $preserver; + + $append_index = $end_index + 1; + } else { + // No end terminator found, re-add the whole match. Should we throw/warn here? + $sb[] = $this->str_slice($css, $index, $last_index); + $append_index = $last_index; + } + + $offset = $last_index; + } + + $sb[] = $this->str_slice($css, $append_index); + + return implode('', $sb); + } + + /** + * Utility method to compress hex color values of the form #AABBCC to #ABC or short color name. + * + * DOES NOT compress CSS ID selectors which match the above pattern (which would break things). + * e.g. #AddressForm { ... } + * + * DOES NOT compress IE filters, which have hex color values (which would break things). + * e.g. filter: chroma(color="#FFFFFF"); + * + * DOES NOT compress invalid hex values. + * e.g. background-color: #aabbccdd + * + * @param string $css + * @return string + */ + private function compress_hex_colors($css) + { + // Look for hex colors inside { ... } (to avoid IDs) and which don't have a =, or a " in front of them (to avoid filters) + $pattern = '/(\=\s*?["\']?)?#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])(\}|[^0-9a-f{][^{]*?\})/iS'; + $_index = $index = $last_index = $offset = 0; + $sb = array(); + // See: http://ajaxmin.codeplex.com/wikipage?title=CSS%20Colors + $short_safe = array( + '#808080' => 'gray', + '#008000' => 'green', + '#800000' => 'maroon', + '#000080' => 'navy', + '#808000' => 'olive', + '#ffa500' => 'orange', + '#800080' => 'purple', + '#c0c0c0' => 'silver', + '#008080' => 'teal', + '#f00' => 'red' + ); + + while (preg_match($pattern, $css, $m, 0, $offset)) { + $index = $this->index_of($css, $m[0], $offset); + $last_index = $index + strlen($m[0]); + $is_filter = $m[1] !== null && $m[1] !== ''; + + $sb[] = $this->str_slice($css, $_index, $index); + + if ($is_filter) { + // Restore, maintain case, otherwise filter will break + $sb[] = $m[1] . '#' . $m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7]; + } else { + if (strtolower($m[2]) == strtolower($m[3]) && + strtolower($m[4]) == strtolower($m[5]) && + strtolower($m[6]) == strtolower($m[7])) { + // Compress. + $hex = '#' . strtolower($m[3] . $m[5] . $m[7]); + } else { + // Non compressible color, restore but lower case. + $hex = '#' . strtolower($m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7]); + } + // replace Hex colors to short safe color names + $sb[] = array_key_exists($hex, $short_safe) ? $short_safe[$hex] : $hex; + } + + $_index = $offset = $last_index - strlen($m[8]); + } + + $sb[] = $this->str_slice($css, $_index); + + return implode('', $sb); + } + + /* CALLBACKS + * --------------------------------------------------------------------------------------------- + */ + + private function replace_string($matches) + { + $match = $matches[0]; + $quote = substr($match, 0, 1); + // Must use addcslashes in PHP to avoid parsing of backslashes + $match = addcslashes($this->str_slice($match, 1, -1), '\\'); + + // maybe the string contains a comment-like substring? + // one, maybe more? put'em back then + if (($pos = $this->index_of($match, self::COMMENT)) >= 0) { + for ($i = 0, $max = count($this->comments); $i < $max; $i++) { + $match = preg_replace('/' . self::COMMENT . $i . '___/', $this->comments[$i], $match, 1); + } + } + + // minify alpha opacity in filter strings + $match = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $match); + + $this->preserved_tokens[] = $match; + return $quote . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . $quote; + } + + private function replace_colon($matches) + { + return preg_replace('/\:/', self::CLASSCOLON, $matches[0]); + } + + private function replace_calc($matches) + { + $this->preserved_tokens[] = trim(preg_replace('/\s*([\*\/\(\),])\s*/', '$1', $matches[2])); + return 'calc('. self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')'; + } + + private function preserve_old_IE_specific_matrix_definition($matches) + { + $this->preserved_tokens[] = $matches[1]; + return 'filter:progid:DXImageTransform.Microsoft.Matrix(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')'; + } + + private function replace_keyframe_zero($matches) + { + return $matches[1] . preg_replace('/0(\{|,[^\)\{]+\{)/', '0%$1', $matches[2]) . $matches[3]; + } + + private function rgb_to_hex($matches) + { + // Support for percentage values rgb(100%, 0%, 45%); + if ($this->index_of($matches[1], '%') >= 0){ + $rgbcolors = explode(',', str_replace('%', '', $matches[1])); + for ($i = 0; $i < count($rgbcolors); $i++) { + $rgbcolors[$i] = $this->round_number(floatval($rgbcolors[$i]) * 2.55); + } + } else { + $rgbcolors = explode(',', $matches[1]); + } + + // Values outside the sRGB color space should be clipped (0-255) + for ($i = 0; $i < count($rgbcolors); $i++) { + $rgbcolors[$i] = $this->clamp_number(intval($rgbcolors[$i], 10), 0, 255); + $rgbcolors[$i] = sprintf("%02x", $rgbcolors[$i]); + } + + // Fix for issue #2528093 + if (!preg_match('/[\s\,\);\}]/', $matches[2])){ + $matches[2] = ' ' . $matches[2]; + } + + return '#' . implode('', $rgbcolors) . $matches[2]; + } + + private function hsl_to_hex($matches) + { + $values = explode(',', str_replace('%', '', $matches[1])); + $h = floatval($values[0]); + $s = floatval($values[1]); + $l = floatval($values[2]); + + // Wrap and clamp, then fraction! + $h = ((($h % 360) + 360) % 360) / 360; + $s = $this->clamp_number($s, 0, 100) / 100; + $l = $this->clamp_number($l, 0, 100) / 100; + + if ($s == 0) { + $r = $g = $b = $this->round_number(255 * $l); + } else { + $v2 = $l < 0.5 ? $l * (1 + $s) : ($l + $s) - ($s * $l); + $v1 = (2 * $l) - $v2; + $r = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h + (1/3))); + $g = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h)); + $b = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h - (1/3))); + } + + return $this->rgb_to_hex(array('', $r.','.$g.','.$b, $matches[2])); + } + + private function lowercase_pseudo_first($matches) + { + return ':first-'. strtolower($matches[1]) .' '. $matches[2]; + } + + private function lowercase_directives($matches) + { + return '@'. strtolower($matches[1]); + } + + private function lowercase_pseudo_elements($matches) + { + return ':'. strtolower($matches[1]); + } + + private function lowercase_common_functions($matches) + { + return ':'. strtolower($matches[1]) .'('; + } + + private function lowercase_common_functions_values($matches) + { + return $matches[1] . strtolower($matches[2]); + } + + private function lowercase_properties($matches) + { + return $matches[1].strtolower($matches[2]).$matches[3]; + } + + /* HELPERS + * --------------------------------------------------------------------------------------------- + */ + + private function hue_to_rgb($v1, $v2, $vh) + { + $vh = $vh < 0 ? $vh + 1 : ($vh > 1 ? $vh - 1 : $vh); + if ($vh * 6 < 1) return $v1 + ($v2 - $v1) * 6 * $vh; + if ($vh * 2 < 1) return $v2; + if ($vh * 3 < 2) return $v1 + ($v2 - $v1) * ((2/3) - $vh) * 6; + return $v1; + } + + private function round_number($n) + { + return intval(floor(floatval($n) + 0.5), 10); + } + + private function clamp_number($n, $min, $max) + { + return min(max($n, $min), $max); + } + + /** + * PHP port of Javascript's "indexOf" function for strings only + * Author: Tubal Martin http://blog.margenn.com + * + * @param string $haystack + * @param string $needle + * @param int $offset index (optional) + * @return int + */ + private function index_of($haystack, $needle, $offset = 0) + { + $index = strpos($haystack, $needle, $offset); + + return ($index !== FALSE) ? $index : -1; + } + + /** + * PHP port of Javascript's "slice" function for strings only + * Author: Tubal Martin http://blog.margenn.com + * Tests: http://margenn.com/tubal/str_slice/ + * + * @param string $str + * @param int $start index + * @param int|bool $end index (optional) + * @return string + */ + private function str_slice($str, $start = 0, $end = FALSE) + { + if ($end !== FALSE && ($start < 0 || $end <= 0)) { + $max = strlen($str); + + if ($start < 0) { + if (($start = $max + $start) < 0) { + return ''; + } + } + + if ($end < 0) { + if (($end = $max + $end) < 0) { + return ''; + } + } + + if ($end <= $start) { + return ''; + } + } + + $slice = ($end === FALSE) ? substr($str, $start) : substr($str, $start, $end - $start); + return ($slice === FALSE) ? '' : $slice; + } + + /** + * Convert strings like "64M" or "30" to int values + * @param mixed $size + * @return int + */ + private function normalize_int($size) + { + if (is_string($size)) { + switch (substr($size, -1)) { + case 'M': case 'm': return $size * 1048576; + case 'K': case 'k': return $size * 1024; + case 'G': case 'g': return $size * 1073741824; + } + } + + return (int) $size; + } +} \ No newline at end of file diff --git a/mrclay/minify/min/lib/DooDigestAuth.php b/mrclay/minify/min/lib/DooDigestAuth.php new file mode 100644 index 000000000000..69bc4ed4db45 --- /dev/null +++ b/mrclay/minify/min/lib/DooDigestAuth.php @@ -0,0 +1,121 @@ + + * @link http://www.doophp.com/ + * @copyright Copyright © 2009 Leng Sheng Hong + * @license http://www.doophp.com/license + */ + +/** + * Handles HTTP digest authentication + * + *

    HTTP digest authentication can be used with the URI router. + * HTTP digest is much more recommended over the use of HTTP Basic auth which doesn't provide any encryption. + * If you are running PHP on Apache in CGI/FastCGI mode, you would need to + * add the following line to your .htaccess for digest auth to work correctly.

    + * RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] + * + *

    This class is tested under Apache 2.2 and Cherokee web server. It should work in both mod_php and cgi mode.

    + * + * @author Leng Sheng Hong + * @version $Id: DooDigestAuth.php 1000 2009-07-7 18:27:22 + * @package doo.auth + * @since 1.0 + */ +class DooDigestAuth{ + + /** + * Authenticate against a list of username and passwords. + * + *

    HTTP Digest Authentication doesn't work with PHP in CGI mode, + * you have to add this into your .htaccess RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]

    + * + * @param string $realm Name of the authentication session + * @param array $users An assoc array of username and password: array('uname1'=>'pwd1', 'uname2'=>'pwd2') + * @param string $fail_msg Message to be displayed if the User cancel the login + * @param string $fail_url URL to be redirect if the User cancel the login + * @return string The username if login success. + */ + public static function http_auth($realm, $users, $fail_msg=NULL, $fail_url=NULL){ + $realm = "Restricted area - $realm"; + + //user => password + //$users = array('admin' => '1234', 'guest' => 'guest'); + if(!empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && strpos($_SERVER['REDIRECT_HTTP_AUTHORIZATION'], 'Digest')===0){ + $_SERVER['PHP_AUTH_DIGEST'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; + } + + if (empty($_SERVER['PHP_AUTH_DIGEST'])) { + header('WWW-Authenticate: Digest realm="'.$realm. + '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); + header('HTTP/1.1 401 Unauthorized'); + if($fail_msg!=NULL) + die($fail_msg); + if($fail_url!=NULL) + die(""); + exit; + } + + // analyze the PHP_AUTH_DIGEST variable + if (!($data = self::http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || !isset($users[$data['username']])){ + header('WWW-Authenticate: Digest realm="'.$realm. + '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); + header('HTTP/1.1 401 Unauthorized'); + if($fail_msg!=NULL) + die($fail_msg); + if($fail_url!=NULL) + die(""); + exit; + } + + // generate the valid response + $A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]); + $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']); + $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2); + + if ($data['response'] != $valid_response){ + header('HTTP/1.1 401 Unauthorized'); + header('WWW-Authenticate: Digest realm="'.$realm. + '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); + if($fail_msg!=NULL) + die($fail_msg); + if($fail_url!=NULL) + die(""); + exit; + } + + // ok, valid username & password + return $data['username']; + } + + /** + * Method to parse the http auth header, works with IE. + * + * Internet Explorer returns a qop="xxxxxxxxxxx" in the header instead of qop=xxxxxxxxxxx as most browsers do. + * + * @param string $txt header string to parse + * @return array An assoc array of the digest auth session + */ + private static function http_digest_parse($txt) + { + $res = preg_match("/username=\"([^\"]+)\"/i", $txt, $match); + $data['username'] = (isset($match[1]))?$match[1]:null; + $res = preg_match('/nonce=\"([^\"]+)\"/i', $txt, $match); + $data['nonce'] = $match[1]; + $res = preg_match('/nc=([0-9]+)/i', $txt, $match); + $data['nc'] = $match[1]; + $res = preg_match('/cnonce=\"([^\"]+)\"/i', $txt, $match); + $data['cnonce'] = $match[1]; + $res = preg_match('/qop=([^,]+)/i', $txt, $match); + $data['qop'] = str_replace('"','',$match[1]); + $res = preg_match('/uri=\"([^\"]+)\"/i', $txt, $match); + $data['uri'] = $match[1]; + $res = preg_match('/response=\"([^\"]+)\"/i', $txt, $match); + $data['response'] = $match[1]; + return $data; + } + + +} diff --git a/mrclay/minify/min/lib/FirePHP.php b/mrclay/minify/min/lib/FirePHP.php new file mode 100644 index 000000000000..d301a641abff --- /dev/null +++ b/mrclay/minify/min/lib/FirePHP.php @@ -0,0 +1,1370 @@ + + * @license http://www.opensource.org/licenses/bsd-license.php + * @package FirePHP + */ + + +/** + * Sends the given data to the FirePHP Firefox Extension. + * The data can be displayed in the Firebug Console or in the + * "Server" request tab. + * + * For more information see: http://www.firephp.org/ + * + * @copyright Copyright (C) 2007-2008 Christoph Dorn + * @author Christoph Dorn + * @license http://www.opensource.org/licenses/bsd-license.php + * @package FirePHP + */ +class FirePHP { + + /** + * FirePHP version + * + * @var string + */ + const VERSION = '0.2.0'; + + /** + * Firebug LOG level + * + * Logs a message to firebug console. + * + * @var string + */ + const LOG = 'LOG'; + + /** + * Firebug INFO level + * + * Logs a message to firebug console and displays an info icon before the message. + * + * @var string + */ + const INFO = 'INFO'; + + /** + * Firebug WARN level + * + * Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise. + * + * @var string + */ + const WARN = 'WARN'; + + /** + * Firebug ERROR level + * + * Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count. + * + * @var string + */ + const ERROR = 'ERROR'; + + /** + * Dumps a variable to firebug's server panel + * + * @var string + */ + const DUMP = 'DUMP'; + + /** + * Displays a stack trace in firebug console + * + * @var string + */ + const TRACE = 'TRACE'; + + /** + * Displays an exception in firebug console + * + * Increments the firebug error count. + * + * @var string + */ + const EXCEPTION = 'EXCEPTION'; + + /** + * Displays an table in firebug console + * + * @var string + */ + const TABLE = 'TABLE'; + + /** + * Starts a group in firebug console + * + * @var string + */ + const GROUP_START = 'GROUP_START'; + + /** + * Ends a group in firebug console + * + * @var string + */ + const GROUP_END = 'GROUP_END'; + + /** + * Singleton instance of FirePHP + * + * @var FirePHP + */ + protected static $instance = null; + + /** + * Wildfire protocol message index + * + * @var int + */ + protected $messageIndex = 1; + + /** + * Options for the library + * + * @var array + */ + protected $options = array(); + + /** + * Filters used to exclude object members when encoding + * + * @var array + */ + protected $objectFilters = array(); + + /** + * A stack of objects used to detect recursion during object encoding + * + * @var object + */ + protected $objectStack = array(); + + /** + * Flag to enable/disable logging + * + * @var boolean + */ + protected $enabled = true; + + /** + * The object constructor + */ + function __construct() { + $this->options['maxObjectDepth'] = 10; + $this->options['maxArrayDepth'] = 20; + $this->options['useNativeJsonEncode'] = true; + $this->options['includeLineNumbers'] = true; + } + + /** + * When the object gets serialized only include specific object members. + * + * @return array + */ + public function __sleep() { + return array('options','objectFilters','enabled'); + } + + /** + * Gets singleton instance of FirePHP + * + * @param boolean $AutoCreate + * @return FirePHP + */ + public static function getInstance($AutoCreate=false) { + if($AutoCreate===true && !self::$instance) { + self::init(); + } + return self::$instance; + } + + /** + * Creates FirePHP object and stores it for singleton access + * + * @return FirePHP + */ + public static function init() { + return self::$instance = new self(); + } + + /** + * Enable and disable logging to Firebug + * + * @param boolean $Enabled TRUE to enable, FALSE to disable + * @return void + */ + public function setEnabled($Enabled) { + $this->enabled = $Enabled; + } + + /** + * Check if logging is enabled + * + * @return boolean TRUE if enabled + */ + public function getEnabled() { + return $this->enabled; + } + + /** + * Specify a filter to be used when encoding an object + * + * Filters are used to exclude object members. + * + * @param string $Class The class name of the object + * @param array $Filter An array or members to exclude + * @return void + */ + public function setObjectFilter($Class, $Filter) { + $this->objectFilters[$Class] = $Filter; + } + + /** + * Set some options for the library + * + * Options: + * - maxObjectDepth: The maximum depth to traverse objects (default: 10) + * - maxArrayDepth: The maximum depth to traverse arrays (default: 20) + * - useNativeJsonEncode: If true will use json_encode() (default: true) + * - includeLineNumbers: If true will include line numbers and filenames (default: true) + * + * @param array $Options The options to be set + * @return void + */ + public function setOptions($Options) { + $this->options = array_merge($this->options,$Options); + } + + /** + * Register FirePHP as your error handler + * + * Will throw exceptions for each php error. + */ + public function registerErrorHandler() + { + //NOTE: The following errors will not be caught by this error handler: + // E_ERROR, E_PARSE, E_CORE_ERROR, + // E_CORE_WARNING, E_COMPILE_ERROR, + // E_COMPILE_WARNING, E_STRICT + + set_error_handler(array($this,'errorHandler')); + } + + /** + * FirePHP's error handler + * + * Throws exception for each php error that will occur. + * + * @param int $errno + * @param string $errstr + * @param string $errfile + * @param int $errline + * @param array $errcontext + */ + public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) + { + // Don't throw exception if error reporting is switched off + if (error_reporting() == 0) { + return; + } + // Only throw exceptions for errors we are asking for + if (error_reporting() & $errno) { + throw new ErrorException($errstr, 0, $errno, $errfile, $errline); + } + } + + /** + * Register FirePHP as your exception handler + */ + public function registerExceptionHandler() + { + set_exception_handler(array($this,'exceptionHandler')); + } + + /** + * FirePHP's exception handler + * + * Logs all exceptions to your firebug console and then stops the script. + * + * @param Exception $Exception + * @throws Exception + */ + function exceptionHandler($Exception) { + $this->fb($Exception); + } + + /** + * Set custom processor url for FirePHP + * + * @param string $URL + */ + public function setProcessorUrl($URL) + { + $this->setHeader('X-FirePHP-ProcessorURL', $URL); + } + + /** + * Set custom renderer url for FirePHP + * + * @param string $URL + */ + public function setRendererUrl($URL) + { + $this->setHeader('X-FirePHP-RendererURL', $URL); + } + + /** + * Start a group for following messages + * + * @param string $Name + * @return true + * @throws Exception + */ + public function group($Name) { + return $this->fb(null, $Name, FirePHP::GROUP_START); + } + + /** + * Ends a group you have started before + * + * @return true + * @throws Exception + */ + public function groupEnd() { + return $this->fb(null, null, FirePHP::GROUP_END); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::LOG + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function log($Object, $Label=null) { + return $this->fb($Object, $Label, FirePHP::LOG); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::INFO + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function info($Object, $Label=null) { + return $this->fb($Object, $Label, FirePHP::INFO); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::WARN + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function warn($Object, $Label=null) { + return $this->fb($Object, $Label, FirePHP::WARN); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::ERROR + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function error($Object, $Label=null) { + return $this->fb($Object, $Label, FirePHP::ERROR); + } + + /** + * Dumps key and variable to firebug server panel + * + * @see FirePHP::DUMP + * @param string $Key + * @param mixed $Variable + * @return true + * @throws Exception + */ + public function dump($Key, $Variable) { + return $this->fb($Variable, $Key, FirePHP::DUMP); + } + + /** + * Log a trace in the firebug console + * + * @see FirePHP::TRACE + * @param string $Label + * @return true + * @throws Exception + */ + public function trace($Label) { + return $this->fb($Label, FirePHP::TRACE); + } + + /** + * Log a table in the firebug console + * + * @see FirePHP::TABLE + * @param string $Label + * @param string $Table + * @return true + * @throws Exception + */ + public function table($Label, $Table) { + return $this->fb($Table, $Label, FirePHP::TABLE); + } + + /** + * Check if FirePHP is installed on client + * + * @return boolean + */ + public function detectClientExtension() { + /* Check if FirePHP is installed on client */ + if(!@preg_match_all('/\sFirePHP\/([\.|\d]*)\s?/si',$this->getUserAgent(),$m) || + !version_compare($m[1][0],'0.0.6','>=')) { + return false; + } + return true; + } + + /** + * Log varible to Firebug + * + * @see http://www.firephp.org/Wiki/Reference/Fb + * @param mixed $Object The variable to be logged + * @return true Return TRUE if message was added to headers, FALSE otherwise + * @throws Exception + */ + public function fb($Object) { + + if(!$this->enabled) { + return false; + } + + if (headers_sent($filename, $linenum)) { + throw $this->newException('Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.'); + } + + $Type = null; + $Label = null; + + if(func_num_args()==1) { + } else + if(func_num_args()==2) { + switch(func_get_arg(1)) { + case self::LOG: + case self::INFO: + case self::WARN: + case self::ERROR: + case self::DUMP: + case self::TRACE: + case self::EXCEPTION: + case self::TABLE: + case self::GROUP_START: + case self::GROUP_END: + $Type = func_get_arg(1); + break; + default: + $Label = func_get_arg(1); + break; + } + } else + if(func_num_args()==3) { + $Type = func_get_arg(2); + $Label = func_get_arg(1); + } else { + throw $this->newException('Wrong number of arguments to fb() function!'); + } + + + if(!$this->detectClientExtension()) { + return false; + } + + $meta = array(); + $skipFinalObjectEncode = false; + + if($Object instanceof Exception) { + + $meta['file'] = $this->_escapeTraceFile($Object->getFile()); + $meta['line'] = $Object->getLine(); + + $trace = $Object->getTrace(); + if($Object instanceof ErrorException + && isset($trace[0]['function']) + && $trace[0]['function']=='errorHandler' + && isset($trace[0]['class']) + && $trace[0]['class']=='FirePHP') { + + $severity = false; + switch($Object->getSeverity()) { + case E_WARNING: $severity = 'E_WARNING'; break; + case E_NOTICE: $severity = 'E_NOTICE'; break; + case E_USER_ERROR: $severity = 'E_USER_ERROR'; break; + case E_USER_WARNING: $severity = 'E_USER_WARNING'; break; + case E_USER_NOTICE: $severity = 'E_USER_NOTICE'; break; + case E_STRICT: $severity = 'E_STRICT'; break; + case E_RECOVERABLE_ERROR: $severity = 'E_RECOVERABLE_ERROR'; break; + case E_DEPRECATED: $severity = 'E_DEPRECATED'; break; + case E_USER_DEPRECATED: $severity = 'E_USER_DEPRECATED'; break; + } + + $Object = array('Class'=>get_class($Object), + 'Message'=>$severity.': '.$Object->getMessage(), + 'File'=>$this->_escapeTraceFile($Object->getFile()), + 'Line'=>$Object->getLine(), + 'Type'=>'trigger', + 'Trace'=>$this->_escapeTrace(array_splice($trace,2))); + $skipFinalObjectEncode = true; + } else { + $Object = array('Class'=>get_class($Object), + 'Message'=>$Object->getMessage(), + 'File'=>$this->_escapeTraceFile($Object->getFile()), + 'Line'=>$Object->getLine(), + 'Type'=>'throw', + 'Trace'=>$this->_escapeTrace($trace)); + $skipFinalObjectEncode = true; + } + $Type = self::EXCEPTION; + + } else + if($Type==self::TRACE) { + + $trace = debug_backtrace(); + if(!$trace) return false; + for( $i=0 ; $i_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php' + || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) { + /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ + } else + if(isset($trace[$i]['class']) + && isset($trace[$i+1]['file']) + && $trace[$i]['class']=='FirePHP' + && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') { + /* Skip fb() */ + } else + if($trace[$i]['function']=='fb' + || $trace[$i]['function']=='trace' + || $trace[$i]['function']=='send') { + $Object = array('Class'=>isset($trace[$i]['class'])?$trace[$i]['class']:'', + 'Type'=>isset($trace[$i]['type'])?$trace[$i]['type']:'', + 'Function'=>isset($trace[$i]['function'])?$trace[$i]['function']:'', + 'Message'=>$trace[$i]['args'][0], + 'File'=>isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'', + 'Line'=>isset($trace[$i]['line'])?$trace[$i]['line']:'', + 'Args'=>isset($trace[$i]['args'])?$this->encodeObject($trace[$i]['args']):'', + 'Trace'=>$this->_escapeTrace(array_splice($trace,$i+1))); + + $skipFinalObjectEncode = true; + $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):''; + $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:''; + break; + } + } + + } else + if($Type==self::TABLE) { + + if(isset($Object[0]) && is_string($Object[0])) { + $Object[1] = $this->encodeTable($Object[1]); + } else { + $Object = $this->encodeTable($Object); + } + + $skipFinalObjectEncode = true; + + } else { + if($Type===null) { + $Type = self::LOG; + } + } + + if($this->options['includeLineNumbers']) { + if(!isset($meta['file']) || !isset($meta['line'])) { + + $trace = debug_backtrace(); + for( $i=0 ; $trace && $i_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php' + || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) { + /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ + } else + if(isset($trace[$i]['class']) + && isset($trace[$i+1]['file']) + && $trace[$i]['class']=='FirePHP' + && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') { + /* Skip fb() */ + } else + if(isset($trace[$i]['file']) + && substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php') { + /* Skip FB::fb() */ + } else { + $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):''; + $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:''; + break; + } + } + + } + } else { + unset($meta['file']); + unset($meta['line']); + } + + $this->setHeader('X-Wf-Protocol-1','http://meta.wildfirehq.org/Protocol/JsonStream/0.2'); + $this->setHeader('X-Wf-1-Plugin-1','http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/'.self::VERSION); + + $structure_index = 1; + if($Type==self::DUMP) { + $structure_index = 2; + $this->setHeader('X-Wf-1-Structure-2','http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1'); + } else { + $this->setHeader('X-Wf-1-Structure-1','http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'); + } + + if($Type==self::DUMP) { + $msg = '{"'.$Label.'":'.$this->jsonEncode($Object, $skipFinalObjectEncode).'}'; + } else { + $msg_meta = array('Type'=>$Type); + if($Label!==null) { + $msg_meta['Label'] = $Label; + } + if(isset($meta['file'])) { + $msg_meta['File'] = $meta['file']; + } + if(isset($meta['line'])) { + $msg_meta['Line'] = $meta['line']; + } + $msg = '['.$this->jsonEncode($msg_meta).','.$this->jsonEncode($Object, $skipFinalObjectEncode).']'; + } + + $parts = explode("\n",chunk_split($msg, 5000, "\n")); + + for( $i=0 ; $i2) { + // Message needs to be split into multiple parts + $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex, + (($i==0)?strlen($msg):'') + . '|' . $part . '|' + . (($isetHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex, + strlen($part) . '|' . $part . '|'); + } + + $this->messageIndex++; + + if ($this->messageIndex > 99999) { + throw new Exception('Maximum number (99,999) of messages reached!'); + } + } + } + + $this->setHeader('X-Wf-1-Index',$this->messageIndex-1); + + return true; + } + + /** + * Standardizes path for windows systems. + * + * @param string $Path + * @return string + */ + protected function _standardizePath($Path) { + return preg_replace('/\\\\+/','/',$Path); + } + + /** + * Escape trace path for windows systems + * + * @param array $Trace + * @return array + */ + protected function _escapeTrace($Trace) { + if(!$Trace) return $Trace; + for( $i=0 ; $i_escapeTraceFile($Trace[$i]['file']); + } + if(isset($Trace[$i]['args'])) { + $Trace[$i]['args'] = $this->encodeObject($Trace[$i]['args']); + } + } + return $Trace; + } + + /** + * Escape file information of trace for windows systems + * + * @param string $File + * @return string + */ + protected function _escapeTraceFile($File) { + /* Check if we have a windows filepath */ + if(strpos($File,'\\')) { + /* First strip down to single \ */ + + $file = preg_replace('/\\\\+/','\\',$File); + + return $file; + } + return $File; + } + + /** + * Send header + * + * @param string $Name + * @param string_type $Value + */ + protected function setHeader($Name, $Value) { + return header($Name.': '.$Value); + } + + /** + * Get user agent + * + * @return string|false + */ + protected function getUserAgent() { + if(!isset($_SERVER['HTTP_USER_AGENT'])) return false; + return $_SERVER['HTTP_USER_AGENT']; + } + + /** + * Returns a new exception + * + * @param string $Message + * @return Exception + */ + protected function newException($Message) { + return new Exception($Message); + } + + /** + * Encode an object into a JSON string + * + * Uses PHP's jeson_encode() if available + * + * @param object $Object The object to be encoded + * @return string The JSON string + */ + protected function jsonEncode($Object, $skipObjectEncode=false) + { + if(!$skipObjectEncode) { + $Object = $this->encodeObject($Object); + } + + if(function_exists('json_encode') + && $this->options['useNativeJsonEncode']!=false) { + + return json_encode($Object); + } else { + return $this->json_encode($Object); + } + } + + /** + * Encodes a table by encoding each row and column with encodeObject() + * + * @param array $Table The table to be encoded + * @return array + */ + protected function encodeTable($Table) { + if(!$Table) return $Table; + for( $i=0 ; $iencodeObject($Table[$i][$j]); + } + } + } + return $Table; + } + + /** + * Encodes an object including members with + * protected and private visibility + * + * @param Object $Object The object to be encoded + * @param int $Depth The current traversal depth + * @return array All members of the object + */ + protected function encodeObject($Object, $ObjectDepth = 1, $ArrayDepth = 1) + { + $return = array(); + + if (is_object($Object)) { + + if ($ObjectDepth > $this->options['maxObjectDepth']) { + return '** Max Object Depth ('.$this->options['maxObjectDepth'].') **'; + } + + foreach ($this->objectStack as $refVal) { + if ($refVal === $Object) { + return '** Recursion ('.get_class($Object).') **'; + } + } + array_push($this->objectStack, $Object); + + $return['__className'] = $class = get_class($Object); + + $reflectionClass = new ReflectionClass($class); + $properties = array(); + foreach( $reflectionClass->getProperties() as $property) { + $properties[$property->getName()] = $property; + } + + $members = (array)$Object; + + foreach( $properties as $raw_name => $property ) { + + $name = $raw_name; + if($property->isStatic()) { + $name = 'static:'.$name; + } + if($property->isPublic()) { + $name = 'public:'.$name; + } else + if($property->isPrivate()) { + $name = 'private:'.$name; + $raw_name = "\0".$class."\0".$raw_name; + } else + if($property->isProtected()) { + $name = 'protected:'.$name; + $raw_name = "\0".'*'."\0".$raw_name; + } + + if(!(isset($this->objectFilters[$class]) + && is_array($this->objectFilters[$class]) + && in_array($raw_name,$this->objectFilters[$class]))) { + + if(array_key_exists($raw_name,$members) + && !$property->isStatic()) { + + $return[$name] = $this->encodeObject($members[$raw_name], $ObjectDepth + 1, 1); + + } else { + if(method_exists($property,'setAccessible')) { + $property->setAccessible(true); + $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1); + } else + if($property->isPublic()) { + $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1); + } else { + $return[$name] = '** Need PHP 5.3 to get value **'; + } + } + } else { + $return[$name] = '** Excluded by Filter **'; + } + } + + // Include all members that are not defined in the class + // but exist in the object + foreach( $members as $raw_name => $value ) { + + $name = $raw_name; + + if ($name{0} == "\0") { + $parts = explode("\0", $name); + $name = $parts[2]; + } + + if(!isset($properties[$name])) { + $name = 'undeclared:'.$name; + + if(!(isset($this->objectFilters[$class]) + && is_array($this->objectFilters[$class]) + && in_array($raw_name,$this->objectFilters[$class]))) { + + $return[$name] = $this->encodeObject($value, $ObjectDepth + 1, 1); + } else { + $return[$name] = '** Excluded by Filter **'; + } + } + } + + array_pop($this->objectStack); + + } elseif (is_array($Object)) { + + if ($ArrayDepth > $this->options['maxArrayDepth']) { + return '** Max Array Depth ('.$this->options['maxArrayDepth'].') **'; + } + + foreach ($Object as $key => $val) { + + // Encoding the $GLOBALS PHP array causes an infinite loop + // if the recursion is not reset here as it contains + // a reference to itself. This is the only way I have come up + // with to stop infinite recursion in this case. + if($key=='GLOBALS' + && is_array($val) + && array_key_exists('GLOBALS',$val)) { + $val['GLOBALS'] = '** Recursion (GLOBALS) **'; + } + + $return[$key] = $this->encodeObject($val, 1, $ArrayDepth + 1); + } + } else { + if(self::is_utf8($Object)) { + return $Object; + } else { + return utf8_encode($Object); + } + } + return $return; + } + + /** + * Returns true if $string is valid UTF-8 and false otherwise. + * + * @param mixed $str String to be tested + * @return boolean + */ + protected static function is_utf8($str) { + $c=0; $b=0; + $bits=0; + $len=strlen($str); + for($i=0; $i<$len; $i++){ + $c=ord($str[$i]); + if($c > 128){ + if(($c >= 254)) return false; + elseif($c >= 252) $bits=6; + elseif($c >= 248) $bits=5; + elseif($c >= 240) $bits=4; + elseif($c >= 224) $bits=3; + elseif($c >= 192) $bits=2; + else return false; + if(($i+$bits) > $len) return false; + while($bits > 1){ + $i++; + $b=ord($str[$i]); + if($b < 128 || $b > 191) return false; + $bits--; + } + } + } + return true; + } + + /** + * Converts to and from JSON format. + * + * JSON (JavaScript Object Notation) is a lightweight data-interchange + * format. It is easy for humans to read and write. It is easy for machines + * to parse and generate. It is based on a subset of the JavaScript + * Programming Language, Standard ECMA-262 3rd Edition - December 1999. + * This feature can also be found in Python. JSON is a text format that is + * completely language independent but uses conventions that are familiar + * to programmers of the C-family of languages, including C, C++, C#, Java, + * JavaScript, Perl, TCL, and many others. These properties make JSON an + * ideal data-interchange language. + * + * This package provides a simple encoder and decoder for JSON notation. It + * is intended for use with client-side Javascript applications that make + * use of HTTPRequest to perform server communication functions - data can + * be encoded into JSON notation for use in a client-side javascript, or + * decoded from incoming Javascript requests. JSON format is native to + * Javascript, and can be directly eval()'ed with no further parsing + * overhead + * + * All strings should be in ASCII or UTF-8 format! + * + * LICENSE: Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: Redistributions of source code must retain the + * above copyright notice, this list of conditions and the following + * disclaimer. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * @category + * @package Services_JSON + * @author Michal Migurski + * @author Matt Knapp + * @author Brett Stimmerman + * @author Christoph Dorn + * @copyright 2005 Michal Migurski + * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $ + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 + */ + + + /** + * Keep a list of objects as we descend into the array so we can detect recursion. + */ + private $json_objectStack = array(); + + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + private function json_utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + } + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $utf8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return mixed JSON string representation of input var or an error if a problem occurs + * @access public + */ + private function json_encode($var) + { + + if(is_object($var)) { + if(in_array($var,$this->json_objectStack)) { + return '"** Recursion **"'; + } + } + + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + + $this->json_objectStack[] = $var; + + $properties = array_map(array($this, 'json_name_value'), + array_keys($var), + array_values($var)); + + array_pop($this->json_objectStack); + + foreach($properties as $property) { + if($property instanceof Exception) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + } + + $this->json_objectStack[] = $var; + + // treat it like a regular array + $elements = array_map(array($this, 'json_encode'), $var); + + array_pop($this->json_objectStack); + + foreach($elements as $element) { + if($element instanceof Exception) { + return $element; + } + } + + return '[' . join(',', $elements) . ']'; + + case 'object': + $vars = self::encodeObject($var); + + $this->json_objectStack[] = $var; + + $properties = array_map(array($this, 'json_name_value'), + array_keys($vars), + array_values($vars)); + + array_pop($this->json_objectStack); + + foreach($properties as $property) { + if($property instanceof Exception) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + + default: + return null; + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + private function json_name_value($name, $value) + { + // Encoding the $GLOBALS PHP array causes an infinite loop + // if the recursion is not reset here as it contains + // a reference to itself. This is the only way I have come up + // with to stop infinite recursion in this case. + if($name=='GLOBALS' + && is_array($value) + && array_key_exists('GLOBALS',$value)) { + $value['GLOBALS'] = '** Recursion **'; + } + + $encoded_value = $this->json_encode($value); + + if($encoded_value instanceof Exception) { + return $encoded_value; + } + + return $this->json_encode(strval($name)) . ':' . $encoded_value; + } +} diff --git a/mrclay/minify/min/lib/HTTP/ConditionalGet.php b/mrclay/minify/min/lib/HTTP/ConditionalGet.php new file mode 100644 index 000000000000..93b7e75d8e1c --- /dev/null +++ b/mrclay/minify/min/lib/HTTP/ConditionalGet.php @@ -0,0 +1,366 @@ + + * list($updateTime, $content) = getDbUpdateAndContent(); + * $cg = new HTTP_ConditionalGet(array( + * 'lastModifiedTime' => $updateTime + * ,'isPublic' => true + * )); + * $cg->sendHeaders(); + * if ($cg->cacheIsValid) { + * exit(); + * } + * echo $content; + * + * + * E.g. Shortcut for the above + * + * HTTP_ConditionalGet::check($updateTime, true); // exits if client has cache + * echo $content; + * + * + * E.g. Content from DB with no update time: + * + * $content = getContentFromDB(); + * $cg = new HTTP_ConditionalGet(array( + * 'contentHash' => md5($content) + * )); + * $cg->sendHeaders(); + * if ($cg->cacheIsValid) { + * exit(); + * } + * echo $content; + * + * + * E.g. Static content with some static includes: + * + * // before content + * $cg = new HTTP_ConditionalGet(array( + * 'lastUpdateTime' => max( + * filemtime(__FILE__) + * ,filemtime('/path/to/header.inc') + * ,filemtime('/path/to/footer.inc') + * ) + * )); + * $cg->sendHeaders(); + * if ($cg->cacheIsValid) { + * exit(); + * } + * + * @package Minify + * @subpackage HTTP + * @author Stephen Clay + */ +class HTTP_ConditionalGet { + + /** + * Does the client have a valid copy of the requested resource? + * + * You'll want to check this after instantiating the object. If true, do + * not send content, just call sendHeaders() if you haven't already. + * + * @var bool + */ + public $cacheIsValid = null; + + /** + * @param array $spec options + * + * 'isPublic': (bool) if false, the Cache-Control header will contain + * "private", allowing only browser caching. (default false) + * + * 'lastModifiedTime': (int) if given, both ETag AND Last-Modified headers + * will be sent with content. This is recommended. + * + * 'encoding': (string) if set, the header "Vary: Accept-Encoding" will + * always be sent and a truncated version of the encoding will be appended + * to the ETag. E.g. "pub123456;gz". This will also trigger a more lenient + * checking of the client's If-None-Match header, as the encoding portion of + * the ETag will be stripped before comparison. + * + * 'contentHash': (string) if given, only the ETag header can be sent with + * content (only HTTP1.1 clients can conditionally GET). The given string + * should be short with no quote characters and always change when the + * resource changes (recommend md5()). This is not needed/used if + * lastModifiedTime is given. + * + * 'eTag': (string) if given, this will be used as the ETag header rather + * than values based on lastModifiedTime or contentHash. Also the encoding + * string will not be appended to the given value as described above. + * + * 'invalidate': (bool) if true, the client cache will be considered invalid + * without testing. Effectively this disables conditional GET. + * (default false) + * + * 'maxAge': (int) if given, this will set the Cache-Control max-age in + * seconds, and also set the Expires header to the equivalent GMT date. + * After the max-age period has passed, the browser will again send a + * conditional GET to revalidate its cache. + */ + public function __construct($spec) + { + $scope = (isset($spec['isPublic']) && $spec['isPublic']) + ? 'public' + : 'private'; + $maxAge = 0; + // backwards compatibility (can be removed later) + if (isset($spec['setExpires']) + && is_numeric($spec['setExpires']) + && ! isset($spec['maxAge'])) { + $spec['maxAge'] = $spec['setExpires'] - $_SERVER['REQUEST_TIME']; + } + if (isset($spec['maxAge'])) { + $maxAge = $spec['maxAge']; + $this->_headers['Expires'] = self::gmtDate( + $_SERVER['REQUEST_TIME'] + $spec['maxAge'] + ); + } + $etagAppend = ''; + if (isset($spec['encoding'])) { + $this->_stripEtag = true; + $this->_headers['Vary'] = 'Accept-Encoding'; + if ('' !== $spec['encoding']) { + if (0 === strpos($spec['encoding'], 'x-')) { + $spec['encoding'] = substr($spec['encoding'], 2); + } + $etagAppend = ';' . substr($spec['encoding'], 0, 2); + } + } + if (isset($spec['lastModifiedTime'])) { + $this->_setLastModified($spec['lastModifiedTime']); + if (isset($spec['eTag'])) { // Use it + $this->_setEtag($spec['eTag'], $scope); + } else { // base both headers on time + $this->_setEtag($spec['lastModifiedTime'] . $etagAppend, $scope); + } + } elseif (isset($spec['eTag'])) { // Use it + $this->_setEtag($spec['eTag'], $scope); + } elseif (isset($spec['contentHash'])) { // Use the hash as the ETag + $this->_setEtag($spec['contentHash'] . $etagAppend, $scope); + } + $privacy = ($scope === 'private') + ? ', private' + : ''; + $this->_headers['Cache-Control'] = "max-age={$maxAge}{$privacy}"; + // invalidate cache if disabled, otherwise check + $this->cacheIsValid = (isset($spec['invalidate']) && $spec['invalidate']) + ? false + : $this->_isCacheValid(); + } + + /** + * Get array of output headers to be sent + * + * In the case of 304 responses, this array will only contain the response + * code header: array('_responseCode' => 'HTTP/1.0 304 Not Modified') + * + * Otherwise something like: + * + * array( + * 'Cache-Control' => 'max-age=0, public' + * ,'ETag' => '"foobar"' + * ) + * + * + * @return array + */ + public function getHeaders() + { + return $this->_headers; + } + + /** + * Set the Content-Length header in bytes + * + * With most PHP configs, as long as you don't flush() output, this method + * is not needed and PHP will buffer all output and set Content-Length for + * you. Otherwise you'll want to call this to let the client know up front. + * + * @param int $bytes + * + * @return int copy of input $bytes + */ + public function setContentLength($bytes) + { + return $this->_headers['Content-Length'] = $bytes; + } + + /** + * Send headers + * + * @see getHeaders() + * + * Note this doesn't "clear" the headers. Calling sendHeaders() will + * call header() again (but probably have not effect) and getHeaders() will + * still return the headers. + * + * @return null + */ + public function sendHeaders() + { + $headers = $this->_headers; + if (array_key_exists('_responseCode', $headers)) { + // FastCGI environments require 3rd arg to header() to be set + list(, $code) = explode(' ', $headers['_responseCode'], 3); + header($headers['_responseCode'], true, $code); + unset($headers['_responseCode']); + } + foreach ($headers as $name => $val) { + header($name . ': ' . $val); + } + } + + /** + * Exit if the client's cache is valid for this resource + * + * This is a convenience method for common use of the class + * + * @param int $lastModifiedTime if given, both ETag AND Last-Modified headers + * will be sent with content. This is recommended. + * + * @param bool $isPublic (default false) if true, the Cache-Control header + * will contain "public", allowing proxies to cache the content. Otherwise + * "private" will be sent, allowing only browser caching. + * + * @param array $options (default empty) additional options for constructor + */ + public static function check($lastModifiedTime = null, $isPublic = false, $options = array()) + { + if (null !== $lastModifiedTime) { + $options['lastModifiedTime'] = (int)$lastModifiedTime; + } + $options['isPublic'] = (bool)$isPublic; + $cg = new HTTP_ConditionalGet($options); + $cg->sendHeaders(); + if ($cg->cacheIsValid) { + exit(); + } + } + + + /** + * Get a GMT formatted date for use in HTTP headers + * + * + * header('Expires: ' . HTTP_ConditionalGet::gmtdate($time)); + * + * + * @param int $time unix timestamp + * + * @return string + */ + public static function gmtDate($time) + { + return gmdate('D, d M Y H:i:s \G\M\T', $time); + } + + protected $_headers = array(); + protected $_lmTime = null; + protected $_etag = null; + protected $_stripEtag = false; + + /** + * @param string $hash + * + * @param string $scope + */ + protected function _setEtag($hash, $scope) + { + $this->_etag = '"' . substr($scope, 0, 3) . $hash . '"'; + $this->_headers['ETag'] = $this->_etag; + } + + /** + * @param int $time + */ + protected function _setLastModified($time) + { + $this->_lmTime = (int)$time; + $this->_headers['Last-Modified'] = self::gmtDate($time); + } + + /** + * Determine validity of client cache and queue 304 header if valid + * + * @return bool + */ + protected function _isCacheValid() + { + if (null === $this->_etag) { + // lmTime is copied to ETag, so this condition implies that the + // server sent neither ETag nor Last-Modified, so the client can't + // possibly has a valid cache. + return false; + } + $isValid = ($this->resourceMatchedEtag() || $this->resourceNotModified()); + if ($isValid) { + $this->_headers['_responseCode'] = 'HTTP/1.0 304 Not Modified'; + } + return $isValid; + } + + /** + * @return bool + */ + protected function resourceMatchedEtag() + { + if (!isset($_SERVER['HTTP_IF_NONE_MATCH'])) { + return false; + } + $clientEtagList = get_magic_quotes_gpc() + ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) + : $_SERVER['HTTP_IF_NONE_MATCH']; + $clientEtags = explode(',', $clientEtagList); + + $compareTo = $this->normalizeEtag($this->_etag); + foreach ($clientEtags as $clientEtag) { + if ($this->normalizeEtag($clientEtag) === $compareTo) { + // respond with the client's matched ETag, even if it's not what + // we would've sent by default + $this->_headers['ETag'] = trim($clientEtag); + return true; + } + } + return false; + } + + /** + * @param string $etag + * + * @return string + */ + protected function normalizeEtag($etag) { + $etag = trim($etag); + return $this->_stripEtag + ? preg_replace('/;\\w\\w"$/', '"', $etag) + : $etag; + } + + /** + * @return bool + */ + protected function resourceNotModified() + { + if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { + return false; + } + // strip off IE's extra data (semicolon) + list($ifModifiedSince) = explode(';', $_SERVER['HTTP_IF_MODIFIED_SINCE'], 2); + if (strtotime($ifModifiedSince) >= $this->_lmTime) { + // Apache 2.2's behavior. If there was no ETag match, send the + // non-encoded version of the ETag value. + $this->_headers['ETag'] = $this->normalizeEtag($this->_etag); + return true; + } + return false; + } +} diff --git a/mrclay/minify/min/lib/HTTP/Encoder.php b/mrclay/minify/min/lib/HTTP/Encoder.php new file mode 100644 index 000000000000..8f347793cfa7 --- /dev/null +++ b/mrclay/minify/min/lib/HTTP/Encoder.php @@ -0,0 +1,335 @@ + + * // Send a CSS file, compressed if possible + * $he = new HTTP_Encoder(array( + * 'content' => file_get_contents($cssFile) + * ,'type' => 'text/css' + * )); + * $he->encode(); + * $he->sendAll(); + * + * + * + * // Shortcut to encoding output + * header('Content-Type: text/css'); // needed if not HTML + * HTTP_Encoder::output($css); + * + * + * + * // Just sniff for the accepted encoding + * $encoding = HTTP_Encoder::getAcceptedEncoding(); + * + * + * For more control over headers, use getHeaders() and getData() and send your + * own output. + * + * Note: If you don't need header mgmt, use PHP's native gzencode, gzdeflate, + * and gzcompress functions for gzip, deflate, and compress-encoding + * respectively. + * + * @package Minify + * @subpackage HTTP + * @author Stephen Clay + */ +class HTTP_Encoder { + + /** + * Should the encoder allow HTTP encoding to IE6? + * + * If you have many IE6 users and the bandwidth savings is worth troubling + * some of them, set this to true. + * + * By default, encoding is only offered to IE7+. When this is true, + * getAcceptedEncoding() will return an encoding for IE6 if its user agent + * string contains "SV1". This has been documented in many places as "safe", + * but there seem to be remaining, intermittent encoding bugs in patched + * IE6 on the wild web. + * + * @var bool + */ + public static $encodeToIe6 = true; + + + /** + * Default compression level for zlib operations + * + * This level is used if encode() is not given a $compressionLevel + * + * @var int + */ + public static $compressionLevel = 6; + + + /** + * Get an HTTP Encoder object + * + * @param array $spec options + * + * 'content': (string required) content to be encoded + * + * 'type': (string) if set, the Content-Type header will have this value. + * + * 'method: (string) only set this if you are forcing a particular encoding + * method. If not set, the best method will be chosen by getAcceptedEncoding() + * The available methods are 'gzip', 'deflate', 'compress', and '' (no + * encoding) + */ + public function __construct($spec) + { + $this->_useMbStrlen = (function_exists('mb_strlen') + && (ini_get('mbstring.func_overload') !== '') + && ((int)ini_get('mbstring.func_overload') & 2)); + $this->_content = $spec['content']; + $this->_headers['Content-Length'] = $this->_useMbStrlen + ? (string)mb_strlen($this->_content, '8bit') + : (string)strlen($this->_content); + if (isset($spec['type'])) { + $this->_headers['Content-Type'] = $spec['type']; + } + if (isset($spec['method']) + && in_array($spec['method'], array('gzip', 'deflate', 'compress', ''))) + { + $this->_encodeMethod = array($spec['method'], $spec['method']); + } else { + $this->_encodeMethod = self::getAcceptedEncoding(); + } + } + + /** + * Get content in current form + * + * Call after encode() for encoded content. + * + * @return string + */ + public function getContent() + { + return $this->_content; + } + + /** + * Get array of output headers to be sent + * + * E.g. + * + * array( + * 'Content-Length' => '615' + * ,'Content-Encoding' => 'x-gzip' + * ,'Vary' => 'Accept-Encoding' + * ) + * + * + * @return array + */ + public function getHeaders() + { + return $this->_headers; + } + + /** + * Send output headers + * + * You must call this before headers are sent and it probably cannot be + * used in conjunction with zlib output buffering / mod_gzip. Errors are + * not handled purposefully. + * + * @see getHeaders() + */ + public function sendHeaders() + { + foreach ($this->_headers as $name => $val) { + header($name . ': ' . $val); + } + } + + /** + * Send output headers and content + * + * A shortcut for sendHeaders() and echo getContent() + * + * You must call this before headers are sent and it probably cannot be + * used in conjunction with zlib output buffering / mod_gzip. Errors are + * not handled purposefully. + */ + public function sendAll() + { + $this->sendHeaders(); + echo $this->_content; + } + + /** + * Determine the client's best encoding method from the HTTP Accept-Encoding + * header. + * + * If no Accept-Encoding header is set, or the browser is IE before v6 SP2, + * this will return ('', ''), the "identity" encoding. + * + * A syntax-aware scan is done of the Accept-Encoding, so the method must + * be non 0. The methods are favored in order of gzip, deflate, then + * compress. Deflate is always smallest and generally faster, but is + * rarely sent by servers, so client support could be buggier. + * + * @param bool $allowCompress allow the older compress encoding + * + * @param bool $allowDeflate allow the more recent deflate encoding + * + * @return array two values, 1st is the actual encoding method, 2nd is the + * alias of that method to use in the Content-Encoding header (some browsers + * call gzip "x-gzip" etc.) + */ + public static function getAcceptedEncoding($allowCompress = true, $allowDeflate = true) + { + // @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + + if (! isset($_SERVER['HTTP_ACCEPT_ENCODING']) + || self::isBuggyIe()) + { + return array('', ''); + } + $ae = $_SERVER['HTTP_ACCEPT_ENCODING']; + // gzip checks (quick) + if (0 === strpos($ae, 'gzip,') // most browsers + || 0 === strpos($ae, 'deflate, gzip,') // opera + ) { + return array('gzip', 'gzip'); + } + // gzip checks (slow) + if (preg_match( + '@(?:^|,)\\s*((?:x-)?gzip)\\s*(?:$|,|;\\s*q=(?:0\\.|1))@' + ,$ae + ,$m)) { + return array('gzip', $m[1]); + } + if ($allowDeflate) { + // deflate checks + $aeRev = strrev($ae); + if (0 === strpos($aeRev, 'etalfed ,') // ie, webkit + || 0 === strpos($aeRev, 'etalfed,') // gecko + || 0 === strpos($ae, 'deflate,') // opera + // slow parsing + || preg_match( + '@(?:^|,)\\s*deflate\\s*(?:$|,|;\\s*q=(?:0\\.|1))@', $ae)) { + return array('deflate', 'deflate'); + } + } + if ($allowCompress && preg_match( + '@(?:^|,)\\s*((?:x-)?compress)\\s*(?:$|,|;\\s*q=(?:0\\.|1))@' + ,$ae + ,$m)) { + return array('compress', $m[1]); + } + return array('', ''); + } + + /** + * Encode (compress) the content + * + * If the encode method is '' (none) or compression level is 0, or the 'zlib' + * extension isn't loaded, we return false. + * + * Then the appropriate gz_* function is called to compress the content. If + * this fails, false is returned. + * + * The header "Vary: Accept-Encoding" is added. If encoding is successful, + * the Content-Length header is updated, and Content-Encoding is also added. + * + * @param int $compressionLevel given to zlib functions. If not given, the + * class default will be used. + * + * @return bool success true if the content was actually compressed + */ + public function encode($compressionLevel = null) + { + if (! self::isBuggyIe()) { + $this->_headers['Vary'] = 'Accept-Encoding'; + } + if (null === $compressionLevel) { + $compressionLevel = self::$compressionLevel; + } + if ('' === $this->_encodeMethod[0] + || ($compressionLevel == 0) + || !extension_loaded('zlib')) + { + return false; + } + if ($this->_encodeMethod[0] === 'deflate') { + $encoded = gzdeflate($this->_content, $compressionLevel); + } elseif ($this->_encodeMethod[0] === 'gzip') { + $encoded = gzencode($this->_content, $compressionLevel); + } else { + $encoded = gzcompress($this->_content, $compressionLevel); + } + if (false === $encoded) { + return false; + } + $this->_headers['Content-Length'] = $this->_useMbStrlen + ? (string)mb_strlen($encoded, '8bit') + : (string)strlen($encoded); + $this->_headers['Content-Encoding'] = $this->_encodeMethod[1]; + $this->_content = $encoded; + return true; + } + + /** + * Encode and send appropriate headers and content + * + * This is a convenience method for common use of the class + * + * @param string $content + * + * @param int $compressionLevel given to zlib functions. If not given, the + * class default will be used. + * + * @return bool success true if the content was actually compressed + */ + public static function output($content, $compressionLevel = null) + { + if (null === $compressionLevel) { + $compressionLevel = self::$compressionLevel; + } + $he = new HTTP_Encoder(array('content' => $content)); + $ret = $he->encode($compressionLevel); + $he->sendAll(); + return $ret; + } + + /** + * Is the browser an IE version earlier than 6 SP2? + * + * @return bool + */ + public static function isBuggyIe() + { + if (empty($_SERVER['HTTP_USER_AGENT'])) { + return false; + } + $ua = $_SERVER['HTTP_USER_AGENT']; + // quick escape for non-IEs + if (0 !== strpos($ua, 'Mozilla/4.0 (compatible; MSIE ') + || false !== strpos($ua, 'Opera')) { + return false; + } + // no regex = faaast + $version = (float)substr($ua, 30); + return self::$encodeToIe6 + ? ($version < 6 || ($version == 6 && false === strpos($ua, 'SV1'))) + : ($version < 7); + } + + protected $_content = ''; + protected $_headers = array(); + protected $_encodeMethod = array('', ''); + protected $_useMbStrlen = false; +} diff --git a/mrclay/minify/min/lib/JSMin.php b/mrclay/minify/min/lib/JSMin.php new file mode 100644 index 000000000000..9840d8b33dd1 --- /dev/null +++ b/mrclay/minify/min/lib/JSMin.php @@ -0,0 +1,449 @@ + + * $minifiedJs = JSMin::minify($js); + * + * + * This is a modified port of jsmin.c. Improvements: + * + * Does not choke on some regexp literals containing quote characters. E.g. /'/ + * + * Spaces are preserved after some add/sub operators, so they are not mistakenly + * converted to post-inc/dec. E.g. a + ++b -> a+ ++b + * + * Preserves multi-line comments that begin with /*! + * + * PHP 5 or higher is required. + * + * Permission is hereby granted to use this version of the library under the + * same terms as jsmin.c, which has the following license: + * + * -- + * Copyright (c) 2002 Douglas Crockford (www.crockford.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * The Software shall be used for Good, not Evil. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * -- + * + * @package JSMin + * @author Ryan Grove (PHP port) + * @author Steve Clay (modifications + cleanup) + * @author Andrea Giammarchi (spaceBeforeRegExp) + * @copyright 2002 Douglas Crockford (jsmin.c) + * @copyright 2008 Ryan Grove (PHP port) + * @license http://opensource.org/licenses/mit-license.php MIT License + * @link http://code.google.com/p/jsmin-php/ + */ + +class JSMin { + const ORD_LF = 10; + const ORD_SPACE = 32; + const ACTION_KEEP_A = 1; + const ACTION_DELETE_A = 2; + const ACTION_DELETE_A_B = 3; + + protected $a = "\n"; + protected $b = ''; + protected $input = ''; + protected $inputIndex = 0; + protected $inputLength = 0; + protected $lookAhead = null; + protected $output = ''; + protected $lastByteOut = ''; + protected $keptComment = ''; + + /** + * Minify Javascript. + * + * @param string $js Javascript to be minified + * + * @return string + */ + public static function minify($js) + { + $jsmin = new JSMin($js); + return $jsmin->min(); + } + + /** + * @param string $input + */ + public function __construct($input) + { + $this->input = $input; + } + + /** + * Perform minification, return result + * + * @return string + */ + public function min() + { + if ($this->output !== '') { // min already run + return $this->output; + } + + $mbIntEnc = null; + if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) { + $mbIntEnc = mb_internal_encoding(); + mb_internal_encoding('8bit'); + } + $this->input = str_replace("\r\n", "\n", $this->input); + $this->inputLength = strlen($this->input); + + $this->action(self::ACTION_DELETE_A_B); + + while ($this->a !== null) { + // determine next command + $command = self::ACTION_KEEP_A; // default + if ($this->a === ' ') { + if (($this->lastByteOut === '+' || $this->lastByteOut === '-') + && ($this->b === $this->lastByteOut)) { + // Don't delete this space. If we do, the addition/subtraction + // could be parsed as a post-increment + } elseif (! $this->isAlphaNum($this->b)) { + $command = self::ACTION_DELETE_A; + } + } elseif ($this->a === "\n") { + if ($this->b === ' ') { + $command = self::ACTION_DELETE_A_B; + + // in case of mbstring.func_overload & 2, must check for null b, + // otherwise mb_strpos will give WARNING + } elseif ($this->b === null + || (false === strpos('{[(+-!~', $this->b) + && ! $this->isAlphaNum($this->b))) { + $command = self::ACTION_DELETE_A; + } + } elseif (! $this->isAlphaNum($this->a)) { + if ($this->b === ' ' + || ($this->b === "\n" + && (false === strpos('}])+-"\'', $this->a)))) { + $command = self::ACTION_DELETE_A_B; + } + } + $this->action($command); + } + $this->output = trim($this->output); + + if ($mbIntEnc !== null) { + mb_internal_encoding($mbIntEnc); + } + return $this->output; + } + + /** + * ACTION_KEEP_A = Output A. Copy B to A. Get the next B. + * ACTION_DELETE_A = Copy B to A. Get the next B. + * ACTION_DELETE_A_B = Get the next B. + * + * @param int $command + * @throws JSMin_UnterminatedRegExpException|JSMin_UnterminatedStringException + */ + protected function action($command) + { + // make sure we don't compress "a + ++b" to "a+++b", etc. + if ($command === self::ACTION_DELETE_A_B + && $this->b === ' ' + && ($this->a === '+' || $this->a === '-')) { + // Note: we're at an addition/substraction operator; the inputIndex + // will certainly be a valid index + if ($this->input[$this->inputIndex] === $this->a) { + // This is "+ +" or "- -". Don't delete the space. + $command = self::ACTION_KEEP_A; + } + } + + switch ($command) { + case self::ACTION_KEEP_A: // 1 + $this->output .= $this->a; + + if ($this->keptComment) { + $this->output = rtrim($this->output, "\n"); + $this->output .= $this->keptComment; + $this->keptComment = ''; + } + + $this->lastByteOut = $this->a; + + // fallthrough intentional + case self::ACTION_DELETE_A: // 2 + $this->a = $this->b; + if ($this->a === "'" || $this->a === '"') { // string literal + $str = $this->a; // in case needed for exception + for(;;) { + $this->output .= $this->a; + $this->lastByteOut = $this->a; + + $this->a = $this->get(); + if ($this->a === $this->b) { // end quote + break; + } + if ($this->isEOF($this->a)) { + $byte = $this->inputIndex - 1; + throw new JSMin_UnterminatedStringException( + "JSMin: Unterminated String at byte {$byte}: {$str}"); + } + $str .= $this->a; + if ($this->a === '\\') { + $this->output .= $this->a; + $this->lastByteOut = $this->a; + + $this->a = $this->get(); + $str .= $this->a; + } + } + } + + // fallthrough intentional + case self::ACTION_DELETE_A_B: // 3 + $this->b = $this->next(); + if ($this->b === '/' && $this->isRegexpLiteral()) { + $this->output .= $this->a . $this->b; + $pattern = '/'; // keep entire pattern in case we need to report it in the exception + for(;;) { + $this->a = $this->get(); + $pattern .= $this->a; + if ($this->a === '[') { + for(;;) { + $this->output .= $this->a; + $this->a = $this->get(); + $pattern .= $this->a; + if ($this->a === ']') { + break; + } + if ($this->a === '\\') { + $this->output .= $this->a; + $this->a = $this->get(); + $pattern .= $this->a; + } + if ($this->isEOF($this->a)) { + throw new JSMin_UnterminatedRegExpException( + "JSMin: Unterminated set in RegExp at byte " + . $this->inputIndex .": {$pattern}"); + } + } + } + + if ($this->a === '/') { // end pattern + break; // while (true) + } elseif ($this->a === '\\') { + $this->output .= $this->a; + $this->a = $this->get(); + $pattern .= $this->a; + } elseif ($this->isEOF($this->a)) { + $byte = $this->inputIndex - 1; + throw new JSMin_UnterminatedRegExpException( + "JSMin: Unterminated RegExp at byte {$byte}: {$pattern}"); + } + $this->output .= $this->a; + $this->lastByteOut = $this->a; + } + $this->b = $this->next(); + } + // end case ACTION_DELETE_A_B + } + } + + /** + * @return bool + */ + protected function isRegexpLiteral() + { + if (false !== strpos("(,=:[!&|?+-~*{;", $this->a)) { + // we obviously aren't dividing + return true; + } + + // we have to check for a preceding keyword, and we don't need to pattern + // match over the whole output. + $recentOutput = substr($this->output, -10); + + // check if return/typeof directly precede a pattern without a space + foreach (array('return', 'typeof') as $keyword) { + if ($this->a !== substr($keyword, -1)) { + // certainly wasn't keyword + continue; + } + if (preg_match("~(^|[\\s\\S])" . substr($keyword, 0, -1) . "$~", $recentOutput, $m)) { + if ($m[1] === '' || !$this->isAlphaNum($m[1])) { + return true; + } + } + } + + // check all keywords + if ($this->a === ' ' || $this->a === "\n") { + if (preg_match('~(^|[\\s\\S])(?:case|else|in|return|typeof)$~', $recentOutput, $m)) { + if ($m[1] === '' || !$this->isAlphaNum($m[1])) { + return true; + } + } + } + + return false; + } + + /** + * Return the next character from stdin. Watch out for lookahead. If the character is a control character, + * translate it to a space or linefeed. + * + * @return string + */ + protected function get() + { + $c = $this->lookAhead; + $this->lookAhead = null; + if ($c === null) { + // getc(stdin) + if ($this->inputIndex < $this->inputLength) { + $c = $this->input[$this->inputIndex]; + $this->inputIndex += 1; + } else { + $c = null; + } + } + if (ord($c) >= self::ORD_SPACE || $c === "\n" || $c === null) { + return $c; + } + if ($c === "\r") { + return "\n"; + } + return ' '; + } + + /** + * Does $a indicate end of input? + * + * @param string $a + * @return bool + */ + protected function isEOF($a) + { + return ord($a) <= self::ORD_LF; + } + + /** + * Get next char (without getting it). If is ctrl character, translate to a space or newline. + * + * @return string + */ + protected function peek() + { + $this->lookAhead = $this->get(); + return $this->lookAhead; + } + + /** + * Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character. + * + * @param string $c + * + * @return bool + */ + protected function isAlphaNum($c) + { + return (preg_match('/^[a-z0-9A-Z_\\$\\\\]$/', $c) || ord($c) > 126); + } + + /** + * Consume a single line comment from input (possibly retaining it) + */ + protected function consumeSingleLineComment() + { + $comment = ''; + while (true) { + $get = $this->get(); + $comment .= $get; + if (ord($get) <= self::ORD_LF) { // end of line reached + // if IE conditional comment + if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) { + $this->keptComment .= "/{$comment}"; + } + return; + } + } + } + + /** + * Consume a multiple line comment from input (possibly retaining it) + * + * @throws JSMin_UnterminatedCommentException + */ + protected function consumeMultipleLineComment() + { + $this->get(); + $comment = ''; + for(;;) { + $get = $this->get(); + if ($get === '*') { + if ($this->peek() === '/') { // end of comment reached + $this->get(); + if (0 === strpos($comment, '!')) { + // preserved by YUI Compressor + if (!$this->keptComment) { + // don't prepend a newline if two comments right after one another + $this->keptComment = "\n"; + } + $this->keptComment .= "/*!" . substr($comment, 1) . "*/\n"; + } else if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) { + // IE conditional + $this->keptComment .= "/*{$comment}*/"; + } + return; + } + } elseif ($get === null) { + throw new JSMin_UnterminatedCommentException( + "JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}"); + } + $comment .= $get; + } + } + + /** + * Get the next character, skipping over comments. Some comments may be preserved. + * + * @return string + */ + protected function next() + { + $get = $this->get(); + if ($get === '/') { + switch ($this->peek()) { + case '/': + $this->consumeSingleLineComment(); + $get = "\n"; + break; + case '*': + $this->consumeMultipleLineComment(); + $get = ' '; + break; + } + } + return $get; + } +} + +class JSMin_UnterminatedStringException extends Exception {} +class JSMin_UnterminatedCommentException extends Exception {} +class JSMin_UnterminatedRegExpException extends Exception {} diff --git a/mrclay/minify/min/lib/JSMinPlus.php b/mrclay/minify/min/lib/JSMinPlus.php new file mode 100644 index 000000000000..5a3c5bdff4fd --- /dev/null +++ b/mrclay/minify/min/lib/JSMinPlus.php @@ -0,0 +1,2086 @@ + + * + * Usage: $minified = JSMinPlus::minify($script [, $filename]) + * + * Versionlog (see also changelog.txt): + * 23-07-2011 - remove dynamic creation of OP_* and KEYWORD_* defines and declare them on top + * reduce memory footprint by minifying by block-scope + * some small byte-saving and performance improvements + * 12-05-2009 - fixed hook:colon precedence, fixed empty body in loop and if-constructs + * 18-04-2009 - fixed crashbug in PHP 5.2.9 and several other bugfixes + * 12-04-2009 - some small bugfixes and performance improvements + * 09-04-2009 - initial open sourced version 1.0 + * + * Latest version of this script: http://files.tweakers.net/jsminplus/jsminplus.zip + * + */ + +/* ***** 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 + * http://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 the Narcissus JavaScript engine. + * + * The Initial Developer of the Original Code is + * Brendan Eich . + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): Tino Zijdel + * PHP port, modifications and minifier routine are (C) 2009-2011 + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +define('TOKEN_END', 1); +define('TOKEN_NUMBER', 2); +define('TOKEN_IDENTIFIER', 3); +define('TOKEN_STRING', 4); +define('TOKEN_REGEXP', 5); +define('TOKEN_NEWLINE', 6); +define('TOKEN_CONDCOMMENT_START', 7); +define('TOKEN_CONDCOMMENT_END', 8); + +define('JS_SCRIPT', 100); +define('JS_BLOCK', 101); +define('JS_LABEL', 102); +define('JS_FOR_IN', 103); +define('JS_CALL', 104); +define('JS_NEW_WITH_ARGS', 105); +define('JS_INDEX', 106); +define('JS_ARRAY_INIT', 107); +define('JS_OBJECT_INIT', 108); +define('JS_PROPERTY_INIT', 109); +define('JS_GETTER', 110); +define('JS_SETTER', 111); +define('JS_GROUP', 112); +define('JS_LIST', 113); + +define('JS_MINIFIED', 999); + +define('DECLARED_FORM', 0); +define('EXPRESSED_FORM', 1); +define('STATEMENT_FORM', 2); + +/* Operators */ +define('OP_SEMICOLON', ';'); +define('OP_COMMA', ','); +define('OP_HOOK', '?'); +define('OP_COLON', ':'); +define('OP_OR', '||'); +define('OP_AND', '&&'); +define('OP_BITWISE_OR', '|'); +define('OP_BITWISE_XOR', '^'); +define('OP_BITWISE_AND', '&'); +define('OP_STRICT_EQ', '==='); +define('OP_EQ', '=='); +define('OP_ASSIGN', '='); +define('OP_STRICT_NE', '!=='); +define('OP_NE', '!='); +define('OP_LSH', '<<'); +define('OP_LE', '<='); +define('OP_LT', '<'); +define('OP_URSH', '>>>'); +define('OP_RSH', '>>'); +define('OP_GE', '>='); +define('OP_GT', '>'); +define('OP_INCREMENT', '++'); +define('OP_DECREMENT', '--'); +define('OP_PLUS', '+'); +define('OP_MINUS', '-'); +define('OP_MUL', '*'); +define('OP_DIV', '/'); +define('OP_MOD', '%'); +define('OP_NOT', '!'); +define('OP_BITWISE_NOT', '~'); +define('OP_DOT', '.'); +define('OP_LEFT_BRACKET', '['); +define('OP_RIGHT_BRACKET', ']'); +define('OP_LEFT_CURLY', '{'); +define('OP_RIGHT_CURLY', '}'); +define('OP_LEFT_PAREN', '('); +define('OP_RIGHT_PAREN', ')'); +define('OP_CONDCOMMENT_END', '@*/'); + +define('OP_UNARY_PLUS', 'U+'); +define('OP_UNARY_MINUS', 'U-'); + +/* Keywords */ +define('KEYWORD_BREAK', 'break'); +define('KEYWORD_CASE', 'case'); +define('KEYWORD_CATCH', 'catch'); +define('KEYWORD_CONST', 'const'); +define('KEYWORD_CONTINUE', 'continue'); +define('KEYWORD_DEBUGGER', 'debugger'); +define('KEYWORD_DEFAULT', 'default'); +define('KEYWORD_DELETE', 'delete'); +define('KEYWORD_DO', 'do'); +define('KEYWORD_ELSE', 'else'); +define('KEYWORD_ENUM', 'enum'); +define('KEYWORD_FALSE', 'false'); +define('KEYWORD_FINALLY', 'finally'); +define('KEYWORD_FOR', 'for'); +define('KEYWORD_FUNCTION', 'function'); +define('KEYWORD_IF', 'if'); +define('KEYWORD_IN', 'in'); +define('KEYWORD_INSTANCEOF', 'instanceof'); +define('KEYWORD_NEW', 'new'); +define('KEYWORD_NULL', 'null'); +define('KEYWORD_RETURN', 'return'); +define('KEYWORD_SWITCH', 'switch'); +define('KEYWORD_THIS', 'this'); +define('KEYWORD_THROW', 'throw'); +define('KEYWORD_TRUE', 'true'); +define('KEYWORD_TRY', 'try'); +define('KEYWORD_TYPEOF', 'typeof'); +define('KEYWORD_VAR', 'var'); +define('KEYWORD_VOID', 'void'); +define('KEYWORD_WHILE', 'while'); +define('KEYWORD_WITH', 'with'); + + +class JSMinPlus +{ + private $parser; + private $reserved = array( + 'break', 'case', 'catch', 'continue', 'default', 'delete', 'do', + 'else', 'finally', 'for', 'function', 'if', 'in', 'instanceof', + 'new', 'return', 'switch', 'this', 'throw', 'try', 'typeof', 'var', + 'void', 'while', 'with', + // Words reserved for future use + 'abstract', 'boolean', 'byte', 'char', 'class', 'const', 'debugger', + 'double', 'enum', 'export', 'extends', 'final', 'float', 'goto', + 'implements', 'import', 'int', 'interface', 'long', 'native', + 'package', 'private', 'protected', 'public', 'short', 'static', + 'super', 'synchronized', 'throws', 'transient', 'volatile', + // These are not reserved, but should be taken into account + // in isValidIdentifier (See jslint source code) + 'arguments', 'eval', 'true', 'false', 'Infinity', 'NaN', 'null', 'undefined' + ); + + private function __construct() + { + $this->parser = new JSParser($this); + } + + public static function minify($js, $filename='') + { + static $instance; + + // this is a singleton + if(!$instance) + $instance = new JSMinPlus(); + + return $instance->min($js, $filename); + } + + private function min($js, $filename) + { + try + { + $n = $this->parser->parse($js, $filename, 1); + return $this->parseTree($n); + } + catch(Exception $e) + { + echo $e->getMessage() . "\n"; + } + + return false; + } + + public function parseTree($n, $noBlockGrouping = false) + { + $s = ''; + + switch ($n->type) + { + case JS_MINIFIED: + $s = $n->value; + break; + + case JS_SCRIPT: + // we do nothing yet with funDecls or varDecls + $noBlockGrouping = true; + // FALL THROUGH + + case JS_BLOCK: + $childs = $n->treeNodes; + $lastType = 0; + for ($c = 0, $i = 0, $j = count($childs); $i < $j; $i++) + { + $type = $childs[$i]->type; + $t = $this->parseTree($childs[$i]); + if (strlen($t)) + { + if ($c) + { + $s = rtrim($s, ';'); + + if ($type == KEYWORD_FUNCTION && $childs[$i]->functionForm == DECLARED_FORM) + { + // put declared functions on a new line + $s .= "\n"; + } + elseif ($type == KEYWORD_VAR && $type == $lastType) + { + // mutiple var-statements can go into one + $t = ',' . substr($t, 4); + } + else + { + // add terminator + $s .= ';'; + } + } + + $s .= $t; + + $c++; + $lastType = $type; + } + } + + if ($c > 1 && !$noBlockGrouping) + { + $s = '{' . $s . '}'; + } + break; + + case KEYWORD_FUNCTION: + $s .= 'function' . ($n->name ? ' ' . $n->name : '') . '('; + $params = $n->params; + for ($i = 0, $j = count($params); $i < $j; $i++) + $s .= ($i ? ',' : '') . $params[$i]; + $s .= '){' . $this->parseTree($n->body, true) . '}'; + break; + + case KEYWORD_IF: + $s = 'if(' . $this->parseTree($n->condition) . ')'; + $thenPart = $this->parseTree($n->thenPart); + $elsePart = $n->elsePart ? $this->parseTree($n->elsePart) : null; + + // empty if-statement + if ($thenPart == '') + $thenPart = ';'; + + if ($elsePart) + { + // be carefull and always make a block out of the thenPart; could be more optimized but is a lot of trouble + if ($thenPart != ';' && $thenPart[0] != '{') + $thenPart = '{' . $thenPart . '}'; + + $s .= $thenPart . 'else'; + + // we could check for more, but that hardly ever applies so go for performance + if ($elsePart[0] != '{') + $s .= ' '; + + $s .= $elsePart; + } + else + { + $s .= $thenPart; + } + break; + + case KEYWORD_SWITCH: + $s = 'switch(' . $this->parseTree($n->discriminant) . '){'; + $cases = $n->cases; + for ($i = 0, $j = count($cases); $i < $j; $i++) + { + $case = $cases[$i]; + if ($case->type == KEYWORD_CASE) + $s .= 'case' . ($case->caseLabel->type != TOKEN_STRING ? ' ' : '') . $this->parseTree($case->caseLabel) . ':'; + else + $s .= 'default:'; + + $statement = $this->parseTree($case->statements, true); + if ($statement) + { + $s .= $statement; + // no terminator for last statement + if ($i + 1 < $j) + $s .= ';'; + } + } + $s .= '}'; + break; + + case KEYWORD_FOR: + $s = 'for(' . ($n->setup ? $this->parseTree($n->setup) : '') + . ';' . ($n->condition ? $this->parseTree($n->condition) : '') + . ';' . ($n->update ? $this->parseTree($n->update) : '') . ')'; + + $body = $this->parseTree($n->body); + if ($body == '') + $body = ';'; + + $s .= $body; + break; + + case KEYWORD_WHILE: + $s = 'while(' . $this->parseTree($n->condition) . ')'; + + $body = $this->parseTree($n->body); + if ($body == '') + $body = ';'; + + $s .= $body; + break; + + case JS_FOR_IN: + $s = 'for(' . ($n->varDecl ? $this->parseTree($n->varDecl) : $this->parseTree($n->iterator)) . ' in ' . $this->parseTree($n->object) . ')'; + + $body = $this->parseTree($n->body); + if ($body == '') + $body = ';'; + + $s .= $body; + break; + + case KEYWORD_DO: + $s = 'do{' . $this->parseTree($n->body, true) . '}while(' . $this->parseTree($n->condition) . ')'; + break; + + case KEYWORD_BREAK: + case KEYWORD_CONTINUE: + $s = $n->value . ($n->label ? ' ' . $n->label : ''); + break; + + case KEYWORD_TRY: + $s = 'try{' . $this->parseTree($n->tryBlock, true) . '}'; + $catchClauses = $n->catchClauses; + for ($i = 0, $j = count($catchClauses); $i < $j; $i++) + { + $t = $catchClauses[$i]; + $s .= 'catch(' . $t->varName . ($t->guard ? ' if ' . $this->parseTree($t->guard) : '') . '){' . $this->parseTree($t->block, true) . '}'; + } + if ($n->finallyBlock) + $s .= 'finally{' . $this->parseTree($n->finallyBlock, true) . '}'; + break; + + case KEYWORD_THROW: + case KEYWORD_RETURN: + $s = $n->type; + if ($n->value) + { + $t = $this->parseTree($n->value); + if (strlen($t)) + { + if ($this->isWordChar($t[0]) || $t[0] == '\\') + $s .= ' '; + + $s .= $t; + } + } + break; + + case KEYWORD_WITH: + $s = 'with(' . $this->parseTree($n->object) . ')' . $this->parseTree($n->body); + break; + + case KEYWORD_VAR: + case KEYWORD_CONST: + $s = $n->value . ' '; + $childs = $n->treeNodes; + for ($i = 0, $j = count($childs); $i < $j; $i++) + { + $t = $childs[$i]; + $s .= ($i ? ',' : '') . $t->name; + $u = $t->initializer; + if ($u) + $s .= '=' . $this->parseTree($u); + } + break; + + case KEYWORD_IN: + case KEYWORD_INSTANCEOF: + $left = $this->parseTree($n->treeNodes[0]); + $right = $this->parseTree($n->treeNodes[1]); + + $s = $left; + + if ($this->isWordChar(substr($left, -1))) + $s .= ' '; + + $s .= $n->type; + + if ($this->isWordChar($right[0]) || $right[0] == '\\') + $s .= ' '; + + $s .= $right; + break; + + case KEYWORD_DELETE: + case KEYWORD_TYPEOF: + $right = $this->parseTree($n->treeNodes[0]); + + $s = $n->type; + + if ($this->isWordChar($right[0]) || $right[0] == '\\') + $s .= ' '; + + $s .= $right; + break; + + case KEYWORD_VOID: + $s = 'void(' . $this->parseTree($n->treeNodes[0]) . ')'; + break; + + case KEYWORD_DEBUGGER: + throw new Exception('NOT IMPLEMENTED: DEBUGGER'); + break; + + case TOKEN_CONDCOMMENT_START: + case TOKEN_CONDCOMMENT_END: + $s = $n->value . ($n->type == TOKEN_CONDCOMMENT_START ? ' ' : ''); + $childs = $n->treeNodes; + for ($i = 0, $j = count($childs); $i < $j; $i++) + $s .= $this->parseTree($childs[$i]); + break; + + case OP_SEMICOLON: + if ($expression = $n->expression) + $s = $this->parseTree($expression); + break; + + case JS_LABEL: + $s = $n->label . ':' . $this->parseTree($n->statement); + break; + + case OP_COMMA: + $childs = $n->treeNodes; + for ($i = 0, $j = count($childs); $i < $j; $i++) + $s .= ($i ? ',' : '') . $this->parseTree($childs[$i]); + break; + + case OP_ASSIGN: + $s = $this->parseTree($n->treeNodes[0]) . $n->value . $this->parseTree($n->treeNodes[1]); + break; + + case OP_HOOK: + $s = $this->parseTree($n->treeNodes[0]) . '?' . $this->parseTree($n->treeNodes[1]) . ':' . $this->parseTree($n->treeNodes[2]); + break; + + case OP_OR: case OP_AND: + case OP_BITWISE_OR: case OP_BITWISE_XOR: case OP_BITWISE_AND: + case OP_EQ: case OP_NE: case OP_STRICT_EQ: case OP_STRICT_NE: + case OP_LT: case OP_LE: case OP_GE: case OP_GT: + case OP_LSH: case OP_RSH: case OP_URSH: + case OP_MUL: case OP_DIV: case OP_MOD: + $s = $this->parseTree($n->treeNodes[0]) . $n->type . $this->parseTree($n->treeNodes[1]); + break; + + case OP_PLUS: + case OP_MINUS: + $left = $this->parseTree($n->treeNodes[0]); + $right = $this->parseTree($n->treeNodes[1]); + + switch ($n->treeNodes[1]->type) + { + case OP_PLUS: + case OP_MINUS: + case OP_INCREMENT: + case OP_DECREMENT: + case OP_UNARY_PLUS: + case OP_UNARY_MINUS: + $s = $left . $n->type . ' ' . $right; + break; + + case TOKEN_STRING: + //combine concatted strings with same quotestyle + if ($n->type == OP_PLUS && substr($left, -1) == $right[0]) + { + $s = substr($left, 0, -1) . substr($right, 1); + break; + } + // FALL THROUGH + + default: + $s = $left . $n->type . $right; + } + break; + + case OP_NOT: + case OP_BITWISE_NOT: + case OP_UNARY_PLUS: + case OP_UNARY_MINUS: + $s = $n->value . $this->parseTree($n->treeNodes[0]); + break; + + case OP_INCREMENT: + case OP_DECREMENT: + if ($n->postfix) + $s = $this->parseTree($n->treeNodes[0]) . $n->value; + else + $s = $n->value . $this->parseTree($n->treeNodes[0]); + break; + + case OP_DOT: + $s = $this->parseTree($n->treeNodes[0]) . '.' . $this->parseTree($n->treeNodes[1]); + break; + + case JS_INDEX: + $s = $this->parseTree($n->treeNodes[0]); + // See if we can replace named index with a dot saving 3 bytes + if ( $n->treeNodes[0]->type == TOKEN_IDENTIFIER && + $n->treeNodes[1]->type == TOKEN_STRING && + $this->isValidIdentifier(substr($n->treeNodes[1]->value, 1, -1)) + ) + $s .= '.' . substr($n->treeNodes[1]->value, 1, -1); + else + $s .= '[' . $this->parseTree($n->treeNodes[1]) . ']'; + break; + + case JS_LIST: + $childs = $n->treeNodes; + for ($i = 0, $j = count($childs); $i < $j; $i++) + $s .= ($i ? ',' : '') . $this->parseTree($childs[$i]); + break; + + case JS_CALL: + $s = $this->parseTree($n->treeNodes[0]) . '(' . $this->parseTree($n->treeNodes[1]) . ')'; + break; + + case KEYWORD_NEW: + case JS_NEW_WITH_ARGS: + $s = 'new ' . $this->parseTree($n->treeNodes[0]) . '(' . ($n->type == JS_NEW_WITH_ARGS ? $this->parseTree($n->treeNodes[1]) : '') . ')'; + break; + + case JS_ARRAY_INIT: + $s = '['; + $childs = $n->treeNodes; + for ($i = 0, $j = count($childs); $i < $j; $i++) + { + $s .= ($i ? ',' : '') . $this->parseTree($childs[$i]); + } + $s .= ']'; + break; + + case JS_OBJECT_INIT: + $s = '{'; + $childs = $n->treeNodes; + for ($i = 0, $j = count($childs); $i < $j; $i++) + { + $t = $childs[$i]; + if ($i) + $s .= ','; + if ($t->type == JS_PROPERTY_INIT) + { + // Ditch the quotes when the index is a valid identifier + if ( $t->treeNodes[0]->type == TOKEN_STRING && + $this->isValidIdentifier(substr($t->treeNodes[0]->value, 1, -1)) + ) + $s .= substr($t->treeNodes[0]->value, 1, -1); + else + $s .= $t->treeNodes[0]->value; + + $s .= ':' . $this->parseTree($t->treeNodes[1]); + } + else + { + $s .= $t->type == JS_GETTER ? 'get' : 'set'; + $s .= ' ' . $t->name . '('; + $params = $t->params; + for ($i = 0, $j = count($params); $i < $j; $i++) + $s .= ($i ? ',' : '') . $params[$i]; + $s .= '){' . $this->parseTree($t->body, true) . '}'; + } + } + $s .= '}'; + break; + + case TOKEN_NUMBER: + $s = $n->value; + if (preg_match('/^([1-9]+)(0{3,})$/', $s, $m)) + $s = $m[1] . 'e' . strlen($m[2]); + break; + + case KEYWORD_NULL: case KEYWORD_THIS: case KEYWORD_TRUE: case KEYWORD_FALSE: + case TOKEN_IDENTIFIER: case TOKEN_STRING: case TOKEN_REGEXP: + $s = $n->value; + break; + + case JS_GROUP: + if (in_array( + $n->treeNodes[0]->type, + array( + JS_ARRAY_INIT, JS_OBJECT_INIT, JS_GROUP, + TOKEN_NUMBER, TOKEN_STRING, TOKEN_REGEXP, TOKEN_IDENTIFIER, + KEYWORD_NULL, KEYWORD_THIS, KEYWORD_TRUE, KEYWORD_FALSE + ) + )) + { + $s = $this->parseTree($n->treeNodes[0]); + } + else + { + $s = '(' . $this->parseTree($n->treeNodes[0]) . ')'; + } + break; + + default: + throw new Exception('UNKNOWN TOKEN TYPE: ' . $n->type); + } + + return $s; + } + + private function isValidIdentifier($string) + { + return preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $string) && !in_array($string, $this->reserved); + } + + private function isWordChar($char) + { + return $char == '_' || $char == '$' || ctype_alnum($char); + } +} + +class JSParser +{ + private $t; + private $minifier; + + private $opPrecedence = array( + ';' => 0, + ',' => 1, + '=' => 2, '?' => 2, ':' => 2, + // The above all have to have the same precedence, see bug 330975 + '||' => 4, + '&&' => 5, + '|' => 6, + '^' => 7, + '&' => 8, + '==' => 9, '!=' => 9, '===' => 9, '!==' => 9, + '<' => 10, '<=' => 10, '>=' => 10, '>' => 10, 'in' => 10, 'instanceof' => 10, + '<<' => 11, '>>' => 11, '>>>' => 11, + '+' => 12, '-' => 12, + '*' => 13, '/' => 13, '%' => 13, + 'delete' => 14, 'void' => 14, 'typeof' => 14, + '!' => 14, '~' => 14, 'U+' => 14, 'U-' => 14, + '++' => 15, '--' => 15, + 'new' => 16, + '.' => 17, + JS_NEW_WITH_ARGS => 0, JS_INDEX => 0, JS_CALL => 0, + JS_ARRAY_INIT => 0, JS_OBJECT_INIT => 0, JS_GROUP => 0 + ); + + private $opArity = array( + ',' => -2, + '=' => 2, + '?' => 3, + '||' => 2, + '&&' => 2, + '|' => 2, + '^' => 2, + '&' => 2, + '==' => 2, '!=' => 2, '===' => 2, '!==' => 2, + '<' => 2, '<=' => 2, '>=' => 2, '>' => 2, 'in' => 2, 'instanceof' => 2, + '<<' => 2, '>>' => 2, '>>>' => 2, + '+' => 2, '-' => 2, + '*' => 2, '/' => 2, '%' => 2, + 'delete' => 1, 'void' => 1, 'typeof' => 1, + '!' => 1, '~' => 1, 'U+' => 1, 'U-' => 1, + '++' => 1, '--' => 1, + 'new' => 1, + '.' => 2, + JS_NEW_WITH_ARGS => 2, JS_INDEX => 2, JS_CALL => 2, + JS_ARRAY_INIT => 1, JS_OBJECT_INIT => 1, JS_GROUP => 1, + TOKEN_CONDCOMMENT_START => 1, TOKEN_CONDCOMMENT_END => 1 + ); + + public function __construct($minifier=null) + { + $this->minifier = $minifier; + $this->t = new JSTokenizer(); + } + + public function parse($s, $f, $l) + { + // initialize tokenizer + $this->t->init($s, $f, $l); + + $x = new JSCompilerContext(false); + $n = $this->Script($x); + if (!$this->t->isDone()) + throw $this->t->newSyntaxError('Syntax error'); + + return $n; + } + + private function Script($x) + { + $n = $this->Statements($x); + $n->type = JS_SCRIPT; + $n->funDecls = $x->funDecls; + $n->varDecls = $x->varDecls; + + // minify by scope + if ($this->minifier) + { + $n->value = $this->minifier->parseTree($n); + + // clear tree from node to save memory + $n->treeNodes = null; + $n->funDecls = null; + $n->varDecls = null; + + $n->type = JS_MINIFIED; + } + + return $n; + } + + private function Statements($x) + { + $n = new JSNode($this->t, JS_BLOCK); + array_push($x->stmtStack, $n); + + while (!$this->t->isDone() && $this->t->peek() != OP_RIGHT_CURLY) + $n->addNode($this->Statement($x)); + + array_pop($x->stmtStack); + + return $n; + } + + private function Block($x) + { + $this->t->mustMatch(OP_LEFT_CURLY); + $n = $this->Statements($x); + $this->t->mustMatch(OP_RIGHT_CURLY); + + return $n; + } + + private function Statement($x) + { + $tt = $this->t->get(); + $n2 = null; + + // Cases for statements ending in a right curly return early, avoiding the + // common semicolon insertion magic after this switch. + switch ($tt) + { + case KEYWORD_FUNCTION: + return $this->FunctionDefinition( + $x, + true, + count($x->stmtStack) > 1 ? STATEMENT_FORM : DECLARED_FORM + ); + break; + + case OP_LEFT_CURLY: + $n = $this->Statements($x); + $this->t->mustMatch(OP_RIGHT_CURLY); + return $n; + + case KEYWORD_IF: + $n = new JSNode($this->t); + $n->condition = $this->ParenExpression($x); + array_push($x->stmtStack, $n); + $n->thenPart = $this->Statement($x); + $n->elsePart = $this->t->match(KEYWORD_ELSE) ? $this->Statement($x) : null; + array_pop($x->stmtStack); + return $n; + + case KEYWORD_SWITCH: + $n = new JSNode($this->t); + $this->t->mustMatch(OP_LEFT_PAREN); + $n->discriminant = $this->Expression($x); + $this->t->mustMatch(OP_RIGHT_PAREN); + $n->cases = array(); + $n->defaultIndex = -1; + + array_push($x->stmtStack, $n); + + $this->t->mustMatch(OP_LEFT_CURLY); + + while (($tt = $this->t->get()) != OP_RIGHT_CURLY) + { + switch ($tt) + { + case KEYWORD_DEFAULT: + if ($n->defaultIndex >= 0) + throw $this->t->newSyntaxError('More than one switch default'); + // FALL THROUGH + case KEYWORD_CASE: + $n2 = new JSNode($this->t); + if ($tt == KEYWORD_DEFAULT) + $n->defaultIndex = count($n->cases); + else + $n2->caseLabel = $this->Expression($x, OP_COLON); + break; + default: + throw $this->t->newSyntaxError('Invalid switch case'); + } + + $this->t->mustMatch(OP_COLON); + $n2->statements = new JSNode($this->t, JS_BLOCK); + while (($tt = $this->t->peek()) != KEYWORD_CASE && $tt != KEYWORD_DEFAULT && $tt != OP_RIGHT_CURLY) + $n2->statements->addNode($this->Statement($x)); + + array_push($n->cases, $n2); + } + + array_pop($x->stmtStack); + return $n; + + case KEYWORD_FOR: + $n = new JSNode($this->t); + $n->isLoop = true; + $this->t->mustMatch(OP_LEFT_PAREN); + + if (($tt = $this->t->peek()) != OP_SEMICOLON) + { + $x->inForLoopInit = true; + if ($tt == KEYWORD_VAR || $tt == KEYWORD_CONST) + { + $this->t->get(); + $n2 = $this->Variables($x); + } + else + { + $n2 = $this->Expression($x); + } + $x->inForLoopInit = false; + } + + if ($n2 && $this->t->match(KEYWORD_IN)) + { + $n->type = JS_FOR_IN; + if ($n2->type == KEYWORD_VAR) + { + if (count($n2->treeNodes) != 1) + { + throw $this->t->SyntaxError( + 'Invalid for..in left-hand side', + $this->t->filename, + $n2->lineno + ); + } + + // NB: n2[0].type == IDENTIFIER and n2[0].value == n2[0].name. + $n->iterator = $n2->treeNodes[0]; + $n->varDecl = $n2; + } + else + { + $n->iterator = $n2; + $n->varDecl = null; + } + + $n->object = $this->Expression($x); + } + else + { + $n->setup = $n2 ? $n2 : null; + $this->t->mustMatch(OP_SEMICOLON); + $n->condition = $this->t->peek() == OP_SEMICOLON ? null : $this->Expression($x); + $this->t->mustMatch(OP_SEMICOLON); + $n->update = $this->t->peek() == OP_RIGHT_PAREN ? null : $this->Expression($x); + } + + $this->t->mustMatch(OP_RIGHT_PAREN); + $n->body = $this->nest($x, $n); + return $n; + + case KEYWORD_WHILE: + $n = new JSNode($this->t); + $n->isLoop = true; + $n->condition = $this->ParenExpression($x); + $n->body = $this->nest($x, $n); + return $n; + + case KEYWORD_DO: + $n = new JSNode($this->t); + $n->isLoop = true; + $n->body = $this->nest($x, $n, KEYWORD_WHILE); + $n->condition = $this->ParenExpression($x); + if (!$x->ecmaStrictMode) + { + // "; + * $link = ""; + * + * // in min.php + * Minify::serve('Groups', array( + * 'groups' => $groupSources + * ,'setExpires' => (time() + 86400 * 365) + * )); + * + * + * @package Minify + * @author Stephen Clay + */ +class Minify_Build { + + /** + * Last modification time of all files in the build + * + * @var int + */ + public $lastModified = 0; + + /** + * String to use as ampersand in uri(). Set this to '&' if + * you are not HTML-escaping URIs. + * + * @var string + */ + public static $ampersand = '&'; + + /** + * Get a time-stamped URI + * + * + * echo $b->uri('/site.js'); + * // outputs "/site.js?1678242" + * + * echo $b->uri('/scriptaculous.js?load=effects'); + * // outputs "/scriptaculous.js?load=effects&1678242" + * + * + * @param string $uri + * @param boolean $forceAmpersand (default = false) Force the use of ampersand to + * append the timestamp to the URI. + * @return string + */ + public function uri($uri, $forceAmpersand = false) { + $sep = ($forceAmpersand || strpos($uri, '?') !== false) + ? self::$ampersand + : '?'; + return "{$uri}{$sep}{$this->lastModified}"; + } + + /** + * Create a build object + * + * @param array $sources array of Minify_Source objects and/or file paths + * + * @return null + */ + public function __construct($sources) + { + $max = 0; + foreach ((array)$sources as $source) { + if ($source instanceof Minify_Source) { + $max = max($max, $source->lastModified); + } elseif (is_string($source)) { + if (0 === strpos($source, '//')) { + $source = $_SERVER['DOCUMENT_ROOT'] . substr($source, 1); + } + if (is_file($source)) { + $max = max($max, filemtime($source)); + } + } + } + $this->lastModified = $max; + } +} diff --git a/mrclay/minify/min/lib/Minify/CSS.php b/mrclay/minify/min/lib/Minify/CSS.php new file mode 100644 index 000000000000..8717cc6714d2 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/CSS.php @@ -0,0 +1,99 @@ + + * @author http://code.google.com/u/1stvamp/ (Issue 64 patch) + */ +class Minify_CSS { + + /** + * Minify a CSS string + * + * @param string $css + * + * @param array $options available options: + * + * 'preserveComments': (default true) multi-line comments that begin + * with "/*!" will be preserved with newlines before and after to + * enhance readability. + * + * 'removeCharsets': (default true) remove all @charset at-rules + * + * 'prependRelativePath': (default null) if given, this string will be + * prepended to all relative URIs in import/url declarations + * + * 'currentDir': (default null) if given, this is assumed to be the + * directory of the current CSS file. Using this, minify will rewrite + * all relative URIs in import/url declarations to correctly point to + * the desired files. For this to work, the files *must* exist and be + * visible by the PHP process. + * + * 'symlinks': (default = array()) If the CSS file is stored in + * a symlink-ed directory, provide an array of link paths to + * target paths, where the link paths are within the document root. Because + * paths need to be normalized for this to work, use "//" to substitute + * the doc root in the link paths (the array keys). E.g.: + * + * array('//symlink' => '/real/target/path') // unix + * array('//static' => 'D:\\staticStorage') // Windows + * + * + * 'docRoot': (default = $_SERVER['DOCUMENT_ROOT']) + * see Minify_CSS_UriRewriter::rewrite + * + * @return string + */ + public static function minify($css, $options = array()) + { + $options = array_merge(array( + 'compress' => true, + 'removeCharsets' => true, + 'preserveComments' => true, + 'currentDir' => null, + 'docRoot' => $_SERVER['DOCUMENT_ROOT'], + 'prependRelativePath' => null, + 'symlinks' => array(), + ), $options); + + if ($options['removeCharsets']) { + $css = preg_replace('/@charset[^;]+;\\s*/', '', $css); + } + if ($options['compress']) { + if (! $options['preserveComments']) { + $css = Minify_CSS_Compressor::process($css, $options); + } else { + $css = Minify_CommentPreserver::process( + $css + ,array('Minify_CSS_Compressor', 'process') + ,array($options) + ); + } + } + if (! $options['currentDir'] && ! $options['prependRelativePath']) { + return $css; + } + if ($options['currentDir']) { + return Minify_CSS_UriRewriter::rewrite( + $css + ,$options['currentDir'] + ,$options['docRoot'] + ,$options['symlinks'] + ); + } else { + return Minify_CSS_UriRewriter::prepend( + $css + ,$options['prependRelativePath'] + ); + } + } +} diff --git a/mrclay/minify/min/lib/Minify/CSS/Compressor.php b/mrclay/minify/min/lib/Minify/CSS/Compressor.php new file mode 100644 index 000000000000..4b9e51d95b8a --- /dev/null +++ b/mrclay/minify/min/lib/Minify/CSS/Compressor.php @@ -0,0 +1,249 @@ + + * @author http://code.google.com/u/1stvamp/ (Issue 64 patch) + */ +class Minify_CSS_Compressor { + + /** + * Minify a CSS string + * + * @param string $css + * + * @param array $options (currently ignored) + * + * @return string + */ + public static function process($css, $options = array()) + { + $obj = new Minify_CSS_Compressor($options); + return $obj->_process($css); + } + + /** + * @var array + */ + protected $_options = null; + + /** + * Are we "in" a hack? I.e. are some browsers targetted until the next comment? + * + * @var bool + */ + protected $_inHack = false; + + + /** + * Constructor + * + * @param array $options (currently ignored) + */ + private function __construct($options) { + $this->_options = $options; + } + + /** + * Minify a CSS string + * + * @param string $css + * + * @return string + */ + protected function _process($css) + { + $css = str_replace("\r\n", "\n", $css); + + // preserve empty comment after '>' + // http://www.webdevout.net/css-hacks#in_css-selectors + $css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css); + + // preserve empty comment between property and value + // http://css-discuss.incutio.com/?page=BoxModelHack + $css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css); + $css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css); + + // apply callback to all valid comments (and strip out surrounding ws + $css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@' + ,array($this, '_commentCB'), $css); + + // remove ws around { } and last semicolon in declaration block + $css = preg_replace('/\\s*{\\s*/', '{', $css); + $css = preg_replace('/;?\\s*}\\s*/', '}', $css); + + // remove ws surrounding semicolons + $css = preg_replace('/\\s*;\\s*/', ';', $css); + + // remove ws around urls + $css = preg_replace('/ + url\\( # url( + \\s* + ([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis) + \\s* + \\) # ) + /x', 'url($1)', $css); + + // remove ws between rules and colons + $css = preg_replace('/ + \\s* + ([{;]) # 1 = beginning of block or rule separator + \\s* + ([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter) + \\s* + : + \\s* + (\\b|[#\'"-]) # 3 = first character of a value + /x', '$1$2:$3', $css); + + // remove ws in selectors + $css = preg_replace_callback('/ + (?: # non-capture + \\s* + [^~>+,\\s]+ # selector part + \\s* + [,>+~] # combinators + )+ + \\s* + [^~>+,\\s]+ # selector part + { # open declaration block + /x' + ,array($this, '_selectorsCB'), $css); + + // minimize hex colors + $css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i' + , '$1#$2$3$4$5', $css); + + // remove spaces between font families + $css = preg_replace_callback('/font-family:([^;}]+)([;}])/' + ,array($this, '_fontFamilyCB'), $css); + + $css = preg_replace('/@import\\s+url/', '@import url', $css); + + // replace any ws involving newlines with a single newline + $css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css); + + // separate common descendent selectors w/ newlines (to limit line lengths) + $css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css); + + // Use newline after 1st numeric value (to limit line lengths). + $css = preg_replace('/ + ((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value + \\s+ + /x' + ,"$1\n", $css); + + // prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/ + $css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css); + + return trim($css); + } + + /** + * Replace what looks like a set of selectors + * + * @param array $m regex matches + * + * @return string + */ + protected function _selectorsCB($m) + { + // remove ws around the combinators + return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]); + } + + /** + * Process a comment and return a replacement + * + * @param array $m regex matches + * + * @return string + */ + protected function _commentCB($m) + { + $hasSurroundingWs = (trim($m[0]) !== $m[1]); + $m = $m[1]; + // $m is the comment content w/o the surrounding tokens, + // but the return value will replace the entire comment. + if ($m === 'keep') { + return '/**/'; + } + if ($m === '" "') { + // component of http://tantek.com/CSS/Examples/midpass.html + return '/*" "*/'; + } + if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) { + // component of http://tantek.com/CSS/Examples/midpass.html + return '/*";}}/* */'; + } + if ($this->_inHack) { + // inversion: feeding only to one browser + if (preg_match('@ + ^/ # comment started like /*/ + \\s* + (\\S[\\s\\S]+?) # has at least some non-ws content + \\s* + /\\* # ends like /*/ or /**/ + @x', $m, $n)) { + // end hack mode after this comment, but preserve the hack and comment content + $this->_inHack = false; + return "/*/{$n[1]}/**/"; + } + } + if (substr($m, -1) === '\\') { // comment ends like \*/ + // begin hack mode and preserve hack + $this->_inHack = true; + return '/*\\*/'; + } + if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */ + // begin hack mode and preserve hack + $this->_inHack = true; + return '/*/*/'; + } + if ($this->_inHack) { + // a regular comment ends hack mode but should be preserved + $this->_inHack = false; + return '/**/'; + } + // Issue 107: if there's any surrounding whitespace, it may be important, so + // replace the comment with a single space + return $hasSurroundingWs // remove all other comments + ? ' ' + : ''; + } + + /** + * Process a font-family listing and return a replacement + * + * @param array $m regex matches + * + * @return string + */ + protected function _fontFamilyCB($m) + { + // Issue 210: must not eliminate WS between words in unquoted families + $pieces = preg_split('/(\'[^\']+\'|"[^"]+")/', $m[1], null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + $out = 'font-family:'; + while (null !== ($piece = array_shift($pieces))) { + if ($piece[0] !== '"' && $piece[0] !== "'") { + $piece = preg_replace('/\\s+/', ' ', $piece); + $piece = preg_replace('/\\s?,\\s?/', ',', $piece); + } + $out .= $piece; + } + return $out . $m[2]; + } +} diff --git a/mrclay/minify/min/lib/Minify/CSS/UriRewriter.php b/mrclay/minify/min/lib/Minify/CSS/UriRewriter.php new file mode 100644 index 000000000000..43cc2548b037 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/CSS/UriRewriter.php @@ -0,0 +1,307 @@ + + */ +class Minify_CSS_UriRewriter { + + /** + * rewrite() and rewriteRelative() append debugging information here + * + * @var string + */ + public static $debugText = ''; + + /** + * In CSS content, rewrite file relative URIs as root relative + * + * @param string $css + * + * @param string $currentDir The directory of the current CSS file. + * + * @param string $docRoot The document root of the web site in which + * the CSS file resides (default = $_SERVER['DOCUMENT_ROOT']). + * + * @param array $symlinks (default = array()) If the CSS file is stored in + * a symlink-ed directory, provide an array of link paths to + * target paths, where the link paths are within the document root. Because + * paths need to be normalized for this to work, use "//" to substitute + * the doc root in the link paths (the array keys). E.g.: + * + * array('//symlink' => '/real/target/path') // unix + * array('//static' => 'D:\\staticStorage') // Windows + * + * + * @return string + */ + public static function rewrite($css, $currentDir, $docRoot = null, $symlinks = array()) + { + self::$_docRoot = self::_realpath( + $docRoot ? $docRoot : $_SERVER['DOCUMENT_ROOT'] + ); + self::$_currentDir = self::_realpath($currentDir); + self::$_symlinks = array(); + + // normalize symlinks + foreach ($symlinks as $link => $target) { + $link = ($link === '//') + ? self::$_docRoot + : str_replace('//', self::$_docRoot . '/', $link); + $link = strtr($link, '/', DIRECTORY_SEPARATOR); + self::$_symlinks[$link] = self::_realpath($target); + } + + self::$debugText .= "docRoot : " . self::$_docRoot . "\n" + . "currentDir : " . self::$_currentDir . "\n"; + if (self::$_symlinks) { + self::$debugText .= "symlinks : " . var_export(self::$_symlinks, 1) . "\n"; + } + self::$debugText .= "\n"; + + $css = self::_trimUrls($css); + + // rewrite + $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/' + ,array(self::$className, '_processUriCB'), $css); + $css = preg_replace_callback('/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/' + ,array(self::$className, '_processUriCB'), $css); + + return $css; + } + + /** + * In CSS content, prepend a path to relative URIs + * + * @param string $css + * + * @param string $path The path to prepend. + * + * @return string + */ + public static function prepend($css, $path) + { + self::$_prependPath = $path; + + $css = self::_trimUrls($css); + + // append + $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/' + ,array(self::$className, '_processUriCB'), $css); + $css = preg_replace_callback('/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/' + ,array(self::$className, '_processUriCB'), $css); + + self::$_prependPath = null; + return $css; + } + + /** + * Get a root relative URI from a file relative URI + * + * + * Minify_CSS_UriRewriter::rewriteRelative( + * '../img/hello.gif' + * , '/home/user/www/css' // path of CSS file + * , '/home/user/www' // doc root + * ); + * // returns '/img/hello.gif' + * + * // example where static files are stored in a symlinked directory + * Minify_CSS_UriRewriter::rewriteRelative( + * 'hello.gif' + * , '/var/staticFiles/theme' + * , '/home/user/www' + * , array('/home/user/www/static' => '/var/staticFiles') + * ); + * // returns '/static/theme/hello.gif' + * + * + * @param string $uri file relative URI + * + * @param string $realCurrentDir realpath of the current file's directory. + * + * @param string $realDocRoot realpath of the site document root. + * + * @param array $symlinks (default = array()) If the file is stored in + * a symlink-ed directory, provide an array of link paths to + * real target paths, where the link paths "appear" to be within the document + * root. E.g.: + * + * array('/home/foo/www/not/real/path' => '/real/target/path') // unix + * array('C:\\htdocs\\not\\real' => 'D:\\real\\target\\path') // Windows + * + * + * @return string + */ + public static function rewriteRelative($uri, $realCurrentDir, $realDocRoot, $symlinks = array()) + { + // prepend path with current dir separator (OS-independent) + $path = strtr($realCurrentDir, '/', DIRECTORY_SEPARATOR) + . DIRECTORY_SEPARATOR . strtr($uri, '/', DIRECTORY_SEPARATOR); + + self::$debugText .= "file-relative URI : {$uri}\n" + . "path prepended : {$path}\n"; + + // "unresolve" a symlink back to doc root + foreach ($symlinks as $link => $target) { + if (0 === strpos($path, $target)) { + // replace $target with $link + $path = $link . substr($path, strlen($target)); + + self::$debugText .= "symlink unresolved : {$path}\n"; + + break; + } + } + // strip doc root + $path = substr($path, strlen($realDocRoot)); + + self::$debugText .= "docroot stripped : {$path}\n"; + + // fix to root-relative URI + $uri = strtr($path, '/\\', '//'); + $uri = self::removeDots($uri); + + self::$debugText .= "traversals removed : {$uri}\n\n"; + + return $uri; + } + + /** + * Remove instances of "./" and "../" where possible from a root-relative URI + * + * @param string $uri + * + * @return string + */ + public static function removeDots($uri) + { + $uri = str_replace('/./', '/', $uri); + // inspired by patch from Oleg Cherniy + do { + $uri = preg_replace('@/[^/]+/\\.\\./@', '/', $uri, 1, $changed); + } while ($changed); + return $uri; + } + + /** + * Defines which class to call as part of callbacks, change this + * if you extend Minify_CSS_UriRewriter + * + * @var string + */ + protected static $className = 'Minify_CSS_UriRewriter'; + + /** + * Get realpath with any trailing slash removed. If realpath() fails, + * just remove the trailing slash. + * + * @param string $path + * + * @return mixed path with no trailing slash + */ + protected static function _realpath($path) + { + $realPath = realpath($path); + if ($realPath !== false) { + $path = $realPath; + } + return rtrim($path, '/\\'); + } + + /** + * Directory of this stylesheet + * + * @var string + */ + private static $_currentDir = ''; + + /** + * DOC_ROOT + * + * @var string + */ + private static $_docRoot = ''; + + /** + * directory replacements to map symlink targets back to their + * source (within the document root) E.g. '/var/www/symlink' => '/var/realpath' + * + * @var array + */ + private static $_symlinks = array(); + + /** + * Path to prepend + * + * @var string + */ + private static $_prependPath = null; + + /** + * @param string $css + * + * @return string + */ + private static function _trimUrls($css) + { + return preg_replace('/ + url\\( # url( + \\s* + ([^\\)]+?) # 1 = URI (assuming does not contain ")") + \\s* + \\) # ) + /x', 'url($1)', $css); + } + + /** + * @param array $m + * + * @return string + */ + private static function _processUriCB($m) + { + // $m matched either '/@import\\s+([\'"])(.*?)[\'"]/' or '/url\\(\\s*([^\\)\\s]+)\\s*\\)/' + $isImport = ($m[0][0] === '@'); + // determine URI and the quote character (if any) + if ($isImport) { + $quoteChar = $m[1]; + $uri = $m[2]; + } else { + // $m[1] is either quoted or not + $quoteChar = ($m[1][0] === "'" || $m[1][0] === '"') + ? $m[1][0] + : ''; + $uri = ($quoteChar === '') + ? $m[1] + : substr($m[1], 1, strlen($m[1]) - 2); + } + // if not root/scheme relative and not starts with scheme + if (!preg_match('~^(/|[a-z]+\:)~', $uri)) { + // URI is file-relative: rewrite depending on options + if (self::$_prependPath === null) { + $uri = self::rewriteRelative($uri, self::$_currentDir, self::$_docRoot, self::$_symlinks); + } else { + $uri = self::$_prependPath . $uri; + if ($uri[0] === '/') { + $root = ''; + $rootRelative = $uri; + $uri = $root . self::removeDots($rootRelative); + } elseif (preg_match('@^((https?\:)?//([^/]+))/@', $uri, $m) && (false !== strpos($m[3], '.'))) { + $root = $m[1]; + $rootRelative = substr($uri, strlen($root)); + $uri = $root . self::removeDots($rootRelative); + } + } + } + return $isImport + ? "@import {$quoteChar}{$uri}{$quoteChar}" + : "url({$quoteChar}{$uri}{$quoteChar})"; + } +} diff --git a/mrclay/minify/min/lib/Minify/CSSmin.php b/mrclay/minify/min/lib/Minify/CSSmin.php new file mode 100644 index 000000000000..4b841162a710 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/CSSmin.php @@ -0,0 +1,85 @@ + + */ +class Minify_CSSmin { + + /** + * Minify a CSS string + * + * @param string $css + * + * @param array $options available options: + * + * 'removeCharsets': (default true) remove all @charset at-rules + * + * 'prependRelativePath': (default null) if given, this string will be + * prepended to all relative URIs in import/url declarations + * + * 'currentDir': (default null) if given, this is assumed to be the + * directory of the current CSS file. Using this, minify will rewrite + * all relative URIs in import/url declarations to correctly point to + * the desired files. For this to work, the files *must* exist and be + * visible by the PHP process. + * + * 'symlinks': (default = array()) If the CSS file is stored in + * a symlink-ed directory, provide an array of link paths to + * target paths, where the link paths are within the document root. Because + * paths need to be normalized for this to work, use "//" to substitute + * the doc root in the link paths (the array keys). E.g.: + * + * array('//symlink' => '/real/target/path') // unix + * array('//static' => 'D:\\staticStorage') // Windows + * + * + * 'docRoot': (default = $_SERVER['DOCUMENT_ROOT']) + * see Minify_CSS_UriRewriter::rewrite + * + * @return string + */ + public static function minify($css, $options = array()) + { + $options = array_merge(array( + 'compress' => true, + 'removeCharsets' => true, + 'currentDir' => null, + 'docRoot' => $_SERVER['DOCUMENT_ROOT'], + 'prependRelativePath' => null, + 'symlinks' => array(), + ), $options); + + if ($options['removeCharsets']) { + $css = preg_replace('/@charset[^;]+;\\s*/', '', $css); + } + if ($options['compress']) { + $obj = new CSSmin(); + $css = $obj->run($css); + } + if (! $options['currentDir'] && ! $options['prependRelativePath']) { + return $css; + } + if ($options['currentDir']) { + return Minify_CSS_UriRewriter::rewrite( + $css + ,$options['currentDir'] + ,$options['docRoot'] + ,$options['symlinks'] + ); + } else { + return Minify_CSS_UriRewriter::prepend( + $css + ,$options['prependRelativePath'] + ); + } + } +} diff --git a/mrclay/minify/min/lib/Minify/Cache/APC.php b/mrclay/minify/min/lib/Minify/Cache/APC.php new file mode 100644 index 000000000000..24ab04620526 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Cache/APC.php @@ -0,0 +1,133 @@ + + * Minify::setCache(new Minify_Cache_APC()); + * + * + * @package Minify + * @author Chris Edwards + **/ +class Minify_Cache_APC { + + /** + * Create a Minify_Cache_APC object, to be passed to + * Minify::setCache(). + * + * + * @param int $expire seconds until expiration (default = 0 + * meaning the item will not get an expiration date) + * + * @return null + */ + public function __construct($expire = 0) + { + $this->_exp = $expire; + } + + /** + * Write data to cache. + * + * @param string $id cache id + * + * @param string $data + * + * @return bool success + */ + public function store($id, $data) + { + return apc_store($id, "{$_SERVER['REQUEST_TIME']}|{$data}", $this->_exp); + } + + /** + * Get the size of a cache entry + * + * @param string $id cache id + * + * @return int size in bytes + */ + public function getSize($id) + { + if (! $this->_fetch($id)) { + return false; + } + return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) + ? mb_strlen($this->_data, '8bit') + : strlen($this->_data); + } + + /** + * Does a valid cache entry exist? + * + * @param string $id cache id + * + * @param int $srcMtime mtime of the original source file(s) + * + * @return bool exists + */ + public function isValid($id, $srcMtime) + { + return ($this->_fetch($id) && ($this->_lm >= $srcMtime)); + } + + /** + * Send the cached content to output + * + * @param string $id cache id + */ + public function display($id) + { + echo $this->_fetch($id) + ? $this->_data + : ''; + } + + /** + * Fetch the cached content + * + * @param string $id cache id + * + * @return string + */ + public function fetch($id) + { + return $this->_fetch($id) + ? $this->_data + : ''; + } + + private $_exp = null; + + // cache of most recently fetched id + private $_lm = null; + private $_data = null; + private $_id = null; + + /** + * Fetch data and timestamp from apc, store in instance + * + * @param string $id + * + * @return bool success + */ + private function _fetch($id) + { + if ($this->_id === $id) { + return true; + } + $ret = apc_fetch($id); + if (false === $ret) { + $this->_id = null; + return false; + } + list($this->_lm, $this->_data) = explode('|', $ret, 2); + $this->_id = $id; + return true; + } +} diff --git a/mrclay/minify/min/lib/Minify/Cache/File.php b/mrclay/minify/min/lib/Minify/Cache/File.php new file mode 100644 index 000000000000..c228eb2b2fda --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Cache/File.php @@ -0,0 +1,197 @@ +_locking = $fileLocking; + $this->_path = $path; + } + + /** + * Write data to cache. + * + * @param string $id cache id (e.g. a filename) + * + * @param string $data + * + * @return bool success + */ + public function store($id, $data) + { + $flag = $this->_locking + ? LOCK_EX + : null; + $file = $this->_path . '/' . $id; + if (! @file_put_contents($file, $data, $flag)) { + $this->_log("Minify_Cache_File: Write failed to '$file'"); + } + // write control + if ($data !== $this->fetch($id)) { + @unlink($file); + $this->_log("Minify_Cache_File: Post-write read failed for '$file'"); + return false; + } + return true; + } + + /** + * Get the size of a cache entry + * + * @param string $id cache id (e.g. a filename) + * + * @return int size in bytes + */ + public function getSize($id) + { + return filesize($this->_path . '/' . $id); + } + + /** + * Does a valid cache entry exist? + * + * @param string $id cache id (e.g. a filename) + * + * @param int $srcMtime mtime of the original source file(s) + * + * @return bool exists + */ + public function isValid($id, $srcMtime) + { + $file = $this->_path . '/' . $id; + return (is_file($file) && (filemtime($file) >= $srcMtime)); + } + + /** + * Send the cached content to output + * + * @param string $id cache id (e.g. a filename) + */ + public function display($id) + { + if ($this->_locking) { + $fp = fopen($this->_path . '/' . $id, 'rb'); + flock($fp, LOCK_SH); + fpassthru($fp); + flock($fp, LOCK_UN); + fclose($fp); + } else { + readfile($this->_path . '/' . $id); + } + } + + /** + * Fetch the cached content + * + * @param string $id cache id (e.g. a filename) + * + * @return string + */ + public function fetch($id) + { + if ($this->_locking) { + $fp = fopen($this->_path . '/' . $id, 'rb'); + if (!$fp) { + return false; + } + flock($fp, LOCK_SH); + $ret = stream_get_contents($fp); + flock($fp, LOCK_UN); + fclose($fp); + return $ret; + } else { + return file_get_contents($this->_path . '/' . $id); + } + } + + /** + * Fetch the cache path used + * + * @return string + */ + public function getPath() + { + return $this->_path; + } + + /** + * Get a usable temp directory + * + * Adapted from Solar/Dir.php + * @author Paul M. Jones + * @license http://opensource.org/licenses/bsd-license.php BSD + * @link http://solarphp.com/trac/core/browser/trunk/Solar/Dir.php + * + * @return string + */ + public static function tmp() + { + static $tmp = null; + if (! $tmp) { + $tmp = function_exists('sys_get_temp_dir') + ? sys_get_temp_dir() + : self::_tmp(); + $tmp = rtrim($tmp, DIRECTORY_SEPARATOR); + } + return $tmp; + } + + /** + * Returns the OS-specific directory for temporary files + * + * @author Paul M. Jones + * @license http://opensource.org/licenses/bsd-license.php BSD + * @link http://solarphp.com/trac/core/browser/trunk/Solar/Dir.php + * + * @return string + */ + protected static function _tmp() + { + // non-Windows system? + if (strtolower(substr(PHP_OS, 0, 3)) != 'win') { + $tmp = empty($_ENV['TMPDIR']) ? getenv('TMPDIR') : $_ENV['TMPDIR']; + if ($tmp) { + return $tmp; + } else { + return '/tmp'; + } + } + // Windows 'TEMP' + $tmp = empty($_ENV['TEMP']) ? getenv('TEMP') : $_ENV['TEMP']; + if ($tmp) { + return $tmp; + } + // Windows 'TMP' + $tmp = empty($_ENV['TMP']) ? getenv('TMP') : $_ENV['TMP']; + if ($tmp) { + return $tmp; + } + // Windows 'windir' + $tmp = empty($_ENV['windir']) ? getenv('windir') : $_ENV['windir']; + if ($tmp) { + return $tmp; + } + // final fallback for Windows + return getenv('SystemRoot') . '\\temp'; + } + + /** + * Send message to the Minify logger + * @param string $msg + * @return null + */ + protected function _log($msg) + { + Minify_Logger::log($msg); + } + + private $_path = null; + private $_locking = null; +} diff --git a/mrclay/minify/min/lib/Minify/Cache/Memcache.php b/mrclay/minify/min/lib/Minify/Cache/Memcache.php new file mode 100644 index 000000000000..72bf454b93a2 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Cache/Memcache.php @@ -0,0 +1,140 @@ + + * // fall back to disk caching if memcache can't connect + * $memcache = new Memcache; + * if ($memcache->connect('localhost', 11211)) { + * Minify::setCache(new Minify_Cache_Memcache($memcache)); + * } else { + * Minify::setCache(); + * } + * + **/ +class Minify_Cache_Memcache { + + /** + * Create a Minify_Cache_Memcache object, to be passed to + * Minify::setCache(). + * + * @param Memcache $memcache already-connected instance + * + * @param int $expire seconds until expiration (default = 0 + * meaning the item will not get an expiration date) + * + * @return null + */ + public function __construct($memcache, $expire = 0) + { + $this->_mc = $memcache; + $this->_exp = $expire; + } + + /** + * Write data to cache. + * + * @param string $id cache id + * + * @param string $data + * + * @return bool success + */ + public function store($id, $data) + { + return $this->_mc->set($id, "{$_SERVER['REQUEST_TIME']}|{$data}", 0, $this->_exp); + } + + + /** + * Get the size of a cache entry + * + * @param string $id cache id + * + * @return int size in bytes + */ + public function getSize($id) + { + if (! $this->_fetch($id)) { + return false; + } + return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) + ? mb_strlen($this->_data, '8bit') + : strlen($this->_data); + } + + /** + * Does a valid cache entry exist? + * + * @param string $id cache id + * + * @param int $srcMtime mtime of the original source file(s) + * + * @return bool exists + */ + public function isValid($id, $srcMtime) + { + return ($this->_fetch($id) && ($this->_lm >= $srcMtime)); + } + + /** + * Send the cached content to output + * + * @param string $id cache id + */ + public function display($id) + { + echo $this->_fetch($id) + ? $this->_data + : ''; + } + + /** + * Fetch the cached content + * + * @param string $id cache id + * + * @return string + */ + public function fetch($id) + { + return $this->_fetch($id) + ? $this->_data + : ''; + } + + private $_mc = null; + private $_exp = null; + + // cache of most recently fetched id + private $_lm = null; + private $_data = null; + private $_id = null; + + /** + * Fetch data and timestamp from memcache, store in instance + * + * @param string $id + * + * @return bool success + */ + private function _fetch($id) + { + if ($this->_id === $id) { + return true; + } + $ret = $this->_mc->get($id); + if (false === $ret) { + $this->_id = null; + return false; + } + list($this->_lm, $this->_data) = explode('|', $ret, 2); + $this->_id = $id; + return true; + } +} diff --git a/mrclay/minify/min/lib/Minify/Cache/WinCache.php b/mrclay/minify/min/lib/Minify/Cache/WinCache.php new file mode 100644 index 000000000000..500bdd822b8b --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Cache/WinCache.php @@ -0,0 +1,130 @@ + + * Minify::setCache(new Minify_Cache_WinCache()); + * + * + * @package Minify + * @author Matthias Fax + **/ +class Minify_Cache_WinCache +{ + + /** + * Create a Minify_Cache_Wincache object, to be passed to + * Minify::setCache(). + * + * + * @param int $expire seconds until expiration (default = 0 + * meaning the item will not get an expiration date) + */ + public function __construct($expire = 0) + { + if (!function_exists('wincache_ucache_info')) { + throw new Exception("WinCache for PHP is not installed to be able to use Minify_Cache_WinCache!"); + } + $this->_exp = $expire; + } + + /** + * Write data to cache. + * + * @param string $id cache id + * + * @param string $data + * + * @return bool success + */ + public function store($id, $data) + { + return wincache_ucache_set($id, "{$_SERVER['REQUEST_TIME']}|{$data}", $this->_exp); + } + + /** + * Get the size of a cache entry + * + * @param string $id cache id + * + * @return int size in bytes + */ + public function getSize($id) + { + if (!$this->_fetch($id)) { + return false; + } + return (function_exists('mb_strlen') && ((int) ini_get('mbstring.func_overload') & 2)) ? mb_strlen($this->_data, '8bit') : strlen($this->_data); + } + + /** + * Does a valid cache entry exist? + * + * @param string $id cache id + * + * @param int $srcMtime mtime of the original source file(s) + * + * @return bool exists + */ + public function isValid($id, $srcMtime) + { + return ($this->_fetch($id) && ($this->_lm >= $srcMtime)); + } + + /** + * Send the cached content to output + * + * @param string $id cache id + */ + public function display($id) + { + echo $this->_fetch($id) ? $this->_data : ''; + } + + /** + * Fetch the cached content + * + * @param string $id cache id + * + * @return string + */ + public function fetch($id) + { + return $this->_fetch($id) ? $this->_data : ''; + } + + private $_exp = NULL; + + // cache of most recently fetched id + private $_lm = NULL; + private $_data = NULL; + private $_id = NULL; + + /** + * Fetch data and timestamp from WinCache, store in instance + * + * @param string $id + * + * @return bool success + */ + private function _fetch($id) + { + if ($this->_id === $id) { + return true; + } + $suc = false; + $ret = wincache_ucache_get($id, $suc); + if (!$suc) { + $this->_id = NULL; + return false; + } + list($this->_lm, $this->_data) = explode('|', $ret, 2); + $this->_id = $id; + return true; + } +} \ No newline at end of file diff --git a/mrclay/minify/min/lib/Minify/Cache/XCache.php b/mrclay/minify/min/lib/Minify/Cache/XCache.php new file mode 100644 index 000000000000..3039deddcb75 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Cache/XCache.php @@ -0,0 +1,126 @@ + + * Minify::setCache(new Minify_Cache_XCache()); + * + * + * @package Minify + * @author Elan Ruusamäe + **/ +class Minify_Cache_XCache { + + /** + * Create a Minify_Cache_XCache object, to be passed to + * Minify::setCache(). + * + * @param int $expire seconds until expiration (default = 0 + * meaning the item will not get an expiration date) + */ + public function __construct($expire = 0) + { + $this->_exp = $expire; + } + + /** + * Write data to cache. + * + * @param string $id cache id + * @param string $data + * @return bool success + */ + public function store($id, $data) + { + return xcache_set($id, "{$_SERVER['REQUEST_TIME']}|{$data}", $this->_exp); + } + + /** + * Get the size of a cache entry + * + * @param string $id cache id + * @return int size in bytes + */ + public function getSize($id) + { + if (! $this->_fetch($id)) { + return false; + } + return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) + ? mb_strlen($this->_data, '8bit') + : strlen($this->_data); + } + + /** + * Does a valid cache entry exist? + * + * @param string $id cache id + * @param int $srcMtime mtime of the original source file(s) + * @return bool exists + */ + public function isValid($id, $srcMtime) + { + return ($this->_fetch($id) && ($this->_lm >= $srcMtime)); + } + + /** + * Send the cached content to output + * + * @param string $id cache id + */ + public function display($id) + { + echo $this->_fetch($id) + ? $this->_data + : ''; + } + + /** + * Fetch the cached content + * + * @param string $id cache id + * @return string + */ + public function fetch($id) + { + return $this->_fetch($id) + ? $this->_data + : ''; + } + + private $_exp = null; + + // cache of most recently fetched id + private $_lm = null; + private $_data = null; + private $_id = null; + + /** + * Fetch data and timestamp from xcache, store in instance + * + * @param string $id + * @return bool success + */ + private function _fetch($id) + { + if ($this->_id === $id) { + return true; + } + $ret = xcache_get($id); + if (false === $ret) { + $this->_id = null; + return false; + } + list($this->_lm, $this->_data) = explode('|', $ret, 2); + $this->_id = $id; + return true; + } +} diff --git a/mrclay/minify/min/lib/Minify/Cache/ZendPlatform.php b/mrclay/minify/min/lib/Minify/Cache/ZendPlatform.php new file mode 100644 index 000000000000..3130d69a7b5f --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Cache/ZendPlatform.php @@ -0,0 +1,142 @@ + + * Minify::setCache(new Minify_Cache_ZendPlatform()); + * + * + * @package Minify + * @author Patrick van Dissel + */ +class Minify_Cache_ZendPlatform { + + + /** + * Create a Minify_Cache_ZendPlatform object, to be passed to + * Minify::setCache(). + * + * @param int $expire seconds until expiration (default = 0 + * meaning the item will not get an expiration date) + * + * @return null + */ + public function __construct($expire = 0) + { + $this->_exp = $expire; + } + + + /** + * Write data to cache. + * + * @param string $id cache id + * + * @param string $data + * + * @return bool success + */ + public function store($id, $data) + { + return output_cache_put($id, "{$_SERVER['REQUEST_TIME']}|{$data}"); + } + + + /** + * Get the size of a cache entry + * + * @param string $id cache id + * + * @return int size in bytes + */ + public function getSize($id) + { + return $this->_fetch($id) + ? strlen($this->_data) + : false; + } + + + /** + * Does a valid cache entry exist? + * + * @param string $id cache id + * + * @param int $srcMtime mtime of the original source file(s) + * + * @return bool exists + */ + public function isValid($id, $srcMtime) + { + $ret = ($this->_fetch($id) && ($this->_lm >= $srcMtime)); + return $ret; + } + + + /** + * Send the cached content to output + * + * @param string $id cache id + */ + public function display($id) + { + echo $this->_fetch($id) + ? $this->_data + : ''; + } + + + /** + * Fetch the cached content + * + * @param string $id cache id + * + * @return string + */ + public function fetch($id) + { + return $this->_fetch($id) + ? $this->_data + : ''; + } + + + private $_exp = null; + + + // cache of most recently fetched id + private $_lm = null; + private $_data = null; + private $_id = null; + + + /** + * Fetch data and timestamp from ZendPlatform, store in instance + * + * @param string $id + * + * @return bool success + */ + private function _fetch($id) + { + if ($this->_id === $id) { + return true; + } + $ret = output_cache_get($id, $this->_exp); + if (false === $ret) { + $this->_id = null; + return false; + } + list($this->_lm, $this->_data) = explode('|', $ret, 2); + $this->_id = $id; + return true; + } +} diff --git a/mrclay/minify/min/lib/Minify/ClosureCompiler.php b/mrclay/minify/min/lib/Minify/ClosureCompiler.php new file mode 100644 index 000000000000..53983a52aa2a --- /dev/null +++ b/mrclay/minify/min/lib/Minify/ClosureCompiler.php @@ -0,0 +1,139 @@ + + * Minify_ClosureCompiler::$jarFile = '/path/to/closure-compiler-20120123.jar'; + * Minify_ClosureCompiler::$tempDir = '/tmp'; + * $code = Minify_ClosureCompiler::minify( + * $code, + * array('compilation_level' => 'SIMPLE_OPTIMIZATIONS') + * ); + * + * --compilation_level WHITESPACE_ONLY, SIMPLE_OPTIMIZATIONS, ADVANCED_OPTIMIZATIONS + * + * + * + * @todo unit tests, $options docs + * @todo more options support (or should just passthru them all?) + * + * @package Minify + * @author Stephen Clay + * @author Elan Ruusamäe + */ +class Minify_ClosureCompiler { + + const OPTION_CHARSET = 'charset'; + const OPTION_COMPILATION_LEVEL = 'compilation_level'; + + public static $isDebug = false; + + /** + * Filepath of the Closure Compiler jar file. This must be set before + * calling minifyJs(). + * + * @var string + */ + public static $jarFile = null; + + /** + * Writable temp directory. This must be set before calling minifyJs(). + * + * @var string + */ + public static $tempDir = null; + + /** + * Filepath of "java" executable (may be needed if not in shell's PATH) + * + * @var string + */ + public static $javaExecutable = 'java'; + + /** + * Minify a Javascript string + * + * @param string $js + * + * @param array $options (verbose is ignored) + * + * @see https://code.google.com/p/closure-compiler/source/browse/trunk/README + * + * @return string + * + * @throws Minify_ClosureCompiler_Exception + */ + public static function minify($js, $options = array()) + { + self::_prepare(); + if (! ($tmpFile = tempnam(self::$tempDir, 'cc_'))) { + throw new Minify_ClosureCompiler_Exception('Minify_ClosureCompiler : could not create temp file in "'.self::$tempDir.'".'); + } + file_put_contents($tmpFile, $js); + $cmd = self::_getCmd($options, $tmpFile); + exec($cmd, $output, $result_code); + unlink($tmpFile); + if ($result_code != 0) { + $message = 'Minify_ClosureCompiler : Closure Compiler execution failed.'; + if (self::$isDebug) { + exec($cmd . ' 2>&1', $error); + if ($error) { + $message .= "\nReason:\n" . join("\n", $error); + } + } + throw new Minify_ClosureCompiler_Exception($message); + } + return implode("\n", $output); + } + + private static function _getCmd($userOptions, $tmpFile) + { + $o = array_merge( + array( + self::OPTION_CHARSET => 'utf-8', + self::OPTION_COMPILATION_LEVEL => 'SIMPLE_OPTIMIZATIONS', + ), + $userOptions + ); + $charsetOption = $o[self::OPTION_CHARSET]; + $cmd = self::$javaExecutable . ' -jar ' . escapeshellarg(self::$jarFile) + . (preg_match('/^[\\da-zA-Z0-9\\-]+$/', $charsetOption) + ? " --charset {$charsetOption}" + : ''); + + foreach (array(self::OPTION_COMPILATION_LEVEL) as $opt) { + if ($o[$opt]) { + $cmd .= " --{$opt} ". escapeshellarg($o[$opt]); + } + } + return $cmd . ' ' . escapeshellarg($tmpFile); + } + + private static function _prepare() + { + if (! is_file(self::$jarFile)) { + throw new Minify_ClosureCompiler_Exception('Minify_ClosureCompiler : $jarFile('.self::$jarFile.') is not a valid file.'); + } + if (! is_readable(self::$jarFile)) { + throw new Minify_ClosureCompiler_Exception('Minify_ClosureCompiler : $jarFile('.self::$jarFile.') is not readable.'); + } + if (! is_dir(self::$tempDir)) { + throw new Minify_ClosureCompiler_Exception('Minify_ClosureCompiler : $tempDir('.self::$tempDir.') is not a valid direcotry.'); + } + if (! is_writable(self::$tempDir)) { + throw new Minify_ClosureCompiler_Exception('Minify_ClosureCompiler : $tempDir('.self::$tempDir.') is not writable.'); + } + } +} + +class Minify_ClosureCompiler_Exception extends Exception {} diff --git a/mrclay/minify/min/lib/Minify/CommentPreserver.php b/mrclay/minify/min/lib/Minify/CommentPreserver.php new file mode 100644 index 000000000000..7a359bf9bb54 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/CommentPreserver.php @@ -0,0 +1,89 @@ + + */ +class Minify_CommentPreserver { + + /** + * String to be prepended to each preserved comment + * + * @var string + */ + public static $prepend = "\n"; + + /** + * String to be appended to each preserved comment + * + * @var string + */ + public static $append = "\n"; + + /** + * Process a string outside of C-style comments that begin with "/*!" + * + * On each non-empty string outside these comments, the given processor + * function will be called. The comments will be surrounded by + * Minify_CommentPreserver::$preprend and Minify_CommentPreserver::$append. + * + * @param string $content + * @param callback $processor function + * @param array $args array of extra arguments to pass to the processor + * function (default = array()) + * @return string + */ + public static function process($content, $processor, $args = array()) + { + $ret = ''; + while (true) { + list($beforeComment, $comment, $afterComment) = self::_nextComment($content); + if ('' !== $beforeComment) { + $callArgs = $args; + array_unshift($callArgs, $beforeComment); + $ret .= call_user_func_array($processor, $callArgs); + } + if (false === $comment) { + break; + } + $ret .= $comment; + $content = $afterComment; + } + return $ret; + } + + /** + * Extract comments that YUI Compressor preserves. + * + * @param string $in input + * + * @return array 3 elements are returned. If a YUI comment is found, the + * 2nd element is the comment and the 1st and 3rd are the surrounding + * strings. If no comment is found, the entire string is returned as the + * 1st element and the other two are false. + */ + private static function _nextComment($in) + { + if ( + false === ($start = strpos($in, '/*!')) + || false === ($end = strpos($in, '*/', $start + 3)) + ) { + return array($in, false, false); + } + $ret = array( + substr($in, 0, $start) + ,self::$prepend . '/*!' . substr($in, $start + 3, $end - $start - 1) . self::$append + ); + $endChars = (strlen($in) - $end - 2); + $ret[] = (0 === $endChars) + ? '' + : substr($in, -$endChars); + return $ret; + } +} diff --git a/mrclay/minify/min/lib/Minify/Controller/Base.php b/mrclay/minify/min/lib/Minify/Controller/Base.php new file mode 100644 index 000000000000..5a86329033e7 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Controller/Base.php @@ -0,0 +1,222 @@ + + */ +abstract class Minify_Controller_Base { + + /** + * Setup controller sources and set an needed options for Minify::source + * + * You must override this method in your subclass controller to set + * $this->sources. If the request is NOT valid, make sure $this->sources + * is left an empty array. Then strip any controller-specific options from + * $options and return it. To serve files, $this->sources must be an array of + * Minify_Source objects. + * + * @param array $options controller and Minify options + * + * @return array $options Minify::serve options + */ + abstract public function setupSources($options); + + /** + * Get default Minify options for this controller. + * + * Override in subclass to change defaults + * + * @return array options for Minify + */ + public function getDefaultMinifyOptions() { + return array( + 'isPublic' => true + ,'encodeOutput' => function_exists('gzdeflate') + ,'encodeMethod' => null // determine later + ,'encodeLevel' => 9 + ,'minifierOptions' => array() // no minifier options + ,'contentTypeCharset' => 'utf-8' + ,'maxAge' => 1800 // 30 minutes + ,'rewriteCssUris' => true + ,'bubbleCssImports' => false + ,'quiet' => false // serve() will send headers and output + ,'debug' => false + + // if you override these, the response codes MUST be directly after + // the first space. + ,'badRequestHeader' => 'HTTP/1.0 400 Bad Request' + ,'errorHeader' => 'HTTP/1.0 500 Internal Server Error' + + // callback function to see/modify content of all sources + ,'postprocessor' => null + // file to require to load preprocessor + ,'postprocessorRequire' => null + ); + } + + /** + * Get default minifiers for this controller. + * + * Override in subclass to change defaults + * + * @return array minifier callbacks for common types + */ + public function getDefaultMinifers() { + $ret[Minify::TYPE_JS] = array('JSMin', 'minify'); + $ret[Minify::TYPE_CSS] = array('Minify_CSS', 'minify'); + $ret[Minify::TYPE_HTML] = array('Minify_HTML', 'minify'); + return $ret; + } + + /** + * Is a user-given file within an allowable directory, existing, + * and having an extension js/css/html/txt ? + * + * This is a convenience function for controllers that have to accept + * user-given paths + * + * @param string $file full file path (already processed by realpath()) + * + * @param array $safeDirs directories where files are safe to serve. Files can also + * be in subdirectories of these directories. + * + * @return bool file is safe + * + * @deprecated use checkAllowDirs, checkNotHidden instead + */ + public static function _fileIsSafe($file, $safeDirs) + { + $pathOk = false; + foreach ((array)$safeDirs as $safeDir) { + if (strpos($file, $safeDir) === 0) { + $pathOk = true; + break; + } + } + $base = basename($file); + if (! $pathOk || ! is_file($file) || $base[0] === '.') { + return false; + } + list($revExt) = explode('.', strrev($base)); + return in_array(strrev($revExt), array('js', 'css', 'html', 'txt')); + } + + /** + * @param string $file + * @param array $allowDirs + * @param string $uri + * @return bool + * @throws Exception + */ + public static function checkAllowDirs($file, $allowDirs, $uri) + { + foreach ((array)$allowDirs as $allowDir) { + if (strpos($file, $allowDir) === 0) { + return true; + } + } + throw new Exception("File '$file' is outside \$allowDirs. If the path is" + . " resolved via an alias/symlink, look into the \$min_symlinks option." + . " E.g. \$min_symlinks['/" . dirname($uri) . "'] = '" . dirname($file) . "';"); + } + + /** + * @param string $file + * @throws Exception + */ + public static function checkNotHidden($file) + { + $b = basename($file); + if (0 === strpos($b, '.')) { + throw new Exception("Filename '$b' starts with period (may be hidden)"); + } + } + + /** + * instances of Minify_Source, which provide content and any individual minification needs. + * + * @var array + * + * @see Minify_Source + */ + public $sources = array(); + + /** + * Short name to place inside cache id + * + * The setupSources() method may choose to set this, making it easier to + * recognize a particular set of sources/settings in the cache folder. It + * will be filtered and truncated to make the final cache id <= 250 bytes. + * + * @var string + */ + public $selectionId = ''; + + /** + * Mix in default controller options with user-given options + * + * @param array $options user options + * + * @return array mixed options + */ + public final function mixInDefaultOptions($options) + { + $ret = array_merge( + $this->getDefaultMinifyOptions(), $options + ); + if (! isset($options['minifiers'])) { + $options['minifiers'] = array(); + } + $ret['minifiers'] = array_merge( + $this->getDefaultMinifers(), $options['minifiers'] + ); + return $ret; + } + + /** + * Analyze sources (if there are any) and set $options 'contentType' + * and 'lastModifiedTime' if they already aren't. + * + * @param array $options options for Minify + * + * @return array options for Minify + */ + public final function analyzeSources($options = array()) + { + if ($this->sources) { + if (! isset($options['contentType'])) { + $options['contentType'] = Minify_Source::getContentType($this->sources); + } + // last modified is needed for caching, even if setExpires is set + if (! isset($options['lastModifiedTime'])) { + $max = 0; + foreach ($this->sources as $source) { + $max = max($source->lastModified, $max); + } + $options['lastModifiedTime'] = $max; + } + } + return $options; + } + + /** + * Send message to the Minify logger + * + * @param string $msg + * + * @return null + */ + public function log($msg) { + Minify_Logger::log($msg); + } +} diff --git a/mrclay/minify/min/lib/Minify/Controller/Files.php b/mrclay/minify/min/lib/Minify/Controller/Files.php new file mode 100644 index 000000000000..f084cd07eb67 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Controller/Files.php @@ -0,0 +1,76 @@ + + * Minify::serve('Files', array( + * 'files' => array( + * '//js/jquery.js' + * ,'//js/plugins.js' + * ,'/home/username/file.js' + * ) + * )); + * + * + * As a shortcut, the controller will replace "//" at the beginning + * of a filename with $_SERVER['DOCUMENT_ROOT'] . '/'. + * + * @package Minify + * @author Stephen Clay + */ +class Minify_Controller_Files extends Minify_Controller_Base { + + /** + * Set up file sources + * + * @param array $options controller and Minify options + * @return array Minify options + * + * Controller options: + * + * 'files': (required) array of complete file paths, or a single path + */ + public function setupSources($options) { + // strip controller options + + $files = $options['files']; + // if $files is a single object, casting will break it + if (is_object($files)) { + $files = array($files); + } elseif (! is_array($files)) { + $files = (array)$files; + } + unset($options['files']); + + $sources = array(); + foreach ($files as $file) { + if ($file instanceof Minify_Source) { + $sources[] = $file; + continue; + } + if (0 === strpos($file, '//')) { + $file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1); + } + $realPath = realpath($file); + if (is_file($realPath)) { + $sources[] = new Minify_Source(array( + 'filepath' => $realPath + )); + } else { + $this->log("The path \"{$file}\" could not be found (or was not a file)"); + return $options; + } + } + if ($sources) { + $this->sources = $sources; + } + return $options; + } +} + diff --git a/mrclay/minify/min/lib/Minify/Controller/Groups.php b/mrclay/minify/min/lib/Minify/Controller/Groups.php new file mode 100644 index 000000000000..c4c25db120b6 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Controller/Groups.php @@ -0,0 +1,91 @@ + + * Minify::serve('Groups', array( + * 'groups' => array( + * 'css' => array('//css/type.css', '//css/layout.css') + * ,'js' => array('//js/jquery.js', '//js/site.js') + * ) + * )); + * + * + * If the above code were placed in /serve.php, it would enable the URLs + * /serve.php/js and /serve.php/css + * + * As a shortcut, the controller will replace "//" at the beginning + * of a filename with $_SERVER['DOCUMENT_ROOT'] . '/'. + * + * @package Minify + * @author Stephen Clay + */ +class Minify_Controller_Groups extends Minify_Controller_Base { + + /** + * Set up groups of files as sources + * + * @param array $options controller and Minify options + * + * 'groups': (required) array mapping PATH_INFO strings to arrays + * of complete file paths. @see Minify_Controller_Groups + * + * @return array Minify options + */ + public function setupSources($options) { + // strip controller options + $groups = $options['groups']; + unset($options['groups']); + + // mod_fcgid places PATH_INFO in ORIG_PATH_INFO + $pi = isset($_SERVER['ORIG_PATH_INFO']) + ? substr($_SERVER['ORIG_PATH_INFO'], 1) + : (isset($_SERVER['PATH_INFO']) + ? substr($_SERVER['PATH_INFO'], 1) + : false + ); + if (false === $pi || ! isset($groups[$pi])) { + // no PATH_INFO or not a valid group + $this->log("Missing PATH_INFO or no group set for \"$pi\""); + return $options; + } + $sources = array(); + + $files = $groups[$pi]; + // if $files is a single object, casting will break it + if (is_object($files)) { + $files = array($files); + } elseif (! is_array($files)) { + $files = (array)$files; + } + foreach ($files as $file) { + if ($file instanceof Minify_Source) { + $sources[] = $file; + continue; + } + if (0 === strpos($file, '//')) { + $file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1); + } + $realPath = realpath($file); + if (is_file($realPath)) { + $sources[] = new Minify_Source(array( + 'filepath' => $realPath + )); + } else { + $this->log("The path \"{$file}\" could not be found (or was not a file)"); + return $options; + } + } + if ($sources) { + $this->sources = $sources; + } + return $options; + } +} + diff --git a/mrclay/minify/min/lib/Minify/Controller/MinApp.php b/mrclay/minify/min/lib/Minify/Controller/MinApp.php new file mode 100644 index 000000000000..ade736f5f8c0 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Controller/MinApp.php @@ -0,0 +1,237 @@ + + */ +class Minify_Controller_MinApp extends Minify_Controller_Base { + + /** + * Set up groups of files as sources + * + * @param array $options controller and Minify options + * + * @return array Minify options + */ + public function setupSources($options) { + // PHP insecure by default: realpath() and other FS functions can't handle null bytes. + foreach (array('g', 'b', 'f') as $key) { + if (isset($_GET[$key])) { + $_GET[$key] = str_replace("\x00", '', (string)$_GET[$key]); + } + } + + // filter controller options + $cOptions = array_merge( + array( + 'allowDirs' => '//' + ,'groupsOnly' => false + ,'groups' => array() + ,'noMinPattern' => '@[-\\.]min\\.(?:js|css)$@i' // matched against basename + ) + ,(isset($options['minApp']) ? $options['minApp'] : array()) + ); + unset($options['minApp']); + $sources = array(); + $this->selectionId = ''; + $firstMissingResource = null; + if (isset($_GET['g'])) { + // add group(s) + $this->selectionId .= 'g=' . $_GET['g']; + $keys = explode(',', $_GET['g']); + if ($keys != array_unique($keys)) { + $this->log("Duplicate group key found."); + return $options; + } + foreach ($keys as $key) { + if (! isset($cOptions['groups'][$key])) { + $this->log("A group configuration for \"{$key}\" was not found"); + return $options; + } + $files = $cOptions['groups'][$key]; + // if $files is a single object, casting will break it + if (is_object($files)) { + $files = array($files); + } elseif (! is_array($files)) { + $files = (array)$files; + } + foreach ($files as $file) { + if ($file instanceof Minify_Source) { + $sources[] = $file; + continue; + } + if (0 === strpos($file, '//')) { + $file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1); + } + $realpath = realpath($file); + if ($realpath && is_file($realpath)) { + $sources[] = $this->_getFileSource($realpath, $cOptions); + } else { + $this->log("The path \"{$file}\" (realpath \"{$realpath}\") could not be found (or was not a file)"); + if (null === $firstMissingResource) { + $firstMissingResource = basename($file); + continue; + } else { + $secondMissingResource = basename($file); + $this->log("More than one file was missing: '$firstMissingResource', '$secondMissingResource'"); + return $options; + } + } + } + if ($sources) { + try { + $this->checkType($sources[0]); + } catch (Exception $e) { + $this->log($e->getMessage()); + return $options; + } + } + } + } + if (! $cOptions['groupsOnly'] && isset($_GET['f'])) { + // try user files + // The following restrictions are to limit the URLs that minify will + // respond to. + if (// verify at least one file, files are single comma separated, + // and are all same extension + ! preg_match('/^[^,]+\\.(css|js)(?:,[^,]+\\.\\1)*$/', $_GET['f'], $m) + // no "//" + || strpos($_GET['f'], '//') !== false + // no "\" + || strpos($_GET['f'], '\\') !== false + ) { + $this->log("GET param 'f' was invalid"); + return $options; + } + $ext = ".{$m[1]}"; + try { + $this->checkType($m[1]); + } catch (Exception $e) { + $this->log($e->getMessage()); + return $options; + } + $files = explode(',', $_GET['f']); + if ($files != array_unique($files)) { + $this->log("Duplicate files were specified"); + return $options; + } + if (isset($_GET['b'])) { + // check for validity + if (preg_match('@^[^/]+(?:/[^/]+)*$@', $_GET['b']) + && false === strpos($_GET['b'], '..') + && $_GET['b'] !== '.') { + // valid base + $base = "/{$_GET['b']}/"; + } else { + $this->log("GET param 'b' was invalid"); + return $options; + } + } else { + $base = '/'; + } + $allowDirs = array(); + foreach ((array)$cOptions['allowDirs'] as $allowDir) { + $allowDirs[] = realpath(str_replace('//', $_SERVER['DOCUMENT_ROOT'] . '/', $allowDir)); + } + $basenames = array(); // just for cache id + foreach ($files as $file) { + $uri = $base . $file; + $path = $_SERVER['DOCUMENT_ROOT'] . $uri; + $realpath = realpath($path); + if (false === $realpath || ! is_file($realpath)) { + $this->log("The path \"{$path}\" (realpath \"{$realpath}\") could not be found (or was not a file)"); + if (null === $firstMissingResource) { + $firstMissingResource = $uri; + continue; + } else { + $secondMissingResource = $uri; + $this->log("More than one file was missing: '$firstMissingResource', '$secondMissingResource`'"); + return $options; + } + } + try { + parent::checkNotHidden($realpath); + parent::checkAllowDirs($realpath, $allowDirs, $uri); + } catch (Exception $e) { + $this->log($e->getMessage()); + return $options; + } + $sources[] = $this->_getFileSource($realpath, $cOptions); + $basenames[] = basename($realpath, $ext); + } + if ($this->selectionId) { + $this->selectionId .= '_f='; + } + $this->selectionId .= implode(',', $basenames) . $ext; + } + if ($sources) { + if (null !== $firstMissingResource) { + array_unshift($sources, new Minify_Source(array( + 'id' => 'missingFile' + // should not cause cache invalidation + ,'lastModified' => 0 + // due to caching, filename is unreliable. + ,'content' => "/* Minify: at least one missing file. See " . Minify::URL_DEBUG . " */\n" + ,'minifier' => '' + ))); + } + $this->sources = $sources; + } else { + $this->log("No sources to serve"); + } + return $options; + } + + /** + * @param string $file + * + * @param array $cOptions + * + * @return Minify_Source + */ + protected function _getFileSource($file, $cOptions) + { + $spec['filepath'] = $file; + if ($cOptions['noMinPattern'] && preg_match($cOptions['noMinPattern'], basename($file))) { + if (preg_match('~\.css$~i', $file)) { + $spec['minifyOptions']['compress'] = false; + } else { + $spec['minifier'] = ''; + } + } + return new Minify_Source($spec); + } + + protected $_type = null; + + /** + * Make sure that only source files of a single type are registered + * + * @param string $sourceOrExt + * + * @throws Exception + */ + public function checkType($sourceOrExt) + { + if ($sourceOrExt === 'js') { + $type = Minify::TYPE_JS; + } elseif ($sourceOrExt === 'css') { + $type = Minify::TYPE_CSS; + } elseif ($sourceOrExt->contentType !== null) { + $type = $sourceOrExt->contentType; + } else { + return; + } + if ($this->_type === null) { + $this->_type = $type; + } elseif ($this->_type !== $type) { + throw new Exception('Content-Type mismatch'); + } + } +} diff --git a/mrclay/minify/min/lib/Minify/Controller/Page.php b/mrclay/minify/min/lib/Minify/Controller/Page.php new file mode 100644 index 000000000000..1095fb46fe28 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Controller/Page.php @@ -0,0 +1,68 @@ + + */ +class Minify_Controller_Page extends Minify_Controller_Base { + + /** + * Set up source of HTML content + * + * @param array $options controller and Minify options + * @return array Minify options + * + * Controller options: + * + * 'content': (required) HTML markup + * + * 'id': (required) id of page (string for use in server-side caching) + * + * 'lastModifiedTime': timestamp of when this content changed. This + * is recommended to allow both server and client-side caching. + * + * 'minifyAll': should all CSS and Javascript blocks be individually + * minified? (default false) + * + * @todo Add 'file' option to read HTML file. + */ + public function setupSources($options) { + if (isset($options['file'])) { + $sourceSpec = array( + 'filepath' => $options['file'] + ); + $f = $options['file']; + } else { + // strip controller options + $sourceSpec = array( + 'content' => $options['content'] + ,'id' => $options['id'] + ); + $f = $options['id']; + unset($options['content'], $options['id']); + } + // something like "builder,index.php" or "directory,file.html" + $this->selectionId = strtr(substr($f, 1 + strlen(dirname(dirname($f)))), '/\\', ',,'); + + if (isset($options['minifyAll'])) { + // this will be the 2nd argument passed to Minify_HTML::minify() + $sourceSpec['minifyOptions'] = array( + 'cssMinifier' => array('Minify_CSS', 'minify') + ,'jsMinifier' => array('JSMin', 'minify') + ); + unset($options['minifyAll']); + } + $this->sources[] = new Minify_Source($sourceSpec); + + $options['contentType'] = Minify::TYPE_HTML; + return $options; + } +} + diff --git a/mrclay/minify/min/lib/Minify/Controller/Version1.php b/mrclay/minify/min/lib/Minify/Controller/Version1.php new file mode 100644 index 000000000000..91fcf61448a2 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Controller/Version1.php @@ -0,0 +1,119 @@ + + * Minify::serve('Version1'); + * + * + * @package Minify + * @author Stephen Clay + */ +class Minify_Controller_Version1 extends Minify_Controller_Base { + + /** + * Set up groups of files as sources + * + * @param array $options controller and Minify options + * @return array Minify options + * + */ + public function setupSources($options) { + // PHP insecure by default: realpath() and other FS functions can't handle null bytes. + if (isset($_GET['files'])) { + $_GET['files'] = str_replace("\x00", '', (string)$_GET['files']); + } + + self::_setupDefines(); + if (MINIFY_USE_CACHE) { + $cacheDir = defined('MINIFY_CACHE_DIR') + ? MINIFY_CACHE_DIR + : ''; + Minify::setCache($cacheDir); + } + $options['badRequestHeader'] = 'HTTP/1.0 404 Not Found'; + $options['contentTypeCharset'] = MINIFY_ENCODING; + + // The following restrictions are to limit the URLs that minify will + // respond to. Ideally there should be only one way to reference a file. + if (! isset($_GET['files']) + // verify at least one file, files are single comma separated, + // and are all same extension + || ! preg_match('/^[^,]+\\.(css|js)(,[^,]+\\.\\1)*$/', $_GET['files'], $m) + // no "//" (makes URL rewriting easier) + || strpos($_GET['files'], '//') !== false + // no "\" + || strpos($_GET['files'], '\\') !== false + // no "./" + || preg_match('/(?:^|[^\\.])\\.\\//', $_GET['files']) + ) { + return $options; + } + + $files = explode(',', $_GET['files']); + if (count($files) > MINIFY_MAX_FILES) { + return $options; + } + + // strings for prepending to relative/absolute paths + $prependRelPaths = dirname($_SERVER['SCRIPT_FILENAME']) + . DIRECTORY_SEPARATOR; + $prependAbsPaths = $_SERVER['DOCUMENT_ROOT']; + + $goodFiles = array(); + $hasBadSource = false; + + $allowDirs = isset($options['allowDirs']) + ? $options['allowDirs'] + : MINIFY_BASE_DIR; + + foreach ($files as $file) { + // prepend appropriate string for abs/rel paths + $file = ($file[0] === '/' ? $prependAbsPaths : $prependRelPaths) . $file; + // make sure a real file! + $file = realpath($file); + // don't allow unsafe or duplicate files + if (parent::_fileIsSafe($file, $allowDirs) + && !in_array($file, $goodFiles)) + { + $goodFiles[] = $file; + $srcOptions = array( + 'filepath' => $file + ); + $this->sources[] = new Minify_Source($srcOptions); + } else { + $hasBadSource = true; + break; + } + } + if ($hasBadSource) { + $this->sources = array(); + } + if (! MINIFY_REWRITE_CSS_URLS) { + $options['rewriteCssUris'] = false; + } + return $options; + } + + private static function _setupDefines() + { + $defaults = array( + 'MINIFY_BASE_DIR' => realpath($_SERVER['DOCUMENT_ROOT']) + ,'MINIFY_ENCODING' => 'utf-8' + ,'MINIFY_MAX_FILES' => 16 + ,'MINIFY_REWRITE_CSS_URLS' => true + ,'MINIFY_USE_CACHE' => true + ); + foreach ($defaults as $const => $val) { + if (! defined($const)) { + define($const, $val); + } + } + } +} + diff --git a/mrclay/minify/min/lib/Minify/DebugDetector.php b/mrclay/minify/min/lib/Minify/DebugDetector.php new file mode 100644 index 000000000000..7db0b41f5ce1 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/DebugDetector.php @@ -0,0 +1,26 @@ + + */ +class Minify_DebugDetector { + public static function shouldDebugRequest($cookie, $get, $requestUri) + { + if (isset($get['debug'])) { + return true; + } + if (! empty($cookie['minifyDebug'])) { + foreach (preg_split('/\\s+/', $cookie['minifyDebug']) as $debugUri) { + $pattern = '@' . preg_quote($debugUri, '@') . '@i'; + $pattern = str_replace(array('\\*', '\\?'), array('.*', '.'), $pattern); + if (preg_match($pattern, $requestUri)) { + return true; + } + } + } + return false; + } +} diff --git a/mrclay/minify/min/lib/Minify/HTML.php b/mrclay/minify/min/lib/Minify/HTML.php new file mode 100644 index 000000000000..6767e81a8456 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/HTML.php @@ -0,0 +1,255 @@ + + */ +class Minify_HTML { + /** + * @var boolean + */ + protected $_jsCleanComments = true; + + /** + * "Minify" an HTML page + * + * @param string $html + * + * @param array $options + * + * 'cssMinifier' : (optional) callback function to process content of STYLE + * elements. + * + * 'jsMinifier' : (optional) callback function to process content of SCRIPT + * elements. Note: the type attribute is ignored. + * + * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If + * unset, minify will sniff for an XHTML doctype. + * + * @return string + */ + public static function minify($html, $options = array()) { + $min = new self($html, $options); + return $min->process(); + } + + + /** + * Create a minifier object + * + * @param string $html + * + * @param array $options + * + * 'cssMinifier' : (optional) callback function to process content of STYLE + * elements. + * + * 'jsMinifier' : (optional) callback function to process content of SCRIPT + * elements. Note: the type attribute is ignored. + * + * 'jsCleanComments' : (optional) whether to remove HTML comments beginning and end of script block + * + * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If + * unset, minify will sniff for an XHTML doctype. + */ + public function __construct($html, $options = array()) + { + $this->_html = str_replace("\r\n", "\n", trim($html)); + if (isset($options['xhtml'])) { + $this->_isXhtml = (bool)$options['xhtml']; + } + if (isset($options['cssMinifier'])) { + $this->_cssMinifier = $options['cssMinifier']; + } + if (isset($options['jsMinifier'])) { + $this->_jsMinifier = $options['jsMinifier']; + } + if (isset($options['jsCleanComments'])) { + $this->_jsCleanComments = (bool)$options['jsCleanComments']; + } + } + + + /** + * Minify the markeup given in the constructor + * + * @return string + */ + public function process() + { + if ($this->_isXhtml === null) { + $this->_isXhtml = (false !== strpos($this->_html, '_replacementHash = 'MINIFYHTML' . md5($_SERVER['REQUEST_TIME']); + $this->_placeholders = array(); + + // replace SCRIPTs (and minify) with placeholders + $this->_html = preg_replace_callback( + '/(\\s*)]*?>)([\\s\\S]*?)<\\/script>(\\s*)/i' + ,array($this, '_removeScriptCB') + ,$this->_html); + + // replace STYLEs (and minify) with placeholders + $this->_html = preg_replace_callback( + '/\\s*]*>)([\\s\\S]*?)<\\/style>\\s*/i' + ,array($this, '_removeStyleCB') + ,$this->_html); + + // remove HTML comments (not containing IE conditional comments). + $this->_html = preg_replace_callback( + '//' + ,array($this, '_commentCB') + ,$this->_html); + + // replace PREs with placeholders + $this->_html = preg_replace_callback('/\\s*]*?>[\\s\\S]*?<\\/pre>)\\s*/i' + ,array($this, '_removePreCB') + ,$this->_html); + + // replace TEXTAREAs with placeholders + $this->_html = preg_replace_callback( + '/\\s*]*?>[\\s\\S]*?<\\/textarea>)\\s*/i' + ,array($this, '_removeTextareaCB') + ,$this->_html); + + // trim each line. + // @todo take into account attribute values that span multiple lines. + $this->_html = preg_replace('/^\\s+|\\s+$/m', '', $this->_html); + + // remove ws around block/undisplayed elements + $this->_html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body' + .'|caption|center|col(?:group)?|dd|dir|div|dl|dt|fieldset|form' + .'|frame(?:set)?|h[1-6]|head|hr|html|legend|li|link|map|menu|meta' + .'|ol|opt(?:group|ion)|p|param|t(?:able|body|head|d|h||r|foot|itle)' + .'|ul)\\b[^>]*>)/i', '$1', $this->_html); + + // remove ws outside of all elements + $this->_html = preg_replace( + '/>(\\s(?:\\s*))?([^<]+)(\\s(?:\s*))?$1$2$3<' + ,$this->_html); + + // use newlines before 1st attribute in open tags (to limit line lengths) + $this->_html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $this->_html); + + // fill placeholders + $this->_html = str_replace( + array_keys($this->_placeholders) + ,array_values($this->_placeholders) + ,$this->_html + ); + // issue 229: multi-pass to catch scripts that didn't get replaced in textareas + $this->_html = str_replace( + array_keys($this->_placeholders) + ,array_values($this->_placeholders) + ,$this->_html + ); + return $this->_html; + } + + protected function _commentCB($m) + { + return (0 === strpos($m[1], '[') || false !== strpos($m[1], '_replacementHash . count($this->_placeholders) . '%'; + $this->_placeholders[$placeholder] = $content; + return $placeholder; + } + + protected $_isXhtml = null; + protected $_replacementHash = null; + protected $_placeholders = array(); + protected $_cssMinifier = null; + protected $_jsMinifier = null; + + protected function _removePreCB($m) + { + return $this->_reservePlace("_reservePlace("\\s*$)/', '', $css); + + // remove CDATA section markers + $css = $this->_removeCdata($css); + + // minify + $minifier = $this->_cssMinifier + ? $this->_cssMinifier + : 'trim'; + $css = call_user_func($minifier, $css); + + return $this->_reservePlace($this->_needsCdata($css) + ? "{$openStyle}/**/" + : "{$openStyle}{$css}" + ); + } + + protected function _removeScriptCB($m) + { + $openScript = "_jsCleanComments) { + $js = preg_replace('/(?:^\\s*\\s*$)/', '', $js); + } + + // remove CDATA section markers + $js = $this->_removeCdata($js); + + // minify + $minifier = $this->_jsMinifier + ? $this->_jsMinifier + : 'trim'; + $js = call_user_func($minifier, $js); + + return $this->_reservePlace($this->_needsCdata($js) + ? "{$ws1}{$openScript}/**/{$ws2}" + : "{$ws1}{$openScript}{$js}{$ws2}" + ); + } + + protected function _removeCdata($str) + { + return (false !== strpos($str, ''), '', $str) + : $str; + } + + protected function _needsCdata($str) + { + return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str)); + } +} diff --git a/mrclay/minify/min/lib/Minify/HTML/Helper.php b/mrclay/minify/min/lib/Minify/HTML/Helper.php new file mode 100644 index 000000000000..f92ab854c1df --- /dev/null +++ b/mrclay/minify/min/lib/Minify/HTML/Helper.php @@ -0,0 +1,225 @@ + + */ +class Minify_HTML_Helper { + public $rewriteWorks = true; + public $minAppUri = '/min'; + public $groupsConfigFile = ''; + + /** + * Get an HTML-escaped Minify URI for a group or set of files + * + * @param string|array $keyOrFiles a group key or array of filepaths/URIs + * @param array $opts options: + * 'farExpires' : (default true) append a modified timestamp for cache revving + * 'debug' : (default false) append debug flag + * 'charset' : (default 'UTF-8') for htmlspecialchars + * 'minAppUri' : (default '/min') URI of min directory + * 'rewriteWorks' : (default true) does mod_rewrite work in min app? + * 'groupsConfigFile' : specify if different + * @return string + */ + public static function getUri($keyOrFiles, $opts = array()) + { + $opts = array_merge(array( // default options + 'farExpires' => true + ,'debug' => false + ,'charset' => 'UTF-8' + ,'minAppUri' => '/min' + ,'rewriteWorks' => true + ,'groupsConfigFile' => '' + ), $opts); + $h = new self; + $h->minAppUri = $opts['minAppUri']; + $h->rewriteWorks = $opts['rewriteWorks']; + $h->groupsConfigFile = $opts['groupsConfigFile']; + if (is_array($keyOrFiles)) { + $h->setFiles($keyOrFiles, $opts['farExpires']); + } else { + $h->setGroup($keyOrFiles, $opts['farExpires']); + } + $uri = $h->getRawUri($opts['farExpires'], $opts['debug']); + return htmlspecialchars($uri, ENT_QUOTES, $opts['charset']); + } + + /** + * Get non-HTML-escaped URI to minify the specified files + * + * @param bool $farExpires + * @param bool $debug + * @return string + */ + public function getRawUri($farExpires = true, $debug = false) + { + $path = rtrim($this->minAppUri, '/') . '/'; + if (! $this->rewriteWorks) { + $path .= '?'; + } + if (null === $this->_groupKey) { + // @todo: implement shortest uri + $path = self::_getShortestUri($this->_filePaths, $path); + } else { + $path .= "g=" . $this->_groupKey; + } + if ($debug) { + $path .= "&debug"; + } elseif ($farExpires && $this->_lastModified) { + $path .= "&" . $this->_lastModified; + } + return $path; + } + + /** + * Set the files that will comprise the URI we're building + * + * @param array $files + * @param bool $checkLastModified + */ + public function setFiles($files, $checkLastModified = true) + { + $this->_groupKey = null; + if ($checkLastModified) { + $this->_lastModified = self::getLastModified($files); + } + // normalize paths like in /min/f= + foreach ($files as $k => $file) { + if (0 === strpos($file, '//')) { + $file = substr($file, 2); + } elseif (0 === strpos($file, '/') + || 1 === strpos($file, ':\\')) { + $file = substr($file, strlen($_SERVER['DOCUMENT_ROOT']) + 1); + } + $file = strtr($file, '\\', '/'); + $files[$k] = $file; + } + $this->_filePaths = $files; + } + + /** + * Set the group of files that will comprise the URI we're building + * + * @param string $key + * @param bool $checkLastModified + */ + public function setGroup($key, $checkLastModified = true) + { + $this->_groupKey = $key; + if ($checkLastModified) { + if (! $this->groupsConfigFile) { + $this->groupsConfigFile = dirname(dirname(dirname(dirname(__FILE__)))) . '/groupsConfig.php'; + } + if (is_file($this->groupsConfigFile)) { + $gc = (require $this->groupsConfigFile); + $keys = explode(',', $key); + foreach ($keys as $key) { + if (isset($gc[$key])) { + $this->_lastModified = self::getLastModified($gc[$key], $this->_lastModified); + } + } + } + } + } + + /** + * Get the max(lastModified) of all files + * + * @param array|string $sources + * @param int $lastModified + * @return int + */ + public static function getLastModified($sources, $lastModified = 0) + { + $max = $lastModified; + foreach ((array)$sources as $source) { + if (is_object($source) && isset($source->lastModified)) { + $max = max($max, $source->lastModified); + } elseif (is_string($source)) { + if (0 === strpos($source, '//')) { + $source = $_SERVER['DOCUMENT_ROOT'] . substr($source, 1); + } + if (is_file($source)) { + $max = max($max, filemtime($source)); + } + } + } + return $max; + } + + protected $_groupKey = null; // if present, URI will be like g=... + protected $_filePaths = array(); + protected $_lastModified = null; + + + /** + * In a given array of strings, find the character they all have at + * a particular index + * + * @param array $arr array of strings + * @param int $pos index to check + * @return mixed a common char or '' if any do not match + */ + protected static function _getCommonCharAtPos($arr, $pos) { + if (!isset($arr[0][$pos])) { + return ''; + } + $c = $arr[0][$pos]; + $l = count($arr); + if ($l === 1) { + return $c; + } + for ($i = 1; $i < $l; ++$i) { + if ($arr[$i][$pos] !== $c) { + return ''; + } + } + return $c; + } + + /** + * Get the shortest URI to minify the set of source files + * + * @param array $paths root-relative URIs of files + * @param string $minRoot root-relative URI of the "min" application + * @return string + */ + protected static function _getShortestUri($paths, $minRoot = '/min/') { + $pos = 0; + $base = ''; + while (true) { + $c = self::_getCommonCharAtPos($paths, $pos); + if ($c === '') { + break; + } else { + $base .= $c; + } + ++$pos; + } + $base = preg_replace('@[^/]+$@', '', $base); + $uri = $minRoot . 'f=' . implode(',', $paths); + + if (substr($base, -1) === '/') { + // we have a base dir! + $basedPaths = $paths; + $l = count($paths); + for ($i = 0; $i < $l; ++$i) { + $basedPaths[$i] = substr($paths[$i], strlen($base)); + } + $base = substr($base, 0, strlen($base) - 1); + $bUri = $minRoot . 'b=' . $base . '&f=' . implode(',', $basedPaths); + + $uri = strlen($uri) < strlen($bUri) + ? $uri + : $bUri; + } + return $uri; + } +} diff --git a/mrclay/minify/min/lib/Minify/ImportProcessor.php b/mrclay/minify/min/lib/Minify/ImportProcessor.php new file mode 100644 index 000000000000..5957babc20d1 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/ImportProcessor.php @@ -0,0 +1,216 @@ + + * @author Simon Schick + */ +class Minify_ImportProcessor { + + public static $filesIncluded = array(); + + public static function process($file) + { + self::$filesIncluded = array(); + self::$_isCss = (strtolower(substr($file, -4)) === '.css'); + $obj = new Minify_ImportProcessor(dirname($file)); + return $obj->_getContent($file); + } + + // allows callback funcs to know the current directory + private $_currentDir = null; + + // allows callback funcs to know the directory of the file that inherits this one + private $_previewsDir = null; + + // allows _importCB to write the fetched content back to the obj + private $_importedContent = ''; + + private static $_isCss = null; + + /** + * @param String $currentDir + * @param String $previewsDir Is only used internally + */ + private function __construct($currentDir, $previewsDir = "") + { + $this->_currentDir = $currentDir; + $this->_previewsDir = $previewsDir; + } + + private function _getContent($file, $is_imported = false) + { + $file = realpath($file); + if (! $file + || in_array($file, self::$filesIncluded) + || false === ($content = @file_get_contents($file)) + ) { + // file missing, already included, or failed read + return ''; + } + self::$filesIncluded[] = realpath($file); + $this->_currentDir = dirname($file); + + // remove UTF-8 BOM if present + if (pack("CCC",0xef,0xbb,0xbf) === substr($content, 0, 3)) { + $content = substr($content, 3); + } + // ensure uniform EOLs + $content = str_replace("\r\n", "\n", $content); + + // process @imports + $content = preg_replace_callback( + '/ + @import\\s+ + (?:url\\(\\s*)? # maybe url( + [\'"]? # maybe quote + (.*?) # 1 = URI + [\'"]? # maybe end quote + (?:\\s*\\))? # maybe ) + ([a-zA-Z,\\s]*)? # 2 = media list + ; # end token + /x' + ,array($this, '_importCB') + ,$content + ); + + // You only need to rework the import-path if the script is imported + if (self::$_isCss && $is_imported) { + // rewrite remaining relative URIs + $content = preg_replace_callback( + '/url\\(\\s*([^\\)\\s]+)\\s*\\)/' + ,array($this, '_urlCB') + ,$content + ); + } + + return $this->_importedContent . $content; + } + + private function _importCB($m) + { + $url = $m[1]; + $mediaList = preg_replace('/\\s+/', '', $m[2]); + + if (strpos($url, '://') > 0) { + // protocol, leave in place for CSS, comment for JS + return self::$_isCss + ? $m[0] + : "/* Minify_ImportProcessor will not include remote content */"; + } + if ('/' === $url[0]) { + // protocol-relative or root path + $url = ltrim($url, '/'); + $file = realpath($_SERVER['DOCUMENT_ROOT']) . DIRECTORY_SEPARATOR + . strtr($url, '/', DIRECTORY_SEPARATOR); + } else { + // relative to current path + $file = $this->_currentDir . DIRECTORY_SEPARATOR + . strtr($url, '/', DIRECTORY_SEPARATOR); + } + $obj = new Minify_ImportProcessor(dirname($file), $this->_currentDir); + $content = $obj->_getContent($file, true); + if ('' === $content) { + // failed. leave in place for CSS, comment for JS + return self::$_isCss + ? $m[0] + : "/* Minify_ImportProcessor could not fetch '{$file}' */"; + } + return (!self::$_isCss || preg_match('@(?:^$|\\ball\\b)@', $mediaList)) + ? $content + : "@media {$mediaList} {\n{$content}\n}\n"; + } + + private function _urlCB($m) + { + // $m[1] is either quoted or not + $quote = ($m[1][0] === "'" || $m[1][0] === '"') + ? $m[1][0] + : ''; + $url = ($quote === '') + ? $m[1] + : substr($m[1], 1, strlen($m[1]) - 2); + if ('/' !== $url[0]) { + if (strpos($url, '//') > 0) { + // probably starts with protocol, do not alter + } else { + // prepend path with current dir separator (OS-independent) + $path = $this->_currentDir + . DIRECTORY_SEPARATOR . strtr($url, '/', DIRECTORY_SEPARATOR); + // update the relative path by the directory of the file that imported this one + $url = self::getPathDiff(realpath($this->_previewsDir), $path); + } + } + return "url({$quote}{$url}{$quote})"; + } + + /** + * @param string $from + * @param string $to + * @param string $ps + * @return string + */ + private function getPathDiff($from, $to, $ps = DIRECTORY_SEPARATOR) + { + $realFrom = $this->truepath($from); + $realTo = $this->truepath($to); + + $arFrom = explode($ps, rtrim($realFrom, $ps)); + $arTo = explode($ps, rtrim($realTo, $ps)); + while (count($arFrom) && count($arTo) && ($arFrom[0] == $arTo[0])) + { + array_shift($arFrom); + array_shift($arTo); + } + return str_pad("", count($arFrom) * 3, '..' . $ps) . implode($ps, $arTo); + } + + /** + * This function is to replace PHP's extremely buggy realpath(). + * @param string $path The original path, can be relative etc. + * @return string The resolved path, it might not exist. + * @see http://stackoverflow.com/questions/4049856/replace-phps-realpath + */ + function truepath($path) + { + // whether $path is unix or not + $unipath = strlen($path) == 0 || $path{0} != '/'; + // attempts to detect if path is relative in which case, add cwd + if (strpos($path, ':') === false && $unipath) + $path = $this->_currentDir . DIRECTORY_SEPARATOR . $path; + + // resolve path parts (single dot, double dot and double delimiters) + $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path); + $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); + $absolutes = array(); + foreach ($parts as $part) { + if ('.' == $part) + continue; + if ('..' == $part) { + array_pop($absolutes); + } else { + $absolutes[] = $part; + } + } + $path = implode(DIRECTORY_SEPARATOR, $absolutes); + // resolve any symlinks + if (file_exists($path) && linkinfo($path) > 0) + $path = readlink($path); + // put initial separator that could have been lost + $path = !$unipath ? '/' . $path : $path; + return $path; + } +} diff --git a/mrclay/minify/min/lib/Minify/JS/ClosureCompiler.php b/mrclay/minify/min/lib/Minify/JS/ClosureCompiler.php new file mode 100644 index 000000000000..e067d7c85eda --- /dev/null +++ b/mrclay/minify/min/lib/Minify/JS/ClosureCompiler.php @@ -0,0 +1,230 @@ + + * + * @todo can use a stream wrapper to unit test this? + */ +class Minify_JS_ClosureCompiler { + + /** + * @var string The option key for the maximum POST byte size + */ + const OPTION_MAX_BYTES = 'maxBytes'; + + /** + * @var string The option key for additional params. @see __construct + */ + const OPTION_ADDITIONAL_OPTIONS = 'additionalParams'; + + /** + * @var string The option key for the fallback Minifier + */ + const OPTION_FALLBACK_FUNCTION = 'fallbackFunc'; + + /** + * @var string The option key for the service URL + */ + const OPTION_COMPILER_URL = 'compilerUrl'; + + /** + * @var int The default maximum POST byte size according to https://developers.google.com/closure/compiler/docs/api-ref + */ + const DEFAULT_MAX_BYTES = 200000; + + /** + * @var string[] $DEFAULT_OPTIONS The default options to pass to the compiler service + * + * @note This would be a constant if PHP allowed it + */ + private static $DEFAULT_OPTIONS = array( + 'output_format' => 'text', + 'compilation_level' => 'SIMPLE_OPTIMIZATIONS' + ); + + /** + * @var string $url URL of compiler server. defaults to Google's + */ + protected $serviceUrl = 'http://closure-compiler.appspot.com/compile'; + + /** + * @var int $maxBytes The maximum JS size that can be sent to the compiler server in bytes + */ + protected $maxBytes = self::DEFAULT_MAX_BYTES; + + /** + * @var string[] $additionalOptions Additional options to pass to the compiler service + */ + protected $additionalOptions = array(); + + /** + * @var callable Function to minify JS if service fails. Default is JSMin + */ + protected $fallbackMinifier = array('JSMin', 'minify'); + + /** + * Minify JavaScript code via HTTP request to a Closure Compiler API + * + * @param string $js input code + * @param array $options Options passed to __construct(). @see __construct + * + * @return string + */ + public static function minify($js, array $options = array()) + { + $obj = new self($options); + return $obj->min($js); + } + + /** + * @param array $options Options with keys available below: + * + * fallbackFunc : (callable) function to minify if service unavailable. Default is JSMin. + * + * compilerUrl : (string) URL to closure compiler server + * + * maxBytes : (int) The maximum amount of bytes to be sent as js_code in the POST request. + * Defaults to 200000. + * + * additionalParams : (string[]) Additional parameters to pass to the compiler server. Can be anything named + * in https://developers.google.com/closure/compiler/docs/api-ref except for js_code and + * output_info + */ + public function __construct(array $options = array()) + { + if (isset($options[self::OPTION_FALLBACK_FUNCTION])) { + $this->fallbackMinifier = $options[self::OPTION_FALLBACK_FUNCTION]; + } + if (isset($options[self::OPTION_COMPILER_URL])) { + $this->serviceUrl = $options[self::OPTION_COMPILER_URL]; + } + if (isset($options[self::OPTION_ADDITIONAL_OPTIONS]) && is_array($options[self::OPTION_ADDITIONAL_OPTIONS])) { + $this->additionalOptions = $options[self::OPTION_ADDITIONAL_OPTIONS]; + } + if (isset($options[self::OPTION_MAX_BYTES])) { + $this->maxBytes = (int) $options[self::OPTION_MAX_BYTES]; + } + } + + /** + * Call the service to perform the minification + * + * @param string $js JavaScript code + * @return string + * @throws Minify_JS_ClosureCompiler_Exception + */ + public function min($js) + { + $postBody = $this->buildPostBody($js); + + if ($this->maxBytes > 0) { + $bytes = (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) + ? mb_strlen($postBody, '8bit') + : strlen($postBody); + if ($bytes > $this->maxBytes) { + throw new Minify_JS_ClosureCompiler_Exception( + 'POST content larger than ' . $this->maxBytes . ' bytes' + ); + } + } + + $response = $this->getResponse($postBody); + + if (preg_match('/^Error\(\d\d?\):/', $response)) { + if (is_callable($this->fallbackMinifier)) { + // use fallback + $response = "/* Received errors from Closure Compiler API:\n$response" + . "\n(Using fallback minifier)\n*/\n"; + $response .= call_user_func($this->fallbackMinifier, $js); + } else { + throw new Minify_JS_ClosureCompiler_Exception($response); + } + } + + if ($response === '') { + $errors = $this->getResponse($this->buildPostBody($js, true)); + throw new Minify_JS_ClosureCompiler_Exception($errors); + } + + return $response; + } + + /** + * Get the response for a given POST body + * + * @param string $postBody + * @return string + * @throws Minify_JS_ClosureCompiler_Exception + */ + protected function getResponse($postBody) + { + $allowUrlFopen = preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen')); + + if ($allowUrlFopen) { + $contents = file_get_contents($this->serviceUrl, false, stream_context_create(array( + 'http' => array( + 'method' => 'POST', + 'header' => "Content-type: application/x-www-form-urlencoded\r\nConnection: close\r\n", + 'content' => $postBody, + 'max_redirects' => 0, + 'timeout' => 15, + ) + ))); + } elseif (defined('CURLOPT_POST')) { + $ch = curl_init($this->serviceUrl); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded')); + curl_setopt($ch, CURLOPT_POSTFIELDS, $postBody); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15); + $contents = curl_exec($ch); + curl_close($ch); + } else { + throw new Minify_JS_ClosureCompiler_Exception( + "Could not make HTTP request: allow_url_open is false and cURL not available" + ); + } + + if (false === $contents) { + throw new Minify_JS_ClosureCompiler_Exception( + "No HTTP response from server" + ); + } + + return trim($contents); + } + + /** + * Build a POST request body + * + * @param string $js JavaScript code + * @param bool $returnErrors + * @return string + */ + protected function buildPostBody($js, $returnErrors = false) + { + return http_build_query( + array_merge( + self::$DEFAULT_OPTIONS, + $this->additionalOptions, + array( + 'js_code' => $js, + 'output_info' => ($returnErrors ? 'errors' : 'compiled_code') + ) + ), + null, + '&' + ); + } +} + +class Minify_JS_ClosureCompiler_Exception extends Exception {} diff --git a/mrclay/minify/min/lib/Minify/Lines.php b/mrclay/minify/min/lib/Minify/Lines.php new file mode 100644 index 000000000000..e999a6c2b5c1 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Lines.php @@ -0,0 +1,143 @@ + + * @author Adam Pedersen (Issue 55 fix) + */ +class Minify_Lines { + + /** + * Add line numbers in C-style comments + * + * This uses a very basic parser easily fooled by comment tokens inside + * strings or regexes, but, otherwise, generally clean code will not be + * mangled. URI rewriting can also be performed. + * + * @param string $content + * + * @param array $options available options: + * + * 'id': (optional) string to identify file. E.g. file name/path + * + * 'currentDir': (default null) if given, this is assumed to be the + * directory of the current CSS file. Using this, minify will rewrite + * all relative URIs in import/url declarations to correctly point to + * the desired files, and prepend a comment with debugging information about + * this process. + * + * @return string + */ + public static function minify($content, $options = array()) + { + $id = (isset($options['id']) && $options['id']) + ? $options['id'] + : ''; + $content = str_replace("\r\n", "\n", $content); + + // Hackily rewrite strings with XPath expressions that are + // likely to throw off our dumb parser (for Prototype 1.6.1). + $content = str_replace('"/*"', '"/"+"*"', $content); + $content = preg_replace('@([\'"])(\\.?//?)\\*@', '$1$2$1+$1*', $content); + + $lines = explode("\n", $content); + $numLines = count($lines); + // determine left padding + $padTo = strlen((string) $numLines); // e.g. 103 lines = 3 digits + $inComment = false; + $i = 0; + $newLines = array(); + while (null !== ($line = array_shift($lines))) { + if (('' !== $id) && (0 == $i % 50)) { + if ($inComment) { + array_push($newLines, '', "/* {$id} *|", ''); + } else { + array_push($newLines, '', "/* {$id} */", ''); + } + } + ++$i; + $newLines[] = self::_addNote($line, $i, $inComment, $padTo); + $inComment = self::_eolInComment($line, $inComment); + } + $content = implode("\n", $newLines) . "\n"; + + // check for desired URI rewriting + if (isset($options['currentDir'])) { + Minify_CSS_UriRewriter::$debugText = ''; + $content = Minify_CSS_UriRewriter::rewrite( + $content + ,$options['currentDir'] + ,isset($options['docRoot']) ? $options['docRoot'] : $_SERVER['DOCUMENT_ROOT'] + ,isset($options['symlinks']) ? $options['symlinks'] : array() + ); + $content = "/* Minify_CSS_UriRewriter::\$debugText\n\n" + . Minify_CSS_UriRewriter::$debugText . "*/\n" + . $content; + } + + return $content; + } + + /** + * Is the parser within a C-style comment at the end of this line? + * + * @param string $line current line of code + * + * @param bool $inComment was the parser in a comment at the + * beginning of the line? + * + * @return bool + */ + private static function _eolInComment($line, $inComment) + { + // crude way to avoid things like // */ + $line = preg_replace('~//.*?(\\*/|/\\*).*~', '', $line); + + while (strlen($line)) { + $search = $inComment + ? '*/' + : '/*'; + $pos = strpos($line, $search); + if (false === $pos) { + return $inComment; + } else { + if ($pos == 0 + || ($inComment + ? substr($line, $pos, 3) + : substr($line, $pos-1, 3)) != '*/*') + { + $inComment = ! $inComment; + } + $line = substr($line, $pos + 2); + } + } + return $inComment; + } + + /** + * Prepend a comment (or note) to the given line + * + * @param string $line current line of code + * + * @param string $note content of note/comment + * + * @param bool $inComment was the parser in a comment at the + * beginning of the line? + * + * @param int $padTo minimum width of comment + * + * @return string + */ + private static function _addNote($line, $note, $inComment, $padTo) + { + return $inComment + ? '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' *| ' . $line + : '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' */ ' . $line; + } +} diff --git a/mrclay/minify/min/lib/Minify/Loader.php b/mrclay/minify/min/lib/Minify/Loader.php new file mode 100644 index 000000000000..0a225c056c05 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Loader.php @@ -0,0 +1,28 @@ + + */ +class Minify_Loader { + public function loadClass($class) + { + $file = dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR; + $file .= strtr($class, "\\_", DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR) . '.php'; + if (is_readable($file)) { + require $file; + } + } + + static public function register() + { + $inst = new self(); + spl_autoload_register(array($inst, 'loadClass')); + } +} diff --git a/mrclay/minify/min/lib/Minify/Logger.php b/mrclay/minify/min/lib/Minify/Logger.php new file mode 100644 index 000000000000..8eb72f452897 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Logger.php @@ -0,0 +1,47 @@ + + * + * @todo lose this singleton! pass log object in Minify::serve and distribute to others + */ +class Minify_Logger { + + /** + * Set logger object. + * + * The object should have a method "log" that accepts a value as 1st argument and + * an optional string label as the 2nd. + * + * @param mixed $obj or a "falsey" value to disable + * @return null + */ + public static function setLogger($obj = null) { + self::$_logger = $obj + ? $obj + : null; + } + + /** + * Pass a message to the logger (if set) + * + * @param string $msg message to log + * @return null + */ + public static function log($msg, $label = 'Minify') { + if (! self::$_logger) return; + self::$_logger->log($msg, $label); + } + + /** + * @var mixed logger object (like FirePHP) or null (i.e. no logger available) + */ + private static $_logger = null; +} diff --git a/mrclay/minify/min/lib/Minify/Packer.php b/mrclay/minify/min/lib/Minify/Packer.php new file mode 100644 index 000000000000..949c3eef046d --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Packer.php @@ -0,0 +1,37 @@ +pack()); + } +} diff --git a/mrclay/minify/min/lib/Minify/Source.php b/mrclay/minify/min/lib/Minify/Source.php new file mode 100644 index 000000000000..5a85d10d0dd9 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/Source.php @@ -0,0 +1,187 @@ + + */ +class Minify_Source { + + /** + * @var int time of last modification + */ + public $lastModified = null; + + /** + * @var callback minifier function specifically for this source. + */ + public $minifier = null; + + /** + * @var array minification options specific to this source. + */ + public $minifyOptions = null; + + /** + * @var string full path of file + */ + public $filepath = null; + + /** + * @var string HTTP Content Type (Minify requires one of the constants Minify::TYPE_*) + */ + public $contentType = null; + + /** + * Create a Minify_Source + * + * In the $spec array(), you can either provide a 'filepath' to an existing + * file (existence will not be checked!) or give 'id' (unique string for + * the content), 'content' (the string content) and 'lastModified' + * (unixtime of last update). + * + * As a shortcut, the controller will replace "//" at the beginning + * of a filepath with $_SERVER['DOCUMENT_ROOT'] . '/'. + * + * @param array $spec options + */ + public function __construct($spec) + { + if (isset($spec['filepath'])) { + if (0 === strpos($spec['filepath'], '//')) { + $spec['filepath'] = $_SERVER['DOCUMENT_ROOT'] . substr($spec['filepath'], 1); + } + $segments = explode('.', $spec['filepath']); + $ext = strtolower(array_pop($segments)); + switch ($ext) { + case 'js' : $this->contentType = 'application/x-javascript'; + break; + case 'css' : $this->contentType = 'text/css'; + break; + case 'htm' : // fallthrough + case 'html' : $this->contentType = 'text/html'; + break; + } + $this->filepath = $spec['filepath']; + $this->_id = $spec['filepath']; + $this->lastModified = filemtime($spec['filepath']) + // offset for Windows uploaders with out of sync clocks + + round(Minify::$uploaderHoursBehind * 3600); + } elseif (isset($spec['id'])) { + $this->_id = 'id::' . $spec['id']; + if (isset($spec['content'])) { + $this->_content = $spec['content']; + } else { + $this->_getContentFunc = $spec['getContentFunc']; + } + $this->lastModified = isset($spec['lastModified']) + ? $spec['lastModified'] + : time(); + } + if (isset($spec['contentType'])) { + $this->contentType = $spec['contentType']; + } + if (isset($spec['minifier'])) { + $this->minifier = $spec['minifier']; + } + if (isset($spec['minifyOptions'])) { + $this->minifyOptions = $spec['minifyOptions']; + } + } + + /** + * Get content + * + * @return string + */ + public function getContent() + { + $content = (null !== $this->filepath) + ? file_get_contents($this->filepath) + : ((null !== $this->_content) + ? $this->_content + : call_user_func($this->_getContentFunc, $this->_id) + ); + // remove UTF-8 BOM if present + return (pack("CCC",0xef,0xbb,0xbf) === substr($content, 0, 3)) + ? substr($content, 3) + : $content; + } + + /** + * Get id + * + * @return string + */ + public function getId() + { + return $this->_id; + } + + /** + * Verifies a single minification call can handle all sources + * + * @param array $sources Minify_Source instances + * + * @return bool true iff there no sources with specific minifier preferences. + */ + public static function haveNoMinifyPrefs($sources) + { + foreach ($sources as $source) { + if (null !== $source->minifier + || null !== $source->minifyOptions) { + return false; + } + } + return true; + } + + /** + * Get unique string for a set of sources + * + * @param array $sources Minify_Source instances + * + * @return string + */ + public static function getDigest($sources) + { + foreach ($sources as $source) { + $info[] = array( + $source->_id, $source->minifier, $source->minifyOptions + ); + } + return md5(serialize($info)); + } + + /** + * Get content type from a group of sources + * + * This is called if the user doesn't pass in a 'contentType' options + * + * @param array $sources Minify_Source instances + * + * @return string content type. e.g. 'text/css' + */ + public static function getContentType($sources) + { + foreach ($sources as $source) { + if ($source->contentType !== null) { + return $source->contentType; + } + } + return 'text/plain'; + } + + protected $_content = null; + protected $_getContentFunc = null; + protected $_id = null; +} + diff --git a/mrclay/minify/min/lib/Minify/YUI/CssCompressor.java b/mrclay/minify/min/lib/Minify/YUI/CssCompressor.java new file mode 100644 index 000000000000..3fb497a9697a --- /dev/null +++ b/mrclay/minify/min/lib/Minify/YUI/CssCompressor.java @@ -0,0 +1,382 @@ +/* + * YUI Compressor + * http://developer.yahoo.com/yui/compressor/ + * 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. + * The copyrights embodied in the content of this file are licensed + * by Yahoo! Inc. under the BSD (revised) open source license. + */ +package com.yahoo.platform.yui.compressor; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import java.util.ArrayList; + +public class CssCompressor { + + private StringBuffer srcsb = new StringBuffer(); + + public CssCompressor(Reader in) throws IOException { + // Read the stream... + int c; + while ((c = in.read()) != -1) { + srcsb.append((char) c); + } + } + + // Leave data urls alone to increase parse performance. + protected String extractDataUrls(String css, ArrayList preservedTokens) { + + int maxIndex = css.length() - 1; + int appendIndex = 0; + + StringBuffer sb = new StringBuffer(); + + Pattern p = Pattern.compile("url\\(\\s*([\"']?)data\\:"); + Matcher m = p.matcher(css); + + /* + * 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(); + } + } + + sb.append(css.substring(appendIndex)); + + return sb.toString(); + } + + public void compress(Writer out, int linebreakpos) + throws IOException { + + Pattern p; + Matcher m; + String css = srcsb.toString(); + + int startIndex = 0; + int endIndex = 0; + int i = 0; + int max = 0; + ArrayList preservedTokens = new ArrayList(0); + ArrayList comments = new ArrayList(0); + String token; + int totallen = css.length(); + String placeholder; + + css = this.extractDataUrls(css, preservedTokens); + + StringBuffer sb = new StringBuffer(css); + + // collect all comment blocks... + while ((startIndex = sb.indexOf("/*", startIndex)) >= 0) { + endIndex = sb.indexOf("*/", startIndex + 2); + if (endIndex < 0) { + endIndex = totallen; + } + + token = sb.substring(startIndex + 2, endIndex); + comments.add(token); + sb.replace(startIndex + 2, endIndex, "___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + (comments.size() - 1) + "___"); + startIndex += 2; + } + css = sb.toString(); + + // preserve strings so their content doesn't get accidentally minified + sb = new StringBuffer(); + p = Pattern.compile("(\"([^\\\\\"]|\\\\.|\\\\)*\")|(\'([^\\\\\']|\\\\.|\\\\)*\')"); + m = p.matcher(css); + while (m.find()) { + token = m.group(); + char quote = token.charAt(0); + token = token.substring(1, token.length() - 1); + + // maybe the string contains a comment-like substring? + // one, maybe more? put'em back then + if (token.indexOf("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_") >= 0) { + for (i = 0, max = comments.size(); i < max; i += 1) { + token = token.replace("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___", comments.get(i).toString()); + } + } + + // minify alpha opacity in filter strings + token = token.replaceAll("(?i)progid:DXImageTransform.Microsoft.Alpha\\(Opacity=", "alpha(opacity="); + + preservedTokens.add(token); + String preserver = quote + "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___" + quote; + m.appendReplacement(sb, preserver); + } + m.appendTail(sb); + css = sb.toString(); + + + // strings are safe, now wrestle the comments + for (i = 0, max = comments.size(); i < max; i += 1) { + + token = comments.get(i).toString(); + placeholder = "___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___"; + + // ! in the first position of the comment means preserve + // so push to the preserved tokens while stripping the ! + if (token.startsWith("!")) { + preservedTokens.add(token); + css = css.replace(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___"); + continue; + } + + // \ in the last position looks like hack for Mac/IE5 + // shorten that to /*\*/ and the next one to /**/ + if (token.endsWith("\\")) { + preservedTokens.add("\\"); + css = css.replace(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___"); + i = i + 1; // attn: advancing the loop + preservedTokens.add(""); + css = css.replace("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___", "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___"); + continue; + } + + // keep empty comments after child selectors (IE7 hack) + // e.g. html >/**/ body + if (token.length() == 0) { + startIndex = css.indexOf(placeholder); + if (startIndex > 2) { + if (css.charAt(startIndex - 3) == '>') { + preservedTokens.add(""); + css = css.replace(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___"); + } + } + } + + // in all other cases kill the comment + css = css.replace("/*" + placeholder + "*/", ""); + } + + + // Normalize all whitespace strings to single spaces. Easier to work with that way. + css = css.replaceAll("\\s+", " "); + + // Remove the spaces before the things that should not have spaces before them. + // But, be careful not to turn "p :link {...}" into "p:link{...}" + // Swap out any pseudo-class colons with the token, and then swap back. + sb = new StringBuffer(); + p = Pattern.compile("(^|\\})(([^\\{:])+:)+([^\\{]*\\{)"); + m = p.matcher(css); + while (m.find()) { + String s = m.group(); + s = s.replaceAll(":", "___YUICSSMIN_PSEUDOCLASSCOLON___"); + s = s.replaceAll( "\\\\", "\\\\\\\\" ).replaceAll( "\\$", "\\\\\\$" ); + m.appendReplacement(sb, s); + } + m.appendTail(sb); + css = sb.toString(); + // Remove spaces before the things that should not have spaces before them. + css = css.replaceAll("\\s+([!{};:>+\\(\\)\\],])", "$1"); + // bring back the colon + css = css.replaceAll("___YUICSSMIN_PSEUDOCLASSCOLON___", ":"); + + // retain space for special IE6 cases + css = css.replaceAll(":first\\-(line|letter)(\\{|,)", ":first-$1 $2"); + + // 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"); + + // 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 ("); + + // Remove the spaces after the things that should not have spaces after them. + css = css.replaceAll("([!{}:;>+\\(\\[,])\\s+", "$1"); + + // remove unnecessary semicolons + css = css.replaceAll(";+}", "}"); + + // Replace 0(px,em,%) with 0. + css = css.replaceAll("([\\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)", "$1$2"); + + // Replace 0 0 0 0; with 0. + css = css.replaceAll(":0 0 0 0(;|})", ":0$1"); + css = css.replaceAll(":0 0 0(;|})", ":0$1"); + css = css.replaceAll(":0 0(;|})", ":0$1"); + + + // Replace background-position:0; with background-position:0 0; + // same for transform-origin + sb = new StringBuffer(); + p = Pattern.compile("(?i)(background-position|transform-origin|webkit-transform-origin|moz-transform-origin|o-transform-origin|ms-transform-origin):0(;|})"); + m = p.matcher(css); + while (m.find()) { + m.appendReplacement(sb, m.group(1).toLowerCase() + ":0 0" + m.group(2)); + } + m.appendTail(sb); + css = sb.toString(); + + // Replace 0.6 to .6, but only when preceded by : or a white-space + css = css.replaceAll("(:|\\s)0+\\.(\\d+)", "$1.$2"); + + // Shorten colors from rgb(51,102,153) to #336699 + // This makes it more likely that it'll get further compressed in the next step. + p = Pattern.compile("rgb\\s*\\(\\s*([0-9,\\s]+)\\s*\\)"); + m = p.matcher(css); + sb = new StringBuffer(); + while (m.find()) { + String[] rgbcolors = m.group(1).split(","); + StringBuffer hexcolor = new StringBuffer("#"); + for (i = 0; i < rgbcolors.length; i++) { + int val = Integer.parseInt(rgbcolors[i]); + if (val < 16) { + hexcolor.append("0"); + } + hexcolor.append(Integer.toHexString(val)); + } + m.appendReplacement(sb, hexcolor.toString()); + } + m.appendTail(sb); + css = sb.toString(); + + // Shorten colors from #AABBCC to #ABC. Note that we want to make sure + // the color is not preceded by either ", " or =. Indeed, the property + // filter: chroma(color="#FFFFFF"); + // would become + // filter: chroma(color="#FFF"); + // which makes the filter break in IE. + // We also want to make sure we're only compressing #AABBCC patterns inside { }, not id selectors ( #FAABAC {} ) + // We also want to avoid compressing invalid values (e.g. #AABBCCD to #ABCD) + p = Pattern.compile("(\\=\\s*?[\"']?)?" + "#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])" + "(:?\\}|[^0-9a-fA-F{][^{]*?\\})"); + + m = p.matcher(css); + sb = new StringBuffer(); + int index = 0; + + while (m.find(index)) { + + sb.append(css.substring(index, m.start())); + + 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)) && + 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()); + + } 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()); + } + } + + index = m.end(7); + } + + sb.append(css.substring(index)); + css = sb.toString(); + + // border: none -> border:0 + sb = new StringBuffer(); + p = Pattern.compile("(?i)(border|border-top|border-right|border-bottom|border-right|outline|background):none(;|})"); + m = p.matcher(css); + while (m.find()) { + m.appendReplacement(sb, m.group(1).toLowerCase() + ":0" + m.group(2)); + } + m.appendTail(sb); + css = sb.toString(); + + // shorter opacity IE filter + css = css.replaceAll("(?i)progid:DXImageTransform.Microsoft.Alpha\\(Opacity=", "alpha(opacity="); + + // Remove empty rules. + css = css.replaceAll("[^\\}\\{/;]+\\{\\}", ""); + + // TODO: Should this be after we re-insert tokens. These could alter the break points. However then + // we'd need to make sure we don't break in the middle of a string etc. + if (linebreakpos >= 0) { + // Some source control tools don't like it when files containing lines longer + // than, say 8000 characters, are checked in. The linebreak option is used in + // that case to split long lines after a specific column. + i = 0; + int linestartpos = 0; + sb = new StringBuffer(css); + while (i < sb.length()) { + char c = sb.charAt(i++); + if (c == '}' && i - linestartpos > linebreakpos) { + sb.insert(i, '\n'); + linestartpos = i; + } + } + + css = sb.toString(); + } + + // Replace multiple semi-colons in a row by a single one + // See SF bug #1980989 + css = css.replaceAll(";;+", ";"); + + // restore preserved comments and strings + for(i = 0, max = preservedTokens.size(); i < max; i++) { + css = css.replace("___YUICSSMIN_PRESERVED_TOKEN_" + i + "___", preservedTokens.get(i).toString()); + } + + // Trim the final string (for any leading or trailing white spaces) + css = css.trim(); + + // Write the output... + out.write(css); + } +} diff --git a/mrclay/minify/min/lib/Minify/YUI/CssCompressor.php b/mrclay/minify/min/lib/Minify/YUI/CssCompressor.php new file mode 100644 index 000000000000..ae3443d44597 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/YUI/CssCompressor.php @@ -0,0 +1,171 @@ ++\\(\\)\\],])@", "$1", $css); + $css = str_replace("___PSEUDOCLASSCOLON___", ":", $css); + + // Remove the spaces after the things that should not have spaces after them. + $css = preg_replace("@([!{}:;>+\\(\\[,])\\s+@", "$1", $css); + + // Add the semicolon where it's missing. + $css = preg_replace("@([^;\\}])}@", "$1;}", $css); + + // Replace 0(px,em,%) with 0. + $css = preg_replace("@([\\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)@", "$1$2", $css); + + // Replace 0 0 0 0; with 0. + $css = str_replace(":0 0 0 0;", ":0;", $css); + $css = str_replace(":0 0 0;", ":0;", $css); + $css = str_replace(":0 0;", ":0;", $css); + + // Replace background-position:0; with background-position:0 0; + $css = str_replace("background-position:0;", "background-position:0 0;", $css); + + // Replace 0.6 to .6, but only when preceded by : or a white-space + $css = preg_replace("@(:|\\s)0+\\.(\\d+)@", "$1.$2", $css); + + // Shorten colors from rgb(51,102,153) to #336699 + // This makes it more likely that it'll get further compressed in the next step. + $css = preg_replace_callback("@rgb\\s*\\(\\s*([0-9,\\s]+)\\s*\\)@", array($this, '_shortenRgbCB'), $css); + + // Shorten colors from #AABBCC to #ABC. Note that we want to make sure + // the color is not preceded by either ", " or =. Indeed, the property + // filter: chroma(color="#FFFFFF"); + // would become + // filter: chroma(color="#FFF"); + // which makes the filter break in IE. + $css = preg_replace_callback("@([^\"'=\\s])(\\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])@", array($this, '_shortenHexCB'), $css); + + // Remove empty rules. + $css = preg_replace("@[^\\}]+\\{;\\}@", "", $css); + + $linebreakpos = isset($this->_options['linebreakpos']) + ? $this->_options['linebreakpos'] + : 0; + + if ($linebreakpos > 0) { + // Some source control tools don't like it when files containing lines longer + // than, say 8000 characters, are checked in. The linebreak option is used in + // that case to split long lines after a specific column. + $i = 0; + $linestartpos = 0; + $sb = $css; + + // make sure strlen returns byte count + $mbIntEnc = null; + if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) { + $mbIntEnc = mb_internal_encoding(); + mb_internal_encoding('8bit'); + } + $sbLength = strlen($css); + while ($i < $sbLength) { + $c = $sb[$i++]; + if ($c === '}' && $i - $linestartpos > $linebreakpos) { + $sb = substr_replace($sb, "\n", $i, 0); + $sbLength++; + $linestartpos = $i; + } + } + $css = $sb; + + // undo potential mb_encoding change + if ($mbIntEnc !== null) { + mb_internal_encoding($mbIntEnc); + } + } + + // Replace the pseudo class for the Box Model Hack + $css = str_replace("___PSEUDOCLASSBMH___", "\"\\\\\"}\\\\\"\"", $css); + + // Replace multiple semi-colons in a row by a single one + // See SF bug #1980989 + $css = preg_replace("@;;+@", ";", $css); + + // prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/ + $css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css); + + // Trim the final string (for any leading or trailing white spaces) + $css = trim($css); + + return $css; + } + + protected function _removeSpacesCB($m) + { + return str_replace(':', '___PSEUDOCLASSCOLON___', $m[0]); + } + + protected function _shortenRgbCB($m) + { + $rgbcolors = explode(',', $m[1]); + $hexcolor = '#'; + for ($i = 0; $i < count($rgbcolors); $i++) { + $val = round($rgbcolors[$i]); + if ($val < 16) { + $hexcolor .= '0'; + } + $hexcolor .= dechex($val); + } + return $hexcolor; + } + + protected function _shortenHexCB($m) + { + // Test for AABBCC pattern + if ((strtolower($m[3])===strtolower($m[4])) && + (strtolower($m[5])===strtolower($m[6])) && + (strtolower($m[7])===strtolower($m[8]))) { + return $m[1] . $m[2] . "#" . $m[3] . $m[5] . $m[7]; + } else { + return $m[0]; + } + } +} \ No newline at end of file diff --git a/mrclay/minify/min/lib/Minify/YUICompressor.php b/mrclay/minify/min/lib/Minify/YUICompressor.php new file mode 100644 index 000000000000..5762e890c610 --- /dev/null +++ b/mrclay/minify/min/lib/Minify/YUICompressor.php @@ -0,0 +1,156 @@ + + * Minify_YUICompressor::$jarFile = '/path/to/yuicompressor-2.4.6.jar'; + * Minify_YUICompressor::$tempDir = '/tmp'; + * $code = Minify_YUICompressor::minifyJs( + * $code + * ,array('nomunge' => true, 'line-break' => 1000) + * ); + * + * + * Note: In case you run out stack (default is 512k), you may increase stack size in $options: + * array('stack-size' => '2048k') + * + * @todo unit tests, $options docs + * + * @package Minify + * @author Stephen Clay + */ +class Minify_YUICompressor { + + /** + * Filepath of the YUI Compressor jar file. This must be set before + * calling minifyJs() or minifyCss(). + * + * @var string + */ + public static $jarFile = null; + + /** + * Writable temp directory. This must be set before calling minifyJs() + * or minifyCss(). + * + * @var string + */ + public static $tempDir = null; + + /** + * Filepath of "java" executable (may be needed if not in shell's PATH) + * + * @var string + */ + public static $javaExecutable = 'java'; + + /** + * Minify a Javascript string + * + * @param string $js + * + * @param array $options (verbose is ignored) + * + * @see http://www.julienlecomte.net/yuicompressor/README + * + * @return string + */ + public static function minifyJs($js, $options = array()) + { + return self::_minify('js', $js, $options); + } + + /** + * Minify a CSS string + * + * @param string $css + * + * @param array $options (verbose is ignored) + * + * @see http://www.julienlecomte.net/yuicompressor/README + * + * @return string + */ + public static function minifyCss($css, $options = array()) + { + return self::_minify('css', $css, $options); + } + + private static function _minify($type, $content, $options) + { + self::_prepare(); + if (! ($tmpFile = tempnam(self::$tempDir, 'yuic_'))) { + throw new Exception('Minify_YUICompressor : could not create temp file in "'.self::$tempDir.'".'); + } + file_put_contents($tmpFile, $content); + exec(self::_getCmd($options, $type, $tmpFile), $output, $result_code); + unlink($tmpFile); + if ($result_code != 0) { + throw new Exception('Minify_YUICompressor : YUI compressor execution failed.'); + } + return implode("\n", $output); + } + + private static function _getCmd($userOptions, $type, $tmpFile) + { + $o = array_merge( + array( + 'charset' => '' + ,'line-break' => 5000 + ,'type' => $type + ,'nomunge' => false + ,'preserve-semi' => false + ,'disable-optimizations' => false + ,'stack-size' => '' + ) + ,$userOptions + ); + $cmd = self::$javaExecutable + . (!empty($o['stack-size']) + ? ' -Xss' . $o['stack-size'] + : '') + . ' -jar ' . escapeshellarg(self::$jarFile) + . " --type {$type}" + . (preg_match('/^[\\da-zA-Z0-9\\-]+$/', $o['charset']) + ? " --charset {$o['charset']}" + : '') + . (is_numeric($o['line-break']) && $o['line-break'] >= 0 + ? ' --line-break ' . (int)$o['line-break'] + : ''); + if ($type === 'js') { + foreach (array('nomunge', 'preserve-semi', 'disable-optimizations') as $opt) { + $cmd .= $o[$opt] + ? " --{$opt}" + : ''; + } + } + return $cmd . ' ' . escapeshellarg($tmpFile); + } + + private static function _prepare() + { + if (! is_file(self::$jarFile)) { + throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not a valid file.'); + } + if (! is_readable(self::$jarFile)) { + throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not readable.'); + } + if (! is_dir(self::$tempDir)) { + throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not a valid direcotry.'); + } + if (! is_writable(self::$tempDir)) { + throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not writable.'); + } + } +} + diff --git a/mrclay/minify/min/lib/MrClay/Cli.php b/mrclay/minify/min/lib/MrClay/Cli.php new file mode 100644 index 000000000000..9aa8e06f29bd --- /dev/null +++ b/mrclay/minify/min/lib/MrClay/Cli.php @@ -0,0 +1,384 @@ +values. + * + * You may also specify that some arguments be used to provide input/output. By communicating + * solely through the file pointers provided by openInput()/openOutput(), you can make your + * app more flexible to end users. + * + * @author Steve Clay + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +class Cli { + + /** + * @var array validation errors + */ + public $errors = array(); + + /** + * @var array option values available after validation. + * + * E.g. array( + * 'a' => false // option was missing + * ,'b' => true // option was present + * ,'c' => "Hello" // option had value + * ,'f' => "/home/user/file" // file path from root + * ,'f.raw' => "~/file" // file path as given to option + * ) + */ + public $values = array(); + + /** + * @var array + */ + public $moreArgs = array(); + + /** + * @var array + */ + public $debug = array(); + + /** + * @var bool The user wants help info + */ + public $isHelpRequest = false; + + /** + * @var Arg[] + */ + protected $_args = array(); + + /** + * @var resource + */ + protected $_stdin = null; + + /** + * @var resource + */ + protected $_stdout = null; + + /** + * @param bool $exitIfNoStdin (default true) Exit() if STDIN is not defined + */ + public function __construct($exitIfNoStdin = true) + { + if ($exitIfNoStdin && ! defined('STDIN')) { + exit('This script is for command-line use only.'); + } + if (isset($GLOBALS['argv'][1]) + && ($GLOBALS['argv'][1] === '-?' || $GLOBALS['argv'][1] === '--help')) { + $this->isHelpRequest = true; + } + } + + /** + * @param Arg|string $letter + * @return Arg + */ + public function addOptionalArg($letter) + { + return $this->addArgument($letter, false); + } + + /** + * @param Arg|string $letter + * @return Arg + */ + public function addRequiredArg($letter) + { + return $this->addArgument($letter, true); + } + + /** + * @param string $letter + * @param bool $required + * @param Arg|null $arg + * @return Arg + * @throws InvalidArgumentException + */ + public function addArgument($letter, $required, Arg $arg = null) + { + if (! preg_match('/^[a-zA-Z]$/', $letter)) { + throw new InvalidArgumentException('$letter must be in [a-zA-Z]'); + } + if (! $arg) { + $arg = new Arg($required); + } + $this->_args[$letter] = $arg; + return $arg; + } + + /** + * @param string $letter + * @return Arg|null + */ + public function getArgument($letter) + { + return isset($this->_args[$letter]) ? $this->_args[$letter] : null; + } + + /* + * Read and validate options + * + * @return bool true if all options are valid + */ + public function validate() + { + $options = ''; + $this->errors = array(); + $this->values = array(); + $this->_stdin = null; + + if ($this->isHelpRequest) { + return false; + } + + $lettersUsed = ''; + foreach ($this->_args as $letter => $arg) { + /* @var Arg $arg */ + $options .= $letter; + $lettersUsed .= $letter; + + if ($arg->mayHaveValue || $arg->mustHaveValue) { + $options .= ($arg->mustHaveValue ? ':' : '::'); + } + } + + $this->debug['argv'] = $GLOBALS['argv']; + $argvCopy = array_slice($GLOBALS['argv'], 1); + $o = getopt($options); + $this->debug['getopt_options'] = $options; + $this->debug['getopt_return'] = $o; + + foreach ($this->_args as $letter => $arg) { + /* @var Arg $arg */ + $this->values[$letter] = false; + if (isset($o[$letter])) { + if (is_bool($o[$letter])) { + + // remove from argv copy + $k = array_search("-$letter", $argvCopy); + if ($k !== false) { + array_splice($argvCopy, $k, 1); + } + + if ($arg->mustHaveValue) { + $this->addError($letter, "Missing value"); + } else { + $this->values[$letter] = true; + } + } else { + // string + $this->values[$letter] = $o[$letter]; + $v =& $this->values[$letter]; + + // remove from argv copy + // first look for -ovalue or -o=value + $pattern = "/^-{$letter}=?" . preg_quote($v, '/') . "$/"; + $foundInArgv = false; + foreach ($argvCopy as $k => $argV) { + if (preg_match($pattern, $argV)) { + array_splice($argvCopy, $k, 1); + $foundInArgv = true; + break; + } + } + if (! $foundInArgv) { + // space separated + $k = array_search("-$letter", $argvCopy); + if ($k !== false) { + array_splice($argvCopy, $k, 2); + } + } + + // check that value isn't really another option + if (strlen($lettersUsed) > 1) { + $pattern = "/^-[" . str_replace($letter, '', $lettersUsed) . "]/i"; + if (preg_match($pattern, $v)) { + $this->addError($letter, "Value was read as another option: %s", $v); + return false; + } + } + if ($arg->assertFile || $arg->assertDir) { + if ($v[0] !== '/' && $v[0] !== '~') { + $this->values["$letter.raw"] = $v; + $v = getcwd() . "/$v"; + } + } + if ($arg->assertFile) { + if ($arg->useAsInfile) { + $this->_stdin = $v; + } elseif ($arg->useAsOutfile) { + $this->_stdout = $v; + } + if ($arg->assertReadable && ! is_readable($v)) { + $this->addError($letter, "File not readable: %s", $v); + continue; + } + if ($arg->assertWritable) { + if (is_file($v)) { + if (! is_writable($v)) { + $this->addError($letter, "File not writable: %s", $v); + } + } else { + if (! is_writable(dirname($v))) { + $this->addError($letter, "Directory not writable: %s", dirname($v)); + } + } + } + } elseif ($arg->assertDir && $arg->assertWritable && ! is_writable($v)) { + $this->addError($letter, "Directory not readable: %s", $v); + } + } + } else { + if ($arg->isRequired()) { + $this->addError($letter, "Missing"); + } + } + } + $this->moreArgs = $argvCopy; + reset($this->moreArgs); + return empty($this->errors); + } + + /** + * Get the full paths of file(s) passed in as unspecified arguments + * + * @return array + */ + public function getPathArgs() + { + $r = $this->moreArgs; + foreach ($r as $k => $v) { + if ($v[0] !== '/' && $v[0] !== '~') { + $v = getcwd() . "/$v"; + $v = str_replace('/./', '/', $v); + do { + $v = preg_replace('@/[^/]+/\\.\\./@', '/', $v, 1, $changed); + } while ($changed); + $r[$k] = $v; + } + } + return $r; + } + + /** + * Get a short list of errors with options + * + * @return string + */ + public function getErrorReport() + { + if (empty($this->errors)) { + return ''; + } + $r = "Some arguments did not pass validation:\n"; + foreach ($this->errors as $letter => $arr) { + $r .= " $letter : " . implode(', ', $arr) . "\n"; + } + $r .= "\n"; + return $r; + } + + /** + * @return string + */ + public function getArgumentsListing() + { + $r = "\n"; + foreach ($this->_args as $letter => $arg) { + /* @var Arg $arg */ + $desc = $arg->getDescription(); + $flag = " -$letter "; + if ($arg->mayHaveValue) { + $flag .= "[VAL]"; + } elseif ($arg->mustHaveValue) { + $flag .= "VAL"; + } + if ($arg->assertFile) { + $flag = str_replace('VAL', 'FILE', $flag); + } elseif ($arg->assertDir) { + $flag = str_replace('VAL', 'DIR', $flag); + } + if ($arg->isRequired()) { + $desc = "(required) $desc"; + } + $flag = str_pad($flag, 12, " ", STR_PAD_RIGHT); + $desc = wordwrap($desc, 70); + $r .= $flag . str_replace("\n", "\n ", $desc) . "\n\n"; + } + return $r; + } + + /** + * Get resource of open input stream. May be STDIN or a file pointer + * to the file specified by an option with 'STDIN'. + * + * @return resource + */ + public function openInput() + { + if (null === $this->_stdin) { + return STDIN; + } else { + $this->_stdin = fopen($this->_stdin, 'rb'); + return $this->_stdin; + } + } + + public function closeInput() + { + if (null !== $this->_stdin) { + fclose($this->_stdin); + } + } + + /** + * Get resource of open output stream. May be STDOUT or a file pointer + * to the file specified by an option with 'STDOUT'. The file will be + * truncated to 0 bytes on opening. + * + * @return resource + */ + public function openOutput() + { + if (null === $this->_stdout) { + return STDOUT; + } else { + $this->_stdout = fopen($this->_stdout, 'wb'); + return $this->_stdout; + } + } + + public function closeOutput() + { + if (null !== $this->_stdout) { + fclose($this->_stdout); + } + } + + /** + * @param string $letter + * @param string $msg + * @param string $value + */ + protected function addError($letter, $msg, $value = null) + { + if ($value !== null) { + $value = var_export($value, 1); + } + $this->errors[$letter][] = sprintf($msg, $value); + } +} + diff --git a/mrclay/minify/min/lib/MrClay/Cli/Arg.php b/mrclay/minify/min/lib/MrClay/Cli/Arg.php new file mode 100644 index 000000000000..5fa5932734e4 --- /dev/null +++ b/mrclay/minify/min/lib/MrClay/Cli/Arg.php @@ -0,0 +1,183 @@ +values['f.raw'] + * + * Use assertReadable()/assertWritable() to cause the validator to test the file/dir for + * read/write permissions respectively. + * + * @method \MrClay\Cli\Arg mayHaveValue() Assert that the argument, if present, may receive a string value + * @method \MrClay\Cli\Arg mustHaveValue() Assert that the argument, if present, must receive a string value + * @method \MrClay\Cli\Arg assertFile() Assert that the argument's value must specify a file + * @method \MrClay\Cli\Arg assertDir() Assert that the argument's value must specify a directory + * @method \MrClay\Cli\Arg assertReadable() Assert that the specified file/dir must be readable + * @method \MrClay\Cli\Arg assertWritable() Assert that the specified file/dir must be writable + * + * @property-read bool mayHaveValue + * @property-read bool mustHaveValue + * @property-read bool assertFile + * @property-read bool assertDir + * @property-read bool assertReadable + * @property-read bool assertWritable + * @property-read bool useAsInfile + * @property-read bool useAsOutfile + * + * @author Steve Clay + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ +class Arg { + /** + * @return array + */ + public function getDefaultSpec() + { + return array( + 'mayHaveValue' => false, + 'mustHaveValue' => false, + 'assertFile' => false, + 'assertDir' => false, + 'assertReadable' => false, + 'assertWritable' => false, + 'useAsInfile' => false, + 'useAsOutfile' => false, + ); + } + + /** + * @var array + */ + protected $spec = array(); + + /** + * @var bool + */ + protected $required = false; + + /** + * @var string + */ + protected $description = ''; + + /** + * @param bool $isRequired + */ + public function __construct($isRequired = false) + { + $this->spec = $this->getDefaultSpec(); + $this->required = (bool) $isRequired; + if ($isRequired) { + $this->spec['mustHaveValue'] = true; + } + } + + /** + * Assert that the argument's value points to a writable file. When + * Cli::openOutput() is called, a write pointer to this file will + * be provided. + * @return Arg + */ + public function useAsOutfile() + { + $this->spec['useAsOutfile'] = true; + return $this->assertFile()->assertWritable(); + } + + /** + * Assert that the argument's value points to a readable file. When + * Cli::openInput() is called, a read pointer to this file will + * be provided. + * @return Arg + */ + public function useAsInfile() + { + $this->spec['useAsInfile'] = true; + return $this->assertFile()->assertReadable(); + } + + /** + * @return array + */ + public function getSpec() + { + return $this->spec; + } + + /** + * @param string $desc + * @return Arg + */ + public function setDescription($desc) + { + $this->description = $desc; + return $this; + } + + /** + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * @return bool + */ + public function isRequired() + { + return $this->required; + } + + /** + * Note: magic methods declared in class PHPDOC + * + * @param string $name + * @param array $args + * @return Arg + * @throws BadMethodCallException + */ + public function __call($name, array $args = array()) + { + if (array_key_exists($name, $this->spec)) { + $this->spec[$name] = true; + if ($name === 'assertFile' || $name === 'assertDir') { + $this->spec['mustHaveValue'] = true; + } + } else { + throw new BadMethodCallException('Method does not exist'); + } + return $this; + } + + /** + * Note: magic properties declared in class PHPDOC + * + * @param string $name + * @return bool|null + */ + public function __get($name) + { + if (array_key_exists($name, $this->spec)) { + return $this->spec[$name]; + } + return null; + } +} diff --git a/mrclay/minify/min/quick-test.css b/mrclay/minify/min/quick-test.css new file mode 100644 index 000000000000..2d9e402bfaa6 --- /dev/null +++ b/mrclay/minify/min/quick-test.css @@ -0,0 +1,30 @@ +/*! This file exists only for testing a Minify installation. It's content is not used. + * + * http://example.org/min/f=min/quick-test.css + */ + +@import url( more.css ); + + body, td, th { + font-family: Verdana , "Bitstream Vera Sans" , Arial Narrow, sans-serif ; + + font-size : 12px; +} + +.nav { + margin-left: 20%; +} +#main-nav { + background-color: red; + border: 1px solid #00ff77; +} + +div#content +h1 + p { + padding-top: 0; + margin-top: 0; +} + +@media all and (min-width: 640px) { + #media-queries-1 { background-color: #0f0; } +} diff --git a/mrclay/minify/min/quick-test.js b/mrclay/minify/min/quick-test.js new file mode 100644 index 000000000000..eceb3584ffb0 --- /dev/null +++ b/mrclay/minify/min/quick-test.js @@ -0,0 +1,74 @@ +/*! This file exists only for testing a Minify installation. It's content is not used. + * + * http://example.org/min/f=min/quick-test.js + */ + +/* Finds the lowest common multiple of two numbers */ +function LCMCalculator(x, y) { // constructor function + var checkInt = function (x) { // inner function + if (x % 1 !== 0) { + throw new TypeError(x + " is not an integer"); // throw an exception + } + return x; + }; + this.a = checkInt(x); + // ^ semicolons are optional + this.b = checkInt(y); +} +// The prototype of object instances created by a constructor is +// that constructor's "prototype" property. +LCMCalculator.prototype = { // object literal + constructor: LCMCalculator, // when reassigning a prototype, set the constructor property appropriately + gcd: function () { // method that calculates the greatest common divisor + // Euclidean algorithm: + var a = Math.abs(this.a), b = Math.abs(this.b), t; + if (a < b) { + // swap variables + t = b; + b = a; + a = t; + } + while (b !== 0) { + t = b; + b = a % b; + a = t; + } + // Only need to calculate GCD once, so "redefine" this method. + // (Actually not redefinition - it's defined on the instance itself, + // so that this.gcd refers to this "redefinition" instead of LCMCalculator.prototype.gcd.) + // Also, 'gcd' === "gcd", this['gcd'] === this.gcd + this['gcd'] = function () { + return a; + }; + return a; + }, + // Object property names can be specified by strings delimited by double (") or single (') quotes. + "lcm" : function () { + // Variable names don't collide with object properties, e.g. |lcm| is not |this.lcm|. + // not using |this.a * this.b| to avoid FP precision issues + var lcm = this.a / this.gcd() * this.b; + // Only need to calculate lcm once, so "redefine" this method. + this.lcm = function () { + return lcm; + }; + return lcm; + }, + toString: function () { + return "LCMCalculator: a = " + this.a + ", b = " + this.b; + } +}; + +//define generic output function; this implementation only works for web browsers +function output(x) { + document.write(x + "
    "); +} + +// Note: Array's map() and forEach() are defined in JavaScript 1.6. +// They are used here to demonstrate JavaScript's inherent functional nature. +[[25, 55], [21, 56], [22, 58], [28, 56]].map(function (pair) { // array literal + mapping function + return new LCMCalculator(pair[0], pair[1]); +}).sort(function (a, b) { // sort with this comparative function + return a.lcm() - b.lcm(); +}).forEach(function (obj) { + output(obj + ", gcd = " + obj.gcd() + ", lcm = " + obj.lcm()); +}); \ No newline at end of file diff --git a/mrclay/minify/min/utils.php b/mrclay/minify/min/utils.php new file mode 100644 index 000000000000..7cf930ac9012 --- /dev/null +++ b/mrclay/minify/min/utils.php @@ -0,0 +1,81 @@ + + * + * + * + * + * + * @param mixed $keyOrFiles a group key or array of file paths/URIs + * @param array $opts options: + * 'farExpires' : (default true) append a modified timestamp for cache revving + * 'debug' : (default false) append debug flag + * 'charset' : (default 'UTF-8') for htmlspecialchars + * 'minAppUri' : (default '/min') URI of min directory + * 'rewriteWorks' : (default true) does mod_rewrite work in min app? + * 'groupsConfigFile' : specify if different + * @return string + */ +function Minify_getUri($keyOrFiles, $opts = array()) +{ + return Minify_HTML_Helper::getUri($keyOrFiles, $opts); +} + + +/** + * Get the last modification time of several source js/css files. If you're + * caching the output of Minify_getUri(), you might want to know if one of the + * dependent source files has changed so you can update the HTML. + * + * Since this makes a bunch of stat() calls, you might not want to check this + * on every request. + * + * @param array $keysAndFiles group keys and/or file paths/URIs. + * @return int latest modification time of all given keys/files + */ +function Minify_mtime($keysAndFiles, $groupsConfigFile = null) +{ + $gc = null; + if (! $groupsConfigFile) { + $groupsConfigFile = dirname(__FILE__) . '/groupsConfig.php'; + } + $sources = array(); + foreach ($keysAndFiles as $keyOrFile) { + if (is_object($keyOrFile) + || 0 === strpos($keyOrFile, '/') + || 1 === strpos($keyOrFile, ':\\')) { + // a file/source obj + $sources[] = $keyOrFile; + } else { + if (! $gc) { + $gc = (require $groupsConfigFile); + } + foreach ($gc[$keyOrFile] as $source) { + $sources[] = $source; + } + } + } + return Minify_HTML_Helper::getLastModified($sources); +} diff --git a/mrclay/minify/min_extras/README.txt b/mrclay/minify/min_extras/README.txt new file mode 100644 index 000000000000..1fef8a8bd190 --- /dev/null +++ b/mrclay/minify/min_extras/README.txt @@ -0,0 +1,11 @@ +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +DO NOT leave this directory on a site in production. Some scripts within may be +resource intensive and some allow file uploads. +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +This directory contains testing scripts and a few example applications built +with the Minify library classes. + +tools/ + Two utility web apps that upload a file, alter it, and send it back to the + user. One applies HTTP encoding, the other minifies CSS/JS/HTML. diff --git a/mrclay/minify/min_extras/cli/minify.php b/mrclay/minify/min_extras/cli/minify.php new file mode 100755 index 000000000000..e0c4b15c8dff --- /dev/null +++ b/mrclay/minify/min_extras/cli/minify.php @@ -0,0 +1,82 @@ +#!/usr/bin/env php +addOptionalArg('d')->assertDir()->setDescription('Your webserver\'s DOCUMENT_ROOT: Relative paths will be rewritten relative to this path. This is required if you\'re passing in CSS.'); + +$cli->addOptionalArg('o')->useAsOutfile()->setDescription('Outfile: If given, output will be placed in this file.'); + +$cli->addOptionalArg('t')->mustHaveValue()->setDescription('Type: must be "css", "js", or "html". This must be provided if passing content via STDIN.'); + +if (! $cli->validate()) { + if ($cli->isHelpRequest) { + echo "The Minify CLI tool!\n\n"; + } + echo "USAGE: ./minify.php [-t TYPE] [-d DOC_ROOT] [-o OUTFILE] file ...\n"; + if ($cli->isHelpRequest) { + echo $cli->getArgumentsListing(); + } + echo "EXAMPLE: ./minify.php ../../min_unit_tests/_test_files/js/*.js\n"; + echo "EXAMPLE: ./minify.php -d../.. ../../min_unit_tests/_test_files/css/*.css\n"; + echo "EXAMPLE: echo \"var js = 'Awesome' && /cool/;\" | ./minify.php -t js\n"; + echo "EXAMPLE: echo \"sel > ector { prop: 'value '; }\" | ./minify.php -t css\n"; + echo "\n"; + exit(0); +} + +$outfile = $cli->values['o']; +$docRoot = $cli->values['d']; +$type = $cli->values['t']; + +if (is_string($type)) { + if (! in_array($type, array('js', 'css', 'html'))) { + echo "Type argument invalid\n"; + exit(1); + } + $type = constant('Minify::TYPE_' . strtoupper($type)); +} + +$paths = $cli->getPathArgs(); +$sources = array(); + +if ($paths) { + foreach ($paths as $path) { + if (is_file($path)) { + $sources[] = new Minify_Source(array( + 'filepath' => $path, + 'minifyOptions' => array('docRoot' => $docRoot), + )); + } else { + $sources[] = new Minify_Source(array( + 'id' => $path, + 'content' => "/*** $path not found ***/\n", + 'minifier' => '', + )); + } + } +} else { + // not paths input, expect STDIN + if (! $type) { + echo "Type must be specified to use STDIN\n"; + exit(1); + } + $in = $cli->openInput(); + $sources[] = new Minify_Source(array( + 'id' => 'one', + 'content' => stream_get_contents($in), + 'contentType' => $type, + )); + $cli->closeInput(); +} + +$combined = Minify::combine($sources) . "\n"; + +$fp = $cli->openOutput(); +fwrite($fp, $combined); +$cli->closeOutput(); diff --git a/mrclay/minify/min_extras/cli/rewrite-uris.php b/mrclay/minify/min_extras/cli/rewrite-uris.php new file mode 100755 index 000000000000..e0cbfa500a75 --- /dev/null +++ b/mrclay/minify/min_extras/cli/rewrite-uris.php @@ -0,0 +1,63 @@ +#!/usr/bin/php +addRequiredArg('d')->assertDir()->setDescription('Your webserver\'s DOCUMENT_ROOT: Relative paths will be rewritten relative to this path.'); + +$cli->addOptionalArg('o')->useAsOutfile()->setDescription('Outfile: If given, output will be placed in this file.'); + +$cli->addOptionalArg('t')->setDescription('Test run: Return output followed by rewriting algorithm.'); + +if (! $cli->validate()) { + echo "USAGE: ./rewrite-uris.php [-t] -d DOC_ROOT [-o OUTFILE] file ...\n"; + if ($cli->isHelpRequest) { + echo $cli->getArgumentsListing(); + } + echo "EXAMPLE: ./rewrite-uris.php -v -d../.. ../../min_unit_tests/_test_files/css/paths_rewrite.css ../../min_unit_tests/_test_files/css/comments.css + \n"; + exit(0); +} + +$outfile = $cli->values['o']; +$testRun = $cli->values['t']; +$docRoot = $cli->values['d']; + +$pathRewriter = function($css, $options) { + return Minify_CSS_UriRewriter::rewrite($css, $options['currentDir'], $options['docRoot']); +}; + +$paths = $cli->getPathArgs(); + +$sources = array(); +foreach ($paths as $path) { + if (is_file($path)) { + $sources[] = new Minify_Source(array( + 'filepath' => $path, + 'minifier' => $pathRewriter, + 'minifyOptions' => array('docRoot' => $docRoot), + )); + } else { + $sources[] = new Minify_Source(array( + 'id' => $path, + 'content' => "/*** $path not found ***/\n", + 'minifier' => '', + )); + } +} +$combined = Minify::combine($sources) . "\n"; + +if ($testRun) { + echo $combined; + echo Minify_CSS_UriRewriter::$debugText . "\n"; +} else { + $fp = $cli->openOutput(); + fwrite($fp, $combined); + $cli->closeOutput(); +} + diff --git a/mrclay/minify/min_extras/config.php b/mrclay/minify/min_extras/config.php new file mode 100644 index 000000000000..b44bceb8ac38 --- /dev/null +++ b/mrclay/minify/min_extras/config.php @@ -0,0 +1,12 @@ +]*>)@i' + ,'$1' + ,$textIn + ); + } + + $sourceSpec['content'] = $textIn; + $sourceSpec['id'] = 'foo'; + if (isset($_POST['minJs'])) { + $sourceSpec['minifyOptions']['jsMinifier'] = array('JSMin', 'minify'); + } + if (isset($_POST['minCss'])) { + $sourceSpec['minifyOptions']['cssMinifier'] = array('Minify_CSS', 'minify'); + } + $source = new Minify_Source($sourceSpec); + Minify_Logger::setLogger(FirePHP::getInstance(true)); + try { + Minify::serve('Files', array( + 'files' => $source + ,'contentType' => Minify::TYPE_HTML + )); + } catch (Exception $e) { + echo h($e->getMessage()); + } + exit; +} + +$tpl = array(); +$tpl['classes'] = array('Minify_HTML', 'JSMin', 'Minify_CSS', 'Minify_CSSmin', 'JSMinPlus'); + +if (isset($_POST['method']) && in_array($_POST['method'], $tpl['classes'])) { + + $args = array($textIn); + if ($_POST['method'] === 'Minify_HTML') { + $args[] = array( + 'cssMinifier' => array('Minify_CSS', 'minify') + ,'jsMinifier' => array('JSMin', 'minify') + ); + } + $func = array($_POST['method'], 'minify'); + $tpl['inBytes'] = strlen($textIn); + $startTime = microtime(true); + try { + $tpl['output'] = call_user_func_array($func, $args); + } catch (Exception $e) { + $tpl['exceptionMsg'] = getExceptionMsg($e, $textIn); + $tpl['output'] = $textIn; + sendPage($tpl); + } + $tpl['time'] = microtime(true) - $startTime; + $tpl['outBytes'] = strlen($tpl['output']); +} + +sendPage($tpl); + + +/** + * @param Exception $e + * @param string $input + * @return string HTML + */ +function getExceptionMsg(Exception $e, $input) { + $msg = "

    " . h($e->getMessage()) . "

    "; + if (0 === strpos(get_class($e), 'JSMin_Unterminated') + && preg_match('~byte (\d+)~', $e->getMessage(), $m)) { + $msg .= "
    ";
    +        if ($m[1] > 200) {
    +            $msg .= h(substr($input, ($m[1] - 200), 200));
    +        } else {
    +            $msg .= h(substr($input, 0, $m[1]));
    +        }
    +        $highlighted = isset($input[$m[1]]) ? h($input[$m[1]]) : '␄';
    +        if ($highlighted === "\n") {
    +            $highlighted = "⏎\n";
    +        }
    +        $msg .= "$highlighted";
    +        $msg .= h(substr($input, $m[1] + 1, 200)) . "
    "; + } + return $msg; +} + +/** + * Draw page + * + * @param array $vars + */ +function sendPage($vars) { + header('Content-Type: text/html; charset=utf-8'); +?> +minifyTextarea + + Bytes in{$vars['inBytes']} (after line endings normalized to \\n) + Bytes out{$vars['outBytes']} (reduced " . round(100 - (100 * $vars['outBytes'] / $vars['inBytes'])) . "%) + Time (s)" . round($vars['time'], 5) . " + + "; +} +?> +
    +

    +

    Minify with: + + + +

    +

    ...or this HTML to the browser. Also minify: + : +. + +

    +
    + + + $type + ,'sent' => $sentType + ,'charset' => $charset + ); +} + +if (isset($_POST['url'])) { + + require '../config.php'; + + $url = trim(getPost('url')); + $ua = trim(getPost('ua')); + $cook = trim(getPost('cook')); + + if (! preg_match('@^https?://@', $url)) { + die('HTTP(s) only.'); + } + + $httpOpts = array( + 'max_redirects' => 0 + ,'timeout' => 3 + ); + if ($ua !== '') { + $httpOpts['user_agent'] = $ua; + } + if ($cook !== '') { + $httpOpts['header'] = "Cookie: {$cook}\r\n"; + } + $ctx = stream_context_create(array( + 'http' => $httpOpts + )); + + // fetch + if (! ($fp = @fopen($url, 'r', false, $ctx))) { + die('Couldn\'t open URL.'); + } + $meta = stream_get_meta_data($fp); + $content = stream_get_contents($fp); + fclose($fp); + + // get type info + $type = sniffType($meta['wrapper_data']); + if (! $type['minify']) { + die('Unrecognized Content-Type: ' . $type['sent']); + } + + if ($type['minify'] === 'text/html' + && isset($_POST['addBase']) + && ! preg_match('@]*>)@i' + ,'$1' + ,$content + ); + } + + $sourceSpec['content'] = $content; + $sourceSpec['id'] = 'foo'; + + if ($type['minify'] === 'text/html') { + if (isset($_POST['minJs'])) { + $sourceSpec['minifyOptions']['jsMinifier'] = array('JSMin', 'minify'); + } + if (isset($_POST['minCss'])) { + $sourceSpec['minifyOptions']['cssMinifier'] = array('Minify_CSS', 'minify'); + } + } + + $source = new Minify_Source($sourceSpec); + + $sendType = 'text/plain'; + if ($type['minify'] === 'text/html' && ! isset($_POST['asText'])) { + $sendType = $type['sent']; + } + if ($type['charset']) { + $sendType .= ';charset=' . $type['charset']; + } + header('Content-Type: ' . $sendType); + // using combine instead of serve because it allows us to specify a + // Content-Type like application/xhtml+xml IF we need to + try { + echo Minify::combine(array($source), array( + 'contentType' => $type['minify'] + )); + } catch (Exception $e) { + header('Content-Type: text/html;charset=utf-8'); + echo htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8'); + } + exit(); +} + +header('Content-Type: text/html; charset=utf-8'); + +$ua = get_magic_quotes_gpc() + ? stripslashes($_SERVER['HTTP_USER_AGENT']) + : $_SERVER['HTTP_USER_AGENT']; + +?> +Minify URL + +

    Warning! Please do not place this application on a public site. This should be used +only for testing.

    + +

    Fetch and Minify a URL

    +

    This tool will retrieve the contents of a URL and minify it. +The fetched resource Content-Type will determine the minifier used.

    + +
    +

    +

    + +
    HTML options +

    If the resource above is sent with an (x)HTML Content-Type, the following options will apply:

    +
      +
    • +
    • +
    • +
    • +
    +
    + +
    Retreival options +
      +
    • +
    • +
    +
    + +
    diff --git a/mrclay/minify/min_extras/tools/testRewriteUri.php b/mrclay/minify/min_extras/tools/testRewriteUri.php new file mode 100644 index 000000000000..b40d9d8818ad --- /dev/null +++ b/mrclay/minify/min_extras/tools/testRewriteUri.php @@ -0,0 +1,58 @@ +"; +} + +// validate user POST (no arrays and fix slashes) +if (! empty($_POST)) { + foreach ($_POST as $name => $val) { + if (! is_string($val)) { + unset($_POST[$name]); + continue; + } + if (get_magic_quotes_gpc()) { + $_POST[$name] = stripslashes($val); + } + } +} + +$defaultCurrentDir = dirname(__FILE__); +$defaultDocRoot = realpath($_SERVER['DOCUMENT_ROOT']); +$defaultSymLink = '//symlinkPath'; +$defaultSymTarget = ($defaultCurrentDir[0] === '/') ? '/tmp' : 'C:\\WINDOWS\\Temp'; +$defaultCss = "url(hello.gif)\nurl(../hello.gif)\nurl(../../hello.gif)\nurl(up/hello.gif)"; + +$out = ''; + +if (isset($_POST['css'])) { + require '../config.php'; + $symlinks = array(); + if ('' !== ($target = getPost('symTarget'))) { + $symlinks[getPost('symLink')] = $target; + } + $css = Minify_CSS_UriRewriter::rewrite( + getPost('css') + , getPost('currentDir') + , getPost('docRoot') + , $symlinks + ); + $out = "
    " . h($css) . '
    '; +} + +?> +

    Test Minify_CSS_UriRewriter::rewrite()

    +
    +
    +
    +
    +

    +

    +
    + \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/.htaccess b/mrclay/minify/min_unit_tests/.htaccess new file mode 100644 index 000000000000..4e05c4c922e8 --- /dev/null +++ b/mrclay/minify/min_unit_tests/.htaccess @@ -0,0 +1,4 @@ + +# In case AddOutputFilterByType has been added +SetEnv no-gzip + diff --git a/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/2.php b/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/2.php new file mode 100644 index 000000000000..9b66f2493257 --- /dev/null +++ b/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/2.php @@ -0,0 +1,44 @@ + $lastModified +)); +if ($cg->cacheIsValid) { + $cg->sendHeaders(); + // we're done + exit(); +} + +// generate content +$title = 'Last-Modified is known : add Content-Length'; +$explain = ' +

    Here, like the first example, we know the Last-Modified time, +but we also want to set the Content-Length to increase cacheability and allow +HTTP persistent connections. Instead of sending headers immediately, we first +generate our content, then use setContentLength(strlen($content)) +to add the header. Then finally call sendHeaders() and send the +content.

    +

    Note: This is not required if your PHP config buffers all +output and your script doesn\'t do any incremental flushing of the output +buffer. PHP will generally set Content-Length for you if it can.

    +

    This script emulates a document that changes every ' .$every. ' seconds. +
    This is version: ' . date('r', $lastModified) . '

    +'; + +require '_include.php'; +$content = get_content(array( + 'title' => $title + ,'explain' => $explain +)); + +$cg->setContentLength(strlen($content)); +$cg->sendHeaders(); +send_slowly($content); + diff --git a/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/3.php b/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/3.php new file mode 100644 index 000000000000..b787c953902a --- /dev/null +++ b/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/3.php @@ -0,0 +1,40 @@ +When Last-Modified is unknown, you can still use ETags, but you need a short +string that is unique for that content. In the worst case, you have to generate +all the content first, then instantiate HTTP_ConditionalGet, setting +the array key contentHash to the output of a hash function of the +content. Since we have the full content, we might as well also use +setContentLength(strlen($content)) in the case where we need to +send it.

    +

    This script emulates a document that changes every ' .$every. ' seconds. +
    This is version: ' . date('r', $lastModified) . '

    +'; +require '_include.php'; +$content = get_content(array( + 'title' => $title + ,'explain' => $explain +)); + +$cg = new HTTP_ConditionalGet(array( + 'contentHash' => substr(md5($content), 7) +)); +if ($cg->cacheIsValid) { + $cg->sendHeaders(); + // we're done + exit(); +} +$cg->setContentLength(strlen($content)); +$cg->sendHeaders(); + +send_slowly($content); + diff --git a/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/4.php b/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/4.php new file mode 100644 index 000000000000..4b77d2084bdd --- /dev/null +++ b/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/4.php @@ -0,0 +1,49 @@ + $lastModified + ,'encoding' => $enc +)); +$cg->sendHeaders(); +if ($cg->cacheIsValid) { + // we're done + exit(); +} + +// output encoded content + +$title = 'ConditionalGet + Encoder'; +$explain = ' +

    Using ConditionalGet and Encoder is straightforward. First impliment the +ConditionalGet, then if the cache is not valid, encode and send the content

    +

    This script emulates a document that changes every ' .$every. ' seconds. +
    This is version: ' . date('r', $lastModified) . '

    +'; +require '_include.php'; +$content = get_content(array( + 'title' => $title + ,'explain' => $explain +)); + +$he = new HTTP_Encoder(array( + 'content' => get_content(array( + 'title' => $title + ,'explain' => $explain + )) +)); +$he->encode(); + +// usually you would just $he->sendAll(), but here we want to emulate slow +// connection +$he->sendHeaders(); +send_slowly($he->getContent()); diff --git a/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/5.php b/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/5.php new file mode 100644 index 000000000000..b443c19734fd --- /dev/null +++ b/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/5.php @@ -0,0 +1,27 @@ + 20 + ,'lastModifiedTime' => filemtime(__FILE__) +)); +$cg->sendHeaders(); + +// generate, send content +$title = 'Last-Modified + Expires'; +$explain = ' +

    Here we set a static "lastModifiedTime" and "maxAge" to 20. The browser +will consider this document fresh for 20 seconds, then revalidate its cache. After +the 304 response, the cache will be good for another 20 seconds. Unless you force +a reload, there will only be 304 responses for this page after the initial download. +'; + +require '_include.php'; +echo get_content(array( + 'title' => $title + ,'explain' => $explain +)); + diff --git a/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/_include.php b/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/_include.php new file mode 100644 index 000000000000..c99a4f2ab2ce --- /dev/null +++ b/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/_include.php @@ -0,0 +1,64 @@ + + + + + +HTTP_ConditionalGet : <?php echo $data['title']; ?> + + +

    HTTP_ConditionalGet

    +

    + + +

    Notes

    +

    How to distinguish 200 and 304 responses

    +

    For these pages all 200 responses are sent in chunks a second apart, so you +should notice that 304 responses are quicker. You can also use HTTP sniffers +like Fiddler (win) and +LiveHTTPHeaders (Firefox add-on) +to verify headers and content being sent.

    +

    Browser notes

    +
    +
    Opera
    +
    Opera has a couple behaviors against the HTTP spec: Manual refreshes (F5) + prevents the ETag/If-Modified-Since headers from being sent; it only sends + them when following a link or bookmark. Also, Opera will not honor the + must-revalidate Cache-Control value unless max-age + is set. To get Opera to follow the spec, ConditionalGet will send Opera max-age=0 + (if one is not already set).
    +
    Safari
    +
    ETag validation is unsupported, but Safari supports HTTP/1.0 validation via + If-Modified-Since headers as long as the cache is explicitly marked + "public" or "private" ("private" is default in ConditionalGet).
    +
    + + + $lastModified +)); +$cg->sendHeaders(); +if ($cg->cacheIsValid) { + // we're done + exit(); +} + +$title = 'Last-Modified is known : simple usage'; +$explain = ' +

    If your content has not changed since a certain timestamp, set this via the +the lastModifiedTime array key when instantiating HTTP_ConditionalGet. +You can immediately call the method sendHeaders() to set the +Last-Modified, ETag, and Cache-Control headers. The, if cacheIsValid +property is false, you echo the content.

    +

    This script emulates a document that changes every ' .$every. ' seconds. +
    This is version: ' . date('r', $lastModified) . '

    +'; + +require '_include.php'; + +echo send_slowly(get_content(array( + 'title' => $title + ,'explain' => $explain +))); + diff --git a/mrclay/minify/min_unit_tests/HTTP_Encoder/green.png b/mrclay/minify/min_unit_tests/HTTP_Encoder/green.png new file mode 100644 index 0000000000000000000000000000000000000000..d9d3a308aec0e9c7be676a8bc5438e5c61427ff2 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_{3?x-PN__%S%*9TgAsieWw;%dH0CL#^d_r6q z{xkglf9682r8`iBv%n*=n1O-o0|+xZtudJa6cj6QjVN(0N=+=u%+FH@$;?efo0^iDsNj}alv + + + +HTTP_Encoder Test + + + +

    HTTP_Encoder test

    +

    HTML

    +

    CSS

    +

    Javascript

    +

    image

    + + + + $content + ,'type' => $type +)); +$he->encode(); +$he->sendAll(); + +?> \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_inc.php b/mrclay/minify/min_unit_tests/_inc.php new file mode 100644 index 000000000000..197ed9567f04 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_inc.php @@ -0,0 +1,62 @@ +0, 'fail'=>0, 'total'=>0); + + $mode = $test ? 'pass' : 'fail'; + $outMode = $test ? 'PASS' : '!FAIL'; + printf("%s: %s (%d of %d tests run so far have %sed)\n", + $outMode, $message, ++$count[$mode], ++$count['total'], $mode); + + return (bool)$test; +} + +/** + * Get number of bytes in a string regardless of mbstring.func_overload + * + * @param string $str + * @return int + */ +function countBytes($str) +{ + return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) + ? mb_strlen($str, '8bit') + : strlen($str); +} + +ob_start(); \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/comments.css b/mrclay/minify/min_unit_tests/_test_files/css/comments.css new file mode 100644 index 000000000000..2ef9fac4986e --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/comments.css @@ -0,0 +1,9 @@ + +/* block comments get removed */ + +/*! YUI Compressor style comments are preserved */ + +/* but all other comments are removed */ + +/* comments that have any surrounding whitespace are replaced by a single space. */ +body{ background:#fff/*eef*/ url(/path/to/image.gif) repeat-y; } diff --git a/mrclay/minify/min_unit_tests/_test_files/css/comments.min.css b/mrclay/minify/min_unit_tests/_test_files/css/comments.min.css new file mode 100644 index 000000000000..e0414a77c951 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/comments.min.css @@ -0,0 +1,3 @@ + +/*! YUI Compressor style comments are preserved */ +body{background:#fff url(/path/to/image.gif) repeat-y} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/hacks.css b/mrclay/minify/min_unit_tests/_test_files/css/hacks.css new file mode 100644 index 000000000000..715bbf779170 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/hacks.css @@ -0,0 +1,66 @@ +/* hide from ie5/mac \*/ a{} +.foo {color:red} +/* necessary comment */ + +/* comment to attempt to confuse parser */ + +/* feed to ie5/mac \*//*/ +@import "ie5mac.css"; +/* necessary comment */ + +/* comment to attempt to confuse parser */ + +/*/ hide from nav4 */ +.foo {display:block;} +/* necessary comment */ + +/* comment to attempt to confuse parser */ + +/*/ feed to nav *//*/ +.foo {display:crazy;} +/* necessary comment */ + +/* hide props from various IE/win */ +div { + width: 140px; + width/* */:/**/100px; + width: /**/100px; +} + +html>/**/body {} + +/* Tantek's box model hack */ +div { + width:400px; + voice-family: "\"}\""; + voice-family:inherit; + width:300px; +} + +/* don't minimize hex colors in filters */ +div { + filter:chroma(color=#aabbcc); + filter:mask(color=#000000) shadow(color=#9BAD71, direction=135) chroma(color=#000000); +} + +@media screen { + /* for IE 5.x-6, hidden from IE 5 Mac */ /*\*/ + * html div#page { + height: 1%; + } + /**/ /* end hidden from IE 5 Mac */ +} + +foo { /* filters for IE */ + _height : 20px; + *height : 15px; +} + +/* http://tantek.com/CSS/Examples/midpass.html */ +@media tty { + i{content:"\";/*" "*/}} @import 'midpassafter.css'; /*";} +}/* */ + +/* leave at least 1 space between these pseudo elements and "{" for IE6: http://www.crankygeek.com/ie6pebug/ */ +p:first-letter {color:red;} +p:first-line {color:red;} diff --git a/mrclay/minify/min_unit_tests/_test_files/css/hacks.min.css b/mrclay/minify/min_unit_tests/_test_files/css/hacks.min.css new file mode 100644 index 000000000000..68be2ee89eda --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/hacks.min.css @@ -0,0 +1,4 @@ +/*\*/a{}.foo{color:red}/**/ /*\*//*/@import "ie5mac.css";/**/ /*/*/.foo{display:block}/**/ /*/*//*/.foo{display:crazy}/**/ div{width:140px;width/**/:/**/100px;width:/**/100px}html>/**/body{}div{width:400px;voice-family:"\"}\"";voice-family:inherit;width:300px}div{filter:chroma(color=#aabbcc);filter:mask(color=#000000) shadow(color=#9BAD71, direction=135) chroma(color=#000000)}@media +screen{/*\*/* html +div#page{height:1%}/**/}foo{_height:20px;*height:15px}@media +tty{i{content:"\";/*" "*/}}@import 'midpassafter.css';/*"}}/* */ p:first-letter {color:red}p:first-line {color:red} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/issue210.css b/mrclay/minify/min_unit_tests/_test_files/css/issue210.css new file mode 100644 index 000000000000..842195b86ee6 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/issue210.css @@ -0,0 +1 @@ +.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; } \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/issue210.min.css b/mrclay/minify/min_unit_tests/_test_files/css/issue210.min.css new file mode 100644 index 000000000000..8a1869d31bf0 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/issue210.min.css @@ -0,0 +1 @@ +.ui-widget{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/issue62.css b/mrclay/minify/min_unit_tests/_test_files/css/issue62.css new file mode 100644 index 000000000000..b9d813f7ddf4 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/issue62.css @@ -0,0 +1,890 @@ +/* +* DEFINITION DES STYLES DE TEXTE +*/ + /*-----------------------------------------------------------------------------------*/ +h1 { + color: #339933; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 14px; + font-weight: bold; + text-decoration: none; +} + +h2 { + color: #339933; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 12px; + font-weight: bold; + text-decoration: none; +} + +h1,h2,h3,h4,h5 { + margin: 0px; + padding: 0px; +} + +.txt_10_noir { + color: black; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 10px; + text-decoration: none; +} + +.txt_10_noir:link,.txt_10_noir:visited,.txt_10_noir:active { + color: black; +} + +.txt_10_noir:hover { + color: red; +} + +.txt_11_noir { + color: black; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.txt_11_noir:link,.txt_11_noir:visited,.txt_11_noir:active { + color: black; +} + +.txt_11_noir:hover { + color: red; +} + +.txt_12_noir { + color: black; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 12px; + text-decoration: none; +} + +.txt_12_noir:link,.txt_12_noir:visited,.txt_12_noir:active { + color: black; +} + +.txt_12_noir:hover { + color: red; +} + +.txt_14_noir { + color: black; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 14px; + text-decoration: none; +} + +.txt_14_noir:link,.txt_14_noir:visited,.txt_14_noir:active { + color: black; +} + +.txt_14_noir:hover { + color: red; +} + +/*-----------------------------------------------------------------------------------*/ +.txt_10_gris { + color: grey; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 10px; + text-decoration: none; +} + +.txt_10_gris:link,.txt_10_gris:visited,.txt_10_gris:active { + color: grey; +} + +.txt_10_gris:hover { + color: red; +} + +.txt_11_gris { + color: grey; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.txt_11_gris:link,.txt_11_gris:visited,.txt_11_gris:active { + color: grey; +} + +.txt_11_gris:hover { + color: red; +} + +.txt_12_gris { + color: grey; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 12px; + text-decoration: none; +} + +.txt_12_gris:link,.txt_12_gris:visited,.txt_12_gris:active { + color: grey; +} + +.txt_12_gris:hover { + color: red; +} + +.txt_14_gris { + color: grey; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 14px; + text-decoration: none; +} + +.txt_14_gris:link,.txt_14_gris:visited,.txt_14_gris:active { + color: grey; +} + +.txt_14_gris:hover { + color: red; +} + +/*-----------------------------------------------------------------------------------*/ +.txt_10_blanc { + color: #FFFFFF; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 10px; + text-decoration: none; +} + +.txt_10_blanc:link,.txt_10_blanc:visited,.txt_10_blanc:active { + color: #FFFFFF; +} + +.txt_10_blanc:hover { + color: #FF8800; /*ORANGE*/ +} + +.txt_11_blanc { + color: #FFFFFF; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.txt_11_blanc:link,.txt_11_blanc:visited,.txt_11_blanc:active { + color: #FFFFFF; +} + +.txt_11_blanc:hover { + color: #FF8800; +} + +.txt_12_blanc { + color: #FFFFFF; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 12px; + text-decoration: none; +} + +.txt_12_blanc:link,.txt_12_blanc:visited,.txt_12_blanc:active { + color: #FFFFFF; +} + +.txt_12_blanc:hover { + color: #FFAA00; +} + +.txt_14_blanc { + color: #FFFFFF; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 14px; + text-decoration: none; +} + +.txt_14_blanc:link,.txt_14_blanc:visited,.txt_14_blanc:active { + color: #FFFFFF; +} + +.txt_14_blanc:hover { + color: #FF8800; +} + +/*-----------------------------------------------------------------------------------*/ +.txt_10_orange { + color: #FF8800; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 10px; + text-decoration: none; +} + +.txt_10_orange:link,.txt_10_orange:visited,.txt_10_orange:active { + color: #FF8800; +} + +.txt_10_orange:hover { + color: darkblue +} + +.txt_11_orange { + color: #FF8800; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.txt_11_orange:link,.txt_11_orange:visited,.txt_11_orange:active { + color: #FF8800; +} + +.txt_11_orange:hover { + color: darkblue; +} + +.txt_12_orange { + color: #FF8800; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 12px; + text-decoration: none; +} + +.txt_12_orange:link,.txt_12_orange:visited,.txt_12_orange:active { + color: #FF8800; +} + +.txt_12_orange:hover { + color: darkblue; +} + +.txt_14_orange { + color: #FF8800; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 14px; + text-decoration: none; +} + +.txt_14_orange:link,.txt_14_orange:visited,.txt_14_orange:active { + color: #FF8800; +} + +.txt_14_orange:hover { + color: darkblue; +} + +/*-----------------------------------------------------------------------------------*/ +.txt_10_rouge { + color: red; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 10px; + text-decoration: none; +} + +.txt_10_rouge:link,.txt_10_rouge:visited,.txt_10_rouge:active { + color: red; +} + +.txt_10_rouge:hover { + color: darkblue; +} + +.txt_11_rouge { + color: red; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.txt_11_rouge:link,.txt_11_rouge:visited,.txt_11_rouge:active { + color: red; +} + +.txt_11_rouge:hover { + color: darkblue; +} + +.txt_12_rouge { + color: red; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 12px; + text-decoration: none; +} + +.txt_12_rouge:link,.txt_12_rouge:visited,.txt_12_rouge:active { + color: red; +} + +.txt_12_rouge:hover { + color: darkblue; +} + +.txt_14_rouge { + color: red; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 14px; + text-decoration: none; +} + +.txt_14_rouge:link,.txt_14_rouge:visited,.txt_14_rouge:active { + color: red; +} + +.txt_14_rouge:hover { + color: darkblue; +} + +/*-----------------------------------------------------------------------------------*/ +.txt_10_bleu { + color: blue; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 10px; + text-decoration: none; +} + +.txt_10_bleu:link,.txt_10_bleu:visited,.txt_10_bleu:active { + color: blue; +} + +.txt_10_bleu:hover { + color: red; +} + +.txt_11_bleu { + color: blue; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.txt_11_bleu:link,.txt_11_bleu:visited,.txt_11_bleu:active { + color: blue; +} + +.txt_11_bleu:hover { + color: red; +} + +.txt_12_bleu { + color: blue; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 12px; + text-decoration: none; +} + +.txt_12_bleu:link,.txt_12_bleu:visited,.txt_12_bleu:active { + color: blue; +} + +.txt_12_bleu:hover { + color: red; +} + +.txt_14_bleu { + color: blue; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 14px; + text-decoration: none; +} + +.txt_14_bleu:link,.txt_14_bleu:visited,.txt_14_bleu:active { + color: blue; +} + +.txt_14_bleu:hover { + color: red; +} + +/*-----------------------------------------------------------------------------------*/ +.txt_10_bleu_f { + color: darkblue; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 10px; + text-decoration: none; +} + +.txt_10_bleu_f:link,.txt_10_bleu_f:visited,.txt_10_bleu_f:active { + color: darkblue; +} + +.txt_10_bleu_f:hover { + color: red; +} + +.txt_11_bleu_f { + color: darkblue; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.txt_11_bleu_f:link,.txt_11_bleu_f:visited,.txt_11_bleu_f:active { + color: darkblue; +} + +.txt_11_bleu_f:hover { + color: red; +} + +.txt_12_bleu_f { + color: darkblue; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 12px; + text-decoration: none; +} + +.txt_12_bleu_f:link,.txt_12_bleu_f:visited,.txt_12_bleu_f:active { + color: darkblue; +} + +.txt_12_bleu_f:hover { + color: red; +} + +.txt_14_bleu_f { + color: darkblue; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 14px; + text-decoration: none; +} + +.txt_14_bleu_f:link,.txt_14_bleu_f:visited,.txt_14_bleu_f:active { + color: darkblue; +} + +.txt_14_bleu_f:hover { + color: red; +} + +/*-----------------------------------------------------------------------------------*/ +.txt_10_vert_f { + color: darkgreen; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 10px; + text-decoration: none; +} + +.txt_10_vert_f:link,.txt_10_vert_f:visited,.txt_10_vert_f:active { + color: darkgreen; +} + +.txt_10_vert_f:hover { + color: red; +} + +.txt_11_vert_f { + color: darkgreen; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.txt_11_vert_f:link,.txt_11_vert_f:visited,.txt_11_vert_f:active { + color: darkgreen; +} + +.txt_11_vert_f:hover { + color: red; +} + +.txt_12_vert_f { + color: darkgreen; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 12px; + text-decoration: none; +} + +.txt_12_vert_f:link,.txt_12_vertf:visited,.txt_12_vert_f:active { + color: darkgreen; +} + +.txt_12_vert_f:hover { + color: red; +} + +.txt_14_vert_f { + color: darkgreen; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 14px; + text-decoration: none; +} + +.txt_14_vert_f:link,.txt_14_vert_f:visited,.txt_14_vert_f:active { + color: darkgreen; +} + +.txt_14_vert_f:hover { + color: red; +} + +/*-----------------------------------------------------------------------------------*/ +.txt_10_vert { + color: green; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 10px; + text-decoration: none; +} + +.txt_10_vert:link,.txt_10_vert:visited,.txt_10_vert:active { + color: green; +} + +.txt_10_vert:hover { + color: red; +} + +.txt_11_vert { + color: green; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.txt_11_vert:link,.txt_11_vert:visited,.txt_11_vert:active { + color: green; +} + +.txt_11_vert:hover { + color: red; +} + +.txt_12_vert { + color: green; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 12px; + text-decoration: none; +} + +.txt_12_vert:link,.txt_12_vert:visited,.txt_12_vert:active { + color: green; +} + +.txt_12_vert:hover { + color: red; +} + +.txt_14_vert { + color: green; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 14px; + text-decoration: none; +} + +.txt_14_vert:link,.txt_14_vert:visited,.txt_14_vert:active { + color: green; +} + +.txt_14_vert:hover { + color: red; +} + +/*-----------------------------------------------------------------------------------*/ +.fond_blanc { + background-color: #FFFFFF; + color: black; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.fond_gris_c, .fond_gris_c tr { + background-color: #FFFFFF; + color: black; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; + background-image: url(../images/fond_4.bmp); + background-repeat: repeat-x; +} + +.fond_gris_c2, .fond_gris_c2 tr { + background-color: #FBFBFB; + color: black; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.fond_bleu_c, .fond_bleu_c tr { + background-color: #D9EEF9; + color: black; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; + background-image: url(../images/fond_1.bmp); +} + +.fond_bleu_c2 { + background-color: #ECF4FF; + color: black; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.fond_bleu_f { + background-color: #003366; + color: black; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.fond_orange { + background-color: #FEEFE7; + color: darkgreen; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 12px; + font-weight: bold; + text-decoration: none; + background-image: url(../images/fond_3.jpg); +} + +.fond_orange_2 { + background-color: #FFF8F4; + color: darkgreen; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 12px; + font-weight: bold; + text-decoration: none; + border: 1px solid orange; + border-collapse: collapse; +} + +.vccDlgBody { + border: 3px solid #336699; + border-collapse: collapse; + color: black; + background-color: #EEFFEE; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +/* DEFINITION DES STYLES DE TABLEAUX */ +.bordure_0 { + border: 0px solid; + color: black; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.bordure_1_bleu { + border: 1px solid green; + border-collapse: collapse; + color: black; + background-color: #FFFFFF; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.bordure_3_bleu { + border: 3px solid #336699; + border-collapse: collapse; + color: black; + background-color: #FFFFFF; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 11px; + text-decoration: none; +} + +.indent { + margin-left: 20px; +} + +/* DEFINITION DES STYLES D'OBJETS DE FORMULAIRE */ +.Btn { + color: #003366; + text-align: center; + font-weight: bold; + background-color: #FFFFFF; + background-image: url(../images/ongletStyle1.jpg); + background-repeat: no-repeat; + background-position: center center; +} + +.Btn:hover { + color: red; +} + +.menu1h { + background-color: #003366; + color: white; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 10px; + font-weight: bold; + text-decoration: none; + border-top: 1px solid #003366; + border-bottom: 1px solid #003366; + border-left: 1px solid #003366; + border-right: 1px solid white; + border-collapse: collapse; + display: block; +} + +.menu1h:hover { + background-color: white; + color: red; + border: 1px solid darkgreen; + border-collapse: collapse; +} + +.menu1h_f { + background-color: #003366; + color: white; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 10px; + font-weight: bold; + text-decoration: none; + border: 1px solid #003366; + display: block; +} + +.menu1h_f:hover { + background-color: white; + color: red; + border: 1px solid darkgreen; + border-collapse: collapse; +} + +.menu1v { + background-color: #003366; + color: white; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 10px; + font-weight: bold; + text-decoration: none; + border: 1px solid #003366; + border-collapse: collapse; + display: block; +} + +.menu1v:hover { + background-color: white; + color: red; + border: 1px solid darkgreen; + border-collapse: collapse; +} + +.menu2v { + background-color: #5588BB; + color: white; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 12px; + font-weight: bold; + text-decoration: none; + border: 1px solid #4277AB; + border-collapse: collapse; + float: left; + display: block; +} + +.menu2v:hover { + background-color: white; + color: red; + border: 1px solid darkgreen; + border-collapse: collapse; +} + +.menuEDF { + background-color: #003366; + color: white; + font-family: Verdana, Arial, Lucida, Tahoma; + font-size: 10px; + text-decoration: none; +} + +.menuEDF:hover { + color: #FF8800; +} + +/*bouton bleu sur blanc*/ +.Bouton { + color: #003366; + text-align: center; + font-weight: bold; + /* Ricardo cursor: hand; */ + cursor: pointer; + background-color: #FFFFFF; +} + +input { + border: 2px solid green; + color: #003366; + background-color: #FFFFFF; + background-image: url(../images/fond_4.bmp); + background-repeat: repeat-x; +} + +.disabled_input { + border: 1px solid gray; + color: grey; + background-color: #FFFFFF; + background-image: url(../images/fond_4.bmp); + background-repeat: repeat-x; +} + +.input0 { + border: 0px; + color: #003366; + background-color: #FFFFFF; + background-image: url(../images/fond_4.bmp); +} + +.input2 { + border: 1px solid green; + color: #003366; + background-color: #FFFFFF; + background-image: url(../images/fond_4.bmp); + background-repeat: repeat-x; +} + +.input3 { + border: 1px solid black; + color: #003366; + background-color: #EEEEEE; + background-image: url(); +} + +.input4 { + border: 1px solid blue; + color: #003366; + background-color: #FFFFFF; + background-image: url(../images/fond_4.bmp); + background-repeat: repeat-x; +} + +.input5 { + border: 1px solid darkblue; + color: #003366; + background-color: #FFFFFF; + background-image: url(../images/fond_4.bmp); + background-repeat: repeat-x; +} + +.input_btn { + border: 0px; + /* cursor: hand; */ + cursor: pointer; +} + +textarea { + border: 2px solid green; + color: #003366; + background-color: #FFFFFF; + background-image: url(../images/fond_5.bmp); +} + +.TEXTAREA3 { + border: 1px solid green; + color: #003366; + background-color: #FFFFFF; + background-image: url(); +} + +.TEXTAREA4 { + border: 1px solid green; + color: #003366; + background-color: #EEEEEE; + background-image: url(); +} + +.hand { + cursor: hand; + cursor: pointer; +} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/issue62.min.css b/mrclay/minify/min_unit_tests/_test_files/css/issue62.min.css new file mode 100644 index 000000000000..5eb1982282fa --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/issue62.min.css @@ -0,0 +1,25 @@ +h1{color:#393;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;font-weight:bold;text-decoration:none}h2{color:#393;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;font-weight:bold;text-decoration:none}h1,h2,h3,h4,h5{margin:0px;padding:0px}.txt_10_noir{color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_noir:link,.txt_10_noir:visited,.txt_10_noir:active{color:black}.txt_10_noir:hover{color:red}.txt_11_noir{color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_noir:link,.txt_11_noir:visited,.txt_11_noir:active{color:black}.txt_11_noir:hover{color:red}.txt_12_noir{color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_noir:link,.txt_12_noir:visited,.txt_12_noir:active{color:black}.txt_12_noir:hover{color:red}.txt_14_noir{color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_noir:link,.txt_14_noir:visited,.txt_14_noir:active{color:black}.txt_14_noir:hover{color:red}.txt_10_gris{color:grey;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_gris:link,.txt_10_gris:visited,.txt_10_gris:active{color:grey}.txt_10_gris:hover{color:red}.txt_11_gris{color:grey;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_gris:link,.txt_11_gris:visited,.txt_11_gris:active{color:grey}.txt_11_gris:hover{color:red}.txt_12_gris{color:grey;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_gris:link,.txt_12_gris:visited,.txt_12_gris:active{color:grey}.txt_12_gris:hover{color:red}.txt_14_gris{color:grey;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_gris:link,.txt_14_gris:visited,.txt_14_gris:active{color:grey}.txt_14_gris:hover{color:red}.txt_10_blanc{color:#FFF;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_blanc:link,.txt_10_blanc:visited,.txt_10_blanc:active{color:#FFF}.txt_10_blanc:hover{color:#F80}.txt_11_blanc{color:#FFF;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_blanc:link,.txt_11_blanc:visited,.txt_11_blanc:active{color:#FFF}.txt_11_blanc:hover{color:#F80}.txt_12_blanc{color:#FFF;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_blanc:link,.txt_12_blanc:visited,.txt_12_blanc:active{color:#FFF}.txt_12_blanc:hover{color:#FA0}.txt_14_blanc{color:#FFF;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_blanc:link,.txt_14_blanc:visited,.txt_14_blanc:active{color:#FFF}.txt_14_blanc:hover{color:#F80}.txt_10_orange{color:#F80;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_orange:link,.txt_10_orange:visited,.txt_10_orange:active{color:#F80}.txt_10_orange:hover{color:darkblue}.txt_11_orange{color:#F80;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_orange:link,.txt_11_orange:visited,.txt_11_orange:active{color:#F80}.txt_11_orange:hover{color:darkblue}.txt_12_orange{color:#F80;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_orange:link,.txt_12_orange:visited,.txt_12_orange:active{color:#F80}.txt_12_orange:hover{color:darkblue}.txt_14_orange{color:#F80;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_orange:link,.txt_14_orange:visited,.txt_14_orange:active{color:#F80}.txt_14_orange:hover{color:darkblue}.txt_10_rouge{color:red;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_rouge:link,.txt_10_rouge:visited,.txt_10_rouge:active{color:red}.txt_10_rouge:hover{color:darkblue}.txt_11_rouge{color:red;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_rouge:link,.txt_11_rouge:visited,.txt_11_rouge:active{color:red}.txt_11_rouge:hover{color:darkblue}.txt_12_rouge{color:red;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_rouge:link,.txt_12_rouge:visited,.txt_12_rouge:active{color:red}.txt_12_rouge:hover{color:darkblue}.txt_14_rouge{color:red;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_rouge:link,.txt_14_rouge:visited,.txt_14_rouge:active{color:red}.txt_14_rouge:hover{color:darkblue}.txt_10_bleu{color:blue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_bleu:link,.txt_10_bleu:visited,.txt_10_bleu:active{color:blue}.txt_10_bleu:hover{color:red}.txt_11_bleu{color:blue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_bleu:link,.txt_11_bleu:visited,.txt_11_bleu:active{color:blue}.txt_11_bleu:hover{color:red}.txt_12_bleu{color:blue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_bleu:link,.txt_12_bleu:visited,.txt_12_bleu:active{color:blue}.txt_12_bleu:hover{color:red}.txt_14_bleu{color:blue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_bleu:link,.txt_14_bleu:visited,.txt_14_bleu:active{color:blue}.txt_14_bleu:hover{color:red}.txt_10_bleu_f{color:darkblue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_bleu_f:link,.txt_10_bleu_f:visited,.txt_10_bleu_f:active{color:darkblue}.txt_10_bleu_f:hover{color:red}.txt_11_bleu_f{color:darkblue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_bleu_f:link,.txt_11_bleu_f:visited,.txt_11_bleu_f:active{color:darkblue}.txt_11_bleu_f:hover{color:red}.txt_12_bleu_f{color:darkblue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_bleu_f:link,.txt_12_bleu_f:visited,.txt_12_bleu_f:active{color:darkblue}.txt_12_bleu_f:hover{color:red}.txt_14_bleu_f{color:darkblue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_bleu_f:link,.txt_14_bleu_f:visited,.txt_14_bleu_f:active{color:darkblue}.txt_14_bleu_f:hover{color:red}.txt_10_vert_f{color:darkgreen;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_vert_f:link,.txt_10_vert_f:visited,.txt_10_vert_f:active{color:darkgreen}.txt_10_vert_f:hover{color:red}.txt_11_vert_f{color:darkgreen;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_vert_f:link,.txt_11_vert_f:visited,.txt_11_vert_f:active{color:darkgreen}.txt_11_vert_f:hover{color:red}.txt_12_vert_f{color:darkgreen;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_vert_f:link,.txt_12_vertf:visited,.txt_12_vert_f:active{color:darkgreen}.txt_12_vert_f:hover{color:red}.txt_14_vert_f{color:darkgreen;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_vert_f:link,.txt_14_vert_f:visited,.txt_14_vert_f:active{color:darkgreen}.txt_14_vert_f:hover{color:red}.txt_10_vert{color:green;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_vert:link,.txt_10_vert:visited,.txt_10_vert:active{color:green}.txt_10_vert:hover{color:red}.txt_11_vert{color:green;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_vert:link,.txt_11_vert:visited,.txt_11_vert:active{color:green}.txt_11_vert:hover{color:red}.txt_12_vert{color:green;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_vert:link,.txt_12_vert:visited,.txt_12_vert:active{color:green}.txt_12_vert:hover{color:red}.txt_14_vert{color:green;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_vert:link,.txt_14_vert:visited,.txt_14_vert:active{color:green}.txt_14_vert:hover{color:red}.fond_blanc{background-color:#FFF;color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.fond_gris_c, .fond_gris_c +tr{background-color:#FFF;color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none;background-image:url(../images/fond_4.bmp);background-repeat:repeat-x}.fond_gris_c2, .fond_gris_c2 +tr{background-color:#FBFBFB;color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.fond_bleu_c, .fond_bleu_c +tr{background-color:#D9EEF9;color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none;background-image:url(../images/fond_1.bmp)}.fond_bleu_c2{background-color:#ECF4FF;color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.fond_bleu_f{background-color:#036;color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.fond_orange{background-color:#FEEFE7;color:darkgreen;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;font-weight:bold;text-decoration:none;background-image:url(../images/fond_3.jpg)}.fond_orange_2{background-color:#FFF8F4;color:darkgreen;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;font-weight:bold;text-decoration:none;border:1px +solid orange;border-collapse:collapse}.vccDlgBody{border:3px +solid #369;border-collapse:collapse;color:black;background-color:#EFE;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.bordure_0{border:0px +solid;color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.bordure_1_bleu{border:1px +solid green;border-collapse:collapse;color:black;background-color:#FFF;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.bordure_3_bleu{border:3px +solid #369;border-collapse:collapse;color:black;background-color:#FFF;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.indent{margin-left:20px}.Btn{color:#036;text-align:center;font-weight:bold;background-color:#FFF;background-image:url(../images/ongletStyle1.jpg);background-repeat:no-repeat;background-position:center center}.Btn:hover{color:red}.menu1h{background-color:#036;color:white;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;font-weight:bold;text-decoration:none;border-top:1px solid #036;border-bottom:1px solid #036;border-left:1px solid #036;border-right:1px solid white;border-collapse:collapse;display:block}.menu1h:hover{background-color:white;color:red;border:1px +solid darkgreen;border-collapse:collapse}.menu1h_f{background-color:#036;color:white;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;font-weight:bold;text-decoration:none;border:1px +solid #036;display:block}.menu1h_f:hover{background-color:white;color:red;border:1px +solid darkgreen;border-collapse:collapse}.menu1v{background-color:#036;color:white;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;font-weight:bold;text-decoration:none;border:1px +solid #036;border-collapse:collapse;display:block}.menu1v:hover{background-color:white;color:red;border:1px +solid darkgreen;border-collapse:collapse}.menu2v{background-color:#58B;color:white;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;font-weight:bold;text-decoration:none;border:1px +solid #4277AB;border-collapse:collapse;float:left;display:block}.menu2v:hover{background-color:white;color:red;border:1px +solid darkgreen;border-collapse:collapse}.menuEDF{background-color:#036;color:white;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.menuEDF:hover{color:#F80}.Bouton{color:#036;text-align:center;font-weight:bold;cursor:pointer;background-color:#FFF}input{border:2px +solid green;color:#036;background-color:#FFF;background-image:url(../images/fond_4.bmp);background-repeat:repeat-x}.disabled_input{border:1px +solid gray;color:grey;background-color:#FFF;background-image:url(../images/fond_4.bmp);background-repeat:repeat-x}.input0{border:0px;color:#036;background-color:#FFF;background-image:url(../images/fond_4.bmp)}.input2{border:1px +solid green;color:#036;background-color:#FFF;background-image:url(../images/fond_4.bmp);background-repeat:repeat-x}.input3{border:1px +solid black;color:#036;background-color:#EEE;background-image:url()}.input4{border:1px +solid blue;color:#036;background-color:#FFF;background-image:url(../images/fond_4.bmp);background-repeat:repeat-x}.input5{border:1px +solid darkblue;color:#036;background-color:#FFF;background-image:url(../images/fond_4.bmp);background-repeat:repeat-x}.input_btn{border:0px;cursor:pointer}textarea{border:2px +solid green;color:#036;background-color:#FFF;background-image:url(../images/fond_5.bmp)}.TEXTAREA3{border:1px +solid green;color:#036;background-color:#FFF;background-image:url()}.TEXTAREA4{border:1px +solid green;color:#036;background-color:#EEE;background-image:url()}.hand{cursor:hand;cursor:pointer} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.css b/mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.css new file mode 100644 index 000000000000..48e75fb69448 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.css @@ -0,0 +1,12 @@ +@import "foo.css"; +@import 'bar/foo.css' print; +@import '/css/foo.css'; /* abs, should not alter */ +@import 'http://foo.com/css/foo.css'; /* abs, should not alter */ +@import url(../foo.css) tv, projection; +@import url("/css/foo.css"); /* abs, should not alter */ +@import url(/css2/foo.css); /* abs, should not alter */ +@import url(data:image/gif;base64,AAAA); /* data, should not alter */ +foo {background:url('bar/foo.png')} +foo {background:url('http://foo.com/css/foo.css');} /* abs, should not alter */ +foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ +foo {background:url(data:image/gif;base64,AAAA);} /* data, should not alter */ \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.min.css b/mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.min.css new file mode 100644 index 000000000000..ffb94e21651e --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.min.css @@ -0,0 +1 @@ +@import "../foo.css";@import '../bar/foo.css' print;@import '/css/foo.css';@import 'http://foo.com/css/foo.css';@import url(../../foo.css) tv, projection;@import url("/css/foo.css");@import url(/css2/foo.css);@import url(data:image/gif;base64,AAAA);foo{background:url('../bar/foo.png')}foo{background:url('http://foo.com/css/foo.css')}foo{background:url("//foo.com/css/foo.css")}foo{background:url(data:image/gif;base64,AAAA)} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.css b/mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.css new file mode 100644 index 000000000000..aa41d0a91e0c --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.css @@ -0,0 +1,14 @@ +@import "foo.css"; +@import 'bar/foo.css' print; +@import '../bar/foo.css' print; +@import '../../foo.css' print; +@import '/css/foo.css'; /* abs, should not alter */ +@import 'http://foo.com/css/foo.css'; /* abs, should not alter */ +@import url(../foo.css) tv, projection; +@import url("/css/foo.css"); /* abs, should not alter */ +@import url(/css2/foo.css); /* abs, should not alter */ +@import url(data:image/gif;base64,AAAA); /* data, should not alter */ +foo {background:url('bar/foo.png')} +foo {background:url('http://foo.com/css/foo.css');} /* abs, should not alter */ +foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ +foo {background:url(data:image/gif;base64,AAAA);} /* data, should not alter */ \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.min.css b/mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.min.css new file mode 100644 index 000000000000..34936155a021 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.min.css @@ -0,0 +1 @@ +@import "/_test_files/css/foo.css";@import '/_test_files/css/bar/foo.css' print;@import '/_test_files/bar/foo.css' print;@import '/foo.css' print;@import '/css/foo.css';@import 'http://foo.com/css/foo.css';@import url(/_test_files/foo.css) tv, projection;@import url("/css/foo.css");@import url(/css2/foo.css);@import url(data:image/gif;base64,AAAA);foo{background:url('/_test_files/css/bar/foo.png')}foo{background:url('http://foo.com/css/foo.css')}foo{background:url("//foo.com/css/foo.css")}foo{background:url(data:image/gif;base64,AAAA)} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/readme.txt b/mrclay/minify/min_unit_tests/_test_files/css/readme.txt new file mode 100644 index 000000000000..01817552960d --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/readme.txt @@ -0,0 +1 @@ +Test suite from http://search.cpan.org/~gtermars/CSS-Minifier-XS/ \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/selectors.css b/mrclay/minify/min_unit_tests/_test_files/css/selectors.css new file mode 100644 index 000000000000..cce2bf2e5e8c --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/selectors.css @@ -0,0 +1,42 @@ +/* http://www.w3.org/TR/css3-selectors/ */ + +* +E[foo] +E[foo="bar"] +E[foo~="bar"] +E[foo^="bar"] +E[foo$="bar"] +E[foo*="bar"] +E[hreflang|="en"] +E:root +E:nth-child(n) +E:nth-last-child(n) +E:nth-of-type(n) +E:nth-last-of-type(n) +E:first-child +E:last-child +E:first-of-type +E:last-of-type +E:only-child +E:only-of-type +E:empty +E:link +E:visited +E:active +E:hover +E:focus +E:target +E:lang(fr) +E:enabled +E:disabled +E:checked +E::first-line +E::first-letter +E::selection +E::before +E::after +E.warning#myid +E:not(s) + > F + + F + ~ F {color: red;} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/selectors.min.css b/mrclay/minify/min_unit_tests/_test_files/css/selectors.min.css new file mode 100644 index 000000000000..643089fcf76c --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/selectors.min.css @@ -0,0 +1,37 @@ +* +E[foo] +E[foo="bar"] +E[foo~="bar"] +E[foo^="bar"] +E[foo$="bar"] +E[foo*="bar"] +E[hreflang|="en"] +E:root +E:nth-child(n) +E:nth-last-child(n) +E:nth-of-type(n) +E:nth-last-of-type(n) +E:first-child +E:last-child +E:first-of-type +E:last-of-type +E:only-child +E:only-of-type +E:empty +E:link +E:visited +E:active +E:hover +E:focus +E:target +E:lang(fr) +E:enabled +E:disabled +E:checked +E::first-line +E::first-letter +E::selection +E::before +E::after +E.warning#myid +E:not(s)>F+F~F{color:red} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/styles.css b/mrclay/minify/min_unit_tests/_test_files/css/styles.css new file mode 100644 index 000000000000..ed0bcd456cf3 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/styles.css @@ -0,0 +1,33 @@ +@charset "utf-8"; + +/* some CSS to try to exercise things in general */ + +@import url( /more.css ); + + body, td, th { + font-family: Verdana , "Bitstream Vera Sans" , Arial Narrow, sans-serif ; + + font-size : 12px; +} + +.nav { + margin-left: 20%; +} +#main-nav { + background-color: red; + border: 1px solid #00ff77; +} + +div#content +h1 + p { + padding-top: 0; + margin-top: 0; +} + +@media all and (min-width: 640px) { + #media-queries-1 { background-color: #0f0; } +} + +@media screen and (max-width: 2000px) { + #media-queries-2 { background-color: #0f0; } +} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/styles.min.css b/mrclay/minify/min_unit_tests/_test_files/css/styles.min.css new file mode 100644 index 000000000000..a71063db1e36 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/styles.min.css @@ -0,0 +1,3 @@ +@import url(/more.css);body,td,th{font-family:Verdana,"Bitstream Vera Sans",Arial Narrow,sans-serif;font-size:12px}.nav{margin-left:20%}#main-nav{background-color:red;border:1px +solid #0f7}div#content +h1+p{padding-top:0;margin-top:0}@media all and (min-width: 640px){#media-queries-1{background-color:#0f0}}@media screen and (max-width: 2000px){#media-queries-2{background-color:#0f0}} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/subsilver.css b/mrclay/minify/min_unit_tests/_test_files/css/subsilver.css new file mode 100644 index 000000000000..492c2ec2d49b --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/subsilver.css @@ -0,0 +1,434 @@ +/* Based on the original Style Sheet for the fisubsilver v2 Theme for phpBB version 2+ +Edited by Daz - http://www.forumimages.com - last updated 26-06-03 */ +/* The content of the posts (body of text) */ +/* General page style */ + + + + /* begin suggest post */ + .float-l{ + float: left; + } + + .form-suggest{ + height:200px; + background:#DEE2D0; + vertical-align: top; + } + + .form-input input{ + font-size: 10px; + } + + .hide{ + display:none; + } + + .form-input textarea{ + font-size: 11px; + width: 350px; + } + + .form-label{ + font-size: 10px; + font-weight: bold; + line-height: 25px; + padding-right: 10px; + text-align: right; + width: 100px; + color: #39738F; + } + + .font-9{ + font-size: 9px; + } + + .form-topic{ + font-weight:bold; + + } + + .form-error{ + color:red; + } + + .inline{ + display: inline; + } + + .space-10{ + clear: both; + font-size: 10px; + height: 10px; + line-height: 10px; + } + + .suggest-success{ + color:green; + padding-left:10px; + font-size:11px; + font-weight:bold; + } + + .top{ + vertical-align: top; + } + /* end suggest post */ + +table td{ + padding:3px; +} + +a:link,a:active,a:visited,a.postlink{ + color: #006699; + text-decoration: none; +} + +a:hover{ + color: #DD6900; +} + +a.admin:hover,a.mod:hover{ + color: #DD6900; +} + +a.but,a.but:hover,a.but:visited{ + color: #000000; + text-decoration: none; +} + +a.topictitle:visited{ + color: #5493B4; +} + +a.topictitle:hover{ + color: #DD6900; +} + + + +body{ + color: #000000; + font: 11px Verdana,Arial,Helvetica,sans-serif; + margin: 0 10px 10px 10px; + padding: 0; + overflow:auto; +} + +/* General font families for common tags */ +font,th,td,p{ + font: 12px Verdana,Arial,Helvetica,sans-serif; +} + +/* Form elements */ +form{ + display: inline; +} + +hr{ + border: 0px solid #FFFFFF; + border-top-width: 1px; + height: 0px; +} + +/* Gets rid of the need for border="0" on hyperlinked images */ +img{ + border: 0 solid; +} + +input{ + font: 11px Verdana,Arial,Helvetica,sans-serif; +} + +input.button,input.liteoption,.fakebut{ + background: #FAFAFA; + border: 1px solid #000000; + font-size: 11px; +} + +input.catbutton{ + background: #FAFAFA; + border: 1px solid #000000; + font-size: 10px; +} + +input.mainoption{ + background: #FAFAFA; + border: 1px solid #000000; + font-size: 11px; + font-weight: bold; +} + +input.post,textarea.post{ + background: #FFFFFF; + border: 1px solid #000000; + font: 11px Verdana,Arial,Helvetica,sans-serif; + padding-bottom: 2px; + padding-left: 2px; +} + +select{ + background: #FFFFFF; + font: 11px Verdana,Arial,Helvetica,sans-serif; +} + +table{ + text-align: left; +} + +td{ + vertical-align: middle; +} + +/* Category gradients*/ +td.cat{ + background-color: #C2C6BA; + font-weight: bold; + height: 20px; + letter-spacing: 1px; + text-indent: 4px; +} + +td.genmed,.genmed{ + font-size: 11px; +} + +/* This is for the table cell above the Topics,Post & Last posts on the index.php */ +td.rowpic{ + background: #C2C6BA; +} + +td.spacerow{ + background: #E5E6E2; +} + +/* Table Header cells */ +th{ + background-color: #FADD31; + background-image: url(images/cellpic3.gif); + background-repeat: repeat-x; + color: #68685E; + font-size: 11px; + font-weight: bold; + line-height:16px; + height: 16px; + padding-left: 8px; + padding-right: 8px; + text-align: center; + white-space: nowrap; +} + +/* Admin & Moderator Colours MODification */ +.admin,.mod{ + font-size: 11px; + font-weight: bold; +} + +.admin,a.admin,a.admin:visited{ + color: #FFA34F; +} + +/* This is the border line & background colour round the entire page */ +.bodyline{ + background: #FFFFFF; + border: 1px solid #98AAB1; +} + +.center{ + text-align: center; +} + +/* Code blocks */ +.code{ + background: #FAFAFA; + border: 1px solid #D1D7DC; + color: #006600; + font: 12px Courier,"Courier New",sans-serif; + padding: 5px; +} + +/* This is for the error messages that pop up */ +.errorline{ + background: #E5E6E2; + border: 1px solid #8F8B8B; + color:#D92A2A; +} + +.explaintitle{ + color: #5C81B1; + font-size: 11px; + font-weight: bold; +} + +/* This is the outline round the main forum tables */ +.forumline{ + background: #FFFFFF; +} + +/* General text */ +.gensmall{ + font-size: 10px; +} + +.h1-font{ + color: #006699; + display: inline; + font: bold 13px Verdana, Arial, Helvetica, sans-serif; + margin: 0; + text-decoration: none; +} + +.h2-font{ + display: inline; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 11px; +} + +.height1{ + height: 1px; +} + +.height22{ + height: 22px; +} + +.height25{ + height: 25px; +} + +.height28{ + height: 28px; +} + +.height30{ + height: 30px; +} + +.height40{ + height: 40px; +} + +/* This is the line in the posting page which shows the rollover +help line. Colour value in row2 */ +.helpline{ + border: 0 solid; + font-size: 10px; +} + +.imgfolder{ + margin: 1px 4px 1px 4px; +} + +.imgspace{ + margin-left: 1px; + margin-right: 2px; +} + +/* Specify the space around images */ +.imgtopic,.imgicon{ + margin-left: 3px; +} + +.left{ + text-align: left; +} + +/* The largest text used in the index page title and toptic title etc. */ +.maintitle,h1,h2{ + color: #5C81B1; + font: bold 20px/120% "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif; + text-decoration: none; +} + +.maxwidth{ + width: 100%; +} + +.mod,a.mod,a.mod:visited{ + color: #006600; +} + +/* Name of poster in viewmsg.php and viewtopic.php and other places */ +.name{ + font-size: 11px; + font-weight: bold; +} + +/* Used for the navigation text,(Page 1,2,3 etc) and the navigation bar when in a forum */ +.nav{ + font-size: 11px; + font-weight: bold; +} + +.nowrap{ + white-space: nowrap; +} + +.postbody{ + font-size: 12px; + line-height: 125%; +} + +.postbody a{ + text-decoration: underline; +} + +/* Location,number of posts,post date etc */ +.postdetails{ + color: #00396A; + font-size: 10px; +} + +/* Quote blocks */ +.quote{ + background: #F3F3EF; + border: 1px solid #C2C6BA; + color: #006699; + font-size: 11px; + line-height: 125%; +} + +.right{ + text-align: right; +} + +/* Main table cell colours and backgrounds */ +.row1{ + background: #F0F0EB; +} + +.row2,.helpline{ + background: #E5E6E2; +} + +.row3{ + background: #DBDBD4; +} + +.subtitle,h2{ + font: bold 18px/180% "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif; + text-decoration: none; +} + +/* titles for the topics:could specify viewed link colour too */ +.topictitle { + color: #000000; + font-size: 11px; + font-weight: bold; +} + +.underline{ + text-decoration: underline; +} + +.top{ +vertical-align:top; +} + +.image-hspace{ +margin-right:3px; +} + +.clear{ +clear:both; +} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/subsilver.min.css b/mrclay/minify/min_unit_tests/_test_files/css/subsilver.min.css new file mode 100644 index 000000000000..f59b15a92eb6 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/subsilver.min.css @@ -0,0 +1,18 @@ +.float-l{float:left}.form-suggest{height:200px;background:#DEE2D0;vertical-align:top}.form-input +input{font-size:10px}.hide{display:none}.form-input +textarea{font-size:11px;width:350px}.form-label{font-size:10px;font-weight:bold;line-height:25px;padding-right:10px;text-align:right;width:100px;color:#39738F}.font-9{font-size:9px}.form-topic{font-weight:bold}.form-error{color:red}.inline{display:inline}.space-10{clear:both;font-size:10px;height:10px;line-height:10px}.suggest-success{color:green;padding-left:10px;font-size:11px;font-weight:bold}.top{vertical-align:top}table +td{padding:3px}a:link,a:active,a:visited,a.postlink{color:#069;text-decoration:none}a:hover{color:#DD6900}a.admin:hover,a.mod:hover{color:#DD6900}a.but,a.but:hover,a.but:visited{color:#000;text-decoration:none}a.topictitle:visited{color:#5493B4}a.topictitle:hover{color:#DD6900}body{color:#000;font:11px Verdana,Arial,Helvetica,sans-serif;margin:0 +10px 10px 10px;padding:0;overflow:auto}font,th,td,p{font:12px Verdana,Arial,Helvetica,sans-serif}form{display:inline}hr{border:0px +solid #FFF;border-top-width:1px;height:0px}img{border:0 +solid}input{font:11px Verdana,Arial,Helvetica,sans-serif}input.button,input.liteoption,.fakebut{background:#FAFAFA;border:1px +solid #000;font-size:11px}input.catbutton{background:#FAFAFA;border:1px +solid #000;font-size:10px}input.mainoption{background:#FAFAFA;border:1px +solid #000;font-size:11px;font-weight:bold}input.post,textarea.post{background:#FFF;border:1px +solid #000;font:11px Verdana,Arial,Helvetica,sans-serif;padding-bottom:2px;padding-left:2px}select{background:#FFF;font:11px Verdana,Arial,Helvetica,sans-serif}table{text-align:left}td{vertical-align:middle}td.cat{background-color:#C2C6BA;font-weight:bold;height:20px;letter-spacing:1px;text-indent:4px}td.genmed,.genmed{font-size:11px}td.rowpic{background:#C2C6BA}td.spacerow{background:#E5E6E2}th{background-color:#FADD31;background-image:url(images/cellpic3.gif);background-repeat:repeat-x;color:#68685E;font-size:11px;font-weight:bold;line-height:16px;height:16px;padding-left:8px;padding-right:8px;text-align:center;white-space:nowrap}.admin,.mod{font-size:11px;font-weight:bold}.admin,a.admin,a.admin:visited{color:#FFA34F}.bodyline{background:#FFF;border:1px +solid #98AAB1}.center{text-align:center}.code{background:#FAFAFA;border:1px +solid #D1D7DC;color:#060;font:12px Courier,"Courier New",sans-serif;padding:5px}.errorline{background:#E5E6E2;border:1px +solid #8F8B8B;color:#D92A2A}.explaintitle{color:#5C81B1;font-size:11px;font-weight:bold}.forumline{background:#FFF}.gensmall{font-size:10px}.h1-font{color:#069;display:inline;font:bold 13px Verdana,Arial,Helvetica,sans-serif;margin:0;text-decoration:none}.h2-font{display:inline;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px}.height1{height:1px}.height22{height:22px}.height25{height:25px}.height28{height:28px}.height30{height:30px}.height40{height:40px}.helpline{border:0 +solid;font-size:10px}.imgfolder{margin:1px +4px 1px 4px}.imgspace{margin-left:1px;margin-right:2px}.imgtopic,.imgicon{margin-left:3px}.left{text-align:left}.maintitle,h1,h2{color:#5C81B1;font:bold 20px/120% "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif;text-decoration:none}.maxwidth{width:100%}.mod,a.mod,a.mod:visited{color:#060}.name{font-size:11px;font-weight:bold}.nav{font-size:11px;font-weight:bold}.nowrap{white-space:nowrap}.postbody{font-size:12px;line-height:125%}.postbody +a{text-decoration:underline}.postdetails{color:#00396A;font-size:10px}.quote{background:#F3F3EF;border:1px +solid #C2C6BA;color:#069;font-size:11px;line-height:125%}.right{text-align:right}.row1{background:#F0F0EB}.row2,.helpline{background:#E5E6E2}.row3{background:#DBDBD4}.subtitle,h2{font:bold 18px/180% "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif;text-decoration:none}.topictitle{color:#000;font-size:11px;font-weight:bold}.underline{text-decoration:underline}.top{vertical-align:top}.image-hspace{margin-right:3px}.clear{clear:both} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.css b/mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.css new file mode 100644 index 000000000000..e2f7f9014946 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.css @@ -0,0 +1,10 @@ +/* test unusual, but valid strings in CSS */ + +foo[attr="multiple spaces"] { + content: "Hello World!"; +} + +foo[attr="Hel\ +lo"] { + content: " \"World\""; +} diff --git a/mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.min.css b/mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.min.css new file mode 100644 index 000000000000..4b7d97e45566 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.min.css @@ -0,0 +1,2 @@ +foo[attr="multiple spaces"]{content:"Hello World!"}foo[attr="Hel\ +lo"]{content:" \"World\""} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/vladmirated.css b/mrclay/minify/min_unit_tests/_test_files/css/vladmirated.css new file mode 100644 index 000000000000..819835e582ce --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/vladmirated.css @@ -0,0 +1,658 @@ +/* from http://www.vladimirated.com/web-development-minify-css-using-php-and-cssmin-class */ + + #comments_inviter #close_me { + clear: both; + text-align: center; + border-top: 1px solid #eeeeee; + padding-top: 10px; + } + + #comments_inviter #close_me span { + color: #108eed; + cursor: pointer; + font-weight: bold; + } + + #comments_inviter img { + float: left; + margin-right: 3px; + margin-bottom: 10px; + } + + #comments_inviter { + width: 200px; + background-color: #FFFFFF; + border: 4px solid #eeeeee; + font-size: 10px; + font-family: verdana; + padding: 10px; + color: #333333; + } + + .one_com { + background-color: #FAFAFA; + padding: 10px; + margin-bottom: 20px; + border: 1px solid #EEEEEE; + } + + .one_com .com_says, .one_com .com_det { + text-transform: lowercase; + color: #333333; + padding: 0px; + font-family: verdana; + margin: 0px; + font-size: 13px; + font-weight: bold; + } + + .flvPlayer { + text-align: center; + border: 5px solid #dddddd; + width: 320px; + } + + .one_com .com_det { + font-size: 10px; + font-weight: normal; + margin-bottom: 20px; + padding-bottom: 10px; + border-bottom: 8px solid #eeeeee; + } + + .one_com .com_det a { + text-decoration: none; + } + + .one_com .com_txt { + background-color: #ffffff; + margin-bottom: 10px; + border-bottom: 2px solid #eeeeee + } + + .one_com .com_txt p { + font-family: verdana; + font-size: 13px; + color: #777777; + margin: 0px; + padding: 5px; + padding-bottom: 10px; + text-transform: lowercase; + } + + .one_com .com_says a { + color: #333333; + } + + .one_com .com_det a { + color: #333333; + } + + .post_box .related_posts { + + } + + .post_box .related_posts p { + padding: 0px; + margin: 0px; + padding-bottom: 20px; + padding-left: 35px; + font-family: verdana; + + } + + .post_box .related_posts a { + color: #108eed; + } + + .post_nav_2 p { + + text-align: center; + color: #cccccc; + font-family: verdana; + } + + .post_box .related_posts h3, #comments_box #respond, .comments_posted h3 { + padding: 0px; + margin: 0px; + font-size: 18px; + color: #FF8000; + padding-top: 30px; + margin-bottom: 20px; + width: 300px; + border-bottom: 5px solid #e0e0e0; + } + + .comments_posted { + + margin-bottom: 50px; + + } + + .comments_posted h3 { + padding: 0px; + margin: 0px; + margin-bottom: 20px; + + } + + .cmt_txtarea { + width: 300px; + height: 100px; + + } + + #comments_box #respond { + + padding-top: 0px; + margin-bottom: 0px; + + } + + .pagetitle { + color: #65DA33; + text-align: center; + } + + #searchform { + padding: 0px; + margin: 0px; + } + + .si { + background-color: #FFFFEE; + border: 1px solid #e0e0e0; + } + + #rightcol #r_news, #rightcol #linksbro, #rightcol #quick_tags { + margin-top: 30px; + padding-bottom: 10px; + } + + #post_nav p { + padding: 0px; + margin: 0px; + padding-bottom: 5px; + } + + #post_nav { + text-align: left; + padding-bottom: 15px; + } + + #post_nav a, .post_nav_2 p a { + text-decoration: none; + font-family: Verdana; + font-size: 12px; + color: #108eed; + } + + #post_nav a:hover, .post_nav_2 p a:hover { + text-decoration: underline; + color: #FF8000; + } + + #rightcol #about { + padding-bottom: 10px; + } + + #rightcol #r_news input { + color: #333333; + font-size: 12px; + } + + #header { + height: 200px; + width: 100%; + background-image: url('images/header_bg.jpg'); + background-repeat: x-repeat; + } + + #header img { + + float: right; + margin-right: -3px; + z-index: 100; + + } + + .tags { + text-transform: lowercase; + color: #333333; + font-family: arial; + font-size: 12px; + border-top: 2px dotted #EEEEEE; + width: 300px; + padding-top: 20px; + padding-bottom: 0px; + margin-top: 0px; + padding-left: 20px; + padding-right: 20px; + } + + .tags a { + color: #108eed; + } + + .tags p { + text-align: left; + margin: 0px; + padding: 0px; + } + + blockquote strong { + font-family: verdana; + display: block; + margin-top: 10px; + color: #FF0000; + font-style: italic; + text-align: right; + } + + blockquote { + margin: 0px; + background-color: #eeeeee; + border: 2px solid #dddddd; + padding: 24px; + padding-top: 10px; + padding-left: 60px; + padding-bottom: 10px; + font-size: 13px; + color: #333333; + margin-bottom: 30px; + margin-top: 10px; + } + + + html>body #header img { margin-right: 0px; } + + #subscribe h3 { + color: #ff0000; + margin-top: 30px; + padding: 20px; + } + + .post_actions a{ + color: #108eed; + } + + .post_actions { + border-top: 4px solid #DDDDDD; + border-bottom: 1px solid #EEEEEE; + text-align: center; + background-color: #FFFFDd; + color: #dddddd; + white-space: no-wrap; + padding-left: 20px; + padding-bottom: 5px; + text-transform: capitalize; + } + + #subscribe td { + color: #333333; + font-size: 12px; + text-transform: lowercase; + } + + #subscribe input { + font-size: 13px; + color: #333333; + } + + .post_content { + font-size: 13px; + margin-top: 10px; + padding-bottom: 10px; + text-align: justify; + font-family: verdana; + } + + .post_content p { + margin: 0px; + padding: 0px; + padding-bottom: 20px; + line-height: 20px; + } + + #header h1 { + z-index: 200; + margin: 0px; + position: absolute; + float: left; + text-transform: lowercase; + padding: 0px; + font-size: 45px; + margin-top: 70px; + margin-left: 40px; + + } + + #header h1 a { + white-space: no-wrap; + text-decoration: none; + color: #FAFAFA; + display: block + } + + #header h1 a:hover { + color: #FAFAFA; + border-bottom: 3px dotted #FAFAFA; + } + + html>body #header h1 { margin-left: 60px; } + + body { + margin: 0px; + padding: 0px; + height: 100%; + width: 100%; + font-family: 'Lucida Sans Unicode', 'Lucida Grande', Sans-Serif, Verdana, Arial; + font-size: 12px; + } + + #leftcol { + float: left; + width: 200px; + margin-left: 0px; + margin-top: 17px; + color: #000; + padding: 3px; + height: 100%; + } + + #leftcol .box_head h3 { + text-transform: uppercase; + padding: 0px; + margin: 0px; + font-family: georgia; + font-size: 18px; + color: #dddddd; + border-top: 4px solid #dddddd; + border-bottom: 4px solid #cccccc; + padding-left: 10px; + padding-top: 10px; + padding-bottom: 10px; + background-image: url('images/stripesbg.png'); + margin-bottom: 10px; + } + + #leftcol .box_head input { + text-transform: lowercase; + color: #333333; + } + + #leftcol .box_head { + margin-left: 7px; + background-color: #ffefd4; + border-bottom: 2px solid #eeeeee; + padding-bottom: 20px; + margin-bottom: 30px; + } + + #leftcol .box_head p a { + color: #0a2d4d; + display: block; + text-decoration: none; + border-bottom: 3px solid #fefefe; + padding-top: 20px; + text-transform: lowercase; + padding-bottom: 20px; + padding-left: 5px; + padding-right: 5px; + } + + #leftcol .box_head p a:hover { + background-color: #fafafa; + border-bottom: 3px solid #eeeeee; + color: #000000; + } + + #leftcol .box_head p { + text-align: left; + margin: 0px; + width: 170px; + padding-bottom: 0px; + padding-top: 0px; + font-size: 11px; + } + + #rightcol { + position: absolute; + left: 77%; + top: 278px; + border: 3px solid #eeeeee; + width: 200px; + z-index: 3; + color: #333333; + padding: 10px; + text-transform: lowercase; + + } + + #rightcol p { + padding: 0px; + marging: 0px; + text-align: justify; + } + + #rightcol #about img, #rightcol #linksbro img { + border: 5px solid #eeeeee; + } + + #rightcol #about h3, #rightcol #r_news h3, #rightcol #linksbro h3, #rightcol #quick_tags h3 { + background-color: #fafafa; + border: 1px dotted #e0e0e0; + font-size: 14px; + color: #104bbc; + padding: 5px; + padding-top: 10px; + font-family: Arial; + padding-bottom: 10px; + } + + #rightcol #about p a, #rightcol #r_news p a, #rightcol #linksbro p a { + color: #108eed; + } + + #rightcol #about p, #rightcol #r_news p, #rightcol #linksbro p { + font-size: 12px; + text-align: left; + } + + #content_warp { + margin: 20px 25% 0 215px; + padding: 3px; + color: #000; + background-color: #ededed; + } + + #content { + margin: 5px; + background-color: #FFFFFF; + padding: 10px; + } + + + #footer { + width: 99%; + margin-top: 30px; + height: 98px; + background-color: #101b1d; + } + + #footer td a { + color: #FF8000; + } + + #footer td a img { + border: 2px solid #108eed; + } + + #footer td p { + font-family: Verdana; + font-size: 10px; + color: #c0c0c0; + padding: 0px; + margin: 0px; + text-align: center; + padding-bottom: 10px; + } + + .s_offer { + color: #65DA33; + font-size: 20px; + font-weight: bold; + font-style: normal; + } + + .post_box { + text-transform: lowercase; + margin-bottom: 40px; + } + + #newsletter_box { + text-transform: lowercase; + margin-bottom: 10px; + margin-top: 30px; + font-style: normal; + background-color: #ffffff; + border: 5px solid #dddddd; + } + + #newsletter_head { + color: #EEEEEE; + font-family: Georgia; + background-image: url('images/stripesbg.png'); + padding: 10px; + padding-left: 30px; + border-bottom: 5px solid #dddddd; + } + + #newsletter_body { + color: #333333; + font-family: Verdana; + text-align: justify; + background-color: #FFFFFF; + padding: 10px; + font-size: 13px; + } + + .s_offer { + color: #65DA33; + font-size: 26px; + font-weight: bold; + font-style: normal; + } + + .post_title a { + color: #EEEEEE; + text-decoration: none; + } + + .post_title a:hover { + color: #c0c0c0; + } + + .post_title { + background-image: url('images/stripe_post.png'); + text-transform: uppercase; + font-size: 18px; + font-family: georgia; + padding: 10px; + border-top: 4px solid #c0c0c0; + margin: 0px; + border-bottom: 2px solid #ffffdd; + } + + .post_det { + text-transform: none; + margin: 0px; + border-top: 1px solid #f0f0f0; + padding: 0px; + padding-top: 5px; + color: #999999; + font-size: 10px; + font-family: verdana; + margin-bottom: 20px; + background-color: #eeeeee; + padding-bottom: 5px; + padding-left: 10px; + text-align: left; + border-bottom: 2px solid #dddddd; + } + + .post_det a { + color: #999999; + text-decoration: none; + } + + + .subtle { + text-transform: lowercase; + font-size: 10px; + font-family: verdana; + color: #108eed; + text-align: justify; + } + + #top_menu #navlist, #top_menu #navlist li { + padding:0px; + margin: 0px; + padding-top: 14px; + text-transform: lowercase; + padding-bottom: 17px; + padding-left: 30px; + border-left: 1px solid #65cdef; + } + + #top_menu #navlist, #top_menu #navlist li #first { + + border-left: 0px; + + } + + #top_menu #navlist { + padding-left: 30px; + background-color: #1dabd9; + border-top: 5px solid #0e96c3; + border-bottom: 5px solid #0e96c3; + } + + #top_menu #navlist li { + color: #444444; + font-size: 10px; + display: inline; + list-style-type: none; + padding-right: 30px; + } + + #top_menu #navlist li a { + text-decoration: none; + font-family: Verdana; + color: #fafafa; + font-size: 12px; + font-weight: bold; + } + + #top_menu #navlist li a:hover { + color: #333333; + } + + .post_content a { + color: #108eed; + } + + ul#tagcloud { padding:0; margin:0; text-align:center; list-style:none; } + ul#tagcloud li { display:inline; font-size:70%; color:#ccc; background: none; padding: 0;} + ul#tagcloud li a, ul#tagcloud li a:link { text-decoration:none; } + ul#tagcloud li a:hover { text-decoration:underline; } + ul#tagcloud li.t1 a { color:#797979; font-size: 120%; } + ul#tagcloud li.t2 a { color:#6d6d6d; font-size: 160%; } + ul#tagcloud li.t3 a { color:#616161; font-size: 190%; } + ul#tagcloud li.t4 a { color:#555555; font-size: 210%; } + ul#tagcloud li.t5 a { color:#484848; font-size: 230%; } + ul#tagcloud li.t6 a { color:#3c3c3c; font-size: 250%; } + ul#tagcloud li.t7 a { color:#303030; font-size: 270%; } + ul#tagcloud li.t8 a { color:#242424; font-size: 290%; } + ul#tagcloud li.t9 a { color:#181818; font-size: 310%; } + ul#tagcloud li.t10 a { color:#0c0c0c; font-size: 330%; } \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/vladmirated.min.css b/mrclay/minify/min_unit_tests/_test_files/css/vladmirated.min.css new file mode 100644 index 000000000000..a59e5001b534 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css/vladmirated.min.css @@ -0,0 +1,79 @@ +#comments_inviter +#close_me{clear:both;text-align:center;border-top:1px solid #eee;padding-top:10px}#comments_inviter #close_me +span{color:#108eed;cursor:pointer;font-weight:bold}#comments_inviter +img{float:left;margin-right:3px;margin-bottom:10px}#comments_inviter{width:200px;background-color:#FFF;border:4px +solid #eee;font-size:10px;font-family:verdana;padding:10px;color:#333}.one_com{background-color:#FAFAFA;padding:10px;margin-bottom:20px;border:1px +solid #EEE}.one_com .com_says, .one_com +.com_det{text-transform:lowercase;color:#333;padding:0px;font-family:verdana;margin:0px;font-size:13px;font-weight:bold}.flvPlayer{text-align:center;border:5px +solid #ddd;width:320px}.one_com +.com_det{font-size:10px;font-weight:normal;margin-bottom:20px;padding-bottom:10px;border-bottom:8px solid #eee}.one_com .com_det +a{text-decoration:none}.one_com +.com_txt{background-color:#fff;margin-bottom:10px;border-bottom:2px solid #eee}.one_com .com_txt +p{font-family:verdana;font-size:13px;color:#777;margin:0px;padding:5px;padding-bottom:10px;text-transform:lowercase}.one_com .com_says +a{color:#333}.one_com .com_det +a{color:#333}.post_box +.related_posts{}.post_box .related_posts +p{padding:0px;margin:0px;padding-bottom:20px;padding-left:35px;font-family:verdana}.post_box .related_posts +a{color:#108eed}.post_nav_2 +p{text-align:center;color:#ccc;font-family:verdana}.post_box .related_posts h3, #comments_box #respond, .comments_posted +h3{padding:0px;margin:0px;font-size:18px;color:#FF8000;padding-top:30px;margin-bottom:20px;width:300px;border-bottom:5px solid #e0e0e0}.comments_posted{margin-bottom:50px}.comments_posted +h3{padding:0px;margin:0px;margin-bottom:20px}.cmt_txtarea{width:300px;height:100px}#comments_box +#respond{padding-top:0px;margin-bottom:0px}.pagetitle{color:#65DA33;text-align:center}#searchform{padding:0px;margin:0px}.si{background-color:#FFE;border:1px +solid #e0e0e0}#rightcol #r_news, #rightcol #linksbro, #rightcol +#quick_tags{margin-top:30px;padding-bottom:10px}#post_nav +p{padding:0px;margin:0px;padding-bottom:5px}#post_nav{text-align:left;padding-bottom:15px}#post_nav a, .post_nav_2 p +a{text-decoration:none;font-family:Verdana;font-size:12px;color:#108eed}#post_nav a:hover, .post_nav_2 p a:hover{text-decoration:underline;color:#FF8000}#rightcol +#about{padding-bottom:10px}#rightcol #r_news +input{color:#333;font-size:12px}#header{height:200px;width:100%;background-image:url('images/header_bg.jpg');background-repeat:x-repeat}#header +img{float:right;margin-right:-3px;z-index:100}.tags{text-transform:lowercase;color:#333;font-family:arial;font-size:12px;border-top:2px dotted #EEE;width:300px;padding-top:20px;padding-bottom:0px;margin-top:0px;padding-left:20px;padding-right:20px}.tags +a{color:#108eed}.tags +p{text-align:left;margin:0px;padding:0px}blockquote +strong{font-family:verdana;display:block;margin-top:10px;color:#F00;font-style:italic;text-align:right}blockquote{margin:0px;background-color:#eee;border:2px +solid #ddd;padding:24px;padding-top:10px;padding-left:60px;padding-bottom:10px;font-size:13px;color:#333;margin-bottom:30px;margin-top:10px}html>body #header +img{margin-right:0px}#subscribe +h3{color:#f00;margin-top:30px;padding:20px}.post_actions +a{color:#108eed}.post_actions{border-top:4px solid #DDD;border-bottom:1px solid #EEE;text-align:center;background-color:#FFD;color:#ddd;white-space:no-wrap;padding-left:20px;padding-bottom:5px;text-transform:capitalize}#subscribe +td{color:#333;font-size:12px;text-transform:lowercase}#subscribe +input{font-size:13px;color:#333}.post_content{font-size:13px;margin-top:10px;padding-bottom:10px;text-align:justify;font-family:verdana}.post_content +p{margin:0px;padding:0px;padding-bottom:20px;line-height:20px}#header +h1{z-index:200;margin:0px;position:absolute;float:left;text-transform:lowercase;padding:0px;font-size:45px;margin-top:70px;margin-left:40px}#header h1 +a{white-space:no-wrap;text-decoration:none;color:#FAFAFA;display:block}#header h1 a:hover{color:#FAFAFA;border-bottom:3px dotted #FAFAFA}html>body #header +h1{margin-left:60px}body{margin:0px;padding:0px;height:100%;width:100%;font-family:'Lucida Sans Unicode','Lucida Grande',Sans-Serif,Verdana,Arial;font-size:12px}#leftcol{float:left;width:200px;margin-left:0px;margin-top:17px;color:#000;padding:3px;height:100%}#leftcol .box_head +h3{text-transform:uppercase;padding:0px;margin:0px;font-family:georgia;font-size:18px;color:#ddd;border-top:4px solid #ddd;border-bottom:4px solid #ccc;padding-left:10px;padding-top:10px;padding-bottom:10px;background-image:url('images/stripesbg.png');margin-bottom:10px}#leftcol .box_head +input{text-transform:lowercase;color:#333}#leftcol +.box_head{margin-left:7px;background-color:#ffefd4;border-bottom:2px solid #eee;padding-bottom:20px;margin-bottom:30px}#leftcol .box_head p +a{color:#0a2d4d;display:block;text-decoration:none;border-bottom:3px solid #fefefe;padding-top:20px;text-transform:lowercase;padding-bottom:20px;padding-left:5px;padding-right:5px}#leftcol .box_head p a:hover{background-color:#fafafa;border-bottom:3px solid #eee;color:#000}#leftcol .box_head +p{text-align:left;margin:0px;width:170px;padding-bottom:0px;padding-top:0px;font-size:11px}#rightcol{position:absolute;left:77%;top:278px;border:3px +solid #eee;width:200px;z-index:3;color:#333;padding:10px;text-transform:lowercase}#rightcol +p{padding:0px;marging:0px;text-align:justify}#rightcol #about img, #rightcol #linksbro +img{border:5px +solid #eee}#rightcol #about h3, #rightcol #r_news h3, #rightcol #linksbro h3, #rightcol #quick_tags +h3{background-color:#fafafa;border:1px +dotted #e0e0e0;font-size:14px;color:#104bbc;padding:5px;padding-top:10px;font-family:Arial;padding-bottom:10px}#rightcol #about p a, #rightcol #r_news p a, #rightcol #linksbro p +a{color:#108eed}#rightcol #about p, #rightcol #r_news p, #rightcol #linksbro +p{font-size:12px;text-align:left}#content_warp{margin:20px +25% 0 215px;padding:3px;color:#000;background-color:#ededed}#content{margin:5px;background-color:#FFF;padding:10px}#footer{width:99%;margin-top:30px;height:98px;background-color:#101b1d}#footer td +a{color:#FF8000}#footer td a +img{border:2px +solid #108eed}#footer td +p{font-family:Verdana;font-size:10px;color:#c0c0c0;padding:0px;margin:0px;text-align:center;padding-bottom:10px}.s_offer{color:#65DA33;font-size:20px;font-weight:bold;font-style:normal}.post_box{text-transform:lowercase;margin-bottom:40px}#newsletter_box{text-transform:lowercase;margin-bottom:10px;margin-top:30px;font-style:normal;background-color:#fff;border:5px +solid #ddd}#newsletter_head{color:#EEE;font-family:Georgia;background-image:url('images/stripesbg.png');padding:10px;padding-left:30px;border-bottom:5px solid #ddd}#newsletter_body{color:#333;font-family:Verdana;text-align:justify;background-color:#FFF;padding:10px;font-size:13px}.s_offer{color:#65DA33;font-size:26px;font-weight:bold;font-style:normal}.post_title +a{color:#EEE;text-decoration:none}.post_title a:hover{color:#c0c0c0}.post_title{background-image:url('images/stripe_post.png');text-transform:uppercase;font-size:18px;font-family:georgia;padding:10px;border-top:4px solid #c0c0c0;margin:0px;border-bottom:2px solid #ffd}.post_det{text-transform:none;margin:0px;border-top:1px solid #f0f0f0;padding:0px;padding-top:5px;color:#999;font-size:10px;font-family:verdana;margin-bottom:20px;background-color:#eee;padding-bottom:5px;padding-left:10px;text-align:left;border-bottom:2px solid #ddd}.post_det +a{color:#999;text-decoration:none}.subtle{text-transform:lowercase;font-size:10px;font-family:verdana;color:#108eed;text-align:justify}#top_menu #navlist, #top_menu #navlist +li{padding:0px;margin:0px;padding-top:14px;text-transform:lowercase;padding-bottom:17px;padding-left:30px;border-left:1px solid #65cdef}#top_menu #navlist, #top_menu #navlist li +#first{border-left:0px}#top_menu +#navlist{padding-left:30px;background-color:#1dabd9;border-top:5px solid #0e96c3;border-bottom:5px solid #0e96c3}#top_menu #navlist +li{color:#444;font-size:10px;display:inline;list-style-type:none;padding-right:30px}#top_menu #navlist li +a{text-decoration:none;font-family:Verdana;color:#fafafa;font-size:12px;font-weight:bold}#top_menu #navlist li a:hover{color:#333}.post_content +a{color:#108eed}ul#tagcloud{padding:0;margin:0;text-align:center;list-style:none}ul#tagcloud +li{display:inline;font-size:70%;color:#ccc;background:none;padding:0}ul#tagcloud li a, ul#tagcloud li a:link{text-decoration:none}ul#tagcloud li a:hover{text-decoration:underline}ul#tagcloud li.t1 +a{color:#797979;font-size:120%}ul#tagcloud li.t2 +a{color:#6d6d6d;font-size:160%}ul#tagcloud li.t3 +a{color:#616161;font-size:190%}ul#tagcloud li.t4 +a{color:#555;font-size:210%}ul#tagcloud li.t5 +a{color:#484848;font-size:230%}ul#tagcloud li.t6 +a{color:#3c3c3c;font-size:250%}ul#tagcloud li.t7 +a{color:#303030;font-size:270%}ul#tagcloud li.t8 +a{color:#242424;font-size:290%}ul#tagcloud li.t9 +a{color:#181818;font-size:310%}ul#tagcloud li.t10 +a{color:#0c0c0c;font-size:330%} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp.css b/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp.css new file mode 100644 index 000000000000..22c109f842ab --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp.css @@ -0,0 +1,17 @@ +@import "/_test_files/css_uriRewriter/foo.css"; +@import '/_test_files/css_uriRewriter/bar/foo.css' print; +@import '/_test_files/bar/foo.css' print; +@import '/foo.css' print; +@import '/css/foo.css'; /* abs, should not alter */ +@import 'http://foo.com/css/foo.css'; /* scheme, should not alter */ +@import url(/_test_files/foo.css) tv, projection; +@import url("/css/foo.css"); /* abs, should not alter */ +@import url(/css2/foo.css); /* abs, should not alter */ +@import url(foo:bar); /* scheme, should not alter */ +foo {background:url('/_test_files/css_uriRewriter/bar/foo.png')} +foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter */ +foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ +foo {background:url(foo:bar);} /* scheme, should not alter */ +foo {background:url("/_test_files/css_uriRewriter/foo bar.jpg");} +@import url('/_test_files/css_uriRewriter/foo bar.css'); +@import "/_test_files/css_uriRewriter/foo bar.css"; diff --git a/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend.css b/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend.css new file mode 100644 index 000000000000..ce31df1b7ca2 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend.css @@ -0,0 +1,17 @@ +@import "http://cnd.com/A/B/foo.css"; +@import 'http://cnd.com/A/B/bar/foo.css' print; +@import 'http://cnd.com/A/bar/foo.css' print; +@import 'http://cnd.com/foo.css' print; +@import '/css/foo.css'; /* abs, should not alter */ +@import 'http://foo.com/css/foo.css'; /* scheme, should not alter */ +@import url(http://cnd.com/A/foo.css) tv, projection; +@import url("/css/foo.css"); /* abs, should not alter */ +@import url(/css2/foo.css); /* abs, should not alter */ +@import url(foo:bar); /* scheme, should not alter */ +foo {background:url('http://cnd.com/A/B/bar/foo.png')} +foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter */ +foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ +foo {background:url(foo:bar);} /* scheme, should not alter */ +foo {background:url("http://cnd.com/A/B/foo bar.jpg");} +@import url('http://cnd.com/A/B/foo bar.css'); +@import "http://cnd.com/A/B/foo bar.css"; diff --git a/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend2.css b/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend2.css new file mode 100644 index 000000000000..087d94ddd004 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend2.css @@ -0,0 +1,17 @@ +@import "//cnd.com/A/B/foo.css"; +@import '//cnd.com/A/B/bar/foo.css' print; +@import '//cnd.com/A/bar/foo.css' print; +@import '//cnd.com/foo.css' print; +@import '/css/foo.css'; /* abs, should not alter */ +@import 'http://foo.com/css/foo.css'; /* scheme, should not alter */ +@import url(//cnd.com/A/foo.css) tv, projection; +@import url("/css/foo.css"); /* abs, should not alter */ +@import url(/css2/foo.css); /* abs, should not alter */ +@import url(foo:bar); /* scheme, should not alter */ +foo {background:url('//cnd.com/A/B/bar/foo.png')} +foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter */ +foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ +foo {background:url(foo:bar);} /* scheme, should not alter */ +foo {background:url("//cnd.com/A/B/foo bar.jpg");} +@import url('//cnd.com/A/B/foo bar.css'); +@import "//cnd.com/A/B/foo bar.css"; diff --git a/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/in.css b/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/in.css new file mode 100644 index 000000000000..3bdce3605a1e --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/in.css @@ -0,0 +1,17 @@ +@import "foo.css"; +@import 'bar/foo.css' print; +@import '../bar/foo.css' print; +@import '../../foo.css' print; +@import '/css/foo.css'; /* abs, should not alter */ +@import 'http://foo.com/css/foo.css'; /* scheme, should not alter */ +@import url(../foo.css) tv, projection; +@import url("/css/foo.css"); /* abs, should not alter */ +@import url(/css2/foo.css); /* abs, should not alter */ +@import url(foo:bar); /* scheme, should not alter */ +foo {background:url('bar/foo.png')} +foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter */ +foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ +foo {background:url(foo:bar);} /* scheme, should not alter */ +foo {background:url("foo bar.jpg");} +@import url('foo bar.css'); +@import "foo bar.css"; diff --git a/mrclay/minify/min_unit_tests/_test_files/html/before.html b/mrclay/minify/min_unit_tests/_test_files/html/before.html new file mode 100644 index 000000000000..3b06d1815529 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/html/before.html @@ -0,0 +1,96 @@ + + + + + + + + + + + css Zen Garden: The Beauty in CSS Design + + + + + + + + + + + + +

    Browser != IE

    +
    + +
    +	White  space  is  important   here!
    +		
    +
    +

    A demonstration of what can be accomplished visually through CSS-based design. Select any style sheet from the list to load it into this page.

    +

    Download the sample html file and css file

    +
    + +
    + + \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/html/before.min.html b/mrclay/minify/min_unit_tests/_test_files/html/before.min.html new file mode 100644 index 000000000000..7ec603d9e213 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/html/before.min.html @@ -0,0 +1,38 @@ +css Zen Garden: The Beauty in CSS Design +

    Browser != IE

    css Zen Garden

    The Beauty of CSS +Design

    +	White  space  is  important   here!
    +		

    A demonstration of what can be accomplished visually through CSS-based design. Select any style sheet from the list to load it into this page.

    Download the sample html file and css file

    \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/html/before2.html b/mrclay/minify/min_unit_tests/_test_files/html/before2.html new file mode 100644 index 000000000000..9592371cd220 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/html/before2.html @@ -0,0 +1,95 @@ + + + + + + + + + + + css Zen Garden: The Beauty in CSS Design + + + + + + + + + + + + +

    Browser != IE

    +
    + +
    +	White  space  is  important   here!
    +		
    +
    +

    A demonstration of what can be accomplished visually through CSS-based design. Select any style sheet from the list to load it into this page.

    +

    Download the sample html file and css file

    +
    + +Preserve at least 1 char of whitespace near scripts in case of document.write(). +
    + + \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/html/before2.min.html b/mrclay/minify/min_unit_tests/_test_files/html/before2.min.html new file mode 100644 index 000000000000..0e1680f2fe60 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/html/before2.min.html @@ -0,0 +1,38 @@ +css Zen Garden: The Beauty in CSS Design +

    Browser != IE

    css Zen Garden

    The Beauty of CSS +Design

    +	White  space  is  important   here!
    +		

    A demonstration of what can be accomplished visually through CSS-based design. Select any style sheet from the list to load it into this page.

    Download the sample html file and css file

    Preserve at least 1 char of whitespace near scripts in case of document.write().
    \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/htmlHelper_groupsConfig.php b/mrclay/minify/min_unit_tests/_test_files/htmlHelper_groupsConfig.php new file mode 100644 index 000000000000..7f5153d99f19 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/htmlHelper_groupsConfig.php @@ -0,0 +1,8 @@ + array( + '//_test_files/css/paths_prepend.css' + ,'//_test_files/css/styles.css' + ) +); diff --git a/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/adjacent.css b/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/adjacent.css new file mode 100644 index 000000000000..da52c6949129 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/adjacent.css @@ -0,0 +1,3 @@ +/* @import url('bad.css' ) bad; */ +adjacent2 foo { background: red url(/red.gif); } +adjacent2 bar { background: url('../green.gif') } \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/tv.css b/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/tv.css new file mode 100644 index 000000000000..69fa2f5ef337 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/tv.css @@ -0,0 +1,4 @@ +@import url( adjacent.css ) all; +@import '../input.css'; +tv foo { background: red url(/red.gif); } +tv bar { background: url('../green.gif') } \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/adjacent.css b/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/adjacent.css new file mode 100644 index 000000000000..fd643486db68 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/adjacent.css @@ -0,0 +1,4 @@ +@import url(../../css/styles.css); +@import url(http://example.com/hello.css); +adjacent foo { background: red url(/red.gif); } +adjacent bar { background: url('../green.gif') } \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/input.css b/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/input.css new file mode 100644 index 000000000000..b0f662272bfb --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/input.css @@ -0,0 +1,5 @@ +@import url(adjacent.css) screen; +@import "1/tv.css" tv, projection; +@import "../lib/css/example.css"; +input foo { background: red url(/red.gif); } +input bar { background: url('../green.gif') } \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/output.css b/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/output.css new file mode 100644 index 000000000000..ca7d8723690e --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/output.css @@ -0,0 +1,52 @@ +@media screen { +@charset "utf-8"; + +/* some CSS to try to exercise things in general */ + +@import url(/more.css); + + body, td, th { + font-family: Verdana , "Bitstream Vera Sans" , Arial Narrow, sans-serif ; + + font-size : 12px; +} + +.nav { + margin-left: 20%; +} +#main-nav { + background-color: red; + border: 1px solid #00ff77; +} + +div#content +h1 + p { + padding-top: 0; + margin-top: 0; +} + +@media all and (min-width: 640px) { + #media-queries-1 { background-color: #0f0; } +} + +@media screen and (max-width: 2000px) { + #media-queries-2 { background-color: #0f0; } +} +@import url(http://example.com/hello.css); +adjacent foo { background: red url(/red.gif); } +adjacent bar { background: url('../green.gif') } +} + +@media tv,projection { +/* @import url('1/bad.css') bad; */ +adjacent2 foo { background: red url(/red.gif); } +adjacent2 bar { background: url('green.gif') } +@import '../input.css'; +tv foo { background: red url(/red.gif); } +tv bar { background: url('green.gif') } +} + +input.test bar { background: url('../lib/img/green.gif') } + +input foo { background: red url(/red.gif); } +input bar { background: url('../green.gif') } \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/importProcessor/lib/css/example.css b/mrclay/minify/min_unit_tests/_test_files/importProcessor/lib/css/example.css new file mode 100644 index 000000000000..715d86025702 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/importProcessor/lib/css/example.css @@ -0,0 +1 @@ +input.test bar { background: url('../img/green.gif') } diff --git a/mrclay/minify/min_unit_tests/_test_files/js/before.js b/mrclay/minify/min_unit_tests/_test_files/js/before.js new file mode 100644 index 000000000000..ae96568254a7 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/js/before.js @@ -0,0 +1,66 @@ +/*! is.js + + (c) 2001 Douglas Crockford + 2001 June 3 +*/ + +// is + +// The -is- object is used to identify the browser. Every browser edition +// identifies itself, but there is no standard way of doing it, and some of +// the identification is deceptive. This is because the authors of web +// browsers are liars. For example, Microsoft's IE browsers claim to be +// Mozilla 4. Netscape 6 claims to be version 5. + +var is = { + ie: navigator.appName == 'Microsoft Internet Explorer', + java: navigator.javaEnabled(), + ns: navigator.appName == 'Netscape', + ua: navigator.userAgent.toLowerCase(), + version: parseFloat(navigator.appVersion.substr(21)) || + parseFloat(navigator.appVersion), + win: navigator.platform == 'Win32' +} +/*!* + * preserve this comment, too + */ +is.mac = is.ua.indexOf('mac') >= 0; +if (is.ua.indexOf('opera') >= 0) { + is.ie = is.ns = false; + is.opera = true; +} +if (is.ua.indexOf('gecko') >= 0) { + is.ie = is.ns = false; + is.gecko = true; +} + +/*@cc_on + /*@if (@_win32) + if (is.ie && is.win) + document.write("PASS: IE/win honored conditional comment.
    "); + @else @*/ + if (is.ie && is.win) + document.write("FAIL: IE/win did not honor multi-line conditional comment.
    "); + else + document.write("PASS: Non-IE/win browser ignores multi-line conditional comment.
    "); + /*@end +@*/ + +var recognizesCondComm = true; +//@cc_on/* +recognizesCondComm = false; +//@cc_on*/ + +if ((is.ie && is.win) == recognizesCondComm) + document.write("PASS: IE/win honored single-line conditional comment.
    "); +else + document.write("FAIL: Non-IE/win browser did not ignore single-line conditional comment.
    "); + +// hello +//@cc_on/* +// world +//@cc_on*/ +//@cc_on/* +'hello'; +/*!* preserved */ +/*!* preserved */ \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/before.min.js b/mrclay/minify/min_unit_tests/_test_files/js/before.min.js new file mode 100644 index 000000000000..bccd725cfae4 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/js/before.min.js @@ -0,0 +1,27 @@ +/*! is.js + + (c) 2001 Douglas Crockford + 2001 June 3 +*/ +var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaEnabled(),ns:navigator.appName=='Netscape',ua:navigator.userAgent.toLowerCase(),version:parseFloat(navigator.appVersion.substr(21))||parseFloat(navigator.appVersion),win:navigator.platform=='Win32'} +/*!* + * preserve this comment, too + */ +is.mac=is.ua.indexOf('mac')>=0;if(is.ua.indexOf('opera')>=0){is.ie=is.ns=false;is.opera=true;} +if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;}/*@cc_on + /*@if (@_win32) + if (is.ie && is.win) + document.write("PASS: IE/win honored conditional comment.
    "); + @else @*/if(is.ie&&is.win) +document.write("FAIL: IE/win did not honor multi-line conditional comment.
    ");else +document.write("PASS: Non-IE/win browser ignores multi-line conditional comment.
    ");/*@end +@*/var recognizesCondComm=true;//@cc_on/* +recognizesCondComm=false;//@cc_on*/ +if((is.ie&&is.win)==recognizesCondComm) +document.write("PASS: IE/win honored single-line conditional comment.
    ");else +document.write("FAIL: Non-IE/win browser did not ignore single-line conditional comment.
    ");//@cc_on/* +//@cc_on*/ +//@cc_on/* +'hello'; +/*!* preserved */ +/*!* preserved */ \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/before.min_plus.js b/mrclay/minify/min_unit_tests/_test_files/js/before.min_plus.js new file mode 100644 index 000000000000..6f06c6e6ce46 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/js/before.min_plus.js @@ -0,0 +1,22 @@ +/* is.js + + (c) 2001 Douglas Crockford + 2001 June 3 +*/ +var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaEnabled(),ns:navigator.appName=='Netscape',ua:navigator.userAgent.toLowerCase(),version:parseFloat(navigator.appVersion.substr(21))||parseFloat(navigator.appVersion),win:navigator.platform=='Win32'} +/** + * preserve this comment, too + */ +is.mac=is.ua.indexOf('mac')>=0;if(is.ua.indexOf('opera')>=0){is.ie=is.ns=false;is.opera=true;} +if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;}/*@cc_on + /*@if (@_win32) + if (is.ie && is.win) + document.write("PASS: IE/win honored conditional comment.
    "); + @else @*/if(is.ie&&is.win) +document.write("FAIL: IE/win did not honor multi-line conditional comment.
    ");else +document.write("PASS: Non-IE/win browser ignores multi-line conditional comment.
    ");/*@end +@*/var recognizesCondComm=true;//@cc_on/* +recognizesCondComm=false;//@cc_on*/ +if((is.ie&&is.win)==recognizesCondComm) +document.write("PASS: IE/win honored single-line conditional comment.
    ");else +document.write("FAIL: Non-IE/win browser did not ignore single-line conditional comment.
    "); \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/condcomm.js b/mrclay/minify/min_unit_tests/_test_files/js/condcomm.js new file mode 100644 index 000000000000..28aa1268beed --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/js/condcomm.js @@ -0,0 +1,14 @@ +var isWin; +/*@cc_on + @if (@_win32) + isWin = true; + @else @*/ isWin = false; + /*@end +@*/ + +isWin = /*@cc_on!*/!1; + +var recognizesCondComm = true; +//@cc_on/* +recognizesCondComm = false; +//@cc_on*/ diff --git a/mrclay/minify/min_unit_tests/_test_files/js/condcomm.min_plus.js b/mrclay/minify/min_unit_tests/_test_files/js/condcomm.min_plus.js new file mode 100644 index 000000000000..d8c1ed3861ef --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/js/condcomm.min_plus.js @@ -0,0 +1,13 @@ +var isWin; +/*@cc_on + @if (@_win32) + isWin = true; + @else @*/ + isWin = false; + /*@end +@*/ + +var recognizesCondComm = true; +//@cc_on/* +recognizesCondComm = false; +//@cc_on*/ \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/issue132.js b/mrclay/minify/min_unit_tests/_test_files/js/issue132.js new file mode 100644 index 000000000000..4ccfb1577ab4 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/js/issue132.js @@ -0,0 +1,7 @@ +// from jQuery tablesorter +ts.addParser({ + id: "currency", + is: function(s) { + return /^[£$€?.]/.test(s); + }, +}); diff --git a/mrclay/minify/min_unit_tests/_test_files/js/issue132.min.js b/mrclay/minify/min_unit_tests/_test_files/js/issue132.min.js new file mode 100644 index 000000000000..721518701c61 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/js/issue132.min.js @@ -0,0 +1 @@ +ts.addParser({id:"currency",is:function(s){return /^[£$€?.]/.test(s);},}); \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/issue141.min.js b/mrclay/minify/min_unit_tests/_test_files/js/issue141.min.js new file mode 100644 index 000000000000..10aa56e811f5 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/js/issue141.min.js @@ -0,0 +1,3 @@ +// The MinApp controller should cause this file to not be minified +// since the basename of the filepath matches the default noMinPattern + diff --git a/mrclay/minify/min_unit_tests/_test_files/js/issue144.js b/mrclay/minify/min_unit_tests/_test_files/js/issue144.js new file mode 100644 index 000000000000..204911da301b --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/js/issue144.js @@ -0,0 +1,9 @@ +a / ++b; +a * --b; +a++ - b; +a + --b; +a - ++b; +a + -b; +a + ++b; +a + --b; +a - --b; \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/issue144.min.js b/mrclay/minify/min_unit_tests/_test_files/js/issue144.min.js new file mode 100644 index 000000000000..e339d0aa5813 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/js/issue144.min.js @@ -0,0 +1 @@ +a/++b;a*--b;a++-b;a+--b;a-++b;a+-b;a+ ++b;a+--b;a- --b; \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/issue256.js b/mrclay/minify/min_unit_tests/_test_files/js/issue256.js new file mode 100644 index 000000000000..519a52f85920 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/js/issue256.js @@ -0,0 +1,3 @@ +!function(){}(window) + +!function(){}(window) \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/issue256.min.js b/mrclay/minify/min_unit_tests/_test_files/js/issue256.min.js new file mode 100644 index 000000000000..eb1b0d6ed0e4 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/js/issue256.min.js @@ -0,0 +1,2 @@ +!function(){}(window) +!function(){}(window) \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/jquery-1.2.3.js b/mrclay/minify/min_unit_tests/_test_files/js/jquery-1.2.3.js new file mode 100644 index 000000000000..c5a3337600c5 --- /dev/null +++ b/mrclay/minify/min_unit_tests/_test_files/js/jquery-1.2.3.js @@ -0,0 +1,3408 @@ +(function(){ +/*! + * jQuery 1.2.3 - New Wave Javascript + * + * Copyright (c) 2008 John Resig (jquery.com) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * $Date: 2008-02-06 00:21:25 -0500 (Wed, 06 Feb 2008) $ + * $Rev: 4663 $ + */ + +// Map over jQuery in case of overwrite +if ( window.jQuery ) + var _jQuery = window.jQuery; + +var jQuery = window.jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.prototype.init( selector, context ); +}; + +// Map over the $ in case of overwrite +if ( window.$ ) + var _$ = window.$; + +// Map the jQuery namespace to the '$' one +window.$ = jQuery; + +// A simple way to check for HTML strings or ID strings +// (both of which we optimize for) +var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/; + +// Is it a simple selector +var isSimple = /^.[^:#\[\.]*$/; + +jQuery.fn = jQuery.prototype = { + init: function( selector, context ) { + // Make sure that a selection was provided + selector = selector || document; + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this[0] = selector; + this.length = 1; + return this; + + // Handle HTML strings + } else if ( typeof selector == "string" ) { + // Are we dealing with HTML string or an ID? + var match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) + selector = jQuery.clean( [ match[1] ], context ); + + // HANDLE: $("#id") + else { + var elem = document.getElementById( match[3] ); + + // Make sure an element was located + if ( elem ) + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id != match[3] ) + return jQuery().find( selector ); + + // Otherwise, we inject the element directly into the jQuery object + else { + this[0] = elem; + this.length = 1; + return this; + } + + else + selector = []; + } + + // HANDLE: $(expr, [context]) + // (which is just equivalent to: $(content).find(expr) + } else + return new jQuery( context ).find( selector ); + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) + return new jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector ); + + return this.setArray( + // HANDLE: $(array) + selector.constructor == Array && selector || + + // HANDLE: $(arraylike) + // Watch for when an array-like object, contains DOM nodes, is passed in as the selector + (selector.jquery || selector.length && selector != window && !selector.nodeType && selector[0] != undefined && selector[0].nodeType) && jQuery.makeArray( selector ) || + + // HANDLE: $(*) + [ selector ] ); + }, + + // The current version of jQuery being used + jquery: "1.2.3", + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + // The number of elements contained in the matched element set + length: 0, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == undefined ? + + // Return a 'clean' array + jQuery.makeArray( this ) : + + // Return just the object + this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + // Build a new jQuery matched element set + var ret = jQuery( elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Force the current matched set of elements to become + // the specified array of elements (destroying the stack in the process) + // You should use pushStack() in order to do this, but maintain the stack + setArray: function( elems ) { + // Resetting the length to 0, then using the native Array push + // is a super-fast way to populate an object with array-like properties + this.length = 0; + Array.prototype.push.apply( this, elems ); + + return this; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + var ret = -1; + + // Locate the position of the desired element + this.each(function(i){ + if ( this == elem ) + ret = i; + }); + + return ret; + }, + + attr: function( name, value, type ) { + var options = name; + + // Look for the case where we're accessing a style value + if ( name.constructor == String ) + if ( value == undefined ) + return this.length && jQuery[ type || "attr" ]( this[0], name ) || undefined; + + else { + options = {}; + options[ name ] = value; + } + + // Check to see if we're setting style values + return this.each(function(i){ + // Set all the styles + for ( name in options ) + jQuery.attr( + type ? + this.style : + this, + name, jQuery.prop( this, options[ name ], type, i, name ) + ); + }); + }, + + css: function( key, value ) { + // ignore negative width and height values + if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 ) + value = undefined; + return this.attr( key, value, "curCSS" ); + }, + + text: function( text ) { + if ( typeof text != "object" && text != null ) + return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); + + var ret = ""; + + jQuery.each( text || this, function(){ + jQuery.each( this.childNodes, function(){ + if ( this.nodeType != 8 ) + ret += this.nodeType != 1 ? + this.nodeValue : + jQuery.fn.text( [ this ] ); + }); + }); + + return ret; + }, + + wrapAll: function( html ) { + if ( this[0] ) + // The elements to wrap the target around + jQuery( html, this[0].ownerDocument ) + .clone() + .insertBefore( this[0] ) + .map(function(){ + var elem = this; + + while ( elem.firstChild ) + elem = elem.firstChild; + + return elem; + }) + .append(this); + + return this; + }, + + wrapInner: function( html ) { + return this.each(function(){ + jQuery( this ).contents().wrapAll( html ); + }); + }, + + wrap: function( html ) { + return this.each(function(){ + jQuery( this ).wrapAll( html ); + }); + }, + + append: function() { + return this.domManip(arguments, true, false, function(elem){ + if (this.nodeType == 1) + this.appendChild( elem ); + }); + }, + + prepend: function() { + return this.domManip(arguments, true, true, function(elem){ + if (this.nodeType == 1) + this.insertBefore( elem, this.firstChild ); + }); + }, + + before: function() { + return this.domManip(arguments, false, false, function(elem){ + this.parentNode.insertBefore( elem, this ); + }); + }, + + after: function() { + return this.domManip(arguments, false, true, function(elem){ + this.parentNode.insertBefore( elem, this.nextSibling ); + }); + }, + + end: function() { + return this.prevObject || jQuery( [] ); + }, + + find: function( selector ) { + var elems = jQuery.map(this, function(elem){ + return jQuery.find( selector, elem ); + }); + + return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ? + jQuery.unique( elems ) : + elems ); + }, + + clone: function( events ) { + // Do the clone + var ret = this.map(function(){ + if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) { + // IE copies events bound via attachEvent when + // using cloneNode. Calling detachEvent on the + // clone will also remove the events from the orignal + // In order to get around this, we use innerHTML. + // Unfortunately, this means some modifications to + // attributes in IE that are actually only stored + // as properties will not be copied (such as the + // the name attribute on an input). + var clone = this.cloneNode(true), + container = document.createElement("div"); + container.appendChild(clone); + return jQuery.clean([container.innerHTML])[0]; + } else + return this.cloneNode(true); + }); + + // Need to set the expando to null on the cloned set if it exists + // removeData doesn't work here, IE removes it from the original as well + // this is primarily for IE but the data expando shouldn't be copied over in any browser + var clone = ret.find("*").andSelf().each(function(){ + if ( this[ expando ] != undefined ) + this[ expando ] = null; + }); + + // Copy the events from the original to the clone + if ( events === true ) + this.find("*").andSelf().each(function(i){ + if (this.nodeType == 3) + return; + var events = jQuery.data( this, "events" ); + + for ( var type in events ) + for ( var handler in events[ type ] ) + jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data ); + }); + + // Return the cloned set + return ret; + }, + + filter: function( selector ) { + return this.pushStack( + jQuery.isFunction( selector ) && + jQuery.grep(this, function(elem, i){ + return selector.call( elem, i ); + }) || + + jQuery.multiFilter( selector, this ) ); + }, + + not: function( selector ) { + if ( selector.constructor == String ) + // test special case where just one selector is passed in + if ( isSimple.test( selector ) ) + return this.pushStack( jQuery.multiFilter( selector, this, true ) ); + else + selector = jQuery.multiFilter( selector, this ); + + var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType; + return this.filter(function() { + return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector; + }); + }, + + add: function( selector ) { + return !selector ? this : this.pushStack( jQuery.merge( + this.get(), + selector.constructor == String ? + jQuery( selector ).get() : + selector.length != undefined && (!selector.nodeName || jQuery.nodeName(selector, "form")) ? + selector : [selector] ) ); + }, + + is: function( selector ) { + return selector ? + jQuery.multiFilter( selector, this ).length > 0 : + false; + }, + + hasClass: function( selector ) { + return this.is( "." + selector ); + }, + + val: function( value ) { + if ( value == undefined ) { + + if ( this.length ) { + var elem = this[0]; + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type == "select-one"; + + // Nothing was selected + if ( index < 0 ) + return null; + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + if ( option.selected ) { + // Get the specifc value for the option + value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value; + + // We don't need an array for one selects + if ( one ) + return value; + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + + // Everything else, we just grab the value + } else + return (this[0].value || "").replace(/\r/g, ""); + + } + + return undefined; + } + + return this.each(function(){ + if ( this.nodeType != 1 ) + return; + + if ( value.constructor == Array && /radio|checkbox/.test( this.type ) ) + this.checked = (jQuery.inArray(this.value, value) >= 0 || + jQuery.inArray(this.name, value) >= 0); + + else if ( jQuery.nodeName( this, "select" ) ) { + var values = value.constructor == Array ? + value : + [ value ]; + + jQuery( "option", this ).each(function(){ + this.selected = (jQuery.inArray( this.value, values ) >= 0 || + jQuery.inArray( this.text, values ) >= 0); + }); + + if ( !values.length ) + this.selectedIndex = -1; + + } else + this.value = value; + }); + }, + + html: function( value ) { + return value == undefined ? + (this.length ? + this[0].innerHTML : + null) : + this.empty().append( value ); + }, + + replaceWith: function( value ) { + return this.after( value ).remove(); + }, + + eq: function( i ) { + return this.slice( i, i + 1 ); + }, + + slice: function() { + return this.pushStack( Array.prototype.slice.apply( this, arguments ) ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function(elem, i){ + return callback.call( elem, i, elem ); + })); + }, + + andSelf: function() { + return this.add( this.prevObject ); + }, + + data: function( key, value ){ + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value == null ) { + var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + if ( data == undefined && this.length ) + data = jQuery.data( this[0], key ); + + return data == null && parts[1] ? + this.data( parts[0] ) : + data; + } else + return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){ + jQuery.data( this, key, value ); + }); + }, + + removeData: function( key ){ + return this.each(function(){ + jQuery.removeData( this, key ); + }); + }, + + domManip: function( args, table, reverse, callback ) { + var clone = this.length > 1, elems; + + return this.each(function(){ + if ( !elems ) { + elems = jQuery.clean( args, this.ownerDocument ); + + if ( reverse ) + elems.reverse(); + } + + var obj = this; + + if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) ) + obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") ); + + var scripts = jQuery( [] ); + + jQuery.each(elems, function(){ + var elem = clone ? + jQuery( this ).clone( true )[0] : + this; + + // execute all scripts after the elements have been injected + if ( jQuery.nodeName( elem, "script" ) ) { + scripts = scripts.add( elem ); + } else { + // Remove any inner scripts for later evaluation + if ( elem.nodeType == 1 ) + scripts = scripts.add( jQuery( "script", elem ).remove() ); + + // Inject the elements into the document + callback.call( obj, elem ); + } + }); + + scripts.each( evalScript ); + }); + } +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.prototype.init.prototype = jQuery.prototype; + +function evalScript( i, elem ) { + if ( elem.src ) + jQuery.ajax({ + url: elem.src, + async: false, + dataType: "script" + }); + + else + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + + if ( elem.parentNode ) + elem.parentNode.removeChild( elem ); +} + +jQuery.extend = jQuery.fn.extend = function() { + // copy reference to target object + var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; + + // Handle a deep copy situation + if ( target.constructor == Boolean ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target != "object" && typeof target != "function" ) + target = {}; + + // extend jQuery itself if only one argument is passed + if ( length == 1 ) { + target = this; + i = 0; + } + + for ( ; i < length; i++ ) + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) + // Extend the base object + for ( var name in options ) { + // Prevent never-ending loop + if ( target === options[ name ] ) + continue; + + // Recurse if we're merging object values + if ( deep && options[ name ] && typeof options[ name ] == "object" && target[ name ] && !options[ name ].nodeType ) + target[ name ] = jQuery.extend( target[ name ], options[ name ] ); + + // Don't bring in undefined values + else if ( options[ name ] != undefined ) + target[ name ] = options[ name ]; + + } + + // Return the modified object + return target; +}; + +var expando = "jQuery" + (new Date()).getTime(), uuid = 0, windowData = {}; + +// exclude the following css properties to add px +var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i; + +jQuery.extend({ + noConflict: function( deep ) { + window.$ = _$; + + if ( deep ) + window.jQuery = _jQuery; + + return jQuery; + }, + + // See test/unit/core.js for details concerning this function. + isFunction: function( fn ) { + return !!fn && typeof fn != "string" && !fn.nodeName && + fn.constructor != Array && /function/i.test( fn + "" ); + }, + + // check if an element is in a (or is an) XML document + isXMLDoc: function( elem ) { + return elem.documentElement && !elem.body || + elem.tagName && elem.ownerDocument && !elem.ownerDocument.body; + }, + + // Evalulates a script in a global context + globalEval: function( data ) { + data = jQuery.trim( data ); + + if ( data ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.getElementsByTagName("head")[0] || document.documentElement, + script = document.createElement("script"); + + script.type = "text/javascript"; + if ( jQuery.browser.msie ) + script.text = data; + else + script.appendChild( document.createTextNode( data ) ); + + head.appendChild( script ); + head.removeChild( script ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); + }, + + cache: {}, + + data: function( elem, name, data ) { + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ]; + + // Compute a unique ID for the element + if ( !id ) + id = elem[ expando ] = ++uuid; + + // Only generate the data cache if we're + // trying to access or manipulate it + if ( name && !jQuery.cache[ id ] ) + jQuery.cache[ id ] = {}; + + // Prevent overriding the named cache with undefined values + if ( data != undefined ) + jQuery.cache[ id ][ name ] = data; + + // Return the named cache data, or the ID for the element + return name ? + jQuery.cache[ id ][ name ] : + id; + }, + + removeData: function( elem, name ) { + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ]; + + // If we want to remove a specific section of the element's data + if ( name ) { + if ( jQuery.cache[ id ] ) { + // Remove the section of cache data + delete jQuery.cache[ id ][ name ]; + + // If we've removed all the data, remove the element's cache + name = ""; + + for ( name in jQuery.cache[ id ] ) + break; + + if ( !name ) + jQuery.removeData( elem ); + } + + // Otherwise, we want to remove all of the element's data + } else { + // Clean up the element expando + try { + delete elem[ expando ]; + } catch(e){ + // IE has trouble directly removing the expando + // but it's ok with using removeAttribute + if ( elem.removeAttribute ) + elem.removeAttribute( expando ); + } + + // Completely remove the data cache + delete jQuery.cache[ id ]; + } + }, + + // args is for internal usage only + each: function( object, callback, args ) { + if ( args ) { + if ( object.length == undefined ) { + for ( var name in object ) + if ( callback.apply( object[ name ], args ) === false ) + break; + } else + for ( var i = 0, length = object.length; i < length; i++ ) + if ( callback.apply( object[ i ], args ) === false ) + break; + + // A special, fast, case for the most common use of each + } else { + if ( object.length == undefined ) { + for ( var name in object ) + if ( callback.call( object[ name ], name, object[ name ] ) === false ) + break; + } else + for ( var i = 0, length = object.length, value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ){} + } + + return object; + }, + + prop: function( elem, value, type, i, name ) { + // Handle executable functions + if ( jQuery.isFunction( value ) ) + value = value.call( elem, i ); + + // Handle passing in a number to a CSS property + return value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ? + value + "px" : + value; + }, + + className: { + // internal only, use addClass("class") + add: function( elem, classNames ) { + jQuery.each((classNames || "").split(/\s+/), function(i, className){ + if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) ) + elem.className += (elem.className ? " " : "") + className; + }); + }, + + // internal only, use removeClass("class") + remove: function( elem, classNames ) { + if (elem.nodeType == 1) + elem.className = classNames != undefined ? + jQuery.grep(elem.className.split(/\s+/), function(className){ + return !jQuery.className.has( classNames, className ); + }).join(" ") : + ""; + }, + + // internal only, use is(".class") + has: function( elem, className ) { + return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1; + } + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback ) { + var old = {}; + // Remember the old values, and insert the new ones + for ( var name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + callback.call( elem ); + + // Revert the old values + for ( var name in options ) + elem.style[ name ] = old[ name ]; + }, + + css: function( elem, name, force ) { + if ( name == "width" || name == "height" ) { + var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ]; + + function getWH() { + val = name == "width" ? elem.offsetWidth : elem.offsetHeight; + var padding = 0, border = 0; + jQuery.each( which, function() { + padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0; + border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0; + }); + val -= Math.round(padding + border); + } + + if ( jQuery(elem).is(":visible") ) + getWH(); + else + jQuery.swap( elem, props, getWH ); + + return Math.max(0, val); + } + + return jQuery.curCSS( elem, name, force ); + }, + + curCSS: function( elem, name, force ) { + var ret; + + // A helper method for determining if an element's values are broken + function color( elem ) { + if ( !jQuery.browser.safari ) + return false; + + var ret = document.defaultView.getComputedStyle( elem, null ); + return !ret || ret.getPropertyValue("color") == ""; + } + + // We need to handle opacity special in IE + if ( name == "opacity" && jQuery.browser.msie ) { + ret = jQuery.attr( elem.style, "opacity" ); + + return ret == "" ? + "1" : + ret; + } + // Opera sometimes will give the wrong display answer, this fixes it, see #2037 + if ( jQuery.browser.opera && name == "display" ) { + var save = elem.style.outline; + elem.style.outline = "0 solid black"; + elem.style.outline = save; + } + + // Make sure we're using the right name for getting the float value + if ( name.match( /float/i ) ) + name = styleFloat; + + if ( !force && elem.style && elem.style[ name ] ) + ret = elem.style[ name ]; + + else if ( document.defaultView && document.defaultView.getComputedStyle ) { + + // Only "float" is needed here + if ( name.match( /float/i ) ) + name = "float"; + + name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase(); + + var getComputedStyle = document.defaultView.getComputedStyle( elem, null ); + + if ( getComputedStyle && !color( elem ) ) + ret = getComputedStyle.getPropertyValue( name ); + + // If the element isn't reporting its values properly in Safari + // then some display: none elements are involved + else { + var swap = [], stack = []; + + // Locate all of the parent display: none elements + for ( var a = elem; a && color(a); a = a.parentNode ) + stack.unshift(a); + + // Go through and make them visible, but in reverse + // (It would be better if we knew the exact display type that they had) + for ( var i = 0; i < stack.length; i++ ) + if ( color( stack[ i ] ) ) { + swap[ i ] = stack[ i ].style.display; + stack[ i ].style.display = "block"; + } + + // Since we flip the display style, we have to handle that + // one special, otherwise get the value + ret = name == "display" && swap[ stack.length - 1 ] != null ? + "none" : + ( getComputedStyle && getComputedStyle.getPropertyValue( name ) ) || ""; + + // Finally, revert the display styles back + for ( var i = 0; i < swap.length; i++ ) + if ( swap[ i ] != null ) + stack[ i ].style.display = swap[ i ]; + } + + // We should always get a number back from opacity + if ( name == "opacity" && ret == "" ) + ret = "1"; + + } else if ( elem.currentStyle ) { + var camelCase = name.replace(/\-(\w)/g, function(all, letter){ + return letter.toUpperCase(); + }); + + ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ]; + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { + // Remember the original values + var style = elem.style.left, runtimeStyle = elem.runtimeStyle.left; + + // Put in the new values to get a computed value out + elem.runtimeStyle.left = elem.currentStyle.left; + elem.style.left = ret || 0; + ret = elem.style.pixelLeft + "px"; + + // Revert the changed values + elem.style.left = style; + elem.runtimeStyle.left = runtimeStyle; + } + } + + return ret; + }, + + clean: function( elems, context ) { + var ret = []; + context = context || document; + // !context.createElement fails in IE with an error but returns typeof 'object' + if (typeof context.createElement == 'undefined') + context = context.ownerDocument || context[0] && context[0].ownerDocument || document; + + jQuery.each(elems, function(i, elem){ + if ( !elem ) + return; + + if ( elem.constructor == Number ) + elem = elem.toString(); + + // Convert html string into DOM nodes + if ( typeof elem == "string" ) { + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ + return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? + all : + front + ">"; + }); + + // Trim whitespace, otherwise indexOf won't work as expected + var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div"); + + var wrap = + // option or optgroup + !tags.indexOf("", "" ] || + + !tags.indexOf("", "" ] || + + tags.match(/^<(thead|tbody|tfoot|colg|cap)/) && + [ 1, "", "
    " ] || + + !tags.indexOf("", "" ] || + + // matched above + (!tags.indexOf("", "" ] || + + !tags.indexOf("", "" ] || + + // IE can't serialize and \ No newline at end of file diff --git a/natxet/CssMin/README b/natxet/CssMin/README new file mode 100644 index 000000000000..b93fa4d613f9 --- /dev/null +++ b/natxet/CssMin/README @@ -0,0 +1,3 @@ +This is just a copy of the CssMin by Joe Scylla to format it for Composer. +Composer: http://packagist.org/about-composer +CssMin: http://code.google.com/p/cssmin/ diff --git a/natxet/CssMin/composer.json b/natxet/CssMin/composer.json new file mode 100644 index 000000000000..85bc40505e30 --- /dev/null +++ b/natxet/CssMin/composer.json @@ -0,0 +1,20 @@ +{ + "name": "natxet/cssmin", + "description": "Minifying CSS", + "keywords": ["css","minify"], + "homepage": "http://code.google.com/p/cssmin/", + "license": "MIT", + "authors": [ + { + "name": "Joe Scylla", + "email": "joe.scylla@gmail.com", + "homepage": "https://profiles.google.com/joe.scylla" + } + ], + "require": { + "php": ">=5.0" + }, + "autoload": { + "classmap": ["src/"] + } +} \ No newline at end of file diff --git a/natxet/CssMin/src/CssMin.php b/natxet/CssMin/src/CssMin.php new file mode 100644 index 000000000000..b33cc4da34bb --- /dev/null +++ b/natxet/CssMin/src/CssMin.php @@ -0,0 +1,5110 @@ + + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * -- + * + * @package CssMin + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +/** + * Abstract definition of a CSS token class. + * + * Every token has to extend this class. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssToken +{ + /** + * Returns the token as string. + * + * @return string + */ + abstract public function __toString(); +} + +/** + * Abstract definition of a for a ruleset start token. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssRulesetStartToken extends aCssToken +{ + +} + +/** + * Abstract definition of a for ruleset end token. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssRulesetEndToken extends aCssToken +{ + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "}"; + } +} + +/** + * Abstract definition of a parser plugin. + * + * Every parser plugin have to extend this class. A parser plugin contains the logic to parse one or aspects of a + * stylesheet. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssParserPlugin +{ + /** + * Plugin configuration. + * + * @var array + */ + protected $configuration = array(); + /** + * The CssParser of the plugin. + * + * @var CssParser + */ + protected $parser = null; + /** + * Plugin buffer. + * + * @var string + */ + protected $buffer = ""; + /** + * Constructor. + * + * @param CssParser $parser The CssParser object of this plugin. + * @param array $configuration Plugin configuration [optional] + * @return void + */ + public function __construct(CssParser $parser, array $configuration = null) + { + $this->configuration = $configuration; + $this->parser = $parser; + } + /** + * Returns the array of chars triggering the parser plugin. + * + * @return array + */ + abstract public function getTriggerChars(); + /** + * Returns the array of states triggering the parser plugin or FALSE if every state will trigger the parser plugin. + * + * @return array + */ + abstract public function getTriggerStates(); + /** + * Parser routine of the plugin. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + abstract public function parse($index, $char, $previousChar, $state); +} + +/** + * Abstract definition of a minifier plugin class. + * + * Minifier plugin process the parsed tokens one by one to apply changes to the token. Every minifier plugin has to + * extend this class. + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssMinifierPlugin +{ + /** + * Plugin configuration. + * + * @var array + */ + protected $configuration = array(); + /** + * The CssMinifier of the plugin. + * + * @var CssMinifier + */ + protected $minifier = null; + /** + * Constructor. + * + * @param CssMinifier $minifier The CssMinifier object of this plugin. + * @param array $configuration Plugin configuration [optional] + * @return void + */ + public function __construct(CssMinifier $minifier, array $configuration = array()) + { + $this->configuration = $configuration; + $this->minifier = $minifier; + } + /** + * Apply the plugin to the token. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + abstract public function apply(aCssToken &$token); + /** + * -- + * + * @return array + */ + abstract public function getTriggerTokens(); +} + +/** + * Abstract definition of a minifier filter class. + * + * Minifier filters allows a pre-processing of the parsed token to add, edit or delete tokens. Every minifier filter + * has to extend this class. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssMinifierFilter +{ + /** + * Filter configuration. + * + * @var array + */ + protected $configuration = array(); + /** + * The CssMinifier of the filter. + * + * @var CssMinifier + */ + protected $minifier = null; + /** + * Constructor. + * + * @param CssMinifier $minifier The CssMinifier object of this plugin. + * @param array $configuration Filter configuration [optional] + * @return void + */ + public function __construct(CssMinifier $minifier, array $configuration = array()) + { + $this->configuration = $configuration; + $this->minifier = $minifier; + } + /** + * Filter the tokens. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + abstract public function apply(array &$tokens); +} + +/** + * Abstract formatter definition. + * + * Every formatter have to extend this class. + * + * @package CssMin/Formatter + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssFormatter +{ + /** + * Indent string. + * + * @var string + */ + protected $indent = " "; + /** + * Declaration padding. + * + * @var integer + */ + protected $padding = 0; + /** + * Tokens. + * + * @var array + */ + protected $tokens = array(); + /** + * Constructor. + * + * @param array $tokens Array of CssToken + * @param string $indent Indent string [optional] + * @param integer $padding Declaration value padding [optional] + */ + public function __construct(array $tokens, $indent = null, $padding = null) + { + $this->tokens = $tokens; + $this->indent = !is_null($indent) ? $indent : $this->indent; + $this->padding = !is_null($padding) ? $padding : $this->padding; + } + /** + * Returns the array of aCssToken as formatted string. + * + * @return string + */ + abstract public function __toString(); +} + +/** + * Abstract definition of a ruleset declaration token. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssDeclarationToken extends aCssToken +{ + /** + * Is the declaration flagged as important? + * + * @var boolean + */ + public $IsImportant = false; + /** + * Is the declaration flagged as last one of the ruleset? + * + * @var boolean + */ + public $IsLast = false; + /** + * Property name of the declaration. + * + * @var string + */ + public $Property = ""; + /** + * Value of the declaration. + * + * @var string + */ + public $Value = ""; + /** + * Set the properties of the @font-face declaration. + * + * @param string $property Property of the declaration + * @param string $value Value of the declaration + * @param boolean $isImportant Is the !important flag is set? + * @param boolean $IsLast Is the declaration the last one of the block? + * @return void + */ + public function __construct($property, $value, $isImportant = false, $isLast = false) + { + $this->Property = $property; + $this->Value = $value; + $this->IsImportant = $isImportant; + $this->IsLast = $isLast; + } + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return $this->Property . ":" . $this->Value . ($this->IsImportant ? " !important" : "") . ($this->IsLast ? "" : ";"); + } +} + +/** + * Abstract definition of a for at-rule block start token. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssAtBlockStartToken extends aCssToken +{ + +} + +/** + * Abstract definition of a for at-rule block end token. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class aCssAtBlockEndToken extends aCssToken +{ + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "}"; + } +} + +/** + * {@link aCssFromatter Formatter} returning the CSS source in {@link http://goo.gl/etzLs Whitesmiths indent style}. + * + * @package CssMin/Formatter + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssWhitesmithsFormatter extends aCssFormatter +{ + /** + * Implements {@link aCssFormatter::__toString()}. + * + * @return string + */ + public function __toString() + { + $r = array(); + $level = 0; + for ($i = 0, $l = count($this->tokens); $i < $l; $i++) + { + $token = $this->tokens[$i]; + $class = get_class($token); + $indent = str_repeat($this->indent, $level); + if ($class === "CssCommentToken") + { + $lines = array_map("trim", explode("\n", $token->Comment)); + for ($ii = 0, $ll = count($lines); $ii < $ll; $ii++) + { + $r[] = $indent . (substr($lines[$ii], 0, 1) == "*" ? " " : "") . $lines[$ii]; + } + } + elseif ($class === "CssAtCharsetToken") + { + $r[] = $indent . "@charset " . $token->Charset . ";"; + } + elseif ($class === "CssAtFontFaceStartToken") + { + $r[] = $indent . "@font-face"; + $r[] = $this->indent . $indent . "{"; + $level++; + } + elseif ($class === "CssAtImportToken") + { + $r[] = $indent . "@import " . $token->Import . " " . implode(", ", $token->MediaTypes) . ";"; + } + elseif ($class === "CssAtKeyframesStartToken") + { + $r[] = $indent . "@keyframes \"" . $token->Name . "\""; + $r[] = $this->indent . $indent . "{"; + $level++; + } + elseif ($class === "CssAtMediaStartToken") + { + $r[] = $indent . "@media " . implode(", ", $token->MediaTypes); + $r[] = $this->indent . $indent . "{"; + $level++; + } + elseif ($class === "CssAtPageStartToken") + { + $r[] = $indent . "@page"; + $r[] = $this->indent . $indent . "{"; + $level++; + } + elseif ($class === "CssAtVariablesStartToken") + { + $r[] = $indent . "@variables " . implode(", ", $token->MediaTypes); + $r[] = $this->indent . $indent . "{"; + $level++; + } + elseif ($class === "CssRulesetStartToken" || $class === "CssAtKeyframesRulesetStartToken") + { + $r[] = $indent . implode(", ", $token->Selectors); + $r[] = $this->indent . $indent . "{"; + $level++; + } + elseif ($class == "CssAtFontFaceDeclarationToken" + || $class === "CssAtKeyframesRulesetDeclarationToken" + || $class === "CssAtPageDeclarationToken" + || $class == "CssAtVariablesDeclarationToken" + || $class === "CssRulesetDeclarationToken" + ) + { + $declaration = $indent . $token->Property . ": "; + if ($this->padding) + { + $declaration = str_pad($declaration, $this->padding, " ", STR_PAD_RIGHT); + } + $r[] = $declaration . $token->Value . ($token->IsImportant ? " !important" : "") . ";"; + } + elseif ($class === "CssAtFontFaceEndToken" + || $class === "CssAtMediaEndToken" + || $class === "CssAtKeyframesEndToken" + || $class === "CssAtKeyframesRulesetEndToken" + || $class === "CssAtPageEndToken" + || $class === "CssAtVariablesEndToken" + || $class === "CssRulesetEndToken" + ) + { + $r[] = $indent . "}"; + $level--; + } + } + return implode("\n", $r); + } +} + +/** + * This {@link aCssMinifierPlugin} will process var-statement and sets the declaration value to the variable value. + * + * This plugin only apply the variable values. The variable values itself will get parsed by the + * {@link CssVariablesMinifierFilter}. + * + * Example: + * + * @variables + * { + * defaultColor: black; + * } + * color: var(defaultColor); + * + * + * Will get converted to: + * + * color:black; + * + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssVariablesMinifierPlugin extends aCssMinifierPlugin +{ + /** + * Regular expression matching a value. + * + * @var string + */ + private $reMatch = "/var\((.+)\)/iSU"; + /** + * Parsed variables. + * + * @var array + */ + private $variables = null; + /** + * Returns the variables. + * + * @return array + */ + public function getVariables() + { + return $this->variables; + } + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + if (stripos($token->Value, "var") !== false && preg_match_all($this->reMatch, $token->Value, $m)) + { + $mediaTypes = $token->MediaTypes; + if (!in_array("all", $mediaTypes)) + { + $mediaTypes[] = "all"; + } + for ($i = 0, $l = count($m[0]); $i < $l; $i++) + { + $variable = trim($m[1][$i]); + foreach ($mediaTypes as $mediaType) + { + if (isset($this->variables[$mediaType], $this->variables[$mediaType][$variable])) + { + // Variable value found => set the declaration value to the variable value and return + $token->Value = str_replace($m[0][$i], $this->variables[$mediaType][$variable], $token->Value); + continue 2; + } + } + // If no value was found trigger an error and replace the token with a CssNullToken + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": No value found for variable " . $variable . " in media types " . implode(", ", $mediaTypes) . "", (string) $token)); + $token = new CssNullToken(); + return true; + } + } + return false; + } + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } + /** + * Sets the variables. + * + * @param array $variables Variables to set + * @return void + */ + public function setVariables(array $variables) + { + $this->variables = $variables; + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} will parse the variable declarations out of @variables at-rule + * blocks. The variables will get store in the {@link CssVariablesMinifierPlugin} that will apply the variables to + * declaration. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssVariablesMinifierFilter extends aCssMinifierFilter +{ + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $variables = array(); + $defaultMediaTypes = array("all"); + $mediaTypes = array(); + $remove = array(); + for($i = 0, $l = count($tokens); $i < $l; $i++) + { + // @variables at-rule block found + if (get_class($tokens[$i]) === "CssAtVariablesStartToken") + { + $remove[] = $i; + $mediaTypes = (count($tokens[$i]->MediaTypes) == 0 ? $defaultMediaTypes : $tokens[$i]->MediaTypes); + foreach ($mediaTypes as $mediaType) + { + if (!isset($variables[$mediaType])) + { + $variables[$mediaType] = array(); + } + } + // Read the variable declaration tokens + for($i = $i; $i < $l; $i++) + { + // Found a variable declaration => read the variable values + if (get_class($tokens[$i]) === "CssAtVariablesDeclarationToken") + { + foreach ($mediaTypes as $mediaType) + { + $variables[$mediaType][$tokens[$i]->Property] = $tokens[$i]->Value; + } + $remove[] = $i; + } + // Found the variables end token => break; + elseif (get_class($tokens[$i]) === "CssAtVariablesEndToken") + { + $remove[] = $i; + break; + } + } + } + } + // Variables in @variables at-rule blocks + foreach($variables as $mediaType => $null) + { + foreach($variables[$mediaType] as $variable => $value) + { + // If a var() statement in a variable value found... + if (stripos($value, "var") !== false && preg_match_all("/var\((.+)\)/iSU", $value, $m)) + { + // ... then replace the var() statement with the variable values. + for ($i = 0, $l = count($m[0]); $i < $l; $i++) + { + $variables[$mediaType][$variable] = str_replace($m[0][$i], (isset($variables[$mediaType][$m[1][$i]]) ? $variables[$mediaType][$m[1][$i]] : ""), $variables[$mediaType][$variable]); + } + } + } + } + // Remove the complete @variables at-rule block + foreach ($remove as $i) + { + $tokens[$i] = null; + } + if (!($plugin = $this->minifier->getPlugin("CssVariablesMinifierPlugin"))) + { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The plugin CssVariablesMinifierPlugin was not found but is required for " . __CLASS__ . "")); + } + else + { + $plugin->setVariables($variables); + } + return count($remove); + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for preserve parsing url() values. + * + * This plugin return no {@link aCssToken CssToken} but ensures that url() values will get parsed properly. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssUrlParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("(", ")"); + } + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return false; + } + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of string + if ($char === "(" && strtolower(substr($this->parser->getSource(), $index - 3, 4)) === "url(" && $state !== "T_URL") + { + $this->parser->pushState("T_URL"); + $this->parser->setExclusive(__CLASS__); + } + // Escaped LF in url => remove escape backslash and LF + elseif ($char === "\n" && $previousChar === "\\" && $state === "T_URL") + { + $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2)); + } + // Parse error: Unescaped LF in string literal + elseif ($char === "\n" && $previousChar !== "\\" && $state === "T_URL") + { + $line = $this->parser->getBuffer(); + $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1) . ")"); // Replace the LF with the url string delimiter + $this->parser->popState(); + $this->parser->unsetExclusive(); + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated string literal", $line . "_")); + } + // End of string + elseif ($char === ")" && $state === "T_URL") + { + $this->parser->popState(); + $this->parser->unsetExclusive(); + } + else + { + return false; + } + return true; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for preserve parsing string values. + * + * This plugin return no {@link aCssToken CssToken} but ensures that string values will get parsed properly. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssStringParserPlugin extends aCssParserPlugin +{ + /** + * Current string delimiter char. + * + * @var string + */ + private $delimiterChar = null; + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("\"", "'", "\n"); + } + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return false; + } + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of string + if (($char === "\"" || $char === "'") && $state !== "T_STRING") + { + $this->delimiterChar = $char; + $this->parser->pushState("T_STRING"); + $this->parser->setExclusive(__CLASS__); + } + // Escaped LF in string => remove escape backslash and LF + elseif ($char === "\n" && $previousChar === "\\" && $state === "T_STRING") + { + $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2)); + } + // Parse error: Unescaped LF in string literal + elseif ($char === "\n" && $previousChar !== "\\" && $state === "T_STRING") + { + $line = $this->parser->getBuffer(); + $this->parser->popState(); + $this->parser->unsetExclusive(); + $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1) . $this->delimiterChar); // Replace the LF with the current string char + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated string literal", $line . "_")); + $this->delimiterChar = null; + } + // End of string + elseif ($char === $this->delimiterChar && $state === "T_STRING") + { + // If the Previous char is a escape char count the amount of the previous escape chars. If the amount of + // escape chars is uneven do not end the string + if ($previousChar == "\\") + { + $source = $this->parser->getSource(); + $c = 1; + $i = $index - 2; + while (substr($source, $i, 1) === "\\") + { + $c++; $i--; + } + if ($c % 2) + { + return false; + } + } + $this->parser->popState(); + $this->parser->unsetExclusive(); + $this->delimiterChar = null; + } + else + { + return false; + } + return true; + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} sorts the ruleset declarations of a ruleset by name. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Rowan Beentje + * @copyright Rowan Beentje + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssSortRulesetPropertiesMinifierFilter extends aCssMinifierFilter +{ + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value larger than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + for ($i = 0, $l = count($tokens); $i < $l; $i++) + { + // Only look for ruleset start rules + if (get_class($tokens[$i]) !== "CssRulesetStartToken") { continue; } + // Look for the corresponding ruleset end + $endIndex = false; + for ($ii = $i + 1; $ii < $l; $ii++) + { + if (get_class($tokens[$ii]) !== "CssRulesetEndToken") { continue; } + $endIndex = $ii; + break; + } + if (!$endIndex) { break; } + $startIndex = $i; + $i = $endIndex; + // Skip if there's only one token in this ruleset + if ($endIndex - $startIndex <= 2) { continue; } + // Ensure that everything between the start and end is a declaration token, for safety + for ($ii = $startIndex + 1; $ii < $endIndex; $ii++) + { + if (get_class($tokens[$ii]) !== "CssRulesetDeclarationToken") { continue(2); } + } + $declarations = array_slice($tokens, $startIndex + 1, $endIndex - $startIndex - 1); + // Check whether a sort is required + $sortRequired = $lastPropertyName = false; + foreach ($declarations as $declaration) + { + if ($lastPropertyName) + { + if (strcmp($lastPropertyName, $declaration->Property) > 0) + { + $sortRequired = true; + break; + } + } + $lastPropertyName = $declaration->Property; + } + if (!$sortRequired) { continue; } + // Arrange the declarations alphabetically by name + usort($declarations, array(__CLASS__, "userDefinedSort1")); + // Update "IsLast" property + for ($ii = 0, $ll = count($declarations) - 1; $ii <= $ll; $ii++) + { + if ($ii == $ll) + { + $declarations[$ii]->IsLast = true; + } + else + { + $declarations[$ii]->IsLast = false; + } + } + // Splice back into the array. + array_splice($tokens, $startIndex + 1, $endIndex - $startIndex - 1, $declarations); + $r += $endIndex - $startIndex - 1; + } + return $r; + } + /** + * User defined sort function. + * + * @return integer + */ + public static function userDefinedSort1($a, $b) + { + return strcmp($a->Property, $b->Property); + } +} + +/** + * This {@link aCssToken CSS token} represents the start of a ruleset. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRulesetStartToken extends aCssRulesetStartToken +{ + /** + * Array of selectors. + * + * @var array + */ + public $Selectors = array(); + /** + * Set the properties of a ruleset token. + * + * @param array $selectors Selectors of the ruleset + * @return void + */ + public function __construct(array $selectors = array()) + { + $this->Selectors = $selectors; + } + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return implode(",", $this->Selectors) . "{"; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing ruleset block with including declarations. + * + * Found rulesets will add a {@link CssRulesetStartToken} and {@link CssRulesetEndToken} to the + * parser; including declarations as {@link CssRulesetDeclarationToken}. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRulesetParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array(",", "{", "}", ":", ";"); + } + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_MEDIA", "T_RULESET::SELECTORS", "T_RULESET", "T_RULESET_DECLARATION"); + } + /** + * Selectors. + * + * @var array + */ + private $selectors = array(); + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of Ruleset and selectors + if ($char === "," && ($state === "T_DOCUMENT" || $state === "T_AT_MEDIA" || $state === "T_RULESET::SELECTORS")) + { + if ($state !== "T_RULESET::SELECTORS") + { + $this->parser->pushState("T_RULESET::SELECTORS"); + } + $this->selectors[] = $this->parser->getAndClearBuffer(",{"); + } + // End of selectors and start of declarations + elseif ($char === "{" && ($state === "T_DOCUMENT" || $state === "T_AT_MEDIA" || $state === "T_RULESET::SELECTORS")) + { + if ($this->parser->getBuffer() !== "") + { + $this->selectors[] = $this->parser->getAndClearBuffer(",{"); + if ($state == "T_RULESET::SELECTORS") + { + $this->parser->popState(); + } + $this->parser->pushState("T_RULESET"); + $this->parser->appendToken(new CssRulesetStartToken($this->selectors)); + $this->selectors = array(); + } + } + // Start of declaration + elseif ($char === ":" && $state === "T_RULESET") + { + $this->parser->pushState("T_RULESET_DECLARATION"); + $this->buffer = $this->parser->getAndClearBuffer(":;", true); + } + // Unterminated ruleset declaration + elseif ($char === ":" && $state === "T_RULESET_DECLARATION") + { + // Ignore Internet Explorer filter declarations + if ($this->buffer === "filter") + { + return false; + } + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_")); + } + // End of declaration + elseif (($char === ";" || $char === "}") && $state === "T_RULESET_DECLARATION") + { + $value = $this->parser->getAndClearBuffer(";}"); + if (strtolower(substr($value, -10, 10)) === "!important") + { + $value = trim(substr($value, 0, -10)); + $isImportant = true; + } + else + { + $isImportant = false; + } + $this->parser->popState(); + $this->parser->appendToken(new CssRulesetDeclarationToken($this->buffer, $value, $this->parser->getMediaTypes(), $isImportant)); + // Declaration ends with a right curly brace; so we have to end the ruleset + if ($char === "}") + { + $this->parser->appendToken(new CssRulesetEndToken()); + $this->parser->popState(); + } + $this->buffer = ""; + } + // End of ruleset + elseif ($char === "}" && $state === "T_RULESET") + { + $this->parser->popState(); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssRulesetEndToken()); + $this->buffer = ""; + $this->selectors = array(); + } + else + { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the end of a ruleset. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRulesetEndToken extends aCssRulesetEndToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents a ruleset declaration. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRulesetDeclarationToken extends aCssDeclarationToken +{ + /** + * Media types of the declaration. + * + * @var array + */ + public $MediaTypes = array("all"); + /** + * Set the properties of a ddocument- or at-rule @media level declaration. + * + * @param string $property Property of the declaration + * @param string $value Value of the declaration + * @param mixed $mediaTypes Media types of the declaration + * @param boolean $isImportant Is the !important flag is set + * @param boolean $isLast Is the declaration the last one of the ruleset + * @return void + */ + public function __construct($property, $value, $mediaTypes = null, $isImportant = false, $isLast = false) + { + parent::__construct($property, $value, $isImportant, $isLast); + $this->MediaTypes = $mediaTypes ? $mediaTypes : array("all"); + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} sets the IsLast property of any last declaration in a ruleset, + * @font-face at-rule or @page at-rule block. If the property IsLast is TRUE the decrations will get stringified + * without tailing semicolon. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRemoveLastDelarationSemiColonMinifierFilter extends aCssMinifierFilter +{ + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + for ($i = 0, $l = count($tokens); $i < $l; $i++) + { + $current = get_class($tokens[$i]); + $next = isset($tokens[$i+1]) ? get_class($tokens[$i+1]) : false; + if (($current === "CssRulesetDeclarationToken" && $next === "CssRulesetEndToken") || + ($current === "CssAtFontFaceDeclarationToken" && $next === "CssAtFontFaceEndToken") || + ($current === "CssAtPageDeclarationToken" && $next === "CssAtPageEndToken")) + { + $tokens[$i]->IsLast = true; + } + } + return 0; + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} will remove any empty rulesets (including @keyframes at-rule block + * rulesets). + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRemoveEmptyRulesetsMinifierFilter extends aCssMinifierFilter +{ + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + for ($i = 0, $l = count($tokens); $i < $l; $i++) + { + $current = get_class($tokens[$i]); + $next = isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false; + if (($current === "CssRulesetStartToken" && $next === "CssRulesetEndToken") || + ($current === "CssAtKeyframesRulesetStartToken" && $next === "CssAtKeyframesRulesetEndToken" && !array_intersect(array("from", "0%", "to", "100%"), array_map("strtolower", $tokens[$i]->Selectors))) + ) + { + $tokens[$i] = null; + $tokens[$i + 1] = null; + $i++; + $r = $r + 2; + } + } + return $r; + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} will remove any empty @font-face, @keyframes, @media and @page + * at-rule blocks. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRemoveEmptyAtBlocksMinifierFilter extends aCssMinifierFilter +{ + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + for ($i = 0, $l = count($tokens); $i < $l; $i++) + { + $current = get_class($tokens[$i]); + $next = isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false; + if (($current === "CssAtFontFaceStartToken" && $next === "CssAtFontFaceEndToken") || + ($current === "CssAtKeyframesStartToken" && $next === "CssAtKeyframesEndToken") || + ($current === "CssAtPageStartToken" && $next === "CssAtPageEndToken") || + ($current === "CssAtMediaStartToken" && $next === "CssAtMediaEndToken")) + { + $tokens[$i] = null; + $tokens[$i + 1] = null; + $i++; + $r = $r + 2; + } + } + return $r; + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} will remove any comments from the array of parsed tokens. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRemoveCommentsMinifierFilter extends aCssMinifierFilter +{ + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + for ($i = 0, $l = count($tokens); $i < $l; $i++) + { + if (get_class($tokens[$i]) === "CssCommentToken") + { + $tokens[$i] = null; + $r++; + } + } + return $r; + } +} + +/** + * CSS Parser. + * + * @package CssMin/Parser + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssParser +{ + /** + * Parse buffer. + * + * @var string + */ + private $buffer = ""; + /** + * {@link aCssParserPlugin Plugins}. + * + * @var array + */ + private $plugins = array(); + /** + * Source to parse. + * + * @var string + */ + private $source = ""; + /** + * Current state. + * + * @var integer + */ + private $state = "T_DOCUMENT"; + /** + * Exclusive state. + * + * @var string + */ + private $stateExclusive = false; + /** + * Media types state. + * + * @var mixed + */ + private $stateMediaTypes = false; + /** + * State stack. + * + * @var array + */ + private $states = array("T_DOCUMENT"); + /** + * Parsed tokens. + * + * @var array + */ + private $tokens = array(); + /** + * Constructer. + * + * Create instances of the used {@link aCssParserPlugin plugins}. + * + * @param string $source CSS source [optional] + * @param array $plugins Plugin configuration [optional] + * @return void + */ + public function __construct($source = null, array $plugins = null) + { + $plugins = array_merge(array + ( + "Comment" => true, + "String" => true, + "Url" => true, + "Expression" => true, + "Ruleset" => true, + "AtCharset" => true, + "AtFontFace" => true, + "AtImport" => true, + "AtKeyframes" => true, + "AtMedia" => true, + "AtPage" => true, + "AtVariables" => true + ), is_array($plugins) ? $plugins : array()); + // Create plugin instances + foreach ($plugins as $name => $config) + { + if ($config !== false) + { + $class = "Css" . $name . "ParserPlugin"; + $config = is_array($config) ? $config : array(); + if (class_exists($class)) + { + $this->plugins[] = new $class($this, $config); + } + else + { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The plugin " . $name . " with the class name " . $class . " was not found")); + } + } + } + if (!is_null($source)) + { + $this->parse($source); + } + } + /** + * Append a token to the array of tokens. + * + * @param aCssToken $token Token to append + * @return void + */ + public function appendToken(aCssToken $token) + { + $this->tokens[] = $token; + } + /** + * Clears the current buffer. + * + * @return void + */ + public function clearBuffer() + { + $this->buffer = ""; + } + /** + * Returns and clear the current buffer. + * + * @param string $trim Chars to use to trim the returned buffer + * @param boolean $tolower if TRUE the returned buffer will get converted to lower case + * @return string + */ + public function getAndClearBuffer($trim = "", $tolower = false) + { + $r = $this->getBuffer($trim, $tolower); + $this->buffer = ""; + return $r; + } + /** + * Returns the current buffer. + * + * @param string $trim Chars to use to trim the returned buffer + * @param boolean $tolower if TRUE the returned buffer will get converted to lower case + * @return string + */ + public function getBuffer($trim = "", $tolower = false) + { + $r = $this->buffer; + if ($trim) + { + $r = trim($r, " \t\n\r\0\x0B" . $trim); + } + if ($tolower) + { + $r = strtolower($r); + } + return $r; + } + /** + * Returns the current media types state. + * + * @return array + */ + public function getMediaTypes() + { + return $this->stateMediaTypes; + } + /** + * Returns the CSS source. + * + * @return string + */ + public function getSource() + { + return $this->source; + } + /** + * Returns the current state. + * + * @return integer The current state + */ + public function getState() + { + return $this->state; + } + /** + * Returns a plugin by class name. + * + * @param string $name Class name of the plugin + * @return aCssParserPlugin + */ + public function getPlugin($class) + { + static $index = null; + if (is_null($index)) + { + $index = array(); + for ($i = 0, $l = count($this->plugins); $i < $l; $i++) + { + $index[get_class($this->plugins[$i])] = $i; + } + } + return isset($index[$class]) ? $this->plugins[$index[$class]] : false; + } + /** + * Returns the parsed tokens. + * + * @return array + */ + public function getTokens() + { + return $this->tokens; + } + /** + * Returns if the current state equals the passed state. + * + * @param integer $state State to compare with the current state + * @return boolean TRUE is the state equals to the passed state; FALSE if not + */ + public function isState($state) + { + return ($this->state == $state); + } + /** + * Parse the CSS source and return a array with parsed tokens. + * + * @param string $source CSS source + * @return array Array with tokens + */ + public function parse($source) + { + // Reset + $this->source = ""; + $this->tokens = array(); + // Create a global and plugin lookup table for trigger chars; set array of plugins as local variable and create + // several helper variables for plugin handling + $globalTriggerChars = ""; + $plugins = $this->plugins; + $pluginCount = count($plugins); + $pluginIndex = array(); + $pluginTriggerStates = array(); + $pluginTriggerChars = array(); + for ($i = 0, $l = count($plugins); $i < $l; $i++) + { + $tPluginClassName = get_class($plugins[$i]); + $pluginTriggerChars[$i] = implode("", $plugins[$i]->getTriggerChars()); + $tPluginTriggerStates = $plugins[$i]->getTriggerStates(); + $pluginTriggerStates[$i] = $tPluginTriggerStates === false ? false : "|" . implode("|", $tPluginTriggerStates) . "|"; + $pluginIndex[$tPluginClassName] = $i; + for ($ii = 0, $ll = strlen($pluginTriggerChars[$i]); $ii < $ll; $ii++) + { + $c = substr($pluginTriggerChars[$i], $ii, 1); + if (strpos($globalTriggerChars, $c) === false) + { + $globalTriggerChars .= $c; + } + } + } + // Normalise line endings + $source = str_replace("\r\n", "\n", $source); // Windows to Unix line endings + $source = str_replace("\r", "\n", $source); // Mac to Unix line endings + $this->source = $source; + // Variables + $buffer = &$this->buffer; + $exclusive = &$this->stateExclusive; + $state = &$this->state; + $c = $p = null; + // -- + for ($i = 0, $l = strlen($source); $i < $l; $i++) + { + // Set the current Char + $c = $source[$i]; // Is faster than: $c = substr($source, $i, 1); + // Normalize and filter double whitespace characters + if ($exclusive === false) + { + if ($c === "\n" || $c === "\t") + { + $c = " "; + } + if ($c === " " && $p === " ") + { + continue; + } + } + $buffer .= $c; + // Extended processing only if the current char is a global trigger char + if (strpos($globalTriggerChars, $c) !== false) + { + // Exclusive state is set; process with the exclusive plugin + if ($exclusive) + { + $tPluginIndex = $pluginIndex[$exclusive]; + if (strpos($pluginTriggerChars[$tPluginIndex], $c) !== false && ($pluginTriggerStates[$tPluginIndex] === false || strpos($pluginTriggerStates[$tPluginIndex], $state) !== false)) + { + $r = $plugins[$tPluginIndex]->parse($i, $c, $p, $state); + // Return value is TRUE => continue with next char + if ($r === true) + { + continue; + } + // Return value is numeric => set new index and continue with next char + elseif ($r !== false && $r != $i) + { + $i = $r; + continue; + } + } + } + // Else iterate through the plugins + else + { + $triggerState = "|" . $state . "|"; + for ($ii = 0, $ll = $pluginCount; $ii < $ll; $ii++) + { + // Only process if the current char is one of the plugin trigger chars + if (strpos($pluginTriggerChars[$ii], $c) !== false && ($pluginTriggerStates[$ii] === false || strpos($pluginTriggerStates[$ii], $triggerState) !== false)) + { + // Process with the plugin + $r = $plugins[$ii]->parse($i, $c, $p, $state); + // Return value is TRUE => break the plugin loop and and continue with next char + if ($r === true) + { + break; + } + // Return value is numeric => set new index, break the plugin loop and and continue with next char + elseif ($r !== false && $r != $i) + { + $i = $r; + break; + } + } + } + } + } + $p = $c; // Set the parent char + } + return $this->tokens; + } + /** + * Remove the last state of the state stack and return the removed stack value. + * + * @return integer Removed state value + */ + public function popState() + { + $r = array_pop($this->states); + $this->state = $this->states[count($this->states) - 1]; + return $r; + } + /** + * Adds a new state onto the state stack. + * + * @param integer $state State to add onto the state stack. + * @return integer The index of the added state in the state stacks + */ + public function pushState($state) + { + $r = array_push($this->states, $state); + $this->state = $this->states[count($this->states) - 1]; + return $r; + } + /** + * Sets/restores the buffer. + * + * @param string $buffer Buffer to set + * @return void + */ + public function setBuffer($buffer) + { + $this->buffer = $buffer; + } + /** + * Set the exclusive state. + * + * @param string $exclusive Exclusive state + * @return void + */ + public function setExclusive($exclusive) + { + $this->stateExclusive = $exclusive; + } + /** + * Set the media types state. + * + * @param array $mediaTypes Media types state + * @return void + */ + public function setMediaTypes(array $mediaTypes) + { + $this->stateMediaTypes = $mediaTypes; + } + /** + * Sets the current state in the state stack; equals to {@link CssParser::popState()} + {@link CssParser::pushState()}. + * + * @param integer $state State to set + * @return integer + */ + public function setState($state) + { + $r = array_pop($this->states); + array_push($this->states, $state); + $this->state = $this->states[count($this->states) - 1]; + return $r; + } + /** + * Removes the exclusive state. + * + * @return void + */ + public function unsetExclusive() + { + $this->stateExclusive = false; + } + /** + * Removes the media types state. + * + * @return void + */ + public function unsetMediaTypes() + { + $this->stateMediaTypes = false; + } +} + +/** + * {@link aCssFromatter Formatter} returning the CSS source in {@link http://goo.gl/j4XdU OTBS indent style} (The One True Brace Style). + * + * @package CssMin/Formatter + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssOtbsFormatter extends aCssFormatter +{ + /** + * Implements {@link aCssFormatter::__toString()}. + * + * @return string + */ + public function __toString() + { + $r = array(); + $level = 0; + for ($i = 0, $l = count($this->tokens); $i < $l; $i++) + { + $token = $this->tokens[$i]; + $class = get_class($token); + $indent = str_repeat($this->indent, $level); + if ($class === "CssCommentToken") + { + $lines = array_map("trim", explode("\n", $token->Comment)); + for ($ii = 0, $ll = count($lines); $ii < $ll; $ii++) + { + $r[] = $indent . (substr($lines[$ii], 0, 1) == "*" ? " " : "") . $lines[$ii]; + } + } + elseif ($class === "CssAtCharsetToken") + { + $r[] = $indent . "@charset " . $token->Charset . ";"; + } + elseif ($class === "CssAtFontFaceStartToken") + { + $r[] = $indent . "@font-face {"; + $level++; + } + elseif ($class === "CssAtImportToken") + { + $r[] = $indent . "@import " . $token->Import . " " . implode(", ", $token->MediaTypes) . ";"; + } + elseif ($class === "CssAtKeyframesStartToken") + { + $r[] = $indent . "@keyframes \"" . $token->Name . "\" {"; + $level++; + } + elseif ($class === "CssAtMediaStartToken") + { + $r[] = $indent . "@media " . implode(", ", $token->MediaTypes) . " {"; + $level++; + } + elseif ($class === "CssAtPageStartToken") + { + $r[] = $indent . "@page {"; + $level++; + } + elseif ($class === "CssAtVariablesStartToken") + { + $r[] = $indent . "@variables " . implode(", ", $token->MediaTypes) . " {"; + $level++; + } + elseif ($class === "CssRulesetStartToken" || $class === "CssAtKeyframesRulesetStartToken") + { + $r[] = $indent . implode(", ", $token->Selectors) . " {"; + $level++; + } + elseif ($class == "CssAtFontFaceDeclarationToken" + || $class === "CssAtKeyframesRulesetDeclarationToken" + || $class === "CssAtPageDeclarationToken" + || $class == "CssAtVariablesDeclarationToken" + || $class === "CssRulesetDeclarationToken" + ) + { + $declaration = $indent . $token->Property . ": "; + if ($this->padding) + { + $declaration = str_pad($declaration, $this->padding, " ", STR_PAD_RIGHT); + } + $r[] = $declaration . $token->Value . ($token->IsImportant ? " !important" : "") . ";"; + } + elseif ($class === "CssAtFontFaceEndToken" + || $class === "CssAtMediaEndToken" + || $class === "CssAtKeyframesEndToken" + || $class === "CssAtKeyframesRulesetEndToken" + || $class === "CssAtPageEndToken" + || $class === "CssAtVariablesEndToken" + || $class === "CssRulesetEndToken" + ) + { + $level--; + $r[] = str_repeat($indent, $level) . "}"; + } + } + return implode("\n", $r); + } +} + +/** + * This {@link aCssToken CSS token} is a utility token that extends {@link aNullToken} and returns only a empty string. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssNullToken extends aCssToken +{ + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return ""; + } +} + +/** + * CSS Minifier. + * + * @package CssMin/Minifier + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssMinifier +{ + /** + * {@link aCssMinifierFilter Filters}. + * + * @var array + */ + private $filters = array(); + /** + * {@link aCssMinifierPlugin Plugins}. + * + * @var array + */ + private $plugins = array(); + /** + * Minified source. + * + * @var string + */ + private $minified = ""; + /** + * Constructer. + * + * Creates instances of {@link aCssMinifierFilter filters} and {@link aCssMinifierPlugin plugins}. + * + * @param string $source CSS source [optional] + * @param array $filters Filter configuration [optional] + * @param array $plugins Plugin configuration [optional] + * @return void + */ + public function __construct($source = null, array $filters = null, array $plugins = null) + { + $filters = array_merge(array + ( + "ImportImports" => false, + "RemoveComments" => true, + "RemoveEmptyRulesets" => true, + "RemoveEmptyAtBlocks" => true, + "ConvertLevel3Properties" => false, + "ConvertLevel3AtKeyframes" => false, + "Variables" => true, + "RemoveLastDelarationSemiColon" => true + ), is_array($filters) ? $filters : array()); + $plugins = array_merge(array + ( + "Variables" => true, + "ConvertFontWeight" => false, + "ConvertHslColors" => false, + "ConvertRgbColors" => false, + "ConvertNamedColors" => false, + "CompressColorValues" => false, + "CompressUnitValues" => false, + "CompressExpressionValues" => false + ), is_array($plugins) ? $plugins : array()); + // Filters + foreach ($filters as $name => $config) + { + if ($config !== false) + { + $class = "Css" . $name . "MinifierFilter"; + $config = is_array($config) ? $config : array(); + if (class_exists($class)) + { + $this->filters[] = new $class($this, $config); + } + else + { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The filter " . $name . " with the class name " . $class . " was not found")); + } + } + } + // Plugins + foreach ($plugins as $name => $config) + { + if ($config !== false) + { + $class = "Css" . $name . "MinifierPlugin"; + $config = is_array($config) ? $config : array(); + if (class_exists($class)) + { + $this->plugins[] = new $class($this, $config); + } + else + { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The plugin " . $name . " with the class name " . $class . " was not found")); + } + } + } + // -- + if (!is_null($source)) + { + $this->minify($source); + } + } + /** + * Returns the minified Source. + * + * @return string + */ + public function getMinified() + { + return $this->minified; + } + /** + * Returns a plugin by class name. + * + * @param string $name Class name of the plugin + * @return aCssMinifierPlugin + */ + public function getPlugin($class) + { + static $index = null; + if (is_null($index)) + { + $index = array(); + for ($i = 0, $l = count($this->plugins); $i < $l; $i++) + { + $index[get_class($this->plugins[$i])] = $i; + } + } + return isset($index[$class]) ? $this->plugins[$index[$class]] : false; + } + /** + * Minifies the CSS source. + * + * @param string $source CSS source + * @return string + */ + public function minify($source) + { + // Variables + $r = ""; + $parser = new CssParser($source); + $tokens = $parser->getTokens(); + $filters = $this->filters; + $filterCount = count($this->filters); + $plugins = $this->plugins; + $pluginCount = count($plugins); + $pluginIndex = array(); + $pluginTriggerTokens = array(); + $globalTriggerTokens = array(); + for ($i = 0, $l = count($plugins); $i < $l; $i++) + { + $tPluginClassName = get_class($plugins[$i]); + $pluginTriggerTokens[$i] = $plugins[$i]->getTriggerTokens(); + foreach ($pluginTriggerTokens[$i] as $v) + { + if (!in_array($v, $globalTriggerTokens)) + { + $globalTriggerTokens[] = $v; + } + } + $pluginTriggerTokens[$i] = "|" . implode("|", $pluginTriggerTokens[$i]) . "|"; + $pluginIndex[$tPluginClassName] = $i; + } + $globalTriggerTokens = "|" . implode("|", $globalTriggerTokens) . "|"; + /* + * Apply filters + */ + for($i = 0; $i < $filterCount; $i++) + { + // Apply the filter; if the return value is larger than 0... + if ($filters[$i]->apply($tokens) > 0) + { + // ...then filter null values and rebuild the token array + $tokens = array_values(array_filter($tokens)); + } + } + $tokenCount = count($tokens); + /* + * Apply plugins + */ + for($i = 0; $i < $tokenCount; $i++) + { + $triggerToken = "|" . get_class($tokens[$i]) . "|"; + if (strpos($globalTriggerTokens, $triggerToken) !== false) + { + for($ii = 0; $ii < $pluginCount; $ii++) + { + if (strpos($pluginTriggerTokens[$ii], $triggerToken) !== false || $pluginTriggerTokens[$ii] === false) + { + // Apply the plugin; if the return value is TRUE continue to the next token + if ($plugins[$ii]->apply($tokens[$i]) === true) + { + continue 2; + } + } + } + } + } + // Stringify the tokens + for($i = 0; $i < $tokenCount; $i++) + { + $r .= (string) $tokens[$i]; + } + $this->minified = $r; + return $r; + } +} + +/** + * CssMin - A (simple) css minifier with benefits + * + * -- + * Copyright (c) 2011 Joe Scylla + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * -- + * + * @package CssMin + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssMin +{ + /** + * Index of classes + * + * @var array + */ + private static $classIndex = array(); + /** + * Parse/minify errors + * + * @var array + */ + private static $errors = array(); + /** + * Verbose output. + * + * @var boolean + */ + private static $isVerbose = false; + /** + * {@link http://goo.gl/JrW54 Autoload} function of CssMin. + * + * @param string $class Name of the class + * @return void + */ + public static function autoload($class) + { + if (isset(self::$classIndex[$class])) + { + require(self::$classIndex[$class]); + } + } + /** + * Return errors + * + * @return array of {CssError}. + */ + public static function getErrors() + { + return self::$errors; + } + /** + * Returns if there were errors. + * + * @return boolean + */ + public static function hasErrors() + { + return count(self::$errors) > 0; + } + /** + * Initialises CssMin. + * + * @return void + */ + public static function initialise() + { + // Create the class index for autoloading or including + $paths = array(dirname(__FILE__)); + while (list($i, $path) = each($paths)) + { + $subDirectorys = glob($path . "*", GLOB_MARK | GLOB_ONLYDIR | GLOB_NOSORT); + if (is_array($subDirectorys)) + { + foreach ($subDirectorys as $subDirectory) + { + $paths[] = $subDirectory; + } + } + $files = glob($path . "*.php", 0); + if (is_array($files)) + { + foreach ($files as $file) + { + $class = substr(basename($file), 0, -4); + self::$classIndex[$class] = $file; + } + } + } + krsort(self::$classIndex); + // Only use autoloading if spl_autoload_register() is available and no __autoload() is defined (because + // __autoload() breaks if spl_autoload_register() is used. + if (function_exists("spl_autoload_register") && !is_callable("__autoload")) + { + spl_autoload_register(array(__CLASS__, "autoload")); + } + // Otherwise include all class files + else + { + foreach (self::$classIndex as $class => $file) + { + if (!class_exists($class)) + { + require_once($file); + } + } + } + } + /** + * Minifies CSS source. + * + * @param string $source CSS source + * @param array $filters Filter configuration [optional] + * @param array $plugins Plugin configuration [optional] + * @return string Minified CSS + */ + public static function minify($source, array $filters = null, array $plugins = null) + { + self::$errors = array(); + $minifier = new CssMinifier($source, $filters, $plugins); + return $minifier->getMinified(); + } + /** + * Parse the CSS source. + * + * @param string $source CSS source + * @param array $plugins Plugin configuration [optional] + * @return array Array of aCssToken + */ + public static function parse($source, array $plugins = null) + { + self::$errors = array(); + $parser = new CssParser($source, $plugins); + return $parser->getTokens(); + } + /** + * -- + * + * @param boolean $to + * @return boolean + */ + public static function setVerbose($to) + { + self::$isVerbose = (boolean) $to; + return self::$isVerbose; + } + /** + * -- + * + * @param CssError $error + * @return void + */ + public static function triggerError(CssError $error) + { + self::$errors[] = $error; + if (self::$isVerbose) + { + trigger_error((string) $error, E_USER_WARNING); + } + } +} +// Initialises CssMin +CssMin::initialise(); + +/** + * This {@link aCssMinifierFilter minifier filter} import external css files defined with the @import at-rule into the + * current stylesheet. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssImportImportsMinifierFilter extends aCssMinifierFilter +{ + /** + * Array with already imported external stylesheets. + * + * @var array + */ + private $imported = array(); + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + if (!isset($this->configuration["BasePath"]) || !is_dir($this->configuration["BasePath"])) + { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Base path " . ($this->configuration["BasePath"] ? $this->configuration["BasePath"] : "null"). " is not a directory")); + return 0; + } + for ($i = 0, $l = count($tokens); $i < $l; $i++) + { + if (get_class($tokens[$i]) === "CssAtImportToken") + { + $import = $this->configuration["BasePath"] . "/" . $tokens[$i]->Import; + // Import file was not found/is not a file + if (!is_file($import)) + { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Import file " . $import. " was not found.", (string) $tokens[$i])); + } + // Import file already imported; remove this @import at-rule to prevent recursions + elseif (in_array($import, $this->imported)) + { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Import file " . $import. " was already imported.", (string) $tokens[$i])); + $tokens[$i] = null; + } + else + { + $this->imported[] = $import; + $parser = new CssParser(file_get_contents($import)); + $import = $parser->getTokens(); + // The @import at-rule has media types defined requiring special handling + if (count($tokens[$i]->MediaTypes) > 0 && !(count($tokens[$i]->MediaTypes) == 1 && $tokens[$i]->MediaTypes[0] == "all")) + { + $blocks = array(); + /* + * Filter or set media types of @import at-rule or remove the @import at-rule if no media type is matching the parent @import at-rule + */ + for($ii = 0, $ll = count($import); $ii < $ll; $ii++) + { + if (get_class($import[$ii]) === "CssAtImportToken") + { + // @import at-rule defines no media type or only the "all" media type; set the media types to the one defined in the parent @import at-rule + if (count($import[$ii]->MediaTypes) == 0 || (count($import[$ii]->MediaTypes) == 1 && $import[$ii]->MediaTypes[0] == "all")) + { + $import[$ii]->MediaTypes = $tokens[$i]->MediaTypes; + } + // @import at-rule defineds one or more media types; filter out media types not matching with the parent @import at-rule + elseif (count($import[$ii]->MediaTypes > 0)) + { + foreach ($import[$ii]->MediaTypes as $index => $mediaType) + { + if (!in_array($mediaType, $tokens[$i]->MediaTypes)) + { + unset($import[$ii]->MediaTypes[$index]); + } + } + $import[$ii]->MediaTypes = array_values($import[$ii]->MediaTypes); + // If there are no media types left in the @import at-rule remove the @import at-rule + if (count($import[$ii]->MediaTypes) == 0) + { + $import[$ii] = null; + } + } + } + } + /* + * Remove media types of @media at-rule block not defined in the @import at-rule + */ + for($ii = 0, $ll = count($import); $ii < $ll; $ii++) + { + if (get_class($import[$ii]) === "CssAtMediaStartToken") + { + foreach ($import[$ii]->MediaTypes as $index => $mediaType) + { + if (!in_array($mediaType, $tokens[$i]->MediaTypes)) + { + unset($import[$ii]->MediaTypes[$index]); + } + $import[$ii]->MediaTypes = array_values($import[$ii]->MediaTypes); + } + } + } + /* + * If no media types left of the @media at-rule block remove the complete block + */ + for($ii = 0, $ll = count($import); $ii < $ll; $ii++) + { + if (get_class($import[$ii]) === "CssAtMediaStartToken") + { + if (count($import[$ii]->MediaTypes) === 0) + { + for ($iii = $ii; $iii < $ll; $iii++) + { + if (get_class($import[$iii]) === "CssAtMediaEndToken") + { + break; + } + } + if (get_class($import[$iii]) === "CssAtMediaEndToken") + { + array_splice($import, $ii, $iii - $ii + 1, array()); + $ll = count($import); + } + } + } + } + /* + * If the media types of the @media at-rule equals the media types defined in the @import + * at-rule remove the CssAtMediaStartToken and CssAtMediaEndToken token + */ + for($ii = 0, $ll = count($import); $ii < $ll; $ii++) + { + if (get_class($import[$ii]) === "CssAtMediaStartToken" && count(array_diff($tokens[$i]->MediaTypes, $import[$ii]->MediaTypes)) === 0) + { + for ($iii = $ii; $iii < $ll; $iii++) + { + if (get_class($import[$iii]) == "CssAtMediaEndToken") + { + break; + } + } + if (get_class($import[$iii]) == "CssAtMediaEndToken") + { + unset($import[$ii]); + unset($import[$iii]); + $import = array_values($import); + $ll = count($import); + } + } + } + /** + * Extract CssAtImportToken and CssAtCharsetToken tokens + */ + for($ii = 0, $ll = count($import); $ii < $ll; $ii++) + { + $class = get_class($import[$ii]); + if ($class === "CssAtImportToken" || $class === "CssAtCharsetToken") + { + $blocks = array_merge($blocks, array_splice($import, $ii, 1, array())); + $ll = count($import); + } + } + /* + * Extract the @font-face, @media and @page at-rule block + */ + for($ii = 0, $ll = count($import); $ii < $ll; $ii++) + { + $class = get_class($import[$ii]); + if ($class === "CssAtFontFaceStartToken" || $class === "CssAtMediaStartToken" || $class === "CssAtPageStartToken" || $class === "CssAtVariablesStartToken") + { + for ($iii = $ii; $iii < $ll; $iii++) + { + $class = get_class($import[$iii]); + if ($class === "CssAtFontFaceEndToken" || $class === "CssAtMediaEndToken" || $class === "CssAtPageEndToken" || $class === "CssAtVariablesEndToken") + { + break; + } + } + $class = get_class($import[$iii]); + if (isset($import[$iii]) && ($class === "CssAtFontFaceEndToken" || $class === "CssAtMediaEndToken" || $class === "CssAtPageEndToken" || $class === "CssAtVariablesEndToken")) + { + $blocks = array_merge($blocks, array_splice($import, $ii, $iii - $ii + 1, array())); + $ll = count($import); + } + } + } + // Create the import array with extracted tokens and the rulesets wrapped into a @media at-rule block + $import = array_merge($blocks, array(new CssAtMediaStartToken($tokens[$i]->MediaTypes)), $import, array(new CssAtMediaEndToken())); + } + // Insert the imported tokens + array_splice($tokens, $i, 1, $import); + // Modify parameters of the for-loop + $i--; + $l = count($tokens); + } + } + } + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for preserve parsing expression() declaration values. + * + * This plugin return no {@link aCssToken CssToken} but ensures that expression() declaration values will get parsed + * properly. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssExpressionParserPlugin extends aCssParserPlugin +{ + /** + * Count of left braces. + * + * @var integer + */ + private $leftBraces = 0; + /** + * Count of right braces. + * + * @var integer + */ + private $rightBraces = 0; + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("(", ")", ";", "}"); + } + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return false; + } + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of expression + if ($char === "(" && strtolower(substr($this->parser->getSource(), $index - 10, 11)) === "expression(" && $state !== "T_EXPRESSION") + { + $this->parser->pushState("T_EXPRESSION"); + $this->leftBraces++; + } + // Count left braces + elseif ($char === "(" && $state === "T_EXPRESSION") + { + $this->leftBraces++; + } + // Count right braces + elseif ($char === ")" && $state === "T_EXPRESSION") + { + $this->rightBraces++; + } + // Possible end of expression; if left and right braces are equal the expressen ends + elseif (($char === ";" || $char === "}") && $state === "T_EXPRESSION" && $this->leftBraces === $this->rightBraces) + { + $this->leftBraces = $this->rightBraces = 0; + $this->parser->popState(); + return $index - 1; + } + else + { + return false; + } + return true; + } +} + +/** + * CSS Error. + * + * @package CssMin + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssError +{ + /** + * File. + * + * @var string + */ + public $File = ""; + /** + * Line. + * + * @var integer + */ + public $Line = 0; + /** + * Error message. + * + * @var string + */ + public $Message = ""; + /** + * Source. + * + * @var string + */ + public $Source = ""; + /** + * Constructor triggering the error. + * + * @param string $message Error message + * @param string $source Corresponding line [optional] + * @return void + */ + public function __construct($file, $line, $message, $source = "") + { + $this->File = $file; + $this->Line = $line; + $this->Message = $message; + $this->Source = $source; + } + /** + * Returns the error as formatted string. + * + * @return string + */ + public function __toString() + { + return $this->Message . ($this->Source ? ":
    " . $this->Source . "": "") . "
    in file " . $this->File . " at line " . $this->Line; + } +} + +/** + * This {@link aCssMinifierPlugin} will convert a color value in rgb notation to hexadecimal notation. + * + * Example: + * + * color: rgb(200,60%,5); + * + * + * Will get converted to: + * + * color:#c89905; + * + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertRgbColorsMinifierPlugin extends aCssMinifierPlugin +{ + /** + * Regular expression matching the value. + * + * @var string + */ + private $reMatch = "/rgb\s*\(\s*([0-9%]+)\s*,\s*([0-9%]+)\s*,\s*([0-9%]+)\s*\)/iS"; + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + if (stripos($token->Value, "rgb") !== false && preg_match($this->reMatch, $token->Value, $m)) + { + for ($i = 1, $l = count($m); $i < $l; $i++) + { + if (strpos("%", $m[$i]) !== false) + { + $m[$i] = substr($m[$i], 0, -1); + $m[$i] = (int) (256 * ($m[$i] / 100)); + } + $m[$i] = str_pad(dechex($m[$i]), 2, "0", STR_PAD_LEFT); + } + $token->Value = str_replace($m[0], "#" . $m[1] . $m[2] . $m[3], $token->Value); + } + return false; + } + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} + +/** + * This {@link aCssMinifierPlugin} will convert named color values to hexadecimal notation. + * + * Example: + * + * color: black; + * border: 1px solid indigo; + * + * + * Will get converted to: + * + * color:#000; + * border:1px solid #4b0082; + * + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertNamedColorsMinifierPlugin extends aCssMinifierPlugin +{ + + /** + * Regular expression matching the value. + * + * @var string + */ + private $reMatch = null; + /** + * Transformation table used by the {@link CssConvertNamedColorsMinifierPlugin::reReplace() replacement method}. + * + * @var array + */ + private $transformation = array + ( + "aliceblue" => "#f0f8ff", + "antiquewhite" => "#faebd7", + "aqua" => "#0ff", + "aquamarine" => "#7fffd4", + "azure" => "#f0ffff", + "beige" => "#f5f5dc", + "black" => "#000", + "blue" => "#00f", + "blueviolet" => "#8a2be2", + "brown" => "#a52a2a", + "burlywood" => "#deb887", + "cadetblue" => "#5f9ea0", + "chartreuse" => "#7fff00", + "chocolate" => "#d2691e", + "coral" => "#ff7f50", + "cornflowerblue" => "#6495ed", + "cornsilk" => "#fff8dc", + "crimson" => "#dc143c", + "darkblue" => "#00008b", + "darkcyan" => "#008b8b", + "darkgoldenrod" => "#b8860b", + "darkgray" => "#a9a9a9", + "darkgreen" => "#006400", + "darkkhaki" => "#bdb76b", + "darkmagenta" => "#8b008b", + "darkolivegreen" => "#556b2f", + "darkorange" => "#ff8c00", + "darkorchid" => "#9932cc", + "darkred" => "#8b0000", + "darksalmon" => "#e9967a", + "darkseagreen" => "#8fbc8f", + "darkslateblue" => "#483d8b", + "darkslategray" => "#2f4f4f", + "darkturquoise" => "#00ced1", + "darkviolet" => "#9400d3", + "deeppink" => "#ff1493", + "deepskyblue" => "#00bfff", + "dimgray" => "#696969", + "dodgerblue" => "#1e90ff", + "firebrick" => "#b22222", + "floralwhite" => "#fffaf0", + "forestgreen" => "#228b22", + "fuchsia" => "#f0f", + "gainsboro" => "#dcdcdc", + "ghostwhite" => "#f8f8ff", + "gold" => "#ffd700", + "goldenrod" => "#daa520", + "gray" => "#808080", + "green" => "#008000", + "greenyellow" => "#adff2f", + "honeydew" => "#f0fff0", + "hotpink" => "#ff69b4", + "indianred" => "#cd5c5c", + "indigo" => "#4b0082", + "ivory" => "#fffff0", + "khaki" => "#f0e68c", + "lavender" => "#e6e6fa", + "lavenderblush" => "#fff0f5", + "lawngreen" => "#7cfc00", + "lemonchiffon" => "#fffacd", + "lightblue" => "#add8e6", + "lightcoral" => "#f08080", + "lightcyan" => "#e0ffff", + "lightgoldenrodyellow" => "#fafad2", + "lightgreen" => "#90ee90", + "lightgrey" => "#d3d3d3", + "lightpink" => "#ffb6c1", + "lightsalmon" => "#ffa07a", + "lightseagreen" => "#20b2aa", + "lightskyblue" => "#87cefa", + "lightslategray" => "#789", + "lightsteelblue" => "#b0c4de", + "lightyellow" => "#ffffe0", + "lime" => "#0f0", + "limegreen" => "#32cd32", + "linen" => "#faf0e6", + "maroon" => "#800000", + "mediumaquamarine" => "#66cdaa", + "mediumblue" => "#0000cd", + "mediumorchid" => "#ba55d3", + "mediumpurple" => "#9370db", + "mediumseagreen" => "#3cb371", + "mediumslateblue" => "#7b68ee", + "mediumspringgreen" => "#00fa9a", + "mediumturquoise" => "#48d1cc", + "mediumvioletred" => "#c71585", + "midnightblue" => "#191970", + "mintcream" => "#f5fffa", + "mistyrose" => "#ffe4e1", + "moccasin" => "#ffe4b5", + "navajowhite" => "#ffdead", + "navy" => "#000080", + "oldlace" => "#fdf5e6", + "olive" => "#808000", + "olivedrab" => "#6b8e23", + "orange" => "#ffa500", + "orangered" => "#ff4500", + "orchid" => "#da70d6", + "palegoldenrod" => "#eee8aa", + "palegreen" => "#98fb98", + "paleturquoise" => "#afeeee", + "palevioletred" => "#db7093", + "papayawhip" => "#ffefd5", + "peachpuff" => "#ffdab9", + "peru" => "#cd853f", + "pink" => "#ffc0cb", + "plum" => "#dda0dd", + "powderblue" => "#b0e0e6", + "purple" => "#800080", + "red" => "#f00", + "rosybrown" => "#bc8f8f", + "royalblue" => "#4169e1", + "saddlebrown" => "#8b4513", + "salmon" => "#fa8072", + "sandybrown" => "#f4a460", + "seagreen" => "#2e8b57", + "seashell" => "#fff5ee", + "sienna" => "#a0522d", + "silver" => "#c0c0c0", + "skyblue" => "#87ceeb", + "slateblue" => "#6a5acd", + "slategray" => "#708090", + "snow" => "#fffafa", + "springgreen" => "#00ff7f", + "steelblue" => "#4682b4", + "tan" => "#d2b48c", + "teal" => "#008080", + "thistle" => "#d8bfd8", + "tomato" => "#ff6347", + "turquoise" => "#40e0d0", + "violet" => "#ee82ee", + "wheat" => "#f5deb3", + "white" => "#fff", + "whitesmoke" => "#f5f5f5", + "yellow" => "#ff0", + "yellowgreen" => "#9acd32" + ); + /** + * Overwrites {@link aCssMinifierPlugin::__construct()}. + * + * The constructor will create the {@link CssConvertNamedColorsMinifierPlugin::$reMatch replace regular expression} + * based on the {@link CssConvertNamedColorsMinifierPlugin::$transformation transformation table}. + * + * @param CssMinifier $minifier The CssMinifier object of this plugin. + * @param array $configuration Plugin configuration [optional] + * @return void + */ + public function __construct(CssMinifier $minifier, array $configuration = array()) + { + $this->reMatch = "/(^|\s)+(" . implode("|", array_keys($this->transformation)) . ")(\s|$)+/iS"; + parent::__construct($minifier, $configuration); + } + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + $lcValue = strtolower($token->Value); + // Declaration value equals a value in the transformation table => simple replace + if (isset($this->transformation[$lcValue])) + { + $token->Value = $this->transformation[$lcValue]; + } + // Declaration value contains a value in the transformation table => regular expression replace + elseif (preg_match($this->reMatch, $token->Value)) + { + $token->Value = preg_replace_callback($this->reMatch, array($this, 'reReplace'), $token->Value); + } + return false; + } + /** + * Callback for replacement value. + * + * @param array $match + * @return string + */ + private function reReplace($match) + { + return $match[1] . $this->transformation[strtolower($match[2])] . $match[3]; + } + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} triggers on CSS Level 3 properties and will add declaration tokens + * with browser-specific properties. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertLevel3PropertiesMinifierFilter extends aCssMinifierFilter +{ + /** + * Css property transformations table. Used to convert CSS3 and proprietary properties to the browser-specific + * counterparts. + * + * @var array + */ + private $transformations = array + ( + // Property Array(Mozilla, Webkit, Opera, Internet Explorer); NULL values are placeholders and will get ignored + "animation" => array(null, "-webkit-animation", null, null), + "animation-delay" => array(null, "-webkit-animation-delay", null, null), + "animation-direction" => array(null, "-webkit-animation-direction", null, null), + "animation-duration" => array(null, "-webkit-animation-duration", null, null), + "animation-fill-mode" => array(null, "-webkit-animation-fill-mode", null, null), + "animation-iteration-count" => array(null, "-webkit-animation-iteration-count", null, null), + "animation-name" => array(null, "-webkit-animation-name", null, null), + "animation-play-state" => array(null, "-webkit-animation-play-state", null, null), + "animation-timing-function" => array(null, "-webkit-animation-timing-function", null, null), + "appearance" => array("-moz-appearance", "-webkit-appearance", null, null), + "backface-visibility" => array(null, "-webkit-backface-visibility", null, null), + "background-clip" => array(null, "-webkit-background-clip", null, null), + "background-composite" => array(null, "-webkit-background-composite", null, null), + "background-inline-policy" => array("-moz-background-inline-policy", null, null, null), + "background-origin" => array(null, "-webkit-background-origin", null, null), + "background-position-x" => array(null, null, null, "-ms-background-position-x"), + "background-position-y" => array(null, null, null, "-ms-background-position-y"), + "background-size" => array(null, "-webkit-background-size", null, null), + "behavior" => array(null, null, null, "-ms-behavior"), + "binding" => array("-moz-binding", null, null, null), + "border-after" => array(null, "-webkit-border-after", null, null), + "border-after-color" => array(null, "-webkit-border-after-color", null, null), + "border-after-style" => array(null, "-webkit-border-after-style", null, null), + "border-after-width" => array(null, "-webkit-border-after-width", null, null), + "border-before" => array(null, "-webkit-border-before", null, null), + "border-before-color" => array(null, "-webkit-border-before-color", null, null), + "border-before-style" => array(null, "-webkit-border-before-style", null, null), + "border-before-width" => array(null, "-webkit-border-before-width", null, null), + "border-border-bottom-colors" => array("-moz-border-bottom-colors", null, null, null), + "border-bottom-left-radius" => array("-moz-border-radius-bottomleft", "-webkit-border-bottom-left-radius", null, null), + "border-bottom-right-radius" => array("-moz-border-radius-bottomright", "-webkit-border-bottom-right-radius", null, null), + "border-end" => array("-moz-border-end", "-webkit-border-end", null, null), + "border-end-color" => array("-moz-border-end-color", "-webkit-border-end-color", null, null), + "border-end-style" => array("-moz-border-end-style", "-webkit-border-end-style", null, null), + "border-end-width" => array("-moz-border-end-width", "-webkit-border-end-width", null, null), + "border-fit" => array(null, "-webkit-border-fit", null, null), + "border-horizontal-spacing" => array(null, "-webkit-border-horizontal-spacing", null, null), + "border-image" => array("-moz-border-image", "-webkit-border-image", null, null), + "border-left-colors" => array("-moz-border-left-colors", null, null, null), + "border-radius" => array("-moz-border-radius", "-webkit-border-radius", null, null), + "border-border-right-colors" => array("-moz-border-right-colors", null, null, null), + "border-start" => array("-moz-border-start", "-webkit-border-start", null, null), + "border-start-color" => array("-moz-border-start-color", "-webkit-border-start-color", null, null), + "border-start-style" => array("-moz-border-start-style", "-webkit-border-start-style", null, null), + "border-start-width" => array("-moz-border-start-width", "-webkit-border-start-width", null, null), + "border-top-colors" => array("-moz-border-top-colors", null, null, null), + "border-top-left-radius" => array("-moz-border-radius-topleft", "-webkit-border-top-left-radius", null, null), + "border-top-right-radius" => array("-moz-border-radius-topright", "-webkit-border-top-right-radius", null, null), + "border-vertical-spacing" => array(null, "-webkit-border-vertical-spacing", null, null), + "box-align" => array("-moz-box-align", "-webkit-box-align", null, null), + "box-direction" => array("-moz-box-direction", "-webkit-box-direction", null, null), + "box-flex" => array("-moz-box-flex", "-webkit-box-flex", null, null), + "box-flex-group" => array(null, "-webkit-box-flex-group", null, null), + "box-flex-lines" => array(null, "-webkit-box-flex-lines", null, null), + "box-ordinal-group" => array("-moz-box-ordinal-group", "-webkit-box-ordinal-group", null, null), + "box-orient" => array("-moz-box-orient", "-webkit-box-orient", null, null), + "box-pack" => array("-moz-box-pack", "-webkit-box-pack", null, null), + "box-reflect" => array(null, "-webkit-box-reflect", null, null), + "box-shadow" => array("-moz-box-shadow", "-webkit-box-shadow", null, null), + "box-sizing" => array("-moz-box-sizing", null, null, null), + "color-correction" => array(null, "-webkit-color-correction", null, null), + "column-break-after" => array(null, "-webkit-column-break-after", null, null), + "column-break-before" => array(null, "-webkit-column-break-before", null, null), + "column-break-inside" => array(null, "-webkit-column-break-inside", null, null), + "column-count" => array("-moz-column-count", "-webkit-column-count", null, null), + "column-gap" => array("-moz-column-gap", "-webkit-column-gap", null, null), + "column-rule" => array("-moz-column-rule", "-webkit-column-rule", null, null), + "column-rule-color" => array("-moz-column-rule-color", "-webkit-column-rule-color", null, null), + "column-rule-style" => array("-moz-column-rule-style", "-webkit-column-rule-style", null, null), + "column-rule-width" => array("-moz-column-rule-width", "-webkit-column-rule-width", null, null), + "column-span" => array(null, "-webkit-column-span", null, null), + "column-width" => array("-moz-column-width", "-webkit-column-width", null, null), + "columns" => array(null, "-webkit-columns", null, null), + "filter" => array(__CLASS__, "filter"), + "float-edge" => array("-moz-float-edge", null, null, null), + "font-feature-settings" => array("-moz-font-feature-settings", null, null, null), + "font-language-override" => array("-moz-font-language-override", null, null, null), + "font-size-delta" => array(null, "-webkit-font-size-delta", null, null), + "font-smoothing" => array(null, "-webkit-font-smoothing", null, null), + "force-broken-image-icon" => array("-moz-force-broken-image-icon", null, null, null), + "highlight" => array(null, "-webkit-highlight", null, null), + "hyphenate-character" => array(null, "-webkit-hyphenate-character", null, null), + "hyphenate-locale" => array(null, "-webkit-hyphenate-locale", null, null), + "hyphens" => array(null, "-webkit-hyphens", null, null), + "force-broken-image-icon" => array("-moz-image-region", null, null, null), + "ime-mode" => array(null, null, null, "-ms-ime-mode"), + "interpolation-mode" => array(null, null, null, "-ms-interpolation-mode"), + "layout-flow" => array(null, null, null, "-ms-layout-flow"), + "layout-grid" => array(null, null, null, "-ms-layout-grid"), + "layout-grid-char" => array(null, null, null, "-ms-layout-grid-char"), + "layout-grid-line" => array(null, null, null, "-ms-layout-grid-line"), + "layout-grid-mode" => array(null, null, null, "-ms-layout-grid-mode"), + "layout-grid-type" => array(null, null, null, "-ms-layout-grid-type"), + "line-break" => array(null, "-webkit-line-break", null, "-ms-line-break"), + "line-clamp" => array(null, "-webkit-line-clamp", null, null), + "line-grid-mode" => array(null, null, null, "-ms-line-grid-mode"), + "logical-height" => array(null, "-webkit-logical-height", null, null), + "logical-width" => array(null, "-webkit-logical-width", null, null), + "margin-after" => array(null, "-webkit-margin-after", null, null), + "margin-after-collapse" => array(null, "-webkit-margin-after-collapse", null, null), + "margin-before" => array(null, "-webkit-margin-before", null, null), + "margin-before-collapse" => array(null, "-webkit-margin-before-collapse", null, null), + "margin-bottom-collapse" => array(null, "-webkit-margin-bottom-collapse", null, null), + "margin-collapse" => array(null, "-webkit-margin-collapse", null, null), + "margin-end" => array("-moz-margin-end", "-webkit-margin-end", null, null), + "margin-start" => array("-moz-margin-start", "-webkit-margin-start", null, null), + "margin-top-collapse" => array(null, "-webkit-margin-top-collapse", null, null), + "marquee " => array(null, "-webkit-marquee", null, null), + "marquee-direction" => array(null, "-webkit-marquee-direction", null, null), + "marquee-increment" => array(null, "-webkit-marquee-increment", null, null), + "marquee-repetition" => array(null, "-webkit-marquee-repetition", null, null), + "marquee-speed" => array(null, "-webkit-marquee-speed", null, null), + "marquee-style" => array(null, "-webkit-marquee-style", null, null), + "mask" => array(null, "-webkit-mask", null, null), + "mask-attachment" => array(null, "-webkit-mask-attachment", null, null), + "mask-box-image" => array(null, "-webkit-mask-box-image", null, null), + "mask-clip" => array(null, "-webkit-mask-clip", null, null), + "mask-composite" => array(null, "-webkit-mask-composite", null, null), + "mask-image" => array(null, "-webkit-mask-image", null, null), + "mask-origin" => array(null, "-webkit-mask-origin", null, null), + "mask-position" => array(null, "-webkit-mask-position", null, null), + "mask-position-x" => array(null, "-webkit-mask-position-x", null, null), + "mask-position-y" => array(null, "-webkit-mask-position-y", null, null), + "mask-repeat" => array(null, "-webkit-mask-repeat", null, null), + "mask-repeat-x" => array(null, "-webkit-mask-repeat-x", null, null), + "mask-repeat-y" => array(null, "-webkit-mask-repeat-y", null, null), + "mask-size" => array(null, "-webkit-mask-size", null, null), + "match-nearest-mail-blockquote-color" => array(null, "-webkit-match-nearest-mail-blockquote-color", null, null), + "max-logical-height" => array(null, "-webkit-max-logical-height", null, null), + "max-logical-width" => array(null, "-webkit-max-logical-width", null, null), + "min-logical-height" => array(null, "-webkit-min-logical-height", null, null), + "min-logical-width" => array(null, "-webkit-min-logical-width", null, null), + "object-fit" => array(null, null, "-o-object-fit", null), + "object-position" => array(null, null, "-o-object-position", null), + "opacity" => array(__CLASS__, "opacity"), + "outline-radius" => array("-moz-outline-radius", null, null, null), + "outline-bottom-left-radius" => array("-moz-outline-radius-bottomleft", null, null, null), + "outline-bottom-right-radius" => array("-moz-outline-radius-bottomright", null, null, null), + "outline-top-left-radius" => array("-moz-outline-radius-topleft", null, null, null), + "outline-top-right-radius" => array("-moz-outline-radius-topright", null, null, null), + "padding-after" => array(null, "-webkit-padding-after", null, null), + "padding-before" => array(null, "-webkit-padding-before", null, null), + "padding-end" => array("-moz-padding-end", "-webkit-padding-end", null, null), + "padding-start" => array("-moz-padding-start", "-webkit-padding-start", null, null), + "perspective" => array(null, "-webkit-perspective", null, null), + "perspective-origin" => array(null, "-webkit-perspective-origin", null, null), + "perspective-origin-x" => array(null, "-webkit-perspective-origin-x", null, null), + "perspective-origin-y" => array(null, "-webkit-perspective-origin-y", null, null), + "rtl-ordering" => array(null, "-webkit-rtl-ordering", null, null), + "scrollbar-3dlight-color" => array(null, null, null, "-ms-scrollbar-3dlight-color"), + "scrollbar-arrow-color" => array(null, null, null, "-ms-scrollbar-arrow-color"), + "scrollbar-base-color" => array(null, null, null, "-ms-scrollbar-base-color"), + "scrollbar-darkshadow-color" => array(null, null, null, "-ms-scrollbar-darkshadow-color"), + "scrollbar-face-color" => array(null, null, null, "-ms-scrollbar-face-color"), + "scrollbar-highlight-color" => array(null, null, null, "-ms-scrollbar-highlight-color"), + "scrollbar-shadow-color" => array(null, null, null, "-ms-scrollbar-shadow-color"), + "scrollbar-track-color" => array(null, null, null, "-ms-scrollbar-track-color"), + "stack-sizing" => array("-moz-stack-sizing", null, null, null), + "svg-shadow" => array(null, "-webkit-svg-shadow", null, null), + "tab-size" => array("-moz-tab-size", null, "-o-tab-size", null), + "table-baseline" => array(null, null, "-o-table-baseline", null), + "text-align-last" => array(null, null, null, "-ms-text-align-last"), + "text-autospace" => array(null, null, null, "-ms-text-autospace"), + "text-combine" => array(null, "-webkit-text-combine", null, null), + "text-decorations-in-effect" => array(null, "-webkit-text-decorations-in-effect", null, null), + "text-emphasis" => array(null, "-webkit-text-emphasis", null, null), + "text-emphasis-color" => array(null, "-webkit-text-emphasis-color", null, null), + "text-emphasis-position" => array(null, "-webkit-text-emphasis-position", null, null), + "text-emphasis-style" => array(null, "-webkit-text-emphasis-style", null, null), + "text-fill-color" => array(null, "-webkit-text-fill-color", null, null), + "text-justify" => array(null, null, null, "-ms-text-justify"), + "text-kashida-space" => array(null, null, null, "-ms-text-kashida-space"), + "text-overflow" => array(null, null, "-o-text-overflow", "-ms-text-overflow"), + "text-security" => array(null, "-webkit-text-security", null, null), + "text-size-adjust" => array(null, "-webkit-text-size-adjust", null, "-ms-text-size-adjust"), + "text-stroke" => array(null, "-webkit-text-stroke", null, null), + "text-stroke-color" => array(null, "-webkit-text-stroke-color", null, null), + "text-stroke-width" => array(null, "-webkit-text-stroke-width", null, null), + "text-underline-position" => array(null, null, null, "-ms-text-underline-position"), + "transform" => array("-moz-transform", "-webkit-transform", "-o-transform", null), + "transform-origin" => array("-moz-transform-origin", "-webkit-transform-origin", "-o-transform-origin", null), + "transform-origin-x" => array(null, "-webkit-transform-origin-x", null, null), + "transform-origin-y" => array(null, "-webkit-transform-origin-y", null, null), + "transform-origin-z" => array(null, "-webkit-transform-origin-z", null, null), + "transform-style" => array(null, "-webkit-transform-style", null, null), + "transition" => array("-moz-transition", "-webkit-transition", "-o-transition", null), + "transition-delay" => array("-moz-transition-delay", "-webkit-transition-delay", "-o-transition-delay", null), + "transition-duration" => array("-moz-transition-duration", "-webkit-transition-duration", "-o-transition-duration", null), + "transition-property" => array("-moz-transition-property", "-webkit-transition-property", "-o-transition-property", null), + "transition-timing-function" => array("-moz-transition-timing-function", "-webkit-transition-timing-function", "-o-transition-timing-function", null), + "user-drag" => array(null, "-webkit-user-drag", null, null), + "user-focus" => array("-moz-user-focus", null, null, null), + "user-input" => array("-moz-user-input", null, null, null), + "user-modify" => array("-moz-user-modify", "-webkit-user-modify", null, null), + "user-select" => array("-moz-user-select", "-webkit-user-select", null, null), + "white-space" => array(__CLASS__, "whiteSpace"), + "window-shadow" => array("-moz-window-shadow", null, null, null), + "word-break" => array(null, null, null, "-ms-word-break"), + "word-wrap" => array(null, null, null, "-ms-word-wrap"), + "writing-mode" => array(null, "-webkit-writing-mode", null, "-ms-writing-mode"), + "zoom" => array(null, null, null, "-ms-zoom") + ); + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + $transformations = &$this->transformations; + for ($i = 0, $l = count($tokens); $i < $l; $i++) + { + if (get_class($tokens[$i]) === "CssRulesetDeclarationToken") + { + $tProperty = $tokens[$i]->Property; + if (isset($transformations[$tProperty])) + { + $result = array(); + if (is_callable($transformations[$tProperty])) + { + $result = call_user_func_array($transformations[$tProperty], array($tokens[$i])); + if (!is_array($result) && is_object($result)) + { + $result = array($result); + } + } + else + { + $tValue = $tokens[$i]->Value; + $tMediaTypes = $tokens[$i]->MediaTypes; + foreach ($transformations[$tProperty] as $property) + { + if ($property !== null) + { + $result[] = new CssRulesetDeclarationToken($property, $tValue, $tMediaTypes); + } + } + } + if (count($result) > 0) + { + array_splice($tokens, $i + 1, 0, $result); + $i += count($result); + $l += count($result); + } + } + } + } + return $r; + } + /** + * Transforms the Internet Explorer specific declaration property "filter" to Internet Explorer 8+ compatible + * declaratiopn property "-ms-filter". + * + * @param aCssToken $token + * @return array + */ + private static function filter($token) + { + $r = array + ( + new CssRulesetDeclarationToken("-ms-filter", "\"" . $token->Value . "\"", $token->MediaTypes), + ); + return $r; + } + /** + * Transforms "opacity: {value}" into browser specific counterparts. + * + * @param aCssToken $token + * @return array + */ + private static function opacity($token) + { + // Calculate the value for Internet Explorer filter statement + $ieValue = (int) ((float) $token->Value * 100); + $r = array + ( + // Internet Explorer >= 8 + new CssRulesetDeclarationToken("-ms-filter", "\"alpha(opacity=" . $ieValue . ")\"", $token->MediaTypes), + // Internet Explorer >= 4 <= 7 + new CssRulesetDeclarationToken("filter", "alpha(opacity=" . $ieValue . ")", $token->MediaTypes), + new CssRulesetDeclarationToken("zoom", "1", $token->MediaTypes) + ); + return $r; + } + /** + * Transforms "white-space: pre-wrap" into browser specific counterparts. + * + * @param aCssToken $token + * @return array + */ + private static function whiteSpace($token) + { + if (strtolower($token->Value) === "pre-wrap") + { + $r = array + ( + // Firefox < 3 + new CssRulesetDeclarationToken("white-space", "-moz-pre-wrap", $token->MediaTypes), + // Webkit + new CssRulesetDeclarationToken("white-space", "-webkit-pre-wrap", $token->MediaTypes), + // Opera >= 4 <= 6 + new CssRulesetDeclarationToken("white-space", "-pre-wrap", $token->MediaTypes), + // Opera >= 7 + new CssRulesetDeclarationToken("white-space", "-o-pre-wrap", $token->MediaTypes), + // Internet Explorer >= 5.5 + new CssRulesetDeclarationToken("word-wrap", "break-word", $token->MediaTypes) + ); + return $r; + } + else + { + return array(); + } + } +} + +/** + * This {@link aCssMinifierFilter minifier filter} will convert @keyframes at-rule block to browser specific counterparts. + * + * @package CssMin/Minifier/Filters + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertLevel3AtKeyframesMinifierFilter extends aCssMinifierFilter +{ + /** + * Implements {@link aCssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type aCssToken + * @return integer Count of added, changed or removed tokens; a return value larger than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + $transformations = array("-moz-keyframes", "-webkit-keyframes"); + for ($i = 0, $l = count($tokens); $i < $l; $i++) + { + if (get_class($tokens[$i]) === "CssAtKeyframesStartToken") + { + for ($ii = $i; $ii < $l; $ii++) + { + if (get_class($tokens[$ii]) === "CssAtKeyframesEndToken") + { + break; + } + } + if (get_class($tokens[$ii]) === "CssAtKeyframesEndToken") + { + $add = array(); + $source = array(); + for ($iii = $i; $iii <= $ii; $iii++) + { + $source[] = clone($tokens[$iii]); + } + foreach ($transformations as $transformation) + { + $t = array(); + foreach ($source as $token) + { + $t[] = clone($token); + } + $t[0]->AtRuleName = $transformation; + $add = array_merge($add, $t); + } + if (isset($this->configuration["RemoveSource"]) && $this->configuration["RemoveSource"] === true) + { + array_splice($tokens, $i, $ii - $i + 1, $add); + } + else + { + array_splice($tokens, $ii + 1, 0, $add); + } + $l = count($tokens); + $i = $ii + count($add); + $r += count($add); + } + } + } + return $r; + } +} + +/** + * This {@link aCssMinifierPlugin} will convert a color value in hsl notation to hexadecimal notation. + * + * Example: + * + * color: hsl(232,36%,48%); + * + * + * Will get converted to: + * + * color:#4e5aa7; + * + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertHslColorsMinifierPlugin extends aCssMinifierPlugin +{ + /** + * Regular expression matching the value. + * + * @var string + */ + private $reMatch = "/^hsl\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*%\s*,\s*([0-9]+)\s*%\s*\)/iS"; + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + if (stripos($token->Value, "hsl") !== false && preg_match($this->reMatch, $token->Value, $m)) + { + $token->Value = str_replace($m[0], $this->hsl2hex($m[1], $m[2], $m[3]), $token->Value); + } + return false; + } + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } + /** + * Convert a HSL value to hexadecimal notation. + * + * Based on: {@link http://www.easyrgb.com/index.php?X=MATH&H=19#text19}. + * + * @param integer $hue Hue + * @param integer $saturation Saturation + * @param integer $lightness Lightnesss + * @return string + */ + private function hsl2hex($hue, $saturation, $lightness) + { + $hue = $hue / 360; + $saturation = $saturation / 100; + $lightness = $lightness / 100; + if ($saturation == 0) + { + $red = $lightness * 255; + $green = $lightness * 255; + $blue = $lightness * 255; + } + else + { + if ($lightness < 0.5 ) + { + $v2 = $lightness * (1 + $saturation); + } + else + { + $v2 = ($lightness + $saturation) - ($saturation * $lightness); + } + $v1 = 2 * $lightness - $v2; + $red = 255 * self::hue2rgb($v1, $v2, $hue + (1 / 3)); + $green = 255 * self::hue2rgb($v1, $v2, $hue); + $blue = 255 * self::hue2rgb($v1, $v2, $hue - (1 / 3)); + } + return "#" . str_pad(dechex(round($red)), 2, "0", STR_PAD_LEFT) . str_pad(dechex(round($green)), 2, "0", STR_PAD_LEFT) . str_pad(dechex(round($blue)), 2, "0", STR_PAD_LEFT); + } + /** + * Apply hue to a rgb color value. + * + * @param integer $v1 Value 1 + * @param integer $v2 Value 2 + * @param integer $hue Hue + * @return integer + */ + private function hue2rgb($v1, $v2, $hue) + { + if ($hue < 0) + { + $hue += 1; + } + if ($hue > 1) + { + $hue -= 1; + } + if ((6 * $hue) < 1) + { + return ($v1 + ($v2 - $v1) * 6 * $hue); + } + if ((2 * $hue) < 1) + { + return ($v2); + } + if ((3 * $hue) < 2) + { + return ($v1 + ($v2 - $v1) * (( 2 / 3) - $hue) * 6); + } + return $v1; + } +} + +/** + * This {@link aCssMinifierPlugin} will convert the font-weight values normal and bold to their numeric notation. + * + * Example: + * + * font-weight: normal; + * font: bold 11px monospace; + * + * + * Will get converted to: + * + * font-weight:400; + * font:700 11px monospace; + * + * + * @package CssMin/Minifier/Pluginsn + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertFontWeightMinifierPlugin extends aCssMinifierPlugin +{ + /** + * Array of included declaration properties this plugin will process; others declaration properties will get + * ignored. + * + * @var array + */ + private $include = array + ( + "font", + "font-weight" + ); + /** + * Regular expression matching the value. + * + * @var string + */ + private $reMatch = null; + /** + * Transformation table used by the {@link CssConvertFontWeightMinifierPlugin::reReplace() replacement method}. + * + * @var array + */ + private $transformation = array + ( + "normal" => "400", + "bold" => "700" + ); + /** + * Overwrites {@link aCssMinifierPlugin::__construct()}. + * + * The constructor will create the {@link CssConvertFontWeightMinifierPlugin::$reMatch replace regular expression} + * based on the {@link CssConvertFontWeightMinifierPlugin::$transformation transformation table}. + * + * @param CssMinifier $minifier The CssMinifier object of this plugin. + * @return void + */ + public function __construct(CssMinifier $minifier) + { + $this->reMatch = "/(^|\s)+(" . implode("|", array_keys($this->transformation)). ")(\s|$)+/iS"; + parent::__construct($minifier); + } + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + if (in_array($token->Property, $this->include) && preg_match($this->reMatch, $token->Value, $m)) + { + $token->Value = preg_replace_callback($this->reMatch, array($this, 'reReplace'), $token->Value); + } + return false; + } + /** + * Callback for replacement value. + * + * @param array $match + * @return string + */ + private function reReplace($match) + { + return $match[1] . $this->transformation[strtolower($match[2])] . $match[3]; + } + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} + +/** + * This {@link aCssMinifierPlugin} will compress several unit values to their short notations. Examples: + * + * + * padding: 0.5em; + * border: 0px; + * margin: 0 0 0 0; + * + * + * Will get compressed to: + * + * + * padding:.5px; + * border:0; + * margin:0; + * + * + * -- + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssCompressUnitValuesMinifierPlugin extends aCssMinifierPlugin +{ + /** + * Regular expression used for matching and replacing unit values. + * + * @var array + */ + private $re = array + ( + "/(^| |-)0\.([0-9]+?)(0+)?(%|em|ex|px|in|cm|mm|pt|pc)/iS" => "\${1}.\${2}\${4}", + "/(^| )-?(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)/iS" => "\${1}0", + "/(^0\s0\s0\s0)|(^0\s0\s0$)|(^0\s0$)/iS" => "0" + ); + /** + * Regular expression matching the value. + * + * @var string + */ + private $reMatch = "/(^| |-)0\.([0-9]+?)(0+)?(%|em|ex|px|in|cm|mm|pt|pc)|(^| )-?(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)|(^0\s0\s0\s0$)|(^0\s0\s0$)|(^0\s0$)/iS"; + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + if (preg_match($this->reMatch, $token->Value)) + { + foreach ($this->re as $reMatch => $reReplace) + { + $token->Value = preg_replace($reMatch, $reReplace, $token->Value); + } + } + return false; + } + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} + +/** + * This {@link aCssMinifierPlugin} compress the content of expresssion() declaration values. + * + * For compression of expressions {@link https://github.com/rgrove/jsmin-php/ JSMin} will get used. JSMin have to be + * already included or loadable via {@link http://goo.gl/JrW54 PHP autoloading}. + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssCompressExpressionValuesMinifierPlugin extends aCssMinifierPlugin +{ + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + if (class_exists("JSMin") && stripos($token->Value, "expression(") !== false) + { + $value = $token->Value; + $value = substr($token->Value, stripos($token->Value, "expression(") + 10); + $value = trim(JSMin::minify($value)); + $token->Value = "expression(" . $value . ")"; + } + return false; + } + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} + +/** + * This {@link aCssMinifierPlugin} will convert hexadecimal color value with 6 chars to their 3 char hexadecimal + * notation (if possible). + * + * Example: + * + * color: #aabbcc; + * + * + * Will get converted to: + * + * color:#abc; + * + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssCompressColorValuesMinifierPlugin extends aCssMinifierPlugin +{ + /** + * Regular expression matching 6 char hexadecimal color values. + * + * @var string + */ + private $reMatch = "/\#([0-9a-f]{6})/iS"; + /** + * Implements {@link aCssMinifierPlugin::minify()}. + * + * @param aCssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(aCssToken &$token) + { + if (strpos($token->Value, "#") !== false && preg_match($this->reMatch, $token->Value, $m)) + { + $value = strtolower($m[1]); + if ($value[0] == $value[1] && $value[2] == $value[3] && $value[4] == $value[5]) + { + $token->Value = str_replace($m[0], "#" . $value[0] . $value[2] . $value[4], $token->Value); + } + } + return false; + } + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} + +/** + * This {@link aCssToken CSS token} represents a CSS comment. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssCommentToken extends aCssToken +{ + /** + * Comment as Text. + * + * @var string + */ + public $Comment = ""; + /** + * Set the properties of a comment token. + * + * @param string $comment Comment including comment delimiters + * @return void + */ + public function __construct($comment) + { + $this->Comment = $comment; + } + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return $this->Comment; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing comments. + * + * Adds a {@link CssCommentToken} to the parser if a comment was found. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssCommentParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("*", "/"); + } + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return false; + } + /** + * Stored buffer for restore. + * + * @var string + */ + private $restoreBuffer = ""; + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + if ($char === "*" && $previousChar === "/" && $state !== "T_COMMENT") + { + $this->parser->pushState("T_COMMENT"); + $this->parser->setExclusive(__CLASS__); + $this->restoreBuffer = substr($this->parser->getAndClearBuffer(), 0, -2); + } + elseif ($char === "/" && $previousChar === "*" && $state === "T_COMMENT") + { + $this->parser->popState(); + $this->parser->unsetExclusive(); + $this->parser->appendToken(new CssCommentToken("/*" . $this->parser->getAndClearBuffer())); + $this->parser->setBuffer($this->restoreBuffer); + } + else + { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the start of a @variables at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtVariablesStartToken extends aCssAtBlockStartToken +{ + /** + * Media types of the @variables at-rule block. + * + * @var array + */ + public $MediaTypes = array(); + /** + * Set the properties of a @variables at-rule token. + * + * @param array $mediaTypes Media types + * @return void + */ + public function __construct($mediaTypes = null) + { + $this->MediaTypes = $mediaTypes ? $mediaTypes : array("all"); + } + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return ""; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing @variables at-rule block with including declarations. + * + * Found @variables at-rule blocks will add a {@link CssAtVariablesStartToken} and {@link CssAtVariablesEndToken} to the + * parser; including declarations as {@link CssAtVariablesDeclarationToken}. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtVariablesParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", "{", "}", ":", ";"); + } + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_VARIABLES::PREPARE", "T_AT_VARIABLES", "T_AT_VARIABLES_DECLARATION"); + } + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of @variables at-rule block + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@variables") + { + $this->parser->pushState("T_AT_VARIABLES::PREPARE"); + $this->parser->clearBuffer(); + return $index + 10; + } + // Start of @variables declarations + elseif ($char === "{" && $state === "T_AT_VARIABLES::PREPARE") + { + $this->parser->setState("T_AT_VARIABLES"); + $mediaTypes = array_filter(array_map("trim", explode(",", $this->parser->getAndClearBuffer("{")))); + $this->parser->appendToken(new CssAtVariablesStartToken($mediaTypes)); + } + // Start of @variables declaration + if ($char === ":" && $state === "T_AT_VARIABLES") + { + $this->buffer = $this->parser->getAndClearBuffer(":"); + $this->parser->pushState("T_AT_VARIABLES_DECLARATION"); + } + // Unterminated @variables declaration + elseif ($char === ":" && $state === "T_AT_VARIABLES_DECLARATION") + { + // Ignore Internet Explorer filter declarations + if ($this->buffer === "filter") + { + return false; + } + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @variables declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_")); + } + // End of @variables declaration + elseif (($char === ";" || $char === "}") && $state === "T_AT_VARIABLES_DECLARATION") + { + $value = $this->parser->getAndClearBuffer(";}"); + if (strtolower(substr($value, -10, 10)) === "!important") + { + $value = trim(substr($value, 0, -10)); + $isImportant = true; + } + else + { + $isImportant = false; + } + $this->parser->popState(); + $this->parser->appendToken(new CssAtVariablesDeclarationToken($this->buffer, $value, $isImportant)); + $this->buffer = ""; + } + // End of @variables at-rule block + elseif ($char === "}" && $state === "T_AT_VARIABLES") + { + $this->parser->popState(); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssAtVariablesEndToken()); + } + else + { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the end of a @variables at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtVariablesEndToken extends aCssAtBlockEndToken +{ + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return ""; + } +} + +/** + * This {@link aCssToken CSS token} represents a declaration of a @variables at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtVariablesDeclarationToken extends aCssDeclarationToken +{ + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return ""; + } +} + +/** + * This {@link aCssToken CSS token} represents the start of a @page at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtPageStartToken extends aCssAtBlockStartToken +{ + /** + * Selector. + * + * @var string + */ + public $Selector = ""; + /** + * Sets the properties of the @page at-rule. + * + * @param string $selector Selector + * @return void + */ + public function __construct($selector = "") + { + $this->Selector = $selector; + } + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@page" . ($this->Selector ? " " . $this->Selector : "") . "{"; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing @page at-rule block with including declarations. + * + * Found @page at-rule blocks will add a {@link CssAtPageStartToken} and {@link CssAtPageEndToken} to the + * parser; including declarations as {@link CssAtPageDeclarationToken}. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtPageParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", "{", "}", ":", ";"); + } + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_PAGE::SELECTOR", "T_AT_PAGE", "T_AT_PAGE_DECLARATION"); + } + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of @page at-rule block + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 5)) === "@page") + { + $this->parser->pushState("T_AT_PAGE::SELECTOR"); + $this->parser->clearBuffer(); + return $index + 5; + } + // Start of @page declarations + elseif ($char === "{" && $state === "T_AT_PAGE::SELECTOR") + { + $selector = $this->parser->getAndClearBuffer("{"); + $this->parser->setState("T_AT_PAGE"); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssAtPageStartToken($selector)); + } + // Start of @page declaration + elseif ($char === ":" && $state === "T_AT_PAGE") + { + $this->parser->pushState("T_AT_PAGE_DECLARATION"); + $this->buffer = $this->parser->getAndClearBuffer(":", true); + } + // Unterminated @font-face declaration + elseif ($char === ":" && $state === "T_AT_PAGE_DECLARATION") + { + // Ignore Internet Explorer filter declarations + if ($this->buffer === "filter") + { + return false; + } + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @page declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_")); + } + // End of @page declaration + elseif (($char === ";" || $char === "}") && $state == "T_AT_PAGE_DECLARATION") + { + $value = $this->parser->getAndClearBuffer(";}"); + if (strtolower(substr($value, -10, 10)) == "!important") + { + $value = trim(substr($value, 0, -10)); + $isImportant = true; + } + else + { + $isImportant = false; + } + $this->parser->popState(); + $this->parser->appendToken(new CssAtPageDeclarationToken($this->buffer, $value, $isImportant)); + // -- + if ($char === "}") + { + $this->parser->popState(); + $this->parser->appendToken(new CssAtPageEndToken()); + } + $this->buffer = ""; + } + // End of @page at-rule block + elseif ($char === "}" && $state === "T_AT_PAGE") + { + $this->parser->popState(); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssAtPageEndToken()); + } + else + { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the end of a @page at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtPageEndToken extends aCssAtBlockEndToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents a declaration of a @page at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtPageDeclarationToken extends aCssDeclarationToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents the start of a @media at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtMediaStartToken extends aCssAtBlockStartToken +{ + /** + * Sets the properties of the @media at-rule. + * + * @param array $mediaTypes Media types + * @return void + */ + public function __construct(array $mediaTypes = array()) + { + $this->MediaTypes = $mediaTypes; + } + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@media " . implode(",", $this->MediaTypes) . "{"; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing @media at-rule block. + * + * Found @media at-rule blocks will add a {@link CssAtMediaStartToken} and {@link CssAtMediaEndToken} to the parser. + * This plugin will also set the the current media types using {@link CssParser::setMediaTypes()} and + * {@link CssParser::unsetMediaTypes()}. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtMediaParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", "{", "}"); + } + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_MEDIA::PREPARE", "T_AT_MEDIA"); + } + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 6)) === "@media") + { + $this->parser->pushState("T_AT_MEDIA::PREPARE"); + $this->parser->clearBuffer(); + return $index + 6; + } + elseif ($char === "{" && $state === "T_AT_MEDIA::PREPARE") + { + $mediaTypes = array_filter(array_map("trim", explode(",", $this->parser->getAndClearBuffer("{")))); + $this->parser->setMediaTypes($mediaTypes); + $this->parser->setState("T_AT_MEDIA"); + $this->parser->appendToken(new CssAtMediaStartToken($mediaTypes)); + } + elseif ($char === "}" && $state === "T_AT_MEDIA") + { + $this->parser->appendToken(new CssAtMediaEndToken()); + $this->parser->clearBuffer(); + $this->parser->unsetMediaTypes(); + $this->parser->popState(); + } + else + { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the end of a @media at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtMediaEndToken extends aCssAtBlockEndToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents the start of a @keyframes at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesStartToken extends aCssAtBlockStartToken +{ + /** + * Name of the at-rule. + * + * @var string + */ + public $AtRuleName = "keyframes"; + /** + * Name + * + * @var string + */ + public $Name = ""; + /** + * Sets the properties of the @page at-rule. + * + * @param string $selector Selector + * @return void + */ + public function __construct($name, $atRuleName = null) + { + $this->Name = $name; + if (!is_null($atRuleName)) + { + $this->AtRuleName = $atRuleName; + } + } + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + if ($this->AtRuleName === "-moz-keyframes") + { + return "@-moz-keyframes " . $this->Name . " {"; + } + return "@" . $this->AtRuleName . " \"" . $this->Name . "\"{"; + } +} + +/** + * This {@link aCssToken CSS token} represents the start of a ruleset of a @keyframes at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesRulesetStartToken extends aCssRulesetStartToken +{ + /** + * Array of selectors. + * + * @var array + */ + public $Selectors = array(); + /** + * Set the properties of a ruleset token. + * + * @param array $selectors Selectors of the ruleset + * @return void + */ + public function __construct(array $selectors = array()) + { + $this->Selectors = $selectors; + } + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return implode(",", $this->Selectors) . "{"; + } +} + +/** + * This {@link aCssToken CSS token} represents the end of a ruleset of a @keyframes at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesRulesetEndToken extends aCssRulesetEndToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents a ruleset declaration of a @keyframes at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesRulesetDeclarationToken extends aCssDeclarationToken +{ + +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing @keyframes at-rule blocks, rulesets and declarations. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesParserPlugin extends aCssParserPlugin +{ + /** + * @var string Keyword + */ + private $atRuleName = ""; + /** + * Selectors. + * + * @var array + */ + private $selectors = array(); + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", "{", "}", ":", ",", ";"); + } + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_KEYFRAMES::NAME", "T_AT_KEYFRAMES", "T_AT_KEYFRAMES_RULESETS", "T_AT_KEYFRAMES_RULESET", "T_AT_KEYFRAMES_RULESET_DECLARATION"); + } + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of @keyframes at-rule block + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@keyframes") + { + $this->atRuleName = "keyframes"; + $this->parser->pushState("T_AT_KEYFRAMES::NAME"); + $this->parser->clearBuffer(); + return $index + 10; + } + // Start of @keyframes at-rule block (@-moz-keyframes) + elseif ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 15)) === "@-moz-keyframes") + { + $this->atRuleName = "-moz-keyframes"; + $this->parser->pushState("T_AT_KEYFRAMES::NAME"); + $this->parser->clearBuffer(); + return $index + 15; + } + // Start of @keyframes at-rule block (@-webkit-keyframes) + elseif ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 18)) === "@-webkit-keyframes") + { + $this->atRuleName = "-webkit-keyframes"; + $this->parser->pushState("T_AT_KEYFRAMES::NAME"); + $this->parser->clearBuffer(); + return $index + 18; + } + // Start of @keyframes at-rule block (@-o-keyframes) + elseif ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 13)) === "@-o-keyframes") + { + $this->atRuleName = "-o-keyframes"; + $this->parser->pushState("T_AT_KEYFRAMES::NAME"); + $this->parser->clearBuffer(); + return $index + 13; + } + // Start of @keyframes at-rule block (@-ms-keyframes) + elseif ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 14)) === "@-ms-keyframes") + { + $this->atRuleName = "-ms-keyframes"; + $this->parser->pushState("T_AT_KEYFRAMES::NAME"); + $this->parser->clearBuffer(); + return $index + 14; + } + // Start of @keyframes rulesets + elseif ($char === "{" && $state === "T_AT_KEYFRAMES::NAME") + { + $name = $this->parser->getAndClearBuffer("{\"'"); + $this->parser->setState("T_AT_KEYFRAMES_RULESETS"); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssAtKeyframesStartToken($name, $this->atRuleName)); + } + // Start of @keyframe ruleset and selectors + if ($char === "," && $state === "T_AT_KEYFRAMES_RULESETS") + { + $this->selectors[] = $this->parser->getAndClearBuffer(",{"); + } + // Start of a @keyframes ruleset + elseif ($char === "{" && $state === "T_AT_KEYFRAMES_RULESETS") + { + if ($this->parser->getBuffer() !== "") + { + $this->selectors[] = $this->parser->getAndClearBuffer(",{"); + $this->parser->pushState("T_AT_KEYFRAMES_RULESET"); + $this->parser->appendToken(new CssAtKeyframesRulesetStartToken($this->selectors)); + $this->selectors = array(); + } + } + // Start of @keyframes ruleset declaration + elseif ($char === ":" && $state === "T_AT_KEYFRAMES_RULESET") + { + $this->parser->pushState("T_AT_KEYFRAMES_RULESET_DECLARATION"); + $this->buffer = $this->parser->getAndClearBuffer(":;", true); + } + // Unterminated @keyframes ruleset declaration + elseif ($char === ":" && $state === "T_AT_KEYFRAMES_RULESET_DECLARATION") + { + // Ignore Internet Explorer filter declarations + if ($this->buffer === "filter") + { + return false; + } + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @keyframes ruleset declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_")); + } + // End of declaration + elseif (($char === ";" || $char === "}") && $state === "T_AT_KEYFRAMES_RULESET_DECLARATION") + { + $value = $this->parser->getAndClearBuffer(";}"); + if (strtolower(substr($value, -10, 10)) === "!important") + { + $value = trim(substr($value, 0, -10)); + $isImportant = true; + } + else + { + $isImportant = false; + } + $this->parser->popState(); + $this->parser->appendToken(new CssAtKeyframesRulesetDeclarationToken($this->buffer, $value, $isImportant)); + // Declaration ends with a right curly brace; so we have to end the ruleset + if ($char === "}") + { + $this->parser->appendToken(new CssAtKeyframesRulesetEndToken()); + $this->parser->popState(); + } + $this->buffer = ""; + } + // End of @keyframes ruleset + elseif ($char === "}" && $state === "T_AT_KEYFRAMES_RULESET") + { + $this->parser->clearBuffer(); + + $this->parser->popState(); + $this->parser->appendToken(new CssAtKeyframesRulesetEndToken()); + } + // End of @keyframes rulesets + elseif ($char === "}" && $state === "T_AT_KEYFRAMES_RULESETS") + { + $this->parser->clearBuffer(); + $this->parser->popState(); + $this->parser->appendToken(new CssAtKeyframesEndToken()); + } + else + { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the end of a @keyframes at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesEndToken extends aCssAtBlockEndToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents a @import at-rule. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1.b1 (2001-02-22) + */ +class CssAtImportToken extends aCssToken +{ + /** + * Import path of the @import at-rule. + * + * @var string + */ + public $Import = ""; + /** + * Media types of the @import at-rule. + * + * @var array + */ + public $MediaTypes = array(); + /** + * Set the properties of a @import at-rule token. + * + * @param string $import Import path + * @param array $mediaTypes Media types + * @return void + */ + public function __construct($import, $mediaTypes) + { + $this->Import = $import; + $this->MediaTypes = $mediaTypes ? $mediaTypes : array(); + } + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@import \"" . $this->Import . "\"" . (count($this->MediaTypes) > 0 ? " " . implode(",", $this->MediaTypes) : ""). ";"; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing @import at-rule. + * + * If a @import at-rule was found this plugin will add a {@link CssAtImportToken} to the parser. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtImportParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", ";", ",", "\n"); + } + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_IMPORT"); + } + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 7)) === "@import") + { + $this->parser->pushState("T_AT_IMPORT"); + $this->parser->clearBuffer(); + return $index + 7; + } + elseif (($char === ";" || $char === "\n") && $state === "T_AT_IMPORT") + { + $this->buffer = $this->parser->getAndClearBuffer(";"); + $pos = false; + foreach (array(")", "\"", "'") as $needle) + { + if (($pos = strrpos($this->buffer, $needle)) !== false) + { + break; + } + } + $import = substr($this->buffer, 0, $pos + 1); + if (stripos($import, "url(") === 0) + { + $import = substr($import, 4, -1); + } + $import = trim($import, " \t\n\r\0\x0B'\""); + $mediaTypes = array_filter(array_map("trim", explode(",", trim(substr($this->buffer, $pos + 1), " \t\n\r\0\x0B{")))); + if ($pos) + { + $this->parser->appendToken(new CssAtImportToken($import, $mediaTypes)); + } + else + { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Invalid @import at-rule syntax", $this->parser->buffer)); + } + $this->parser->popState(); + } + else + { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the start of a @font-face at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtFontFaceStartToken extends aCssAtBlockStartToken +{ + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@font-face{"; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing @font-face at-rule block with including declarations. + * + * Found @font-face at-rule blocks will add a {@link CssAtFontFaceStartToken} and {@link CssAtFontFaceEndToken} to the + * parser; including declarations as {@link CssAtFontFaceDeclarationToken}. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtFontFaceParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", "{", "}", ":", ";"); + } + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_FONT_FACE::PREPARE", "T_AT_FONT_FACE", "T_AT_FONT_FACE_DECLARATION"); + } + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of @font-face at-rule block + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@font-face") + { + $this->parser->pushState("T_AT_FONT_FACE::PREPARE"); + $this->parser->clearBuffer(); + return $index + 10; + } + // Start of @font-face declarations + elseif ($char === "{" && $state === "T_AT_FONT_FACE::PREPARE") + { + $this->parser->setState("T_AT_FONT_FACE"); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssAtFontFaceStartToken()); + } + // Start of @font-face declaration + elseif ($char === ":" && $state === "T_AT_FONT_FACE") + { + $this->parser->pushState("T_AT_FONT_FACE_DECLARATION"); + $this->buffer = $this->parser->getAndClearBuffer(":", true); + } + // Unterminated @font-face declaration + elseif ($char === ":" && $state === "T_AT_FONT_FACE_DECLARATION") + { + // Ignore Internet Explorer filter declarations + if ($this->buffer === "filter") + { + return false; + } + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @font-face declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_")); + } + // End of @font-face declaration + elseif (($char === ";" || $char === "}") && $state === "T_AT_FONT_FACE_DECLARATION") + { + $value = $this->parser->getAndClearBuffer(";}"); + if (strtolower(substr($value, -10, 10)) === "!important") + { + $value = trim(substr($value, 0, -10)); + $isImportant = true; + } + else + { + $isImportant = false; + } + $this->parser->popState(); + $this->parser->appendToken(new CssAtFontFaceDeclarationToken($this->buffer, $value, $isImportant)); + $this->buffer = ""; + // -- + if ($char === "}") + { + $this->parser->appendToken(new CssAtFontFaceEndToken()); + $this->parser->popState(); + } + } + // End of @font-face at-rule block + elseif ($char === "}" && $state === "T_AT_FONT_FACE") + { + $this->parser->appendToken(new CssAtFontFaceEndToken()); + $this->parser->clearBuffer(); + $this->parser->popState(); + } + else + { + return false; + } + return true; + } +} + +/** + * This {@link aCssToken CSS token} represents the end of a @font-face at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtFontFaceEndToken extends aCssAtBlockEndToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents a declaration of a @font-face at-rule block. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtFontFaceDeclarationToken extends aCssDeclarationToken +{ + +} + +/** + * This {@link aCssToken CSS token} represents a @charset at-rule. + * + * @package CssMin/Tokens + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtCharsetToken extends aCssToken +{ + /** + * Charset of the @charset at-rule. + * + * @var string + */ + public $Charset = ""; + /** + * Set the properties of @charset at-rule token. + * + * @param string $charset Charset of the @charset at-rule token + * @return void + */ + public function __construct($charset) + { + $this->Charset = $charset; + } + /** + * Implements {@link aCssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@charset " . $this->Charset . ";"; + } +} + +/** + * {@link aCssParserPlugin Parser plugin} for parsing @charset at-rule. + * + * If a @charset at-rule was found this plugin will add a {@link CssAtCharsetToken} to the parser. + * + * @package CssMin/Parser/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtCharsetParserPlugin extends aCssParserPlugin +{ + /** + * Implements {@link aCssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", ";", "\n"); + } + /** + * Implements {@link aCssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_CHARSET"); + } + /** + * Implements {@link aCssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 8)) === "@charset") + { + $this->parser->pushState("T_AT_CHARSET"); + $this->parser->clearBuffer(); + return $index + 8; + } + elseif (($char === ";" || $char === "\n") && $state === "T_AT_CHARSET") + { + $charset = $this->parser->getAndClearBuffer(";"); + $this->parser->popState(); + $this->parser->appendToken(new CssAtCharsetToken($charset)); + } + else + { + return false; + } + return true; + } +} + +?> From 635aaf81d0d97f000c9d4b90fc5a3240d05cf371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Tue, 7 Oct 2014 12:16:40 +0200 Subject: [PATCH 2/2] remove demo and test files from mrclay/minify --- .gitignore | 4 +- mrclay/minify/.editorconfig | 19 - mrclay/minify/.gitignore | 7 - mrclay/minify/composer.json | 32 - mrclay/minify/min/.htaccess | 13 - mrclay/minify/min/builder/.htaccess | 4 - mrclay/minify/min/builder/_index.js | 260 -- mrclay/minify/min/builder/bm.js | 36 - mrclay/minify/min/builder/bm2.js | 15 - mrclay/minify/min/builder/index.php | 241 -- mrclay/minify/min/builder/jquery-1.6.3.min.js | 4 - mrclay/minify/min/builder/ocCheck.php | 36 - mrclay/minify/min/builder/rewriteTest.js | 1 - mrclay/minify/min/builder/test.php | 43 - mrclay/minify/min/config-test.php | 10 - mrclay/minify/min/config.php | 191 - mrclay/minify/min/groupsConfig.php | 17 - mrclay/minify/min/index.php | 86 - mrclay/minify/min/quick-test.css | 30 - mrclay/minify/min/quick-test.js | 74 - mrclay/minify/min/utils.php | 81 - mrclay/minify/min_extras/README.txt | 11 - mrclay/minify/min_extras/cli/minify.php | 82 - mrclay/minify/min_extras/cli/rewrite-uris.php | 63 - mrclay/minify/min_extras/config.php | 12 - .../min_extras/tools/minifyTextarea.php | 175 - mrclay/minify/min_extras/tools/minifyUrl.php | 164 - .../min_extras/tools/testRewriteUri.php | 58 - mrclay/minify/min_unit_tests/.htaccess | 4 - .../min_unit_tests/HTTP_ConditionalGet/2.php | 44 - .../min_unit_tests/HTTP_ConditionalGet/3.php | 40 - .../min_unit_tests/HTTP_ConditionalGet/4.php | 49 - .../min_unit_tests/HTTP_ConditionalGet/5.php | 27 - .../HTTP_ConditionalGet/_include.php | 64 - .../HTTP_ConditionalGet/index.php | 36 - .../min_unit_tests/HTTP_Encoder/green.png | Bin 202 -> 0 bytes .../min_unit_tests/HTTP_Encoder/index.php | 60 - mrclay/minify/min_unit_tests/_inc.php | 62 - .../_test_files/css/comments.css | 9 - .../_test_files/css/comments.min.css | 3 - .../min_unit_tests/_test_files/css/hacks.css | 66 - .../_test_files/css/hacks.min.css | 4 - .../_test_files/css/issue210.css | 1 - .../_test_files/css/issue210.min.css | 1 - .../_test_files/css/issue62.css | 890 ----- .../_test_files/css/issue62.min.css | 25 - .../_test_files/css/paths_prepend.css | 12 - .../_test_files/css/paths_prepend.min.css | 1 - .../_test_files/css/paths_rewrite.css | 14 - .../_test_files/css/paths_rewrite.min.css | 1 - .../min_unit_tests/_test_files/css/readme.txt | 1 - .../_test_files/css/selectors.css | 42 - .../_test_files/css/selectors.min.css | 37 - .../min_unit_tests/_test_files/css/styles.css | 33 - .../_test_files/css/styles.min.css | 3 - .../_test_files/css/subsilver.css | 434 --- .../_test_files/css/subsilver.min.css | 18 - .../_test_files/css/unusual_strings.css | 10 - .../_test_files/css/unusual_strings.min.css | 2 - .../_test_files/css/vladmirated.css | 658 ---- .../_test_files/css/vladmirated.min.css | 79 - .../_test_files/css_uriRewriter/exp.css | 17 - .../css_uriRewriter/exp_prepend.css | 17 - .../css_uriRewriter/exp_prepend2.css | 17 - .../_test_files/css_uriRewriter/in.css | 17 - .../_test_files/html/before.html | 96 - .../_test_files/html/before.min.html | 38 - .../_test_files/html/before2.html | 95 - .../_test_files/html/before2.min.html | 38 - .../_test_files/htmlHelper_groupsConfig.php | 8 - .../importProcessor/css/1/adjacent.css | 3 - .../_test_files/importProcessor/css/1/tv.css | 4 - .../importProcessor/css/adjacent.css | 4 - .../_test_files/importProcessor/css/input.css | 5 - .../importProcessor/css/output.css | 52 - .../importProcessor/lib/css/example.css | 1 - .../min_unit_tests/_test_files/js/before.js | 66 - .../_test_files/js/before.min.js | 27 - .../_test_files/js/before.min_plus.js | 22 - .../min_unit_tests/_test_files/js/condcomm.js | 14 - .../_test_files/js/condcomm.min_plus.js | 13 - .../min_unit_tests/_test_files/js/issue132.js | 7 - .../_test_files/js/issue132.min.js | 1 - .../_test_files/js/issue141.min.js | 3 - .../min_unit_tests/_test_files/js/issue144.js | 9 - .../_test_files/js/issue144.min.js | 1 - .../min_unit_tests/_test_files/js/issue256.js | 3 - .../_test_files/js/issue256.min.js | 2 - .../_test_files/js/jquery-1.2.3.js | 3408 ----------------- .../min_unit_tests/_test_files/js/regexes.js | 24 - .../_test_files/js/regexes.min.js | 3 - .../_test_files/minify/QueryString.js | 168 - .../_test_files/minify/email.js | 24 - .../_test_files/minify/issue143.js | 6 - .../_test_files/minify/issue73_1.js | 2 - .../_test_files/minify/issue73_2.js | 3 - .../_test_files/minify/issue89_1.css | 7 - .../_test_files/minify/issue89_2.css | 7 - .../_test_files/minify/issue89_out.min.css | 1 - .../_test_files/minify/lines_bugs.js | 10 - .../_test_files/minify/lines_output.js | 72 - .../_test_files/minify/minified.css | 5 - .../_test_files/minify/minified.js | 12 - .../test_HTTP_ConditionalGet.php | 135 - .../min_unit_tests/test_HTTP_Encoder.php | 314 -- mrclay/minify/min_unit_tests/test_JSMin.php | 108 - .../minify/min_unit_tests/test_JSMinPlus.php | 49 - mrclay/minify/min_unit_tests/test_Minify.php | 222 -- .../min_unit_tests/test_Minify_Build.php | 33 - .../minify/min_unit_tests/test_Minify_CSS.php | 51 - .../test_Minify_CSS_UriRewriter.php | 93 - .../min_unit_tests/test_Minify_Cache_APC.php | 31 - .../min_unit_tests/test_Minify_Cache_File.php | 50 - .../test_Minify_Cache_Memcache.php | 50 - .../test_Minify_Cache_WinCache.php | 31 - .../test_Minify_Cache_ZendPlatform.php | 31 - .../test_Minify_ClosureCompiler.php | 75 - .../test_Minify_CommentPreserver.php | 35 - .../min_unit_tests/test_Minify_HTML.php | 55 - .../test_Minify_HTML_Helper.php | 66 - .../test_Minify_ImportProcessor.php | 37 - .../test_Minify_JS_ClosureCompiler.php | 125 - .../min_unit_tests/test_Minify_Lines.php | 32 - .../min_unit_tests/test_Minify_YuiCSS.php | 56 - mrclay/minify/min_unit_tests/test_all.php | 23 - .../min_unit_tests/test_environment.php | 138 - .../min_unit_tests/test_js_in_browser.html | 4 - 127 files changed, 3 insertions(+), 10672 deletions(-) delete mode 100644 mrclay/minify/.editorconfig delete mode 100644 mrclay/minify/.gitignore delete mode 100644 mrclay/minify/composer.json delete mode 100644 mrclay/minify/min/.htaccess delete mode 100644 mrclay/minify/min/builder/.htaccess delete mode 100644 mrclay/minify/min/builder/_index.js delete mode 100644 mrclay/minify/min/builder/bm.js delete mode 100644 mrclay/minify/min/builder/bm2.js delete mode 100644 mrclay/minify/min/builder/index.php delete mode 100644 mrclay/minify/min/builder/jquery-1.6.3.min.js delete mode 100644 mrclay/minify/min/builder/ocCheck.php delete mode 100644 mrclay/minify/min/builder/rewriteTest.js delete mode 100644 mrclay/minify/min/builder/test.php delete mode 100644 mrclay/minify/min/config-test.php delete mode 100644 mrclay/minify/min/config.php delete mode 100644 mrclay/minify/min/groupsConfig.php delete mode 100644 mrclay/minify/min/index.php delete mode 100644 mrclay/minify/min/quick-test.css delete mode 100644 mrclay/minify/min/quick-test.js delete mode 100644 mrclay/minify/min/utils.php delete mode 100644 mrclay/minify/min_extras/README.txt delete mode 100755 mrclay/minify/min_extras/cli/minify.php delete mode 100755 mrclay/minify/min_extras/cli/rewrite-uris.php delete mode 100644 mrclay/minify/min_extras/config.php delete mode 100644 mrclay/minify/min_extras/tools/minifyTextarea.php delete mode 100644 mrclay/minify/min_extras/tools/minifyUrl.php delete mode 100644 mrclay/minify/min_extras/tools/testRewriteUri.php delete mode 100644 mrclay/minify/min_unit_tests/.htaccess delete mode 100644 mrclay/minify/min_unit_tests/HTTP_ConditionalGet/2.php delete mode 100644 mrclay/minify/min_unit_tests/HTTP_ConditionalGet/3.php delete mode 100644 mrclay/minify/min_unit_tests/HTTP_ConditionalGet/4.php delete mode 100644 mrclay/minify/min_unit_tests/HTTP_ConditionalGet/5.php delete mode 100644 mrclay/minify/min_unit_tests/HTTP_ConditionalGet/_include.php delete mode 100644 mrclay/minify/min_unit_tests/HTTP_ConditionalGet/index.php delete mode 100644 mrclay/minify/min_unit_tests/HTTP_Encoder/green.png delete mode 100644 mrclay/minify/min_unit_tests/HTTP_Encoder/index.php delete mode 100644 mrclay/minify/min_unit_tests/_inc.php delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/comments.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/comments.min.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/hacks.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/hacks.min.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/issue210.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/issue210.min.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/issue62.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/issue62.min.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.min.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.min.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/readme.txt delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/selectors.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/selectors.min.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/styles.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/styles.min.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/subsilver.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/subsilver.min.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.min.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/vladmirated.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css/vladmirated.min.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend2.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/in.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/html/before.html delete mode 100644 mrclay/minify/min_unit_tests/_test_files/html/before.min.html delete mode 100644 mrclay/minify/min_unit_tests/_test_files/html/before2.html delete mode 100644 mrclay/minify/min_unit_tests/_test_files/html/before2.min.html delete mode 100644 mrclay/minify/min_unit_tests/_test_files/htmlHelper_groupsConfig.php delete mode 100644 mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/adjacent.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/tv.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/importProcessor/css/adjacent.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/importProcessor/css/input.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/importProcessor/css/output.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/importProcessor/lib/css/example.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/js/before.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/js/before.min.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/js/before.min_plus.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/js/condcomm.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/js/condcomm.min_plus.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/js/issue132.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/js/issue132.min.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/js/issue141.min.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/js/issue144.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/js/issue144.min.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/js/issue256.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/js/issue256.min.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/js/jquery-1.2.3.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/js/regexes.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/js/regexes.min.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/QueryString.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/email.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/issue143.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/issue73_1.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/issue73_2.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/issue89_1.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/issue89_2.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/issue89_out.min.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/lines_bugs.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/lines_output.js delete mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/minified.css delete mode 100644 mrclay/minify/min_unit_tests/_test_files/minify/minified.js delete mode 100644 mrclay/minify/min_unit_tests/test_HTTP_ConditionalGet.php delete mode 100644 mrclay/minify/min_unit_tests/test_HTTP_Encoder.php delete mode 100644 mrclay/minify/min_unit_tests/test_JSMin.php delete mode 100644 mrclay/minify/min_unit_tests/test_JSMinPlus.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_Build.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_CSS.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_CSS_UriRewriter.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_Cache_APC.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_Cache_File.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_Cache_Memcache.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_Cache_WinCache.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_Cache_ZendPlatform.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_ClosureCompiler.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_CommentPreserver.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_HTML.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_HTML_Helper.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_ImportProcessor.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_JS_ClosureCompiler.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_Lines.php delete mode 100644 mrclay/minify/min_unit_tests/test_Minify_YuiCSS.php delete mode 100644 mrclay/minify/min_unit_tests/test_all.php delete mode 100644 mrclay/minify/min_unit_tests/test_environment.php delete mode 100644 mrclay/minify/min_unit_tests/test_js_in_browser.html diff --git a/.gitignore b/.gitignore index 4faa9e52b5f8..2f114bc3956f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ bin # ignore demo files james-heinrich/getid3/demos james-heinrich/getid3/helperapps - +mrclay/minify/min_unit_tests +mrclay/minify/min_extras +mrclay/minify/min/builder diff --git a/mrclay/minify/.editorconfig b/mrclay/minify/.editorconfig deleted file mode 100644 index 09c610724ebe..000000000000 --- a/mrclay/minify/.editorconfig +++ /dev/null @@ -1,19 +0,0 @@ -# top-most EditorConfig file -root = true - -[*] -charset = utf-8 -end_of_line = lf - -; temporary -trim_trailing_whitespace = false - -[*.php] -indent_style = space -indent_size = 4 -insert_final_newline = true - -[vendor/**] -; Use editor default (possible autodetection). -indent_style = -indent_size = diff --git a/mrclay/minify/.gitignore b/mrclay/minify/.gitignore deleted file mode 100644 index 76383dada768..000000000000 --- a/mrclay/minify/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ - -# / -/test -/docs -.idea/ -.DS_Store -vendor diff --git a/mrclay/minify/composer.json b/mrclay/minify/composer.json deleted file mode 100644 index bb6b8702a3fb..000000000000 --- a/mrclay/minify/composer.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "mrclay/minify", - "type": "library", - "description": "Minify is a PHP5 app that helps you follow several rules for client-side performance. It combines multiple CSS or Javascript files, removes unnecessary whitespace and comments, and serves them with gzip encoding and optimal client-side cache headers", - "homepage": "http://code.google.com/p/minify/", - "license": "BSD-3-Clause", - "authors": [ - { - "name": "Stephen Clay", - "email": "steve@mrclay.org", - "role": "Developer" - } - ], - "support": { - "email": "minify@googlegroups.com", - "issues": "http://code.google.com/p/minify/issues/list", - "wiki": "http://code.google.com/p/minify/w/list" - }, - "autoload": { - "classmap": ["min/lib/"] - }, - "require": { - "php": ">=5.2.1", - "ext-pcre": "*" - }, - "require-dev": { - "tubalmartin/cssmin": "~2.4.8" - }, - "suggest": { - "tubalmartin/cssmin": "Support minify with CSSMin (YUI PHP port)" - } -} diff --git a/mrclay/minify/min/.htaccess b/mrclay/minify/min/.htaccess deleted file mode 100644 index 06c1161ef37b..000000000000 --- a/mrclay/minify/min/.htaccess +++ /dev/null @@ -1,13 +0,0 @@ - -RewriteEngine on - -# You may need RewriteBase on some servers -#RewriteBase /min - -# rewrite URLs like "/min/f=..." to "/min/?f=..." -RewriteRule ^([bfg]=.*) index.php?$1 [L,NE] - - -# In case AddOutputFilterByType has been added -SetEnv no-gzip - diff --git a/mrclay/minify/min/builder/.htaccess b/mrclay/minify/min/builder/.htaccess deleted file mode 100644 index 53cac3b13200..000000000000 --- a/mrclay/minify/min/builder/.htaccess +++ /dev/null @@ -1,4 +0,0 @@ - -RewriteEngine on -RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] - \ No newline at end of file diff --git a/mrclay/minify/min/builder/_index.js b/mrclay/minify/min/builder/_index.js deleted file mode 100644 index de13fb389c8e..000000000000 --- a/mrclay/minify/min/builder/_index.js +++ /dev/null @@ -1,260 +0,0 @@ -/*! - * Minify URI Builder - */ -var MUB = { - _uid : 0, - _minRoot : '/min/?', - checkRewrite : function () { - var testUri = location.pathname.replace(/\/[^\/]*$/, '/rewriteTest.js').substr(1); - function fail() { - $('#minRewriteFailed')[0].className = 'topNote'; - } - $.ajax({ - url : '../f=' + testUri + '&' + (new Date()).getTime(), - success : function (data) { - if (data === '1') { - MUB._minRoot = '/min/'; - $('span.minRoot').html('/min/'); - } else - fail(); - }, - error : fail - }); - }, - /** - * Get markup for new source LI element - */ - newLi : function () { - return '
  • http://' + location.host + '/' + - ' ' + - '
  • '; - }, - /** - * Add new empty source LI and attach handlers to buttons - */ - addLi : function () { - $('#sources').append(MUB.newLi()); - var li = $('#li' + MUB._uid)[0]; - $('button[title=Remove]', li).click(function () { - $('#results').addClass('hide'); - var hadValue = !!$('input', li)[0].value; - $(li).remove(); - }); - $('button[title$=Earlier]', li).click(function () { - $(li).prev('li').find('input').each(function () { - $('#results').addClass('hide'); - // this = previous li input - var tmp = this.value; - this.value = $('input', li).val(); - $('input', li).val(tmp); - MUB.updateAllTestLinks(); - }); - }); - $('button[title$=Later]', li).click(function () { - $(li).next('li').find('input').each(function () { - $('#results').addClass('hide'); - // this = next li input - var tmp = this.value; - this.value = $('input', li).val(); - $('input', li).val(tmp); - MUB.updateAllTestLinks(); - }); - }); - ++MUB._uid; - }, - /** - * In the context of a source LI element, this will analyze the URI in - * the INPUT and check the URL on the site. - */ - liUpdateTestLink : function () { // call in context of li element - if (! $('input', this)[0].value) - return; - var li = this; - $('span', this).html(''); - var url = location.protocol + '//' + location.host + '/' + - $('input', this)[0].value.replace(/^\//, ''); - $.ajax({ - url : url, - complete : function (xhr, stat) { - if ('success' === stat) - $('span', li).html(''); - else { - $('span', li).html('') - .find('button').click(function () { - MUB.liUpdateTestLink.call(li); - }); - } - }, - dataType : 'text' - }); - }, - /** - * Check all source URLs - */ - updateAllTestLinks : function () { - $('#sources li').each(MUB.liUpdateTestLink); - }, - /** - * In a given array of strings, find the character they all have at - * a particular index - * @param Array arr array of strings - * @param Number pos index to check - * @return mixed a common char or '' if any do not match - */ - getCommonCharAtPos : function (arr, pos) { - var i, - l = arr.length, - c = arr[0].charAt(pos); - if (c === '' || l === 1) - return c; - for (i = 1; i < l; ++i) - if (arr[i].charAt(pos) !== c) - return ''; - return c; - }, - /** - * Get the shortest URI to minify the set of source files - * @param Array sources URIs - */ - getBestUri : function (sources) { - var pos = 0, - base = '', - c; - while (true) { - c = MUB.getCommonCharAtPos(sources, pos); - if (c === '') - break; - else - base += c; - ++pos; - } - base = base.replace(/[^\/]+$/, ''); - var uri = MUB._minRoot + 'f=' + sources.join(','); - if (base.charAt(base.length - 1) === '/') { - // we have a base dir! - var basedSources = sources, - i, - l = sources.length; - for (i = 0; i < l; ++i) { - basedSources[i] = sources[i].substr(base.length); - } - base = base.substr(0, base.length - 1); - var bUri = MUB._minRoot + 'b=' + base + '&f=' + basedSources.join(','); - //window.console && console.log([uri, bUri]); - uri = uri.length < bUri.length ? uri : bUri; - } - return uri; - }, - /** - * Create the Minify URI for the sources - */ - update : function () { - MUB.updateAllTestLinks(); - var sources = [], - ext = false, - fail = false, - markup; - $('#sources input').each(function () { - var m, val; - if (! fail && this.value && (m = this.value.match(/\.(css|js)$/))) { - var thisExt = m[1]; - if (ext === false) - ext = thisExt; - else if (thisExt !== ext) { - fail = true; - return alert('extensions must match!'); - } - this.value = this.value.replace(/^\//, ''); - if (-1 !== $.inArray(this.value, sources)) { - fail = true; - return alert('duplicate file!'); - } - sources.push(this.value); - } - }); - if (fail || ! sources.length) - return; - $('#groupConfig').val(" 'keyName' => array('//" + sources.join("', '//") + "'),"); - var uri = MUB.getBestUri(sources), - uriH = uri.replace(//, '>').replace(/&/, '&'); - $('#uriA').html(uriH)[0].href = uri; - if (ext === 'js') { - markup = ''; - } else { - markup = ''; - } - $('#uriHtml').val(markup); - $('#results').removeClass('hide'); - }, - /** - * Handler for the "Add file +" button - */ - addButtonClick : function () { - $('#results').addClass('hide'); - MUB.addLi(); - MUB.updateAllTestLinks(); - $('#update').removeClass('hide').click(MUB.update); - $('#sources li:last input')[0].focus(); - }, - /** - * Runs on DOMready - */ - init : function () { - $('#jsDidntLoad').remove(); - $('#app').removeClass('hide'); - $('#sources').html(''); - $('#add button').click(MUB.addButtonClick); - // make easier to copy text out of - $('#uriHtml, #groupConfig, #symlinkOpt').click(function () { - this.select(); - }).focus(function () { - this.select(); - }); - $('a.ext').attr({target:'_blank'}); - if (location.hash) { - // make links out of URIs from bookmarklet - $('#getBm').addClass('hide'); - var i = 0, found = location.hash.substr(1).split(','), l = found.length; - $('#bmUris').html('

    Found by bookmarklet: /

    '); - var $p = $('#bmUris p'); - for (; i < l; i++) { - $p.append($('').text(found[i])[0]); - if (i < (l - 1)) { - $p.append(', /'); - } - } - $('#bmUris a').click(function () { - MUB.addButtonClick(); - $('#sources li:last input').val(this.innerHTML); - MUB.liUpdateTestLink.call($('#sources li:last')[0]); - $('#results').addClass('hide'); - return false; - }).attr({title:'Add file +'}); - } else { - // setup bookmarklet 1 - $.ajax({ - url : '../?f=' + location.pathname.replace(/\/[^\/]*$/, '/bm.js').substr(1), - success : function (code) { - $('#bm')[0].href = code - .replace('%BUILDER_URL%', location.href) - .replace(/\n/g, ' '); - }, - dataType : 'text' - }); - if ($.browser.msie) { - $('#getBm p:last').append(' Sorry, not supported in MSIE!'); - } - MUB.addButtonClick(); - } - // setup bookmarklet 2 - $.ajax({ - url : '../?f=' + location.pathname.replace(/\/[^\/]*$/, '/bm2.js').substr(1), - success : function (code) { - $('#bm2')[0].href = code.replace(/\n/g, ' '); - }, - dataType : 'text' - }); - MUB.checkRewrite(); - } -}; -$(MUB.init); diff --git a/mrclay/minify/min/builder/bm.js b/mrclay/minify/min/builder/bm.js deleted file mode 100644 index 10d19438143c..000000000000 --- a/mrclay/minify/min/builder/bm.js +++ /dev/null @@ -1,36 +0,0 @@ -javascript:(function() { - var d = document - ,uris = [] - ,i = 0 - ,o - ,home = (location + '').split('/').splice(0, 3).join('/') + '/'; - function add(uri) { - return (0 === uri.indexOf(home)) - && (!/[\?&]/.test(uri)) - && uris.push(escape(uri.substr(home.length))); - }; - function sheet(ss) { - // we must check the domain with add() before accessing ss.cssRules - // otherwise a security exception will be thrown - if (ss.href && add(ss.href) && ss.cssRules) { - var i = 0, r; - while (r = ss.cssRules[i++]) - r.styleSheet && sheet(r.styleSheet); - } - }; - while (o = d.getElementsByTagName('script')[i++]) - o.src && !(o.type && /vbs/i.test(o.type)) && add(o.src); - i = 0; - while (o = d.styleSheets[i++]) - /* http://www.w3.org/TR/DOM-Level-2-Style/stylesheets.html#StyleSheets-DocumentStyle-styleSheets - document.styleSheet is a list property where [0] accesses the 1st element and - [outOfRange] returns null. In IE, styleSheets is a function, and also throws an - exception when you check the out of bounds index. (sigh) */ - sheet(o); - if (uris.length) - window.open('%BUILDER_URL%#' + uris.join(',')); - else - alert('No js/css files found with URLs within "' - + home.split('/')[2] - + '".\n(This tool is limited to URLs with the same domain.)'); -})(); \ No newline at end of file diff --git a/mrclay/minify/min/builder/bm2.js b/mrclay/minify/min/builder/bm2.js deleted file mode 100644 index 6b558ce0c1bb..000000000000 --- a/mrclay/minify/min/builder/bm2.js +++ /dev/null @@ -1,15 +0,0 @@ -javascript:(function(){ - var d = document - ,c = d.cookie - ,m = c.match(/\bminifyDebug=([^; ]+)/) - ,v = m ? decodeURIComponent(m[1]) : '' - ,p = prompt('Debug Minify URIs on ' + location.hostname + ' which contain:' - + '\n(empty for none, space = OR, * = any string, ? = any char)', v) - ; - if (p === null) return; - p = p.replace(/^\s+|\s+$/, ''); - v = (p === '') - ? 'minifyDebug=; expires=Fri, 27 Jul 2001 02:47:11 UTC; path=/' - : 'minifyDebug=' + encodeURIComponent(p) + '; path=/'; - d.cookie = v; -})(); \ No newline at end of file diff --git a/mrclay/minify/min/builder/index.php b/mrclay/minify/min/builder/index.php deleted file mode 100644 index 78a533ba1801..000000000000 --- a/mrclay/minify/min/builder/index.php +++ /dev/null @@ -1,241 +0,0 @@ - $min_builderPassword)); -} - -$cachePathCode = ''; -if (! isset($min_cachePath) && ! function_exists('sys_get_temp_dir')) { - $detectedTmp = Minify_Cache_File::tmp(); - $cachePathCode = "\$min_cachePath = " . var_export($detectedTmp, 1) . ';'; -} - -ob_start(); -?> - -Minify URI Builder - - - - - -
    Note: It looks like you're running Minify in a user - directory. You may need the following option in /min/config.php to have URIs - correctly rewritten in CSS output: -
    -
    - - -

    Uh Oh. Minify was unable to - serve Javascript for this app. To troubleshoot this, - enable FirePHP debugging - and request the Minify URL directly. Hopefully the - FirePHP console will report the cause of the error. -

    - - -

    Note: was discovered as a usable temp directory.
    To - slightly improve performance you can hardcode this in /min/config.php: -

    - - -

    Note: Your webserver does not seem to - support mod_rewrite (used in /min/.htaccess). Your Minify URIs will contain "?", which -may reduce the benefit of proxy cache servers.

    - -

    Minify URI Builder

    - - - -
    - -

    Create a list of Javascript or CSS files (or 1 is fine) you'd like to combine -and click [Update].

    - -
    -
    - -
    - -

    - -
    - -

    Minify URI

    -

    Place this URI in your HTML to serve the files above combined, minified, compressed and -with cache headers.

    - - - -
    URI/min (opens in new window)
    HTML
    - -

    How to serve these files as a group

    -

    For the best performance you can serve these files as a pre-defined group with a URI -like: /min/?g=keyName

    -

    To do this, add a line like this to /min/groupsConfig.php:

    - -
    return array(
    -    ... your existing groups here ...
    -
    -);
    - -

    Make sure to replace keyName with a unique key for this group.

    -
    - -
    -

    Find URIs on a Page

    -

    You can use the bookmarklet below to fetch all CSS & Javascript URIs from a page -on your site. When you active it, this page will open in a new window with a list of -available URIs to add.

    - -

    Create Minify URIs (right-click, add to bookmarks)

    -
    - -

    Combining CSS files that contain @import

    -

    If your CSS files contain @import declarations, Minify will not -remove them. Therefore, you will want to remove those that point to files already -in your list, and move any others to the top of the first file in your list -(imports below any styles will be ignored by browsers as invalid).

    -

    If you desire, you can use Minify URIs in imports and they will not be touched -by Minify. E.g. @import "/min/?g=css2";

    - -

    Debug Mode

    -

    When /min/config.php has $min_allowDebugFlag = true; - you can get debug output by appending &debug to a Minify URL, or - by sending the cookie minDebug=<match>, where <match> - should be a string in the Minify URIs you'd like to debug. This bookmarklet will allow you to - set this cookie.

    -

    Minify Debug (right-click, add to bookmarks)

    - -
    - -
    -

    Need help? Check the wiki, - or post to the discussion - list.

    -

    Powered by Minify

    - - - - - - $content - ,'id' => __FILE__ - ,'lastModifiedTime' => max( - // regenerate cache if any of these change - filemtime(__FILE__) - ,filemtime(dirname(__FILE__) . '/../config.php') - ,filemtime(dirname(__FILE__) . '/../lib/Minify.php') - ) - ,'minifyAll' => true - ,'encodeOutput' => $encodeOutput -)); diff --git a/mrclay/minify/min/builder/jquery-1.6.3.min.js b/mrclay/minify/min/builder/jquery-1.6.3.min.js deleted file mode 100644 index 89b152163b05..000000000000 --- a/mrclay/minify/min/builder/jquery-1.6.3.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.6.3 http://jquery.com/ | http://jquery.org/license */ -(function(a,b){function cu(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cr(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cq(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cp(){cn=b}function co(){setTimeout(cp,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bv(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bl(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bd,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bk(a){f.nodeName(a,"input")?bj(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bj)}function bj(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bi(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bh(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bg(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function U(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function M(a,b){return(a&&a!=="*"?a+".":"")+b.replace(y,"`").replace(z,"&")}function L(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function J(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function D(){return!0}function C(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function K(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(K,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+"").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.3",length:0,size:function(){return this.length},toArray:function(){return G.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?F.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),B.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(G.apply(this,arguments),"slice",G.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:F,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;B.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!B){B=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",C,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",C),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,"constructor")&&!E.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(x,"ms-").replace(w,y)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
    a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},m&&f.extend(p,{position:"absolute",left:"-1000px",top:"-1000px"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
    ",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
    t
    ",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i=f.expando,j=typeof c=="string",k=a.nodeType,l=k?f.cache:a,m=k?a[f.expando]:a[f.expando]&&f.expando;if((!m||e&&m&&l[m]&&!l[m][i])&&j&&d===b)return;m||(k?a[f.expando]=m=++f.uuid:m=f.expando),l[m]||(l[m]={},k||(l[m].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?l[m][i]=f.extend(l[m][i],c):l[m]=f.extend(l[m],c);g=l[m],e&&(g[i]||(g[i]={}),g=g[i]),d!==b&&(g[f.camelCase(c)]=d);if(c==="events"&&!g[c])return g[i]&&g[i].events;j?(h=g[c],h==null&&(h=g[f.camelCase(c)])):h=g;return h}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e=f.expando,g=a.nodeType,h=g?f.cache:a,i=g?a[f.expando]:f.expando;if(!h[i])return;if(b){d=c?h[i][e]:h[i];if(d){d[b]||(b=f.camelCase(b)),delete d[b];if(!l(d))return}}if(c){delete h[i][e];if(!l(h[i]))return}var j=h[i][e];f.support.deleteExpando||!h.setInterval?delete h[i]:h[i]=null,j?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=j):g&&(f.support.deleteExpando?delete a[f.expando]:a.removeAttribute?a.removeAttribute(f.expando):a[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=v:u&&(i=u)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.attr(a,b,""),a.removeAttribute(b),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(u&&f.nodeName(a,"button"))return u.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(u&&f.nodeName(a,"button"))return u.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==null?g:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabIndex=f.propHooks.tabIndex,v={get:function(a,c){var d;return f.prop(a,c)===!0||(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(u=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var w=/\.(.*)$/,x=/^(?:textarea|input|select)$/i,y=/\./g,z=/ /g,A=/[^\w\s.|`]/g,B=function(a){return a.replace(A,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=C;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=C);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),B).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},I=function(c){var d=c.target,e,g;if(!!x.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=H(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:I,beforedeactivate:I,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&I.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&I.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",H(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in G)f.event.add(this,c+".specialChange",G[c]);return x.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return x.test(this.nodeName)}},G=f.event.special.change.filters,G.focus=G.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

    ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
    ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=S.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(U(c[0])||U(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=R.call(arguments);N.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!T[a]?f.unique(e):e,(this.length>1||P.test(d))&&O.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]};be.optgroup=be.option,be.tbody=be.tfoot=be.colgroup=be.caption=be.thead,be.th=be.td,f.support.htmlSerialize||(be._default=[1,"div
    ","
    "]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!be[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bh(a,d),e=bi(a),g=bi(d);for(h=0;e[h];++h)g[h]&&bh(e[h],g[h])}if(b){bg(a,d);if(c){e=bi(a),g=bi(d);for(h=0;e[h];++h)bg(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=be[l]||be._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bn.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bm,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bm.test(g)?g.replace(bm,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bv(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bw=function(a,c){var d,e,g;c=c.replace(bo,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bx=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bp.test(d)&&bq.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bv=bw||bx,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bz=/%20/g,bA=/\[\]$/,bB=/\r?\n/g,bC=/#.*$/,bD=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bE=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bF=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bG=/^(?:GET|HEAD)$/,bH=/^\/\//,bI=/\?/,bJ=/)<[^<]*)*<\/script>/gi,bK=/^(?:select|textarea)/i,bL=/\s+/,bM=/([?&])_=[^&]*/,bN=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bO=f.fn.load,bP={},bQ={},bR,bS,bT=["*/"]+["*"];try{bR=e.href}catch(bU){bR=c.createElement("a"),bR.href="",bR=bR.href}bS=bN.exec(bR.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bO)return bO.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
    ").append(c.replace(bJ,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bK.test(this.nodeName)||bE.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bB,"\r\n")}}):{name:b.name,value:c.replace(bB,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?bX(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),bX(a,b);return a},ajaxSettings:{url:bR,isLocal:bF.test(bS[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bT},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bV(bP),ajaxTransport:bV(bQ),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?bZ(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=b$(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bD.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bC,"").replace(bH,bS[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bL),d.crossDomain==null&&(r=bN.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bS[1]&&r[2]==bS[2]&&(r[3]||(r[1]==="http:"?80:443))==(bS[3]||(bS[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bW(bP,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bG.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bI.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bM,"$1_="+x);d.url=y+(y===d.url?(bI.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bT+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bW(bQ,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){s<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bz,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cq("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
    ";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=ct.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!ct.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cu(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cu(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNaN(j)?i:j}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/mrclay/minify/min/builder/ocCheck.php b/mrclay/minify/min/builder/ocCheck.php deleted file mode 100644 index 5c40e7471c78..000000000000 --- a/mrclay/minify/min/builder/ocCheck.php +++ /dev/null @@ -1,36 +0,0 @@ - 'World!' - ,'method' => 'deflate' - )); - $he->encode(); - $he->sendAll(); - -} else { - // echo status "0" or "1" - header('Content-Type: text/plain'); - echo (int)$_oc; -} diff --git a/mrclay/minify/min/builder/rewriteTest.js b/mrclay/minify/min/builder/rewriteTest.js deleted file mode 100644 index 56a6051ca2b0..000000000000 --- a/mrclay/minify/min/builder/rewriteTest.js +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/mrclay/minify/min/builder/test.php b/mrclay/minify/min/builder/test.php deleted file mode 100644 index 7f3e04be2090..000000000000 --- a/mrclay/minify/min/builder/test.php +++ /dev/null @@ -1,43 +0,0 @@ -realpath(DOCUMENT_ROOT) failed. You may need " - . "to set \$min_documentRoot manually (hopefully realpath() is not " - . "broken in your environment).

    "; - } - if (0 !== strpos(realpath(__FILE__), realpath($_SERVER['DOCUMENT_ROOT']))) { - echo "

    DOCUMENT_ROOT doesn't contain this file. You may " - . " need to set \$min_documentRoot manually

    "; - } - if (isset($_SERVER['SUBDOMAIN_DOCUMENT_ROOT'])) { - echo "

    \$_SERVER['SUBDOMAIN_DOCUMENT_ROOT'] is set. " - . "You may need to set \$min_documentRoot to this in config.php

    "; - } - -} - -//*/ \ No newline at end of file diff --git a/mrclay/minify/min/config-test.php b/mrclay/minify/min/config-test.php deleted file mode 100644 index 7524a3d11042..000000000000 --- a/mrclay/minify/min/config-test.php +++ /dev/null @@ -1,10 +0,0 @@ - - * array('//symlink' => '/real/target/path') // unix - * array('//static' => 'D:\\staticStorage') // Windows - * - */ -$min_symlinks = array(); - - -/** - * If you upload files from Windows to a non-Windows server, Windows may report - * incorrect mtimes for the files. This may cause Minify to keep serving stale - * cache files when source file changes are made too frequently (e.g. more than - * once an hour). - * - * Immediately after modifying and uploading a file, use the touch command to - * update the mtime on the server. If the mtime jumps ahead by a number of hours, - * set this variable to that number. If the mtime moves back, this should not be - * needed. - * - * In the Windows SFTP client WinSCP, there's an option that may fix this - * issue without changing the variable below. Under login > environment, - * select the option "Adjust remote timestamp with DST". - * @link http://winscp.net/eng/docs/ui_login_environment#daylight_saving_time - */ -$min_uploaderHoursBehind = 0; - - -/** - * Path to Minify's lib folder. If you happen to move it, change - * this accordingly. - */ -$min_libPath = dirname(__FILE__) . '/lib'; - - -// try to disable output_compression (may not have an effect) -ini_set('zlib.output_compression', '0'); diff --git a/mrclay/minify/min/groupsConfig.php b/mrclay/minify/min/groupsConfig.php deleted file mode 100644 index c9007768381e..000000000000 --- a/mrclay/minify/min/groupsConfig.php +++ /dev/null @@ -1,17 +0,0 @@ - array('//js/file1.js', '//js/file2.js'), - // 'css' => array('//css/file1.css', '//css/file2.css'), -); \ No newline at end of file diff --git a/mrclay/minify/min/index.php b/mrclay/minify/min/index.php deleted file mode 100644 index a49ad0b688ef..000000000000 --- a/mrclay/minify/min/index.php +++ /dev/null @@ -1,86 +0,0 @@ - MINIFY_MIN_DIR . '/config.php', - 'test' => MINIFY_MIN_DIR . '/config-test.php', - 'groups' => MINIFY_MIN_DIR . '/groupsConfig.php' -); - -// check for custom config paths -if (!empty($min_customConfigPaths) && is_array($min_customConfigPaths)) { - $min_configPaths = array_merge($min_configPaths, $min_customConfigPaths); -} - -// load config -require $min_configPaths['base']; - -if (isset($_GET['test'])) { - include $min_configPaths['test']; -} - -require "$min_libPath/Minify/Loader.php"; -Minify_Loader::register(); - -Minify::$uploaderHoursBehind = $min_uploaderHoursBehind; -Minify::setCache( - isset($min_cachePath) ? $min_cachePath : '' - ,$min_cacheFileLocking -); - -if ($min_documentRoot) { - $_SERVER['DOCUMENT_ROOT'] = $min_documentRoot; - Minify::$isDocRootSet = true; -} - -$min_serveOptions['minifierOptions']['text/css']['symlinks'] = $min_symlinks; -// auto-add targets to allowDirs -foreach ($min_symlinks as $uri => $target) { - $min_serveOptions['minApp']['allowDirs'][] = $target; -} - -if ($min_allowDebugFlag) { - $min_serveOptions['debug'] = Minify_DebugDetector::shouldDebugRequest($_COOKIE, $_GET, $_SERVER['REQUEST_URI']); -} - -if ($min_errorLogger) { - if (true === $min_errorLogger) { - $min_errorLogger = FirePHP::getInstance(true); - } - Minify_Logger::setLogger($min_errorLogger); -} - -// check for URI versioning -if (preg_match('/&\\d/', $_SERVER['QUERY_STRING']) || isset($_GET['v'])) { - $min_serveOptions['maxAge'] = 31536000; -} - -// need groups config? -if (isset($_GET['g'])) { - // well need groups config - $min_serveOptions['minApp']['groups'] = (require $min_configPaths['groups']); -} - -// serve or redirect -if (isset($_GET['f']) || isset($_GET['g'])) { - if (! isset($min_serveController)) { - $min_serveController = new Minify_Controller_MinApp(); - } - Minify::serve($min_serveController, $min_serveOptions); - -} elseif ($min_enableBuilder) { - header('Location: builder/'); - exit; -} else { - header('Location: /'); - exit; -} diff --git a/mrclay/minify/min/quick-test.css b/mrclay/minify/min/quick-test.css deleted file mode 100644 index 2d9e402bfaa6..000000000000 --- a/mrclay/minify/min/quick-test.css +++ /dev/null @@ -1,30 +0,0 @@ -/*! This file exists only for testing a Minify installation. It's content is not used. - * - * http://example.org/min/f=min/quick-test.css - */ - -@import url( more.css ); - - body, td, th { - font-family: Verdana , "Bitstream Vera Sans" , Arial Narrow, sans-serif ; - - font-size : 12px; -} - -.nav { - margin-left: 20%; -} -#main-nav { - background-color: red; - border: 1px solid #00ff77; -} - -div#content -h1 + p { - padding-top: 0; - margin-top: 0; -} - -@media all and (min-width: 640px) { - #media-queries-1 { background-color: #0f0; } -} diff --git a/mrclay/minify/min/quick-test.js b/mrclay/minify/min/quick-test.js deleted file mode 100644 index eceb3584ffb0..000000000000 --- a/mrclay/minify/min/quick-test.js +++ /dev/null @@ -1,74 +0,0 @@ -/*! This file exists only for testing a Minify installation. It's content is not used. - * - * http://example.org/min/f=min/quick-test.js - */ - -/* Finds the lowest common multiple of two numbers */ -function LCMCalculator(x, y) { // constructor function - var checkInt = function (x) { // inner function - if (x % 1 !== 0) { - throw new TypeError(x + " is not an integer"); // throw an exception - } - return x; - }; - this.a = checkInt(x); - // ^ semicolons are optional - this.b = checkInt(y); -} -// The prototype of object instances created by a constructor is -// that constructor's "prototype" property. -LCMCalculator.prototype = { // object literal - constructor: LCMCalculator, // when reassigning a prototype, set the constructor property appropriately - gcd: function () { // method that calculates the greatest common divisor - // Euclidean algorithm: - var a = Math.abs(this.a), b = Math.abs(this.b), t; - if (a < b) { - // swap variables - t = b; - b = a; - a = t; - } - while (b !== 0) { - t = b; - b = a % b; - a = t; - } - // Only need to calculate GCD once, so "redefine" this method. - // (Actually not redefinition - it's defined on the instance itself, - // so that this.gcd refers to this "redefinition" instead of LCMCalculator.prototype.gcd.) - // Also, 'gcd' === "gcd", this['gcd'] === this.gcd - this['gcd'] = function () { - return a; - }; - return a; - }, - // Object property names can be specified by strings delimited by double (") or single (') quotes. - "lcm" : function () { - // Variable names don't collide with object properties, e.g. |lcm| is not |this.lcm|. - // not using |this.a * this.b| to avoid FP precision issues - var lcm = this.a / this.gcd() * this.b; - // Only need to calculate lcm once, so "redefine" this method. - this.lcm = function () { - return lcm; - }; - return lcm; - }, - toString: function () { - return "LCMCalculator: a = " + this.a + ", b = " + this.b; - } -}; - -//define generic output function; this implementation only works for web browsers -function output(x) { - document.write(x + "
    "); -} - -// Note: Array's map() and forEach() are defined in JavaScript 1.6. -// They are used here to demonstrate JavaScript's inherent functional nature. -[[25, 55], [21, 56], [22, 58], [28, 56]].map(function (pair) { // array literal + mapping function - return new LCMCalculator(pair[0], pair[1]); -}).sort(function (a, b) { // sort with this comparative function - return a.lcm() - b.lcm(); -}).forEach(function (obj) { - output(obj + ", gcd = " + obj.gcd() + ", lcm = " + obj.lcm()); -}); \ No newline at end of file diff --git a/mrclay/minify/min/utils.php b/mrclay/minify/min/utils.php deleted file mode 100644 index 7cf930ac9012..000000000000 --- a/mrclay/minify/min/utils.php +++ /dev/null @@ -1,81 +0,0 @@ - - * - * - * - * - * - * @param mixed $keyOrFiles a group key or array of file paths/URIs - * @param array $opts options: - * 'farExpires' : (default true) append a modified timestamp for cache revving - * 'debug' : (default false) append debug flag - * 'charset' : (default 'UTF-8') for htmlspecialchars - * 'minAppUri' : (default '/min') URI of min directory - * 'rewriteWorks' : (default true) does mod_rewrite work in min app? - * 'groupsConfigFile' : specify if different - * @return string - */ -function Minify_getUri($keyOrFiles, $opts = array()) -{ - return Minify_HTML_Helper::getUri($keyOrFiles, $opts); -} - - -/** - * Get the last modification time of several source js/css files. If you're - * caching the output of Minify_getUri(), you might want to know if one of the - * dependent source files has changed so you can update the HTML. - * - * Since this makes a bunch of stat() calls, you might not want to check this - * on every request. - * - * @param array $keysAndFiles group keys and/or file paths/URIs. - * @return int latest modification time of all given keys/files - */ -function Minify_mtime($keysAndFiles, $groupsConfigFile = null) -{ - $gc = null; - if (! $groupsConfigFile) { - $groupsConfigFile = dirname(__FILE__) . '/groupsConfig.php'; - } - $sources = array(); - foreach ($keysAndFiles as $keyOrFile) { - if (is_object($keyOrFile) - || 0 === strpos($keyOrFile, '/') - || 1 === strpos($keyOrFile, ':\\')) { - // a file/source obj - $sources[] = $keyOrFile; - } else { - if (! $gc) { - $gc = (require $groupsConfigFile); - } - foreach ($gc[$keyOrFile] as $source) { - $sources[] = $source; - } - } - } - return Minify_HTML_Helper::getLastModified($sources); -} diff --git a/mrclay/minify/min_extras/README.txt b/mrclay/minify/min_extras/README.txt deleted file mode 100644 index 1fef8a8bd190..000000000000 --- a/mrclay/minify/min_extras/README.txt +++ /dev/null @@ -1,11 +0,0 @@ -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -DO NOT leave this directory on a site in production. Some scripts within may be -resource intensive and some allow file uploads. -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -This directory contains testing scripts and a few example applications built -with the Minify library classes. - -tools/ - Two utility web apps that upload a file, alter it, and send it back to the - user. One applies HTTP encoding, the other minifies CSS/JS/HTML. diff --git a/mrclay/minify/min_extras/cli/minify.php b/mrclay/minify/min_extras/cli/minify.php deleted file mode 100755 index e0c4b15c8dff..000000000000 --- a/mrclay/minify/min_extras/cli/minify.php +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env php -addOptionalArg('d')->assertDir()->setDescription('Your webserver\'s DOCUMENT_ROOT: Relative paths will be rewritten relative to this path. This is required if you\'re passing in CSS.'); - -$cli->addOptionalArg('o')->useAsOutfile()->setDescription('Outfile: If given, output will be placed in this file.'); - -$cli->addOptionalArg('t')->mustHaveValue()->setDescription('Type: must be "css", "js", or "html". This must be provided if passing content via STDIN.'); - -if (! $cli->validate()) { - if ($cli->isHelpRequest) { - echo "The Minify CLI tool!\n\n"; - } - echo "USAGE: ./minify.php [-t TYPE] [-d DOC_ROOT] [-o OUTFILE] file ...\n"; - if ($cli->isHelpRequest) { - echo $cli->getArgumentsListing(); - } - echo "EXAMPLE: ./minify.php ../../min_unit_tests/_test_files/js/*.js\n"; - echo "EXAMPLE: ./minify.php -d../.. ../../min_unit_tests/_test_files/css/*.css\n"; - echo "EXAMPLE: echo \"var js = 'Awesome' && /cool/;\" | ./minify.php -t js\n"; - echo "EXAMPLE: echo \"sel > ector { prop: 'value '; }\" | ./minify.php -t css\n"; - echo "\n"; - exit(0); -} - -$outfile = $cli->values['o']; -$docRoot = $cli->values['d']; -$type = $cli->values['t']; - -if (is_string($type)) { - if (! in_array($type, array('js', 'css', 'html'))) { - echo "Type argument invalid\n"; - exit(1); - } - $type = constant('Minify::TYPE_' . strtoupper($type)); -} - -$paths = $cli->getPathArgs(); -$sources = array(); - -if ($paths) { - foreach ($paths as $path) { - if (is_file($path)) { - $sources[] = new Minify_Source(array( - 'filepath' => $path, - 'minifyOptions' => array('docRoot' => $docRoot), - )); - } else { - $sources[] = new Minify_Source(array( - 'id' => $path, - 'content' => "/*** $path not found ***/\n", - 'minifier' => '', - )); - } - } -} else { - // not paths input, expect STDIN - if (! $type) { - echo "Type must be specified to use STDIN\n"; - exit(1); - } - $in = $cli->openInput(); - $sources[] = new Minify_Source(array( - 'id' => 'one', - 'content' => stream_get_contents($in), - 'contentType' => $type, - )); - $cli->closeInput(); -} - -$combined = Minify::combine($sources) . "\n"; - -$fp = $cli->openOutput(); -fwrite($fp, $combined); -$cli->closeOutput(); diff --git a/mrclay/minify/min_extras/cli/rewrite-uris.php b/mrclay/minify/min_extras/cli/rewrite-uris.php deleted file mode 100755 index e0cbfa500a75..000000000000 --- a/mrclay/minify/min_extras/cli/rewrite-uris.php +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/php -addRequiredArg('d')->assertDir()->setDescription('Your webserver\'s DOCUMENT_ROOT: Relative paths will be rewritten relative to this path.'); - -$cli->addOptionalArg('o')->useAsOutfile()->setDescription('Outfile: If given, output will be placed in this file.'); - -$cli->addOptionalArg('t')->setDescription('Test run: Return output followed by rewriting algorithm.'); - -if (! $cli->validate()) { - echo "USAGE: ./rewrite-uris.php [-t] -d DOC_ROOT [-o OUTFILE] file ...\n"; - if ($cli->isHelpRequest) { - echo $cli->getArgumentsListing(); - } - echo "EXAMPLE: ./rewrite-uris.php -v -d../.. ../../min_unit_tests/_test_files/css/paths_rewrite.css ../../min_unit_tests/_test_files/css/comments.css - \n"; - exit(0); -} - -$outfile = $cli->values['o']; -$testRun = $cli->values['t']; -$docRoot = $cli->values['d']; - -$pathRewriter = function($css, $options) { - return Minify_CSS_UriRewriter::rewrite($css, $options['currentDir'], $options['docRoot']); -}; - -$paths = $cli->getPathArgs(); - -$sources = array(); -foreach ($paths as $path) { - if (is_file($path)) { - $sources[] = new Minify_Source(array( - 'filepath' => $path, - 'minifier' => $pathRewriter, - 'minifyOptions' => array('docRoot' => $docRoot), - )); - } else { - $sources[] = new Minify_Source(array( - 'id' => $path, - 'content' => "/*** $path not found ***/\n", - 'minifier' => '', - )); - } -} -$combined = Minify::combine($sources) . "\n"; - -if ($testRun) { - echo $combined; - echo Minify_CSS_UriRewriter::$debugText . "\n"; -} else { - $fp = $cli->openOutput(); - fwrite($fp, $combined); - $cli->closeOutput(); -} - diff --git a/mrclay/minify/min_extras/config.php b/mrclay/minify/min_extras/config.php deleted file mode 100644 index b44bceb8ac38..000000000000 --- a/mrclay/minify/min_extras/config.php +++ /dev/null @@ -1,12 +0,0 @@ -]*>)@i' - ,'$1' - ,$textIn - ); - } - - $sourceSpec['content'] = $textIn; - $sourceSpec['id'] = 'foo'; - if (isset($_POST['minJs'])) { - $sourceSpec['minifyOptions']['jsMinifier'] = array('JSMin', 'minify'); - } - if (isset($_POST['minCss'])) { - $sourceSpec['minifyOptions']['cssMinifier'] = array('Minify_CSS', 'minify'); - } - $source = new Minify_Source($sourceSpec); - Minify_Logger::setLogger(FirePHP::getInstance(true)); - try { - Minify::serve('Files', array( - 'files' => $source - ,'contentType' => Minify::TYPE_HTML - )); - } catch (Exception $e) { - echo h($e->getMessage()); - } - exit; -} - -$tpl = array(); -$tpl['classes'] = array('Minify_HTML', 'JSMin', 'Minify_CSS', 'Minify_CSSmin', 'JSMinPlus'); - -if (isset($_POST['method']) && in_array($_POST['method'], $tpl['classes'])) { - - $args = array($textIn); - if ($_POST['method'] === 'Minify_HTML') { - $args[] = array( - 'cssMinifier' => array('Minify_CSS', 'minify') - ,'jsMinifier' => array('JSMin', 'minify') - ); - } - $func = array($_POST['method'], 'minify'); - $tpl['inBytes'] = strlen($textIn); - $startTime = microtime(true); - try { - $tpl['output'] = call_user_func_array($func, $args); - } catch (Exception $e) { - $tpl['exceptionMsg'] = getExceptionMsg($e, $textIn); - $tpl['output'] = $textIn; - sendPage($tpl); - } - $tpl['time'] = microtime(true) - $startTime; - $tpl['outBytes'] = strlen($tpl['output']); -} - -sendPage($tpl); - - -/** - * @param Exception $e - * @param string $input - * @return string HTML - */ -function getExceptionMsg(Exception $e, $input) { - $msg = "

    " . h($e->getMessage()) . "

    "; - if (0 === strpos(get_class($e), 'JSMin_Unterminated') - && preg_match('~byte (\d+)~', $e->getMessage(), $m)) { - $msg .= "
    ";
    -        if ($m[1] > 200) {
    -            $msg .= h(substr($input, ($m[1] - 200), 200));
    -        } else {
    -            $msg .= h(substr($input, 0, $m[1]));
    -        }
    -        $highlighted = isset($input[$m[1]]) ? h($input[$m[1]]) : '␄';
    -        if ($highlighted === "\n") {
    -            $highlighted = "⏎\n";
    -        }
    -        $msg .= "$highlighted";
    -        $msg .= h(substr($input, $m[1] + 1, 200)) . "
    "; - } - return $msg; -} - -/** - * Draw page - * - * @param array $vars - */ -function sendPage($vars) { - header('Content-Type: text/html; charset=utf-8'); -?> -minifyTextarea - - Bytes in{$vars['inBytes']} (after line endings normalized to \\n) - Bytes out{$vars['outBytes']} (reduced " . round(100 - (100 * $vars['outBytes'] / $vars['inBytes'])) . "%) - Time (s)" . round($vars['time'], 5) . " - - "; -} -?> -
    -

    -

    Minify with: - - - -

    -

    ...or this HTML to the browser. Also minify: - : -. - -

    -
    - - - $type - ,'sent' => $sentType - ,'charset' => $charset - ); -} - -if (isset($_POST['url'])) { - - require '../config.php'; - - $url = trim(getPost('url')); - $ua = trim(getPost('ua')); - $cook = trim(getPost('cook')); - - if (! preg_match('@^https?://@', $url)) { - die('HTTP(s) only.'); - } - - $httpOpts = array( - 'max_redirects' => 0 - ,'timeout' => 3 - ); - if ($ua !== '') { - $httpOpts['user_agent'] = $ua; - } - if ($cook !== '') { - $httpOpts['header'] = "Cookie: {$cook}\r\n"; - } - $ctx = stream_context_create(array( - 'http' => $httpOpts - )); - - // fetch - if (! ($fp = @fopen($url, 'r', false, $ctx))) { - die('Couldn\'t open URL.'); - } - $meta = stream_get_meta_data($fp); - $content = stream_get_contents($fp); - fclose($fp); - - // get type info - $type = sniffType($meta['wrapper_data']); - if (! $type['minify']) { - die('Unrecognized Content-Type: ' . $type['sent']); - } - - if ($type['minify'] === 'text/html' - && isset($_POST['addBase']) - && ! preg_match('@]*>)@i' - ,'$1' - ,$content - ); - } - - $sourceSpec['content'] = $content; - $sourceSpec['id'] = 'foo'; - - if ($type['minify'] === 'text/html') { - if (isset($_POST['minJs'])) { - $sourceSpec['minifyOptions']['jsMinifier'] = array('JSMin', 'minify'); - } - if (isset($_POST['minCss'])) { - $sourceSpec['minifyOptions']['cssMinifier'] = array('Minify_CSS', 'minify'); - } - } - - $source = new Minify_Source($sourceSpec); - - $sendType = 'text/plain'; - if ($type['minify'] === 'text/html' && ! isset($_POST['asText'])) { - $sendType = $type['sent']; - } - if ($type['charset']) { - $sendType .= ';charset=' . $type['charset']; - } - header('Content-Type: ' . $sendType); - // using combine instead of serve because it allows us to specify a - // Content-Type like application/xhtml+xml IF we need to - try { - echo Minify::combine(array($source), array( - 'contentType' => $type['minify'] - )); - } catch (Exception $e) { - header('Content-Type: text/html;charset=utf-8'); - echo htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8'); - } - exit(); -} - -header('Content-Type: text/html; charset=utf-8'); - -$ua = get_magic_quotes_gpc() - ? stripslashes($_SERVER['HTTP_USER_AGENT']) - : $_SERVER['HTTP_USER_AGENT']; - -?> -Minify URL - -

    Warning! Please do not place this application on a public site. This should be used -only for testing.

    - -

    Fetch and Minify a URL

    -

    This tool will retrieve the contents of a URL and minify it. -The fetched resource Content-Type will determine the minifier used.

    - -
    -

    -

    - -
    HTML options -

    If the resource above is sent with an (x)HTML Content-Type, the following options will apply:

    -
      -
    • -
    • -
    • -
    • -
    -
    - -
    Retreival options -
      -
    • -
    • -
    -
    - -
    diff --git a/mrclay/minify/min_extras/tools/testRewriteUri.php b/mrclay/minify/min_extras/tools/testRewriteUri.php deleted file mode 100644 index b40d9d8818ad..000000000000 --- a/mrclay/minify/min_extras/tools/testRewriteUri.php +++ /dev/null @@ -1,58 +0,0 @@ -"; -} - -// validate user POST (no arrays and fix slashes) -if (! empty($_POST)) { - foreach ($_POST as $name => $val) { - if (! is_string($val)) { - unset($_POST[$name]); - continue; - } - if (get_magic_quotes_gpc()) { - $_POST[$name] = stripslashes($val); - } - } -} - -$defaultCurrentDir = dirname(__FILE__); -$defaultDocRoot = realpath($_SERVER['DOCUMENT_ROOT']); -$defaultSymLink = '//symlinkPath'; -$defaultSymTarget = ($defaultCurrentDir[0] === '/') ? '/tmp' : 'C:\\WINDOWS\\Temp'; -$defaultCss = "url(hello.gif)\nurl(../hello.gif)\nurl(../../hello.gif)\nurl(up/hello.gif)"; - -$out = ''; - -if (isset($_POST['css'])) { - require '../config.php'; - $symlinks = array(); - if ('' !== ($target = getPost('symTarget'))) { - $symlinks[getPost('symLink')] = $target; - } - $css = Minify_CSS_UriRewriter::rewrite( - getPost('css') - , getPost('currentDir') - , getPost('docRoot') - , $symlinks - ); - $out = "
    " . h($css) . '
    '; -} - -?> -

    Test Minify_CSS_UriRewriter::rewrite()

    -
    -
    -
    -
    -

    -

    -
    - \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/.htaccess b/mrclay/minify/min_unit_tests/.htaccess deleted file mode 100644 index 4e05c4c922e8..000000000000 --- a/mrclay/minify/min_unit_tests/.htaccess +++ /dev/null @@ -1,4 +0,0 @@ - -# In case AddOutputFilterByType has been added -SetEnv no-gzip - diff --git a/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/2.php b/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/2.php deleted file mode 100644 index 9b66f2493257..000000000000 --- a/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/2.php +++ /dev/null @@ -1,44 +0,0 @@ - $lastModified -)); -if ($cg->cacheIsValid) { - $cg->sendHeaders(); - // we're done - exit(); -} - -// generate content -$title = 'Last-Modified is known : add Content-Length'; -$explain = ' -

    Here, like the first example, we know the Last-Modified time, -but we also want to set the Content-Length to increase cacheability and allow -HTTP persistent connections. Instead of sending headers immediately, we first -generate our content, then use setContentLength(strlen($content)) -to add the header. Then finally call sendHeaders() and send the -content.

    -

    Note: This is not required if your PHP config buffers all -output and your script doesn\'t do any incremental flushing of the output -buffer. PHP will generally set Content-Length for you if it can.

    -

    This script emulates a document that changes every ' .$every. ' seconds. -
    This is version: ' . date('r', $lastModified) . '

    -'; - -require '_include.php'; -$content = get_content(array( - 'title' => $title - ,'explain' => $explain -)); - -$cg->setContentLength(strlen($content)); -$cg->sendHeaders(); -send_slowly($content); - diff --git a/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/3.php b/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/3.php deleted file mode 100644 index b787c953902a..000000000000 --- a/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/3.php +++ /dev/null @@ -1,40 +0,0 @@ -When Last-Modified is unknown, you can still use ETags, but you need a short -string that is unique for that content. In the worst case, you have to generate -all the content first, then instantiate HTTP_ConditionalGet, setting -the array key contentHash to the output of a hash function of the -content. Since we have the full content, we might as well also use -setContentLength(strlen($content)) in the case where we need to -send it.

    -

    This script emulates a document that changes every ' .$every. ' seconds. -
    This is version: ' . date('r', $lastModified) . '

    -'; -require '_include.php'; -$content = get_content(array( - 'title' => $title - ,'explain' => $explain -)); - -$cg = new HTTP_ConditionalGet(array( - 'contentHash' => substr(md5($content), 7) -)); -if ($cg->cacheIsValid) { - $cg->sendHeaders(); - // we're done - exit(); -} -$cg->setContentLength(strlen($content)); -$cg->sendHeaders(); - -send_slowly($content); - diff --git a/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/4.php b/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/4.php deleted file mode 100644 index 4b77d2084bdd..000000000000 --- a/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/4.php +++ /dev/null @@ -1,49 +0,0 @@ - $lastModified - ,'encoding' => $enc -)); -$cg->sendHeaders(); -if ($cg->cacheIsValid) { - // we're done - exit(); -} - -// output encoded content - -$title = 'ConditionalGet + Encoder'; -$explain = ' -

    Using ConditionalGet and Encoder is straightforward. First impliment the -ConditionalGet, then if the cache is not valid, encode and send the content

    -

    This script emulates a document that changes every ' .$every. ' seconds. -
    This is version: ' . date('r', $lastModified) . '

    -'; -require '_include.php'; -$content = get_content(array( - 'title' => $title - ,'explain' => $explain -)); - -$he = new HTTP_Encoder(array( - 'content' => get_content(array( - 'title' => $title - ,'explain' => $explain - )) -)); -$he->encode(); - -// usually you would just $he->sendAll(), but here we want to emulate slow -// connection -$he->sendHeaders(); -send_slowly($he->getContent()); diff --git a/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/5.php b/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/5.php deleted file mode 100644 index b443c19734fd..000000000000 --- a/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/5.php +++ /dev/null @@ -1,27 +0,0 @@ - 20 - ,'lastModifiedTime' => filemtime(__FILE__) -)); -$cg->sendHeaders(); - -// generate, send content -$title = 'Last-Modified + Expires'; -$explain = ' -

    Here we set a static "lastModifiedTime" and "maxAge" to 20. The browser -will consider this document fresh for 20 seconds, then revalidate its cache. After -the 304 response, the cache will be good for another 20 seconds. Unless you force -a reload, there will only be 304 responses for this page after the initial download. -'; - -require '_include.php'; -echo get_content(array( - 'title' => $title - ,'explain' => $explain -)); - diff --git a/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/_include.php b/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/_include.php deleted file mode 100644 index c99a4f2ab2ce..000000000000 --- a/mrclay/minify/min_unit_tests/HTTP_ConditionalGet/_include.php +++ /dev/null @@ -1,64 +0,0 @@ - - - - - -HTTP_ConditionalGet : <?php echo $data['title']; ?> - - -

    HTTP_ConditionalGet

    -

    - - -

    Notes

    -

    How to distinguish 200 and 304 responses

    -

    For these pages all 200 responses are sent in chunks a second apart, so you -should notice that 304 responses are quicker. You can also use HTTP sniffers -like Fiddler (win) and -LiveHTTPHeaders (Firefox add-on) -to verify headers and content being sent.

    -

    Browser notes

    -
    -
    Opera
    -
    Opera has a couple behaviors against the HTTP spec: Manual refreshes (F5) - prevents the ETag/If-Modified-Since headers from being sent; it only sends - them when following a link or bookmark. Also, Opera will not honor the - must-revalidate Cache-Control value unless max-age - is set. To get Opera to follow the spec, ConditionalGet will send Opera max-age=0 - (if one is not already set).
    -
    Safari
    -
    ETag validation is unsupported, but Safari supports HTTP/1.0 validation via - If-Modified-Since headers as long as the cache is explicitly marked - "public" or "private" ("private" is default in ConditionalGet).
    -
    - - - $lastModified -)); -$cg->sendHeaders(); -if ($cg->cacheIsValid) { - // we're done - exit(); -} - -$title = 'Last-Modified is known : simple usage'; -$explain = ' -

    If your content has not changed since a certain timestamp, set this via the -the lastModifiedTime array key when instantiating HTTP_ConditionalGet. -You can immediately call the method sendHeaders() to set the -Last-Modified, ETag, and Cache-Control headers. The, if cacheIsValid -property is false, you echo the content.

    -

    This script emulates a document that changes every ' .$every. ' seconds. -
    This is version: ' . date('r', $lastModified) . '

    -'; - -require '_include.php'; - -echo send_slowly(get_content(array( - 'title' => $title - ,'explain' => $explain -))); - diff --git a/mrclay/minify/min_unit_tests/HTTP_Encoder/green.png b/mrclay/minify/min_unit_tests/HTTP_Encoder/green.png deleted file mode 100644 index d9d3a308aec0e9c7be676a8bc5438e5c61427ff2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_{3?x-PN__%S%*9TgAsieWw;%dH0CL#^d_r6q z{xkglf9682r8`iBv%n*=n1O-o0|+xZtudJa6cj6QjVN(0N=+=u%+FH@$;?efo0^iDsNj}alv - - - -HTTP_Encoder Test - - - -

    HTTP_Encoder test

    -

    HTML

    -

    CSS

    -

    Javascript

    -

    image

    - - - - $content - ,'type' => $type -)); -$he->encode(); -$he->sendAll(); - -?> \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_inc.php b/mrclay/minify/min_unit_tests/_inc.php deleted file mode 100644 index 197ed9567f04..000000000000 --- a/mrclay/minify/min_unit_tests/_inc.php +++ /dev/null @@ -1,62 +0,0 @@ -0, 'fail'=>0, 'total'=>0); - - $mode = $test ? 'pass' : 'fail'; - $outMode = $test ? 'PASS' : '!FAIL'; - printf("%s: %s (%d of %d tests run so far have %sed)\n", - $outMode, $message, ++$count[$mode], ++$count['total'], $mode); - - return (bool)$test; -} - -/** - * Get number of bytes in a string regardless of mbstring.func_overload - * - * @param string $str - * @return int - */ -function countBytes($str) -{ - return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) - ? mb_strlen($str, '8bit') - : strlen($str); -} - -ob_start(); \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/comments.css b/mrclay/minify/min_unit_tests/_test_files/css/comments.css deleted file mode 100644 index 2ef9fac4986e..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/comments.css +++ /dev/null @@ -1,9 +0,0 @@ - -/* block comments get removed */ - -/*! YUI Compressor style comments are preserved */ - -/* but all other comments are removed */ - -/* comments that have any surrounding whitespace are replaced by a single space. */ -body{ background:#fff/*eef*/ url(/path/to/image.gif) repeat-y; } diff --git a/mrclay/minify/min_unit_tests/_test_files/css/comments.min.css b/mrclay/minify/min_unit_tests/_test_files/css/comments.min.css deleted file mode 100644 index e0414a77c951..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/comments.min.css +++ /dev/null @@ -1,3 +0,0 @@ - -/*! YUI Compressor style comments are preserved */ -body{background:#fff url(/path/to/image.gif) repeat-y} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/hacks.css b/mrclay/minify/min_unit_tests/_test_files/css/hacks.css deleted file mode 100644 index 715bbf779170..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/hacks.css +++ /dev/null @@ -1,66 +0,0 @@ -/* hide from ie5/mac \*/ a{} -.foo {color:red} -/* necessary comment */ - -/* comment to attempt to confuse parser */ - -/* feed to ie5/mac \*//*/ -@import "ie5mac.css"; -/* necessary comment */ - -/* comment to attempt to confuse parser */ - -/*/ hide from nav4 */ -.foo {display:block;} -/* necessary comment */ - -/* comment to attempt to confuse parser */ - -/*/ feed to nav *//*/ -.foo {display:crazy;} -/* necessary comment */ - -/* hide props from various IE/win */ -div { - width: 140px; - width/* */:/**/100px; - width: /**/100px; -} - -html>/**/body {} - -/* Tantek's box model hack */ -div { - width:400px; - voice-family: "\"}\""; - voice-family:inherit; - width:300px; -} - -/* don't minimize hex colors in filters */ -div { - filter:chroma(color=#aabbcc); - filter:mask(color=#000000) shadow(color=#9BAD71, direction=135) chroma(color=#000000); -} - -@media screen { - /* for IE 5.x-6, hidden from IE 5 Mac */ /*\*/ - * html div#page { - height: 1%; - } - /**/ /* end hidden from IE 5 Mac */ -} - -foo { /* filters for IE */ - _height : 20px; - *height : 15px; -} - -/* http://tantek.com/CSS/Examples/midpass.html */ -@media tty { - i{content:"\";/*" "*/}} @import 'midpassafter.css'; /*";} -}/* */ - -/* leave at least 1 space between these pseudo elements and "{" for IE6: http://www.crankygeek.com/ie6pebug/ */ -p:first-letter {color:red;} -p:first-line {color:red;} diff --git a/mrclay/minify/min_unit_tests/_test_files/css/hacks.min.css b/mrclay/minify/min_unit_tests/_test_files/css/hacks.min.css deleted file mode 100644 index 68be2ee89eda..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/hacks.min.css +++ /dev/null @@ -1,4 +0,0 @@ -/*\*/a{}.foo{color:red}/**/ /*\*//*/@import "ie5mac.css";/**/ /*/*/.foo{display:block}/**/ /*/*//*/.foo{display:crazy}/**/ div{width:140px;width/**/:/**/100px;width:/**/100px}html>/**/body{}div{width:400px;voice-family:"\"}\"";voice-family:inherit;width:300px}div{filter:chroma(color=#aabbcc);filter:mask(color=#000000) shadow(color=#9BAD71, direction=135) chroma(color=#000000)}@media -screen{/*\*/* html -div#page{height:1%}/**/}foo{_height:20px;*height:15px}@media -tty{i{content:"\";/*" "*/}}@import 'midpassafter.css';/*"}}/* */ p:first-letter {color:red}p:first-line {color:red} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/issue210.css b/mrclay/minify/min_unit_tests/_test_files/css/issue210.css deleted file mode 100644 index 842195b86ee6..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/issue210.css +++ /dev/null @@ -1 +0,0 @@ -.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; } \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/issue210.min.css b/mrclay/minify/min_unit_tests/_test_files/css/issue210.min.css deleted file mode 100644 index 8a1869d31bf0..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/issue210.min.css +++ /dev/null @@ -1 +0,0 @@ -.ui-widget{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/issue62.css b/mrclay/minify/min_unit_tests/_test_files/css/issue62.css deleted file mode 100644 index b9d813f7ddf4..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/issue62.css +++ /dev/null @@ -1,890 +0,0 @@ -/* -* DEFINITION DES STYLES DE TEXTE -*/ - /*-----------------------------------------------------------------------------------*/ -h1 { - color: #339933; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 14px; - font-weight: bold; - text-decoration: none; -} - -h2 { - color: #339933; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 12px; - font-weight: bold; - text-decoration: none; -} - -h1,h2,h3,h4,h5 { - margin: 0px; - padding: 0px; -} - -.txt_10_noir { - color: black; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 10px; - text-decoration: none; -} - -.txt_10_noir:link,.txt_10_noir:visited,.txt_10_noir:active { - color: black; -} - -.txt_10_noir:hover { - color: red; -} - -.txt_11_noir { - color: black; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.txt_11_noir:link,.txt_11_noir:visited,.txt_11_noir:active { - color: black; -} - -.txt_11_noir:hover { - color: red; -} - -.txt_12_noir { - color: black; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 12px; - text-decoration: none; -} - -.txt_12_noir:link,.txt_12_noir:visited,.txt_12_noir:active { - color: black; -} - -.txt_12_noir:hover { - color: red; -} - -.txt_14_noir { - color: black; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 14px; - text-decoration: none; -} - -.txt_14_noir:link,.txt_14_noir:visited,.txt_14_noir:active { - color: black; -} - -.txt_14_noir:hover { - color: red; -} - -/*-----------------------------------------------------------------------------------*/ -.txt_10_gris { - color: grey; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 10px; - text-decoration: none; -} - -.txt_10_gris:link,.txt_10_gris:visited,.txt_10_gris:active { - color: grey; -} - -.txt_10_gris:hover { - color: red; -} - -.txt_11_gris { - color: grey; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.txt_11_gris:link,.txt_11_gris:visited,.txt_11_gris:active { - color: grey; -} - -.txt_11_gris:hover { - color: red; -} - -.txt_12_gris { - color: grey; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 12px; - text-decoration: none; -} - -.txt_12_gris:link,.txt_12_gris:visited,.txt_12_gris:active { - color: grey; -} - -.txt_12_gris:hover { - color: red; -} - -.txt_14_gris { - color: grey; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 14px; - text-decoration: none; -} - -.txt_14_gris:link,.txt_14_gris:visited,.txt_14_gris:active { - color: grey; -} - -.txt_14_gris:hover { - color: red; -} - -/*-----------------------------------------------------------------------------------*/ -.txt_10_blanc { - color: #FFFFFF; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 10px; - text-decoration: none; -} - -.txt_10_blanc:link,.txt_10_blanc:visited,.txt_10_blanc:active { - color: #FFFFFF; -} - -.txt_10_blanc:hover { - color: #FF8800; /*ORANGE*/ -} - -.txt_11_blanc { - color: #FFFFFF; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.txt_11_blanc:link,.txt_11_blanc:visited,.txt_11_blanc:active { - color: #FFFFFF; -} - -.txt_11_blanc:hover { - color: #FF8800; -} - -.txt_12_blanc { - color: #FFFFFF; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 12px; - text-decoration: none; -} - -.txt_12_blanc:link,.txt_12_blanc:visited,.txt_12_blanc:active { - color: #FFFFFF; -} - -.txt_12_blanc:hover { - color: #FFAA00; -} - -.txt_14_blanc { - color: #FFFFFF; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 14px; - text-decoration: none; -} - -.txt_14_blanc:link,.txt_14_blanc:visited,.txt_14_blanc:active { - color: #FFFFFF; -} - -.txt_14_blanc:hover { - color: #FF8800; -} - -/*-----------------------------------------------------------------------------------*/ -.txt_10_orange { - color: #FF8800; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 10px; - text-decoration: none; -} - -.txt_10_orange:link,.txt_10_orange:visited,.txt_10_orange:active { - color: #FF8800; -} - -.txt_10_orange:hover { - color: darkblue -} - -.txt_11_orange { - color: #FF8800; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.txt_11_orange:link,.txt_11_orange:visited,.txt_11_orange:active { - color: #FF8800; -} - -.txt_11_orange:hover { - color: darkblue; -} - -.txt_12_orange { - color: #FF8800; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 12px; - text-decoration: none; -} - -.txt_12_orange:link,.txt_12_orange:visited,.txt_12_orange:active { - color: #FF8800; -} - -.txt_12_orange:hover { - color: darkblue; -} - -.txt_14_orange { - color: #FF8800; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 14px; - text-decoration: none; -} - -.txt_14_orange:link,.txt_14_orange:visited,.txt_14_orange:active { - color: #FF8800; -} - -.txt_14_orange:hover { - color: darkblue; -} - -/*-----------------------------------------------------------------------------------*/ -.txt_10_rouge { - color: red; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 10px; - text-decoration: none; -} - -.txt_10_rouge:link,.txt_10_rouge:visited,.txt_10_rouge:active { - color: red; -} - -.txt_10_rouge:hover { - color: darkblue; -} - -.txt_11_rouge { - color: red; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.txt_11_rouge:link,.txt_11_rouge:visited,.txt_11_rouge:active { - color: red; -} - -.txt_11_rouge:hover { - color: darkblue; -} - -.txt_12_rouge { - color: red; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 12px; - text-decoration: none; -} - -.txt_12_rouge:link,.txt_12_rouge:visited,.txt_12_rouge:active { - color: red; -} - -.txt_12_rouge:hover { - color: darkblue; -} - -.txt_14_rouge { - color: red; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 14px; - text-decoration: none; -} - -.txt_14_rouge:link,.txt_14_rouge:visited,.txt_14_rouge:active { - color: red; -} - -.txt_14_rouge:hover { - color: darkblue; -} - -/*-----------------------------------------------------------------------------------*/ -.txt_10_bleu { - color: blue; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 10px; - text-decoration: none; -} - -.txt_10_bleu:link,.txt_10_bleu:visited,.txt_10_bleu:active { - color: blue; -} - -.txt_10_bleu:hover { - color: red; -} - -.txt_11_bleu { - color: blue; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.txt_11_bleu:link,.txt_11_bleu:visited,.txt_11_bleu:active { - color: blue; -} - -.txt_11_bleu:hover { - color: red; -} - -.txt_12_bleu { - color: blue; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 12px; - text-decoration: none; -} - -.txt_12_bleu:link,.txt_12_bleu:visited,.txt_12_bleu:active { - color: blue; -} - -.txt_12_bleu:hover { - color: red; -} - -.txt_14_bleu { - color: blue; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 14px; - text-decoration: none; -} - -.txt_14_bleu:link,.txt_14_bleu:visited,.txt_14_bleu:active { - color: blue; -} - -.txt_14_bleu:hover { - color: red; -} - -/*-----------------------------------------------------------------------------------*/ -.txt_10_bleu_f { - color: darkblue; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 10px; - text-decoration: none; -} - -.txt_10_bleu_f:link,.txt_10_bleu_f:visited,.txt_10_bleu_f:active { - color: darkblue; -} - -.txt_10_bleu_f:hover { - color: red; -} - -.txt_11_bleu_f { - color: darkblue; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.txt_11_bleu_f:link,.txt_11_bleu_f:visited,.txt_11_bleu_f:active { - color: darkblue; -} - -.txt_11_bleu_f:hover { - color: red; -} - -.txt_12_bleu_f { - color: darkblue; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 12px; - text-decoration: none; -} - -.txt_12_bleu_f:link,.txt_12_bleu_f:visited,.txt_12_bleu_f:active { - color: darkblue; -} - -.txt_12_bleu_f:hover { - color: red; -} - -.txt_14_bleu_f { - color: darkblue; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 14px; - text-decoration: none; -} - -.txt_14_bleu_f:link,.txt_14_bleu_f:visited,.txt_14_bleu_f:active { - color: darkblue; -} - -.txt_14_bleu_f:hover { - color: red; -} - -/*-----------------------------------------------------------------------------------*/ -.txt_10_vert_f { - color: darkgreen; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 10px; - text-decoration: none; -} - -.txt_10_vert_f:link,.txt_10_vert_f:visited,.txt_10_vert_f:active { - color: darkgreen; -} - -.txt_10_vert_f:hover { - color: red; -} - -.txt_11_vert_f { - color: darkgreen; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.txt_11_vert_f:link,.txt_11_vert_f:visited,.txt_11_vert_f:active { - color: darkgreen; -} - -.txt_11_vert_f:hover { - color: red; -} - -.txt_12_vert_f { - color: darkgreen; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 12px; - text-decoration: none; -} - -.txt_12_vert_f:link,.txt_12_vertf:visited,.txt_12_vert_f:active { - color: darkgreen; -} - -.txt_12_vert_f:hover { - color: red; -} - -.txt_14_vert_f { - color: darkgreen; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 14px; - text-decoration: none; -} - -.txt_14_vert_f:link,.txt_14_vert_f:visited,.txt_14_vert_f:active { - color: darkgreen; -} - -.txt_14_vert_f:hover { - color: red; -} - -/*-----------------------------------------------------------------------------------*/ -.txt_10_vert { - color: green; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 10px; - text-decoration: none; -} - -.txt_10_vert:link,.txt_10_vert:visited,.txt_10_vert:active { - color: green; -} - -.txt_10_vert:hover { - color: red; -} - -.txt_11_vert { - color: green; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.txt_11_vert:link,.txt_11_vert:visited,.txt_11_vert:active { - color: green; -} - -.txt_11_vert:hover { - color: red; -} - -.txt_12_vert { - color: green; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 12px; - text-decoration: none; -} - -.txt_12_vert:link,.txt_12_vert:visited,.txt_12_vert:active { - color: green; -} - -.txt_12_vert:hover { - color: red; -} - -.txt_14_vert { - color: green; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 14px; - text-decoration: none; -} - -.txt_14_vert:link,.txt_14_vert:visited,.txt_14_vert:active { - color: green; -} - -.txt_14_vert:hover { - color: red; -} - -/*-----------------------------------------------------------------------------------*/ -.fond_blanc { - background-color: #FFFFFF; - color: black; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.fond_gris_c, .fond_gris_c tr { - background-color: #FFFFFF; - color: black; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; - background-image: url(../images/fond_4.bmp); - background-repeat: repeat-x; -} - -.fond_gris_c2, .fond_gris_c2 tr { - background-color: #FBFBFB; - color: black; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.fond_bleu_c, .fond_bleu_c tr { - background-color: #D9EEF9; - color: black; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; - background-image: url(../images/fond_1.bmp); -} - -.fond_bleu_c2 { - background-color: #ECF4FF; - color: black; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.fond_bleu_f { - background-color: #003366; - color: black; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.fond_orange { - background-color: #FEEFE7; - color: darkgreen; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 12px; - font-weight: bold; - text-decoration: none; - background-image: url(../images/fond_3.jpg); -} - -.fond_orange_2 { - background-color: #FFF8F4; - color: darkgreen; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 12px; - font-weight: bold; - text-decoration: none; - border: 1px solid orange; - border-collapse: collapse; -} - -.vccDlgBody { - border: 3px solid #336699; - border-collapse: collapse; - color: black; - background-color: #EEFFEE; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -/* DEFINITION DES STYLES DE TABLEAUX */ -.bordure_0 { - border: 0px solid; - color: black; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.bordure_1_bleu { - border: 1px solid green; - border-collapse: collapse; - color: black; - background-color: #FFFFFF; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.bordure_3_bleu { - border: 3px solid #336699; - border-collapse: collapse; - color: black; - background-color: #FFFFFF; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 11px; - text-decoration: none; -} - -.indent { - margin-left: 20px; -} - -/* DEFINITION DES STYLES D'OBJETS DE FORMULAIRE */ -.Btn { - color: #003366; - text-align: center; - font-weight: bold; - background-color: #FFFFFF; - background-image: url(../images/ongletStyle1.jpg); - background-repeat: no-repeat; - background-position: center center; -} - -.Btn:hover { - color: red; -} - -.menu1h { - background-color: #003366; - color: white; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 10px; - font-weight: bold; - text-decoration: none; - border-top: 1px solid #003366; - border-bottom: 1px solid #003366; - border-left: 1px solid #003366; - border-right: 1px solid white; - border-collapse: collapse; - display: block; -} - -.menu1h:hover { - background-color: white; - color: red; - border: 1px solid darkgreen; - border-collapse: collapse; -} - -.menu1h_f { - background-color: #003366; - color: white; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 10px; - font-weight: bold; - text-decoration: none; - border: 1px solid #003366; - display: block; -} - -.menu1h_f:hover { - background-color: white; - color: red; - border: 1px solid darkgreen; - border-collapse: collapse; -} - -.menu1v { - background-color: #003366; - color: white; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 10px; - font-weight: bold; - text-decoration: none; - border: 1px solid #003366; - border-collapse: collapse; - display: block; -} - -.menu1v:hover { - background-color: white; - color: red; - border: 1px solid darkgreen; - border-collapse: collapse; -} - -.menu2v { - background-color: #5588BB; - color: white; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 12px; - font-weight: bold; - text-decoration: none; - border: 1px solid #4277AB; - border-collapse: collapse; - float: left; - display: block; -} - -.menu2v:hover { - background-color: white; - color: red; - border: 1px solid darkgreen; - border-collapse: collapse; -} - -.menuEDF { - background-color: #003366; - color: white; - font-family: Verdana, Arial, Lucida, Tahoma; - font-size: 10px; - text-decoration: none; -} - -.menuEDF:hover { - color: #FF8800; -} - -/*bouton bleu sur blanc*/ -.Bouton { - color: #003366; - text-align: center; - font-weight: bold; - /* Ricardo cursor: hand; */ - cursor: pointer; - background-color: #FFFFFF; -} - -input { - border: 2px solid green; - color: #003366; - background-color: #FFFFFF; - background-image: url(../images/fond_4.bmp); - background-repeat: repeat-x; -} - -.disabled_input { - border: 1px solid gray; - color: grey; - background-color: #FFFFFF; - background-image: url(../images/fond_4.bmp); - background-repeat: repeat-x; -} - -.input0 { - border: 0px; - color: #003366; - background-color: #FFFFFF; - background-image: url(../images/fond_4.bmp); -} - -.input2 { - border: 1px solid green; - color: #003366; - background-color: #FFFFFF; - background-image: url(../images/fond_4.bmp); - background-repeat: repeat-x; -} - -.input3 { - border: 1px solid black; - color: #003366; - background-color: #EEEEEE; - background-image: url(); -} - -.input4 { - border: 1px solid blue; - color: #003366; - background-color: #FFFFFF; - background-image: url(../images/fond_4.bmp); - background-repeat: repeat-x; -} - -.input5 { - border: 1px solid darkblue; - color: #003366; - background-color: #FFFFFF; - background-image: url(../images/fond_4.bmp); - background-repeat: repeat-x; -} - -.input_btn { - border: 0px; - /* cursor: hand; */ - cursor: pointer; -} - -textarea { - border: 2px solid green; - color: #003366; - background-color: #FFFFFF; - background-image: url(../images/fond_5.bmp); -} - -.TEXTAREA3 { - border: 1px solid green; - color: #003366; - background-color: #FFFFFF; - background-image: url(); -} - -.TEXTAREA4 { - border: 1px solid green; - color: #003366; - background-color: #EEEEEE; - background-image: url(); -} - -.hand { - cursor: hand; - cursor: pointer; -} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/issue62.min.css b/mrclay/minify/min_unit_tests/_test_files/css/issue62.min.css deleted file mode 100644 index 5eb1982282fa..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/issue62.min.css +++ /dev/null @@ -1,25 +0,0 @@ -h1{color:#393;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;font-weight:bold;text-decoration:none}h2{color:#393;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;font-weight:bold;text-decoration:none}h1,h2,h3,h4,h5{margin:0px;padding:0px}.txt_10_noir{color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_noir:link,.txt_10_noir:visited,.txt_10_noir:active{color:black}.txt_10_noir:hover{color:red}.txt_11_noir{color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_noir:link,.txt_11_noir:visited,.txt_11_noir:active{color:black}.txt_11_noir:hover{color:red}.txt_12_noir{color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_noir:link,.txt_12_noir:visited,.txt_12_noir:active{color:black}.txt_12_noir:hover{color:red}.txt_14_noir{color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_noir:link,.txt_14_noir:visited,.txt_14_noir:active{color:black}.txt_14_noir:hover{color:red}.txt_10_gris{color:grey;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_gris:link,.txt_10_gris:visited,.txt_10_gris:active{color:grey}.txt_10_gris:hover{color:red}.txt_11_gris{color:grey;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_gris:link,.txt_11_gris:visited,.txt_11_gris:active{color:grey}.txt_11_gris:hover{color:red}.txt_12_gris{color:grey;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_gris:link,.txt_12_gris:visited,.txt_12_gris:active{color:grey}.txt_12_gris:hover{color:red}.txt_14_gris{color:grey;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_gris:link,.txt_14_gris:visited,.txt_14_gris:active{color:grey}.txt_14_gris:hover{color:red}.txt_10_blanc{color:#FFF;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_blanc:link,.txt_10_blanc:visited,.txt_10_blanc:active{color:#FFF}.txt_10_blanc:hover{color:#F80}.txt_11_blanc{color:#FFF;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_blanc:link,.txt_11_blanc:visited,.txt_11_blanc:active{color:#FFF}.txt_11_blanc:hover{color:#F80}.txt_12_blanc{color:#FFF;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_blanc:link,.txt_12_blanc:visited,.txt_12_blanc:active{color:#FFF}.txt_12_blanc:hover{color:#FA0}.txt_14_blanc{color:#FFF;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_blanc:link,.txt_14_blanc:visited,.txt_14_blanc:active{color:#FFF}.txt_14_blanc:hover{color:#F80}.txt_10_orange{color:#F80;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_orange:link,.txt_10_orange:visited,.txt_10_orange:active{color:#F80}.txt_10_orange:hover{color:darkblue}.txt_11_orange{color:#F80;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_orange:link,.txt_11_orange:visited,.txt_11_orange:active{color:#F80}.txt_11_orange:hover{color:darkblue}.txt_12_orange{color:#F80;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_orange:link,.txt_12_orange:visited,.txt_12_orange:active{color:#F80}.txt_12_orange:hover{color:darkblue}.txt_14_orange{color:#F80;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_orange:link,.txt_14_orange:visited,.txt_14_orange:active{color:#F80}.txt_14_orange:hover{color:darkblue}.txt_10_rouge{color:red;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_rouge:link,.txt_10_rouge:visited,.txt_10_rouge:active{color:red}.txt_10_rouge:hover{color:darkblue}.txt_11_rouge{color:red;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_rouge:link,.txt_11_rouge:visited,.txt_11_rouge:active{color:red}.txt_11_rouge:hover{color:darkblue}.txt_12_rouge{color:red;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_rouge:link,.txt_12_rouge:visited,.txt_12_rouge:active{color:red}.txt_12_rouge:hover{color:darkblue}.txt_14_rouge{color:red;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_rouge:link,.txt_14_rouge:visited,.txt_14_rouge:active{color:red}.txt_14_rouge:hover{color:darkblue}.txt_10_bleu{color:blue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_bleu:link,.txt_10_bleu:visited,.txt_10_bleu:active{color:blue}.txt_10_bleu:hover{color:red}.txt_11_bleu{color:blue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_bleu:link,.txt_11_bleu:visited,.txt_11_bleu:active{color:blue}.txt_11_bleu:hover{color:red}.txt_12_bleu{color:blue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_bleu:link,.txt_12_bleu:visited,.txt_12_bleu:active{color:blue}.txt_12_bleu:hover{color:red}.txt_14_bleu{color:blue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_bleu:link,.txt_14_bleu:visited,.txt_14_bleu:active{color:blue}.txt_14_bleu:hover{color:red}.txt_10_bleu_f{color:darkblue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_bleu_f:link,.txt_10_bleu_f:visited,.txt_10_bleu_f:active{color:darkblue}.txt_10_bleu_f:hover{color:red}.txt_11_bleu_f{color:darkblue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_bleu_f:link,.txt_11_bleu_f:visited,.txt_11_bleu_f:active{color:darkblue}.txt_11_bleu_f:hover{color:red}.txt_12_bleu_f{color:darkblue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_bleu_f:link,.txt_12_bleu_f:visited,.txt_12_bleu_f:active{color:darkblue}.txt_12_bleu_f:hover{color:red}.txt_14_bleu_f{color:darkblue;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_bleu_f:link,.txt_14_bleu_f:visited,.txt_14_bleu_f:active{color:darkblue}.txt_14_bleu_f:hover{color:red}.txt_10_vert_f{color:darkgreen;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_vert_f:link,.txt_10_vert_f:visited,.txt_10_vert_f:active{color:darkgreen}.txt_10_vert_f:hover{color:red}.txt_11_vert_f{color:darkgreen;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_vert_f:link,.txt_11_vert_f:visited,.txt_11_vert_f:active{color:darkgreen}.txt_11_vert_f:hover{color:red}.txt_12_vert_f{color:darkgreen;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_vert_f:link,.txt_12_vertf:visited,.txt_12_vert_f:active{color:darkgreen}.txt_12_vert_f:hover{color:red}.txt_14_vert_f{color:darkgreen;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_vert_f:link,.txt_14_vert_f:visited,.txt_14_vert_f:active{color:darkgreen}.txt_14_vert_f:hover{color:red}.txt_10_vert{color:green;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.txt_10_vert:link,.txt_10_vert:visited,.txt_10_vert:active{color:green}.txt_10_vert:hover{color:red}.txt_11_vert{color:green;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.txt_11_vert:link,.txt_11_vert:visited,.txt_11_vert:active{color:green}.txt_11_vert:hover{color:red}.txt_12_vert{color:green;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;text-decoration:none}.txt_12_vert:link,.txt_12_vert:visited,.txt_12_vert:active{color:green}.txt_12_vert:hover{color:red}.txt_14_vert{color:green;font-family:Verdana,Arial,Lucida,Tahoma;font-size:14px;text-decoration:none}.txt_14_vert:link,.txt_14_vert:visited,.txt_14_vert:active{color:green}.txt_14_vert:hover{color:red}.fond_blanc{background-color:#FFF;color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.fond_gris_c, .fond_gris_c -tr{background-color:#FFF;color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none;background-image:url(../images/fond_4.bmp);background-repeat:repeat-x}.fond_gris_c2, .fond_gris_c2 -tr{background-color:#FBFBFB;color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.fond_bleu_c, .fond_bleu_c -tr{background-color:#D9EEF9;color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none;background-image:url(../images/fond_1.bmp)}.fond_bleu_c2{background-color:#ECF4FF;color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.fond_bleu_f{background-color:#036;color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.fond_orange{background-color:#FEEFE7;color:darkgreen;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;font-weight:bold;text-decoration:none;background-image:url(../images/fond_3.jpg)}.fond_orange_2{background-color:#FFF8F4;color:darkgreen;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;font-weight:bold;text-decoration:none;border:1px -solid orange;border-collapse:collapse}.vccDlgBody{border:3px -solid #369;border-collapse:collapse;color:black;background-color:#EFE;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.bordure_0{border:0px -solid;color:black;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.bordure_1_bleu{border:1px -solid green;border-collapse:collapse;color:black;background-color:#FFF;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.bordure_3_bleu{border:3px -solid #369;border-collapse:collapse;color:black;background-color:#FFF;font-family:Verdana,Arial,Lucida,Tahoma;font-size:11px;text-decoration:none}.indent{margin-left:20px}.Btn{color:#036;text-align:center;font-weight:bold;background-color:#FFF;background-image:url(../images/ongletStyle1.jpg);background-repeat:no-repeat;background-position:center center}.Btn:hover{color:red}.menu1h{background-color:#036;color:white;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;font-weight:bold;text-decoration:none;border-top:1px solid #036;border-bottom:1px solid #036;border-left:1px solid #036;border-right:1px solid white;border-collapse:collapse;display:block}.menu1h:hover{background-color:white;color:red;border:1px -solid darkgreen;border-collapse:collapse}.menu1h_f{background-color:#036;color:white;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;font-weight:bold;text-decoration:none;border:1px -solid #036;display:block}.menu1h_f:hover{background-color:white;color:red;border:1px -solid darkgreen;border-collapse:collapse}.menu1v{background-color:#036;color:white;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;font-weight:bold;text-decoration:none;border:1px -solid #036;border-collapse:collapse;display:block}.menu1v:hover{background-color:white;color:red;border:1px -solid darkgreen;border-collapse:collapse}.menu2v{background-color:#58B;color:white;font-family:Verdana,Arial,Lucida,Tahoma;font-size:12px;font-weight:bold;text-decoration:none;border:1px -solid #4277AB;border-collapse:collapse;float:left;display:block}.menu2v:hover{background-color:white;color:red;border:1px -solid darkgreen;border-collapse:collapse}.menuEDF{background-color:#036;color:white;font-family:Verdana,Arial,Lucida,Tahoma;font-size:10px;text-decoration:none}.menuEDF:hover{color:#F80}.Bouton{color:#036;text-align:center;font-weight:bold;cursor:pointer;background-color:#FFF}input{border:2px -solid green;color:#036;background-color:#FFF;background-image:url(../images/fond_4.bmp);background-repeat:repeat-x}.disabled_input{border:1px -solid gray;color:grey;background-color:#FFF;background-image:url(../images/fond_4.bmp);background-repeat:repeat-x}.input0{border:0px;color:#036;background-color:#FFF;background-image:url(../images/fond_4.bmp)}.input2{border:1px -solid green;color:#036;background-color:#FFF;background-image:url(../images/fond_4.bmp);background-repeat:repeat-x}.input3{border:1px -solid black;color:#036;background-color:#EEE;background-image:url()}.input4{border:1px -solid blue;color:#036;background-color:#FFF;background-image:url(../images/fond_4.bmp);background-repeat:repeat-x}.input5{border:1px -solid darkblue;color:#036;background-color:#FFF;background-image:url(../images/fond_4.bmp);background-repeat:repeat-x}.input_btn{border:0px;cursor:pointer}textarea{border:2px -solid green;color:#036;background-color:#FFF;background-image:url(../images/fond_5.bmp)}.TEXTAREA3{border:1px -solid green;color:#036;background-color:#FFF;background-image:url()}.TEXTAREA4{border:1px -solid green;color:#036;background-color:#EEE;background-image:url()}.hand{cursor:hand;cursor:pointer} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.css b/mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.css deleted file mode 100644 index 48e75fb69448..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.css +++ /dev/null @@ -1,12 +0,0 @@ -@import "foo.css"; -@import 'bar/foo.css' print; -@import '/css/foo.css'; /* abs, should not alter */ -@import 'http://foo.com/css/foo.css'; /* abs, should not alter */ -@import url(../foo.css) tv, projection; -@import url("/css/foo.css"); /* abs, should not alter */ -@import url(/css2/foo.css); /* abs, should not alter */ -@import url(data:image/gif;base64,AAAA); /* data, should not alter */ -foo {background:url('bar/foo.png')} -foo {background:url('http://foo.com/css/foo.css');} /* abs, should not alter */ -foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ -foo {background:url(data:image/gif;base64,AAAA);} /* data, should not alter */ \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.min.css b/mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.min.css deleted file mode 100644 index ffb94e21651e..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/paths_prepend.min.css +++ /dev/null @@ -1 +0,0 @@ -@import "../foo.css";@import '../bar/foo.css' print;@import '/css/foo.css';@import 'http://foo.com/css/foo.css';@import url(../../foo.css) tv, projection;@import url("/css/foo.css");@import url(/css2/foo.css);@import url(data:image/gif;base64,AAAA);foo{background:url('../bar/foo.png')}foo{background:url('http://foo.com/css/foo.css')}foo{background:url("//foo.com/css/foo.css")}foo{background:url(data:image/gif;base64,AAAA)} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.css b/mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.css deleted file mode 100644 index aa41d0a91e0c..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.css +++ /dev/null @@ -1,14 +0,0 @@ -@import "foo.css"; -@import 'bar/foo.css' print; -@import '../bar/foo.css' print; -@import '../../foo.css' print; -@import '/css/foo.css'; /* abs, should not alter */ -@import 'http://foo.com/css/foo.css'; /* abs, should not alter */ -@import url(../foo.css) tv, projection; -@import url("/css/foo.css"); /* abs, should not alter */ -@import url(/css2/foo.css); /* abs, should not alter */ -@import url(data:image/gif;base64,AAAA); /* data, should not alter */ -foo {background:url('bar/foo.png')} -foo {background:url('http://foo.com/css/foo.css');} /* abs, should not alter */ -foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ -foo {background:url(data:image/gif;base64,AAAA);} /* data, should not alter */ \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.min.css b/mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.min.css deleted file mode 100644 index 34936155a021..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/paths_rewrite.min.css +++ /dev/null @@ -1 +0,0 @@ -@import "/_test_files/css/foo.css";@import '/_test_files/css/bar/foo.css' print;@import '/_test_files/bar/foo.css' print;@import '/foo.css' print;@import '/css/foo.css';@import 'http://foo.com/css/foo.css';@import url(/_test_files/foo.css) tv, projection;@import url("/css/foo.css");@import url(/css2/foo.css);@import url(data:image/gif;base64,AAAA);foo{background:url('/_test_files/css/bar/foo.png')}foo{background:url('http://foo.com/css/foo.css')}foo{background:url("//foo.com/css/foo.css")}foo{background:url(data:image/gif;base64,AAAA)} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/readme.txt b/mrclay/minify/min_unit_tests/_test_files/css/readme.txt deleted file mode 100644 index 01817552960d..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/readme.txt +++ /dev/null @@ -1 +0,0 @@ -Test suite from http://search.cpan.org/~gtermars/CSS-Minifier-XS/ \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/selectors.css b/mrclay/minify/min_unit_tests/_test_files/css/selectors.css deleted file mode 100644 index cce2bf2e5e8c..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/selectors.css +++ /dev/null @@ -1,42 +0,0 @@ -/* http://www.w3.org/TR/css3-selectors/ */ - -* -E[foo] -E[foo="bar"] -E[foo~="bar"] -E[foo^="bar"] -E[foo$="bar"] -E[foo*="bar"] -E[hreflang|="en"] -E:root -E:nth-child(n) -E:nth-last-child(n) -E:nth-of-type(n) -E:nth-last-of-type(n) -E:first-child -E:last-child -E:first-of-type -E:last-of-type -E:only-child -E:only-of-type -E:empty -E:link -E:visited -E:active -E:hover -E:focus -E:target -E:lang(fr) -E:enabled -E:disabled -E:checked -E::first-line -E::first-letter -E::selection -E::before -E::after -E.warning#myid -E:not(s) - > F - + F - ~ F {color: red;} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/selectors.min.css b/mrclay/minify/min_unit_tests/_test_files/css/selectors.min.css deleted file mode 100644 index 643089fcf76c..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/selectors.min.css +++ /dev/null @@ -1,37 +0,0 @@ -* -E[foo] -E[foo="bar"] -E[foo~="bar"] -E[foo^="bar"] -E[foo$="bar"] -E[foo*="bar"] -E[hreflang|="en"] -E:root -E:nth-child(n) -E:nth-last-child(n) -E:nth-of-type(n) -E:nth-last-of-type(n) -E:first-child -E:last-child -E:first-of-type -E:last-of-type -E:only-child -E:only-of-type -E:empty -E:link -E:visited -E:active -E:hover -E:focus -E:target -E:lang(fr) -E:enabled -E:disabled -E:checked -E::first-line -E::first-letter -E::selection -E::before -E::after -E.warning#myid -E:not(s)>F+F~F{color:red} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/styles.css b/mrclay/minify/min_unit_tests/_test_files/css/styles.css deleted file mode 100644 index ed0bcd456cf3..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/styles.css +++ /dev/null @@ -1,33 +0,0 @@ -@charset "utf-8"; - -/* some CSS to try to exercise things in general */ - -@import url( /more.css ); - - body, td, th { - font-family: Verdana , "Bitstream Vera Sans" , Arial Narrow, sans-serif ; - - font-size : 12px; -} - -.nav { - margin-left: 20%; -} -#main-nav { - background-color: red; - border: 1px solid #00ff77; -} - -div#content -h1 + p { - padding-top: 0; - margin-top: 0; -} - -@media all and (min-width: 640px) { - #media-queries-1 { background-color: #0f0; } -} - -@media screen and (max-width: 2000px) { - #media-queries-2 { background-color: #0f0; } -} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/styles.min.css b/mrclay/minify/min_unit_tests/_test_files/css/styles.min.css deleted file mode 100644 index a71063db1e36..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/styles.min.css +++ /dev/null @@ -1,3 +0,0 @@ -@import url(/more.css);body,td,th{font-family:Verdana,"Bitstream Vera Sans",Arial Narrow,sans-serif;font-size:12px}.nav{margin-left:20%}#main-nav{background-color:red;border:1px -solid #0f7}div#content -h1+p{padding-top:0;margin-top:0}@media all and (min-width: 640px){#media-queries-1{background-color:#0f0}}@media screen and (max-width: 2000px){#media-queries-2{background-color:#0f0}} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/subsilver.css b/mrclay/minify/min_unit_tests/_test_files/css/subsilver.css deleted file mode 100644 index 492c2ec2d49b..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/subsilver.css +++ /dev/null @@ -1,434 +0,0 @@ -/* Based on the original Style Sheet for the fisubsilver v2 Theme for phpBB version 2+ -Edited by Daz - http://www.forumimages.com - last updated 26-06-03 */ -/* The content of the posts (body of text) */ -/* General page style */ - - - - /* begin suggest post */ - .float-l{ - float: left; - } - - .form-suggest{ - height:200px; - background:#DEE2D0; - vertical-align: top; - } - - .form-input input{ - font-size: 10px; - } - - .hide{ - display:none; - } - - .form-input textarea{ - font-size: 11px; - width: 350px; - } - - .form-label{ - font-size: 10px; - font-weight: bold; - line-height: 25px; - padding-right: 10px; - text-align: right; - width: 100px; - color: #39738F; - } - - .font-9{ - font-size: 9px; - } - - .form-topic{ - font-weight:bold; - - } - - .form-error{ - color:red; - } - - .inline{ - display: inline; - } - - .space-10{ - clear: both; - font-size: 10px; - height: 10px; - line-height: 10px; - } - - .suggest-success{ - color:green; - padding-left:10px; - font-size:11px; - font-weight:bold; - } - - .top{ - vertical-align: top; - } - /* end suggest post */ - -table td{ - padding:3px; -} - -a:link,a:active,a:visited,a.postlink{ - color: #006699; - text-decoration: none; -} - -a:hover{ - color: #DD6900; -} - -a.admin:hover,a.mod:hover{ - color: #DD6900; -} - -a.but,a.but:hover,a.but:visited{ - color: #000000; - text-decoration: none; -} - -a.topictitle:visited{ - color: #5493B4; -} - -a.topictitle:hover{ - color: #DD6900; -} - - - -body{ - color: #000000; - font: 11px Verdana,Arial,Helvetica,sans-serif; - margin: 0 10px 10px 10px; - padding: 0; - overflow:auto; -} - -/* General font families for common tags */ -font,th,td,p{ - font: 12px Verdana,Arial,Helvetica,sans-serif; -} - -/* Form elements */ -form{ - display: inline; -} - -hr{ - border: 0px solid #FFFFFF; - border-top-width: 1px; - height: 0px; -} - -/* Gets rid of the need for border="0" on hyperlinked images */ -img{ - border: 0 solid; -} - -input{ - font: 11px Verdana,Arial,Helvetica,sans-serif; -} - -input.button,input.liteoption,.fakebut{ - background: #FAFAFA; - border: 1px solid #000000; - font-size: 11px; -} - -input.catbutton{ - background: #FAFAFA; - border: 1px solid #000000; - font-size: 10px; -} - -input.mainoption{ - background: #FAFAFA; - border: 1px solid #000000; - font-size: 11px; - font-weight: bold; -} - -input.post,textarea.post{ - background: #FFFFFF; - border: 1px solid #000000; - font: 11px Verdana,Arial,Helvetica,sans-serif; - padding-bottom: 2px; - padding-left: 2px; -} - -select{ - background: #FFFFFF; - font: 11px Verdana,Arial,Helvetica,sans-serif; -} - -table{ - text-align: left; -} - -td{ - vertical-align: middle; -} - -/* Category gradients*/ -td.cat{ - background-color: #C2C6BA; - font-weight: bold; - height: 20px; - letter-spacing: 1px; - text-indent: 4px; -} - -td.genmed,.genmed{ - font-size: 11px; -} - -/* This is for the table cell above the Topics,Post & Last posts on the index.php */ -td.rowpic{ - background: #C2C6BA; -} - -td.spacerow{ - background: #E5E6E2; -} - -/* Table Header cells */ -th{ - background-color: #FADD31; - background-image: url(images/cellpic3.gif); - background-repeat: repeat-x; - color: #68685E; - font-size: 11px; - font-weight: bold; - line-height:16px; - height: 16px; - padding-left: 8px; - padding-right: 8px; - text-align: center; - white-space: nowrap; -} - -/* Admin & Moderator Colours MODification */ -.admin,.mod{ - font-size: 11px; - font-weight: bold; -} - -.admin,a.admin,a.admin:visited{ - color: #FFA34F; -} - -/* This is the border line & background colour round the entire page */ -.bodyline{ - background: #FFFFFF; - border: 1px solid #98AAB1; -} - -.center{ - text-align: center; -} - -/* Code blocks */ -.code{ - background: #FAFAFA; - border: 1px solid #D1D7DC; - color: #006600; - font: 12px Courier,"Courier New",sans-serif; - padding: 5px; -} - -/* This is for the error messages that pop up */ -.errorline{ - background: #E5E6E2; - border: 1px solid #8F8B8B; - color:#D92A2A; -} - -.explaintitle{ - color: #5C81B1; - font-size: 11px; - font-weight: bold; -} - -/* This is the outline round the main forum tables */ -.forumline{ - background: #FFFFFF; -} - -/* General text */ -.gensmall{ - font-size: 10px; -} - -.h1-font{ - color: #006699; - display: inline; - font: bold 13px Verdana, Arial, Helvetica, sans-serif; - margin: 0; - text-decoration: none; -} - -.h2-font{ - display: inline; - font-family: Verdana, Arial, Helvetica, sans-serif; - font-size: 11px; -} - -.height1{ - height: 1px; -} - -.height22{ - height: 22px; -} - -.height25{ - height: 25px; -} - -.height28{ - height: 28px; -} - -.height30{ - height: 30px; -} - -.height40{ - height: 40px; -} - -/* This is the line in the posting page which shows the rollover -help line. Colour value in row2 */ -.helpline{ - border: 0 solid; - font-size: 10px; -} - -.imgfolder{ - margin: 1px 4px 1px 4px; -} - -.imgspace{ - margin-left: 1px; - margin-right: 2px; -} - -/* Specify the space around images */ -.imgtopic,.imgicon{ - margin-left: 3px; -} - -.left{ - text-align: left; -} - -/* The largest text used in the index page title and toptic title etc. */ -.maintitle,h1,h2{ - color: #5C81B1; - font: bold 20px/120% "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif; - text-decoration: none; -} - -.maxwidth{ - width: 100%; -} - -.mod,a.mod,a.mod:visited{ - color: #006600; -} - -/* Name of poster in viewmsg.php and viewtopic.php and other places */ -.name{ - font-size: 11px; - font-weight: bold; -} - -/* Used for the navigation text,(Page 1,2,3 etc) and the navigation bar when in a forum */ -.nav{ - font-size: 11px; - font-weight: bold; -} - -.nowrap{ - white-space: nowrap; -} - -.postbody{ - font-size: 12px; - line-height: 125%; -} - -.postbody a{ - text-decoration: underline; -} - -/* Location,number of posts,post date etc */ -.postdetails{ - color: #00396A; - font-size: 10px; -} - -/* Quote blocks */ -.quote{ - background: #F3F3EF; - border: 1px solid #C2C6BA; - color: #006699; - font-size: 11px; - line-height: 125%; -} - -.right{ - text-align: right; -} - -/* Main table cell colours and backgrounds */ -.row1{ - background: #F0F0EB; -} - -.row2,.helpline{ - background: #E5E6E2; -} - -.row3{ - background: #DBDBD4; -} - -.subtitle,h2{ - font: bold 18px/180% "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif; - text-decoration: none; -} - -/* titles for the topics:could specify viewed link colour too */ -.topictitle { - color: #000000; - font-size: 11px; - font-weight: bold; -} - -.underline{ - text-decoration: underline; -} - -.top{ -vertical-align:top; -} - -.image-hspace{ -margin-right:3px; -} - -.clear{ -clear:both; -} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/subsilver.min.css b/mrclay/minify/min_unit_tests/_test_files/css/subsilver.min.css deleted file mode 100644 index f59b15a92eb6..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/subsilver.min.css +++ /dev/null @@ -1,18 +0,0 @@ -.float-l{float:left}.form-suggest{height:200px;background:#DEE2D0;vertical-align:top}.form-input -input{font-size:10px}.hide{display:none}.form-input -textarea{font-size:11px;width:350px}.form-label{font-size:10px;font-weight:bold;line-height:25px;padding-right:10px;text-align:right;width:100px;color:#39738F}.font-9{font-size:9px}.form-topic{font-weight:bold}.form-error{color:red}.inline{display:inline}.space-10{clear:both;font-size:10px;height:10px;line-height:10px}.suggest-success{color:green;padding-left:10px;font-size:11px;font-weight:bold}.top{vertical-align:top}table -td{padding:3px}a:link,a:active,a:visited,a.postlink{color:#069;text-decoration:none}a:hover{color:#DD6900}a.admin:hover,a.mod:hover{color:#DD6900}a.but,a.but:hover,a.but:visited{color:#000;text-decoration:none}a.topictitle:visited{color:#5493B4}a.topictitle:hover{color:#DD6900}body{color:#000;font:11px Verdana,Arial,Helvetica,sans-serif;margin:0 -10px 10px 10px;padding:0;overflow:auto}font,th,td,p{font:12px Verdana,Arial,Helvetica,sans-serif}form{display:inline}hr{border:0px -solid #FFF;border-top-width:1px;height:0px}img{border:0 -solid}input{font:11px Verdana,Arial,Helvetica,sans-serif}input.button,input.liteoption,.fakebut{background:#FAFAFA;border:1px -solid #000;font-size:11px}input.catbutton{background:#FAFAFA;border:1px -solid #000;font-size:10px}input.mainoption{background:#FAFAFA;border:1px -solid #000;font-size:11px;font-weight:bold}input.post,textarea.post{background:#FFF;border:1px -solid #000;font:11px Verdana,Arial,Helvetica,sans-serif;padding-bottom:2px;padding-left:2px}select{background:#FFF;font:11px Verdana,Arial,Helvetica,sans-serif}table{text-align:left}td{vertical-align:middle}td.cat{background-color:#C2C6BA;font-weight:bold;height:20px;letter-spacing:1px;text-indent:4px}td.genmed,.genmed{font-size:11px}td.rowpic{background:#C2C6BA}td.spacerow{background:#E5E6E2}th{background-color:#FADD31;background-image:url(images/cellpic3.gif);background-repeat:repeat-x;color:#68685E;font-size:11px;font-weight:bold;line-height:16px;height:16px;padding-left:8px;padding-right:8px;text-align:center;white-space:nowrap}.admin,.mod{font-size:11px;font-weight:bold}.admin,a.admin,a.admin:visited{color:#FFA34F}.bodyline{background:#FFF;border:1px -solid #98AAB1}.center{text-align:center}.code{background:#FAFAFA;border:1px -solid #D1D7DC;color:#060;font:12px Courier,"Courier New",sans-serif;padding:5px}.errorline{background:#E5E6E2;border:1px -solid #8F8B8B;color:#D92A2A}.explaintitle{color:#5C81B1;font-size:11px;font-weight:bold}.forumline{background:#FFF}.gensmall{font-size:10px}.h1-font{color:#069;display:inline;font:bold 13px Verdana,Arial,Helvetica,sans-serif;margin:0;text-decoration:none}.h2-font{display:inline;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px}.height1{height:1px}.height22{height:22px}.height25{height:25px}.height28{height:28px}.height30{height:30px}.height40{height:40px}.helpline{border:0 -solid;font-size:10px}.imgfolder{margin:1px -4px 1px 4px}.imgspace{margin-left:1px;margin-right:2px}.imgtopic,.imgicon{margin-left:3px}.left{text-align:left}.maintitle,h1,h2{color:#5C81B1;font:bold 20px/120% "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif;text-decoration:none}.maxwidth{width:100%}.mod,a.mod,a.mod:visited{color:#060}.name{font-size:11px;font-weight:bold}.nav{font-size:11px;font-weight:bold}.nowrap{white-space:nowrap}.postbody{font-size:12px;line-height:125%}.postbody -a{text-decoration:underline}.postdetails{color:#00396A;font-size:10px}.quote{background:#F3F3EF;border:1px -solid #C2C6BA;color:#069;font-size:11px;line-height:125%}.right{text-align:right}.row1{background:#F0F0EB}.row2,.helpline{background:#E5E6E2}.row3{background:#DBDBD4}.subtitle,h2{font:bold 18px/180% "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif;text-decoration:none}.topictitle{color:#000;font-size:11px;font-weight:bold}.underline{text-decoration:underline}.top{vertical-align:top}.image-hspace{margin-right:3px}.clear{clear:both} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.css b/mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.css deleted file mode 100644 index e2f7f9014946..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.css +++ /dev/null @@ -1,10 +0,0 @@ -/* test unusual, but valid strings in CSS */ - -foo[attr="multiple spaces"] { - content: "Hello World!"; -} - -foo[attr="Hel\ -lo"] { - content: " \"World\""; -} diff --git a/mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.min.css b/mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.min.css deleted file mode 100644 index 4b7d97e45566..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/unusual_strings.min.css +++ /dev/null @@ -1,2 +0,0 @@ -foo[attr="multiple spaces"]{content:"Hello World!"}foo[attr="Hel\ -lo"]{content:" \"World\""} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/vladmirated.css b/mrclay/minify/min_unit_tests/_test_files/css/vladmirated.css deleted file mode 100644 index 819835e582ce..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/vladmirated.css +++ /dev/null @@ -1,658 +0,0 @@ -/* from http://www.vladimirated.com/web-development-minify-css-using-php-and-cssmin-class */ - - #comments_inviter #close_me { - clear: both; - text-align: center; - border-top: 1px solid #eeeeee; - padding-top: 10px; - } - - #comments_inviter #close_me span { - color: #108eed; - cursor: pointer; - font-weight: bold; - } - - #comments_inviter img { - float: left; - margin-right: 3px; - margin-bottom: 10px; - } - - #comments_inviter { - width: 200px; - background-color: #FFFFFF; - border: 4px solid #eeeeee; - font-size: 10px; - font-family: verdana; - padding: 10px; - color: #333333; - } - - .one_com { - background-color: #FAFAFA; - padding: 10px; - margin-bottom: 20px; - border: 1px solid #EEEEEE; - } - - .one_com .com_says, .one_com .com_det { - text-transform: lowercase; - color: #333333; - padding: 0px; - font-family: verdana; - margin: 0px; - font-size: 13px; - font-weight: bold; - } - - .flvPlayer { - text-align: center; - border: 5px solid #dddddd; - width: 320px; - } - - .one_com .com_det { - font-size: 10px; - font-weight: normal; - margin-bottom: 20px; - padding-bottom: 10px; - border-bottom: 8px solid #eeeeee; - } - - .one_com .com_det a { - text-decoration: none; - } - - .one_com .com_txt { - background-color: #ffffff; - margin-bottom: 10px; - border-bottom: 2px solid #eeeeee - } - - .one_com .com_txt p { - font-family: verdana; - font-size: 13px; - color: #777777; - margin: 0px; - padding: 5px; - padding-bottom: 10px; - text-transform: lowercase; - } - - .one_com .com_says a { - color: #333333; - } - - .one_com .com_det a { - color: #333333; - } - - .post_box .related_posts { - - } - - .post_box .related_posts p { - padding: 0px; - margin: 0px; - padding-bottom: 20px; - padding-left: 35px; - font-family: verdana; - - } - - .post_box .related_posts a { - color: #108eed; - } - - .post_nav_2 p { - - text-align: center; - color: #cccccc; - font-family: verdana; - } - - .post_box .related_posts h3, #comments_box #respond, .comments_posted h3 { - padding: 0px; - margin: 0px; - font-size: 18px; - color: #FF8000; - padding-top: 30px; - margin-bottom: 20px; - width: 300px; - border-bottom: 5px solid #e0e0e0; - } - - .comments_posted { - - margin-bottom: 50px; - - } - - .comments_posted h3 { - padding: 0px; - margin: 0px; - margin-bottom: 20px; - - } - - .cmt_txtarea { - width: 300px; - height: 100px; - - } - - #comments_box #respond { - - padding-top: 0px; - margin-bottom: 0px; - - } - - .pagetitle { - color: #65DA33; - text-align: center; - } - - #searchform { - padding: 0px; - margin: 0px; - } - - .si { - background-color: #FFFFEE; - border: 1px solid #e0e0e0; - } - - #rightcol #r_news, #rightcol #linksbro, #rightcol #quick_tags { - margin-top: 30px; - padding-bottom: 10px; - } - - #post_nav p { - padding: 0px; - margin: 0px; - padding-bottom: 5px; - } - - #post_nav { - text-align: left; - padding-bottom: 15px; - } - - #post_nav a, .post_nav_2 p a { - text-decoration: none; - font-family: Verdana; - font-size: 12px; - color: #108eed; - } - - #post_nav a:hover, .post_nav_2 p a:hover { - text-decoration: underline; - color: #FF8000; - } - - #rightcol #about { - padding-bottom: 10px; - } - - #rightcol #r_news input { - color: #333333; - font-size: 12px; - } - - #header { - height: 200px; - width: 100%; - background-image: url('images/header_bg.jpg'); - background-repeat: x-repeat; - } - - #header img { - - float: right; - margin-right: -3px; - z-index: 100; - - } - - .tags { - text-transform: lowercase; - color: #333333; - font-family: arial; - font-size: 12px; - border-top: 2px dotted #EEEEEE; - width: 300px; - padding-top: 20px; - padding-bottom: 0px; - margin-top: 0px; - padding-left: 20px; - padding-right: 20px; - } - - .tags a { - color: #108eed; - } - - .tags p { - text-align: left; - margin: 0px; - padding: 0px; - } - - blockquote strong { - font-family: verdana; - display: block; - margin-top: 10px; - color: #FF0000; - font-style: italic; - text-align: right; - } - - blockquote { - margin: 0px; - background-color: #eeeeee; - border: 2px solid #dddddd; - padding: 24px; - padding-top: 10px; - padding-left: 60px; - padding-bottom: 10px; - font-size: 13px; - color: #333333; - margin-bottom: 30px; - margin-top: 10px; - } - - - html>body #header img { margin-right: 0px; } - - #subscribe h3 { - color: #ff0000; - margin-top: 30px; - padding: 20px; - } - - .post_actions a{ - color: #108eed; - } - - .post_actions { - border-top: 4px solid #DDDDDD; - border-bottom: 1px solid #EEEEEE; - text-align: center; - background-color: #FFFFDd; - color: #dddddd; - white-space: no-wrap; - padding-left: 20px; - padding-bottom: 5px; - text-transform: capitalize; - } - - #subscribe td { - color: #333333; - font-size: 12px; - text-transform: lowercase; - } - - #subscribe input { - font-size: 13px; - color: #333333; - } - - .post_content { - font-size: 13px; - margin-top: 10px; - padding-bottom: 10px; - text-align: justify; - font-family: verdana; - } - - .post_content p { - margin: 0px; - padding: 0px; - padding-bottom: 20px; - line-height: 20px; - } - - #header h1 { - z-index: 200; - margin: 0px; - position: absolute; - float: left; - text-transform: lowercase; - padding: 0px; - font-size: 45px; - margin-top: 70px; - margin-left: 40px; - - } - - #header h1 a { - white-space: no-wrap; - text-decoration: none; - color: #FAFAFA; - display: block - } - - #header h1 a:hover { - color: #FAFAFA; - border-bottom: 3px dotted #FAFAFA; - } - - html>body #header h1 { margin-left: 60px; } - - body { - margin: 0px; - padding: 0px; - height: 100%; - width: 100%; - font-family: 'Lucida Sans Unicode', 'Lucida Grande', Sans-Serif, Verdana, Arial; - font-size: 12px; - } - - #leftcol { - float: left; - width: 200px; - margin-left: 0px; - margin-top: 17px; - color: #000; - padding: 3px; - height: 100%; - } - - #leftcol .box_head h3 { - text-transform: uppercase; - padding: 0px; - margin: 0px; - font-family: georgia; - font-size: 18px; - color: #dddddd; - border-top: 4px solid #dddddd; - border-bottom: 4px solid #cccccc; - padding-left: 10px; - padding-top: 10px; - padding-bottom: 10px; - background-image: url('images/stripesbg.png'); - margin-bottom: 10px; - } - - #leftcol .box_head input { - text-transform: lowercase; - color: #333333; - } - - #leftcol .box_head { - margin-left: 7px; - background-color: #ffefd4; - border-bottom: 2px solid #eeeeee; - padding-bottom: 20px; - margin-bottom: 30px; - } - - #leftcol .box_head p a { - color: #0a2d4d; - display: block; - text-decoration: none; - border-bottom: 3px solid #fefefe; - padding-top: 20px; - text-transform: lowercase; - padding-bottom: 20px; - padding-left: 5px; - padding-right: 5px; - } - - #leftcol .box_head p a:hover { - background-color: #fafafa; - border-bottom: 3px solid #eeeeee; - color: #000000; - } - - #leftcol .box_head p { - text-align: left; - margin: 0px; - width: 170px; - padding-bottom: 0px; - padding-top: 0px; - font-size: 11px; - } - - #rightcol { - position: absolute; - left: 77%; - top: 278px; - border: 3px solid #eeeeee; - width: 200px; - z-index: 3; - color: #333333; - padding: 10px; - text-transform: lowercase; - - } - - #rightcol p { - padding: 0px; - marging: 0px; - text-align: justify; - } - - #rightcol #about img, #rightcol #linksbro img { - border: 5px solid #eeeeee; - } - - #rightcol #about h3, #rightcol #r_news h3, #rightcol #linksbro h3, #rightcol #quick_tags h3 { - background-color: #fafafa; - border: 1px dotted #e0e0e0; - font-size: 14px; - color: #104bbc; - padding: 5px; - padding-top: 10px; - font-family: Arial; - padding-bottom: 10px; - } - - #rightcol #about p a, #rightcol #r_news p a, #rightcol #linksbro p a { - color: #108eed; - } - - #rightcol #about p, #rightcol #r_news p, #rightcol #linksbro p { - font-size: 12px; - text-align: left; - } - - #content_warp { - margin: 20px 25% 0 215px; - padding: 3px; - color: #000; - background-color: #ededed; - } - - #content { - margin: 5px; - background-color: #FFFFFF; - padding: 10px; - } - - - #footer { - width: 99%; - margin-top: 30px; - height: 98px; - background-color: #101b1d; - } - - #footer td a { - color: #FF8000; - } - - #footer td a img { - border: 2px solid #108eed; - } - - #footer td p { - font-family: Verdana; - font-size: 10px; - color: #c0c0c0; - padding: 0px; - margin: 0px; - text-align: center; - padding-bottom: 10px; - } - - .s_offer { - color: #65DA33; - font-size: 20px; - font-weight: bold; - font-style: normal; - } - - .post_box { - text-transform: lowercase; - margin-bottom: 40px; - } - - #newsletter_box { - text-transform: lowercase; - margin-bottom: 10px; - margin-top: 30px; - font-style: normal; - background-color: #ffffff; - border: 5px solid #dddddd; - } - - #newsletter_head { - color: #EEEEEE; - font-family: Georgia; - background-image: url('images/stripesbg.png'); - padding: 10px; - padding-left: 30px; - border-bottom: 5px solid #dddddd; - } - - #newsletter_body { - color: #333333; - font-family: Verdana; - text-align: justify; - background-color: #FFFFFF; - padding: 10px; - font-size: 13px; - } - - .s_offer { - color: #65DA33; - font-size: 26px; - font-weight: bold; - font-style: normal; - } - - .post_title a { - color: #EEEEEE; - text-decoration: none; - } - - .post_title a:hover { - color: #c0c0c0; - } - - .post_title { - background-image: url('images/stripe_post.png'); - text-transform: uppercase; - font-size: 18px; - font-family: georgia; - padding: 10px; - border-top: 4px solid #c0c0c0; - margin: 0px; - border-bottom: 2px solid #ffffdd; - } - - .post_det { - text-transform: none; - margin: 0px; - border-top: 1px solid #f0f0f0; - padding: 0px; - padding-top: 5px; - color: #999999; - font-size: 10px; - font-family: verdana; - margin-bottom: 20px; - background-color: #eeeeee; - padding-bottom: 5px; - padding-left: 10px; - text-align: left; - border-bottom: 2px solid #dddddd; - } - - .post_det a { - color: #999999; - text-decoration: none; - } - - - .subtle { - text-transform: lowercase; - font-size: 10px; - font-family: verdana; - color: #108eed; - text-align: justify; - } - - #top_menu #navlist, #top_menu #navlist li { - padding:0px; - margin: 0px; - padding-top: 14px; - text-transform: lowercase; - padding-bottom: 17px; - padding-left: 30px; - border-left: 1px solid #65cdef; - } - - #top_menu #navlist, #top_menu #navlist li #first { - - border-left: 0px; - - } - - #top_menu #navlist { - padding-left: 30px; - background-color: #1dabd9; - border-top: 5px solid #0e96c3; - border-bottom: 5px solid #0e96c3; - } - - #top_menu #navlist li { - color: #444444; - font-size: 10px; - display: inline; - list-style-type: none; - padding-right: 30px; - } - - #top_menu #navlist li a { - text-decoration: none; - font-family: Verdana; - color: #fafafa; - font-size: 12px; - font-weight: bold; - } - - #top_menu #navlist li a:hover { - color: #333333; - } - - .post_content a { - color: #108eed; - } - - ul#tagcloud { padding:0; margin:0; text-align:center; list-style:none; } - ul#tagcloud li { display:inline; font-size:70%; color:#ccc; background: none; padding: 0;} - ul#tagcloud li a, ul#tagcloud li a:link { text-decoration:none; } - ul#tagcloud li a:hover { text-decoration:underline; } - ul#tagcloud li.t1 a { color:#797979; font-size: 120%; } - ul#tagcloud li.t2 a { color:#6d6d6d; font-size: 160%; } - ul#tagcloud li.t3 a { color:#616161; font-size: 190%; } - ul#tagcloud li.t4 a { color:#555555; font-size: 210%; } - ul#tagcloud li.t5 a { color:#484848; font-size: 230%; } - ul#tagcloud li.t6 a { color:#3c3c3c; font-size: 250%; } - ul#tagcloud li.t7 a { color:#303030; font-size: 270%; } - ul#tagcloud li.t8 a { color:#242424; font-size: 290%; } - ul#tagcloud li.t9 a { color:#181818; font-size: 310%; } - ul#tagcloud li.t10 a { color:#0c0c0c; font-size: 330%; } \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css/vladmirated.min.css b/mrclay/minify/min_unit_tests/_test_files/css/vladmirated.min.css deleted file mode 100644 index a59e5001b534..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css/vladmirated.min.css +++ /dev/null @@ -1,79 +0,0 @@ -#comments_inviter -#close_me{clear:both;text-align:center;border-top:1px solid #eee;padding-top:10px}#comments_inviter #close_me -span{color:#108eed;cursor:pointer;font-weight:bold}#comments_inviter -img{float:left;margin-right:3px;margin-bottom:10px}#comments_inviter{width:200px;background-color:#FFF;border:4px -solid #eee;font-size:10px;font-family:verdana;padding:10px;color:#333}.one_com{background-color:#FAFAFA;padding:10px;margin-bottom:20px;border:1px -solid #EEE}.one_com .com_says, .one_com -.com_det{text-transform:lowercase;color:#333;padding:0px;font-family:verdana;margin:0px;font-size:13px;font-weight:bold}.flvPlayer{text-align:center;border:5px -solid #ddd;width:320px}.one_com -.com_det{font-size:10px;font-weight:normal;margin-bottom:20px;padding-bottom:10px;border-bottom:8px solid #eee}.one_com .com_det -a{text-decoration:none}.one_com -.com_txt{background-color:#fff;margin-bottom:10px;border-bottom:2px solid #eee}.one_com .com_txt -p{font-family:verdana;font-size:13px;color:#777;margin:0px;padding:5px;padding-bottom:10px;text-transform:lowercase}.one_com .com_says -a{color:#333}.one_com .com_det -a{color:#333}.post_box -.related_posts{}.post_box .related_posts -p{padding:0px;margin:0px;padding-bottom:20px;padding-left:35px;font-family:verdana}.post_box .related_posts -a{color:#108eed}.post_nav_2 -p{text-align:center;color:#ccc;font-family:verdana}.post_box .related_posts h3, #comments_box #respond, .comments_posted -h3{padding:0px;margin:0px;font-size:18px;color:#FF8000;padding-top:30px;margin-bottom:20px;width:300px;border-bottom:5px solid #e0e0e0}.comments_posted{margin-bottom:50px}.comments_posted -h3{padding:0px;margin:0px;margin-bottom:20px}.cmt_txtarea{width:300px;height:100px}#comments_box -#respond{padding-top:0px;margin-bottom:0px}.pagetitle{color:#65DA33;text-align:center}#searchform{padding:0px;margin:0px}.si{background-color:#FFE;border:1px -solid #e0e0e0}#rightcol #r_news, #rightcol #linksbro, #rightcol -#quick_tags{margin-top:30px;padding-bottom:10px}#post_nav -p{padding:0px;margin:0px;padding-bottom:5px}#post_nav{text-align:left;padding-bottom:15px}#post_nav a, .post_nav_2 p -a{text-decoration:none;font-family:Verdana;font-size:12px;color:#108eed}#post_nav a:hover, .post_nav_2 p a:hover{text-decoration:underline;color:#FF8000}#rightcol -#about{padding-bottom:10px}#rightcol #r_news -input{color:#333;font-size:12px}#header{height:200px;width:100%;background-image:url('images/header_bg.jpg');background-repeat:x-repeat}#header -img{float:right;margin-right:-3px;z-index:100}.tags{text-transform:lowercase;color:#333;font-family:arial;font-size:12px;border-top:2px dotted #EEE;width:300px;padding-top:20px;padding-bottom:0px;margin-top:0px;padding-left:20px;padding-right:20px}.tags -a{color:#108eed}.tags -p{text-align:left;margin:0px;padding:0px}blockquote -strong{font-family:verdana;display:block;margin-top:10px;color:#F00;font-style:italic;text-align:right}blockquote{margin:0px;background-color:#eee;border:2px -solid #ddd;padding:24px;padding-top:10px;padding-left:60px;padding-bottom:10px;font-size:13px;color:#333;margin-bottom:30px;margin-top:10px}html>body #header -img{margin-right:0px}#subscribe -h3{color:#f00;margin-top:30px;padding:20px}.post_actions -a{color:#108eed}.post_actions{border-top:4px solid #DDD;border-bottom:1px solid #EEE;text-align:center;background-color:#FFD;color:#ddd;white-space:no-wrap;padding-left:20px;padding-bottom:5px;text-transform:capitalize}#subscribe -td{color:#333;font-size:12px;text-transform:lowercase}#subscribe -input{font-size:13px;color:#333}.post_content{font-size:13px;margin-top:10px;padding-bottom:10px;text-align:justify;font-family:verdana}.post_content -p{margin:0px;padding:0px;padding-bottom:20px;line-height:20px}#header -h1{z-index:200;margin:0px;position:absolute;float:left;text-transform:lowercase;padding:0px;font-size:45px;margin-top:70px;margin-left:40px}#header h1 -a{white-space:no-wrap;text-decoration:none;color:#FAFAFA;display:block}#header h1 a:hover{color:#FAFAFA;border-bottom:3px dotted #FAFAFA}html>body #header -h1{margin-left:60px}body{margin:0px;padding:0px;height:100%;width:100%;font-family:'Lucida Sans Unicode','Lucida Grande',Sans-Serif,Verdana,Arial;font-size:12px}#leftcol{float:left;width:200px;margin-left:0px;margin-top:17px;color:#000;padding:3px;height:100%}#leftcol .box_head -h3{text-transform:uppercase;padding:0px;margin:0px;font-family:georgia;font-size:18px;color:#ddd;border-top:4px solid #ddd;border-bottom:4px solid #ccc;padding-left:10px;padding-top:10px;padding-bottom:10px;background-image:url('images/stripesbg.png');margin-bottom:10px}#leftcol .box_head -input{text-transform:lowercase;color:#333}#leftcol -.box_head{margin-left:7px;background-color:#ffefd4;border-bottom:2px solid #eee;padding-bottom:20px;margin-bottom:30px}#leftcol .box_head p -a{color:#0a2d4d;display:block;text-decoration:none;border-bottom:3px solid #fefefe;padding-top:20px;text-transform:lowercase;padding-bottom:20px;padding-left:5px;padding-right:5px}#leftcol .box_head p a:hover{background-color:#fafafa;border-bottom:3px solid #eee;color:#000}#leftcol .box_head -p{text-align:left;margin:0px;width:170px;padding-bottom:0px;padding-top:0px;font-size:11px}#rightcol{position:absolute;left:77%;top:278px;border:3px -solid #eee;width:200px;z-index:3;color:#333;padding:10px;text-transform:lowercase}#rightcol -p{padding:0px;marging:0px;text-align:justify}#rightcol #about img, #rightcol #linksbro -img{border:5px -solid #eee}#rightcol #about h3, #rightcol #r_news h3, #rightcol #linksbro h3, #rightcol #quick_tags -h3{background-color:#fafafa;border:1px -dotted #e0e0e0;font-size:14px;color:#104bbc;padding:5px;padding-top:10px;font-family:Arial;padding-bottom:10px}#rightcol #about p a, #rightcol #r_news p a, #rightcol #linksbro p -a{color:#108eed}#rightcol #about p, #rightcol #r_news p, #rightcol #linksbro -p{font-size:12px;text-align:left}#content_warp{margin:20px -25% 0 215px;padding:3px;color:#000;background-color:#ededed}#content{margin:5px;background-color:#FFF;padding:10px}#footer{width:99%;margin-top:30px;height:98px;background-color:#101b1d}#footer td -a{color:#FF8000}#footer td a -img{border:2px -solid #108eed}#footer td -p{font-family:Verdana;font-size:10px;color:#c0c0c0;padding:0px;margin:0px;text-align:center;padding-bottom:10px}.s_offer{color:#65DA33;font-size:20px;font-weight:bold;font-style:normal}.post_box{text-transform:lowercase;margin-bottom:40px}#newsletter_box{text-transform:lowercase;margin-bottom:10px;margin-top:30px;font-style:normal;background-color:#fff;border:5px -solid #ddd}#newsletter_head{color:#EEE;font-family:Georgia;background-image:url('images/stripesbg.png');padding:10px;padding-left:30px;border-bottom:5px solid #ddd}#newsletter_body{color:#333;font-family:Verdana;text-align:justify;background-color:#FFF;padding:10px;font-size:13px}.s_offer{color:#65DA33;font-size:26px;font-weight:bold;font-style:normal}.post_title -a{color:#EEE;text-decoration:none}.post_title a:hover{color:#c0c0c0}.post_title{background-image:url('images/stripe_post.png');text-transform:uppercase;font-size:18px;font-family:georgia;padding:10px;border-top:4px solid #c0c0c0;margin:0px;border-bottom:2px solid #ffd}.post_det{text-transform:none;margin:0px;border-top:1px solid #f0f0f0;padding:0px;padding-top:5px;color:#999;font-size:10px;font-family:verdana;margin-bottom:20px;background-color:#eee;padding-bottom:5px;padding-left:10px;text-align:left;border-bottom:2px solid #ddd}.post_det -a{color:#999;text-decoration:none}.subtle{text-transform:lowercase;font-size:10px;font-family:verdana;color:#108eed;text-align:justify}#top_menu #navlist, #top_menu #navlist -li{padding:0px;margin:0px;padding-top:14px;text-transform:lowercase;padding-bottom:17px;padding-left:30px;border-left:1px solid #65cdef}#top_menu #navlist, #top_menu #navlist li -#first{border-left:0px}#top_menu -#navlist{padding-left:30px;background-color:#1dabd9;border-top:5px solid #0e96c3;border-bottom:5px solid #0e96c3}#top_menu #navlist -li{color:#444;font-size:10px;display:inline;list-style-type:none;padding-right:30px}#top_menu #navlist li -a{text-decoration:none;font-family:Verdana;color:#fafafa;font-size:12px;font-weight:bold}#top_menu #navlist li a:hover{color:#333}.post_content -a{color:#108eed}ul#tagcloud{padding:0;margin:0;text-align:center;list-style:none}ul#tagcloud -li{display:inline;font-size:70%;color:#ccc;background:none;padding:0}ul#tagcloud li a, ul#tagcloud li a:link{text-decoration:none}ul#tagcloud li a:hover{text-decoration:underline}ul#tagcloud li.t1 -a{color:#797979;font-size:120%}ul#tagcloud li.t2 -a{color:#6d6d6d;font-size:160%}ul#tagcloud li.t3 -a{color:#616161;font-size:190%}ul#tagcloud li.t4 -a{color:#555;font-size:210%}ul#tagcloud li.t5 -a{color:#484848;font-size:230%}ul#tagcloud li.t6 -a{color:#3c3c3c;font-size:250%}ul#tagcloud li.t7 -a{color:#303030;font-size:270%}ul#tagcloud li.t8 -a{color:#242424;font-size:290%}ul#tagcloud li.t9 -a{color:#181818;font-size:310%}ul#tagcloud li.t10 -a{color:#0c0c0c;font-size:330%} \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp.css b/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp.css deleted file mode 100644 index 22c109f842ab..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp.css +++ /dev/null @@ -1,17 +0,0 @@ -@import "/_test_files/css_uriRewriter/foo.css"; -@import '/_test_files/css_uriRewriter/bar/foo.css' print; -@import '/_test_files/bar/foo.css' print; -@import '/foo.css' print; -@import '/css/foo.css'; /* abs, should not alter */ -@import 'http://foo.com/css/foo.css'; /* scheme, should not alter */ -@import url(/_test_files/foo.css) tv, projection; -@import url("/css/foo.css"); /* abs, should not alter */ -@import url(/css2/foo.css); /* abs, should not alter */ -@import url(foo:bar); /* scheme, should not alter */ -foo {background:url('/_test_files/css_uriRewriter/bar/foo.png')} -foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter */ -foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ -foo {background:url(foo:bar);} /* scheme, should not alter */ -foo {background:url("/_test_files/css_uriRewriter/foo bar.jpg");} -@import url('/_test_files/css_uriRewriter/foo bar.css'); -@import "/_test_files/css_uriRewriter/foo bar.css"; diff --git a/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend.css b/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend.css deleted file mode 100644 index ce31df1b7ca2..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend.css +++ /dev/null @@ -1,17 +0,0 @@ -@import "http://cnd.com/A/B/foo.css"; -@import 'http://cnd.com/A/B/bar/foo.css' print; -@import 'http://cnd.com/A/bar/foo.css' print; -@import 'http://cnd.com/foo.css' print; -@import '/css/foo.css'; /* abs, should not alter */ -@import 'http://foo.com/css/foo.css'; /* scheme, should not alter */ -@import url(http://cnd.com/A/foo.css) tv, projection; -@import url("/css/foo.css"); /* abs, should not alter */ -@import url(/css2/foo.css); /* abs, should not alter */ -@import url(foo:bar); /* scheme, should not alter */ -foo {background:url('http://cnd.com/A/B/bar/foo.png')} -foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter */ -foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ -foo {background:url(foo:bar);} /* scheme, should not alter */ -foo {background:url("http://cnd.com/A/B/foo bar.jpg");} -@import url('http://cnd.com/A/B/foo bar.css'); -@import "http://cnd.com/A/B/foo bar.css"; diff --git a/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend2.css b/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend2.css deleted file mode 100644 index 087d94ddd004..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/exp_prepend2.css +++ /dev/null @@ -1,17 +0,0 @@ -@import "//cnd.com/A/B/foo.css"; -@import '//cnd.com/A/B/bar/foo.css' print; -@import '//cnd.com/A/bar/foo.css' print; -@import '//cnd.com/foo.css' print; -@import '/css/foo.css'; /* abs, should not alter */ -@import 'http://foo.com/css/foo.css'; /* scheme, should not alter */ -@import url(//cnd.com/A/foo.css) tv, projection; -@import url("/css/foo.css"); /* abs, should not alter */ -@import url(/css2/foo.css); /* abs, should not alter */ -@import url(foo:bar); /* scheme, should not alter */ -foo {background:url('//cnd.com/A/B/bar/foo.png')} -foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter */ -foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ -foo {background:url(foo:bar);} /* scheme, should not alter */ -foo {background:url("//cnd.com/A/B/foo bar.jpg");} -@import url('//cnd.com/A/B/foo bar.css'); -@import "//cnd.com/A/B/foo bar.css"; diff --git a/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/in.css b/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/in.css deleted file mode 100644 index 3bdce3605a1e..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/css_uriRewriter/in.css +++ /dev/null @@ -1,17 +0,0 @@ -@import "foo.css"; -@import 'bar/foo.css' print; -@import '../bar/foo.css' print; -@import '../../foo.css' print; -@import '/css/foo.css'; /* abs, should not alter */ -@import 'http://foo.com/css/foo.css'; /* scheme, should not alter */ -@import url(../foo.css) tv, projection; -@import url("/css/foo.css"); /* abs, should not alter */ -@import url(/css2/foo.css); /* abs, should not alter */ -@import url(foo:bar); /* scheme, should not alter */ -foo {background:url('bar/foo.png')} -foo {background:url('http://foo.com/css/foo.css');} /* scheme, should not alter */ -foo {background:url("//foo.com/css/foo.css");} /* protocol relative, should not alter */ -foo {background:url(foo:bar);} /* scheme, should not alter */ -foo {background:url("foo bar.jpg");} -@import url('foo bar.css'); -@import "foo bar.css"; diff --git a/mrclay/minify/min_unit_tests/_test_files/html/before.html b/mrclay/minify/min_unit_tests/_test_files/html/before.html deleted file mode 100644 index 3b06d1815529..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/html/before.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - css Zen Garden: The Beauty in CSS Design - - - - - - - - - - - - -

    Browser != IE

    -
    - -
    -	White  space  is  important   here!
    -		
    -
    -

    A demonstration of what can be accomplished visually through CSS-based design. Select any style sheet from the list to load it into this page.

    -

    Download the sample html file and css file

    -
    - -
    - - \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/html/before.min.html b/mrclay/minify/min_unit_tests/_test_files/html/before.min.html deleted file mode 100644 index 7ec603d9e213..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/html/before.min.html +++ /dev/null @@ -1,38 +0,0 @@ -css Zen Garden: The Beauty in CSS Design -

    Browser != IE

    css Zen Garden

    The Beauty of CSS -Design

    -	White  space  is  important   here!
    -		

    A demonstration of what can be accomplished visually through CSS-based design. Select any style sheet from the list to load it into this page.

    Download the sample html file and css file

    \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/html/before2.html b/mrclay/minify/min_unit_tests/_test_files/html/before2.html deleted file mode 100644 index 9592371cd220..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/html/before2.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - css Zen Garden: The Beauty in CSS Design - - - - - - - - - - - - -

    Browser != IE

    -
    - -
    -	White  space  is  important   here!
    -		
    -
    -

    A demonstration of what can be accomplished visually through CSS-based design. Select any style sheet from the list to load it into this page.

    -

    Download the sample html file and css file

    -
    - -Preserve at least 1 char of whitespace near scripts in case of document.write(). -
    - - \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/html/before2.min.html b/mrclay/minify/min_unit_tests/_test_files/html/before2.min.html deleted file mode 100644 index 0e1680f2fe60..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/html/before2.min.html +++ /dev/null @@ -1,38 +0,0 @@ -css Zen Garden: The Beauty in CSS Design -

    Browser != IE

    css Zen Garden

    The Beauty of CSS -Design

    -	White  space  is  important   here!
    -		

    A demonstration of what can be accomplished visually through CSS-based design. Select any style sheet from the list to load it into this page.

    Download the sample html file and css file

    Preserve at least 1 char of whitespace near scripts in case of document.write().
    \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/htmlHelper_groupsConfig.php b/mrclay/minify/min_unit_tests/_test_files/htmlHelper_groupsConfig.php deleted file mode 100644 index 7f5153d99f19..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/htmlHelper_groupsConfig.php +++ /dev/null @@ -1,8 +0,0 @@ - array( - '//_test_files/css/paths_prepend.css' - ,'//_test_files/css/styles.css' - ) -); diff --git a/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/adjacent.css b/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/adjacent.css deleted file mode 100644 index da52c6949129..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/adjacent.css +++ /dev/null @@ -1,3 +0,0 @@ -/* @import url('bad.css' ) bad; */ -adjacent2 foo { background: red url(/red.gif); } -adjacent2 bar { background: url('../green.gif') } \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/tv.css b/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/tv.css deleted file mode 100644 index 69fa2f5ef337..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/1/tv.css +++ /dev/null @@ -1,4 +0,0 @@ -@import url( adjacent.css ) all; -@import '../input.css'; -tv foo { background: red url(/red.gif); } -tv bar { background: url('../green.gif') } \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/adjacent.css b/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/adjacent.css deleted file mode 100644 index fd643486db68..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/adjacent.css +++ /dev/null @@ -1,4 +0,0 @@ -@import url(../../css/styles.css); -@import url(http://example.com/hello.css); -adjacent foo { background: red url(/red.gif); } -adjacent bar { background: url('../green.gif') } \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/input.css b/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/input.css deleted file mode 100644 index b0f662272bfb..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/input.css +++ /dev/null @@ -1,5 +0,0 @@ -@import url(adjacent.css) screen; -@import "1/tv.css" tv, projection; -@import "../lib/css/example.css"; -input foo { background: red url(/red.gif); } -input bar { background: url('../green.gif') } \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/output.css b/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/output.css deleted file mode 100644 index ca7d8723690e..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/importProcessor/css/output.css +++ /dev/null @@ -1,52 +0,0 @@ -@media screen { -@charset "utf-8"; - -/* some CSS to try to exercise things in general */ - -@import url(/more.css); - - body, td, th { - font-family: Verdana , "Bitstream Vera Sans" , Arial Narrow, sans-serif ; - - font-size : 12px; -} - -.nav { - margin-left: 20%; -} -#main-nav { - background-color: red; - border: 1px solid #00ff77; -} - -div#content -h1 + p { - padding-top: 0; - margin-top: 0; -} - -@media all and (min-width: 640px) { - #media-queries-1 { background-color: #0f0; } -} - -@media screen and (max-width: 2000px) { - #media-queries-2 { background-color: #0f0; } -} -@import url(http://example.com/hello.css); -adjacent foo { background: red url(/red.gif); } -adjacent bar { background: url('../green.gif') } -} - -@media tv,projection { -/* @import url('1/bad.css') bad; */ -adjacent2 foo { background: red url(/red.gif); } -adjacent2 bar { background: url('green.gif') } -@import '../input.css'; -tv foo { background: red url(/red.gif); } -tv bar { background: url('green.gif') } -} - -input.test bar { background: url('../lib/img/green.gif') } - -input foo { background: red url(/red.gif); } -input bar { background: url('../green.gif') } \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/importProcessor/lib/css/example.css b/mrclay/minify/min_unit_tests/_test_files/importProcessor/lib/css/example.css deleted file mode 100644 index 715d86025702..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/importProcessor/lib/css/example.css +++ /dev/null @@ -1 +0,0 @@ -input.test bar { background: url('../img/green.gif') } diff --git a/mrclay/minify/min_unit_tests/_test_files/js/before.js b/mrclay/minify/min_unit_tests/_test_files/js/before.js deleted file mode 100644 index ae96568254a7..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/js/before.js +++ /dev/null @@ -1,66 +0,0 @@ -/*! is.js - - (c) 2001 Douglas Crockford - 2001 June 3 -*/ - -// is - -// The -is- object is used to identify the browser. Every browser edition -// identifies itself, but there is no standard way of doing it, and some of -// the identification is deceptive. This is because the authors of web -// browsers are liars. For example, Microsoft's IE browsers claim to be -// Mozilla 4. Netscape 6 claims to be version 5. - -var is = { - ie: navigator.appName == 'Microsoft Internet Explorer', - java: navigator.javaEnabled(), - ns: navigator.appName == 'Netscape', - ua: navigator.userAgent.toLowerCase(), - version: parseFloat(navigator.appVersion.substr(21)) || - parseFloat(navigator.appVersion), - win: navigator.platform == 'Win32' -} -/*!* - * preserve this comment, too - */ -is.mac = is.ua.indexOf('mac') >= 0; -if (is.ua.indexOf('opera') >= 0) { - is.ie = is.ns = false; - is.opera = true; -} -if (is.ua.indexOf('gecko') >= 0) { - is.ie = is.ns = false; - is.gecko = true; -} - -/*@cc_on - /*@if (@_win32) - if (is.ie && is.win) - document.write("PASS: IE/win honored conditional comment.
    "); - @else @*/ - if (is.ie && is.win) - document.write("FAIL: IE/win did not honor multi-line conditional comment.
    "); - else - document.write("PASS: Non-IE/win browser ignores multi-line conditional comment.
    "); - /*@end -@*/ - -var recognizesCondComm = true; -//@cc_on/* -recognizesCondComm = false; -//@cc_on*/ - -if ((is.ie && is.win) == recognizesCondComm) - document.write("PASS: IE/win honored single-line conditional comment.
    "); -else - document.write("FAIL: Non-IE/win browser did not ignore single-line conditional comment.
    "); - -// hello -//@cc_on/* -// world -//@cc_on*/ -//@cc_on/* -'hello'; -/*!* preserved */ -/*!* preserved */ \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/before.min.js b/mrclay/minify/min_unit_tests/_test_files/js/before.min.js deleted file mode 100644 index bccd725cfae4..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/js/before.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! is.js - - (c) 2001 Douglas Crockford - 2001 June 3 -*/ -var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaEnabled(),ns:navigator.appName=='Netscape',ua:navigator.userAgent.toLowerCase(),version:parseFloat(navigator.appVersion.substr(21))||parseFloat(navigator.appVersion),win:navigator.platform=='Win32'} -/*!* - * preserve this comment, too - */ -is.mac=is.ua.indexOf('mac')>=0;if(is.ua.indexOf('opera')>=0){is.ie=is.ns=false;is.opera=true;} -if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;}/*@cc_on - /*@if (@_win32) - if (is.ie && is.win) - document.write("PASS: IE/win honored conditional comment.
    "); - @else @*/if(is.ie&&is.win) -document.write("FAIL: IE/win did not honor multi-line conditional comment.
    ");else -document.write("PASS: Non-IE/win browser ignores multi-line conditional comment.
    ");/*@end -@*/var recognizesCondComm=true;//@cc_on/* -recognizesCondComm=false;//@cc_on*/ -if((is.ie&&is.win)==recognizesCondComm) -document.write("PASS: IE/win honored single-line conditional comment.
    ");else -document.write("FAIL: Non-IE/win browser did not ignore single-line conditional comment.
    ");//@cc_on/* -//@cc_on*/ -//@cc_on/* -'hello'; -/*!* preserved */ -/*!* preserved */ \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/before.min_plus.js b/mrclay/minify/min_unit_tests/_test_files/js/before.min_plus.js deleted file mode 100644 index 6f06c6e6ce46..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/js/before.min_plus.js +++ /dev/null @@ -1,22 +0,0 @@ -/* is.js - - (c) 2001 Douglas Crockford - 2001 June 3 -*/ -var is={ie:navigator.appName=='Microsoft Internet Explorer',java:navigator.javaEnabled(),ns:navigator.appName=='Netscape',ua:navigator.userAgent.toLowerCase(),version:parseFloat(navigator.appVersion.substr(21))||parseFloat(navigator.appVersion),win:navigator.platform=='Win32'} -/** - * preserve this comment, too - */ -is.mac=is.ua.indexOf('mac')>=0;if(is.ua.indexOf('opera')>=0){is.ie=is.ns=false;is.opera=true;} -if(is.ua.indexOf('gecko')>=0){is.ie=is.ns=false;is.gecko=true;}/*@cc_on - /*@if (@_win32) - if (is.ie && is.win) - document.write("PASS: IE/win honored conditional comment.
    "); - @else @*/if(is.ie&&is.win) -document.write("FAIL: IE/win did not honor multi-line conditional comment.
    ");else -document.write("PASS: Non-IE/win browser ignores multi-line conditional comment.
    ");/*@end -@*/var recognizesCondComm=true;//@cc_on/* -recognizesCondComm=false;//@cc_on*/ -if((is.ie&&is.win)==recognizesCondComm) -document.write("PASS: IE/win honored single-line conditional comment.
    ");else -document.write("FAIL: Non-IE/win browser did not ignore single-line conditional comment.
    "); \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/condcomm.js b/mrclay/minify/min_unit_tests/_test_files/js/condcomm.js deleted file mode 100644 index 28aa1268beed..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/js/condcomm.js +++ /dev/null @@ -1,14 +0,0 @@ -var isWin; -/*@cc_on - @if (@_win32) - isWin = true; - @else @*/ isWin = false; - /*@end -@*/ - -isWin = /*@cc_on!*/!1; - -var recognizesCondComm = true; -//@cc_on/* -recognizesCondComm = false; -//@cc_on*/ diff --git a/mrclay/minify/min_unit_tests/_test_files/js/condcomm.min_plus.js b/mrclay/minify/min_unit_tests/_test_files/js/condcomm.min_plus.js deleted file mode 100644 index d8c1ed3861ef..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/js/condcomm.min_plus.js +++ /dev/null @@ -1,13 +0,0 @@ -var isWin; -/*@cc_on - @if (@_win32) - isWin = true; - @else @*/ - isWin = false; - /*@end -@*/ - -var recognizesCondComm = true; -//@cc_on/* -recognizesCondComm = false; -//@cc_on*/ \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/issue132.js b/mrclay/minify/min_unit_tests/_test_files/js/issue132.js deleted file mode 100644 index 4ccfb1577ab4..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/js/issue132.js +++ /dev/null @@ -1,7 +0,0 @@ -// from jQuery tablesorter -ts.addParser({ - id: "currency", - is: function(s) { - return /^[£$€?.]/.test(s); - }, -}); diff --git a/mrclay/minify/min_unit_tests/_test_files/js/issue132.min.js b/mrclay/minify/min_unit_tests/_test_files/js/issue132.min.js deleted file mode 100644 index 721518701c61..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/js/issue132.min.js +++ /dev/null @@ -1 +0,0 @@ -ts.addParser({id:"currency",is:function(s){return /^[£$€?.]/.test(s);},}); \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/issue141.min.js b/mrclay/minify/min_unit_tests/_test_files/js/issue141.min.js deleted file mode 100644 index 10aa56e811f5..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/js/issue141.min.js +++ /dev/null @@ -1,3 +0,0 @@ -// The MinApp controller should cause this file to not be minified -// since the basename of the filepath matches the default noMinPattern - diff --git a/mrclay/minify/min_unit_tests/_test_files/js/issue144.js b/mrclay/minify/min_unit_tests/_test_files/js/issue144.js deleted file mode 100644 index 204911da301b..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/js/issue144.js +++ /dev/null @@ -1,9 +0,0 @@ -a / ++b; -a * --b; -a++ - b; -a + --b; -a - ++b; -a + -b; -a + ++b; -a + --b; -a - --b; \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/issue144.min.js b/mrclay/minify/min_unit_tests/_test_files/js/issue144.min.js deleted file mode 100644 index e339d0aa5813..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/js/issue144.min.js +++ /dev/null @@ -1 +0,0 @@ -a/++b;a*--b;a++-b;a+--b;a-++b;a+-b;a+ ++b;a+--b;a- --b; \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/issue256.js b/mrclay/minify/min_unit_tests/_test_files/js/issue256.js deleted file mode 100644 index 519a52f85920..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/js/issue256.js +++ /dev/null @@ -1,3 +0,0 @@ -!function(){}(window) - -!function(){}(window) \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/issue256.min.js b/mrclay/minify/min_unit_tests/_test_files/js/issue256.min.js deleted file mode 100644 index eb1b0d6ed0e4..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/js/issue256.min.js +++ /dev/null @@ -1,2 +0,0 @@ -!function(){}(window) -!function(){}(window) \ No newline at end of file diff --git a/mrclay/minify/min_unit_tests/_test_files/js/jquery-1.2.3.js b/mrclay/minify/min_unit_tests/_test_files/js/jquery-1.2.3.js deleted file mode 100644 index c5a3337600c5..000000000000 --- a/mrclay/minify/min_unit_tests/_test_files/js/jquery-1.2.3.js +++ /dev/null @@ -1,3408 +0,0 @@ -(function(){ -/*! - * jQuery 1.2.3 - New Wave Javascript - * - * Copyright (c) 2008 John Resig (jquery.com) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * $Date: 2008-02-06 00:21:25 -0500 (Wed, 06 Feb 2008) $ - * $Rev: 4663 $ - */ - -// Map over jQuery in case of overwrite -if ( window.jQuery ) - var _jQuery = window.jQuery; - -var jQuery = window.jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.prototype.init( selector, context ); -}; - -// Map over the $ in case of overwrite -if ( window.$ ) - var _$ = window.$; - -// Map the jQuery namespace to the '$' one -window.$ = jQuery; - -// A simple way to check for HTML strings or ID strings -// (both of which we optimize for) -var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/; - -// Is it a simple selector -var isSimple = /^.[^:#\[\.]*$/; - -jQuery.fn = jQuery.prototype = { - init: function( selector, context ) { - // Make sure that a selection was provided - selector = selector || document; - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this[0] = selector; - this.length = 1; - return this; - - // Handle HTML strings - } else if ( typeof selector == "string" ) { - // Are we dealing with HTML string or an ID? - var match = quickExpr.exec( selector ); - - // Verify a match, and that no context was specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) - selector = jQuery.clean( [ match[1] ], context ); - - // HANDLE: $("#id") - else { - var elem = document.getElementById( match[3] ); - - // Make sure an element was located - if ( elem ) - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id != match[3] ) - return jQuery().find( selector ); - - // Otherwise, we inject the element directly into the jQuery object - else { - this[0] = elem; - this.length = 1; - return this; - } - - else - selector = []; - } - - // HANDLE: $(expr, [context]) - // (which is just equivalent to: $(content).find(expr) - } else - return new jQuery( context ).find( selector ); - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) - return new jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector ); - - return this.setArray( - // HANDLE: $(array) - selector.constructor == Array && selector || - - // HANDLE: $(arraylike) - // Watch for when an array-like object, contains DOM nodes, is passed in as the selector - (selector.jquery || selector.length && selector != window && !selector.nodeType && selector[0] != undefined && selector[0].nodeType) && jQuery.makeArray( selector ) || - - // HANDLE: $(*) - [ selector ] ); - }, - - // The current version of jQuery being used - jquery: "1.2.3", - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - // The number of elements contained in the matched element set - length: 0, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == undefined ? - - // Return a 'clean' array - jQuery.makeArray( this ) : - - // Return just the object - this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - // Build a new jQuery matched element set - var ret = jQuery( elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Force the current matched set of elements to become - // the specified array of elements (destroying the stack in the process) - // You should use pushStack() in order to do this, but maintain the stack - setArray: function( elems ) { - // Resetting the length to 0, then using the native Array push - // is a super-fast way to populate an object with array-like properties - this.length = 0; - Array.prototype.push.apply( this, elems ); - - return this; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - var ret = -1; - - // Locate the position of the desired element - this.each(function(i){ - if ( this == elem ) - ret = i; - }); - - return ret; - }, - - attr: function( name, value, type ) { - var options = name; - - // Look for the case where we're accessing a style value - if ( name.constructor == String ) - if ( value == undefined ) - return this.length && jQuery[ type || "attr" ]( this[0], name ) || undefined; - - else { - options = {}; - options[ name ] = value; - } - - // Check to see if we're setting style values - return this.each(function(i){ - // Set all the styles - for ( name in options ) - jQuery.attr( - type ? - this.style : - this, - name, jQuery.prop( this, options[ name ], type, i, name ) - ); - }); - }, - - css: function( key, value ) { - // ignore negative width and height values - if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 ) - value = undefined; - return this.attr( key, value, "curCSS" ); - }, - - text: function( text ) { - if ( typeof text != "object" && text != null ) - return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); - - var ret = ""; - - jQuery.each( text || this, function(){ - jQuery.each( this.childNodes, function(){ - if ( this.nodeType != 8 ) - ret += this.nodeType != 1 ? - this.nodeValue : - jQuery.fn.text( [ this ] ); - }); - }); - - return ret; - }, - - wrapAll: function( html ) { - if ( this[0] ) - // The elements to wrap the target around - jQuery( html, this[0].ownerDocument ) - .clone() - .insertBefore( this[0] ) - .map(function(){ - var elem = this; - - while ( elem.firstChild ) - elem = elem.firstChild; - - return elem; - }) - .append(this); - - return this; - }, - - wrapInner: function( html ) { - return this.each(function(){ - jQuery( this ).contents().wrapAll( html ); - }); - }, - - wrap: function( html ) { - return this.each(function(){ - jQuery( this ).wrapAll( html ); - }); - }, - - append: function() { - return this.domManip(arguments, true, false, function(elem){ - if (this.nodeType == 1) - this.appendChild( elem ); - }); - }, - - prepend: function() { - return this.domManip(arguments, true, true, function(elem){ - if (this.nodeType == 1) - this.insertBefore( elem, this.firstChild ); - }); - }, - - before: function() { - return this.domManip(arguments, false, false, function(elem){ - this.parentNode.insertBefore( elem, this ); - }); - }, - - after: function() { - return this.domManip(arguments, false, true, function(elem){ - this.parentNode.insertBefore( elem, this.nextSibling ); - }); - }, - - end: function() { - return this.prevObject || jQuery( [] ); - }, - - find: function( selector ) { - var elems = jQuery.map(this, function(elem){ - return jQuery.find( selector, elem ); - }); - - return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ? - jQuery.unique( elems ) : - elems ); - }, - - clone: function( events ) { - // Do the clone - var ret = this.map(function(){ - if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) { - // IE copies events bound via attachEvent when - // using cloneNode. Calling detachEvent on the - // clone will also remove the events from the orignal - // In order to get around this, we use innerHTML. - // Unfortunately, this means some modifications to - // attributes in IE that are actually only stored - // as properties will not be copied (such as the - // the name attribute on an input). - var clone = this.cloneNode(true), - container = document.createElement("div"); - container.appendChild(clone); - return jQuery.clean([container.innerHTML])[0]; - } else - return this.cloneNode(true); - }); - - // Need to set the expando to null on the cloned set if it exists - // removeData doesn't work here, IE removes it from the original as well - // this is primarily for IE but the data expando shouldn't be copied over in any browser - var clone = ret.find("*").andSelf().each(function(){ - if ( this[ expando ] != undefined ) - this[ expando ] = null; - }); - - // Copy the events from the original to the clone - if ( events === true ) - this.find("*").andSelf().each(function(i){ - if (this.nodeType == 3) - return; - var events = jQuery.data( this, "events" ); - - for ( var type in events ) - for ( var handler in events[ type ] ) - jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data ); - }); - - // Return the cloned set - return ret; - }, - - filter: function( selector ) { - return this.pushStack( - jQuery.isFunction( selector ) && - jQuery.grep(this, function(elem, i){ - return selector.call( elem, i ); - }) || - - jQuery.multiFilter( selector, this ) ); - }, - - not: function( selector ) { - if ( selector.constructor == String ) - // test special case where just one selector is passed in - if ( isSimple.test( selector ) ) - return this.pushStack( jQuery.multiFilter( selector, this, true ) ); - else - selector = jQuery.multiFilter( selector, this ); - - var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType; - return this.filter(function() { - return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector; - }); - }, - - add: function( selector ) { - return !selector ? this : this.pushStack( jQuery.merge( - this.get(), - selector.constructor == String ? - jQuery( selector ).get() : - selector.length != undefined && (!selector.nodeName || jQuery.nodeName(selector, "form")) ? - selector : [selector] ) ); - }, - - is: function( selector ) { - return selector ? - jQuery.multiFilter( selector, this ).length > 0 : - false; - }, - - hasClass: function( selector ) { - return this.is( "." + selector ); - }, - - val: function( value ) { - if ( value == undefined ) { - - if ( this.length ) { - var elem = this[0]; - - // We need to handle select boxes special - if ( jQuery.nodeName( elem, "select" ) ) { - var index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type == "select-one"; - - // Nothing was selected - if ( index < 0 ) - return null; - - // Loop through all the selected options - for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { - var option = options[ i ]; - - if ( option.selected ) { - // Get the specifc value for the option - value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value; - - // We don't need an array for one selects - if ( one ) - return value; - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - - // Everything else, we just grab the value - } else - return (this[0].value || "").replace(/\r/g, ""); - - } - - return undefined; - } - - return this.each(function(){ - if ( this.nodeType != 1 ) - return; - - if ( value.constructor == Array && /radio|checkbox/.test( this.type ) ) - this.checked = (jQuery.inArray(this.value, value) >= 0 || - jQuery.inArray(this.name, value) >= 0); - - else if ( jQuery.nodeName( this, "select" ) ) { - var values = value.constructor == Array ? - value : - [ value ]; - - jQuery( "option", this ).each(function(){ - this.selected = (jQuery.inArray( this.value, values ) >= 0 || - jQuery.inArray( this.text, values ) >= 0); - }); - - if ( !values.length ) - this.selectedIndex = -1; - - } else - this.value = value; - }); - }, - - html: function( value ) { - return value == undefined ? - (this.length ? - this[0].innerHTML : - null) : - this.empty().append( value ); - }, - - replaceWith: function( value ) { - return this.after( value ).remove(); - }, - - eq: function( i ) { - return this.slice( i, i + 1 ); - }, - - slice: function() { - return this.pushStack( Array.prototype.slice.apply( this, arguments ) ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function(elem, i){ - return callback.call( elem, i, elem ); - })); - }, - - andSelf: function() { - return this.add( this.prevObject ); - }, - - data: function( key, value ){ - var parts = key.split("."); - parts[1] = parts[1] ? "." + parts[1] : ""; - - if ( value == null ) { - var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); - - if ( data == undefined && this.length ) - data = jQuery.data( this[0], key ); - - return data == null && parts[1] ? - this.data( parts[0] ) : - data; - } else - return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){ - jQuery.data( this, key, value ); - }); - }, - - removeData: function( key ){ - return this.each(function(){ - jQuery.removeData( this, key ); - }); - }, - - domManip: function( args, table, reverse, callback ) { - var clone = this.length > 1, elems; - - return this.each(function(){ - if ( !elems ) { - elems = jQuery.clean( args, this.ownerDocument ); - - if ( reverse ) - elems.reverse(); - } - - var obj = this; - - if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) ) - obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") ); - - var scripts = jQuery( [] ); - - jQuery.each(elems, function(){ - var elem = clone ? - jQuery( this ).clone( true )[0] : - this; - - // execute all scripts after the elements have been injected - if ( jQuery.nodeName( elem, "script" ) ) { - scripts = scripts.add( elem ); - } else { - // Remove any inner scripts for later evaluation - if ( elem.nodeType == 1 ) - scripts = scripts.add( jQuery( "script", elem ).remove() ); - - // Inject the elements into the document - callback.call( obj, elem ); - } - }); - - scripts.each( evalScript ); - }); - } -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.prototype.init.prototype = jQuery.prototype; - -function evalScript( i, elem ) { - if ( elem.src ) - jQuery.ajax({ - url: elem.src, - async: false, - dataType: "script" - }); - - else - jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); - - if ( elem.parentNode ) - elem.parentNode.removeChild( elem ); -} - -jQuery.extend = jQuery.fn.extend = function() { - // copy reference to target object - var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; - - // Handle a deep copy situation - if ( target.constructor == Boolean ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target != "object" && typeof target != "function" ) - target = {}; - - // extend jQuery itself if only one argument is passed - if ( length == 1 ) { - target = this; - i = 0; - } - - for ( ; i < length; i++ ) - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) - // Extend the base object - for ( var name in options ) { - // Prevent never-ending loop - if ( target === options[ name ] ) - continue; - - // Recurse if we're merging object values - if ( deep && options[ name ] && typeof options[ name ] == "object" && target[ name ] && !options[ name ].nodeType ) - target[ name ] = jQuery.extend( target[ name ], options[ name ] ); - - // Don't bring in undefined values - else if ( options[ name ] != undefined ) - target[ name ] = options[ name ]; - - } - - // Return the modified object - return target; -}; - -var expando = "jQuery" + (new Date()).getTime(), uuid = 0, windowData = {}; - -// exclude the following css properties to add px -var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i; - -jQuery.extend({ - noConflict: function( deep ) { - window.$ = _$; - - if ( deep ) - window.jQuery = _jQuery; - - return jQuery; - }, - - // See test/unit/core.js for details concerning this function. - isFunction: function( fn ) { - return !!fn && typeof fn != "string" && !fn.nodeName && - fn.constructor != Array && /function/i.test( fn + "" ); - }, - - // check if an element is in a (or is an) XML document - isXMLDoc: function( elem ) { - return elem.documentElement && !elem.body || - elem.tagName && elem.ownerDocument && !elem.ownerDocument.body; - }, - - // Evalulates a script in a global context - globalEval: function( data ) { - data = jQuery.trim( data ); - - if ( data ) { - // Inspired by code by Andrea Giammarchi - // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html - var head = document.getElementsByTagName("head")[0] || document.documentElement, - script = document.createElement("script"); - - script.type = "text/javascript"; - if ( jQuery.browser.msie ) - script.text = data; - else - script.appendChild( document.createTextNode( data ) ); - - head.appendChild( script ); - head.removeChild( script ); - } - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); - }, - - cache: {}, - - data: function( elem, name, data ) { - elem = elem == window ? - windowData : - elem; - - var id = elem[ expando ]; - - // Compute a unique ID for the element - if ( !id ) - id = elem[ expando ] = ++uuid; - - // Only generate the data cache if we're - // trying to access or manipulate it - if ( name && !jQuery.cache[ id ] ) - jQuery.cache[ id ] = {}; - - // Prevent overriding the named cache with undefined values - if ( data != undefined ) - jQuery.cache[ id ][ name ] = data; - - // Return the named cache data, or the ID for the element - return name ? - jQuery.cache[ id ][ name ] : - id; - }, - - removeData: function( elem, name ) { - elem = elem == window ? - windowData : - elem; - - var id = elem[ expando ]; - - // If we want to remove a specific section of the element's data - if ( name ) { - if ( jQuery.cache[ id ] ) { - // Remove the section of cache data - delete jQuery.cache[ id ][ name ]; - - // If we've removed all the data, remove the element's cache - name = ""; - - for ( name in jQuery.cache[ id ] ) - break; - - if ( !name ) - jQuery.removeData( elem ); - } - - // Otherwise, we want to remove all of the element's data - } else { - // Clean up the element expando - try { - delete elem[ expando ]; - } catch(e){ - // IE has trouble directly removing the expando - // but it's ok with using removeAttribute - if ( elem.removeAttribute ) - elem.removeAttribute( expando ); - } - - // Completely remove the data cache - delete jQuery.cache[ id ]; - } - }, - - // args is for internal usage only - each: function( object, callback, args ) { - if ( args ) { - if ( object.length == undefined ) { - for ( var name in object ) - if ( callback.apply( object[ name ], args ) === false ) - break; - } else - for ( var i = 0, length = object.length; i < length; i++ ) - if ( callback.apply( object[ i ], args ) === false ) - break; - - // A special, fast, case for the most common use of each - } else { - if ( object.length == undefined ) { - for ( var name in object ) - if ( callback.call( object[ name ], name, object[ name ] ) === false ) - break; - } else - for ( var i = 0, length = object.length, value = object[0]; - i < length && callback.call( value, i, value ) !== false; value = object[++i] ){} - } - - return object; - }, - - prop: function( elem, value, type, i, name ) { - // Handle executable functions - if ( jQuery.isFunction( value ) ) - value = value.call( elem, i ); - - // Handle passing in a number to a CSS property - return value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ? - value + "px" : - value; - }, - - className: { - // internal only, use addClass("class") - add: function( elem, classNames ) { - jQuery.each((classNames || "").split(/\s+/), function(i, className){ - if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) ) - elem.className += (elem.className ? " " : "") + className; - }); - }, - - // internal only, use removeClass("class") - remove: function( elem, classNames ) { - if (elem.nodeType == 1) - elem.className = classNames != undefined ? - jQuery.grep(elem.className.split(/\s+/), function(className){ - return !jQuery.className.has( classNames, className ); - }).join(" ") : - ""; - }, - - // internal only, use is(".class") - has: function( elem, className ) { - return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1; - } - }, - - // A method for quickly swapping in/out CSS properties to get correct calculations - swap: function( elem, options, callback ) { - var old = {}; - // Remember the old values, and insert the new ones - for ( var name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - callback.call( elem ); - - // Revert the old values - for ( var name in options ) - elem.style[ name ] = old[ name ]; - }, - - css: function( elem, name, force ) { - if ( name == "width" || name == "height" ) { - var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ]; - - function getWH() { - val = name == "width" ? elem.offsetWidth : elem.offsetHeight; - var padding = 0, border = 0; - jQuery.each( which, function() { - padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0; - border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0; - }); - val -= Math.round(padding + border); - } - - if ( jQuery(elem).is(":visible") ) - getWH(); - else - jQuery.swap( elem, props, getWH ); - - return Math.max(0, val); - } - - return jQuery.curCSS( elem, name, force ); - }, - - curCSS: function( elem, name, force ) { - var ret; - - // A helper method for determining if an element's values are broken - function color( elem ) { - if ( !jQuery.browser.safari ) - return false; - - var ret = document.defaultView.getComputedStyle( elem, null ); - return !ret || ret.getPropertyValue("color") == ""; - } - - // We need to handle opacity special in IE - if ( name == "opacity" && jQuery.browser.msie ) { - ret = jQuery.attr( elem.style, "opacity" ); - - return ret == "" ? - "1" : - ret; - } - // Opera sometimes will give the wrong display answer, this fixes it, see #2037 - if ( jQuery.browser.opera && name == "display" ) { - var save = elem.style.outline; - elem.style.outline = "0 solid black"; - elem.style.outline = save; - } - - // Make sure we're using the right name for getting the float value - if ( name.match( /float/i ) ) - name = styleFloat; - - if ( !force && elem.style && elem.style[ name ] ) - ret = elem.style[ name ]; - - else if ( document.defaultView && document.defaultView.getComputedStyle ) { - - // Only "float" is needed here - if ( name.match( /float/i ) ) - name = "float"; - - name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase(); - - var getComputedStyle = document.defaultView.getComputedStyle( elem, null ); - - if ( getComputedStyle && !color( elem ) ) - ret = getComputedStyle.getPropertyValue( name ); - - // If the element isn't reporting its values properly in Safari - // then some display: none elements are involved - else { - var swap = [], stack = []; - - // Locate all of the parent display: none elements - for ( var a = elem; a && color(a); a = a.parentNode ) - stack.unshift(a); - - // Go through and make them visible, but in reverse - // (It would be better if we knew the exact display type that they had) - for ( var i = 0; i < stack.length; i++ ) - if ( color( stack[ i ] ) ) { - swap[ i ] = stack[ i ].style.display; - stack[ i ].style.display = "block"; - } - - // Since we flip the display style, we have to handle that - // one special, otherwise get the value - ret = name == "display" && swap[ stack.length - 1 ] != null ? - "none" : - ( getComputedStyle && getComputedStyle.getPropertyValue( name ) ) || ""; - - // Finally, revert the display styles back - for ( var i = 0; i < swap.length; i++ ) - if ( swap[ i ] != null ) - stack[ i ].style.display = swap[ i ]; - } - - // We should always get a number back from opacity - if ( name == "opacity" && ret == "" ) - ret = "1"; - - } else if ( elem.currentStyle ) { - var camelCase = name.replace(/\-(\w)/g, function(all, letter){ - return letter.toUpperCase(); - }); - - ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ]; - - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels - if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { - // Remember the original values - var style = elem.style.left, runtimeStyle = elem.runtimeStyle.left; - - // Put in the new values to get a computed value out - elem.runtimeStyle.left = elem.currentStyle.left; - elem.style.left = ret || 0; - ret = elem.style.pixelLeft + "px"; - - // Revert the changed values - elem.style.left = style; - elem.runtimeStyle.left = runtimeStyle; - } - } - - return ret; - }, - - clean: function( elems, context ) { - var ret = []; - context = context || document; - // !context.createElement fails in IE with an error but returns typeof 'object' - if (typeof context.createElement == 'undefined') - context = context.ownerDocument || context[0] && context[0].ownerDocument || document; - - jQuery.each(elems, function(i, elem){ - if ( !elem ) - return; - - if ( elem.constructor == Number ) - elem = elem.toString(); - - // Convert html string into DOM nodes - if ( typeof elem == "string" ) { - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ - return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? - all : - front + ">"; - }); - - // Trim whitespace, otherwise indexOf won't work as expected - var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div"); - - var wrap = - // option or optgroup - !tags.indexOf("", "" ] || - - !tags.indexOf("", "" ] || - - tags.match(/^<(thead|tbody|tfoot|colg|cap)/) && - [ 1, "", "
    " ] || - - !tags.indexOf("", "" ] || - - // matched above - (!tags.indexOf("", "" ] || - - !tags.indexOf("", "" ] || - - // IE can't serialize and \ No newline at end of file