PluginProbe
PhastPress / 1.90
PhastPress v1.90
3.12 3.11 1.75 1.76 1.77 1.78 1.79 1.80 1.81 1.82 1.83 1.84 1.85 1.86 1.87 1.88 1.89 1.90 1.91 1.92 1.93 1.94 1.95 1.96 1.97 All 119 releases
← All changes | sdk/phast.php +597 -525 1.761.90 View file →
@@ -258,9 +258,9 @@
258 258 public function getURI()
259 259 {
260 260 return $this->getEnvValue('REQUEST_URI');
261 261 }
262 - private function getEnvValue($key)
262 + public function getEnvValue($key)
263 263 {
264 264 if (isset($this->env[$key])) {
265 265 return $this->env[$key];
266 266 }
@@ -329,9 +329,9 @@
329 329 {
330 330 public static function get()
331 331 {
332 332 $request = \Kibo\Phast\HTTP\Request::fromGlobals();
333 - return ['securityToken' => null, 'retrieverMap' => [$request->getHost() => $request->getDocumentRoot()], 'httpClient' => \Kibo\Phast\HTTP\CURLClient::class, 'cache' => ['cacheRoot' => sys_get_temp_dir() . '/phast-cache-' . (new \Kibo\Phast\Common\System())->getUserId(), 'shardingDepth' => 1, 'garbageCollection' => ['maxItems' => 100, 'probability' => 0.1, 'maxAge' => 86400 * 365], 'diskCleanup' => ['maxSize' => 500 * pow(1024, 2), 'probability' => 0.02, 'portionToFree' => 0.5]], 'servicesUrl' => '/phast.php', 'serviceRequestFormat' => \Kibo\Phast\Services\ServiceRequest::FORMAT_PATH, 'compressServiceResponse' => true, 'optimizeHTMLDocumentsOnly' => true, 'outputServerSideStats' => true, 'documents' => ['maxBufferSizeToApply' => pow(1024, 2), 'baseUrl' => $request->getAbsoluteURI(), 'filters' => [\Kibo\Phast\Filters\HTML\CommentsRemoval\Filter::class => [], \Kibo\Phast\Filters\HTML\Minify\Filter::class => [], \Kibo\Phast\Filters\HTML\MinifyScripts\Filter::class => [], \Kibo\Phast\Filters\HTML\BaseURLSetter\Filter::class => [], \Kibo\Phast\Filters\HTML\ImagesOptimizationService\Tags\Filter::class => [], \Kibo\Phast\Filters\HTML\LazyImageLoading\Filter::class => [], \Kibo\Phast\Filters\HTML\CSSInlining\Filter::class => ['optimizerSizeDiffThreshold' => 1024, 'whitelist' => ['~^https?://fonts\\.googleapis\\.com/~' => ['ieCompatible' => false], '~^https?://ajax\\.googleapis\\.com/ajax/libs/jqueryui/~', '~^https?://maxcdn\\.bootstrapcdn\\.com/[^?#]*\\.css~', '~^https?://idangero\\.us/~', '~^https?://[^/]*\\.github\\.io/~', '~^https?://\\w+\\.typekit\\.net/~' => ['ieCompatible' => false], '~^https?://stackpath\\.bootstrapcdn\\.com/~', '~^https?://cdnjs\\.cloudflare\\.com/~']], \Kibo\Phast\Filters\HTML\ImagesOptimizationService\CSS\Filter::class => [], \Kibo\Phast\Filters\HTML\DelayedIFrameLoading\Filter::class => [], \Kibo\Phast\Filters\HTML\ScriptsProxyService\Filter::class => ['urlRefreshTime' => 7200], \Kibo\Phast\Filters\HTML\Diagnostics\Filter::class => ['enabled' => 'diagnostics'], \Kibo\Phast\Filters\HTML\ScriptsDeferring\Filter::class => [], \Kibo\Phast\Filters\HTML\PhastScriptsCompiler\Filter::class => []]], 'images' => ['enable-cache' => 'imgcache', 'api-mode' => false, 'factory' => \Kibo\Phast\Filters\Image\ImageFactory::class, 'maxImageInliningSize' => 512, 'whitelist' => ['~^https?://ajax\\.googleapis\\.com/ajax/libs/jqueryui/~'], 'filters' => [\Kibo\Phast\Filters\Image\ImageAPIClient\Filter::class => ['api-url' => 'https://optimize.phast.io/?service=images', 'host-name' => $request->getHost(), 'request-uri' => $request->getURI(), 'plugin-version' => 'phast-core-1.0']]], 'styles' => ['filters' => [\Kibo\Phast\Filters\Text\Decode\Filter::class => [], \Kibo\Phast\Filters\CSS\ImportsStripper\Filter::class => [], \Kibo\Phast\Filters\CSS\CSSMinifier\Filter::class => [], \Kibo\Phast\Filters\CSS\CSSURLRewriter\Filter::class => [], \Kibo\Phast\Filters\CSS\ImageURLRewriter\Filter::class => ['maxImageInliningSize' => 512], \Kibo\Phast\Filters\CSS\FontSwap\Filter::class => []]], 'logging' => ['logWriters' => [['class' => \Kibo\Phast\Logging\LogWriters\PHPError\Writer::class, 'levelMask' => \Kibo\Phast\Logging\LogLevel::EMERGENCY | \Kibo\Phast\Logging\LogLevel::ALERT | \Kibo\Phast\Logging\LogLevel::CRITICAL | \Kibo\Phast\Logging\LogLevel::ERROR | \Kibo\Phast\Logging\LogLevel::WARNING], ['enabled' => 'diagnostics', 'class' => \Kibo\Phast\Logging\LogWriters\JSONLFile\Writer::class, 'logRoot' => sys_get_temp_dir() . '/phast-logs']]], 'switches' => ['phast' => true, 'diagnostics' => false], 'scripts' => ['removeLicenseHeaders' => false, 'whitelist' => ['~^https?://' . preg_quote($request->getHost(), '~') . '/~', '~^https?://(ssl|www)\\.google-analytics\\.com/(analytics\\.js|ga\\.js|gtm/js)($|\\?)~', '~^https?://www\\.googletagmanager\\.com/~', '~^https?://www\\.googleadservices\\.com/~', '~^https?://pixel\\.adcrowd\\.com/~', '~^https?://connect\\.facebook\\.net/~', '~^https?://static\\.hotjar\\.com/~', '~^https?://v2\\.zopim\\.com/~', '~^https?://stats\\.g\\.doubleclick\\.net/dc\\.js$~', '~^https?://s\\.pinimg\\.com/~']]];
333 + return ['securityToken' => null, 'retrieverMap' => [$request->getHost() => $request->getDocumentRoot()], 'httpClient' => \Kibo\Phast\HTTP\CURLClient::class, 'cache' => ['cacheRoot' => sys_get_temp_dir() . '/phast-cache-' . (new \Kibo\Phast\Common\System())->getUserId(), 'shardingDepth' => 1, 'garbageCollection' => ['maxItems' => 100, 'probability' => 0.1, 'maxAge' => 86400 * 365], 'diskCleanup' => ['maxSize' => 500 * pow(1024, 2), 'probability' => 0.02, 'portionToFree' => 0.5]], 'servicesUrl' => '/phast.php', 'serviceRequestFormat' => \Kibo\Phast\Services\ServiceRequest::FORMAT_PATH, 'compressServiceResponse' => true, 'optimizeHTMLDocumentsOnly' => true, 'outputServerSideStats' => true, 'documents' => ['maxBufferSizeToApply' => pow(1024, 2), 'baseUrl' => $request->getAbsoluteURI(), 'filters' => [\Kibo\Phast\Filters\HTML\CommentsRemoval\Filter::class => [], \Kibo\Phast\Filters\HTML\MetaCharset\Filter::class => [], \Kibo\Phast\Filters\HTML\Minify\Filter::class => [], \Kibo\Phast\Filters\HTML\MinifyScripts\Filter::class => [], \Kibo\Phast\Filters\HTML\BaseURLSetter\Filter::class => [], \Kibo\Phast\Filters\HTML\ImagesOptimizationService\Tags\Filter::class => [], \Kibo\Phast\Filters\HTML\LazyImageLoading\Filter::class => [], \Kibo\Phast\Filters\HTML\CSSInlining\Filter::class => ['optimizerSizeDiffThreshold' => 1024, 'whitelist' => ['~^https?://fonts\\.googleapis\\.com/~' => ['ieCompatible' => false], '~^https?://ajax\\.googleapis\\.com/ajax/libs/jqueryui/~', '~^https?://maxcdn\\.bootstrapcdn\\.com/[^?#]*\\.css~', '~^https?://idangero\\.us/~', '~^https?://[^/]*\\.github\\.io/~', '~^https?://\\w+\\.typekit\\.net/~' => ['ieCompatible' => false], '~^https?://stackpath\\.bootstrapcdn\\.com/~', '~^https?://cdnjs\\.cloudflare\\.com/~']], \Kibo\Phast\Filters\HTML\ImagesOptimizationService\CSS\Filter::class => [], \Kibo\Phast\Filters\HTML\DelayedIFrameLoading\Filter::class => [], \Kibo\Phast\Filters\HTML\ScriptsProxyService\Filter::class => ['urlRefreshTime' => 7200], \Kibo\Phast\Filters\HTML\Diagnostics\Filter::class => ['enabled' => 'diagnostics'], \Kibo\Phast\Filters\HTML\ScriptsDeferring\Filter::class => [], \Kibo\Phast\Filters\HTML\PhastScriptsCompiler\Filter::class => []]], 'images' => ['enable-cache' => 'imgcache', 'api-mode' => false, 'factory' => \Kibo\Phast\Filters\Image\ImageFactory::class, 'maxImageInliningSize' => 512, 'whitelist' => ['~^https?://ajax\\.googleapis\\.com/ajax/libs/jqueryui/~'], 'filters' => [\Kibo\Phast\Filters\Image\ImageAPIClient\Filter::class => ['api-url' => 'https://optimize.phast.io/?service=images', 'host-name' => $request->getHost(), 'request-uri' => $request->getURI(), 'plugin-version' => 'phast-core-1.0']]], 'styles' => ['filters' => [\Kibo\Phast\Filters\Text\Decode\Filter::class => [], \Kibo\Phast\Filters\CSS\ImportsStripper\Filter::class => [], \Kibo\Phast\Filters\CSS\CSSMinifier\Filter::class => [], \Kibo\Phast\Filters\CSS\CSSURLRewriter\Filter::class => [], \Kibo\Phast\Filters\CSS\ImageURLRewriter\Filter::class => ['maxImageInliningSize' => 512], \Kibo\Phast\Filters\CSS\FontSwap\Filter::class => []]], 'logging' => ['logWriters' => [['class' => \Kibo\Phast\Logging\LogWriters\PHPError\Writer::class, 'levelMask' => \Kibo\Phast\Logging\LogLevel::EMERGENCY | \Kibo\Phast\Logging\LogLevel::ALERT | \Kibo\Phast\Logging\LogLevel::CRITICAL | \Kibo\Phast\Logging\LogLevel::ERROR | \Kibo\Phast\Logging\LogLevel::WARNING], ['enabled' => 'diagnostics', 'class' => \Kibo\Phast\Logging\LogWriters\JSONLFile\Writer::class, 'logRoot' => sys_get_temp_dir() . '/phast-logs']]], 'switches' => ['phast' => true, 'diagnostics' => false], 'scripts' => ['removeLicenseHeaders' => false, 'whitelist' => ['~^https?://' . preg_quote($request->getHost(), '~') . '/~']]];
334 334 }
335 335 }
336 336 namespace Kibo\Phast\Environment;
337 337
@@ -1153,10 +1153,14 @@
1153 1153 $this->client = $client;
1154 1154 }
1155 1155 public function retrieve(\Kibo\Phast\ValueObjects\URL $url)
1156 1156 {
1157 + $cdnLoop = ['Phast'];
1158 + if (!empty($_SERVER['HTTP_CDN_LOOP'])) {
1159 + $cdnLoop[] = $_SERVER['HTTP_CDN_LOOP'];
1160 + }
1157 1161 try {
1158 - $response = $this->client->get($url, ['User-Agent' => 'Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0']);
1162 + $response = $this->client->get($url, ['User-Agent' => 'Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0', 'CDN-Loop' => implode(', ', $cdnLoop)]);
1159 1163 } catch (\Exception $e) {
1160 1164 $this->logger()->warning('Caught {cls} while fetching {url}: ({code}) {message}', ['cls' => get_class($e), 'url' => (string) $url, 'code' => $e->getCode(), 'message' => $e->getMessage()]);
1161 1165 return false;
1162 1166 }
@@ -1273,13 +1277,13 @@
1273 1277 return $cb($file);
1274 1278 }
1275 1279 private function getExtensionForURL(\Kibo\Phast\ValueObjects\URL $url)
1276 1280 {
1277 - $dotPosition = strrpos($url->getPath(), '.');
1281 + $dotPosition = strrpos($url->getDecodedPath(), '.');
1278 1282 if ($dotPosition === false) {
1279 1283 return '';
1280 1284 }
1281 - return strtolower(substr($url->getPath(), $dotPosition + 1));
1285 + return strtolower(substr($url->getDecodedPath(), $dotPosition + 1));
1282 1286 }
1283 1287 private function getFileForURL(\Kibo\Phast\ValueObjects\URL $url)
1284 1288 {
1285 1289 if (!isset($this->map[$url->getHost()])) {
@@ -1286,15 +1290,15 @@
1286 1290 return false;
1287 1291 }
1288 1292 $submap = $this->map[$url->getHost()];
1289 1293 if (!is_array($submap)) {
1290 - return $this->appendNormalized($submap, $url->getPath());
1294 + return $this->appendNormalized($submap, $url->getDecodedPath());
1291 1295 }
1292 1296 $selectedPath = null;
1293 1297 $selectedRoot = null;
1294 1298 foreach ($submap as $prefix => $root) {
1295 1299 $pattern = '~^(?=/)/*?(?:' . str_replace('~', '\\~', $prefix) . ')(?<path>/*(?<=/).*)~';
1296 - if (preg_match($pattern, $url->getPath(), $match) && ($selectedPath === null || strlen($match['path']) < strlen($selectedPath))) {
1300 + if (preg_match($pattern, $url->getDecodedPath(), $match) && ($selectedPath === null || strlen($match['path']) < strlen($selectedPath))) {
1297 1301 $selectedRoot = $root;
1298 1302 $selectedPath = $match['path'];
1299 1303 }
1300 1304 }
@@ -1526,9 +1530,8 @@
1526 1530 $this->cache = $cache;
1527 1531 }
1528 1532 public function transformElements(\Traversable $elements, \Kibo\Phast\Filters\HTML\HTMLPageContext $context)
1529 1533 {
1530 - $inTags = ['pre' => 0, 'textarea' => 0];
1531 1534 foreach ($elements as $element) {
1532 1535 if ($element instanceof \Kibo\Phast\Parsing\HTML\HTMLStreamElements\Tag && $element->getTagName() === 'script' && ($content = $element->getTextContent()) !== '') {
1533 1536 $content = trim($content);
1534 1537 if ($this->isJSElement($element) && preg_match('~[()[\\]{};]\\s~', $content)) {
@@ -1800,9 +1803,10 @@
1800 1803 if (preg_match($pattern, $url)) {
1801 1804 return true;
1802 1805 }
1803 1806 }
1804 - if ($this->retriever->getCacheSalt(\Kibo\Phast\ValueObjects\URL::fromString($url))) {
1807 + $urlObject = \Kibo\Phast\ValueObjects\URL::fromString($url);
1808 + if (preg_match('~\\.(jpe?g|gif|png)$~i', $urlObject->getPath()) && $this->retriever->getCacheSalt($urlObject)) {
1805 1809 return true;
1806 1810 }
1807 1811 return false;
1808 1812 }
@@ -1894,16 +1898,9 @@
1894 1898 }
1895 1899 private function rewriteSrc(\Kibo\Phast\Parsing\HTML\HTMLStreamElements\Tag $img, \Kibo\Phast\Filters\HTML\HTMLPageContext $context, $attribute)
1896 1900 {
1897 1901 $url = $img->getAttribute($attribute);
1898 - $params = [];
1899 - foreach (['width', 'height'] as $attr) {
1900 - $value = $img->getAttribute($attr);
1901 - if (preg_match('/^[1-9][0-9]*$/', $value)) {
1902 - $params[$attr] = $value;
1903 - }
1904 - }
1905 - $newURL = $this->rewriter->rewriteUrl($url, $context->getBaseUrl(), $params);
1902 + $newURL = $this->rewriter->rewriteUrl($url, $context->getBaseUrl());
1906 1903 $img->setAttribute($attribute, $newURL);
1907 1904 }
1908 1905 private function rewriteSrcset(\Kibo\Phast\Parsing\HTML\HTMLStreamElements\Tag $img, \Kibo\Phast\Filters\HTML\HTMLPageContext $context, $attribute)
1909 1906 {
@@ -2167,9 +2164,9 @@
2167 2164 $bundlerMappings = \Kibo\Phast\Services\Bundler\ShortBundlerParamsParser::getParamsMappings();
2168 2165 $jsMappings = array_combine(array_values($bundlerMappings), array_keys($bundlerMappings));
2169 2166 $resourcesLoader = \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/resources-loader.js', "var Promise=phast.ES6Promise.Promise;phast.ResourceLoader=function(a,b){this.get=function(c){return b.get(c).then(function(d){if(typeof d!==\"string\"){throw new Error(\"response should be string\")}return d}).catch(function(){var e=a.get(c);e.then(function(f){b.set(c,f)});return e})}};phast.ResourceLoader.RequestParams={};phast.ResourceLoader.RequestParams.FaultyParams={};phast.ResourceLoader.RequestParams.fromString=function(g){try{return JSON.parse(g)}catch(h){return phast.ResourceLoader.RequestParams.FaultyParams}};phast.ResourceLoader.BundlerServiceClient=function(i,j,k){var l=phast.ResourceLoader.BundlerServiceClient.RequestsPack;var m=l.PackItem;var n;this.get=function(q){if(q===phast.ResourceLoader.RequestParams.FaultyParams){return Promise.reject(new Error(\"Parameters did not parse as JSON\"))}return new Promise(function(r,s){if(n===undefined){n=new l(j)}n.add(new m({success:r,error:s},q));setTimeout(o);if(n.toQuery().length>4500){console.log(\"[Phast] Resource loader: Pack got too big; flushing early...\");o()}})};function o(){if(n===undefined){return}var t=n;n=undefined;p(t)}function p(u){var v=phast.buildServiceUrl({serviceUrl:i,pathInfo:k},\"service=bundler&\"+u.toQuery());var w=function(){console.error(\"[Phast] Request to bundler failed with status\",y.status);console.log(\"URL:\",v);u.handleError()};var x=function(){if(y.status>=200&&y.status<300){u.handleResponse(y.responseText)}else{u.handleError()}};var y=new XMLHttpRequest;y.open(\"GET\",v);y.addEventListener(\"error\",w);y.addEventListener(\"abort\",w);y.addEventListener(\"load\",x);y.send()}};phast.ResourceLoader.BundlerServiceClient.RequestsPack=function(z){var A={};this.getLength=function(){var F=0;for(var G in A){F++}return F};this.add=function(H){var I;if(H.params.token){I=\"token=\"+H.params.token}else if(H.params.ref){I=\"ref=\"+H.params.ref}else{I=\"\"}if(!A[I]){A[I]={params:H.params,requests:[H.request]}}else{A[I].requests.push(H.request)}};this.toQuery=function(){var J=[],K=[],L=\"\";B().forEach(function(M){var N,O;for(var P in A[M].params){if(P===\"cacheMarker\"){K.push(A[M].params.cacheMarker);continue}N=z[P]?z[P]:P;if(P===\"strip-imports\"){O=encodeURIComponent(N)}else if(P===\"src\"){O=encodeURIComponent(N)+\"=\"+encodeURIComponent(C(A[M].params.src,L));L=A[M].params.src}else{O=encodeURIComponent(N)+\"=\"+encodeURIComponent(A[M].params[P])}J.push(O)}});if(K.length>0){J.unshift(\"c=\"+phast.hash(K.join(\"|\"),23045))}return E(J.join(\"&\"))};function B(){return Object.keys(A).sort(function(R,S){return Q(R,S)?1:Q(S,R)?-1:0});function Q(T,U){if(typeof A[T].params.src!==\"undefined\"&&typeof A[U].params.src!==\"undefined\"){return A[T].params.src>A[U].params.src}return T>U}}function C(V,W){var X=0,Y=Math.pow(36,2)-1;while(X<W.length&&V[X]===W[X]){X++}X=Math.min(X,Y);return D(X)+\"\"+V.substr(X)}function D(Z){var \$=[\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\",\"i\",\"j\",\"k\",\"l\",\"m\",\"n\",\"o\",\"p\",\"q\",\"r\",\"s\",\"t\",\"u\",\"v\",\"w\",\"x\",\"y\",\"z\"];var _=Z%36;var aa=Math.floor((Z-_)/36);return \$[aa]+\$[_]}function E(ba){if(!/(^|&)s=/.test(ba)){return ba}return ba.replace(/(%..)|([A-M])|([N-Z])/gi,function(ca,da,ea,fa){if(da){return ca}return String.fromCharCode(ca.charCodeAt(0)+(ea?13:-13))})}this.handleResponse=function(ga){try{var ha=JSON.parse(ga)}catch(ja){this.handleError();return}var ia=B();if(ha.length!==ia.length){console.error(\"[Phast] Requested\",ia.length,\"items from bundler, but got\",ha.length,\"response(s)\");this.handleError();return}ha.forEach(function(ka,la){if(ka.status===200){A[ia[la]].requests.forEach(function(ma){ma.success(ka.content)})}else{A[ia[la]].requests.forEach(function(na){na.error(new Error(\"Got from bundler: \"+JSON.stringify(ka)))})}})}.bind(this);this.handleError=function(){for(var oa in A){A[oa].requests.forEach(function(pa){pa.error()})}}};phast.ResourceLoader.BundlerServiceClient.RequestsPack.PackItem=function(qa,ra){this.request=qa;this.params=ra};phast.ResourceLoader.IndexedDBStorage=function(sa){var ta=phast.ResourceLoader.IndexedDBStorage;var ua=ta.logPrefix;var va=ta.requestToPromise;var wa;Ba();this.get=function(Ca){return xa(\"readonly\").then(function(Da){return va(Da.get(Ca)).catch(ya(\"reading from store\"))})};this.store=function(Ea){return xa(\"readwrite\").then(function(Fa){return va(Fa.put(Ea)).catch(ya(\"writing to store\"))})};this.clear=function(){return xa(\"readwrite\").then(function(Ga){return va(Ga.clear())})};this.iterateOnAll=function(Ha){return xa(\"readonly\").then(function(Ia){return za(Ha,Ia.openCursor()).catch(ya(\"iterating on all\"))})};function xa(Ja){return wa.get().then(function(Ka){try{return Ka.transaction(sa.storeName,Ja).objectStore(sa.storeName)}catch(La){console.error(ua,\"Could not open store; recreating database:\",La);Aa();throw La}})}function ya(Ma){return function(Na){console.error(ua,\"Error \"+Ma+\":\",Na);Aa();throw Na}}function za(Oa,Pa){return new Promise(function(Qa,Ra){Pa.onsuccess=function(Sa){var Ta=Sa.target.result;if(Ta){Oa(Ta.value);Ta.continue()}else{Qa()}};Pa.onerror=Ra})}function Aa(){var Ua=wa.dropDB().then(Ba);wa={get:function(){return Promise.reject(new Error(\"Database is being dropped and recreated\"))},dropDB:function(){return Ua}}}function Ba(){wa=new phast.ResourceLoader.IndexedDBStorage.Connection(sa)}};phast.ResourceLoader.IndexedDBStorage.logPrefix=\"[Phast] Resource loader:\";phast.ResourceLoader.IndexedDBStorage.requestToPromise=function(Va){return new Promise(function(Wa,Xa){Va.onsuccess=function(){Wa(Va.result)};Va.onerror=function(){Xa(Va.error)}})};phast.ResourceLoader.IndexedDBStorage.ConnectionParams=function(){this.dbName=\"phastResourcesCache\";this.dbVersion=1;this.storeName=\"resources\"};phast.ResourceLoader.IndexedDBStorage.StoredResource=function(Ya,Za){this.token=Ya;this.content=Za};phast.ResourceLoader.IndexedDBStorage.Connection=function(\$a){var _a=phast.ResourceLoader.IndexedDBStorage.logPrefix;var ab=phast.ResourceLoader.IndexedDBStorage.requestToPromise;var bb;this.get=cb;this.dropDB=db;function cb(){if(!bb){bb=eb(\$a)}return bb}function db(){return cb().then(function(gb){console.error(_a,\"Dropping DB\");gb.close();bb=null;return ab(window.indexedDB.deleteDatabase(\$a.dbName))})}function eb(hb){if(typeof window.indexedDB===\"undefined\"){return Promise.reject(new Error(\"IndexedDB is not available\"))}var ib=window.indexedDB.open(hb.dbName,hb.dbVersion);ib.onupgradeneeded=function(){fb(ib.result,hb)};return ab(ib).then(function(jb){jb.onversionchange=function(){console.debug(_a,\"Closing DB\");jb.close();if(bb){bb=null}};return jb}).catch(function(kb){console.log(_a,\"IndexedDB cache is not available. This is usually due to using private browsing mode.\");throw kb})}function fb(lb,mb){lb.createObjectStore(mb.storeName,{keyPath:\"token\"})}};phast.ResourceLoader.StorageCache=function(nb,ob){var pb=phast.ResourceLoader.IndexedDBStorage.StoredResource;this.get=function(xb){return sb(rb(xb))};this.set=function(yb,zb){return tb(rb(yb),zb,false)};var qb=null;function rb(Ab){return JSON.stringify(Ab)}function sb(Bb){return ob.get(Bb).then(function(Cb){if(Cb){return Promise.resolve(Cb.content)}return Promise.resolve()})}function tb(Db,Eb,Fb){return wb().then(function(Gb){var Hb=Eb.length+Gb;if(Hb>nb.maxStorageSize){return Fb||Eb.length>nb.maxStorageSize?Promise.reject(new Error(\"Storage quota will be exceeded\")):ub(Db,Eb)}qb=Hb;var Ib=new pb(Db,Eb);return ob.store(Ib)})}function ub(Jb,Kb){return vb().then(function(){return tb(Jb,Kb,true)})}function vb(){return ob.clear().then(function(){qb=0})}function wb(){if(qb!==null){return Promise.resolve(qb)}var Lb=0;return ob.iterateOnAll(function(Mb){Lb+=Mb.content.length}).then(function(){qb=Lb;return Promise.resolve(qb)})}};phast.ResourceLoader.StorageCache.StorageCacheParams=function(){this.maxStorageSize=4.5*1024*1024};phast.ResourceLoader.BlackholeCache=function(){this.get=function(){return Promise.reject()};this.set=function(){return Promise.reject()}};phast.ResourceLoader.make=function(Nb,Ob,Pb){var Qb=Sb();var Rb=new phast.ResourceLoader.BundlerServiceClient(Nb,Ob,Pb);return new phast.ResourceLoader(Rb,Qb);function Sb(){var Tb=window.navigator.userAgent;if(/safari/i.test(Tb)&&!/chrome|android/i.test(Tb)){console.log(\"[Phast] Not using IndexedDB cache on Safari\");return new phast.ResourceLoader.BlackholeCache}else{var Ub=new phast.ResourceLoader.IndexedDBStorage.ConnectionParams;var Vb=new phast.ResourceLoader.IndexedDBStorage(Ub);var Wb=new phast.ResourceLoader.StorageCache.StorageCacheParams;return new phast.ResourceLoader.StorageCache(Wb,Vb)}}};\n");
2170 2167 $resourcesLoader->setConfig('resourcesLoader', ['serviceUrl' => (string) $this->serviceUrl, 'shortParamsMappings' => $jsMappings, 'pathInfo' => $this->serviceRequestFormat === \Kibo\Phast\Services\ServiceRequest::FORMAT_PATH]);
2171 - $scripts = array_merge([\Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/runner.js', "phast.config=JSON.parse(atob(phast.config));while(phast.scripts.length){phast.scripts.shift()()}\n"), \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/es6-promise.js', "(function(a,b){typeof exports===\"object\"&&typeof module!==\"undefined\"?module.exports=b():typeof define===\"function\"&&define.amd?define(b):a.ES6Promise=b()})(phast,function(){\"use strict\";function c(ia){var ja=typeof ia;return ia!==null&&(ja===\"object\"||ja===\"function\")}function d(ka){return typeof ka===\"function\"}var e=void 0;if(Array.isArray){e=Array.isArray}else{e=function(la){return Object.prototype.toString.call(la)===\"[object Array]\"}}var f=e;var g=0;var h=void 0;var i=void 0;var j=function ma(na,oa){w[g]=na;w[g+1]=oa;g+=2;if(g===2){if(i){i(x)}else{z()}}};function k(pa){i=pa}function l(qa){j=qa}var m=typeof window!==\"undefined\"?window:undefined;var n=m||{};var o=n.MutationObserver||n.WebKitMutationObserver;var p=typeof self===\"undefined\"&&typeof process!==\"undefined\"&&{}.toString.call(process)===\"[object process]\";var q=typeof Uint8ClampedArray!==\"undefined\"&&typeof importScripts!==\"undefined\"&&typeof MessageChannel!==\"undefined\";function r(){return function(){return process.nextTick(x)}}function s(){if(typeof h!==\"undefined\"){return function(){h(x)}}return v()}function t(){var ra=0;var sa=new o(x);var ta=document.createTextNode(\"\");sa.observe(ta,{characterData:true});return function(){ta.data=ra=++ra%2}}function u(){var ua=new MessageChannel;ua.port1.onmessage=x;return function(){return ua.port2.postMessage(0)}}function v(){var va=setTimeout;return function(){return va(x,1)}}var w=new Array(1e3);function x(){for(var wa=0;wa<g;wa+=2){var xa=w[wa];var ya=w[wa+1];xa(ya);w[wa]=undefined;w[wa+1]=undefined}g=0}function y(){try{var za=Function(\"return this\")().require(\"vertx\");h=za.runOnLoop||za.runOnContext;return s()}catch(Aa){return v()}}var z=void 0;if(p){z=r()}else if(o){z=t()}else if(q){z=u()}else if(m===undefined&&typeof require===\"function\"){z=y()}else{z=v()}function A(Ba,Ca){var Da=this;var Ea=new this.constructor(D);if(Ea[C]===undefined){\$(Ea)}var Fa=Da._state;if(Fa){var Ga=arguments[Fa-1];j(function(){return W(Fa,Ea,Ga,Da._result)})}else{T(Da,Ea,Ba,Ca)}return Ea}function B(Ha){var Ia=this;if(Ha&&typeof Ha===\"object\"&&Ha.constructor===Ia){return Ha}var Ja=new Ia(D);P(Ja,Ha);return Ja}var C=Math.random().toString(36).substring(2);function D(){}var E=void 0;var F=1;var G=2;var H={error:null};function I(){return new TypeError(\"You cannot resolve a promise with itself\")}function J(){return new TypeError(\"A promises callback cannot return that same promise.\")}function K(Ka){try{return Ka.then}catch(La){H.error=La;return H}}function L(Ma,Na,Oa,Pa){try{Ma.call(Na,Oa,Pa)}catch(Qa){return Qa}}function M(Ra,Sa,Ta){j(function(Ua){var Va=false;var Wa=L(Ta,Sa,function(Xa){if(Va){return}Va=true;if(Sa!==Xa){P(Ua,Xa)}else{R(Ua,Xa)}},function(Ya){if(Va){return}Va=true;S(Ua,Ya)},\"Settle: \"+(Ua._label||\" unknown promise\"));if(!Va&&Wa){Va=true;S(Ua,Wa)}},Ra)}function N(Za,\$a){if(\$a._state===F){R(Za,\$a._result)}else if(\$a._state===G){S(Za,\$a._result)}else{T(\$a,undefined,function(_a){return P(Za,_a)},function(ab){return S(Za,ab)})}}function O(bb,cb,db){if(cb.constructor===bb.constructor&&db===A&&cb.constructor.resolve===B){N(bb,cb)}else{if(db===H){S(bb,H.error);H.error=null}else if(db===undefined){R(bb,cb)}else if(d(db)){M(bb,cb,db)}else{R(bb,cb)}}}function P(eb,fb){if(eb===fb){S(eb,I())}else if(c(fb)){O(eb,fb,K(fb))}else{R(eb,fb)}}function Q(gb){if(gb._onerror){gb._onerror(gb._result)}U(gb)}function R(hb,ib){if(hb._state!==E){return}hb._result=ib;hb._state=F;if(hb._subscribers.length!==0){j(U,hb)}}function S(jb,kb){if(jb._state!==E){return}jb._state=G;jb._result=kb;j(Q,jb)}function T(lb,mb,nb,ob){var pb=lb._subscribers;var qb=pb.length;lb._onerror=null;pb[qb]=mb;pb[qb+F]=nb;pb[qb+G]=ob;if(qb===0&&lb._state){j(U,lb)}}function U(rb){var sb=rb._subscribers;var tb=rb._state;if(sb.length===0){return}var ub=void 0,vb=void 0,wb=rb._result;for(var xb=0;xb<sb.length;xb+=3){ub=sb[xb];vb=sb[xb+tb];if(ub){W(tb,ub,vb,wb)}else{vb(wb)}}rb._subscribers.length=0}function V(yb,zb){try{return yb(zb)}catch(Ab){H.error=Ab;return H}}function W(Bb,Cb,Db,Eb){var Fb=d(Db),Gb=void 0,Hb=void 0,Ib=void 0,Jb=void 0;if(Fb){Gb=V(Db,Eb);if(Gb===H){Jb=true;Hb=Gb.error;Gb.error=null}else{Ib=true}if(Cb===Gb){S(Cb,J());return}}else{Gb=Eb;Ib=true}if(Cb._state!==E){}else if(Fb&&Ib){P(Cb,Gb)}else if(Jb){S(Cb,Hb)}else if(Bb===F){R(Cb,Gb)}else if(Bb===G){S(Cb,Gb)}}function X(Kb,Lb){try{Lb(function Mb(Nb){P(Kb,Nb)},function Ob(Pb){S(Kb,Pb)})}catch(Qb){S(Kb,Qb)}}var Y=0;function Z(){return Y++}function \$(Rb){Rb[C]=Y++;Rb._state=undefined;Rb._result=undefined;Rb._subscribers=[]}function _(){return new Error(\"Array Methods must be provided an Array\")}var aa=function(){function Sb(Tb,Ub){this._instanceConstructor=Tb;this.promise=new Tb(D);if(!this.promise[C]){\$(this.promise)}if(f(Ub)){this.length=Ub.length;this._remaining=Ub.length;this._result=new Array(this.length);if(this.length===0){R(this.promise,this._result)}else{this.length=this.length||0;this._enumerate(Ub);if(this._remaining===0){R(this.promise,this._result)}}}else{S(this.promise,_())}}Sb.prototype._enumerate=function Vb(Wb){for(var Xb=0;this._state===E&&Xb<Wb.length;Xb++){this._eachEntry(Wb[Xb],Xb)}};Sb.prototype._eachEntry=function Yb(Zb,\$b){var _b=this._instanceConstructor;var ac=_b.resolve;if(ac===B){var bc=K(Zb);if(bc===A&&Zb._state!==E){this._settledAt(Zb._state,\$b,Zb._result)}else if(typeof bc!==\"function\"){this._remaining--;this._result[\$b]=Zb}else if(_b===ga){var cc=new _b(D);O(cc,Zb,bc);this._willSettleAt(cc,\$b)}else{this._willSettleAt(new _b(function(dc){return dc(Zb)}),\$b)}}else{this._willSettleAt(ac(Zb),\$b)}};Sb.prototype._settledAt=function ec(fc,gc,hc){var ic=this.promise;if(ic._state===E){this._remaining--;if(fc===G){S(ic,hc)}else{this._result[gc]=hc}}if(this._remaining===0){R(ic,this._result)}};Sb.prototype._willSettleAt=function jc(kc,lc){var mc=this;T(kc,undefined,function(nc){return mc._settledAt(F,lc,nc)},function(oc){return mc._settledAt(G,lc,oc)})};return Sb}();function ba(pc){return new aa(this,pc).promise}function ca(qc){var rc=this;if(!f(qc)){return new rc(function(sc,tc){return tc(new TypeError(\"You must pass an array to race.\"))})}else{return new rc(function(uc,vc){var wc=qc.length;for(var xc=0;xc<wc;xc++){rc.resolve(qc[xc]).then(uc,vc)}})}}function da(yc){var zc=this;var Ac=new zc(D);S(Ac,yc);return Ac}function ea(){throw new TypeError(\"You must pass a resolver function as the first argument to the promise constructor\")}function fa(){throw new TypeError(\"Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.\")}var ga=function(){function Bc(Cc){this[C]=Z();this._result=this._state=undefined;this._subscribers=[];if(D!==Cc){typeof Cc!==\"function\"&&ea();this instanceof Bc?X(this,Cc):fa()}}Bc.prototype.catch=function Dc(Ec){return this.then(null,Ec)};Bc.prototype.finally=function Fc(Gc){var Hc=this;var Ic=Hc.constructor;return Hc.then(function(Jc){return Ic.resolve(Gc()).then(function(){return Jc})},function(Kc){return Ic.resolve(Gc()).then(function(){throw Kc})})};return Bc}();ga.prototype.then=A;ga.all=ba;ga.race=ca;ga.resolve=B;ga.reject=da;ga._setScheduler=k;ga._setAsap=l;ga._asap=j;function ha(){var Lc=void 0;if(typeof global!==\"undefined\"){Lc=global}else if(typeof self!==\"undefined\"){Lc=self}else{try{Lc=Function(\"return this\")()}catch(Oc){throw new Error(\"polyfill failed because global object is unavailable in this environment\")}}var Mc=Lc.Promise;if(Mc){var Nc=null;try{Nc=Object.prototype.toString.call(Mc.resolve())}catch(Pc){}if(Nc===\"[object Promise]\"&&!Mc.cast){return}}Lc.Promise=ga}ga.polyfill=ha;ga.Promise=ga;return ga});\n"), \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/hash.js', "function murmurhash3_32_gc(a,b){var c,d,e,f,g,h,i,j,k,l;c=a.length&3;d=a.length-c;e=b;g=3432918353;i=461845907;l=0;while(l<d){k=a.charCodeAt(l)&255|(a.charCodeAt(++l)&255)<<8|(a.charCodeAt(++l)&255)<<16|(a.charCodeAt(++l)&255)<<24;++l;k=(k&65535)*g+(((k>>>16)*g&65535)<<16)&4294967295;k=k<<15|k>>>17;k=(k&65535)*i+(((k>>>16)*i&65535)<<16)&4294967295;e^=k;e=e<<13|e>>>19;f=(e&65535)*5+(((e>>>16)*5&65535)<<16)&4294967295;e=(f&65535)+27492+(((f>>>16)+58964&65535)<<16)}k=0;switch(c){case 3:k^=(a.charCodeAt(l+2)&255)<<16;case 2:k^=(a.charCodeAt(l+1)&255)<<8;case 1:k^=a.charCodeAt(l)&255;k=(k&65535)*g+(((k>>>16)*g&65535)<<16)&4294967295;k=k<<15|k>>>17;k=(k&65535)*i+(((k>>>16)*i&65535)<<16)&4294967295;e^=k}e^=a.length;e^=e>>>16;e=(e&65535)*2246822507+(((e>>>16)*2246822507&65535)<<16)&4294967295;e^=e>>>13;e=(e&65535)*3266489909+(((e>>>16)*3266489909&65535)<<16)&4294967295;e^=e>>>16;return e>>>0}phast.hash=murmurhash3_32_gc;\n"), \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/service-url.js', "phast.buildServiceUrl=function(a,b){if(a.pathInfo){return appendPathInfo(a.serviceUrl,buildQuery(b))}else{return appendQueryString(a.serviceUrl,buildQuery(b))}};function buildQuery(c){if(typeof c===\"string\"){return c}var d=[];for(var e in c){if(c.hasOwnProperty(e)){d.push(encodeURIComponent(e)+\"=\"+encodeURIComponent(c[e]))}}return d.join(\"&\")}function appendPathInfo(f,g){var h=btoa(g).replace(/=/g,\"\").replace(/\\//g,\"_\").replace(/\\+/g,\"-\");return f.replace(/\\?.*\$/,\"\").replace(/\\/__p__\\.js\$/,\"\")+\"/\"+h+\".q.js\"}function appendQueryString(i,j){var k=i.indexOf(\"?\")>-1?\"&\":\"?\";return i+k+j}\n"), $resourcesLoader, \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/phast.js', "var Promise=phast.ES6Promise;phast.ResourceLoader.instance=phast.ResourceLoader.make(phast.config.resourcesLoader.serviceUrl,phast.config.resourcesLoader.shortParamsMappings,phast.config.resourcesLoader.pathInfo);phast.forEachSelectedElement=function(a,b){Array.prototype.forEach.call(window.document.querySelectorAll(a),b)};phast.once=function(c){var d=false;return function(){if(!d){d=true;c.apply(this,Array.prototype.slice(arguments))}}};phast.on=function(e,f){return new Promise(function(g){e.addEventListener(f,g)})};phast.wait=function(h){return new Promise(function(i){setTimeout(i,h)})};phast.on(document,\"DOMContentLoaded\").then(function(){var j,k;function l(n){return n&&n.nodeType===8&&/^\\s*\\[Phast\\]/.test(n.textContent)}function m(o){while(o){if(l(o)){return o}o=o.nextSibling}return false}k=m(document.documentElement.nextSibling);if(k===false){k=m(document.body.firstChild)}if(k){j=k.textContent.replace(/^\\s+|\\s+\$/g,\"\").split(\"\\n\");console.groupCollapsed(j.shift());console.log(j.join(\"\\n\"));console.groupEnd()}});phast.on(document,\"DOMContentLoaded\").then(function(){var p=performance.timing;var q=[];q.push([\"Downloading phases:\"]);q.push([\" Look up hostname in DNS + %s ms\",t(p.domainLookupEnd-p.fetchStart)]);q.push([\" Establish connection + %s ms\",t(p.connectEnd-p.domainLookupEnd)]);q.push([\" Send request + %s ms\",t(p.requestStart-p.connectEnd)]);q.push([\" Receive first byte + %s ms\",t(p.responseStart-p.requestStart)]);q.push([\" Download page + %s ms\",t(p.responseEnd-p.responseStart)]);q.push([\"\"]);q.push([\"Totals:\"]);q.push([\" Time to first byte %s ms\",t(p.responseStart-p.fetchStart)]);q.push([\" (since request start) %s ms\",t(p.responseStart-p.requestStart)]);q.push([\" Total request time %s ms\",t(p.responseEnd-p.fetchStart)]);q.push([\" (since request start) %s ms\",t(p.responseEnd-p.requestStart)]);q.push([\" \"]);var r=[];var s=[];q.forEach(function(u){r.push(u.shift());s=s.concat(u)});console.groupCollapsed(\"[Phast] Client-side performance metrics\");console.log.apply(console,[r.join(\"\\n\")].concat(s));console.groupEnd();function t(v){v=\"\"+v;while(v.length<4){v=\" \"+v}return v}});\n")], $scripts);
2168 + $scripts = array_merge([\Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/runner.js', "phast.config=JSON.parse(atob(phast.config));while(phast.scripts.length){phast.scripts.shift()()}\n"), \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/es6-promise.js', "(function(a,b){typeof exports===\"object\"&&typeof module!==\"undefined\"?module.exports=b():typeof define===\"function\"&&define.amd?define(b):a.ES6Promise=b()})(phast,function(){\"use strict\";function c(ia){var ja=typeof ia;return ia!==null&&(ja===\"object\"||ja===\"function\")}function d(ka){return typeof ka===\"function\"}var e=void 0;if(Array.isArray){e=Array.isArray}else{e=function(la){return Object.prototype.toString.call(la)===\"[object Array]\"}}var f=e;var g=0;var h=void 0;var i=void 0;var j=function ma(na,oa){w[g]=na;w[g+1]=oa;g+=2;if(g===2){if(i){i(x)}else{z()}}};function k(pa){i=pa}function l(qa){j=qa}var m=typeof window!==\"undefined\"?window:undefined;var n=m||{};var o=n.MutationObserver||n.WebKitMutationObserver;var p=typeof self===\"undefined\"&&typeof process!==\"undefined\"&&{}.toString.call(process)===\"[object process]\";var q=typeof Uint8ClampedArray!==\"undefined\"&&typeof importScripts!==\"undefined\"&&typeof MessageChannel!==\"undefined\";function r(){return function(){return process.nextTick(x)}}function s(){if(typeof h!==\"undefined\"){return function(){h(x)}}return v()}function t(){var ra=0;var sa=new o(x);var ta=document.createTextNode(\"\");sa.observe(ta,{characterData:true});return function(){ta.data=ra=++ra%2}}function u(){var ua=new MessageChannel;ua.port1.onmessage=x;return function(){return ua.port2.postMessage(0)}}function v(){var va=setTimeout;return function(){return va(x,1)}}var w=new Array(1e3);function x(){for(var wa=0;wa<g;wa+=2){var xa=w[wa];var ya=w[wa+1];xa(ya);w[wa]=undefined;w[wa+1]=undefined}g=0}function y(){try{var za=Function(\"return this\")().require(\"vertx\");h=za.runOnLoop||za.runOnContext;return s()}catch(Aa){return v()}}var z=void 0;if(p){z=r()}else if(o){z=t()}else if(q){z=u()}else if(m===undefined&&typeof require===\"function\"){z=y()}else{z=v()}function A(Ba,Ca){var Da=this;var Ea=new this.constructor(D);if(Ea[C]===undefined){\$(Ea)}var Fa=Da._state;if(Fa){var Ga=arguments[Fa-1];j(function(){return W(Fa,Ea,Ga,Da._result)})}else{T(Da,Ea,Ba,Ca)}return Ea}function B(Ha){var Ia=this;if(Ha&&typeof Ha===\"object\"&&Ha.constructor===Ia){return Ha}var Ja=new Ia(D);P(Ja,Ha);return Ja}var C=Math.random().toString(36).substring(2);function D(){}var E=void 0;var F=1;var G=2;var H={error:null};function I(){return new TypeError(\"You cannot resolve a promise with itself\")}function J(){return new TypeError(\"A promises callback cannot return that same promise.\")}function K(Ka){try{return Ka.then}catch(La){H.error=La;return H}}function L(Ma,Na,Oa,Pa){try{Ma.call(Na,Oa,Pa)}catch(Qa){return Qa}}function M(Ra,Sa,Ta){j(function(Ua){var Va=false;var Wa=L(Ta,Sa,function(Xa){if(Va){return}Va=true;if(Sa!==Xa){P(Ua,Xa)}else{R(Ua,Xa)}},function(Ya){if(Va){return}Va=true;S(Ua,Ya)},\"Settle: \"+(Ua._label||\" unknown promise\"));if(!Va&&Wa){Va=true;S(Ua,Wa)}},Ra)}function N(Za,\$a){if(\$a._state===F){R(Za,\$a._result)}else if(\$a._state===G){S(Za,\$a._result)}else{T(\$a,undefined,function(_a){return P(Za,_a)},function(ab){return S(Za,ab)})}}function O(bb,cb,db){if(cb.constructor===bb.constructor&&db===A&&cb.constructor.resolve===B){N(bb,cb)}else{if(db===H){S(bb,H.error);H.error=null}else if(db===undefined){R(bb,cb)}else if(d(db)){M(bb,cb,db)}else{R(bb,cb)}}}function P(eb,fb){if(eb===fb){S(eb,I())}else if(c(fb)){O(eb,fb,K(fb))}else{R(eb,fb)}}function Q(gb){if(gb._onerror){gb._onerror(gb._result)}U(gb)}function R(hb,ib){if(hb._state!==E){return}hb._result=ib;hb._state=F;if(hb._subscribers.length!==0){j(U,hb)}}function S(jb,kb){if(jb._state!==E){return}jb._state=G;jb._result=kb;j(Q,jb)}function T(lb,mb,nb,ob){var pb=lb._subscribers;var qb=pb.length;lb._onerror=null;pb[qb]=mb;pb[qb+F]=nb;pb[qb+G]=ob;if(qb===0&&lb._state){j(U,lb)}}function U(rb){var sb=rb._subscribers;var tb=rb._state;if(sb.length===0){return}var ub=void 0,vb=void 0,wb=rb._result;for(var xb=0;xb<sb.length;xb+=3){ub=sb[xb];vb=sb[xb+tb];if(ub){W(tb,ub,vb,wb)}else{vb(wb)}}rb._subscribers.length=0}function V(yb,zb){try{return yb(zb)}catch(Ab){H.error=Ab;return H}}function W(Bb,Cb,Db,Eb){var Fb=d(Db),Gb=void 0,Hb=void 0,Ib=void 0,Jb=void 0;if(Fb){Gb=V(Db,Eb);if(Gb===H){Jb=true;Hb=Gb.error;Gb.error=null}else{Ib=true}if(Cb===Gb){S(Cb,J());return}}else{Gb=Eb;Ib=true}if(Cb._state!==E){}else if(Fb&&Ib){P(Cb,Gb)}else if(Jb){S(Cb,Hb)}else if(Bb===F){R(Cb,Gb)}else if(Bb===G){S(Cb,Gb)}}function X(Kb,Lb){try{Lb(function Mb(Nb){P(Kb,Nb)},function Ob(Pb){S(Kb,Pb)})}catch(Qb){S(Kb,Qb)}}var Y=0;function Z(){return Y++}function \$(Rb){Rb[C]=Y++;Rb._state=undefined;Rb._result=undefined;Rb._subscribers=[]}function _(){return new Error(\"Array Methods must be provided an Array\")}var aa=function(){function Sb(Tb,Ub){this._instanceConstructor=Tb;this.promise=new Tb(D);if(!this.promise[C]){\$(this.promise)}if(f(Ub)){this.length=Ub.length;this._remaining=Ub.length;this._result=new Array(this.length);if(this.length===0){R(this.promise,this._result)}else{this.length=this.length||0;this._enumerate(Ub);if(this._remaining===0){R(this.promise,this._result)}}}else{S(this.promise,_())}}Sb.prototype._enumerate=function Vb(Wb){for(var Xb=0;this._state===E&&Xb<Wb.length;Xb++){this._eachEntry(Wb[Xb],Xb)}};Sb.prototype._eachEntry=function Yb(Zb,\$b){var _b=this._instanceConstructor;var ac=_b.resolve;if(ac===B){var bc=K(Zb);if(bc===A&&Zb._state!==E){this._settledAt(Zb._state,\$b,Zb._result)}else if(typeof bc!==\"function\"){this._remaining--;this._result[\$b]=Zb}else if(_b===ga){var cc=new _b(D);O(cc,Zb,bc);this._willSettleAt(cc,\$b)}else{this._willSettleAt(new _b(function(dc){return dc(Zb)}),\$b)}}else{this._willSettleAt(ac(Zb),\$b)}};Sb.prototype._settledAt=function ec(fc,gc,hc){var ic=this.promise;if(ic._state===E){this._remaining--;if(fc===G){S(ic,hc)}else{this._result[gc]=hc}}if(this._remaining===0){R(ic,this._result)}};Sb.prototype._willSettleAt=function jc(kc,lc){var mc=this;T(kc,undefined,function(nc){return mc._settledAt(F,lc,nc)},function(oc){return mc._settledAt(G,lc,oc)})};return Sb}();function ba(pc){return new aa(this,pc).promise}function ca(qc){var rc=this;if(!f(qc)){return new rc(function(sc,tc){return tc(new TypeError(\"You must pass an array to race.\"))})}else{return new rc(function(uc,vc){var wc=qc.length;for(var xc=0;xc<wc;xc++){rc.resolve(qc[xc]).then(uc,vc)}})}}function da(yc){var zc=this;var Ac=new zc(D);S(Ac,yc);return Ac}function ea(){throw new TypeError(\"You must pass a resolver function as the first argument to the promise constructor\")}function fa(){throw new TypeError(\"Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.\")}var ga=function(){function Bc(Cc){this[C]=Z();this._result=this._state=undefined;this._subscribers=[];if(D!==Cc){typeof Cc!==\"function\"&&ea();this instanceof Bc?X(this,Cc):fa()}}Bc.prototype.catch=function Dc(Ec){return this.then(null,Ec)};Bc.prototype.finally=function Fc(Gc){var Hc=this;var Ic=Hc.constructor;return Hc.then(function(Jc){return Ic.resolve(Gc()).then(function(){return Jc})},function(Kc){return Ic.resolve(Gc()).then(function(){throw Kc})})};return Bc}();ga.prototype.then=A;ga.all=ba;ga.race=ca;ga.resolve=B;ga.reject=da;ga._setScheduler=k;ga._setAsap=l;ga._asap=j;function ha(){var Lc=void 0;if(typeof global!==\"undefined\"){Lc=global}else if(typeof self!==\"undefined\"){Lc=self}else{try{Lc=Function(\"return this\")()}catch(Oc){throw new Error(\"polyfill failed because global object is unavailable in this environment\")}}var Mc=Lc.Promise;if(Mc){var Nc=null;try{Nc=Object.prototype.toString.call(Mc.resolve())}catch(Pc){}if(Nc===\"[object Promise]\"&&!Mc.cast){return}}Lc.Promise=ga}ga.polyfill=ha;ga.Promise=ga;return ga});\n"), \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/hash.js', "function murmurhash3_32_gc(a,b){var c,d,e,f,g,h,i,j,k,l;c=a.length&3;d=a.length-c;e=b;g=3432918353;i=461845907;l=0;while(l<d){k=a.charCodeAt(l)&255|(a.charCodeAt(++l)&255)<<8|(a.charCodeAt(++l)&255)<<16|(a.charCodeAt(++l)&255)<<24;++l;k=(k&65535)*g+(((k>>>16)*g&65535)<<16)&4294967295;k=k<<15|k>>>17;k=(k&65535)*i+(((k>>>16)*i&65535)<<16)&4294967295;e^=k;e=e<<13|e>>>19;f=(e&65535)*5+(((e>>>16)*5&65535)<<16)&4294967295;e=(f&65535)+27492+(((f>>>16)+58964&65535)<<16)}k=0;switch(c){case 3:k^=(a.charCodeAt(l+2)&255)<<16;case 2:k^=(a.charCodeAt(l+1)&255)<<8;case 1:k^=a.charCodeAt(l)&255;k=(k&65535)*g+(((k>>>16)*g&65535)<<16)&4294967295;k=k<<15|k>>>17;k=(k&65535)*i+(((k>>>16)*i&65535)<<16)&4294967295;e^=k}e^=a.length;e^=e>>>16;e=(e&65535)*2246822507+(((e>>>16)*2246822507&65535)<<16)&4294967295;e^=e>>>13;e=(e&65535)*3266489909+(((e>>>16)*3266489909&65535)<<16)&4294967295;e^=e>>>16;return e>>>0}phast.hash=murmurhash3_32_gc;\n"), \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/service-url.js', "phast.buildServiceUrl=function(a,b){if(a.pathInfo){return appendPathInfo(a.serviceUrl,buildQuery(b))}else{return appendQueryString(a.serviceUrl,buildQuery(b))}};function buildQuery(c){if(typeof c===\"string\"){return c}var d=[];for(var e in c){if(c.hasOwnProperty(e)){d.push(encodeURIComponent(e)+\"=\"+encodeURIComponent(c[e]))}}return d.join(\"&\")}function appendPathInfo(f,g){var h=btoa(g).replace(/=/g,\"\").replace(/\\//g,\"_\").replace(/\\+/g,\"-\");var i=j(h+\".q.js\");return f.replace(/\\?.*\$/,\"\").replace(/\\/__p__\\.js\$/,\"\")+\"/\"+i;function j(l){return k(k(l).match(/[\\s\\S]{1,255}/g).join(\"/\"))}function k(m){return m.split(\"\").reverse().join(\"\")}}function appendQueryString(n,o){var p=n.indexOf(\"?\")>-1?\"&\":\"?\";return n+p+o}\n"), $resourcesLoader, \Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/PhastScriptsCompiler/phast.js', "var Promise=phast.ES6Promise;phast.ResourceLoader.instance=phast.ResourceLoader.make(phast.config.resourcesLoader.serviceUrl,phast.config.resourcesLoader.shortParamsMappings,phast.config.resourcesLoader.pathInfo);phast.forEachSelectedElement=function(a,b){Array.prototype.forEach.call(window.document.querySelectorAll(a),b)};phast.once=function(c){var d=false;return function(){if(!d){d=true;c.apply(this,Array.prototype.slice(arguments))}}};phast.on=function(e,f){return new Promise(function(g){e.addEventListener(f,g)})};phast.wait=function(h){return new Promise(function(i){setTimeout(i,h)})};phast.on(document,\"DOMContentLoaded\").then(function(){var j,k;function l(n){return n&&n.nodeType===8&&/^\\s*\\[Phast\\]/.test(n.textContent)}function m(o){while(o){if(l(o)){return o}o=o.nextSibling}return false}k=m(document.documentElement.nextSibling);if(k===false){k=m(document.body.firstChild)}if(k){j=k.textContent.replace(/^\\s+|\\s+\$/g,\"\").split(\"\\n\");console.groupCollapsed(j.shift());console.log(j.join(\"\\n\"));console.groupEnd()}});phast.on(document,\"DOMContentLoaded\").then(function(){var p=performance.timing;var q=[];q.push([\"Downloading phases:\"]);q.push([\" Look up hostname in DNS + %s ms\",t(p.domainLookupEnd-p.fetchStart)]);q.push([\" Establish connection + %s ms\",t(p.connectEnd-p.domainLookupEnd)]);q.push([\" Send request + %s ms\",t(p.requestStart-p.connectEnd)]);q.push([\" Receive first byte + %s ms\",t(p.responseStart-p.requestStart)]);q.push([\" Download page + %s ms\",t(p.responseEnd-p.responseStart)]);q.push([\"\"]);q.push([\"Totals:\"]);q.push([\" Time to first byte %s ms\",t(p.responseStart-p.fetchStart)]);q.push([\" (since request start) %s ms\",t(p.responseStart-p.requestStart)]);q.push([\" Total request time %s ms\",t(p.responseEnd-p.fetchStart)]);q.push([\" (since request start) %s ms\",t(p.responseEnd-p.requestStart)]);q.push([\" \"]);var r=[];var s=[];q.forEach(function(u){r.push(u.shift());s=s.concat(u)});console.groupCollapsed(\"[Phast] Client-side performance metrics\");console.log.apply(console,[r.join(\"\\n\")].concat(s));console.groupEnd();function t(v){v=\"\"+v;while(v.length<4){v=\" \"+v}return v}});\n")], $scripts);
2172 2169 $compiled = $this->compileScripts($scripts);
2173 2170 return '(' . $compiled . ')(' . $this->compileConfig($scripts) . ');';
2174 2171 }
2175 2172 /**
@@ -2317,8 +2314,29 @@
2317 2314 {
2318 2315 return \Kibo\Phast\ValueObjects\URL::fromString($url)->withBase($this->context->getBaseUrl());
2319 2316 }
2320 2317 }
2318 +namespace Kibo\Phast\Filters\HTML\MetaCharset;
2319 +
2320 +class Filter implements \Kibo\Phast\Filters\HTML\HTMLStreamFilter
2321 +{
2322 + public function transformElements(\Traversable $elements, \Kibo\Phast\Filters\HTML\HTMLPageContext $context)
2323 + {
2324 + $didYield = false;
2325 + foreach ($elements as $element) {
2326 + if ($element instanceof \Kibo\Phast\Parsing\HTML\HTMLStreamElements\Tag) {
2327 + if ($element->tagName == 'meta' && array_keys($element->getAttributes()) == ['charset']) {
2328 + continue;
2329 + }
2330 + if (!$didYield && !in_array($element->tagName, ['html', 'head', '!doctype'])) {
2331 + (yield new \Kibo\Phast\Parsing\HTML\HTMLStreamElements\Tag('meta', ['charset' => 'utf-8']));
2332 + $didYield = true;
2333 + }
2334 + }
2335 + (yield $element);
2336 + }
2337 + }
2338 +}
2321 2339 namespace Kibo\Phast\Filters\HTML\BaseURLSetter;
2322 2340
2323 2341 class Filter extends \Kibo\Phast\Filters\HTML\BaseHTMLStreamFilter
2324 2342 {
@@ -3380,8 +3398,452 @@
3380 3398 {
3381 3399 return new \Kibo\Phast\Filters\Text\Decode\Filter();
3382 3400 }
3383 3401 }
3402 +namespace Kibo\Phast\JSMin;
3403 +
3404 +class UnterminatedRegExpException extends \Exception
3405 +{
3406 +}
3407 +namespace Kibo\Phast\JSMin;
3408 +
3409 +class UnterminatedCommentException extends \Exception
3410 +{
3411 +}
3412 +namespace Kibo\Phast\JSMin;
3413 +
3414 +class UnterminatedStringException extends \Exception
3415 +{
3416 +}
3417 +namespace Kibo\Phast\JSMin;
3418 +
3419 +/**
3420 + * JSMin.php - modified PHP implementation of Douglas Crockford's JSMin.
3421 + *
3422 + * <code>
3423 + * $minifiedJs = JSMin::minify($js);
3424 + * </code>
3425 + *
3426 + * This is a modified port of jsmin.c. Improvements:
3427 + *
3428 + * Does not choke on some regexp literals containing quote characters. E.g. /'/
3429 + *
3430 + * Spaces are preserved after some add/sub operators, so they are not mistakenly
3431 + * converted to post-inc/dec. E.g. a + ++b -> a+ ++b
3432 + *
3433 + * Preserves multi-line comments that begin with /*!
3434 + *
3435 + * PHP 5 or higher is required.
3436 + *
3437 + * Permission is hereby granted to use this version of the library under the
3438 + * same terms as jsmin.c, which has the following license:
3439 + *
3440 + * --
3441 + * Copyright (c) 2002 Douglas Crockford (www.crockford.com)
3442 + *
3443 + * Permission is hereby granted, free of charge, to any person obtaining a copy of
3444 + * this software and associated documentation files (the "Software"), to deal in
3445 + * the Software without restriction, including without limitation the rights to
3446 + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
3447 + * of the Software, and to permit persons to whom the Software is furnished to do
3448 + * so, subject to the following conditions:
3449 + *
3450 + * The above copyright notice and this permission notice shall be included in all
3451 + * copies or substantial portions of the Software.
3452 + *
3453 + * The Software shall be used for Good, not Evil.
3454 + *
3455 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3456 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3457 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3458 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3459 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3460 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3461 + * SOFTWARE.
3462 + * --
3463 + *
3464 + * @package JSMin
3465 + * @author Ryan Grove <ryan@wonko.com> (PHP port)
3466 + * @author Steve Clay <steve@mrclay.org> (modifications + cleanup)
3467 + * @author Andrea Giammarchi <http://www.3site.eu> (spaceBeforeRegExp)
3468 + * @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c)
3469 + * @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port)
3470 + * @license http://opensource.org/licenses/mit-license.php MIT License
3471 + * @link http://code.google.com/p/jsmin-php/
3472 + */
3473 +class JSMin
3474 +{
3475 + const ACTION_KEEP_A = 1;
3476 + const ACTION_DELETE_A = 2;
3477 + const ACTION_DELETE_A_B = 3;
3478 + protected $a = "\n";
3479 + protected $b = '';
3480 + protected $input = '';
3481 + protected $inputIndex = 0;
3482 + protected $inputLength = 0;
3483 + protected $lookAhead = null;
3484 + protected $output = '';
3485 + protected $lastByteOut = '';
3486 + protected $keptComment = '';
3487 + /**
3488 + * Minify Javascript.
3489 + *
3490 + * @param string $js Javascript to be minified
3491 + *
3492 + * @return string
3493 + */
3494 + public static function minify($js)
3495 + {
3496 + $jsmin = new \Kibo\Phast\JSMin\JSMin($js);
3497 + return $jsmin->min();
3498 + }
3499 + /**
3500 + * @param string $input
3501 + */
3502 + public function __construct($input)
3503 + {
3504 + $this->input = $input;
3505 + }
3506 + /**
3507 + * Perform minification, return result
3508 + *
3509 + * @return string
3510 + */
3511 + public function min()
3512 + {
3513 + if ($this->output !== '') {
3514 + // min already run
3515 + return $this->output;
3516 + }
3517 + $mbIntEnc = null;
3518 + if (function_exists('mb_strlen') && (int) ini_get('mbstring.func_overload') & 2) {
3519 + $mbIntEnc = mb_internal_encoding();
3520 + mb_internal_encoding('8bit');
3521 + }
3522 + if (isset($this->input[0]) && $this->input[0] === "\357") {
3523 + $this->input = substr($this->input, 3);
3524 + }
3525 + $this->input = str_replace("\r\n", "\n", $this->input);
3526 + $this->inputLength = strlen($this->input);
3527 + $this->action(self::ACTION_DELETE_A_B);
3528 + while ($this->a !== null) {
3529 + // determine next command
3530 + $command = self::ACTION_KEEP_A;
3531 + // default
3532 + if ($this->isWhiteSpace($this->a)) {
3533 + if (($this->lastByteOut === '+' || $this->lastByteOut === '-') && $this->b === $this->lastByteOut) {
3534 + // Don't delete this space. If we do, the addition/subtraction
3535 + // could be parsed as a post-increment
3536 + } elseif (!$this->isAlphaNum($this->b)) {
3537 + $command = self::ACTION_DELETE_A;
3538 + }
3539 + } elseif ($this->isLineTerminator($this->a)) {
3540 + if ($this->isWhiteSpace($this->b)) {
3541 + $command = self::ACTION_DELETE_A_B;
3542 + // in case of mbstring.func_overload & 2, must check for null b,
3543 + // otherwise mb_strpos will give WARNING
3544 + } elseif ($this->b === null || false === strpos('{[(+-!~', $this->b) && !$this->isAlphaNum($this->b)) {
3545 + $command = self::ACTION_DELETE_A;
3546 + }
3547 + } elseif (!$this->isAlphaNum($this->a)) {
3548 + if ($this->isWhiteSpace($this->b) || $this->isLineTerminator($this->b) && false === strpos('}])+-"\'', $this->a)) {
3549 + $command = self::ACTION_DELETE_A_B;
3550 + }
3551 + }
3552 + $this->action($command);
3553 + }
3554 + $this->output = trim($this->output);
3555 + if ($mbIntEnc !== null) {
3556 + mb_internal_encoding($mbIntEnc);
3557 + }
3558 + return $this->output;
3559 + }
3560 + /**
3561 + * ACTION_KEEP_A = Output A. Copy B to A. Get the next B.
3562 + * ACTION_DELETE_A = Copy B to A. Get the next B.
3563 + * ACTION_DELETE_A_B = Get the next B.
3564 + *
3565 + * @param int $command
3566 + * @throws UnterminatedRegExpException|UnterminatedStringException
3567 + */
3568 + protected function action($command)
3569 + {
3570 + // make sure we don't compress "a + ++b" to "a+++b", etc.
3571 + if ($command === self::ACTION_DELETE_A_B && $this->b === ' ' && ($this->a === '+' || $this->a === '-')) {
3572 + // Note: we're at an addition/substraction operator; the inputIndex
3573 + // will certainly be a valid index
3574 + if ($this->input[$this->inputIndex] === $this->a) {
3575 + // This is "+ +" or "- -". Don't delete the space.
3576 + $command = self::ACTION_KEEP_A;
3577 + }
3578 + }
3579 + switch ($command) {
3580 + case self::ACTION_KEEP_A:
3581 + // 1
3582 + $this->output .= $this->a;
3583 + if ($this->keptComment) {
3584 + $this->output = rtrim($this->output, "\n");
3585 + $this->output .= $this->keptComment;
3586 + $this->keptComment = '';
3587 + }
3588 + $this->lastByteOut = $this->a;
3589 + // fallthrough intentional
3590 + case self::ACTION_DELETE_A:
3591 + // 2
3592 + $this->a = $this->b;
3593 + if ($this->a === "'" || $this->a === '"' || $this->a === '`') {
3594 + // string/template literal
3595 + $delimiter = $this->a;
3596 + $str = $this->a;
3597 + // in case needed for exception
3598 + for (;;) {
3599 + $this->output .= $this->a;
3600 + $this->lastByteOut = $this->a;
3601 + $this->a = $this->get();
3602 + if ($this->a === $this->b) {
3603 + // end quote
3604 + break;
3605 + }
3606 + if ($delimiter === '`' && $this->isLineTerminator($this->a)) {
3607 + // leave the newline
3608 + } elseif ($this->isEOF($this->a)) {
3609 + $byte = $this->inputIndex - 1;
3610 + throw new \Kibo\Phast\JSMin\UnterminatedStringException("JSMin: Unterminated String at byte {$byte}: {$str}");
3611 + }
3612 + $str .= $this->a;
3613 + if ($this->a === '\\') {
3614 + $this->output .= $this->a;
3615 + $this->lastByteOut = $this->a;
3616 + $this->a = $this->get();
3617 + $str .= $this->a;
3618 + }
3619 + }
3620 + }
3621 + // fallthrough intentional
3622 + case self::ACTION_DELETE_A_B:
3623 + // 3
3624 + $this->b = $this->next();
3625 + if ($this->b === '/' && $this->isRegexpLiteral()) {
3626 + $this->output .= $this->a . $this->b;
3627 + $pattern = '/';
3628 + // keep entire pattern in case we need to report it in the exception
3629 + for (;;) {
3630 + $this->a = $this->get();
3631 + $pattern .= $this->a;
3632 + if ($this->a === '[') {
3633 + for (;;) {
3634 + $this->output .= $this->a;
3635 + $this->a = $this->get();
3636 + $pattern .= $this->a;
3637 + if ($this->a === ']') {
3638 + break;
3639 + }
3640 + if ($this->a === '\\') {
3641 + $this->output .= $this->a;
3642 + $this->a = $this->get();
3643 + $pattern .= $this->a;
3644 + }
3645 + if ($this->isEOF($this->a)) {
3646 + throw new \Kibo\Phast\JSMin\UnterminatedRegExpException("JSMin: Unterminated set in RegExp at byte " . $this->inputIndex . ": {$pattern}");
3647 + }
3648 + }
3649 + }
3650 + if ($this->a === '/') {
3651 + // end pattern
3652 + break;
3653 + // while (true)
3654 + } elseif ($this->a === '\\') {
3655 + $this->output .= $this->a;
3656 + $this->a = $this->get();
3657 + $pattern .= $this->a;
3658 + } elseif ($this->isEOF($this->a)) {
3659 + $byte = $this->inputIndex - 1;
3660 + throw new \Kibo\Phast\JSMin\UnterminatedRegExpException("JSMin: Unterminated RegExp at byte {$byte}: {$pattern}");
3661 + }
3662 + $this->output .= $this->a;
3663 + $this->lastByteOut = $this->a;
3664 + }
3665 + $this->b = $this->next();
3666 + }
3667 + }
3668 + }
3669 + /**
3670 + * @return bool
3671 + */
3672 + protected function isRegexpLiteral()
3673 + {
3674 + if (false !== strpos("(,=:[!&|?+-~*{;", $this->a)) {
3675 + // we can't divide after these tokens
3676 + return true;
3677 + }
3678 + // check if first non-ws token is "/" (see starts-regex.js)
3679 + $length = strlen($this->output);
3680 + if ($this->isWhiteSpace($this->a) || $this->isLineTerminator($this->a)) {
3681 + if ($length < 2) {
3682 + // weird edge case
3683 + return true;
3684 + }
3685 + }
3686 + // if the "/" follows a keyword, it must be a regexp, otherwise it's best to assume division
3687 + $subject = $this->output . trim($this->a);
3688 + if (!preg_match('/(?:case|else|in|return|typeof)$/', $subject, $m)) {
3689 + // not a keyword
3690 + return false;
3691 + }
3692 + // can't be sure it's a keyword yet (see not-regexp.js)
3693 + $charBeforeKeyword = substr($subject, 0 - strlen($m[0]) - 1, 1);
3694 + if ($this->isAlphaNum($charBeforeKeyword)) {
3695 + // this is really an identifier ending in a keyword, e.g. "xreturn"
3696 + return false;
3697 + }
3698 + // it's a regexp. Remove unneeded whitespace after keyword
3699 + if ($this->isWhiteSpace($this->a) || $this->isLineTerminator($this->a)) {
3700 + $this->a = '';
3701 + }
3702 + return true;
3703 + }
3704 + /**
3705 + * Return the next character from stdin. Watch out for lookahead. If the character is a control character,
3706 + * translate it to a space or linefeed.
3707 + *
3708 + * @return string
3709 + */
3710 + protected function get()
3711 + {
3712 + $c = $this->lookAhead;
3713 + $this->lookAhead = null;
3714 + if ($c === null) {
3715 + // getc(stdin)
3716 + if ($this->inputIndex < $this->inputLength) {
3717 + $c = $this->input[$this->inputIndex];
3718 + $this->inputIndex += 1;
3719 + } else {
3720 + $c = null;
3721 + }
3722 + }
3723 + if ($c === "\r") {
3724 + return "\n";
3725 + }
3726 + return $c;
3727 + }
3728 + /**
3729 + * Does $a indicate end of input?
3730 + *
3731 + * @param string $a
3732 + * @return bool
3733 + */
3734 + protected function isEOF($a)
3735 + {
3736 + return $a === null || $this->isLineTerminator($a);
3737 + }
3738 + /**
3739 + * Get next char (without getting it). If is ctrl character, translate to a space or newline.
3740 + *
3741 + * @return string
3742 + */
3743 + protected function peek()
3744 + {
3745 + $this->lookAhead = $this->get();
3746 + return $this->lookAhead;
3747 + }
3748 + /**
3749 + * Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character.
3750 + *
3751 + * @param string $c
3752 + *
3753 + * @return bool
3754 + */
3755 + protected function isAlphaNum($c)
3756 + {
3757 + return preg_match('/^[a-z0-9A-Z_\\$\\\\]$/', $c) || ord($c) > 126;
3758 + }
3759 + /**
3760 + * Consume a single line comment from input (possibly retaining it)
3761 + */
3762 + protected function consumeSingleLineComment()
3763 + {
3764 + $comment = '';
3765 + while (true) {
3766 + $get = $this->get();
3767 + $comment .= $get;
3768 + if ($this->isEOF($get)) {
3769 + // if IE conditional comment
3770 + if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
3771 + $this->keptComment .= "/{$comment}";
3772 + }
3773 + return;
3774 + }
3775 + }
3776 + }
3777 + /**
3778 + * Consume a multiple line comment from input (possibly retaining it)
3779 + *
3780 + * @throws UnterminatedCommentException
3781 + */
3782 + protected function consumeMultipleLineComment()
3783 + {
3784 + $this->get();
3785 + $comment = '';
3786 + for (;;) {
3787 + $get = $this->get();
3788 + if ($get === '*') {
3789 + if ($this->peek() === '/') {
3790 + // end of comment reached
3791 + $this->get();
3792 + if (0 === strpos($comment, '!')) {
3793 + // preserved by YUI Compressor
3794 + if (!$this->keptComment) {
3795 + // don't prepend a newline if two comments right after one another
3796 + $this->keptComment = "\n";
3797 + }
3798 + $this->keptComment .= "/*!" . substr($comment, 1) . "*/\n";
3799 + } else {
3800 + if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
3801 + // IE conditional
3802 + $this->keptComment .= "/*{$comment}*/";
3803 + }
3804 + }
3805 + return;
3806 + }
3807 + } elseif ($get === null) {
3808 + throw new \Kibo\Phast\JSMin\UnterminatedCommentException("JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}");
3809 + }
3810 + $comment .= $get;
3811 + }
3812 + }
3813 + /**
3814 + * Get the next character, skipping over comments. Some comments may be preserved.
3815 + *
3816 + * @return string
3817 + */
3818 + protected function next()
3819 + {
3820 + $get = $this->get();
3821 + if ($get === '/') {
3822 + switch ($this->peek()) {
3823 + case '/':
3824 + $this->consumeSingleLineComment();
3825 + $get = "\n";
3826 + break;
3827 + case '*':
3828 + $this->consumeMultipleLineComment();
3829 + $get = ' ';
3830 + break;
3831 + }
3832 + }
3833 + return $get;
3834 + }
3835 + protected function isWhiteSpace($s)
3836 + {
3837 + // https://www.ecma-international.org/ecma-262/#sec-white-space
3838 + return $s !== null && strpos(" \t\v\f", $s) !== false;
3839 + }
3840 + protected function isLineTerminator($s)
3841 + {
3842 + // https://www.ecma-international.org/ecma-262/#sec-line-terminators
3843 + return $s !== null && strpos("\n\r", $s) !== false;
3844 + }
3845 +}
3384 3846 namespace Kibo\Phast\Parsing\HTML;
3385 3847
3386 3848 class PCRETokenizer
3387 3849 {
@@ -4089,8 +4551,12 @@
4089 4551 */
4090 4552 public static function serve(callable $getConfig = null)
4091 4553 {
4092 4554 $httpRequest = \Kibo\Phast\HTTP\Request::fromGlobals();
4555 + if ($httpRequest->getHeader('CDN-Loop') && preg_match('~(^|,)\\s*Phast\\b~', $httpRequest->getHeader('CDN-Loop'))) {
4556 + http_response_code(508);
4557 + die('Loop detected');
4558 + }
4093 4559 $serviceRequest = \Kibo\Phast\Services\ServiceRequest::fromHTTPRequest($httpRequest);
4094 4560 $serviceParams = $serviceRequest->getParams();
4095 4561 if (defined('PHAST_SERVICE')) {
4096 4562 $service = PHAST_SERVICE;
@@ -4100,11 +4566,15 @@
4100 4566 } else {
4101 4567 $service = $serviceParams['service'];
4102 4568 }
4103 4569 if (isset($serviceParams['src']) && !headers_sent()) {
4104 - http_response_code(301);
4105 - header('Location: ' . $serviceParams['src']);
4106 - header('Cache-Control: max-age=86400');
4570 + if (self::isRewrittenRequest($httpRequest)) {
4571 + http_response_code(500);
4572 + } else {
4573 + http_response_code(301);
4574 + header('Location: ' . $serviceParams['src']);
4575 + header('Cache-Control: max-age=86400');
4576 + }
4107 4577 }
4108 4578 if ($getConfig === null) {
4109 4579 $config = [];
4110 4580 } else {
@@ -4118,14 +4588,17 @@
4118 4588 \Kibo\Phast\Logging\Log::info('Starting service');
4119 4589 $response = (new \Kibo\Phast\Services\Factory())->make($service, $runtimeConfig)->serve($serviceRequest);
4120 4590 \Kibo\Phast\Logging\Log::info('Service completed');
4121 4591 } catch (\Kibo\Phast\Exceptions\UnauthorizedException $e) {
4592 + echo "Unauthorized\n";
4122 4593 \Kibo\Phast\Logging\Log::error('Unauthorized exception: {message}', ['message' => $e->getMessage()]);
4123 4594 exit;
4124 4595 } catch (\Kibo\Phast\Exceptions\ItemNotFoundException $e) {
4596 + echo "Item not found\n";
4125 4597 \Kibo\Phast\Logging\Log::error('Item not found: {message}', ['message' => $e->getMessage()]);
4126 4598 exit;
4127 4599 } catch (\Exception $e) {
4600 + echo "Internal error, see logs\n";
4128 4601 \Kibo\Phast\Logging\Log::critical('Unhandled exception: {type} Message: {message} File: {file} Line: {line}', ['type' => get_class($e), 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine()]);
4129 4602 exit;
4130 4603 }
4131 4604 header_remove('Location');
@@ -4131,8 +4604,12 @@
4131 4604 header_remove('Location');
4132 4605 header_remove('Cache-Control');
4133 4606 self::output($httpRequest, $response, $runtimeConfig);
4134 4607 }
4608 + public static function isRewrittenRequest()
4609 + {
4610 + return !!\Kibo\Phast\Services\ServiceRequest::getRewrittenService(\Kibo\Phast\HTTP\Request::fromGlobals());
4611 + }
4135 4612 public static function output(\Kibo\Phast\HTTP\Request $request, \Kibo\Phast\HTTP\Response $response, array $config, \Kibo\Phast\Common\ObjectifiedFunctions $funcs = null)
4136 4613 {
4137 4614 if (is_null($funcs)) {
4138 4615 $funcs = new \Kibo\Phast\Common\ObjectifiedFunctions();
@@ -4295,15 +4772,33 @@
4295 4772 }
4296 4773 }
4297 4774 namespace Kibo\Phast\Common;
4298 4775
4776 +class JSMinifier extends \Kibo\Phast\JSMin\JSMin
4777 +{
4778 + protected $removeLicenseHeaders;
4779 + public function __construct($input, $removeLicenseHeaders = false)
4780 + {
4781 + parent::__construct($input);
4782 + $this->removeLicenseHeaders = $removeLicenseHeaders;
4783 + }
4784 + protected function consumeMultipleLineComment()
4785 + {
4786 + parent::consumeMultipleLineComment();
4787 + if ($this->removeLicenseHeaders) {
4788 + $this->keptComment = preg_replace('~/\\*!.*?\\*/~s', '', $this->keptComment);
4789 + }
4790 + }
4791 +}
4792 +namespace Kibo\Phast\Common;
4793 +
4299 4794 class OutputBufferHandler
4300 4795 {
4301 4796 use \Kibo\Phast\Logging\LoggingTrait;
4302 4797 const START_PATTERN = '~
4303 4798 (
4304 - \\s*+ <!doctype\\s++html> |
4305 - \\s*+ <html> |
4799 + \\s*+ <!doctype\\s++html\\b[^<>]*> |
4800 + \\s*+ <html\\b[^<>]*> |
4306 4801 \\s*+ <head> |
4307 4802 \\s*+ <!--.*?-->
4308 4803 )++
4309 4804 ~xsiA';
@@ -4326,9 +4821,9 @@
4326 4821 public function install()
4327 4822 {
4328 4823 $ignoreHandlers = ['default output handler', 'ob_gzhandler'];
4329 4824 if (!array_diff(ob_list_handlers(), $ignoreHandlers)) {
4330 - while (@ob_end_clean()) {
4825 + while (ob_get_level() && @ob_end_clean()) {
4331 4826 }
4332 4827 }
4333 4828 ob_start([$this, 'handleChunk'], 2);
4334 4829 ob_implicit_flush(1);
@@ -4914,8 +5409,13 @@
4914 5409 public function getPass()
4915 5410 {
4916 5411 return $this->pass;
4917 5412 }
5413 + /** @return string */
5414 + public function getDecodedPath()
5415 + {
5416 + return urldecode($this->path);
5417 + }
4918 5418 /**
4919 5419 * @return string
4920 5420 */
4921 5421 public function getPath()
@@ -6190,8 +6690,12 @@
6190 6690 /**
6191 6691 * @var string
6192 6692 */
6193 6693 private $token;
6694 + /**
6695 + * @var bool
6696 + */
6697 + private $trusted = false;
6194 6698 public function __construct()
6195 6699 {
6196 6700 if (!isset(self::$switches)) {
6197 6701 self::$switches = new \Kibo\Phast\Environment\Switches();
@@ -6214,18 +6718,8 @@
6214 6718 return self::$defaultSerializationMode;
6215 6719 }
6216 6720 public static function fromHTTPRequest(\Kibo\Phast\HTTP\Request $request)
6217 6721 {
6218 - $query = $request->getQuery();
6219 - if ($query->get('src')) {
6220 - $query->set('src', preg_replace('~^hxxp(?=s?://)~', 'http', $query->get('src')));
6221 - }
6222 - $pathInfo = $request->getPathInfo();
6223 - if ($pathParams = self::parseBase64PathInfo($pathInfo)) {
6224 - $query->update($pathParams);
6225 - } elseif ($pathInfo) {
6226 - $query->update(self::parsePathInfo($pathInfo));
6227 - }
6228 6722 $instance = new self();
6229 6723 self::$switches = new \Kibo\Phast\Environment\Switches();
6230 6724 $instance->httpRequest = $request;
6231 6725 if ($request->getCookie('phast')) {
@@ -6230,23 +6724,48 @@
6230 6724 $instance->httpRequest = $request;
6231 6725 if ($request->getCookie('phast')) {
6232 6726 self::$switches = \Kibo\Phast\Environment\Switches::fromString($request->getCookie('phast'));
6233 6727 }
6234 - if ($token = $query->pop('token')) {
6235 - $instance->token = $token;
6728 + if ($service = self::getRewrittenService($request)) {
6729 + $instance->query = \Kibo\Phast\ValueObjects\Query::fromAssoc(['service' => $service, 'src' => $request->getAbsoluteURI()]);
6730 + $instance->trusted = true;
6731 + } else {
6732 + $query = $request->getQuery();
6733 + if ($query->get('src')) {
6734 + $query->set('src', preg_replace('~^hxxp(?=s?://)~', 'http', $query->get('src')));
6735 + }
6736 + $pathInfo = $request->getPathInfo();
6737 + if ($pathParams = self::parseBase64PathInfo($pathInfo)) {
6738 + $query->update($pathParams);
6739 + } elseif ($pathInfo) {
6740 + $query->update(self::parsePathInfo($pathInfo));
6741 + }
6742 + if ($token = $query->pop('token')) {
6743 + $instance->token = $token;
6744 + }
6745 + $instance->query = $query;
6746 + if ($query->get('phast')) {
6747 + self::$propagatedSwitches = $query->get('phast');
6748 + $paramsSwitches = \Kibo\Phast\Environment\Switches::fromString($query->get('phast'));
6749 + self::$switches = self::$switches->merge($paramsSwitches);
6750 + }
6751 + if ($query->get('documentRequestId')) {
6752 + self::$documentRequestId = $query->get('documentRequestId');
6753 + } else {
6754 + self::$documentRequestId = (string) mt_rand(0, 999999999);
6755 + }
6236 6756 }
6237 - $instance->query = $query;
6238 - if ($query->get('phast')) {
6239 - self::$propagatedSwitches = $query->get('phast');
6240 - $paramsSwitches = \Kibo\Phast\Environment\Switches::fromString($query->get('phast'));
6241 - self::$switches = self::$switches->merge($paramsSwitches);
6757 + return $instance;
6758 + }
6759 + public static function getRewrittenService(\Kibo\Phast\HTTP\Request $request)
6760 + {
6761 + if ($service = $request->getEnvValue('REDIRECT_PHAST_SERVICE')) {
6762 + return $service;
6242 6763 }
6243 - if ($query->get('documentRequestId')) {
6244 - self::$documentRequestId = $query->get('documentRequestId');
6245 - } else {
6246 - self::$documentRequestId = (string) mt_rand(0, 999999999);
6764 + if ($service = $request->getEnvValue('PHAST_SERVICE')) {
6765 + return $service;
6247 6766 }
6248 - return $instance;
6767 + return null;
6249 6768 }
6250 6769 public function hasRequestSwitchesSet()
6251 6770 {
6252 6771 return !empty(self::$propagatedSwitches);
@@ -6322,9 +6841,9 @@
6322 6841 * @return bool
6323 6842 */
6324 6843 public function verify(\Kibo\Phast\Security\ServiceSignature $signature)
6325 6844 {
6326 - return $signature->verify($this->token, $this->getVerificationString()) || $signature->verify($this->token, $this->getVerificationStringWithoutStemSuffix());
6845 + return $this->trusted || $signature->verify($this->token, $this->getVerificationString()) || $signature->verify($this->token, $this->getVerificationStringWithoutStemSuffix());
6327 6846 }
6328 6847 private static function parsePathInfo($string)
6329 6848 {
6330 6849 $values = new \Kibo\Phast\ValueObjects\Query();
@@ -6360,12 +6879,13 @@
6360 6879 return $url->withPath($path)->toString();
6361 6880 }
6362 6881 private static function parseBase64PathInfo($string)
6363 6882 {
6364 - if (!preg_match('~^/([a-z0-9_-]+)\\.q\\.js$~i', $string, $match)) {
6883 + if (!preg_match('~^((/[a-z0-9_-]+)+)\\.q\\.js$~i', $string, $match)) {
6365 6884 return null;
6366 6885 }
6367 - return \Kibo\Phast\ValueObjects\Query::fromString(\Kibo\Phast\Common\Base64url::decode($match[1]));
6886 + $data = str_replace('/', '', $match[1]);
6887 + return \Kibo\Phast\ValueObjects\Query::fromString(\Kibo\Phast\Common\Base64url::decode($data));
6368 6888 }
6369 6889 /**
6370 6890 * @param callable $paramsFilter
6371 6891 * @return string
@@ -6615,452 +7135,8 @@
6615 7135
6616 7136 class UndefinedObjectifiedFunction extends \RuntimeException
6617 7137 {
6618 7138 }
6619 -namespace JSMin;
6620 -
6621 -class UnterminatedCommentException extends \Exception
6622 -{
6623 -}
6624 -namespace JSMin;
6625 -
6626 -class UnterminatedRegExpException extends \Exception
6627 -{
6628 -}
6629 -namespace JSMin;
6630 -
6631 -/**
6632 - * JSMin.php - modified PHP implementation of Douglas Crockford's JSMin.
6633 - *
6634 - * <code>
6635 - * $minifiedJs = JSMin::minify($js);
6636 - * </code>
6637 - *
6638 - * This is a modified port of jsmin.c. Improvements:
6639 - *
6640 - * Does not choke on some regexp literals containing quote characters. E.g. /'/
6641 - *
6642 - * Spaces are preserved after some add/sub operators, so they are not mistakenly
6643 - * converted to post-inc/dec. E.g. a + ++b -> a+ ++b
6644 - *
6645 - * Preserves multi-line comments that begin with /*!
6646 - *
6647 - * PHP 5 or higher is required.
6648 - *
6649 - * Permission is hereby granted to use this version of the library under the
6650 - * same terms as jsmin.c, which has the following license:
6651 - *
6652 - * --
6653 - * Copyright (c) 2002 Douglas Crockford (www.crockford.com)
6654 - *
6655 - * Permission is hereby granted, free of charge, to any person obtaining a copy of
6656 - * this software and associated documentation files (the "Software"), to deal in
6657 - * the Software without restriction, including without limitation the rights to
6658 - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
6659 - * of the Software, and to permit persons to whom the Software is furnished to do
6660 - * so, subject to the following conditions:
6661 - *
6662 - * The above copyright notice and this permission notice shall be included in all
6663 - * copies or substantial portions of the Software.
6664 - *
6665 - * The Software shall be used for Good, not Evil.
6666 - *
6667 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6668 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6669 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6670 - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6671 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6672 - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
6673 - * SOFTWARE.
6674 - * --
6675 - *
6676 - * @package JSMin
6677 - * @author Ryan Grove <ryan@wonko.com> (PHP port)
6678 - * @author Steve Clay <steve@mrclay.org> (modifications + cleanup)
6679 - * @author Andrea Giammarchi <http://www.3site.eu> (spaceBeforeRegExp)
6680 - * @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c)
6681 - * @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port)
6682 - * @license http://opensource.org/licenses/mit-license.php MIT License
6683 - * @link http://code.google.com/p/jsmin-php/
6684 - */
6685 -class JSMin
6686 -{
6687 - const ACTION_KEEP_A = 1;
6688 - const ACTION_DELETE_A = 2;
6689 - const ACTION_DELETE_A_B = 3;
6690 - protected $a = "\n";
6691 - protected $b = '';
6692 - protected $input = '';
6693 - protected $inputIndex = 0;
6694 - protected $inputLength = 0;
6695 - protected $lookAhead = null;
6696 - protected $output = '';
6697 - protected $lastByteOut = '';
6698 - protected $keptComment = '';
6699 - /**
6700 - * Minify Javascript.
6701 - *
6702 - * @param string $js Javascript to be minified
6703 - *
6704 - * @return string
6705 - */
6706 - public static function minify($js)
6707 - {
6708 - $jsmin = new \JSMin\JSMin($js);
6709 - return $jsmin->min();
6710 - }
6711 - /**
6712 - * @param string $input
6713 - */
6714 - public function __construct($input)
6715 - {
6716 - $this->input = $input;
6717 - }
6718 - /**
6719 - * Perform minification, return result
6720 - *
6721 - * @return string
6722 - */
6723 - public function min()
6724 - {
6725 - if ($this->output !== '') {
6726 - // min already run
6727 - return $this->output;
6728 - }
6729 - $mbIntEnc = null;
6730 - if (function_exists('mb_strlen') && (int) ini_get('mbstring.func_overload') & 2) {
6731 - $mbIntEnc = mb_internal_encoding();
6732 - mb_internal_encoding('8bit');
6733 - }
6734 - if (isset($this->input[0]) && $this->input[0] === "\357") {
6735 - $this->input = substr($this->input, 3);
6736 - }
6737 - $this->input = str_replace("\r\n", "\n", $this->input);
6738 - $this->inputLength = strlen($this->input);
6739 - $this->action(self::ACTION_DELETE_A_B);
6740 - while ($this->a !== null) {
6741 - // determine next command
6742 - $command = self::ACTION_KEEP_A;
6743 - // default
6744 - if ($this->isWhiteSpace($this->a)) {
6745 - if (($this->lastByteOut === '+' || $this->lastByteOut === '-') && $this->b === $this->lastByteOut) {
6746 - // Don't delete this space. If we do, the addition/subtraction
6747 - // could be parsed as a post-increment
6748 - } elseif (!$this->isAlphaNum($this->b)) {
6749 - $command = self::ACTION_DELETE_A;
6750 - }
6751 - } elseif ($this->isLineTerminator($this->a)) {
6752 - if ($this->isWhiteSpace($this->b)) {
6753 - $command = self::ACTION_DELETE_A_B;
6754 - // in case of mbstring.func_overload & 2, must check for null b,
6755 - // otherwise mb_strpos will give WARNING
6756 - } elseif ($this->b === null || false === strpos('{[(+-!~', $this->b) && !$this->isAlphaNum($this->b)) {
6757 - $command = self::ACTION_DELETE_A;
6758 - }
6759 - } elseif (!$this->isAlphaNum($this->a)) {
6760 - if ($this->isWhiteSpace($this->b) || $this->isLineTerminator($this->b) && false === strpos('}])+-"\'', $this->a)) {
6761 - $command = self::ACTION_DELETE_A_B;
6762 - }
6763 - }
6764 - $this->action($command);
6765 - }
6766 - $this->output = trim($this->output);
6767 - if ($mbIntEnc !== null) {
6768 - mb_internal_encoding($mbIntEnc);
6769 - }
6770 - return $this->output;
6771 - }
6772 - /**
6773 - * ACTION_KEEP_A = Output A. Copy B to A. Get the next B.
6774 - * ACTION_DELETE_A = Copy B to A. Get the next B.
6775 - * ACTION_DELETE_A_B = Get the next B.
6776 - *
6777 - * @param int $command
6778 - * @throws UnterminatedRegExpException|UnterminatedStringException
6779 - */
6780 - protected function action($command)
6781 - {
6782 - // make sure we don't compress "a + ++b" to "a+++b", etc.
6783 - if ($command === self::ACTION_DELETE_A_B && $this->b === ' ' && ($this->a === '+' || $this->a === '-')) {
6784 - // Note: we're at an addition/substraction operator; the inputIndex
6785 - // will certainly be a valid index
6786 - if ($this->input[$this->inputIndex] === $this->a) {
6787 - // This is "+ +" or "- -". Don't delete the space.
6788 - $command = self::ACTION_KEEP_A;
6789 - }
6790 - }
6791 - switch ($command) {
6792 - case self::ACTION_KEEP_A:
6793 - // 1
6794 - $this->output .= $this->a;
6795 - if ($this->keptComment) {
6796 - $this->output = rtrim($this->output, "\n");
6797 - $this->output .= $this->keptComment;
6798 - $this->keptComment = '';
6799 - }
6800 - $this->lastByteOut = $this->a;
6801 - // fallthrough intentional
6802 - case self::ACTION_DELETE_A:
6803 - // 2
6804 - $this->a = $this->b;
6805 - if ($this->a === "'" || $this->a === '"' || $this->a === '`') {
6806 - // string/template literal
6807 - $delimiter = $this->a;
6808 - $str = $this->a;
6809 - // in case needed for exception
6810 - for (;;) {
6811 - $this->output .= $this->a;
6812 - $this->lastByteOut = $this->a;
6813 - $this->a = $this->get();
6814 - if ($this->a === $this->b) {
6815 - // end quote
6816 - break;
6817 - }
6818 - if ($delimiter === '`' && $this->isLineTerminator($this->a)) {
6819 - // leave the newline
6820 - } elseif ($this->isEOF($this->a)) {
6821 - $byte = $this->inputIndex - 1;
6822 - throw new \JSMin\UnterminatedStringException("JSMin: Unterminated String at byte {$byte}: {$str}");
6823 - }
6824 - $str .= $this->a;
6825 - if ($this->a === '\\') {
6826 - $this->output .= $this->a;
6827 - $this->lastByteOut = $this->a;
6828 - $this->a = $this->get();
6829 - $str .= $this->a;
6830 - }
6831 - }
6832 - }
6833 - // fallthrough intentional
6834 - case self::ACTION_DELETE_A_B:
6835 - // 3
6836 - $this->b = $this->next();
6837 - if ($this->b === '/' && $this->isRegexpLiteral()) {
6838 - $this->output .= $this->a . $this->b;
6839 - $pattern = '/';
6840 - // keep entire pattern in case we need to report it in the exception
6841 - for (;;) {
6842 - $this->a = $this->get();
6843 - $pattern .= $this->a;
6844 - if ($this->a === '[') {
6845 - for (;;) {
6846 - $this->output .= $this->a;
6847 - $this->a = $this->get();
6848 - $pattern .= $this->a;
6849 - if ($this->a === ']') {
6850 - break;
6851 - }
6852 - if ($this->a === '\\') {
6853 - $this->output .= $this->a;
6854 - $this->a = $this->get();
6855 - $pattern .= $this->a;
6856 - }
6857 - if ($this->isEOF($this->a)) {
6858 - throw new \JSMin\UnterminatedRegExpException("JSMin: Unterminated set in RegExp at byte " . $this->inputIndex . ": {$pattern}");
6859 - }
6860 - }
6861 - }
6862 - if ($this->a === '/') {
6863 - // end pattern
6864 - break;
6865 - // while (true)
6866 - } elseif ($this->a === '\\') {
6867 - $this->output .= $this->a;
6868 - $this->a = $this->get();
6869 - $pattern .= $this->a;
6870 - } elseif ($this->isEOF($this->a)) {
6871 - $byte = $this->inputIndex - 1;
6872 - throw new \JSMin\UnterminatedRegExpException("JSMin: Unterminated RegExp at byte {$byte}: {$pattern}");
6873 - }
6874 - $this->output .= $this->a;
6875 - $this->lastByteOut = $this->a;
6876 - }
6877 - $this->b = $this->next();
6878 - }
6879 - }
6880 - }
6881 - /**
6882 - * @return bool
6883 - */
6884 - protected function isRegexpLiteral()
6885 - {
6886 - if (false !== strpos("(,=:[!&|?+-~*{;", $this->a)) {
6887 - // we can't divide after these tokens
6888 - return true;
6889 - }
6890 - // check if first non-ws token is "/" (see starts-regex.js)
6891 - $length = strlen($this->output);
6892 - if ($this->isWhiteSpace($this->a) || $this->isLineTerminator($this->a)) {
6893 - if ($length < 2) {
6894 - // weird edge case
6895 - return true;
6896 - }
6897 - }
6898 - // if the "/" follows a keyword, it must be a regexp, otherwise it's best to assume division
6899 - $subject = $this->output . trim($this->a);
6900 - if (!preg_match('/(?:case|else|in|return|typeof)$/', $subject, $m)) {
6901 - // not a keyword
6902 - return false;
6903 - }
6904 - // can't be sure it's a keyword yet (see not-regexp.js)
6905 - $charBeforeKeyword = substr($subject, 0 - strlen($m[0]) - 1, 1);
6906 - if ($this->isAlphaNum($charBeforeKeyword)) {
6907 - // this is really an identifier ending in a keyword, e.g. "xreturn"
6908 - return false;
6909 - }
6910 - // it's a regexp. Remove unneeded whitespace after keyword
6911 - if ($this->isWhiteSpace($this->a) || $this->isLineTerminator($this->a)) {
6912 - $this->a = '';
6913 - }
6914 - return true;
6915 - }
6916 - /**
6917 - * Return the next character from stdin. Watch out for lookahead. If the character is a control character,
6918 - * translate it to a space or linefeed.
6919 - *
6920 - * @return string
6921 - */
6922 - protected function get()
6923 - {
6924 - $c = $this->lookAhead;
6925 - $this->lookAhead = null;
6926 - if ($c === null) {
6927 - // getc(stdin)
6928 - if ($this->inputIndex < $this->inputLength) {
6929 - $c = $this->input[$this->inputIndex];
6930 - $this->inputIndex += 1;
6931 - } else {
6932 - $c = null;
6933 - }
6934 - }
6935 - if ($c === "\r") {
6936 - return "\n";
6937 - }
6938 - return $c;
6939 - }
6940 - /**
6941 - * Does $a indicate end of input?
6942 - *
6943 - * @param string $a
6944 - * @return bool
6945 - */
6946 - protected function isEOF($a)
6947 - {
6948 - return $a === null || $this->isLineTerminator($a);
6949 - }
6950 - /**
6951 - * Get next char (without getting it). If is ctrl character, translate to a space or newline.
6952 - *
6953 - * @return string
6954 - */
6955 - protected function peek()
6956 - {
6957 - $this->lookAhead = $this->get();
6958 - return $this->lookAhead;
6959 - }
6960 - /**
6961 - * Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character.
6962 - *
6963 - * @param string $c
6964 - *
6965 - * @return bool
6966 - */
6967 - protected function isAlphaNum($c)
6968 - {
6969 - return preg_match('/^[a-z0-9A-Z_\\$\\\\]$/', $c) || ord($c) > 126;
6970 - }
6971 - /**
6972 - * Consume a single line comment from input (possibly retaining it)
6973 - */
6974 - protected function consumeSingleLineComment()
6975 - {
6976 - $comment = '';
6977 - while (true) {
6978 - $get = $this->get();
6979 - $comment .= $get;
6980 - if ($this->isEOF($get)) {
6981 - // if IE conditional comment
6982 - if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
6983 - $this->keptComment .= "/{$comment}";
6984 - }
6985 - return;
6986 - }
6987 - }
6988 - }
6989 - /**
6990 - * Consume a multiple line comment from input (possibly retaining it)
6991 - *
6992 - * @throws UnterminatedCommentException
6993 - */
6994 - protected function consumeMultipleLineComment()
6995 - {
6996 - $this->get();
6997 - $comment = '';
6998 - for (;;) {
6999 - $get = $this->get();
7000 - if ($get === '*') {
7001 - if ($this->peek() === '/') {
7002 - // end of comment reached
7003 - $this->get();
7004 - if (0 === strpos($comment, '!')) {
7005 - // preserved by YUI Compressor
7006 - if (!$this->keptComment) {
7007 - // don't prepend a newline if two comments right after one another
7008 - $this->keptComment = "\n";
7009 - }
7010 - $this->keptComment .= "/*!" . substr($comment, 1) . "*/\n";
7011 - } else {
7012 - if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
7013 - // IE conditional
7014 - $this->keptComment .= "/*{$comment}*/";
7015 - }
7016 - }
7017 - return;
7018 - }
7019 - } elseif ($get === null) {
7020 - throw new \JSMin\UnterminatedCommentException("JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}");
7021 - }
7022 - $comment .= $get;
7023 - }
7024 - }
7025 - /**
7026 - * Get the next character, skipping over comments. Some comments may be preserved.
7027 - *
7028 - * @return string
7029 - */
7030 - protected function next()
7031 - {
7032 - $get = $this->get();
7033 - if ($get === '/') {
7034 - switch ($this->peek()) {
7035 - case '/':
7036 - $this->consumeSingleLineComment();
7037 - $get = "\n";
7038 - break;
7039 - case '*':
7040 - $this->consumeMultipleLineComment();
7041 - $get = ' ';
7042 - break;
7043 - }
7044 - }
7045 - return $get;
7046 - }
7047 - protected function isWhiteSpace($s)
7048 - {
7049 - // https://www.ecma-international.org/ecma-262/#sec-white-space
7050 - return $s !== null && strpos(" \t\v\f", $s) !== false;
7051 - }
7052 - protected function isLineTerminator($s)
7053 - {
7054 - // https://www.ecma-international.org/ecma-262/#sec-line-terminators
7055 - return $s !== null && strpos("\n\r", $s) !== false;
7056 - }
7057 -}
7058 -namespace JSMin;
7059 -
7060 -class UnterminatedStringException extends \Exception
7061 -{
7062 -}
7063 7139 namespace Kibo\PhastPlugins\SDK;
7064 7140
7065 7141 /**
7066 7142 * Provides commonly needed URLs
@@ -8419,9 +8495,9 @@
8419 8495 return $this->rootsProvider->getCacheRootCandidates();
8420 8496 }
8421 8497 public function getCacheRoot()
8422 8498 {
8423 - $key = md5(@$_SERVER['DOCUMENT_ROOT']) . '.' . (new \Kibo\Phast\Common\System())->getUserId();
8499 + $key = $this->getKey();
8424 8500 $candidates = $this->getCacheRootCandidates();
8425 8501 if ($result = $this->findExistingCacheRoot($key, $candidates)) {
8426 8502 return $result;
8427 8503 }
@@ -8433,27 +8509,41 @@
8433 8509 public function hasCacheRoot()
8434 8510 {
8435 8511 return (bool) $this->getCacheRoot();
8436 8512 }
8513 + public function getAllCacheRoots()
8514 + {
8515 + return $this->findAllExistingCacheRoots($this->getKey(), $this->getCacheRootCandidates());
8516 + }
8517 + private function getKey()
8518 + {
8519 + return md5(@$_SERVER['DOCUMENT_ROOT']) . '.' . (new \Kibo\Phast\Common\System())->getUserId();
8520 + }
8437 8521 private function findExistingCacheRoot($key, $candidates)
8438 8522 {
8439 - foreach ($candidates as $dir) {
8523 + foreach ($this->findAllExistingCacheRoots($key, $candidates) as $checkDir) {
8524 + if (!is_writable($checkDir)) {
8525 + continue;
8526 + }
8527 + if (function_exists('posix_geteuid') && fileowner($checkDir) !== posix_geteuid()) {
8528 + continue;
8529 + }
8530 + $this->createIndexFile($checkDir);
8531 + return $checkDir;
8532 + }
8533 + return false;
8534 + }
8535 + private function findAllExistingCacheRoots($key, $candidates)
8536 + {
8537 + foreach ($this->getCacheRootCandidates() as $dir) {
8440 8538 $checkDirs = ["{$dir}/{$key}", "{$dir}/phastpress.{$key}", "{$dir}/phast.{$key}"];
8441 8539 foreach ($checkDirs as $checkDir) {
8442 8540 if (!is_dir($checkDir)) {
8443 8541 continue;
8444 8542 }
8445 - if (!is_writable($checkDir)) {
8446 - continue;
8447 - }
8448 - if (function_exists('posix_geteuid') && fileowner($checkDir) !== posix_geteuid()) {
8449 - continue;
8450 - }
8451 - $this->createIndexFile($checkDir);
8452 - return $checkDir;
8543 + (yield $checkDir);
8453 8544 }
8454 8545 }
8455 - return false;
8456 8546 }
8457 8547 private function createNewCacheRoot($key, $candidates)
8458 8548 {
8459 8549 foreach ($this->getCacheRootCandidates() as $dir) {
@@ -8537,9 +8627,9 @@
8537 8627 class Translations
8538 8628 {
8539 8629 const DATA = array('en' => array('AdminPanel' => array('errors' => array('no-cache-root' => '@:plugin-name can not write to any cache directory! Please, make one of the following directories writable: {params}', 'no-service-config' => '@:plugin-name failed to create a service configuration in any of the following directories: {params}', 'network-error' => 'Failed to connect to plugin server! Please, try again later! {params}', 'cache' => '{params}'), 'warnings' => array('disabled' => '@:plugin-name optimizations are off!', 'admin-only' => '@:plugin-name optimizations will be applied only for logged-in users with the "Administrator" privilege. This is for previewing purposes. Select the "On" setting for "@:plugin-name optimizations" below to activate for all users!
8540 8630 ')), 'Backend' => array('install-notice' => 'Thank you for using <b>@:plugin-name</b>. Optimizations are <b>{pluginState}</b>. Go to <b><a href="{settingsUrl}">Settings</a></b> to configure <b>@:plugin-name</b>.
8541 -', 'status' => array('on' => 'on', 'off' => 'off', 'admin' => 'on for administrators')), 'Information' => array('additional' => 'Additional information'), 'Notification' => array('error' => 'error', 'warning' => 'warning', 'information' => 'information', 'success' => 'success'), 'OnOffSwitch' => array('on' => 'On', 'off' => 'Off'), 'SavingStatus' => array('saving' => 'Saving', 'saved' => 'Saved'), 'Settings' => array('common' => array('tip' => 'Tip:', 'on' => 'On:', 'off' => 'Off:'), 'sections' => array('plugin' => array('title' => 'Plugin', 'enabled' => array('name' => '@:plugin-name optimizations', 'description' => array('main' => 'Test your site {without} and {with}', 'without' => 'without @:plugin-name', 'with' => 'with @:plugin-name')), 'admin-only' => array('name' => 'Only optimize for administrators', 'description' => array('on' => 'Only privileged users will be served with optimized version', 'off' => 'All users will be served with optimized version', 'tip' => 'Use this to preview your site before launching the optimizations')), 'pathinfo' => array('name' => 'Remove query string from processed resources', 'description' => array('start' => 'Make sure that processed resources don\'t have query strings, for a higher score in GTmetrix.', 'on' => 'Use the path for requests for processed resources. This requires a server that supports "PATH_INFO".', 'off' => 'Use the GET parameters for requests for processed resources.')), 'footer-link' => array('name' => 'Let the world know about @:plugin-name', 'description' => 'Add a "Optimized by @:plugin-name" notice to the footer of your site and help spread the word.'), 'compress-service-response' => array('name' => 'Enable gzip compression on processed resources', 'description' => 'This compresses the optimized and bundled JavaScript and CSS generated by PhastPress. Disable this if your server already compresses PhastPress responses.')), 'images' => array('title' => 'Images', 'tags' => array('name' => 'Optimize images in tags', 'description' => 'Compress images with optimal settings. {newline} Resize images to fit {width}x{height} pixels or to the appropriate size for {imgTag} tags with {widthAttr} or {heightAttr}. {newline} Reload changed images while still leveraging browser caching.'), 'css' => array('name' => 'Optimize images in CSS', 'description' => array(0 => 'Compress images in stylesheets with optional settings and resizes the to fit {width}x{height} pixels.', 1 => 'Reload changed images while still leveraging browser caching.')), 'api' => array('name' => 'Use the Phast Image Optimization API', 'description' => array(0 => 'Optimize your images on our servers free of charge.', 1 => 'This will give you the best possible results without installing any software and will reduce the load on your hosting.')), 'lazy' => array('name' => 'Lazy load images', 'description' => array(0 => 'This adds the loading=lazy attribute to img tags so that images are only load once they are visible on the page.', 1 => 'This helps pass the "Defer offscreen images" audit in PageSpeed Insights.'))), 'html-filters' => array('title' => 'HTML, CSS & JS', 'css' => array('name' => 'Optimize CSS', 'description' => array(0 => 'Incline critical styles first and prevent unused styles from blocking the page load.', 1 => 'Minify stylesheets and leverage browser caching.', 2 => 'Inline Google Fonts CSS to speed up font loading.')), 'async-js' => array('name' => 'Load scripts asynchronously', 'description' => 'Allow the page to finish loading before all scripts have been executed.'), 'minify-js' => array('name' => 'Minify scripts and improve caching', 'description' => array(0 => 'Minify scripts and fix caching for Google Analytics and Hotjar.', 1 => 'Reload changed scripts while still leveraging browser caching.')), 'iframe' => array('name' => 'Defer IFrame loading', 'description' => 'Start loading IFrames after the page has finished loading.'), 'minify-html' => array('name' => 'Minify HTML', 'description' => 'Remove unnecessary whitespace from the HTML code of the page.'), 'minify-inline-scripts' => array('name' => 'Minify inline scripts and JSON', 'description' => 'Remove unnecessary whitespace from inline scripts and JSON data.'))))));
8631 +', 'status' => array('on' => 'on', 'off' => 'off', 'admin' => 'on for administrators')), 'Information' => array('additional' => 'Additional information'), 'Notification' => array('error' => 'error', 'warning' => 'warning', 'information' => 'information', 'success' => 'success'), 'OnOffSwitch' => array('on' => 'On', 'off' => 'Off'), 'SavingStatus' => array('saving' => 'Saving', 'saved' => 'Saved'), 'Settings' => array('common' => array('tip' => 'Tip:', 'on' => 'On:', 'off' => 'Off:'), 'sections' => array('plugin' => array('title' => 'Plugin', 'enabled' => array('name' => '@:plugin-name optimizations', 'description' => array('main' => 'Test your site {without} and {with}', 'without' => 'without @:plugin-name', 'with' => 'with @:plugin-name')), 'admin-only' => array('name' => 'Only optimize for administrators', 'description' => array('on' => 'Only privileged users will be served with optimized version', 'off' => 'All users will be served with optimized version', 'tip' => 'Use this to preview your site before launching the optimizations')), 'pathinfo' => array('name' => 'Remove query string from processed resources', 'description' => array('start' => 'Make sure that processed resources don\'t have query strings, for a higher score in GTmetrix.', 'on' => 'Use the path for requests for processed resources. This requires a server that supports "PATH_INFO".', 'off' => 'Use the GET parameters for requests for processed resources.')), 'footer-link' => array('name' => 'Let the world know about @:plugin-name', 'description' => 'Add a "Optimized by @:plugin-name" notice to the footer of your site and help spread the word.'), 'compress-service-response' => array('name' => 'Enable gzip compression on processed resources', 'description' => 'This compresses the optimized and bundled JavaScript and CSS generated by PhastPress. Disable this if your server already compresses PhastPress responses.')), 'images' => array('title' => 'Images', 'tags' => array('name' => 'Optimize images in tags', 'description' => 'Compress images with optimal settings. {newline} Resize images to fit {width}x{height} pixels or to the appropriate size for {imgTag} tags with {widthAttr} or {heightAttr}. {newline} Reload changed images while still leveraging browser caching.'), 'css' => array('name' => 'Optimize images in CSS', 'description' => array(0 => 'Compress images in stylesheets with optional settings and resizes the to fit {width}x{height} pixels.', 1 => 'Reload changed images while still leveraging browser caching.')), 'api' => array('name' => 'Use the Phast Image Optimization API', 'description' => array(0 => 'Optimize your images on our servers free of charge.', 1 => 'This will give you the best possible results without installing any software and will reduce the load on your hosting.')), 'lazy' => array('name' => 'Lazy load images', 'description' => array(0 => 'This adds the loading=lazy attribute to img tags so that images are only load once they are visible on the page.', 1 => 'This helps pass the "Defer offscreen images" audit in PageSpeed Insights.'))), 'html-filters' => array('title' => 'HTML, CSS & JS', 'css' => array('name' => 'Optimize CSS', 'description' => array(0 => 'Incline critical styles first and prevent unused styles from blocking the page load.', 1 => 'Minify stylesheets and leverage browser caching.', 2 => 'Inline Google Fonts CSS to speed up font loading.')), 'async-js' => array('name' => 'Load scripts asynchronously', 'description' => 'Allow the page to finish loading before all scripts have been executed.'), 'minify-js' => array('name' => 'Minify scripts and improve caching', 'description' => array(0 => 'Minify scripts and set long cache durations.', 1 => 'Reload changed scripts while still leveraging browser caching.')), 'iframe' => array('name' => 'Defer IFrame loading', 'description' => 'Start loading IFrames after the page has finished loading.'), 'minify-html' => array('name' => 'Minify HTML', 'description' => 'Remove unnecessary whitespace from the HTML code of the page.'), 'minify-inline-scripts' => array('name' => 'Minify inline scripts and JSON', 'description' => 'Remove unnecessary whitespace from inline scripts and JSON data.'))))));
8542 8632 }
8543 8633 namespace Kibo\PhastPlugins\SDK\AJAX;
8544 8634
8545 8635 /**
@@ -8764,9 +8854,9 @@
8764 8854 (yield $script);
8765 8855 }
8766 8856 protected function afterLoop()
8767 8857 {
8768 - $this->context->addPhastJavaScript(\Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/ScriptsDeferring/scripts-loader.js', "var Promise=phast.ES6Promise;phast.ScriptsLoader={};phast.ScriptsLoader.getScriptsInExecutionOrder=function(a,b){var c=a.querySelectorAll('script[type=\"text/phast\"]');var d=[],e=[];for(var f=0;f<c.length;f++){if(getSrc(c[f])!==undefined&&c[f].hasAttribute(\"defer\")){e.push(c[f])}else{d.push(c[f])}}return d.concat(e).map(function(g){return b.makeScriptFromElement(g)})};phast.ScriptsLoader.executeScripts=function(h){var i=h.map(function(k){return k.init()});var j=Promise.resolve();h.forEach(function(l){j=phast.ScriptsLoader.chainScript(j,l)});return j.then(function(){return Promise.all(i).catch(function(){})})};phast.ScriptsLoader.chainScript=function(m,n){var o;try{if(n.describe){o=n.describe()}else{o=\"unknown script\"}}catch(p){o=\"script.describe() failed\"}return m.then(function(){var q=n.execute();q.then(function(){console.debug(\"\342\234\223\",o)});return q}).catch(function(r){console.error(\"\342\234\230\",o);if(r){console.log(r)}})};var insertBefore=window.Element.prototype.insertBefore;phast.ScriptsLoader.Utilities=function(s){this._document=s;var t=0;function u(C){return new Promise(function(D){var E=\"PhastCompleteScript\"+ ++t;var F=s.createElement(\"script\");F.textContent=C;var G=s.createElement(\"script\");G.textContent=E+\"()\";window[E]=H;s.body.appendChild(F);s.body.appendChild(G);function H(){D();s.body.removeChild(F);s.body.removeChild(G);delete window[E]}})}function v(I){var J=s.createElement(I.nodeName);Array.prototype.forEach.call(I.attributes,function(K){J.setAttribute(K.nodeName,K.nodeValue)});return J}function w(L){L.removeAttribute(\"data-phast-params\");var M={};Array.prototype.map.call(L.attributes,function(N){return N.nodeName}).map(function(O){var P=O.match(/^data-phast-original-(.*)/i);if(P){M[P[1].toLowerCase()]=L.getAttribute(O);L.removeAttribute(O)}});Object.keys(M).sort().map(function(Q){L.setAttribute(Q,M[Q])});if(!(\"type\"in M)){L.removeAttribute(\"type\")}}function x(R,S){return new Promise(function(T,U){var V=S.getAttribute(\"src\");S.addEventListener(\"load\",T);S.addEventListener(\"error\",U);S.removeAttribute(\"src\");insertBefore.call(R.parentNode,S,R);R.parentNode.removeChild(R);if(V){S.setAttribute(\"src\",V)}})}function y(W,X){return A(W,function(){return u(X)})}function z(Y,Z){return A(Z,function(){return x(Y,Z)})}function A(\$,_){var aa=\$.nextElementSibling;var ba=Promise.resolve();s.write=function(fa){ca(fa)};s.writeln=function(ga){ca(ga+\"\\n\")};function ca(ha){var ia=s.createElement(\"div\");ia.innerHTML=ha;var ja=da(ia);if(aa&&aa.parentNode!==\$.parentNode){aa=\$.nextElementSibling}while(ia.firstChild){\$.parentNode.insertBefore(ia.firstChild,aa)}ja.map(ea)}function da(ka){return Array.prototype.slice.call(ka.getElementsByTagName(\"script\")).filter(function(la){var ma=la.getAttribute(\"type\");return!ma||/^(text|application)\\/javascript(;|\$)/i.test(ma)})}function ea(na){var oa=new phast.ScriptsLoader.Scripts.Factory(s);var pa=oa.makeScriptFromElement(na);ba=phast.ScriptsLoader.chainScript(ba,pa)}return _().then(function(){return ba}).finally(function(){delete s.write;delete s.writeln})}function B(qa){var ra=s.createElement(\"link\");ra.setAttribute(\"rel\",\"preload\");ra.setAttribute(\"as\",\"script\");ra.setAttribute(\"href\",qa);s.head.appendChild(ra)}this.executeString=u;this.copyElement=v;this.restoreOriginals=w;this.replaceElement=x;this.writeProtectAndExecuteString=y;this.writeProtectAndReplaceElement=z;this.addPreload=B};phast.ScriptsLoader.Scripts={};phast.ScriptsLoader.Scripts.InlineScript=function(sa,ta){this._utils=sa;this._element=ta;this.init=function(){return Promise.resolve()};this.execute=function(){var ua=ta.textContent.replace(/^\\s*<!--.*\\n/i,\"\");sa.restoreOriginals(ta);return sa.writeProtectAndExecuteString(ta,ua)};this.describe=function(){return\"inline script\"}};phast.ScriptsLoader.Scripts.AsyncBrowserScript=function(va,wa){var xa;this._utils=va;this._element=wa;this.init=function(){va.addPreload(getSrc(wa));return new Promise(function(ya){xa=ya})};this.execute=function(){var za=va.copyElement(wa);va.restoreOriginals(za);va.replaceElement(wa,za).then(xa).catch(xa);return Promise.resolve()};this.describe=function(){return\"async script at \"+getSrc(wa)}};phast.ScriptsLoader.Scripts.SyncBrowserScript=function(Aa,Ba){this._utils=Aa;this._element=Ba;this.init=function(){Aa.addPreload(getSrc(Ba));return Promise.resolve()};this.execute=function(){var Ca=Aa.copyElement(Ba);Aa.restoreOriginals(Ca);return Aa.writeProtectAndReplaceElement(Ba,Ca)};this.describe=function(){return\"sync script at \"+getSrc(Ba)}};phast.ScriptsLoader.Scripts.AsyncAJAXScript=function(Da,Ea,Fa,Ga){this._utils=Da;this._element=Ea;this._fetch=Fa;this._fallback=Ga;var Ha;var Ia;this.init=function(){Ha=Fa(Ea);return new Promise(function(Ja){Ia=Ja})};this.execute=function(){Ha.then(function(Ka){Da.restoreOriginals(Ea);return Da.executeString(Ka).then(Ia)}).catch(function(){Ga.init();return Ga.execute().then(Ia)});return Promise.resolve()};this.describe=function(){return\"bundled async script at \"+Ea.getAttribute(\"data-phast-original-src\")}};phast.ScriptsLoader.Scripts.SyncAJAXScript=function(La,Ma,Na,Oa){this._utils=La;this._element=Ma;this._fetch=Na;this._fallback=Oa;var Pa;this.init=function(){Pa=Na(Ma);return Pa};this.execute=function(){return Pa.then(function(Qa){La.restoreOriginals(Ma);return La.writeProtectAndExecuteString(Ma,Qa)}).catch(function(){Oa.init();return Oa.execute()})};this.describe=function(){return\"bundled sync script at \"+Ma.getAttribute(\"data-phast-original-src\")}};phast.ScriptsLoader.Scripts.Factory=function(Ra,Sa){var Ta=phast.ScriptsLoader.Scripts;var Ua=new phast.ScriptsLoader.Utilities(Ra);this.makeScriptFromElement=function(Ya){var Za;if(Va(Ya)){if(Xa(Ya)){Za=new Ta.AsyncBrowserScript(Ua,Ya);return Sa?new Ta.AsyncAJAXScript(Ua,Ya,Sa,Za):Za}Za=new Ta.SyncBrowserScript(Ua,Ya);return Sa?new Ta.SyncAJAXScript(Ua,Ya,Sa,Za):Za}if(Wa(Ya)){return new Ta.InlineScript(Ua,Ya)}if(Xa(Ya)){return new Ta.AsyncBrowserScript(Ua,Ya)}return new Ta.SyncBrowserScript(Ua,Ya)};function Va(\$a){return \$a.hasAttribute(\"data-phast-params\")}function Wa(_a){return!_a.hasAttribute(\"src\")}function Xa(ab){return ab.hasAttribute(\"async\")}};function getSrc(bb){if(bb.hasAttribute(\"data-phast-original-src\")){return bb.getAttribute(\"data-phast-original-src\")}else if(bb.hasAttribute(\"src\")){return bb.getAttribute(\"src\")}}\n"));
8858 + $this->context->addPhastJavaScript(\Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/ScriptsDeferring/scripts-loader.js', "var Promise=phast.ES6Promise;var hasCurrentScript=!!document.currentScript;phast.ScriptsLoader={};phast.ScriptsLoader.getScriptsInExecutionOrder=function(a,b){var c=a.querySelectorAll('script[type=\"text/phast\"]');var d=[],e=[];for(var f=0;f<c.length;f++){if(getSrc(c[f])!==undefined&&c[f].hasAttribute(\"defer\")){e.push(c[f])}else{d.push(c[f])}}return d.concat(e).map(function(g){return b.makeScriptFromElement(g)})};phast.ScriptsLoader.executeScripts=function(h){var i=h.map(function(k){return k.init()});var j=Promise.resolve();h.forEach(function(l){j=phast.ScriptsLoader.chainScript(j,l)});return j.then(function(){return Promise.all(i).catch(function(){})})};phast.ScriptsLoader.chainScript=function(m,n){var o;try{if(n.describe){o=n.describe()}else{o=\"unknown script\"}}catch(p){o=\"script.describe() failed\"}return m.then(function(){var q=n.execute();q.then(function(){console.debug(\"\342\234\223\",o)});return q}).catch(function(r){console.error(\"\342\234\230\",o);if(r){console.log(r)}})};var insertBefore=window.Element.prototype.insertBefore;phast.ScriptsLoader.Utilities=function(s){this._document=s;var t=0;function u(C){return new Promise(function(D){var E=\"PhastCompleteScript\"+ ++t;var F=s.createElement(\"script\");F.textContent=C;var G=s.createElement(\"script\");G.textContent=E+\"()\";window[E]=H;s.body.appendChild(F);s.body.appendChild(G);function H(){D();s.body.removeChild(F);s.body.removeChild(G);delete window[E]}})}function v(I){var J=s.createElement(I.nodeName);Array.prototype.forEach.call(I.attributes,function(K){J.setAttribute(K.nodeName,K.nodeValue)});return J}function w(L){L.removeAttribute(\"data-phast-params\");var M={};Array.prototype.map.call(L.attributes,function(N){return N.nodeName}).map(function(O){var P=O.match(/^data-phast-original-(.*)/i);if(P){M[P[1].toLowerCase()]=L.getAttribute(O);L.removeAttribute(O)}});Object.keys(M).sort().map(function(Q){L.setAttribute(Q,M[Q])});if(!(\"type\"in M)){L.removeAttribute(\"type\")}}function x(R,S){return new Promise(function(T,U){var V=S.getAttribute(\"src\");S.addEventListener(\"load\",T);S.addEventListener(\"error\",U);S.removeAttribute(\"src\");insertBefore.call(R.parentNode,S,R);R.parentNode.removeChild(R);if(V){S.setAttribute(\"src\",V)}})}function y(W,X){return A(W,function(){return u(X)})}function z(Y,Z){return A(Z,function(){return x(Y,Z)})}function A(\$,_){var aa=\$.nextElementSibling;var ba=Promise.resolve();var ca;if(isAsync(\$)){ca=\"async\"}else if(isDefer(\$)){ca=\"defer\"}s.write=function(ga){if(ca){console.warn(\"document.write call from \"+ca+\" script ignored\");return}da(ga)};s.writeln=function(ha){if(ca){console.warn(\"document.writeln call from \"+ca+\" script ignored\");return}da(ha+\"\\n\")};if(hasCurrentScript){try{Object.defineProperty(s,\"currentScript\",{configurable:true,get:function(){return \$}})}catch(ia){console.error(\"[Phast] Unable to override document.currentScript on this browser: \",ia)}}function da(ja){var ka=s.createElement(\"div\");ka.innerHTML=ja;var la=ea(ka);if(aa&&aa.parentNode!==\$.parentNode){aa=\$.nextElementSibling}while(ka.firstChild){\$.parentNode.insertBefore(ka.firstChild,aa)}la.map(fa)}function ea(ma){return Array.prototype.slice.call(ma.getElementsByTagName(\"script\")).filter(function(na){var oa=na.getAttribute(\"type\");return!oa||/^(text|application)\\/javascript(;|\$)/i.test(oa)})}function fa(pa){var qa=new phast.ScriptsLoader.Scripts.Factory(s);var ra=qa.makeScriptFromElement(pa);ba=phast.ScriptsLoader.chainScript(ba,ra)}return _().then(function(){return ba}).finally(function(){delete s.write;delete s.writeln;if(hasCurrentScript){delete s.currentScript}})}function B(sa){var ta=s.createElement(\"link\");ta.setAttribute(\"rel\",\"preload\");ta.setAttribute(\"as\",\"script\");ta.setAttribute(\"href\",sa);s.head.appendChild(ta)}this.executeString=u;this.copyElement=v;this.restoreOriginals=w;this.replaceElement=x;this.writeProtectAndExecuteString=y;this.writeProtectAndReplaceElement=z;this.addPreload=B};phast.ScriptsLoader.Scripts={};phast.ScriptsLoader.Scripts.InlineScript=function(ua,va){this._utils=ua;this._element=va;this.init=function(){return Promise.resolve()};this.execute=function(){var wa=va.textContent.replace(/^\\s*<!--.*\\n/i,\"\");ua.restoreOriginals(va);return ua.writeProtectAndExecuteString(va,wa)};this.describe=function(){return\"inline script\"}};phast.ScriptsLoader.Scripts.AsyncBrowserScript=function(xa,ya){var za;this._utils=xa;this._element=ya;this.init=function(){xa.addPreload(getSrc(ya));return new Promise(function(Aa){za=Aa})};this.execute=function(){var Ba=xa.copyElement(ya);xa.restoreOriginals(Ba);xa.replaceElement(ya,Ba).then(za).catch(za);return Promise.resolve()};this.describe=function(){return\"async script at \"+getSrc(ya)}};phast.ScriptsLoader.Scripts.SyncBrowserScript=function(Ca,Da){this._utils=Ca;this._element=Da;this.init=function(){Ca.addPreload(getSrc(Da));return Promise.resolve()};this.execute=function(){var Ea=Ca.copyElement(Da);Ca.restoreOriginals(Ea);return Ca.writeProtectAndReplaceElement(Da,Ea)};this.describe=function(){return\"sync script at \"+getSrc(Da)}};phast.ScriptsLoader.Scripts.AsyncAJAXScript=function(Fa,Ga,Ha,Ia){this._utils=Fa;this._element=Ga;this._fetch=Ha;this._fallback=Ia;var Ja;var Ka;this.init=function(){Ja=Ha(Ga);return new Promise(function(La){Ka=La})};this.execute=function(){Ja.then(function(Ma){Fa.restoreOriginals(Ga);return Fa.writeProtectAndExecuteString(Ga,Ma).then(Ka)}).catch(function(){Ia.init();return Ia.execute().then(Ka)});return Promise.resolve()};this.describe=function(){return\"bundled async script at \"+Ga.getAttribute(\"data-phast-original-src\")}};phast.ScriptsLoader.Scripts.SyncAJAXScript=function(Na,Oa,Pa,Qa){this._utils=Na;this._element=Oa;this._fetch=Pa;this._fallback=Qa;var Ra;this.init=function(){Ra=Pa(Oa);return Ra};this.execute=function(){return Ra.then(function(Sa){Na.restoreOriginals(Oa);return Na.writeProtectAndExecuteString(Oa,Sa)}).catch(function(){Qa.init();return Qa.execute()})};this.describe=function(){return\"bundled sync script at \"+Oa.getAttribute(\"data-phast-original-src\")}};phast.ScriptsLoader.Scripts.Factory=function(Ta,Ua){var Va=phast.ScriptsLoader.Scripts;var Wa=new phast.ScriptsLoader.Utilities(Ta);this.makeScriptFromElement=function(Za){var \$a;if(Xa(Za)){if(isAsync(Za)){\$a=new Va.AsyncBrowserScript(Wa,Za);return Ua?new Va.AsyncAJAXScript(Wa,Za,Ua,\$a):\$a}\$a=new Va.SyncBrowserScript(Wa,Za);return Ua?new Va.SyncAJAXScript(Wa,Za,Ua,\$a):\$a}if(Ya(Za)){return new Va.InlineScript(Wa,Za)}if(isAsync(Za)){return new Va.AsyncBrowserScript(Wa,Za)}return new Va.SyncBrowserScript(Wa,Za)};function Xa(_a){return _a.hasAttribute(\"data-phast-params\")}function Ya(ab){return!ab.hasAttribute(\"src\")}};function getSrc(bb){if(bb.hasAttribute(\"data-phast-original-src\")){return bb.getAttribute(\"data-phast-original-src\")}else if(bb.hasAttribute(\"src\")){return bb.getAttribute(\"src\")}}function isAsync(cb){return cb.hasAttribute(\"async\")}function isDefer(db){return db.hasAttribute(\"defer\")}\n"));
8769 8859 $this->context->addPhastJavaScript(\Kibo\Phast\ValueObjects\PhastJavaScript::fromString('/home/albert/code/phast/src/Build/../../src/Filters/HTML/ScriptsDeferring/rewrite.js', "var Promise=phast.ES6Promise;var go=phast.once(loadScripts);phast.on(document,\"DOMContentLoaded\").then(function(){if(phast.stylesLoading){phast.onStylesLoaded=go;setTimeout(go,4e3)}else{Promise.resolve().then(go)}});var loadFiltered=false;window.addEventListener(\"load\",function(a){if(!loadFiltered){a.stopImmediatePropagation()}loadFiltered=true});function loadScripts(){var b=new phast.ScriptsLoader.Scripts.Factory(document,fetchScript);var c=phast.ScriptsLoader.getScriptsInExecutionOrder(document,b);if(c.length===0){return}try{Object.defineProperty(document,\"readyState\",{configurable:true,get:function(){return\"loading\"}})}catch(d){console.error(\"[Phast] Unable to override document.readyState on this browser: \",d)}phast.ScriptsLoader.executeScripts(c).then(restoreReadyState)}function restoreReadyState(){window.requestAnimationFrame(function(){delete document[\"readyState\"];triggerEvent(document,\"readystatechange\");triggerEvent(document,\"DOMContentLoaded\");window.requestAnimationFrame(function(){if(loadFiltered){triggerEvent(window,\"load\")}else{loadFiltered=true}})})}function triggerEvent(e,f){var g=document.createEvent(\"Event\");g.initEvent(f,true,true);e.dispatchEvent(g)}function fetchScript(h){return phast.ResourceLoader.instance.get(phast.ResourceLoader.RequestParams.fromString(h.getAttribute(\"data-phast-params\")))}\n"));
8770 8860 }
8771 8861 private function rewrite(\Kibo\Phast\Parsing\HTML\HTMLStreamElements\Tag $script)
8772 8862 {
@@ -8779,9 +8869,9 @@
8779 8869 }
8780 8870 }
8781 8871 private function isDeferralDisabled(\Kibo\Phast\Parsing\HTML\HTMLStreamElements\Tag $script)
8782 8872 {
8783 - return $script->hasAttribute('data-phast-no-defer') || $script->hasAttribute('data-pagespeed-no-defer') || $script->getAttribute('data-cfasync') === 'false';
8873 + return $script->hasAttribute('data-phast-no-defer') || $script->hasAttribute('data-pagespeed-no-defer') || $script->getAttribute('data-cfasync') === 'false' || preg_match('~^\\s*(?<q>[\'"])phast-no-defer\\k<q>~', $script->textContent);
8784 8874 }
8785 8875 }
8786 8876 namespace Kibo\Phast\Filters\HTML\ImagesOptimizationService\Tags;
8787 8877
@@ -9532,26 +9622,8 @@
9532 9622 if ($this->textContent) {
9533 9623 $o .= " content=[{$this->textContent}]";
9534 9624 }
9535 9625 return $o;
9536 - }
9537 -}
9538 -namespace Kibo\Phast\Common;
9539 -
9540 -class JSMinifier extends \JSMin\JSMin
9541 -{
9542 - protected $removeLicenseHeaders;
9543 - public function __construct($input, $removeLicenseHeaders = false)
9544 - {
9545 - parent::__construct($input);
9546 - $this->removeLicenseHeaders = $removeLicenseHeaders;
9547 - }
9548 - protected function consumeMultipleLineComment()
9549 - {
9550 - parent::consumeMultipleLineComment();
9551 - if ($this->removeLicenseHeaders) {
9552 - $this->keptComment = preg_replace('~/\\*!.*?\\*/~s', '', $this->keptComment);
9553 - }
9554 9626 }
9555 9627 }
9556 9628 namespace Kibo\Phast\Logging\LogWriters\Dummy;
9557 9629