From d869f7ef484a63f4533104eabf87fb8893c469c2 Mon Sep 17 00:00:00 2001 From: John Berlin Date: Fri, 28 Jun 2019 01:01:45 -0400 Subject: [PATCH] auto-fetch: (#484) - reworked both proxy and non-proxy mode backing workers to no-longer fetch in burst mode but as sent with a maximum of 20 fetches running at a time - added just-fetch to non-proxy mode backing worker - updated the auto fetch worker abstraction in non-proxy mode used by wombat to exposed like in proxy mode and ensured that value property for the srcset object is used when sending rewritten srcset values to the backing worker - combined the backing worker proxy & non-proxy mode into a single file - added rollup config for back auto fetch worker --- pywb/static/autoFetchWorker.js | 446 ++++++------ pywb/static/autoFetchWorkerProxyMode.js | 303 --------- pywb/static/wombat.js | 4 +- pywb/static/wombatProxyMode.js | 4 +- pywb/static/wombatWorkers.js | 2 +- tests/test_proxy.py | 8 +- wombat/package.json | 21 +- wombat/rollup.config.dev.js | 58 +- wombat/rollup.config.prod.js | 22 +- wombat/src/autoFetchWorker.js | 633 ++++++++++-------- wombat/src/autoFetcher.js | 292 ++++++++ ...erProxyMode.js => autoFetcherProxyMode.js} | 106 ++- wombat/src/customStorage.js | 6 +- wombat/src/wombat.js | 27 +- wombat/src/wombatLite.js | 17 +- wombat/yarn.lock | 154 ++--- 16 files changed, 1081 insertions(+), 1022 deletions(-) delete mode 100644 pywb/static/autoFetchWorkerProxyMode.js mode change 100755 => 100644 wombat/src/autoFetchWorker.js create mode 100755 wombat/src/autoFetcher.js rename wombat/src/{autoFetchWorkerProxyMode.js => autoFetcherProxyMode.js} (85%) diff --git a/pywb/static/autoFetchWorker.js b/pywb/static/autoFetchWorker.js index 2cb21846..d0f0a664 100644 --- a/pywb/static/autoFetchWorker.js +++ b/pywb/static/autoFetchWorker.js @@ -1,20 +1,29 @@ 'use strict'; // thanks wombat var STYLE_REGEX = /(url\s*\(\s*[\\"']*)([^)'"]+)([\\"']*\s*\))/gi; -var IMPORT_REGEX = /(@import\s+[\\"']*)([^)'";]+)([\\"']*\s*;?)/gi; +var IMPORT_REGEX = /(@import\s*[\\"']*)([^)'";]+)([\\"']*\s*;?)/gi; var srcsetSplit = /\s*(\S*\s+[\d.]+[wx]),|(?:\s*,(?:\s+|(?=https?:)))/; -var DefaultNumImFetches = 30; -var FullImgQDrainLen = 10; -var DefaultNumAvFetches = 5; -var FullAVQDrainLen = 5; +var MaxRunningFetches = 15; var DataURLPrefix = 'data:'; +var seen = {}; +// array of URLs to be fetched +var queue = []; +var runningFetches = 0; +// a URL to resolve relative URLs found in the cssText of CSSMedia rules. +var currentResolver = null; -// the autofetcher instance for this worker -var autofetcher = null; +var config = { + havePromise: typeof self.Promise !== 'undefined', + haveFetch: typeof self.fetch !== 'undefined', + proxyMode: false, + mod: null, + prefix: null, + prefixMod: null, + relative: null, + rwRe: null +}; -function noop() {} - -if (typeof self.Promise === 'undefined') { +if (!config.havePromise) { // not kewl we must polyfill Promise self.Promise = function(executor) { executor(noop, noop); @@ -31,157 +40,97 @@ if (typeof self.Promise === 'undefined') { }; } -if (typeof self.fetch === 'undefined') { +if (!config.haveFetch) { // not kewl we must polyfill fetch. self.fetch = function(url) { return new Promise(function(resolve) { var xhr = new XMLHttpRequest(); - xhr.open('GET', url); + xhr.open('GET', url, true); + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + if (!config.havePromise) { + fetchDoneOrErrored(); + } + resolve(); + } + }; xhr.send(); - resolve(); }); }; } +if (location.search.indexOf('init') !== -1) { + (function() { + var init; + if (typeof self.URL === 'function') { + var loc = new self.URL(location.href); + init = JSON.parse(loc.searchParams.get('init')); + } else { + var search = decodeURIComponent(location.search.split('?')[1]).split('&'); + init = JSON.parse(search[0].substr(search[0].indexOf('=') + 1)); + init.prefix = decodeURIComponent(init.prefix); + init.baseURI = decodeURIComponent(init.prefix); + } + config.prefix = init.prefix; + config.mod = init.mod; + config.prefixMod = init.prefix + init.mod; + config.rwRe = new RegExp(init.rwRe, 'g'); + config.relative = init.prefix.split(location.origin)[1]; + config.schemeless = '/' + config.relative; + })(); +} else { + config.proxyMode = true; +} + self.onmessage = function(event) { var data = event.data; switch (data.type) { case 'values': - autofetcher.autoFetch(data); + autoFetch(data); + break; + case 'fetch-all': + justFetch(data); break; } }; -function AutoFetcher(init) { - if (!(this instanceof AutoFetcher)) { - return new AutoFetcher(init); - } - this.prefix = init.prefix; - this.mod = init.mod; - this.prefixMod = init.prefix + init.mod; - this.rwRe = new RegExp(init.rwRe); - // relative url, WorkerLocation is set by owning document - this.relative = init.prefix.split(location.origin)[1]; - // schemeless url - this.schemeless = '/' + this.relative; - // local cache of URLs fetched, to reduce server load - this.seen = {}; - // array of URLs to be fetched - this.queue = []; - this.avQueue = []; - // should we queue a URL or not - this.queuing = false; - this.queuingAV = false; - this.urlExtractor = this.urlExtractor.bind(this); - this.imgFetchDone = this.imgFetchDone.bind(this); - this.avFetchDone = this.avFetchDone.bind(this); +function noop() {} + +function fetchDoneOrErrored() { + runningFetches -= 1; + fetchFromQ(); } -AutoFetcher.prototype.delay = function() { - // 2 second delay seem reasonable - return new Promise(function(resolve, reject) { - setTimeout(resolve, 2000); - }); -}; +function fetchURL(urlToBeFetched) { + runningFetches += 1; + fetch(urlToBeFetched) + .then(fetchDoneOrErrored) + .catch(fetchDoneOrErrored); +} -AutoFetcher.prototype.imgFetchDone = function() { - if (this.queue.length > 0) { - // we have a Q of some length drain it - var autofetcher = this; - this.delay().then(function() { - autofetcher.queuing = false; - autofetcher.fetchImgs(); - }); - } else { - this.queuing = false; - } -}; - -AutoFetcher.prototype.avFetchDone = function() { - if (this.avQueue.length > 0) { - // we have a Q of some length drain it - var autofetcher = this; - this.delay().then(function() { - autofetcher.queuingAV = false; - autofetcher.fetchAV(); - }); - } else { - this.queuingAV = false; - } -}; - -AutoFetcher.prototype.fetchAV = function() { - if (this.queuingAV || this.avQueue.length === 0) { +function queueOrFetch(urlToBeFetched) { + if ( + !urlToBeFetched || + urlToBeFetched.indexOf(DataURLPrefix) === 0 || + seen[urlToBeFetched] != null + ) { return; } - // the number of fetches is limited to a maximum of DefaultNumAvFetches + FullAVQDrainLen outstanding fetches - // the baseline maximum number of fetches is DefaultNumAvFetches but if the size(avQueue) <= FullAVQDrainLen - // we add them to the current batch. Because audio video resources might be big - // we limit how many we fetch at a time drastically - this.queuingAV = true; - var runningFetchers = []; - while ( - this.avQueue.length > 0 && - runningFetchers.length <= DefaultNumAvFetches - ) { - runningFetchers.push(fetch(this.avQueue.shift()).catch(noop)); - } - if (this.avQueue.length <= FullAVQDrainLen) { - while (this.avQueue.length > 0) { - runningFetchers.push(fetch(this.avQueue.shift()).catch(noop)); - } - } - Promise.all(runningFetchers) - .then(this.avFetchDone) - .catch(this.avFetchDone); -}; - -AutoFetcher.prototype.fetchImgs = function() { - if (this.queuing || this.queue.length === 0) { + seen[urlToBeFetched] = true; + if (runningFetches >= MaxRunningFetches) { + queue.push(urlToBeFetched); return; } - // the number of fetches is limited to a maximum of DefaultNumImFetches + FullImgQDrainLen outstanding fetches - // the baseline maximum number of fetches is DefaultNumImFetches but if the size(queue) <= FullImgQDrainLen - // we add them to the current batch - this.queuing = true; - var runningFetchers = []; - while ( - this.queue.length > 0 && - runningFetchers.length <= DefaultNumImFetches - ) { - runningFetchers.push(fetch(this.queue.shift()).catch(noop)); + fetchURL(urlToBeFetched); +} + +function fetchFromQ() { + while (queue.length && runningFetches < MaxRunningFetches) { + fetchURL(queue.shift()); } - if (this.queue.length <= FullImgQDrainLen) { - while (this.queue.length > 0) { - runningFetchers.push(fetch(this.queue.shift()).catch(noop)); - } - } - Promise.all(runningFetchers) - .then(this.imgFetchDone) - .catch(this.imgFetchDone); -}; +} -AutoFetcher.prototype.queueNonAVURL = function(url) { - // ensure we do not request data urls - if (url.indexOf(DataURLPrefix) === 0) return; - // check to see if we have seen this url before in order - // to lessen the load against the server content is fetched from - if (this.seen[url] != null) return; - this.seen[url] = true; - this.queue.push(url); -}; - -AutoFetcher.prototype.queueAVURL = function(url) { - // ensure we do not request data urls - if (url.indexOf(DataURLPrefix) === 0) return; - // check to see if we have seen this url before in order - // to lessen the load against the server content is fetched from - if (this.seen[url] != null) return; - this.seen[url] = true; - this.avQueue.push(url); -}; - -AutoFetcher.prototype.maybeResolveURL = function(url, base) { +function maybeResolveURL(url, base) { // given a url and base url returns a resolved full URL or // null if resolution was unsuccessful try { @@ -190,99 +139,129 @@ AutoFetcher.prototype.maybeResolveURL = function(url, base) { } catch (e) { return null; } -}; +} -AutoFetcher.prototype.maybeFixUpRelSchemelessPrefix = function(url) { +function safeResolve(url, resolver) { + // Guard against the exception thrown by the URL constructor if the URL or resolver is bad + // if resolver is undefined/null then this function passes url through + var resolvedURL = url; + if (resolver) { + try { + var _url = new URL(url, resolver); + return _url.href; + } catch (e) { + resolvedURL = url; + } + } + return resolvedURL; +} + +function maybeFixUpRelSchemelessPrefix(url) { // attempt to ensure rewritten relative or schemeless URLs become full URLS! // otherwise returns null if this did not happen - if (url.indexOf(this.relative) === 0) { - return url.replace(this.relative, this.prefix); + if (url.indexOf(config.relative) === 0) { + return url.replace(config.relative, config.prefix); } - if (url.indexOf(this.schemeless) === 0) { - return url.replace(this.schemeless, this.prefix); + if (url.indexOf(config.schemeless) === 0) { + return url.replace(config.schemeless, config.prefix); } return null; -}; +} -AutoFetcher.prototype.maybeFixUpURL = function(url, resolveOpts) { +function maybeFixUpURL(url, resolveOpts) { // attempt to fix up the url and do our best to ensure we can get dat 200 OK! - if (this.rwRe.test(url)) { + if (config.rwRe.test(url)) { return url; } var mod = resolveOpts.mod || 'mp_'; // first check for / (relative) or // (schemeless) rewritten urls - var maybeFixed = this.maybeFixUpRelSchemelessPrefix(url); + var maybeFixed = maybeFixUpRelSchemelessPrefix(url); if (maybeFixed != null) { return maybeFixed; } // resolve URL against tag src if (resolveOpts.tagSrc != null) { - maybeFixed = this.maybeResolveURL(url, resolveOpts.tagSrc); + maybeFixed = maybeResolveURL(url, resolveOpts.tagSrc); if (maybeFixed != null) { - return this.prefix + mod + '/' + maybeFixed; + return config.prefix + mod + '/' + maybeFixed; } } // finally last attempt resolve the originating documents base URI if (resolveOpts.docBaseURI) { - maybeFixed = this.maybeResolveURL(url, resolveOpts.docBaseURI); + maybeFixed = maybeResolveURL(url, resolveOpts.docBaseURI); if (maybeFixed != null) { - return this.prefix + mod + '/' + maybeFixed; + return config.prefix + mod + '/' + maybeFixed; } } // not much to do now..... - return this.prefixMod + '/' + url; -}; + return config.prefixMod + '/' + url; +} -AutoFetcher.prototype.urlExtractor = function( - match, - n1, - n2, - n3, - offset, - string -) { +function urlExtractor(match, n1, n2, n3, offset, string) { // Same function as style_replacer in wombat.rewrite_style, n2 is our URL - this.queueNonAVURL(n2); + queueOrFetch(n2); return n1 + n2 + n3; -}; +} -AutoFetcher.prototype.handleMedia = function(mediaRules) { +function urlExtractorProxyMode(match, n1, n2, n3, offset, string) { + // Same function as style_replacer in wombat.rewrite_style, n2 is our URL + // this.currentResolver is set to the URL which the browser would normally + // resolve relative urls with (URL of the stylesheet) in an exceptionless manner + // (resolvedURL will be undefined if an error occurred) + queueOrFetch(safeResolve(n2, currentResolver)); + return n1 + n2 + n3; +} + +function handleMedia(mediaRules) { // this is a broken down rewrite_style if (mediaRules == null || mediaRules.length === 0) return; - // var rules = mediaRules.values; for (var i = 0; i < mediaRules.length; i++) { mediaRules[i] - .replace(STYLE_REGEX, this.urlExtractor) - .replace(IMPORT_REGEX, this.urlExtractor); + .replace(STYLE_REGEX, urlExtractor) + .replace(IMPORT_REGEX, urlExtractor); } -}; +} -AutoFetcher.prototype.handleSrc = function(srcValues, context) { +function handleMediaProxyMode(mediaRules) { + // this is a broken down rewrite_style + if (mediaRules == null || mediaRules.length === 0) return; + for (var i = 0; i < mediaRules.length; i++) { + // set currentResolver to the value of this stylesheets URL, done to ensure we do not have to + // create functions on each loop iteration because we potentially create a new `URL` object + // twice per iteration + currentResolver = mediaRules[i].resolve; + mediaRules[i].cssText + .replace(STYLE_REGEX, urlExtractorProxyMode) + .replace(IMPORT_REGEX, urlExtractorProxyMode); + } +} + +function handleSrc(srcValues, context) { var resolveOpts = { docBaseURI: context.docBaseURI }; if (srcValues.value) { resolveOpts.mod = srcValues.mod; - if (resolveOpts.mod === 1) { - return this.queueNonAVURL( - this.maybeFixUpURL(srcValues.value.trim(), resolveOpts) - ); - } - return this.queueAVURL( - this.maybeFixUpURL(srcValues.value.trim(), resolveOpts) - ); + return queueOrFetch(maybeFixUpURL(srcValues.value.trim(), resolveOpts)); } var len = srcValues.values.length; for (var i = 0; i < len; i++) { var value = srcValues.values[i]; resolveOpts.mod = value.mod; - if (resolveOpts.mod === 'im_') { - this.queueNonAVURL(this.maybeFixUpURL(value.src, resolveOpts)); - } else { - this.queueAVURL(this.maybeFixUpURL(value.src, resolveOpts)); - } + queueOrFetch(maybeFixUpURL(value.src, resolveOpts)); } -}; +} -AutoFetcher.prototype.extractSrcSetNotPreSplit = function(ssV, resolveOpts) { +function handleSrcProxyMode(srcValues) { + // preservation worker in proxy mode sends us the value of the srcset attribute of an element + // and a URL to correctly resolve relative URLS. Thus we must recreate rewrite_srcset logic here + if (srcValues == null || srcValues.length === 0) return; + var srcVal; + for (var i = 0; i < srcValues.length; i++) { + srcVal = srcValues[i]; + queueOrFetch(safeResolve(srcVal.src, srcVal.resolve)); + } +} + +function extractSrcSetNotPreSplit(ssV, resolveOpts) { if (!ssV) return; // was from extract from local doc so we need to duplicate work var srcsetValues = ssV.split(srcsetSplit); @@ -290,41 +269,38 @@ AutoFetcher.prototype.extractSrcSetNotPreSplit = function(ssV, resolveOpts) { // grab the URL not width/height key if (srcsetValues[i]) { var value = srcsetValues[i].trim().split(' ')[0]; - var maybeResolvedURL = this.maybeFixUpURL(value.trim(), resolveOpts); - if (resolveOpts.mod === 'im_') { - this.queueNonAVURL(maybeResolvedURL); - } else { - this.queueAVURL(maybeResolvedURL); - } + var maybeResolvedURL = maybeFixUpURL(value.trim(), resolveOpts); + queueOrFetch(maybeResolvedURL); } } -}; +} -AutoFetcher.prototype.extractSrcset = function(srcsets, context) { +function extractSrcset(srcsets) { // was rewrite_srcset and only need to q for (var i = 0; i < srcsets.length; i++) { // grab the URL not width/height key var url = srcsets[i].split(' ')[0]; - if (context.mod === 'im_') { - this.queueNonAVURL(url); - } else { - this.queueAVURL(url); - } + queueOrFetch(url); } -}; +} -AutoFetcher.prototype.handleSrcset = function(srcset, context) { - var resolveOpts = { docBaseURI: context.docBaseURI }; +function handleSrcset(srcset, context) { + if (srcset == null) return; + var resolveOpts = { + docBaseURI: context.docBaseURI, + mode: null, + tagSrc: null + }; if (srcset.value) { // we have a single value, this srcset came from either // preserveDataSrcset (not presplit) preserveSrcset (presplit) resolveOpts.mod = srcset.mod; if (!srcset.presplit) { // extract URLs from the srcset string - return this.extractSrcSetNotPreSplit(srcset.value, resolveOpts); + return extractSrcSetNotPreSplit(srcset.value, resolveOpts); } // we have an array of srcset URL strings - return this.extractSrcset(srcset.value, resolveOpts); + return extractSrcset(srcset.value); } // we have an array of values, these srcsets came from extractFromLocalDoc var len = srcset.values.length; @@ -332,38 +308,64 @@ AutoFetcher.prototype.handleSrcset = function(srcset, context) { var ssv = srcset.values[i]; resolveOpts.mod = ssv.mod; resolveOpts.tagSrc = ssv.tagSrc; - this.extractSrcSetNotPreSplit(ssv.srcset, resolveOpts); + extractSrcSetNotPreSplit(ssv.srcset, resolveOpts); } -}; +} -AutoFetcher.prototype.autoFetch = function(data) { +function handleSrcsetProxyMode(srcsets) { + // preservation worker in proxy mode sends us the value of the srcset attribute of an element + // and a URL to correctly resolve relative URLS. Thus we must recreate rewrite_srcset logic here + if (srcsets == null) return; + var length = srcsets.length; + var extractedSrcSet, srcsetValue, ssSplit, j; + for (var i = 0; i < length; i++) { + extractedSrcSet = srcsets[i]; + ssSplit = extractedSrcSet.srcset.split(srcsetSplit); + for (j = 0; j < ssSplit.length; j++) { + if (ssSplit[j]) { + srcsetValue = ssSplit[j].trim(); + if (srcsetValue) { + queueOrFetch( + safeResolve(srcsetValue.split(' ')[0], extractedSrcSet.resolve) + ); + } + } + } + } +} + +function autoFetch(data) { // we got a message and now we autofetch! // these calls turn into no ops if they have no work if (data.media) { - this.handleMedia(data.media); + if (config.proxyMode) { + handleMediaProxyMode(data.media); + } else { + handleMedia(data.media); + } } if (data.src) { - this.handleSrc(data.src, data.context || {}); + if (config.proxyMode) { + handleSrcProxyMode(data.src); + } else { + handleSrc(data.src, data.context || { docBaseURI: null }); + } } if (data.srcset) { - this.handleSrcset(data.srcset, data.context || {}); + if (config.proxyMode) { + handleSrcsetProxyMode(data.srcset); + } else { + handleSrcset(data.srcset, data.context || { docBaseURI: null }); + } + } +} + +function justFetch(data) { + // we got a message containing only urls to be fetched + if (data == null || data.values == null) return; + for (var i = 0; i < data.values.length; ++i) { + queueOrFetch(data.values[i]); } - - this.fetchImgs(); - this.fetchAV(); -}; - -// initialize ourselves from the query params :) -try { - var loc = new self.URL(location.href); - autofetcher = new AutoFetcher(JSON.parse(loc.searchParams.get('init'))); -} catch (e) { - // likely we are in an older version of safari - var search = decodeURIComponent(location.search.split('?')[1]).split('&'); - var init = JSON.parse(search[0].substr(search[0].indexOf('=') + 1)); - init.prefix = decodeURIComponent(init.prefix); - init.baseURI = decodeURIComponent(init.baseURI); - autofetcher = new AutoFetcher(init); } diff --git a/pywb/static/autoFetchWorkerProxyMode.js b/pywb/static/autoFetchWorkerProxyMode.js deleted file mode 100644 index 1abdd4c7..00000000 --- a/pywb/static/autoFetchWorkerProxyMode.js +++ /dev/null @@ -1,303 +0,0 @@ -'use strict'; -// thanks wombat -var STYLE_REGEX = /(url\s*\(\s*[\\"']*)([^)'"]+)([\\"']*\s*\))/gi; -var IMPORT_REGEX = /(@import\s+[\\"']*)([^)'";]+)([\\"']*\s*;?)/gi; -var srcsetSplit = /\s*(\S*\s+[\d.]+[wx]),|(?:\s*,(?:\s+|(?=https?:)))/; -var DefaultNumImFetches = 30; -var FullImgQDrainLen = 10; -var DefaultNumAvFetches = 5; -var FullAVQDrainLen = 5; -var DataURLPrefix = 'data:'; -var FetchDelay = 1000; -// the autofetcher instance for this worker -var autofetcher = null; - -function noop() {} - -if (typeof self.Promise === 'undefined') { - // not kewl we must polyfill Promise - self.Promise = function(executor) { - executor(noop, noop); - }; - self.Promise.prototype.then = function(cb) { - if (cb) cb(); - return this; - }; - self.Promise.prototype.catch = function() { - return this; - }; - self.Promise.all = function(values) { - return new Promise(noop); - }; -} - -if (typeof self.fetch === 'undefined') { - // not kewl we must polyfill fetch. - self.fetch = function(url) { - return new Promise(function(resolve) { - var xhr = new XMLHttpRequest(); - xhr.open('GET', url); - xhr.send(); - resolve(); - }); - }; -} - -self.onmessage = function(event) { - var data = event.data; - switch (data.type) { - case 'values': - autofetcher.autofetchMediaSrcset(data); - break; - case 'fetch-all': - autofetcher.justFetch(data); - break; - } -}; - -function AutoFetcher() { - if (!(this instanceof AutoFetcher)) { - return new AutoFetcher(); - } - // local cache of URLs fetched, to reduce server load - this.seen = {}; - // array of URLs to be fetched - this.queue = []; - this.avQueue = []; - // should we queue a URL or not - this.queuing = false; - // a URL to resolve relative URLs found in the cssText of CSSMedia rules. - this.currentResolver = null; - // should we queue a URL or not - this.queuing = false; - this.queuingAV = false; - this.urlExtractor = this.urlExtractor.bind(this); - this.imgFetchDone = this.imgFetchDone.bind(this); - this.avFetchDone = this.avFetchDone.bind(this); -} - -AutoFetcher.prototype.delay = function() { - return new Promise(function(resolve, reject) { - setTimeout(resolve, FetchDelay); - }); -}; - -AutoFetcher.prototype.imgFetchDone = function() { - if (this.queue.length > 0) { - // we have a Q of some length drain it - var autofetcher = this; - this.delay().then(function() { - autofetcher.queuing = false; - autofetcher.fetchImgs(); - }); - } else { - this.queuing = false; - } -}; - -AutoFetcher.prototype.avFetchDone = function() { - if (this.avQueue.length > 0) { - // we have a Q of some length drain it - var autofetcher = this; - this.delay().then(function() { - autofetcher.queuingAV = false; - autofetcher.fetchAV(); - }); - } else { - this.queuingAV = false; - } -}; - -AutoFetcher.prototype.fetchAV = function() { - if (this.queuingAV || this.avQueue.length === 0) { - return; - } - // the number of fetches is limited to a maximum of DefaultNumAvFetches + FullAVQDrainLen outstanding fetches - // the baseline maximum number of fetches is DefaultNumAvFetches but if the size(avQueue) <= FullAVQDrainLen - // we add them to the current batch. Because audio video resources might be big - // we limit how many we fetch at a time drastically - this.queuingAV = true; - var runningFetchers = []; - while ( - this.avQueue.length > 0 && - runningFetchers.length <= DefaultNumAvFetches - ) { - runningFetchers.push(fetch(this.avQueue.shift()).catch(noop)); - } - if (this.avQueue.length <= FullAVQDrainLen) { - while (this.avQueue.length > 0) { - runningFetchers.push(fetch(this.avQueue.shift()).catch(noop)); - } - } - Promise.all(runningFetchers) - .then(this.avFetchDone) - .catch(this.avFetchDone); -}; - -AutoFetcher.prototype.fetchImgs = function() { - if (this.queuing || this.queue.length === 0) { - return; - } - // the number of fetches is limited to a maximum of DefaultNumImFetches + FullImgQDrainLen outstanding fetches - // the baseline maximum number of fetches is DefaultNumImFetches but if the size(queue) <= FullImgQDrainLen - // we add them to the current batch - this.queuing = true; - var runningFetchers = []; - while ( - this.queue.length > 0 && - runningFetchers.length <= DefaultNumImFetches - ) { - runningFetchers.push(fetch(this.queue.shift()).catch(noop)); - } - if (this.queue.length <= FullImgQDrainLen) { - while (this.queue.length > 0) { - runningFetchers.push(fetch(this.queue.shift()).catch(noop)); - } - } - Promise.all(runningFetchers) - .then(this.imgFetchDone) - .catch(this.imgFetchDone); -}; - -AutoFetcher.prototype.queueNonAVURL = function(url) { - // ensure we do not request data urls - if (url.indexOf(DataURLPrefix) === 0) return; - // check to see if we have seen this url before in order - // to lessen the load against the server content is fetched from - if (this.seen[url] != null) return; - this.seen[url] = true; - this.queue.push(url); -}; - -AutoFetcher.prototype.queueAVURL = function(url) { - // ensure we do not request data urls - if (url.indexOf(DataURLPrefix) === 0) return; - // check to see if we have seen this url before in order - // to lessen the load against the server content is fetched from - if (this.seen[url] != null) return; - this.seen[url] = true; - this.avQueue.push(url); -}; - -AutoFetcher.prototype.safeResolve = function(url, resolver) { - // Guard against the exception thrown by the URL constructor if the URL or resolver is bad - // if resolver is undefined/null then this function passes url through - var resolvedURL = url; - if (resolver) { - try { - resolvedURL = new URL(url, resolver).href; - } catch (e) { - resolvedURL = url; - } - } - return resolvedURL; -}; - -AutoFetcher.prototype.urlExtractor = function( - match, - n1, - n2, - n3, - offset, - string -) { - // Same function as style_replacer in wombat.rewrite_style, n2 is our URL - // this.currentResolver is set to the URL which the browser would normally - // resolve relative urls with (URL of the stylesheet) in an exceptionless manner - // (resolvedURL will be undefined if an error occurred) - var resolvedURL = this.safeResolve(n2, this.currentResolver); - if (resolvedURL) { - this.queueNonAVURL(resolvedURL); - } - return n1 + n2 + n3; -}; - -AutoFetcher.prototype.extractMedia = function(mediaRules) { - // this is a broken down rewrite_style - if (mediaRules == null) return; - for (var i = 0; i < mediaRules.length; i++) { - // set currentResolver to the value of this stylesheets URL, done to ensure we do not have to - // create functions on each loop iteration because we potentially create a new `URL` object - // twice per iteration - this.currentResolver = mediaRules[i].resolve; - mediaRules[i].cssText - .replace(STYLE_REGEX, this.urlExtractor) - .replace(IMPORT_REGEX, this.urlExtractor); - } -}; - -AutoFetcher.prototype.extractSrcset = function(srcsets) { - // preservation worker in proxy mode sends us the value of the srcset attribute of an element - // and a URL to correctly resolve relative URLS. Thus we must recreate rewrite_srcset logic here - if (srcsets == null) return; - var length = srcsets.length; - var extractedSrcSet, srcsetValue, ssSplit, j; - for (var i = 0; i < length; i++) { - extractedSrcSet = srcsets[i]; - ssSplit = extractedSrcSet.srcset.split(srcsetSplit); - console.log(ssSplit); - for (j = 0; j < ssSplit.length; j++) { - if (ssSplit[j]) { - srcsetValue = ssSplit[j].trim(); - if (srcsetValue.length > 0) { - // resolve the URL in an exceptionless manner (resolvedURL will be undefined if an error occurred) - var resolvedURL = this.safeResolve( - srcsetValue.split(' ')[0], - extractedSrcSet.resolve - ); - if (resolvedURL) { - if (extractedSrcSet.mod === 'im_') { - this.queueNonAVURL(resolvedURL); - } else { - this.queueAVURL(resolvedURL); - } - } else { - console.log(resolvedURL); - } - } else { - console.log(srcsetValue); - } - } - } - } -}; - -AutoFetcher.prototype.extractSrc = function(srcVals) { - // preservation worker in proxy mode sends us the value of the srcset attribute of an element - // and a URL to correctly resolve relative URLS. Thus we must recreate rewrite_srcset logic here - if (srcVals == null || srcVals.length === 0) return; - var length = srcVals.length; - var srcVal; - for (var i = 0; i < length; i++) { - srcVal = srcVals[i]; - var resolvedURL = this.safeResolve(srcVal.src, srcVal.resolve); - if (resolvedURL) { - if (srcVal.mod === 'im_') { - this.queueNonAVURL(resolvedURL); - } else { - this.queueAVURL(resolvedURL); - } - } - } -}; - -AutoFetcher.prototype.autofetchMediaSrcset = function(data) { - // we got a message and now we autofetch! - // these calls turn into no ops if they have no work - this.extractMedia(data.media); - this.extractSrcset(data.srcset); - this.extractSrc(data.src); - this.fetchImgs(); - this.fetchAV(); -}; - -AutoFetcher.prototype.justFetch = function(data) { - // we got a message containing only urls to be fetched - if (data == null || data.values == null) return; - for (var i = 0; i < data.values.length; ++i) { - this.queueNonAVURL(data.values[i]); - } - this.fetchImgs(); -}; - -autofetcher = new AutoFetcher(); diff --git a/pywb/static/wombat.js b/pywb/static/wombat.js index 8135a3cd..6178534a 100644 --- a/pywb/static/wombat.js +++ b/pywb/static/wombat.js @@ -1,5 +1,5 @@ /* -Copyright(c) 2013-2018 Rhizome and Ilya Kreymer. Released under the GNU General Public License. +Copyright(c) 2013-2018 Rhizome and Contributors. Released under the GNU General Public License. This file is part of pywb, https://github.com/webrecorder/pywb @@ -16,4 +16,4 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with pywb. If not, see . */ -(function(){function FuncMap(){this._map=[]}function ensureNumber(maybeNumber){try{switch(typeof maybeNumber){case"number":case"bigint":return maybeNumber;}var converted=Number(maybeNumber);return isNaN(converted)?null:converted}catch(e){}return null}function addToStringTagToClass(clazz,tag){typeof self.Symbol!=="undefined"&&typeof self.Symbol.toStringTag!=="undefined"&&Object.defineProperty(clazz.prototype,self.Symbol.toStringTag,{value:tag,enumerable:false})}function autobind(clazz){for(var prop,propValue,proto=clazz.__proto__||clazz.constructor.prototype||clazz.prototype,clazzProps=Object.getOwnPropertyNames(proto),len=clazzProps.length,i=0;i=0){var fnMapping=this._map.splice(idx,1);return fnMapping[0][1]}return null},FuncMap.prototype.map=function(param){for(var i=0;i0&&afw.preserveMedia(media)})},AutoFetchWorker.prototype.terminate=function(){this.worker.terminate()},AutoFetchWorker.prototype.postMessage=function(msg,deferred){if(deferred){var afWorker=this;return void Promise.resolve().then(function(){afWorker.worker.postMessage(msg)})}this.worker.postMessage(msg)},AutoFetchWorker.prototype.preserveSrcset=function(srcset,mod){this.postMessage({type:"values",srcset:{values:srcset,mod:mod,presplit:true}},true)},AutoFetchWorker.prototype.preserveDataSrcset=function(elem){this.postMessage({type:"values",srcset:{value:elem.dataset.srcset,mod:this.rwMod(elem),presplit:false}},true)},AutoFetchWorker.prototype.preserveMedia=function(media){this.postMessage({type:"values",media:media},true)},AutoFetchWorker.prototype.getSrcset=function(elem){return this.wombat.wb_getAttribute?this.wombat.wb_getAttribute.call(elem,"srcset"):elem.getAttribute("srcset")},AutoFetchWorker.prototype.rwMod=function(elem){switch(elem.tagName){case"SOURCE":return elem.parentElement&&elem.parentElement.tagName==="PICTURE"?"im_":"oe_";case"IMG":return"im_";}return"oe_"},AutoFetchWorker.prototype.extractFromLocalDoc=function(){var afw=this;Promise.resolve().then(function(){for(var msg={type:"values",context:{docBaseURI:document.baseURI}},media=[],i=0,sheets=document.styleSheets;i=0},Wombat.prototype.isString=function(arg){return arg!=null&&Object.getPrototypeOf(arg)===String.prototype},Wombat.prototype.isSavedSrcSrcset=function(elem){switch(elem.tagName){case"IMG":case"VIDEO":case"AUDIO":return true;case"SOURCE":if(!elem.parentElement)return false;switch(elem.parentElement.tagName){case"PICTURE":case"VIDEO":case"AUDIO":return true;default:return false;}default:return false;}},Wombat.prototype.isSavedDataSrcSrcset=function(elem){return!!(elem.dataset&&elem.dataset.srcset!=null)&&this.isSavedSrcSrcset(elem)},Wombat.prototype.isHostUrl=function(str){if(str.indexOf("www.")===0)return true;var matches=str.match(this.hostnamePortRe);return!!(matches&&matches[0].length<64)||(matches=str.match(this.ipPortRe),!!matches&&matches[0].length<64)},Wombat.prototype.isArgumentsObj=function(maybeArgumentsObj){if(!maybeArgumentsObj||typeof maybeArgumentsObj.toString!=="function")return false;try{return this.utilFns.objToString.call(maybeArgumentsObj)==="[object Arguments]"}catch(e){return false}},Wombat.prototype.deproxyArrayHandlingArgumentsObj=function(maybeArgumentsObj){if(!maybeArgumentsObj||maybeArgumentsObj instanceof NodeList||!maybeArgumentsObj.length)return maybeArgumentsObj;for(var args=this.isArgumentsObj(maybeArgumentsObj)?new Array(maybeArgumentsObj.length):maybeArgumentsObj,i=0;i=0)||scriptType.indexOf("text/template")>=0)},Wombat.prototype.skipWrapScriptTextBasedOnText=function(text){if(!text||text.indexOf("_____WB$wombat$assign$function_____")>=0||text.indexOf("<")===0)return true;for(var override_props=["window","self","document","location","top","parent","frames","opener"],i=0;i=0)return false;return true},Wombat.prototype.nodeHasChildren=function(node){if(!node)return false;if(typeof node.hasChildNodes==="function")return node.hasChildNodes();var kids=node.children||node.childNodes;return!!kids&&kids.length>0},Wombat.prototype.rwModForElement=function(elem,attrName){if(!elem)return undefined;var mod="mp_";if(!(elem.tagName==="LINK"&&attrName==="href")){var maybeMod=this.tagToMod[elem.tagName];maybeMod!=null&&(mod=maybeMod[attrName])}else if(elem.rel){var relV=elem.rel.trim().toLowerCase(),asV=this.wb_getAttribute.call(elem,"as");if(asV&&this.linkTagMods.linkRelToAs[relV]!=null){var asMods=this.linkTagMods.linkRelToAs[relV];mod=asMods[asV.toLowerCase()]}else this.linkTagMods[relV]!=null&&(mod=this.linkTagMods[relV])}return mod},Wombat.prototype.removeWBOSRC=function(elem){elem.tagName!=="SCRIPT"||elem.__$removedWBOSRC$__||(elem.hasAttribute("__wb_orig_src")&&elem.removeAttribute("__wb_orig_src"),elem.__$removedWBOSRC$__=true)},Wombat.prototype.retrieveWBOSRC=function(elem){if(elem.tagName==="SCRIPT"&&!elem.__$removedWBOSRC$__){var maybeWBOSRC;return maybeWBOSRC=this.wb_getAttribute?this.wb_getAttribute.call(elem,"__wb_orig_src"):elem.getAttribute("__wb_orig_src"),maybeWBOSRC==null&&(elem.__$removedWBOSRC$__=true),maybeWBOSRC}return undefined},Wombat.prototype.wrapScriptTextJsProxy=function(scriptText){return"var _____WB$wombat$assign$function_____ = function(name) {return (self._wb_wombat && self._wb_wombat.local_init &&self._wb_wombat.local_init(name)) || self[name]; };\nvar _____WB$wombat$check$this$function_____ = function(thisObj) {if (thisObj && thisObj._WB_wombat_obj_proxy) return thisObj._WB_wombat_obj_proxy;return thisObj; }\nif (!self.__WB_pmw) { self.__WB_pmw = function(obj) { this.__WB_source = obj; return this; } }\n{\nlet window = _____WB$wombat$assign$function_____(\"window\");\nlet self = _____WB$wombat$assign$function_____(\"self\");\nlet document = _____WB$wombat$assign$function_____(\"document\");\nlet location = _____WB$wombat$assign$function_____(\"location\");\nlet top = _____WB$wombat$assign$function_____(\"top\");\nlet parent = _____WB$wombat$assign$function_____(\"parent\");\nlet frames = _____WB$wombat$assign$function_____(\"frames\");\nlet opener = _____WB$wombat$assign$function_____(\"opener\");\n"+scriptText.replace(this.DotPostMessageRe,".__WB_pmw(self.window)$1")+"\n\n}"},Wombat.prototype.watchElem=function(elem,func){if(!this.$wbwindow.MutationObserver)return false;var m=new this.$wbwindow.MutationObserver(function(records,observer){for(var r,i=0;i"},Wombat.prototype.getFinalUrl=function(useRel,mod,url){var prefix=useRel?this.wb_rel_prefix:this.wb_abs_prefix;return mod==null&&(mod=this.wb_info.mod),this.wb_info.is_live||(prefix+=this.wb_info.wombat_ts),prefix+=mod,prefix[prefix.length-1]!=="/"&&(prefix+="/"),prefix+url},Wombat.prototype.resolveRelUrl=function(url,doc){var docObj=doc||this.$wbwindow.document,parser=this.makeParser(docObj.baseURI,docObj),hash=parser.href.lastIndexOf("#"),href=hash>=0?parser.href.substring(0,hash):parser.href,lastslash=href.lastIndexOf("/");return parser.href=lastslash>=0&&lastslash!==href.length-1?href.substring(0,lastslash+1)+url:href+url,parser.href},Wombat.prototype.extractOriginalURL=function(rewrittenUrl){if(!rewrittenUrl)return"";if(this.wb_is_proxy)return rewrittenUrl;var rwURLString=rewrittenUrl.toString(),url=rwURLString;if(this.startsWithOneOf(url,this.IGNORE_PREFIXES))return url;var start=this.wb_rel_prefix?1:0,index=url.indexOf("/http",start);return index<0&&(index=url.indexOf("///",start)),index>=0?url=url.substr(index+1):(index=url.indexOf(this.wb_replay_prefix),index>=0&&(url=url.substr(index+this.wb_replay_prefix.length)),url.length>4&&url.charAt(2)==="_"&&url.charAt(3)==="/"&&(url=url.substr(4)),url!==rwURLString&&!this.startsWithOneOf(url,this.VALID_PREFIXES)&&(url=this.wb_orig_scheme+url)),rwURLString.charAt(0)==="/"&&rwURLString.charAt(1)!=="/"&&this.startsWith(url,this.wb_orig_origin)&&(url=url.substr(this.wb_orig_origin.length)),this.startsWith(url,this.REL_PREFIX)?this.wb_info.wombat_scheme+":"+url:url},Wombat.prototype.makeParser=function(maybeRewrittenURL,doc){var originalURL=this.extractOriginalURL(maybeRewrittenURL),docElem=doc;doc||(this.$wbwindow.location.href==="about:blank"&&this.$wbwindow.opener?docElem=this.$wbwindow.opener.document:docElem=this.$wbwindow.document);var p=docElem.createElement("a");return p._no_rewrite=true,p.href=originalURL,p},Wombat.prototype.defProp=function(obj,prop,setFunc,getFunc,enumerable){var existingDescriptor=Object.getOwnPropertyDescriptor(obj,prop);if(existingDescriptor&&!existingDescriptor.configurable)return false;if(!getFunc)return false;var descriptor={configurable:true,enumerable:enumerable||false,get:getFunc};setFunc&&(descriptor.set=setFunc);try{return Object.defineProperty(obj,prop,descriptor),true}catch(e){return console.warn("Failed to redefine property %s",prop,e.message),false}},Wombat.prototype.defGetterProp=function(obj,prop,getFunc,enumerable){var existingDescriptor=Object.getOwnPropertyDescriptor(obj,prop);if(existingDescriptor&&!existingDescriptor.configurable)return false;if(!getFunc)return false;try{return Object.defineProperty(obj,prop,{configurable:true,enumerable:enumerable||false,get:getFunc}),true}catch(e){return console.warn("Failed to redefine property %s",prop,e.message),false}},Wombat.prototype.getOrigGetter=function(obj,prop){var orig_getter;if(obj.__lookupGetter__&&(orig_getter=obj.__lookupGetter__(prop)),!orig_getter&&Object.getOwnPropertyDescriptor){var props=Object.getOwnPropertyDescriptor(obj,prop);props&&(orig_getter=props.get)}return orig_getter},Wombat.prototype.getOrigSetter=function(obj,prop){var orig_setter;if(obj.__lookupSetter__&&(orig_setter=obj.__lookupSetter__(prop)),!orig_setter&&Object.getOwnPropertyDescriptor){var props=Object.getOwnPropertyDescriptor(obj,prop);props&&(orig_setter=props.set)}return orig_setter},Wombat.prototype.getAllOwnProps=function(obj){for(var ownProps=[],props=Object.getOwnPropertyNames(obj),i=0;i "+final_href),actualLocation.href=final_href}}},Wombat.prototype.checkLocationChange=function(wombatLoc,isTop){var locType=typeof wombatLoc,actual_location=isTop?this.$wbwindow.__WB_replay_top.location:this.$wbwindow.location;locType==="string"?this.updateLocation(wombatLoc,actual_location.href,actual_location):locType==="object"&&this.updateLocation(wombatLoc.href,wombatLoc._orig_href,actual_location)},Wombat.prototype.checkAllLocations=function(){return!this.wb_wombat_updating&&void(this.wb_wombat_updating=true,this.checkLocationChange(this.$wbwindow.WB_wombat_location,false),this.$wbwindow.WB_wombat_location!=this.$wbwindow.__WB_replay_top.WB_wombat_location&&this.checkLocationChange(this.$wbwindow.__WB_replay_top.WB_wombat_location,true),this.wb_wombat_updating=false)},Wombat.prototype.proxyToObj=function(source){if(source)try{var proxyRealObj=source.__WBProxyRealObj__;if(proxyRealObj)return proxyRealObj}catch(e){}return source},Wombat.prototype.objToProxy=function(obj){if(obj)try{var maybeWbProxy=obj._WB_wombat_obj_proxy;if(maybeWbProxy)return maybeWbProxy}catch(e){}return obj},Wombat.prototype.defaultProxyGet=function(obj,prop,ownProps,fnCache){switch(prop){case"__WBProxyRealObj__":return obj;case"location":case"WB_wombat_location":return obj.WB_wombat_location;case"_WB_wombat_obj_proxy":return obj._WB_wombat_obj_proxy;case"__WB_pmw":return obj[prop];case"constructor":if(obj.constructor===Window)return obj.constructor;}var retVal=obj[prop],type=typeof retVal;if(type==="function"&&ownProps.indexOf(prop)!==-1){switch(prop){case"requestAnimationFrame":case"cancelAnimationFrame":{if(!this.isNativeFunction(retVal))return retVal;break}}var cachedFN=fnCache[prop];return cachedFN&&cachedFN.original===retVal||(cachedFN={original:retVal,boundFn:retVal.bind(obj)},fnCache[prop]=cachedFN),cachedFN.boundFn}return type==="object"&&retVal&&retVal._WB_wombat_obj_proxy?(retVal instanceof Window&&this.initNewWindowWombat(retVal),retVal._WB_wombat_obj_proxy):retVal},Wombat.prototype.setLoc=function(loc,originalURL){var parser=this.makeParser(originalURL,loc.ownerDocument);loc._orig_href=originalURL,loc._parser=parser;var href=parser.href;loc._hash=parser.hash,loc._href=href,loc._host=parser.host,loc._hostname=parser.hostname,loc._origin=parser.origin?parser.origin:parser.protocol+"//"+parser.hostname+(parser.port?":"+parser.port:""),loc._pathname=parser.pathname,loc._port=parser.port,loc._protocol=parser.protocol,loc._search=parser.search,Object.defineProperty||(loc.href=href,loc.hash=parser.hash,loc.host=loc._host,loc.hostname=loc._hostname,loc.origin=loc._origin,loc.pathname=loc._pathname,loc.port=loc._port,loc.protocol=loc._protocol,loc.search=loc._search)},Wombat.prototype.makeGetLocProp=function(prop,origGetter){var wombat=this;return function newGetLocProp(){if(this._no_rewrite)return origGetter.call(this,prop);var curr_orig_href=origGetter.call(this,"href");return prop==="href"?wombat.extractOriginalURL(curr_orig_href):(this._orig_href!==curr_orig_href&&wombat.setLoc(this,curr_orig_href),this["_"+prop])}},Wombat.prototype.makeSetLocProp=function(prop,origSetter,origGetter){var wombat=this;return function newSetLocProp(value){if(this._no_rewrite)return origSetter.call(this,prop,value);if(this["_"+prop]!==value){if(this["_"+prop]=value,!this._parser){var href=origGetter.call(this);this._parser=wombat.makeParser(href,this.ownerDocument)}var rel=false;prop==="href"&&typeof value==="string"&&value&&(value[0]==="."?value=wombat.resolveRelUrl(value,this.ownerDocument):value[0]==="/"&&(value.length<=1||value[1]!=="/")&&(rel=true,value=WB_wombat_location.origin+value));try{this._parser[prop]=value}catch(e){console.log("Error setting "+prop+" = "+value)}prop==="hash"?(value=this._parser[prop],origSetter.call(this,"hash",value)):(rel=rel||value===this._parser.pathname,value=wombat.rewriteUrl(this._parser.href,rel),origSetter.call(this,"href",value))}}},Wombat.prototype.styleReplacer=function(match,n1,n2,n3,offset,string){return n1+this.rewriteUrl(n2)+n3},Wombat.prototype.ensureServerSideInjectsExistOnWindow=function(win){win&&(typeof win._____WB$wombat$check$this$function_____!=="function"&&(win._____WB$wombat$check$this$function_____=function(thisObj){return thisObj&&thisObj._WB_wombat_obj_proxy?thisObj._WB_wombat_obj_proxy:thisObj}),typeof win._____WB$wombat$assign$function_____!=="function"&&(win._____WB$wombat$assign$function_____=function(name){return self._wb_wombat&&self._wb_wombat.local_init&&self._wb_wombat.local_init(name)||self[name]}))},Wombat.prototype.domConstructorErrorChecker=function(thisObj,what,args,numRequiredArgs){var erorMsg,needArgs=typeof numRequiredArgs==="number"?numRequiredArgs:1;if(thisObj instanceof Window?erorMsg="Failed to construct '"+what+"': Please use the 'new' operator, this DOM object constructor cannot be called as a function.":args&&args.length=0)return url;if(url.indexOf(this.wb_rel_prefix)===0&&url.indexOf("http")>1){var scheme_sep=url.indexOf(":/");return scheme_sep>0&&url[scheme_sep+2]!=="/"?url.substring(0,scheme_sep+2)+"/"+url.substring(scheme_sep+2):url}return this.getFinalUrl(true,mod,this.wb_orig_origin+url)}url.charAt(0)==="."&&(url=this.resolveRelUrl(url,doc));var prefix=this.startsWithOneOf(url.toLowerCase(),this.VALID_PREFIXES);if(prefix){var orig_host=this.$wbwindow.__WB_replay_top.location.host,orig_protocol=this.$wbwindow.__WB_replay_top.location.protocol,prefix_host=prefix+orig_host+"/";if(this.startsWith(url,prefix_host)){if(this.startsWith(url,this.wb_replay_prefix))return url;var curr_scheme=orig_protocol+"//",path=url.substring(prefix_host.length),rebuild=false;return path.indexOf(this.wb_rel_prefix)<0&&url.indexOf("/static/")<0&&(path=this.getFinalUrl(true,mod,WB_wombat_location.origin+"/"+path),rebuild=true),prefix!==curr_scheme&&prefix!==this.REL_PREFIX&&(rebuild=true),rebuild&&(url=useRel?"":curr_scheme+orig_host,path&&path[0]!=="/"&&(url+="/"),url+=path),url}return this.getFinalUrl(useRel,mod,url)}return prefix=this.startsWithOneOf(url,this.BAD_PREFIXES),prefix?this.getFinalUrl(useRel,mod,this.extractOriginalURL(url)):this.isHostUrl(url)&&!this.startsWith(url,originalLoc.host+"/")?this.getFinalUrl(useRel,mod,this.wb_orig_scheme+url):url},Wombat.prototype.rewriteUrl=function(url,useRel,mod,doc){var rewritten=this.rewriteUrl_(url,useRel,mod,doc);return this.debug_rw&&(url===rewritten?console.log("NOT REWRITTEN "+url):console.log("REWRITE: "+url+" -> "+rewritten)),rewritten},Wombat.prototype.performAttributeRewrite=function(elem,name,value,absUrlOnly){switch(name){case"innerHTML":case"outerHTML":return this.rewriteHtml(value);case"filter":return this.rewriteInlineStyle(value);case"style":return this.rewriteStyle(value);case"srcset":return this.rewriteSrcset(value,elem);}if(absUrlOnly&&!this.startsWithOneOf(value,this.VALID_PREFIXES))return value;var mod=this.rwModForElement(elem,name);return this.wbUseAFWorker&&this.WBAutoFetchWorker&&this.isSavedDataSrcSrcset(elem)&&this.WBAutoFetchWorker.preserveDataSrcset(elem),this.rewriteUrl(value,false,mod,elem.ownerDocument)},Wombat.prototype.rewriteAttr=function(elem,name,absUrlOnly){var changed=false;if(!elem||!elem.getAttribute||elem._no_rewrite||elem["_"+name])return changed;var value=this.wb_getAttribute.call(elem,name);if(!value||this.startsWith(value,"javascript:"))return changed;var new_value=this.performAttributeRewrite(elem,name,value,absUrlOnly);return new_value!==value&&(this.removeWBOSRC(elem),this.wb_setAttribute.call(elem,name,new_value),changed=true),changed},Wombat.prototype.noExceptRewriteStyle=function(style){try{return this.rewriteStyle(style)}catch(e){return style}},Wombat.prototype.rewriteStyle=function(style){if(!style)return style;var value=style;return typeof style==="object"&&(value=style.toString()),typeof value==="string"?value.replace(this.STYLE_REGEX,this.styleReplacer).replace(this.IMPORT_REGEX,this.styleReplacer).replace(this.no_wombatRe,""):value},Wombat.prototype.rewriteSrcset=function(value,elem){if(!value)return"";for(var split=value.split(this.srcsetRe),values=[],i=0;i=0){var JS="javascript:";new_value="javascript:window.parent._wb_wombat.initNewWindowWombat(window);"+value.substr(11)}return new_value||(new_value=this.rewriteUrl(value,false,this.rwModForElement(elem,attrName))),new_value!==value&&(this.wb_setAttribute.call(elem,attrName,new_value),true)},Wombat.prototype.rewriteScript=function(elem){if(elem.hasAttribute("src")||!elem.textContent||!this.$wbwindow.Proxy)return this.rewriteAttr(elem,"src");if(this.skipWrapScriptBasedOnType(elem.type))return false;var text=elem.textContent.trim();return!this.skipWrapScriptTextBasedOnText(text)&&(elem.textContent=this.wrapScriptTextJsProxy(text),true)},Wombat.prototype.rewriteSVGElem=function(elem){var changed=this.rewriteAttr(elem,"filter");return changed=this.rewriteAttr(elem,"style")||changed,changed=this.rewriteAttr(elem,"xlink:href")||changed,changed=this.rewriteAttr(elem,"href")||changed,changed=this.rewriteAttr(elem,"src")||changed,changed},Wombat.prototype.rewriteElem=function(elem){var changed=false;if(!elem)return changed;if(elem instanceof SVGElement)changed=this.rewriteSVGElem(elem);else switch(elem.tagName){case"META":var maybeCSP=this.wb_getAttribute.call(elem,"http-equiv");maybeCSP&&maybeCSP.toLowerCase()==="content-security-policy"&&(this.wb_setAttribute.call(elem,"http-equiv","_"+maybeCSP),changed=true);break;case"STYLE":var new_content=this.rewriteStyle(elem.textContent);elem.textContent!==new_content&&(elem.textContent=new_content,changed=true,this.wbUseAFWorker&&this.WBAutoFetchWorker&&elem.sheet!=null&&this.WBAutoFetchWorker.deferredSheetExtraction(elem.sheet));break;case"LINK":changed=this.rewriteAttr(elem,"href"),this.wbUseAFWorker&&elem.rel==="stylesheet"&&this._addEventListener(elem,"load",this.utilFns.wbSheetMediaQChecker);break;case"IMG":changed=this.rewriteAttr(elem,"src"),changed=this.rewriteAttr(elem,"srcset")||changed,changed=this.rewriteAttr(elem,"style")||changed,this.wbUseAFWorker&&this.WBAutoFetchWorker&&elem.dataset.srcset&&this.WBAutoFetchWorker.preserveDataSrcset(elem);break;case"OBJECT":changed=this.rewriteAttr(elem,"data",true),changed=this.rewriteAttr(elem,"style")||changed;break;case"FORM":changed=this.rewriteAttr(elem,"poster"),changed=this.rewriteAttr(elem,"action")||changed,changed=this.rewriteAttr(elem,"style")||changed;break;case"IFRAME":case"FRAME":changed=this.rewriteFrameSrc(elem,"src"),changed=this.rewriteAttr(elem,"style")||changed;break;case"SCRIPT":changed=this.rewriteScript(elem);break;default:{changed=this.rewriteAttr(elem,"src"),changed=this.rewriteAttr(elem,"srcset")||changed,changed=this.rewriteAttr(elem,"href")||changed,changed=this.rewriteAttr(elem,"style")||changed,changed=this.rewriteAttr(elem,"poster")||changed;break}}return elem.hasAttribute&&elem.removeAttribute&&(elem.hasAttribute("crossorigin")&&(elem.removeAttribute("crossorigin"),changed=true),elem.hasAttribute("integrity")&&(elem.removeAttribute("integrity"),changed=true)),changed},Wombat.prototype.recurseRewriteElem=function(curr){if(!this.nodeHasChildren(curr))return false;for(var changed=false,rewriteQ=[curr.children||curr.childNodes];rewriteQ.length>0;)for(var child,children=rewriteQ.shift(),i=0;i"+rwString+"","text/html");if(!inner_doc||!this.nodeHasChildren(inner_doc.head)||!inner_doc.head.children[0].content)return rwString;var template=inner_doc.head.children[0];if(template._no_rewrite=true,this.recurseRewriteElem(template.content)){var new_html=template.innerHTML;if(checkEndTag){var first_elem=template.content.children&&template.content.children[0];if(first_elem){var end_tag="";this.endsWith(new_html,end_tag)&&!this.endsWith(rwString,end_tag)&&(new_html=new_html.substring(0,new_html.length-end_tag.length))}else if(rwString[0]!=="<"||rwString[rwString.length-1]!==">")return this.write_buff+=rwString,undefined}return new_html}return rwString},Wombat.prototype.rewriteHtmlFull=function(string,checkEndTag){var inner_doc=new DOMParser().parseFromString(string,"text/html");if(!inner_doc)return string;for(var changed=false,i=0;i=0)inner_doc.documentElement._no_rewrite=true,new_html=this.reconstructDocType(inner_doc.doctype)+inner_doc.documentElement.outerHTML;else{inner_doc.head._no_rewrite=true,inner_doc.body._no_rewrite=true;var headHasKids=this.nodeHasChildren(inner_doc.head),bodyHasKids=this.nodeHasChildren(inner_doc.body);if(new_html=(headHasKids?inner_doc.head.outerHTML:"")+(bodyHasKids?inner_doc.body.outerHTML:""),checkEndTag)if(inner_doc.all.length>3){var end_tag="";this.endsWith(new_html,end_tag)&&!this.endsWith(string,end_tag)&&(new_html=new_html.substring(0,new_html.length-end_tag.length))}else if(string[0]!=="<"||string[string.length-1]!==">")return void(this.write_buff+=string);new_html=this.reconstructDocType(inner_doc.doctype)+new_html}return new_html}return string},Wombat.prototype.rewriteInlineStyle=function(orig){var decoded;try{decoded=decodeURIComponent(orig)}catch(e){decoded=orig}if(decoded!==orig){var parts=this.rewriteStyle(decoded).split(",",2);return parts[0]+","+encodeURIComponent(parts[1])}return this.rewriteStyle(orig)},Wombat.prototype.rewriteCookie=function(cookie){var wombat=this,rwCookie=cookie.replace(this.wb_abs_prefix,"").replace(this.wb_rel_prefix,"");return rwCookie=rwCookie.replace(this.cookie_domain_regex,function(m,m1){var message={domain:m1,cookie:rwCookie,wb_type:"cookie"};return wombat.sendTopMessage(message,true),wombat.$wbwindow.location.hostname.indexOf(".")>=0&&!wombat.IP_RX.test(wombat.$wbwindow.location.hostname)?"Domain=."+wombat.$wbwindow.location.hostname:""}).replace(this.cookie_path_regex,function(m,m1){var rewritten=wombat.rewriteUrl(m1);return rewritten.indexOf(wombat.wb_curr_host)===0&&(rewritten=rewritten.substring(wombat.wb_curr_host.length)),"Path="+rewritten}),wombat.$wbwindow.location.protocol!=="https:"&&(rwCookie=rwCookie.replace("secure","")),rwCookie.replace(",|",",")},Wombat.prototype.rewriteWorker=function(workerUrl){if(!workerUrl)return workerUrl;var isBlob=workerUrl.indexOf("blob:")===0,isJS=workerUrl.indexOf("javascript:")===0;if(!isBlob&&!isJS){if(!this.startsWithOneOf(workerUrl,this.VALID_PREFIXES)&&!this.startsWith(workerUrl,"/")&&!this.startsWithOneOf(workerUrl,this.BAD_PREFIXES)){var rurl=this.resolveRelUrl(workerUrl,this.$wbwindow.document);return this.rewriteUrl(rurl,false,"wkr_",this.$wbwindow.document)}return this.rewriteUrl(workerUrl,false,"wkr_",this.$wbwindow.document)}var workerCode=isJS?workerUrl.replace("javascript:",""):null;if(isBlob){var x=new XMLHttpRequest;this.utilFns.XHRopen.call(x,"GET",workerUrl,false),x.send(),workerCode=x.responseText.replace(this.workerBlobRe,"").replace(this.rmCheckThisInjectRe,"this")}if(this.wb_info.static_prefix||this.wb_info.ww_rw_script){var originalURL=this.$wbwindow.document.baseURI,ww_rw=this.wb_info.ww_rw_script||this.wb_info.static_prefix+"wombatWorkers.js",rw="(function() { self.importScripts('"+ww_rw+"'); new WBWombat({'prefix': '"+this.wb_abs_prefix+"', 'prefixMod': '"+this.wb_abs_prefix+"wkrf_/', 'originalURL': '"+originalURL+"'}); })();";workerCode=rw+workerCode}var blob=new Blob([workerCode],{type:"application/javascript"});return URL.createObjectURL(blob)},Wombat.prototype.rewriteTextNodeFn=function(fnThis,originalFn,argsObj){var args,deproxiedThis=this.proxyToObj(fnThis);if(argsObj.length>0&&deproxiedThis.parentElement&&deproxiedThis.parentElement.tagName==="STYLE"){args=new Array(argsObj.length);var dataIndex=argsObj.length-1;dataIndex===2?(args[0]=argsObj[0],args[1]=argsObj[1]):dataIndex===1&&(args[0]=argsObj[0]),args[dataIndex]=this.rewriteStyle(argsObj[dataIndex])}else args=argsObj;return originalFn.__WB_orig_apply?originalFn.__WB_orig_apply(deproxiedThis,args):originalFn.apply(deproxiedThis,args)},Wombat.prototype.rewriteDocWriteWriteln=function(fnThis,originalFn,argsObj){var string,thisObj=this.proxyToObj(fnThis),argLen=argsObj.length;if(argLen===0)return originalFn.call(thisObj);string=argLen===1?argsObj[0]:Array.prototype.join.call(argsObj,"");var new_buff=this.rewriteHtml(string,true),res=originalFn.call(thisObj,new_buff);return this.initNewWindowWombat(thisObj.defaultView),res},Wombat.prototype.rewriteChildNodeFn=function(fnThis,originalFn,argsObj){var thisObj=this.proxyToObj(fnThis);if(argsObj.length===0)return originalFn.call(thisObj);var newArgs=this.rewriteElementsInArguments(argsObj);return originalFn.__WB_orig_apply?originalFn.__WB_orig_apply(thisObj,newArgs):originalFn.apply(thisObj,newArgs)},Wombat.prototype.rewriteInsertAdjHTMLOrElemArgs=function(fnThis,originalFn,position,textOrElem,rwHTML){var fnThisObj=this.proxyToObj(fnThis);return fnThisObj._no_rewrite?originalFn.call(fnThisObj,position,textOrElem):rwHTML?originalFn.call(fnThisObj,position,this.rewriteHtml(textOrElem)):(this.rewriteElemComplete(textOrElem),originalFn.call(fnThisObj,position,textOrElem))},Wombat.prototype.rewriteSetTimeoutInterval=function(fnThis,originalFn,argsObj){var rw=this.isString(argsObj[0]),args=rw?new Array(argsObj.length):argsObj;if(rw){args[0]=this.$wbwindow.Proxy?this.wrapScriptTextJsProxy(argsObj[0]):argsObj[0].replace(/\blocation\b/g,"WB_wombat_$&");for(var i=1;i0&&cssStyleValueOverride(this.$wbwindow.CSSStyleValue,"parse"),this.$wbwindow.CSSStyleValue.parseAll&&this.$wbwindow.CSSStyleValue.parseAll.toString().indexOf("[native code]")>0&&cssStyleValueOverride(this.$wbwindow.CSSStyleValue,"parseAll")}if(this.$wbwindow.CSSKeywordValue&&this.$wbwindow.CSSKeywordValue.prototype){var oCSSKV=this.$wbwindow.CSSKeywordValue;this.$wbwindow.CSSKeywordValue=function(CSSKeywordValue_){return function CSSKeywordValue(cssValue){return wombat.domConstructorErrorChecker(this,"CSSKeywordValue",arguments),new CSSKeywordValue_(wombat.rewriteStyle(cssValue))}}(this.$wbwindow.CSSKeywordValue),this.$wbwindow.CSSKeywordValue.prototype=oCSSKV.prototype,Object.defineProperty(this.$wbwindow.CSSKeywordValue.prototype,"constructor",{value:this.$wbwindow.CSSKeywordValue}),addToStringTagToClass(this.$wbwindow.CSSKeywordValue,"CSSKeywordValue")}if(this.$wbwindow.StylePropertyMap&&this.$wbwindow.StylePropertyMap.prototype){var originalSet=this.$wbwindow.StylePropertyMap.prototype.set;this.$wbwindow.StylePropertyMap.prototype.set=function set(){if(arguments.length<=1)return originalSet.__WB_orig_apply?originalSet.__WB_orig_apply(this,arguments):originalSet.apply(this,arguments);var newArgs=new Array(arguments.length);newArgs[0]=arguments[0];for(var i=1;i=0||name==="href"?wombat.extractOriginalURL(value):value},svgImgProto.getAttributeNS=function getAttributeNS(ns,name){var value=orig_getAttrNS.call(this,ns,name);return name.indexOf("xlink:href")>=0||name==="href"?wombat.extractOriginalURL(value):value},svgImgProto.setAttribute=function setAttribute(name,value){var rwValue=value;return(name.indexOf("xlink:href")>=0||name==="href")&&(rwValue=wombat.rewriteUrl(value)),orig_setAttr.call(this,name,rwValue)},svgImgProto.setAttributeNS=function setAttributeNS(ns,name,value){var rwValue=value;return(name.indexOf("xlink:href")>=0||name==="href")&&(rwValue=wombat.rewriteUrl(value)),orig_setAttrNS.call(this,ns,name,rwValue)}}},Wombat.prototype.initCreateElementNSFix=function(){if(this.$wbwindow.document.createElementNS&&this.$wbwindow.Document.prototype.createElementNS){var orig_createElementNS=this.$wbwindow.document.createElementNS,wombat=this,createElementNS=function createElementNS(namespaceURI,qualifiedName){return orig_createElementNS.call(wombat.proxyToObj(this),wombat.extractOriginalURL(namespaceURI),qualifiedName)};this.$wbwindow.Document.prototype.createElementNS=createElementNS,this.$wbwindow.document.createElementNS=createElementNS}},Wombat.prototype.initInsertAdjacentElementHTMLOverrides=function(){var Element=this.$wbwindow.Element;if(Element&&Element.prototype){var elementProto=Element.prototype,rewriteFn=this.rewriteInsertAdjHTMLOrElemArgs;if(elementProto.insertAdjacentHTML){var origInsertAdjacentHTML=elementProto.insertAdjacentHTML;elementProto.insertAdjacentHTML=function insertAdjacentHTML(position,text){return rewriteFn(this,origInsertAdjacentHTML,position,text,true)}}if(elementProto.insertAdjacentElement){var origIAdjElem=elementProto.insertAdjacentElement;elementProto.insertAdjacentElement=function insertAdjacentElement(position,element){return rewriteFn(this,origIAdjElem,position,element,false)}}}},Wombat.prototype.initDomOverride=function(){var Node=this.$wbwindow.Node;if(Node&&Node.prototype){var rewriteFn=this.rewriteNodeFuncArgs;if(Node.prototype.appendChild){var originalAppendChild=Node.prototype.appendChild;Node.prototype.appendChild=function appendChild(newNode,oldNode){return rewriteFn(this,originalAppendChild,newNode,oldNode)}}if(Node.prototype.insertBefore){var originalInsertBefore=Node.prototype.insertBefore;Node.prototype.insertBefore=function insertBefore(newNode,oldNode){return rewriteFn(this,originalInsertBefore,newNode,oldNode)}}if(Node.prototype.replaceChild){var originalReplaceChild=Node.prototype.replaceChild;Node.prototype.replaceChild=function replaceChild(newNode,oldNode){return rewriteFn(this,originalReplaceChild,newNode,oldNode)}}this.overridePropToProxy(Node.prototype,"ownerDocument"),this.overridePropToProxy(this.$wbwindow.HTMLHtmlElement.prototype,"parentNode"),this.overridePropToProxy(this.$wbwindow.Event.prototype,"target")}this.$wbwindow.Element&&this.$wbwindow.Element.prototype&&(this.overrideParentNodeAppendPrepend(this.$wbwindow.Element),this.overrideChildNodeInterface(this.$wbwindow.Element,false)),this.$wbwindow.DocumentFragment&&this.$wbwindow.DocumentFragment.prototype&&this.overrideParentNodeAppendPrepend(this.$wbwindow.DocumentFragment)},Wombat.prototype.initDocOverrides=function($document){if(Object.defineProperty){this.overridePropExtract($document,"referrer"),this.defGetterProp($document,"origin",function origin(){return this.WB_wombat_location.origin}),this.defGetterProp(this.$wbwindow,"origin",function origin(){return this.WB_wombat_location.origin});var wombat=this,domain_setter=function domain(val){var loc=this.WB_wombat_location;loc&&wombat.endsWith(loc.hostname,val)&&(this.__wb_domain=val)},domain_getter=function domain(){return this.__wb_domain||this.WB_wombat_location.hostname};this.defProp($document,"domain",domain_setter,domain_getter)}},Wombat.prototype.initDocWriteOpenCloseOverride=function(){if(this.$wbwindow.DOMParser){var DocumentProto=this.$wbwindow.Document.prototype,$wbDocument=this.$wbwindow.document,docWriteWritelnRWFn=this.rewriteDocWriteWriteln,orig_doc_write=$wbDocument.write,new_write=function write(){return docWriteWritelnRWFn(this,orig_doc_write,arguments)};$wbDocument.write=new_write,DocumentProto.write=new_write;var orig_doc_writeln=$wbDocument.writeln,new_writeln=function writeln(){return docWriteWritelnRWFn(this,orig_doc_writeln,arguments)};$wbDocument.writeln=new_writeln,DocumentProto.writeln=new_writeln;var wombat=this,orig_doc_open=$wbDocument.open,new_open=function open(){var res,thisObj=wombat.proxyToObj(this);if(arguments.length===3){var rwUrl=wombat.rewriteUrl(arguments[0],false,"mp_");res=orig_doc_open.call(thisObj,rwUrl,arguments[1],arguments[2]),wombat.initNewWindowWombat(res,rwUrl)}else res=orig_doc_open.call(thisObj),wombat.initNewWindowWombat(thisObj.defaultView);return res};$wbDocument.open=new_open,DocumentProto.open=new_open;var originalClose=$wbDocument.close,newClose=function close(){var thisObj=wombat.proxyToObj(this);return wombat.initNewWindowWombat(thisObj.defaultView),originalClose.__WB_orig_apply?originalClose.__WB_orig_apply(thisObj,arguments):originalClose.apply(thisObj,arguments)};$wbDocument.close=newClose,DocumentProto.close=newClose;var oBodyGetter=this.getOrigGetter(DocumentProto,"body"),oBodySetter=this.getOrigSetter(DocumentProto,"body");oBodyGetter&&oBodySetter&&this.defProp(DocumentProto,"body",function body(newBody){return newBody&&(newBody instanceof HTMLBodyElement||newBody instanceof HTMLFrameSetElement)&&wombat.rewriteElemComplete(newBody),oBodySetter.call(wombat.proxyToObj(this),newBody)},oBodyGetter)}},Wombat.prototype.initIframeWombat=function(iframe){var win;win=iframe._get_contentWindow?iframe._get_contentWindow.call(iframe):iframe.contentWindow;try{if(!win||win===this.$wbwindow||win._skip_wombat||win._wb_wombat)return}catch(e){return}var src=this.wb_getAttribute.call(iframe,"src");this.initNewWindowWombat(win,src)},Wombat.prototype.initNewWindowWombat=function(win,src){if(this.ensureServerSideInjectsExistOnWindow(win),win&&!win._wb_wombat)if(!src||src===""||this.startsWith(src,"about:")||src.indexOf("javascript:")>=0){var wombat=new Wombat(win,this.wb_info);win._wb_wombat=wombat.wombatInit()}else this.initProtoPmOrigin(win),this.initPostMessageOverride(win),this.initMessageEventOverride(win)},Wombat.prototype.initTimeoutIntervalOverrides=function(){var rewriteFn=this.rewriteSetTimeoutInterval;if(this.$wbwindow.setTimeout&&!this.$wbwindow.setTimeout.__$wbpatched$__){var originalSetTimeout=this.$wbwindow.setTimeout;this.$wbwindow.setTimeout=function setTimeout(){return rewriteFn(this,originalSetTimeout,arguments)},this.$wbwindow.setTimeout.__$wbpatched$__=true}if(this.$wbwindow.setInterval&&!this.$wbwindow.setInterval.__$wbpatched$__){var originalSetInterval=this.$wbwindow.setInterval;this.$wbwindow.setInterval=function setInterval(){return rewriteFn(this,originalSetInterval,arguments)},this.$wbwindow.setInterval.__$wbpatched$__=true}},Wombat.prototype.initWorkerOverrides=function(){var wombat=this;if(this.$wbwindow.Worker&&!this.$wbwindow.Worker._wb_worker_overriden){var orig_worker=this.$wbwindow.Worker;this.$wbwindow.Worker=function(Worker_){return function Worker(url,options){return wombat.domConstructorErrorChecker(this,"Worker",arguments),new Worker_(wombat.rewriteWorker(url),options)}}(orig_worker),this.$wbwindow.Worker.prototype=orig_worker.prototype,Object.defineProperty(this.$wbwindow.Worker.prototype,"constructor",{value:this.$wbwindow.Worker}),this.$wbwindow.Worker._wb_worker_overriden=true}if(this.$wbwindow.SharedWorker&&!this.$wbwindow.SharedWorker.__wb_sharedWorker_overriden){var oSharedWorker=this.$wbwindow.SharedWorker;this.$wbwindow.SharedWorker=function(SharedWorker_){return function SharedWorker(url,options){return wombat.domConstructorErrorChecker(this,"SharedWorker",arguments),new SharedWorker_(wombat.rewriteWorker(url),options)}}(oSharedWorker),this.$wbwindow.SharedWorker.prototype=oSharedWorker.prototype,Object.defineProperty(this.$wbwindow.SharedWorker.prototype,"constructor",{value:this.$wbwindow.SharedWorker}),this.$wbwindow.SharedWorker.__wb_sharedWorker_overriden=true}if(this.$wbwindow.ServiceWorkerContainer&&this.$wbwindow.ServiceWorkerContainer.prototype&&this.$wbwindow.ServiceWorkerContainer.prototype.register){var orig_register=this.$wbwindow.ServiceWorkerContainer.prototype.register;this.$wbwindow.ServiceWorkerContainer.prototype.register=function register(scriptURL,options){var newScriptURL=new URL(scriptURL,wombat.$wbwindow.document.baseURI).href,mod=wombat.getPageUnderModifier();return options&&options.scope?options.scope=wombat.rewriteUrl(options.scope,false,mod):options={scope:wombat.rewriteUrl("/",false,mod)},orig_register.call(this,wombat.rewriteUrl(newScriptURL,false,"sw_"),options)}}if(this.$wbwindow.Worklet&&this.$wbwindow.Worklet.prototype&&this.$wbwindow.Worklet.prototype.addModule&&!this.$wbwindow.Worklet.__wb_workerlet_overriden){var oAddModule=this.$wbwindow.Worklet.prototype.addModule;this.$wbwindow.Worklet.prototype.addModule=function addModule(moduleURL,options){var rwModuleURL=wombat.rewriteUrl(moduleURL,false,"js_");return oAddModule.call(this,rwModuleURL,options)},this.$wbwindow.Worklet.__wb_workerlet_overriden=true}},Wombat.prototype.initLocOverride=function(loc,oSetter,oGetter){if(Object.defineProperty)for(var prop,i=0;i=0){var fnMapping=this._map.splice(idx,1);return fnMapping[0][1]}return null},FuncMap.prototype.map=function(param){for(var i=0;i0&&afw.preserveMedia(media)})},AutoFetcher.prototype.terminate=function(){this.worker.terminate()},AutoFetcher.prototype.justFetch=function(urls){this.worker.postMessage({type:"fetch-all",values:urls})},AutoFetcher.prototype.postMessage=function(msg,deferred){if(deferred){var afWorker=this;return void Promise.resolve().then(function(){afWorker.worker.postMessage(msg)})}this.worker.postMessage(msg)},AutoFetcher.prototype.preserveSrcset=function(srcset,mod){this.postMessage({type:"values",srcset:{value:srcset,mod:mod,presplit:true}},true)},AutoFetcher.prototype.preserveDataSrcset=function(elem){this.postMessage({type:"values",srcset:{value:elem.dataset.srcset,mod:this.rwMod(elem),presplit:false}},true)},AutoFetcher.prototype.preserveMedia=function(media){this.postMessage({type:"values",media:media},true)},AutoFetcher.prototype.getSrcset=function(elem){return this.wombat.wb_getAttribute?this.wombat.wb_getAttribute.call(elem,"srcset"):elem.getAttribute("srcset")},AutoFetcher.prototype.rwMod=function(elem){switch(elem.tagName){case"SOURCE":return elem.parentElement&&elem.parentElement.tagName==="PICTURE"?"im_":"oe_";case"IMG":return"im_";}return"oe_"},AutoFetcher.prototype.extractFromLocalDoc=function(){var afw=this;Promise.resolve().then(function(){for(var msg={type:"values",context:{docBaseURI:document.baseURI}},media=[],i=0,sheets=document.styleSheets;i=0},Wombat.prototype.isString=function(arg){return arg!=null&&Object.getPrototypeOf(arg)===String.prototype},Wombat.prototype.isSavedSrcSrcset=function(elem){switch(elem.tagName){case"IMG":case"VIDEO":case"AUDIO":return true;case"SOURCE":if(!elem.parentElement)return false;switch(elem.parentElement.tagName){case"PICTURE":case"VIDEO":case"AUDIO":return true;default:return false;}default:return false;}},Wombat.prototype.isSavedDataSrcSrcset=function(elem){return!!(elem.dataset&&elem.dataset.srcset!=null)&&this.isSavedSrcSrcset(elem)},Wombat.prototype.isHostUrl=function(str){if(str.indexOf("www.")===0)return true;var matches=str.match(this.hostnamePortRe);return!!(matches&&matches[0].length<64)||(matches=str.match(this.ipPortRe),!!matches&&matches[0].length<64)},Wombat.prototype.isArgumentsObj=function(maybeArgumentsObj){if(!maybeArgumentsObj||typeof maybeArgumentsObj.toString!=="function")return false;try{return this.utilFns.objToString.call(maybeArgumentsObj)==="[object Arguments]"}catch(e){return false}},Wombat.prototype.deproxyArrayHandlingArgumentsObj=function(maybeArgumentsObj){if(!maybeArgumentsObj||maybeArgumentsObj instanceof NodeList||!maybeArgumentsObj.length)return maybeArgumentsObj;for(var args=this.isArgumentsObj(maybeArgumentsObj)?new Array(maybeArgumentsObj.length):maybeArgumentsObj,i=0;i=0)||scriptType.indexOf("text/template")>=0)},Wombat.prototype.skipWrapScriptTextBasedOnText=function(text){if(!text||text.indexOf("_____WB$wombat$assign$function_____")>=0||text.indexOf("<")===0)return true;for(var override_props=["window","self","document","location","top","parent","frames","opener"],i=0;i=0)return false;return true},Wombat.prototype.nodeHasChildren=function(node){if(!node)return false;if(typeof node.hasChildNodes==="function")return node.hasChildNodes();var kids=node.children||node.childNodes;return!!kids&&kids.length>0},Wombat.prototype.rwModForElement=function(elem,attrName){if(!elem)return undefined;var mod="mp_";if(!(elem.tagName==="LINK"&&attrName==="href")){var maybeMod=this.tagToMod[elem.tagName];maybeMod!=null&&(mod=maybeMod[attrName])}else if(elem.rel){var relV=elem.rel.trim().toLowerCase(),asV=this.wb_getAttribute.call(elem,"as");if(asV&&this.linkTagMods.linkRelToAs[relV]!=null){var asMods=this.linkTagMods.linkRelToAs[relV];mod=asMods[asV.toLowerCase()]}else this.linkTagMods[relV]!=null&&(mod=this.linkTagMods[relV])}return mod},Wombat.prototype.removeWBOSRC=function(elem){elem.tagName!=="SCRIPT"||elem.__$removedWBOSRC$__||(elem.hasAttribute("__wb_orig_src")&&elem.removeAttribute("__wb_orig_src"),elem.__$removedWBOSRC$__=true)},Wombat.prototype.retrieveWBOSRC=function(elem){if(elem.tagName==="SCRIPT"&&!elem.__$removedWBOSRC$__){var maybeWBOSRC;return maybeWBOSRC=this.wb_getAttribute?this.wb_getAttribute.call(elem,"__wb_orig_src"):elem.getAttribute("__wb_orig_src"),maybeWBOSRC==null&&(elem.__$removedWBOSRC$__=true),maybeWBOSRC}return undefined},Wombat.prototype.wrapScriptTextJsProxy=function(scriptText){return"var _____WB$wombat$assign$function_____ = function(name) {return (self._wb_wombat && self._wb_wombat.local_init &&self._wb_wombat.local_init(name)) || self[name]; };\nvar _____WB$wombat$check$this$function_____ = function(thisObj) {if (thisObj && thisObj._WB_wombat_obj_proxy) return thisObj._WB_wombat_obj_proxy;return thisObj; }\nif (!self.__WB_pmw) { self.__WB_pmw = function(obj) { this.__WB_source = obj; return this; } }\n{\nlet window = _____WB$wombat$assign$function_____(\"window\");\nlet self = _____WB$wombat$assign$function_____(\"self\");\nlet document = _____WB$wombat$assign$function_____(\"document\");\nlet location = _____WB$wombat$assign$function_____(\"location\");\nlet top = _____WB$wombat$assign$function_____(\"top\");\nlet parent = _____WB$wombat$assign$function_____(\"parent\");\nlet frames = _____WB$wombat$assign$function_____(\"frames\");\nlet opener = _____WB$wombat$assign$function_____(\"opener\");\n"+scriptText.replace(this.DotPostMessageRe,".__WB_pmw(self.window)$1")+"\n\n}"},Wombat.prototype.watchElem=function(elem,func){if(!this.$wbwindow.MutationObserver)return false;var m=new this.$wbwindow.MutationObserver(function(records,observer){for(var r,i=0;i"},Wombat.prototype.getFinalUrl=function(useRel,mod,url){var prefix=useRel?this.wb_rel_prefix:this.wb_abs_prefix;return mod==null&&(mod=this.wb_info.mod),this.wb_info.is_live||(prefix+=this.wb_info.wombat_ts),prefix+=mod,prefix[prefix.length-1]!=="/"&&(prefix+="/"),prefix+url},Wombat.prototype.resolveRelUrl=function(url,doc){var docObj=doc||this.$wbwindow.document,parser=this.makeParser(docObj.baseURI,docObj),hash=parser.href.lastIndexOf("#"),href=hash>=0?parser.href.substring(0,hash):parser.href,lastslash=href.lastIndexOf("/");return parser.href=lastslash>=0&&lastslash!==href.length-1?href.substring(0,lastslash+1)+url:href+url,parser.href},Wombat.prototype.extractOriginalURL=function(rewrittenUrl){if(!rewrittenUrl)return"";if(this.wb_is_proxy)return rewrittenUrl;var rwURLString=rewrittenUrl.toString(),url=rwURLString;if(this.startsWithOneOf(url,this.IGNORE_PREFIXES))return url;var start;start=this.startsWith(url,this.wb_abs_prefix)?this.wb_abs_prefix.length:this.wb_rel_prefix&&this.startsWith(url,this.wb_rel_prefix)?this.wb_rel_prefix.length:this.wb_rel_prefix?1:0;var index=url.indexOf("/http",start);return index<0&&(index=url.indexOf("///",start)),index>=0?url=url.substr(index+1):(index=url.indexOf(this.wb_replay_prefix),index>=0&&(url=url.substr(index+this.wb_replay_prefix.length)),url.length>4&&url.charAt(2)==="_"&&url.charAt(3)==="/"&&(url=url.substr(4)),url!==rwURLString&&!this.startsWithOneOf(url,this.VALID_PREFIXES)&&(url=this.wb_orig_scheme+url)),rwURLString.charAt(0)==="/"&&rwURLString.charAt(1)!=="/"&&this.startsWith(url,this.wb_orig_origin)&&(url=url.substr(this.wb_orig_origin.length)),this.startsWith(url,this.REL_PREFIX)?this.wb_info.wombat_scheme+":"+url:url},Wombat.prototype.makeParser=function(maybeRewrittenURL,doc){var originalURL=this.extractOriginalURL(maybeRewrittenURL),docElem=doc;doc||(this.$wbwindow.location.href==="about:blank"&&this.$wbwindow.opener?docElem=this.$wbwindow.opener.document:docElem=this.$wbwindow.document);var p=docElem.createElement("a");return p._no_rewrite=true,p.href=originalURL,p},Wombat.prototype.defProp=function(obj,prop,setFunc,getFunc,enumerable){var existingDescriptor=Object.getOwnPropertyDescriptor(obj,prop);if(existingDescriptor&&!existingDescriptor.configurable)return false;if(!getFunc)return false;var descriptor={configurable:true,enumerable:enumerable||false,get:getFunc};setFunc&&(descriptor.set=setFunc);try{return Object.defineProperty(obj,prop,descriptor),true}catch(e){return console.warn("Failed to redefine property %s",prop,e.message),false}},Wombat.prototype.defGetterProp=function(obj,prop,getFunc,enumerable){var existingDescriptor=Object.getOwnPropertyDescriptor(obj,prop);if(existingDescriptor&&!existingDescriptor.configurable)return false;if(!getFunc)return false;try{return Object.defineProperty(obj,prop,{configurable:true,enumerable:enumerable||false,get:getFunc}),true}catch(e){return console.warn("Failed to redefine property %s",prop,e.message),false}},Wombat.prototype.getOrigGetter=function(obj,prop){var orig_getter;if(obj.__lookupGetter__&&(orig_getter=obj.__lookupGetter__(prop)),!orig_getter&&Object.getOwnPropertyDescriptor){var props=Object.getOwnPropertyDescriptor(obj,prop);props&&(orig_getter=props.get)}return orig_getter},Wombat.prototype.getOrigSetter=function(obj,prop){var orig_setter;if(obj.__lookupSetter__&&(orig_setter=obj.__lookupSetter__(prop)),!orig_setter&&Object.getOwnPropertyDescriptor){var props=Object.getOwnPropertyDescriptor(obj,prop);props&&(orig_setter=props.set)}return orig_setter},Wombat.prototype.getAllOwnProps=function(obj){for(var ownProps=[],props=Object.getOwnPropertyNames(obj),i=0;i "+final_href),actualLocation.href=final_href}}},Wombat.prototype.checkLocationChange=function(wombatLoc,isTop){var locType=typeof wombatLoc,actual_location=isTop?this.$wbwindow.__WB_replay_top.location:this.$wbwindow.location;locType==="string"?this.updateLocation(wombatLoc,actual_location.href,actual_location):locType==="object"&&this.updateLocation(wombatLoc.href,wombatLoc._orig_href,actual_location)},Wombat.prototype.checkAllLocations=function(){return!this.wb_wombat_updating&&void(this.wb_wombat_updating=true,this.checkLocationChange(this.$wbwindow.WB_wombat_location,false),this.$wbwindow.WB_wombat_location!=this.$wbwindow.__WB_replay_top.WB_wombat_location&&this.checkLocationChange(this.$wbwindow.__WB_replay_top.WB_wombat_location,true),this.wb_wombat_updating=false)},Wombat.prototype.proxyToObj=function(source){if(source)try{var proxyRealObj=source.__WBProxyRealObj__;if(proxyRealObj)return proxyRealObj}catch(e){}return source},Wombat.prototype.objToProxy=function(obj){if(obj)try{var maybeWbProxy=obj._WB_wombat_obj_proxy;if(maybeWbProxy)return maybeWbProxy}catch(e){}return obj},Wombat.prototype.defaultProxyGet=function(obj,prop,ownProps,fnCache){switch(prop){case"__WBProxyRealObj__":return obj;case"location":case"WB_wombat_location":return obj.WB_wombat_location;case"_WB_wombat_obj_proxy":return obj._WB_wombat_obj_proxy;case"__WB_pmw":return obj[prop];case"constructor":if(obj.constructor===Window)return obj.constructor;}var retVal=obj[prop],type=typeof retVal;if(type==="function"&&ownProps.indexOf(prop)!==-1){switch(prop){case"requestAnimationFrame":case"cancelAnimationFrame":{if(!this.isNativeFunction(retVal))return retVal;break}}var cachedFN=fnCache[prop];return cachedFN&&cachedFN.original===retVal||(cachedFN={original:retVal,boundFn:retVal.bind(obj)},fnCache[prop]=cachedFN),cachedFN.boundFn}return type==="object"&&retVal&&retVal._WB_wombat_obj_proxy?(retVal instanceof Window&&this.initNewWindowWombat(retVal),retVal._WB_wombat_obj_proxy):retVal},Wombat.prototype.setLoc=function(loc,originalURL){var parser=this.makeParser(originalURL,loc.ownerDocument);loc._orig_href=originalURL,loc._parser=parser;var href=parser.href;loc._hash=parser.hash,loc._href=href,loc._host=parser.host,loc._hostname=parser.hostname,loc._origin=parser.origin?parser.origin:parser.protocol+"//"+parser.hostname+(parser.port?":"+parser.port:""),loc._pathname=parser.pathname,loc._port=parser.port,loc._protocol=parser.protocol,loc._search=parser.search,Object.defineProperty||(loc.href=href,loc.hash=parser.hash,loc.host=loc._host,loc.hostname=loc._hostname,loc.origin=loc._origin,loc.pathname=loc._pathname,loc.port=loc._port,loc.protocol=loc._protocol,loc.search=loc._search)},Wombat.prototype.makeGetLocProp=function(prop,origGetter){var wombat=this;return function newGetLocProp(){if(this._no_rewrite)return origGetter.call(this,prop);var curr_orig_href=origGetter.call(this,"href");return prop==="href"?wombat.extractOriginalURL(curr_orig_href):(this._orig_href!==curr_orig_href&&wombat.setLoc(this,curr_orig_href),this["_"+prop])}},Wombat.prototype.makeSetLocProp=function(prop,origSetter,origGetter){var wombat=this;return function newSetLocProp(value){if(this._no_rewrite)return origSetter.call(this,prop,value);if(this["_"+prop]!==value){if(this["_"+prop]=value,!this._parser){var href=origGetter.call(this);this._parser=wombat.makeParser(href,this.ownerDocument)}var rel=false;prop==="href"&&typeof value==="string"&&value&&(value[0]==="."?value=wombat.resolveRelUrl(value,this.ownerDocument):value[0]==="/"&&(value.length<=1||value[1]!=="/")&&(rel=true,value=WB_wombat_location.origin+value));try{this._parser[prop]=value}catch(e){console.log("Error setting "+prop+" = "+value)}prop==="hash"?(value=this._parser[prop],origSetter.call(this,"hash",value)):(rel=rel||value===this._parser.pathname,value=wombat.rewriteUrl(this._parser.href,rel),origSetter.call(this,"href",value))}}},Wombat.prototype.styleReplacer=function(match,n1,n2,n3,offset,string){return n1+this.rewriteUrl(n2)+n3},Wombat.prototype.ensureServerSideInjectsExistOnWindow=function(win){win&&(typeof win._____WB$wombat$check$this$function_____!=="function"&&(win._____WB$wombat$check$this$function_____=function(thisObj){return thisObj&&thisObj._WB_wombat_obj_proxy?thisObj._WB_wombat_obj_proxy:thisObj}),typeof win._____WB$wombat$assign$function_____!=="function"&&(win._____WB$wombat$assign$function_____=function(name){return self._wb_wombat&&self._wb_wombat.local_init&&self._wb_wombat.local_init(name)||self[name]}))},Wombat.prototype.domConstructorErrorChecker=function(thisObj,what,args,numRequiredArgs){var erorMsg,needArgs=typeof numRequiredArgs==="number"?numRequiredArgs:1;if(thisObj instanceof Window?erorMsg="Failed to construct '"+what+"': Please use the 'new' operator, this DOM object constructor cannot be called as a function.":args&&args.length=0)return url;if(url.indexOf(this.wb_rel_prefix)===0&&url.indexOf("http")>1){var scheme_sep=url.indexOf(":/");return scheme_sep>0&&url[scheme_sep+2]!=="/"?url.substring(0,scheme_sep+2)+"/"+url.substring(scheme_sep+2):url}return this.getFinalUrl(true,mod,this.wb_orig_origin+url)}url.charAt(0)==="."&&(url=this.resolveRelUrl(url,doc));var prefix=this.startsWithOneOf(url.toLowerCase(),this.VALID_PREFIXES);if(prefix){var orig_host=this.$wbwindow.__WB_replay_top.location.host,orig_protocol=this.$wbwindow.__WB_replay_top.location.protocol,prefix_host=prefix+orig_host+"/";if(this.startsWith(url,prefix_host)){if(this.startsWith(url,this.wb_replay_prefix))return url;var curr_scheme=orig_protocol+"//",path=url.substring(prefix_host.length),rebuild=false;return path.indexOf(this.wb_rel_prefix)<0&&url.indexOf("/static/")<0&&(path=this.getFinalUrl(true,mod,WB_wombat_location.origin+"/"+path),rebuild=true),prefix!==curr_scheme&&prefix!==this.REL_PREFIX&&(rebuild=true),rebuild&&(url=useRel?"":curr_scheme+orig_host,path&&path[0]!=="/"&&(url+="/"),url+=path),url}return this.getFinalUrl(useRel,mod,url)}return prefix=this.startsWithOneOf(url,this.BAD_PREFIXES),prefix?this.getFinalUrl(useRel,mod,this.extractOriginalURL(url)):this.isHostUrl(url)&&!this.startsWith(url,originalLoc.host+"/")?this.getFinalUrl(useRel,mod,this.wb_orig_scheme+url):url},Wombat.prototype.rewriteUrl=function(url,useRel,mod,doc){var rewritten=this.rewriteUrl_(url,useRel,mod,doc);return this.debug_rw&&(url===rewritten?console.log("NOT REWRITTEN "+url):console.log("REWRITE: "+url+" -> "+rewritten)),rewritten},Wombat.prototype.performAttributeRewrite=function(elem,name,value,absUrlOnly){switch(name){case"innerHTML":case"outerHTML":return this.rewriteHtml(value);case"filter":return this.rewriteInlineStyle(value);case"style":return this.rewriteStyle(value);case"srcset":return this.rewriteSrcset(value,elem);}if(absUrlOnly&&!this.startsWithOneOf(value,this.VALID_PREFIXES))return value;var mod=this.rwModForElement(elem,name);return this.wbUseAFWorker&&this.WBAutoFetchWorker&&this.isSavedDataSrcSrcset(elem)&&this.WBAutoFetchWorker.preserveDataSrcset(elem),this.rewriteUrl(value,false,mod,elem.ownerDocument)},Wombat.prototype.rewriteAttr=function(elem,name,absUrlOnly){var changed=false;if(!elem||!elem.getAttribute||elem._no_rewrite||elem["_"+name])return changed;var value=this.wb_getAttribute.call(elem,name);if(!value||this.startsWith(value,"javascript:"))return changed;var new_value=this.performAttributeRewrite(elem,name,value,absUrlOnly);return new_value!==value&&(this.removeWBOSRC(elem),this.wb_setAttribute.call(elem,name,new_value),changed=true),changed},Wombat.prototype.noExceptRewriteStyle=function(style){try{return this.rewriteStyle(style)}catch(e){return style}},Wombat.prototype.rewriteStyle=function(style){if(!style)return style;var value=style;return typeof style==="object"&&(value=style.toString()),typeof value==="string"?value.replace(this.STYLE_REGEX,this.styleReplacer).replace(this.IMPORT_REGEX,this.styleReplacer).replace(this.no_wombatRe,""):value},Wombat.prototype.rewriteSrcset=function(value,elem){if(!value)return"";for(var split=value.split(this.srcsetRe),values=[],mod=this.rwModForElement(elem,"srcset"),i=0;i=0){var JS="javascript:";new_value="javascript:window.parent._wb_wombat.initNewWindowWombat(window);"+value.substr(11)}return new_value||(new_value=this.rewriteUrl(value,false,this.rwModForElement(elem,attrName))),new_value!==value&&(this.wb_setAttribute.call(elem,attrName,new_value),true)},Wombat.prototype.rewriteScript=function(elem){if(elem.hasAttribute("src")||!elem.textContent||!this.$wbwindow.Proxy)return this.rewriteAttr(elem,"src");if(this.skipWrapScriptBasedOnType(elem.type))return false;var text=elem.textContent.trim();return!this.skipWrapScriptTextBasedOnText(text)&&(elem.textContent=this.wrapScriptTextJsProxy(text),true)},Wombat.prototype.rewriteSVGElem=function(elem){var changed=this.rewriteAttr(elem,"filter");return changed=this.rewriteAttr(elem,"style")||changed,changed=this.rewriteAttr(elem,"xlink:href")||changed,changed=this.rewriteAttr(elem,"href")||changed,changed=this.rewriteAttr(elem,"src")||changed,changed},Wombat.prototype.rewriteElem=function(elem){var changed=false;if(!elem)return changed;if(elem instanceof SVGElement)changed=this.rewriteSVGElem(elem);else switch(elem.tagName){case"META":var maybeCSP=this.wb_getAttribute.call(elem,"http-equiv");maybeCSP&&maybeCSP.toLowerCase()==="content-security-policy"&&(this.wb_setAttribute.call(elem,"http-equiv","_"+maybeCSP),changed=true);break;case"STYLE":var new_content=this.rewriteStyle(elem.textContent);elem.textContent!==new_content&&(elem.textContent=new_content,changed=true,this.wbUseAFWorker&&this.WBAutoFetchWorker&&elem.sheet!=null&&this.WBAutoFetchWorker.deferredSheetExtraction(elem.sheet));break;case"LINK":changed=this.rewriteAttr(elem,"href"),this.wbUseAFWorker&&elem.rel==="stylesheet"&&this._addEventListener(elem,"load",this.utilFns.wbSheetMediaQChecker);break;case"IMG":changed=this.rewriteAttr(elem,"src"),changed=this.rewriteAttr(elem,"srcset")||changed,changed=this.rewriteAttr(elem,"style")||changed,this.wbUseAFWorker&&this.WBAutoFetchWorker&&elem.dataset.srcset&&this.WBAutoFetchWorker.preserveDataSrcset(elem);break;case"OBJECT":changed=this.rewriteAttr(elem,"data",true),changed=this.rewriteAttr(elem,"style")||changed;break;case"FORM":changed=this.rewriteAttr(elem,"poster"),changed=this.rewriteAttr(elem,"action")||changed,changed=this.rewriteAttr(elem,"style")||changed;break;case"IFRAME":case"FRAME":changed=this.rewriteFrameSrc(elem,"src"),changed=this.rewriteAttr(elem,"style")||changed;break;case"SCRIPT":changed=this.rewriteScript(elem);break;default:{changed=this.rewriteAttr(elem,"src"),changed=this.rewriteAttr(elem,"srcset")||changed,changed=this.rewriteAttr(elem,"href")||changed,changed=this.rewriteAttr(elem,"style")||changed,changed=this.rewriteAttr(elem,"poster")||changed;break}}return elem.hasAttribute&&elem.removeAttribute&&(elem.hasAttribute("crossorigin")&&(elem.removeAttribute("crossorigin"),changed=true),elem.hasAttribute("integrity")&&(elem.removeAttribute("integrity"),changed=true)),changed},Wombat.prototype.recurseRewriteElem=function(curr){if(!this.nodeHasChildren(curr))return false;for(var changed=false,rewriteQ=[curr.children||curr.childNodes];rewriteQ.length>0;)for(var child,children=rewriteQ.shift(),i=0;i"+rwString+"","text/html");if(!inner_doc||!this.nodeHasChildren(inner_doc.head)||!inner_doc.head.children[0].content)return rwString;var template=inner_doc.head.children[0];if(template._no_rewrite=true,this.recurseRewriteElem(template.content)){var new_html=template.innerHTML;if(checkEndTag){var first_elem=template.content.children&&template.content.children[0];if(first_elem){var end_tag="";this.endsWith(new_html,end_tag)&&!this.endsWith(rwString,end_tag)&&(new_html=new_html.substring(0,new_html.length-end_tag.length))}else if(rwString[0]!=="<"||rwString[rwString.length-1]!==">")return this.write_buff+=rwString,undefined}return new_html}return rwString},Wombat.prototype.rewriteHtmlFull=function(string,checkEndTag){var inner_doc=new DOMParser().parseFromString(string,"text/html");if(!inner_doc)return string;for(var changed=false,i=0;i=0)inner_doc.documentElement._no_rewrite=true,new_html=this.reconstructDocType(inner_doc.doctype)+inner_doc.documentElement.outerHTML;else{inner_doc.head._no_rewrite=true,inner_doc.body._no_rewrite=true;var headHasKids=this.nodeHasChildren(inner_doc.head),bodyHasKids=this.nodeHasChildren(inner_doc.body);if(new_html=(headHasKids?inner_doc.head.outerHTML:"")+(bodyHasKids?inner_doc.body.outerHTML:""),checkEndTag)if(inner_doc.all.length>3){var end_tag="";this.endsWith(new_html,end_tag)&&!this.endsWith(string,end_tag)&&(new_html=new_html.substring(0,new_html.length-end_tag.length))}else if(string[0]!=="<"||string[string.length-1]!==">")return void(this.write_buff+=string);new_html=this.reconstructDocType(inner_doc.doctype)+new_html}return new_html}return string},Wombat.prototype.rewriteInlineStyle=function(orig){var decoded;try{decoded=decodeURIComponent(orig)}catch(e){decoded=orig}if(decoded!==orig){var parts=this.rewriteStyle(decoded).split(",",2);return parts[0]+","+encodeURIComponent(parts[1])}return this.rewriteStyle(orig)},Wombat.prototype.rewriteCookie=function(cookie){var wombat=this,rwCookie=cookie.replace(this.wb_abs_prefix,"").replace(this.wb_rel_prefix,"");return rwCookie=rwCookie.replace(this.cookie_domain_regex,function(m,m1){var message={domain:m1,cookie:rwCookie,wb_type:"cookie"};return wombat.sendTopMessage(message,true),wombat.$wbwindow.location.hostname.indexOf(".")>=0&&!wombat.IP_RX.test(wombat.$wbwindow.location.hostname)?"Domain=."+wombat.$wbwindow.location.hostname:""}).replace(this.cookie_path_regex,function(m,m1){var rewritten=wombat.rewriteUrl(m1);return rewritten.indexOf(wombat.wb_curr_host)===0&&(rewritten=rewritten.substring(wombat.wb_curr_host.length)),"Path="+rewritten}),wombat.$wbwindow.location.protocol!=="https:"&&(rwCookie=rwCookie.replace("secure","")),rwCookie.replace(",|",",")},Wombat.prototype.rewriteWorker=function(workerUrl){if(!workerUrl)return workerUrl;var isBlob=workerUrl.indexOf("blob:")===0,isJS=workerUrl.indexOf("javascript:")===0;if(!isBlob&&!isJS){if(!this.startsWithOneOf(workerUrl,this.VALID_PREFIXES)&&!this.startsWith(workerUrl,"/")&&!this.startsWithOneOf(workerUrl,this.BAD_PREFIXES)){var rurl=this.resolveRelUrl(workerUrl,this.$wbwindow.document);return this.rewriteUrl(rurl,false,"wkr_",this.$wbwindow.document)}return this.rewriteUrl(workerUrl,false,"wkr_",this.$wbwindow.document)}var workerCode=isJS?workerUrl.replace("javascript:",""):null;if(isBlob){var x=new XMLHttpRequest;this.utilFns.XHRopen.call(x,"GET",workerUrl,false),x.send(),workerCode=x.responseText.replace(this.workerBlobRe,"").replace(this.rmCheckThisInjectRe,"this")}if(this.wb_info.static_prefix||this.wb_info.ww_rw_script){var originalURL=this.$wbwindow.document.baseURI,ww_rw=this.wb_info.ww_rw_script||this.wb_info.static_prefix+"wombatWorkers.js",rw="(function() { self.importScripts('"+ww_rw+"'); new WBWombat({'prefix': '"+this.wb_abs_prefix+"', 'prefixMod': '"+this.wb_abs_prefix+"wkrf_/', 'originalURL': '"+originalURL+"'}); })();";workerCode=rw+workerCode}var blob=new Blob([workerCode],{type:"application/javascript"});return URL.createObjectURL(blob)},Wombat.prototype.rewriteTextNodeFn=function(fnThis,originalFn,argsObj){var args,deproxiedThis=this.proxyToObj(fnThis);if(argsObj.length>0&&deproxiedThis.parentElement&&deproxiedThis.parentElement.tagName==="STYLE"){args=new Array(argsObj.length);var dataIndex=argsObj.length-1;dataIndex===2?(args[0]=argsObj[0],args[1]=argsObj[1]):dataIndex===1&&(args[0]=argsObj[0]),args[dataIndex]=this.rewriteStyle(argsObj[dataIndex])}else args=argsObj;return originalFn.__WB_orig_apply?originalFn.__WB_orig_apply(deproxiedThis,args):originalFn.apply(deproxiedThis,args)},Wombat.prototype.rewriteDocWriteWriteln=function(fnThis,originalFn,argsObj){var string,thisObj=this.proxyToObj(fnThis),argLen=argsObj.length;if(argLen===0)return originalFn.call(thisObj);string=argLen===1?argsObj[0]:Array.prototype.join.call(argsObj,"");var new_buff=this.rewriteHtml(string,true),res=originalFn.call(thisObj,new_buff);return this.initNewWindowWombat(thisObj.defaultView),res},Wombat.prototype.rewriteChildNodeFn=function(fnThis,originalFn,argsObj){var thisObj=this.proxyToObj(fnThis);if(argsObj.length===0)return originalFn.call(thisObj);var newArgs=this.rewriteElementsInArguments(argsObj);return originalFn.__WB_orig_apply?originalFn.__WB_orig_apply(thisObj,newArgs):originalFn.apply(thisObj,newArgs)},Wombat.prototype.rewriteInsertAdjHTMLOrElemArgs=function(fnThis,originalFn,position,textOrElem,rwHTML){var fnThisObj=this.proxyToObj(fnThis);return fnThisObj._no_rewrite?originalFn.call(fnThisObj,position,textOrElem):rwHTML?originalFn.call(fnThisObj,position,this.rewriteHtml(textOrElem)):(this.rewriteElemComplete(textOrElem),originalFn.call(fnThisObj,position,textOrElem))},Wombat.prototype.rewriteSetTimeoutInterval=function(fnThis,originalFn,argsObj){var rw=this.isString(argsObj[0]),args=rw?new Array(argsObj.length):argsObj;if(rw){args[0]=this.$wbwindow.Proxy?this.wrapScriptTextJsProxy(argsObj[0]):argsObj[0].replace(/\blocation\b/g,"WB_wombat_$&");for(var i=1;i0&&cssStyleValueOverride(this.$wbwindow.CSSStyleValue,"parse"),this.$wbwindow.CSSStyleValue.parseAll&&this.$wbwindow.CSSStyleValue.parseAll.toString().indexOf("[native code]")>0&&cssStyleValueOverride(this.$wbwindow.CSSStyleValue,"parseAll")}if(this.$wbwindow.CSSKeywordValue&&this.$wbwindow.CSSKeywordValue.prototype){var oCSSKV=this.$wbwindow.CSSKeywordValue;this.$wbwindow.CSSKeywordValue=function(CSSKeywordValue_){return function CSSKeywordValue(cssValue){return wombat.domConstructorErrorChecker(this,"CSSKeywordValue",arguments),new CSSKeywordValue_(wombat.rewriteStyle(cssValue))}}(this.$wbwindow.CSSKeywordValue),this.$wbwindow.CSSKeywordValue.prototype=oCSSKV.prototype,Object.defineProperty(this.$wbwindow.CSSKeywordValue.prototype,"constructor",{value:this.$wbwindow.CSSKeywordValue}),addToStringTagToClass(this.$wbwindow.CSSKeywordValue,"CSSKeywordValue")}if(this.$wbwindow.StylePropertyMap&&this.$wbwindow.StylePropertyMap.prototype){var originalSet=this.$wbwindow.StylePropertyMap.prototype.set;this.$wbwindow.StylePropertyMap.prototype.set=function set(){if(arguments.length<=1)return originalSet.__WB_orig_apply?originalSet.__WB_orig_apply(this,arguments):originalSet.apply(this,arguments);var newArgs=new Array(arguments.length);newArgs[0]=arguments[0];for(var i=1;i=0||name==="href"?wombat.extractOriginalURL(value):value},svgImgProto.getAttributeNS=function getAttributeNS(ns,name){var value=orig_getAttrNS.call(this,ns,name);return name.indexOf("xlink:href")>=0||name==="href"?wombat.extractOriginalURL(value):value},svgImgProto.setAttribute=function setAttribute(name,value){var rwValue=value;return(name.indexOf("xlink:href")>=0||name==="href")&&(rwValue=wombat.rewriteUrl(value)),orig_setAttr.call(this,name,rwValue)},svgImgProto.setAttributeNS=function setAttributeNS(ns,name,value){var rwValue=value;return(name.indexOf("xlink:href")>=0||name==="href")&&(rwValue=wombat.rewriteUrl(value)),orig_setAttrNS.call(this,ns,name,rwValue)}}},Wombat.prototype.initCreateElementNSFix=function(){if(this.$wbwindow.document.createElementNS&&this.$wbwindow.Document.prototype.createElementNS){var orig_createElementNS=this.$wbwindow.document.createElementNS,wombat=this,createElementNS=function createElementNS(namespaceURI,qualifiedName){return orig_createElementNS.call(wombat.proxyToObj(this),wombat.extractOriginalURL(namespaceURI),qualifiedName)};this.$wbwindow.Document.prototype.createElementNS=createElementNS,this.$wbwindow.document.createElementNS=createElementNS}},Wombat.prototype.initInsertAdjacentElementHTMLOverrides=function(){var Element=this.$wbwindow.Element;if(Element&&Element.prototype){var elementProto=Element.prototype,rewriteFn=this.rewriteInsertAdjHTMLOrElemArgs;if(elementProto.insertAdjacentHTML){var origInsertAdjacentHTML=elementProto.insertAdjacentHTML;elementProto.insertAdjacentHTML=function insertAdjacentHTML(position,text){return rewriteFn(this,origInsertAdjacentHTML,position,text,true)}}if(elementProto.insertAdjacentElement){var origIAdjElem=elementProto.insertAdjacentElement;elementProto.insertAdjacentElement=function insertAdjacentElement(position,element){return rewriteFn(this,origIAdjElem,position,element,false)}}}},Wombat.prototype.initDomOverride=function(){var Node=this.$wbwindow.Node;if(Node&&Node.prototype){var rewriteFn=this.rewriteNodeFuncArgs;if(Node.prototype.appendChild){var originalAppendChild=Node.prototype.appendChild;Node.prototype.appendChild=function appendChild(newNode,oldNode){return rewriteFn(this,originalAppendChild,newNode,oldNode)}}if(Node.prototype.insertBefore){var originalInsertBefore=Node.prototype.insertBefore;Node.prototype.insertBefore=function insertBefore(newNode,oldNode){return rewriteFn(this,originalInsertBefore,newNode,oldNode)}}if(Node.prototype.replaceChild){var originalReplaceChild=Node.prototype.replaceChild;Node.prototype.replaceChild=function replaceChild(newNode,oldNode){return rewriteFn(this,originalReplaceChild,newNode,oldNode)}}this.overridePropToProxy(Node.prototype,"ownerDocument"),this.overridePropToProxy(this.$wbwindow.HTMLHtmlElement.prototype,"parentNode"),this.overridePropToProxy(this.$wbwindow.Event.prototype,"target")}this.$wbwindow.Element&&this.$wbwindow.Element.prototype&&(this.overrideParentNodeAppendPrepend(this.$wbwindow.Element),this.overrideChildNodeInterface(this.$wbwindow.Element,false)),this.$wbwindow.DocumentFragment&&this.$wbwindow.DocumentFragment.prototype&&this.overrideParentNodeAppendPrepend(this.$wbwindow.DocumentFragment)},Wombat.prototype.initDocOverrides=function($document){if(Object.defineProperty){this.overridePropExtract($document,"referrer"),this.defGetterProp($document,"origin",function origin(){return this.WB_wombat_location.origin}),this.defGetterProp(this.$wbwindow,"origin",function origin(){return this.WB_wombat_location.origin});var wombat=this,domain_setter=function domain(val){var loc=this.WB_wombat_location;loc&&wombat.endsWith(loc.hostname,val)&&(this.__wb_domain=val)},domain_getter=function domain(){return this.__wb_domain||this.WB_wombat_location.hostname};this.defProp($document,"domain",domain_setter,domain_getter)}},Wombat.prototype.initDocWriteOpenCloseOverride=function(){if(this.$wbwindow.DOMParser){var DocumentProto=this.$wbwindow.Document.prototype,$wbDocument=this.$wbwindow.document,docWriteWritelnRWFn=this.rewriteDocWriteWriteln,orig_doc_write=$wbDocument.write,new_write=function write(){return docWriteWritelnRWFn(this,orig_doc_write,arguments)};$wbDocument.write=new_write,DocumentProto.write=new_write;var orig_doc_writeln=$wbDocument.writeln,new_writeln=function writeln(){return docWriteWritelnRWFn(this,orig_doc_writeln,arguments)};$wbDocument.writeln=new_writeln,DocumentProto.writeln=new_writeln;var wombat=this,orig_doc_open=$wbDocument.open,new_open=function open(){var res,thisObj=wombat.proxyToObj(this);if(arguments.length===3){var rwUrl=wombat.rewriteUrl(arguments[0],false,"mp_");res=orig_doc_open.call(thisObj,rwUrl,arguments[1],arguments[2]),wombat.initNewWindowWombat(res,rwUrl)}else res=orig_doc_open.call(thisObj),wombat.initNewWindowWombat(thisObj.defaultView);return res};$wbDocument.open=new_open,DocumentProto.open=new_open;var originalClose=$wbDocument.close,newClose=function close(){var thisObj=wombat.proxyToObj(this);return wombat.initNewWindowWombat(thisObj.defaultView),originalClose.__WB_orig_apply?originalClose.__WB_orig_apply(thisObj,arguments):originalClose.apply(thisObj,arguments)};$wbDocument.close=newClose,DocumentProto.close=newClose;var oBodyGetter=this.getOrigGetter(DocumentProto,"body"),oBodySetter=this.getOrigSetter(DocumentProto,"body");oBodyGetter&&oBodySetter&&this.defProp(DocumentProto,"body",function body(newBody){return newBody&&(newBody instanceof HTMLBodyElement||newBody instanceof HTMLFrameSetElement)&&wombat.rewriteElemComplete(newBody),oBodySetter.call(wombat.proxyToObj(this),newBody)},oBodyGetter)}},Wombat.prototype.initIframeWombat=function(iframe){var win;win=iframe._get_contentWindow?iframe._get_contentWindow.call(iframe):iframe.contentWindow;try{if(!win||win===this.$wbwindow||win._skip_wombat||win._wb_wombat)return}catch(e){return}var src=this.wb_getAttribute.call(iframe,"src");this.initNewWindowWombat(win,src)},Wombat.prototype.initNewWindowWombat=function(win,src){if(this.ensureServerSideInjectsExistOnWindow(win),win&&!win._wb_wombat)if(!src||src===""||this.startsWith(src,"about:")||src.indexOf("javascript:")>=0){var wombat=new Wombat(win,this.wb_info);win._wb_wombat=wombat.wombatInit()}else this.initProtoPmOrigin(win),this.initPostMessageOverride(win),this.initMessageEventOverride(win)},Wombat.prototype.initTimeoutIntervalOverrides=function(){var rewriteFn=this.rewriteSetTimeoutInterval;if(this.$wbwindow.setTimeout&&!this.$wbwindow.setTimeout.__$wbpatched$__){var originalSetTimeout=this.$wbwindow.setTimeout;this.$wbwindow.setTimeout=function setTimeout(){return rewriteFn(this,originalSetTimeout,arguments)},this.$wbwindow.setTimeout.__$wbpatched$__=true}if(this.$wbwindow.setInterval&&!this.$wbwindow.setInterval.__$wbpatched$__){var originalSetInterval=this.$wbwindow.setInterval;this.$wbwindow.setInterval=function setInterval(){return rewriteFn(this,originalSetInterval,arguments)},this.$wbwindow.setInterval.__$wbpatched$__=true}},Wombat.prototype.initWorkerOverrides=function(){var wombat=this;if(this.$wbwindow.Worker&&!this.$wbwindow.Worker._wb_worker_overriden){var orig_worker=this.$wbwindow.Worker;this.$wbwindow.Worker=function(Worker_){return function Worker(url,options){return wombat.domConstructorErrorChecker(this,"Worker",arguments),new Worker_(wombat.rewriteWorker(url),options)}}(orig_worker),this.$wbwindow.Worker.prototype=orig_worker.prototype,Object.defineProperty(this.$wbwindow.Worker.prototype,"constructor",{value:this.$wbwindow.Worker}),this.$wbwindow.Worker._wb_worker_overriden=true}if(this.$wbwindow.SharedWorker&&!this.$wbwindow.SharedWorker.__wb_sharedWorker_overriden){var oSharedWorker=this.$wbwindow.SharedWorker;this.$wbwindow.SharedWorker=function(SharedWorker_){return function SharedWorker(url,options){return wombat.domConstructorErrorChecker(this,"SharedWorker",arguments),new SharedWorker_(wombat.rewriteWorker(url),options)}}(oSharedWorker),this.$wbwindow.SharedWorker.prototype=oSharedWorker.prototype,Object.defineProperty(this.$wbwindow.SharedWorker.prototype,"constructor",{value:this.$wbwindow.SharedWorker}),this.$wbwindow.SharedWorker.__wb_sharedWorker_overriden=true}if(this.$wbwindow.ServiceWorkerContainer&&this.$wbwindow.ServiceWorkerContainer.prototype&&this.$wbwindow.ServiceWorkerContainer.prototype.register){var orig_register=this.$wbwindow.ServiceWorkerContainer.prototype.register;this.$wbwindow.ServiceWorkerContainer.prototype.register=function register(scriptURL,options){var newScriptURL=new URL(scriptURL,wombat.$wbwindow.document.baseURI).href,mod=wombat.getPageUnderModifier();return options&&options.scope?options.scope=wombat.rewriteUrl(options.scope,false,mod):options={scope:wombat.rewriteUrl("/",false,mod)},orig_register.call(this,wombat.rewriteUrl(newScriptURL,false,"sw_"),options)}}if(this.$wbwindow.Worklet&&this.$wbwindow.Worklet.prototype&&this.$wbwindow.Worklet.prototype.addModule&&!this.$wbwindow.Worklet.__wb_workerlet_overriden){var oAddModule=this.$wbwindow.Worklet.prototype.addModule;this.$wbwindow.Worklet.prototype.addModule=function addModule(moduleURL,options){var rwModuleURL=wombat.rewriteUrl(moduleURL,false,"js_");return oAddModule.call(this,rwModuleURL,options)},this.$wbwindow.Worklet.__wb_workerlet_overriden=true}},Wombat.prototype.initLocOverride=function(loc,oSetter,oGetter){if(Object.defineProperty)for(var prop,i=0;i. */ -(function(){function autobind(clazz){for(var prop,propValue,proto=clazz.__proto__||clazz.constructor.prototype||clazz.prototype,clazzProps=Object.getOwnPropertyNames(proto),len=clazzProps.length,i=0;i source[srcset], picture > source[data-srcset], picture > source[data-src], video > source[srcset], video > source[data-srcset], video > source[data-src], audio > source[srcset], audio > source[data-srcset], audio > source[data-src]",this.mutationOpts={characterData:false,characterDataOldValue:false,attributes:true,attributeOldValue:true,subtree:true,childList:true,attributeFilter:["src","srcset"]},autobind(this),this._init(true)):new AutoFetchWorkerProxyMode(wombat,isTop)}function WombatLite($wbwindow,wbinfo){return this instanceof WombatLite?void(this.wb_info=wbinfo,this.$wbwindow=$wbwindow,this.wb_info.top_host=this.wb_info.top_host||"*",this.wb_info.wombat_opts=this.wb_info.wombat_opts||{},this.wbAutoFetchWorkerPrefix=(this.wb_info.auto_fetch_worker_prefix||this.wb_info.static_prefix)+"autoFetchWorkerProxyMode.js",this.WBAutoFetchWorker=null):new WombatLite($wbwindow,wbinfo)}AutoFetchWorkerProxyMode.prototype._init=function(first){var afwpm=this;if(document.readyState==="complete")return this.styleTag=document.createElement("style"),this.styleTag.id="$wrStyleParser$",document.head.appendChild(this.styleTag),void(this.isTop?fetch(this.wombat.wbAutoFetchWorkerPrefix).then(function(res){res.text().then(function(text){var blob=new Blob([text],{type:"text/javascript"});afwpm.worker=new afwpm.wombat.$wbwindow.Worker(URL.createObjectURL(blob)),afwpm.startChecking()}).catch(error=>{console.error("Could not create the backing worker for AutoFetchWorkerProxyMode"),console.error(error)})}):(this.worker={postMessage:function(msg){msg.wb_type||(msg={wb_type:"aaworker",msg:msg}),afwpm.wombat.$wbwindow.top.postMessage(msg,"*")},terminate:function(){}},this.startChecking()));if(first)var i=setInterval(function(){document.readyState==="complete"&&(afwpm._init(),clearInterval(i))},1e3)},AutoFetchWorkerProxyMode.prototype.startChecking=function(){this.extractFromLocalDoc(),this.mutationObz=new MutationObserver(this.mutationCB),this.mutationObz.observe(document,this.mutationOpts)},AutoFetchWorkerProxyMode.prototype.terminate=function(){this.worker.terminate()},AutoFetchWorkerProxyMode.prototype.justFetch=function(urls){this.worker.postMessage({type:"fetch-all",values:urls})},AutoFetchWorkerProxyMode.prototype.postMessage=function(msg){this.worker.postMessage(msg)},AutoFetchWorkerProxyMode.prototype.handleMutatedStyleElem=function(elem,accum,text){var checkNode,baseURI=document.baseURI;if(text){if(!elem.parentNode||elem.parentNode.localName!=="style")return;checkNode=elem.parentNode}else checkNode=elem;try{var extractedMedia=this.extractMediaRules(checkNode.sheet,baseURI);if(extractedMedia.length)return void(accum.media=accum.media.concat(extractedMedia))}catch(e){}!text&&checkNode.href&&accum.deferred.push(this.fetchCSSAndExtract(checkNode.href))},AutoFetchWorkerProxyMode.prototype.handleMutatedElem=function(elem,accum){var baseURI=document.baseURI;if(elem.nodeType===Node.TEXT_NODE)return this.handleMutatedStyleElem(elem,accum,true);switch(elem.localName){case"img":case"video":case"audio":case"source":return this.handleDomElement(elem,baseURI,accum);case"style":case"link":return this.handleMutatedStyleElem(elem,accum);}return this.extractSrcSrcsetFrom(elem,baseURI,accum)},AutoFetchWorkerProxyMode.prototype.mutationCB=function(mutationList,observer){for(var accum={type:"values",srcset:[],src:[],media:[],deferred:[]},i=0;i source[srcset], picture > source[data-srcset], picture > source[data-src], video > source[srcset], video > source[data-srcset], video > source[data-src], audio > source[srcset], audio > source[data-srcset], audio > source[data-src]",autobind(this),this._init(config,true)):new AutoFetcherProxyMode(wombat,config)}function WombatLite($wbwindow,wbinfo){return this instanceof WombatLite?void(this.wb_info=wbinfo,this.$wbwindow=$wbwindow,this.wb_info.top_host=this.wb_info.top_host||"*",this.wb_info.wombat_opts=this.wb_info.wombat_opts||{},this.WBAutoFetchWorker=null):new WombatLite($wbwindow,wbinfo)}AutoFetcherProxyMode.prototype._init=function(config,first){var afwpm=this,wombat=this.wombat;if(document.readyState==="complete")return this.styleTag=document.createElement("style"),this.styleTag.id="$wrStyleParser$",document.head.appendChild(this.styleTag),void(config.isTop?fetch(config.workerURL).then(function(res){res.text().then(function(text){var blob=new Blob([text],{type:"text/javascript"});afwpm.worker=new wombat.$wbwindow.Worker(URL.createObjectURL(blob),{type:"classic",credentials:"include"}),afwpm.startChecking()}).catch(error=>{console.error("Could not create the backing worker for AutoFetchWorkerProxyMode"),console.error(error)})}):(this.worker={postMessage:function(msg){msg.wb_type||(msg={wb_type:"aaworker",msg:msg}),wombat.$wbwindow.top.postMessage(msg,"*")},terminate:function(){}},this.startChecking()));if(first)var i=setInterval(function(){document.readyState==="complete"&&(afwpm._init(config),clearInterval(i))},1e3)},AutoFetcherProxyMode.prototype.startChecking=function(){this.extractFromLocalDoc(),this.mutationObz=new MutationObserver(this.mutationCB),this.mutationObz.observe(document.documentElement,{characterData:false,characterDataOldValue:false,attributes:true,attributeOldValue:true,subtree:true,childList:true,attributeFilter:["src","srcset"]})},AutoFetcherProxyMode.prototype.terminate=function(){this.worker.terminate()},AutoFetcherProxyMode.prototype.justFetch=function(urls){this.worker.postMessage({type:"fetch-all",values:urls})},AutoFetcherProxyMode.prototype.postMessage=function(msg){this.worker.postMessage(msg)},AutoFetcherProxyMode.prototype.handleMutatedStyleElem=function(elem,accum,text){var checkNode,baseURI=document.baseURI;if(text){if(!elem.parentNode||elem.parentNode.localName!=="style")return;checkNode=elem.parentNode}else checkNode=elem;try{var extractedMedia=this.extractMediaRules(checkNode.sheet,baseURI);if(extractedMedia.length)return void(accum.media=accum.media.concat(extractedMedia))}catch(e){}!text&&checkNode.href&&accum.deferred.push(this.fetchCSSAndExtract(checkNode.href))},AutoFetcherProxyMode.prototype.handleMutatedElem=function(elem,accum){var baseURI=document.baseURI;if(elem.nodeType===Node.TEXT_NODE)return this.handleMutatedStyleElem(elem,accum,true);switch(elem.localName){case"img":case"video":case"audio":case"source":return this.handleDomElement(elem,baseURI,accum);case"style":case"link":return this.handleMutatedStyleElem(elem,accum);}return this.extractSrcSrcsetFrom(elem,baseURI,accum)},AutoFetcherProxyMode.prototype.mutationCB=function(mutationList,observer){for(var accum={type:"values",srcset:[],src:[],media:[],deferred:[]},i=0;i source[srcset], picture > source[data-srcset], picture > source[data-src], ' + - 'video > source[srcset], video > source[data-srcset], video > source[data-src], ' + - 'audio > source[srcset], audio > source[data-srcset], audio > source[data-src]'; - - this.isTop = wombat.$wbwindow === wombat.$wbwindow.__WB_replay_top; - - /** @type {Wombat} */ - this.wombat = wombat; - /** @type {Window} */ - this.$wbwindow = wombat.$wbwindow; - - /** @type {?Worker|Object} */ - this.worker = null; - autobind(this); - this._initWorker(); +if (!config.havePromise) { + // not kewl we must polyfill Promise + self.Promise = function(executor) { + executor(noop, noop); + }; + self.Promise.prototype.then = function(cb) { + if (cb) cb(); + return this; + }; + self.Promise.prototype.catch = function() { + return this; + }; + self.Promise.all = function(values) { + return new Promise(noop); + }; } -/** - * Initializes the backing worker IFF the execution context we are in is - * the replay tops otherwise creates a dummy worker that simply bounces the - * message that would have been sent to the backing worker to replay top. - * - * If creation of the worker fails, likely due to the execution context we - * are currently in having an null origin, we fallback to dummy worker creation. - * @private - */ -AutoFetchWorker.prototype._initWorker = function() { - var wombat = this.wombat; - if (this.isTop) { - // we are top and can will own this worker - // setup URL for the kewl case - // Normal replay and preservation mode pworker setup, its all one origin so YAY! - var workerURL = - (wombat.wb_info.auto_fetch_worker_prefix || - wombat.wb_info.static_prefix) + - 'autoFetchWorker.js?init=' + - encodeURIComponent( - JSON.stringify({ - mod: wombat.wb_info.mod, - prefix: wombat.wb_abs_prefix, - rwRe: wombat.wb_unrewrite_rx - }) - ); - try { - this.worker = new Worker(workerURL); - return; - } catch (e) { - // it is likely we are in some kind of horrid iframe setup - // and the execution context we are currently in has a null origin - console.error( - 'Failed to create auto fetch worker\n', - e, - '\nFalling back to non top behavior' - ); - } - } - - // add only the portions of the worker interface we use since we are not top - // and if in proxy mode start check polling - this.worker = { - postMessage: function(msg) { - if (!msg.wb_type) { - msg = { wb_type: 'aaworker', msg: msg }; - } - wombat.$wbwindow.__WB_replay_top.__orig_postMessage(msg, '*'); - }, - terminate: function() {} - }; -}; - -/** - * Extracts the media rules from the supplied CSSStyleSheet object if any - * are present and returns an array of the media cssText - * @param {CSSStyleSheet} sheet - * @return {Array} - */ -AutoFetchWorker.prototype.extractMediaRulesFromSheet = function(sheet) { - var rules; - var media = []; - try { - rules = sheet.cssRules || sheet.rules; - } catch (e) { - return media; - } - - // loop through each rule of the stylesheet - for (var i = 0; i < rules.length; ++i) { - var rule = rules[i]; - if (rule.type === CSSRule.MEDIA_RULE) { - // we are a media rule so get its text - media.push(rule.cssText); - } - } - return media; -}; - -/** - * Extracts the media rules from the supplied CSSStyleSheet object if any - * are present after a tick of the event loop sending the results of the - * extraction to the backing worker - * @param {CSSStyleSheet|StyleSheet} sheet - */ -AutoFetchWorker.prototype.deferredSheetExtraction = function(sheet) { - var afw = this; - // defer things until next time the Promise.resolve Qs are cleared - Promise.resolve().then(function() { - // loop through each rule of the stylesheet - var media = afw.extractMediaRulesFromSheet(sheet); - if (media.length > 0) { - // we have some media rules to preserve - afw.preserveMedia(media); - } - }); -}; - -/** - * Terminates the backing worker. This is a no op when we are not - * operating in the execution context of replay top - */ -AutoFetchWorker.prototype.terminate = function() { - // terminate the worker, a no op when not replay top - this.worker.terminate(); -}; - -/** - * Sends a message to backing worker. If deferred is true - * the message is sent after one tick of the event loop - * @param {Object} msg - * @param {boolean} [deferred] - */ -AutoFetchWorker.prototype.postMessage = function(msg, deferred) { - if (deferred) { - var afWorker = this; - Promise.resolve().then(function() { - afWorker.worker.postMessage(msg); +if (!config.haveFetch) { + // not kewl we must polyfill fetch. + self.fetch = function(url) { + return new Promise(function(resolve) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + if (!config.havePromise) { + fetchDoneOrErrored(); + } + resolve(); + } + }; + xhr.send(); }); + }; +} + +if (location.search.indexOf('init') !== -1) { + (function() { + var init; + if (typeof self.URL === 'function') { + var loc = new self.URL(location.href); + init = JSON.parse(loc.searchParams.get('init')); + } else { + var search = decodeURIComponent(location.search.split('?')[1]).split('&'); + init = JSON.parse(search[0].substr(search[0].indexOf('=') + 1)); + init.prefix = decodeURIComponent(init.prefix); + init.baseURI = decodeURIComponent(init.prefix); + } + config.prefix = init.prefix; + config.mod = init.mod; + config.prefixMod = init.prefix + init.mod; + config.rwRe = new RegExp(init.rwRe, 'g'); + config.relative = init.prefix.split(location.origin)[1]; + config.schemeless = '/' + config.relative; + })(); +} else { + config.proxyMode = true; +} + +self.onmessage = function(event) { + var data = event.data; + switch (data.type) { + case 'values': + autoFetch(data); + break; + case 'fetch-all': + justFetch(data); + break; + } +}; + +function noop() {} + +function fetchDoneOrErrored() { + runningFetches -= 1; + fetchFromQ(); +} + +function fetchURL(urlToBeFetched) { + runningFetches += 1; + fetch(urlToBeFetched) + .then(fetchDoneOrErrored) + .catch(fetchDoneOrErrored); +} + +function queueOrFetch(urlToBeFetched) { + if ( + !urlToBeFetched || + urlToBeFetched.indexOf(DataURLPrefix) === 0 || + seen[urlToBeFetched] != null + ) { return; } - this.worker.postMessage(msg); -}; - -/** - * Sends the supplied srcset value to the backing worker for preservation - * @param {string|Array} srcset - * @param {string} [mod] - */ -AutoFetchWorker.prototype.preserveSrcset = function(srcset, mod) { - // send values from rewriteSrcset to the worker - this.postMessage( - { - type: 'values', - srcset: { values: srcset, mod: mod, presplit: true } - }, - true - ); -}; - -/** - * Send the value of the supplied elements data-srcset attribute to the - * backing worker for preservation - * @param {Node} elem - */ -AutoFetchWorker.prototype.preserveDataSrcset = function(elem) { - // send values from rewriteAttr srcset to the worker deferred - // to ensure the page viewer sees the images first - this.postMessage( - { - type: 'values', - srcset: { - value: elem.dataset.srcset, - mod: this.rwMod(elem), - presplit: false - } - }, - true - ); -}; - -/** - * Sends the supplied array of cssText from media rules to the backing worker - * @param {Array} media - */ -AutoFetchWorker.prototype.preserveMedia = function(media) { - // send CSSMediaRule values to the worker - this.postMessage({ type: 'values', media: media }, true); -}; - -/** - * Extracts the value of the srcset property if it exists from the supplied - * element - * @param {Element} elem - * @return {?string} - */ -AutoFetchWorker.prototype.getSrcset = function(elem) { - if (this.wombat.wb_getAttribute) { - return this.wombat.wb_getAttribute.call(elem, 'srcset'); + seen[urlToBeFetched] = true; + if (runningFetches >= MaxRunningFetches) { + queue.push(urlToBeFetched); + return; } - return elem.getAttribute('srcset'); -}; + fetchURL(urlToBeFetched); +} -/** - * Returns the correct rewrite modifier for the supplied element - * @param {Element} elem - * @return {string} - */ -AutoFetchWorker.prototype.rwMod = function(elem) { - switch (elem.tagName) { - case 'SOURCE': - if (elem.parentElement && elem.parentElement.tagName === 'PICTURE') { - return 'im_'; - } - return 'oe_'; - case 'IMG': - return 'im_'; +function fetchFromQ() { + while (queue.length && runningFetches < MaxRunningFetches) { + fetchURL(queue.shift()); } - return 'oe_'; -}; +} -/** - * Extracts the media rules from stylesheets and the (data-)srcset URLs from - * image elements the current context's document contains - */ -AutoFetchWorker.prototype.extractFromLocalDoc = function() { - // get the values to be preserved from the documents stylesheets - // and all img, video, audio elements with (data-)?srcset or data-src - var afw = this; - Promise.resolve().then(function() { - var msg = { - type: 'values', - context: { docBaseURI: document.baseURI } - }; - var media = []; - var i = 0; - var sheets = document.styleSheets; - for (; i < sheets.length; ++i) { - media = media.concat(afw.extractMediaRulesFromSheet(sheets[i])); +function maybeResolveURL(url, base) { + // given a url and base url returns a resolved full URL or + // null if resolution was unsuccessful + try { + var _url = new URL(url, base); + return _url.href; + } catch (e) { + return null; + } +} + +function safeResolve(url, resolver) { + // Guard against the exception thrown by the URL constructor if the URL or resolver is bad + // if resolver is undefined/null then this function passes url through + var resolvedURL = url; + if (resolver) { + try { + var _url = new URL(url, resolver); + return _url.href; + } catch (e) { + resolvedURL = url; } - var elems = document.querySelectorAll(afw.elemSelector); - var srcset = { values: [], presplit: false }; - var src = { values: [] }; - var elem, srcv, mod; - for (i = 0; i < elems.length; ++i) { - elem = elems[i]; - // we want the original src value in order to resolve URLs in the worker when needed - srcv = elem.src ? elem.src : null; - // a from value of 1 indicates images and a 2 indicates audio/video - mod = afw.rwMod(elem); - if (elem.srcset) { - srcset.values.push({ - srcset: afw.getSrcset(elem), - mod: mod, - tagSrc: srcv - }); - } - if (elem.dataset.srcset) { - srcset.values.push({ - srcset: elem.dataset.srcset, - mod: mod, - tagSrc: srcv - }); - } - if (elem.dataset.src) { - src.values.push({ src: elem.dataset.src, mod: mod }); - } - if (elem.tagName === 'SOURCE' && srcv) { - src.values.push({ src: srcv, mod: mod }); + } + return resolvedURL; +} + +function maybeFixUpRelSchemelessPrefix(url) { + // attempt to ensure rewritten relative or schemeless URLs become full URLS! + // otherwise returns null if this did not happen + if (url.indexOf(config.relative) === 0) { + return url.replace(config.relative, config.prefix); + } + if (url.indexOf(config.schemeless) === 0) { + return url.replace(config.schemeless, config.prefix); + } + return null; +} + +function maybeFixUpURL(url, resolveOpts) { + // attempt to fix up the url and do our best to ensure we can get dat 200 OK! + if (config.rwRe.test(url)) { + return url; + } + var mod = resolveOpts.mod || 'mp_'; + // first check for / (relative) or // (schemeless) rewritten urls + var maybeFixed = maybeFixUpRelSchemelessPrefix(url); + if (maybeFixed != null) { + return maybeFixed; + } + // resolve URL against tag src + if (resolveOpts.tagSrc != null) { + maybeFixed = maybeResolveURL(url, resolveOpts.tagSrc); + if (maybeFixed != null) { + return config.prefix + mod + '/' + maybeFixed; + } + } + // finally last attempt resolve the originating documents base URI + if (resolveOpts.docBaseURI) { + maybeFixed = maybeResolveURL(url, resolveOpts.docBaseURI); + if (maybeFixed != null) { + return config.prefix + mod + '/' + maybeFixed; + } + } + // not much to do now..... + return config.prefixMod + '/' + url; +} + +function urlExtractor(match, n1, n2, n3, offset, string) { + // Same function as style_replacer in wombat.rewrite_style, n2 is our URL + queueOrFetch(n2); + return n1 + n2 + n3; +} + +function urlExtractorProxyMode(match, n1, n2, n3, offset, string) { + // Same function as style_replacer in wombat.rewrite_style, n2 is our URL + // this.currentResolver is set to the URL which the browser would normally + // resolve relative urls with (URL of the stylesheet) in an exceptionless manner + // (resolvedURL will be undefined if an error occurred) + queueOrFetch(safeResolve(n2, currentResolver)); + return n1 + n2 + n3; +} + +function handleMedia(mediaRules) { + // this is a broken down rewrite_style + if (mediaRules == null || mediaRules.length === 0) return; + for (var i = 0; i < mediaRules.length; i++) { + mediaRules[i] + .replace(STYLE_REGEX, urlExtractor) + .replace(IMPORT_REGEX, urlExtractor); + } +} + +function handleMediaProxyMode(mediaRules) { + // this is a broken down rewrite_style + if (mediaRules == null || mediaRules.length === 0) return; + for (var i = 0; i < mediaRules.length; i++) { + // set currentResolver to the value of this stylesheets URL, done to ensure we do not have to + // create functions on each loop iteration because we potentially create a new `URL` object + // twice per iteration + currentResolver = mediaRules[i].resolve; + mediaRules[i].cssText + .replace(STYLE_REGEX, urlExtractorProxyMode) + .replace(IMPORT_REGEX, urlExtractorProxyMode); + } +} + +function handleSrc(srcValues, context) { + var resolveOpts = { docBaseURI: context.docBaseURI }; + if (srcValues.value) { + resolveOpts.mod = srcValues.mod; + return queueOrFetch(maybeFixUpURL(srcValues.value.trim(), resolveOpts)); + } + var len = srcValues.values.length; + for (var i = 0; i < len; i++) { + var value = srcValues.values[i]; + resolveOpts.mod = value.mod; + queueOrFetch(maybeFixUpURL(value.src, resolveOpts)); + } +} + +function handleSrcProxyMode(srcValues) { + // preservation worker in proxy mode sends us the value of the srcset attribute of an element + // and a URL to correctly resolve relative URLS. Thus we must recreate rewrite_srcset logic here + if (srcValues == null || srcValues.length === 0) return; + var srcVal; + for (var i = 0; i < srcValues.length; i++) { + srcVal = srcValues[i]; + queueOrFetch(safeResolve(srcVal.src, srcVal.resolve)); + } +} + +function extractSrcSetNotPreSplit(ssV, resolveOpts) { + if (!ssV) return; + // was from extract from local doc so we need to duplicate work + var srcsetValues = ssV.split(srcsetSplit); + for (var i = 0; i < srcsetValues.length; i++) { + // grab the URL not width/height key + if (srcsetValues[i]) { + var value = srcsetValues[i].trim().split(' ')[0]; + var maybeResolvedURL = maybeFixUpURL(value.trim(), resolveOpts); + queueOrFetch(maybeResolvedURL); + } + } +} + +function extractSrcset(srcsets) { + // was rewrite_srcset and only need to q + for (var i = 0; i < srcsets.length; i++) { + // grab the URL not width/height key + var url = srcsets[i].split(' ')[0]; + queueOrFetch(url); + } +} + +function handleSrcset(srcset, context) { + if (srcset == null) return; + var resolveOpts = { + docBaseURI: context.docBaseURI, + mode: null, + tagSrc: null + }; + if (srcset.value) { + // we have a single value, this srcset came from either + // preserveDataSrcset (not presplit) preserveSrcset (presplit) + resolveOpts.mod = srcset.mod; + if (!srcset.presplit) { + // extract URLs from the srcset string + return extractSrcSetNotPreSplit(srcset.value, resolveOpts); + } + // we have an array of srcset URL strings + return extractSrcset(srcset.value); + } + // we have an array of values, these srcsets came from extractFromLocalDoc + var len = srcset.values.length; + for (var i = 0; i < len; i++) { + var ssv = srcset.values[i]; + resolveOpts.mod = ssv.mod; + resolveOpts.tagSrc = ssv.tagSrc; + extractSrcSetNotPreSplit(ssv.srcset, resolveOpts); + } +} + +function handleSrcsetProxyMode(srcsets) { + // preservation worker in proxy mode sends us the value of the srcset attribute of an element + // and a URL to correctly resolve relative URLS. Thus we must recreate rewrite_srcset logic here + if (srcsets == null) return; + var length = srcsets.length; + var extractedSrcSet, srcsetValue, ssSplit, j; + for (var i = 0; i < length; i++) { + extractedSrcSet = srcsets[i]; + ssSplit = extractedSrcSet.srcset.split(srcsetSplit); + for (j = 0; j < ssSplit.length; j++) { + if (ssSplit[j]) { + srcsetValue = ssSplit[j].trim(); + if (srcsetValue) { + queueOrFetch( + safeResolve(srcsetValue.split(' ')[0], extractedSrcSet.resolve) + ); + } } } - if (media.length) { - msg.media = media; + } +} + +function autoFetch(data) { + // we got a message and now we autofetch! + // these calls turn into no ops if they have no work + if (data.media) { + if (config.proxyMode) { + handleMediaProxyMode(data.media); + } else { + handleMedia(data.media); } - if (srcset.values.length) { - msg.srcset = srcset; + } + + if (data.src) { + if (config.proxyMode) { + handleSrcProxyMode(data.src); + } else { + handleSrc(data.src, data.context || { docBaseURI: null }); } - if (src.values.length) { - msg.src = src; + } + + if (data.srcset) { + if (config.proxyMode) { + handleSrcsetProxyMode(data.srcset); + } else { + handleSrcset(data.srcset, data.context || { docBaseURI: null }); } - if (msg.media || msg.srcset || msg.src) { - afw.postMessage(msg); - } - }); -}; + } +} + +function justFetch(data) { + // we got a message containing only urls to be fetched + if (data == null || data.values == null) return; + for (var i = 0; i < data.values.length; ++i) { + queueOrFetch(data.values[i]); + } +} diff --git a/wombat/src/autoFetcher.js b/wombat/src/autoFetcher.js new file mode 100755 index 00000000..a26a60a2 --- /dev/null +++ b/wombat/src/autoFetcher.js @@ -0,0 +1,292 @@ +/* eslint-disable camelcase */ +import { autobind } from './wombatUtils'; + +/** + * Create a new instance of AutoFetcher + * @param {Wombat} wombat + * @param {{isTop: boolean, workerURL: string}} config + */ +export default function AutoFetcher(wombat, config) { + if (!(this instanceof AutoFetcher)) { + return new AutoFetcher(wombat, config); + } + // specifically target the elements we desire + this.elemSelector = + 'img[srcset], img[data-srcset], img[data-src], video[srcset], video[data-srcset], video[data-src], audio[srcset], audio[data-srcset], audio[data-src], ' + + 'picture > source[srcset], picture > source[data-srcset], picture > source[data-src], ' + + 'video > source[srcset], video > source[data-srcset], video > source[data-src], ' + + 'audio > source[srcset], audio > source[data-srcset], audio > source[data-src]'; + + /** @type {Wombat} */ + this.wombat = wombat; + /** @type {Window} */ + this.$wbwindow = wombat.$wbwindow; + + /** @type {?Worker|Object} */ + this.worker = null; + autobind(this); + this._initWorker(config); +} + +/** + * Initializes the backing worker IFF the execution context we are in is + * the replay tops otherwise creates a dummy worker that simply bounces the + * message that would have been sent to the backing worker to replay top. + * + * If creation of the worker fails, likely due to the execution context we + * are currently in having an null origin, we fallback to dummy worker creation. + * @param {{isTop: boolean, workerURL: string}} config + * @private + */ +AutoFetcher.prototype._initWorker = function(config) { + var wombat = this.wombat; + if (config.isTop) { + // we are top and can will own this worker + // setup URL for the kewl case + // Normal replay and preservation mode pworker setup, its all one origin so YAY! + try { + this.worker = new Worker(config.workerURL, { + type: 'classic', + credentials: 'include' + }); + } catch (e) { + // it is likely we are in some kind of horrid iframe setup + // and the execution context we are currently in has a null origin + console.error('Failed to create auto fetch worker\n', e); + } + return; + } + + // add only the portions of the worker interface we use since we are not top + // and if in proxy mode start check polling + this.worker = { + postMessage: function(msg) { + if (!msg.wb_type) { + msg = { wb_type: 'aaworker', msg: msg }; + } + wombat.$wbwindow.__WB_replay_top.__orig_postMessage(msg, '*'); + }, + terminate: function() {} + }; +}; + +/** + * Extracts the media rules from the supplied CSSStyleSheet object if any + * are present and returns an array of the media cssText + * @param {CSSStyleSheet} sheet + * @return {Array} + */ +AutoFetcher.prototype.extractMediaRulesFromSheet = function(sheet) { + var rules; + var media = []; + try { + rules = sheet.cssRules || sheet.rules; + } catch (e) { + return media; + } + + // loop through each rule of the stylesheet + for (var i = 0; i < rules.length; ++i) { + var rule = rules[i]; + if (rule.type === CSSRule.MEDIA_RULE) { + // we are a media rule so get its text + media.push(rule.cssText); + } + } + return media; +}; + +/** + * Extracts the media rules from the supplied CSSStyleSheet object if any + * are present after a tick of the event loop sending the results of the + * extraction to the backing worker + * @param {CSSStyleSheet|StyleSheet} sheet + */ +AutoFetcher.prototype.deferredSheetExtraction = function(sheet) { + var afw = this; + // defer things until next time the Promise.resolve Qs are cleared + Promise.resolve().then(function() { + // loop through each rule of the stylesheet + var media = afw.extractMediaRulesFromSheet(sheet); + if (media.length > 0) { + // we have some media rules to preserve + afw.preserveMedia(media); + } + }); +}; + +/** + * Terminates the backing worker. This is a no op when we are not + * operating in the execution context of replay top + */ +AutoFetcher.prototype.terminate = function() { + // terminate the worker, a no op when not replay top + this.worker.terminate(); +}; + +/** + * Sends the supplied array of URLs to the backing worker + * @param {Array} urls + */ +AutoFetcher.prototype.justFetch = function(urls) { + this.worker.postMessage({ type: 'fetch-all', values: urls }); +}; + +/** + * Sends a message to backing worker. If deferred is true + * the message is sent after one tick of the event loop + * @param {Object} msg + * @param {boolean} [deferred] + */ +AutoFetcher.prototype.postMessage = function(msg, deferred) { + if (deferred) { + var afWorker = this; + Promise.resolve().then(function() { + afWorker.worker.postMessage(msg); + }); + return; + } + this.worker.postMessage(msg); +}; + +/** + * Sends the supplied srcset value to the backing worker for preservation + * @param {string|Array} srcset + * @param {string} [mod] + */ +AutoFetcher.prototype.preserveSrcset = function(srcset, mod) { + // send values from rewriteSrcset to the worker + this.postMessage( + { + type: 'values', + srcset: { value: srcset, mod: mod, presplit: true } + }, + true + ); +}; + +/** + * Send the value of the supplied elements data-srcset attribute to the + * backing worker for preservation + * @param {Node} elem + */ +AutoFetcher.prototype.preserveDataSrcset = function(elem) { + // send values from rewriteAttr srcset to the worker deferred + // to ensure the page viewer sees the images first + this.postMessage( + { + type: 'values', + srcset: { + value: elem.dataset.srcset, + mod: this.rwMod(elem), + presplit: false + } + }, + true + ); +}; + +/** + * Sends the supplied array of cssText from media rules to the backing worker + * @param {Array} media + */ +AutoFetcher.prototype.preserveMedia = function(media) { + // send CSSMediaRule values to the worker + this.postMessage({ type: 'values', media: media }, true); +}; + +/** + * Extracts the value of the srcset property if it exists from the supplied + * element + * @param {Element} elem + * @return {?string} + */ +AutoFetcher.prototype.getSrcset = function(elem) { + if (this.wombat.wb_getAttribute) { + return this.wombat.wb_getAttribute.call(elem, 'srcset'); + } + return elem.getAttribute('srcset'); +}; + +/** + * Returns the correct rewrite modifier for the supplied element + * @param {Element} elem + * @return {string} + */ +AutoFetcher.prototype.rwMod = function(elem) { + switch (elem.tagName) { + case 'SOURCE': + if (elem.parentElement && elem.parentElement.tagName === 'PICTURE') { + return 'im_'; + } + return 'oe_'; + case 'IMG': + return 'im_'; + } + return 'oe_'; +}; + +/** + * Extracts the media rules from stylesheets and the (data-)srcset URLs from + * image elements the current context's document contains + */ +AutoFetcher.prototype.extractFromLocalDoc = function() { + // get the values to be preserved from the documents stylesheets + // and all img, video, audio elements with (data-)?srcset or data-src + var afw = this; + Promise.resolve().then(function() { + var msg = { + type: 'values', + context: { docBaseURI: document.baseURI } + }; + var media = []; + var i = 0; + var sheets = document.styleSheets; + for (; i < sheets.length; ++i) { + media = media.concat(afw.extractMediaRulesFromSheet(sheets[i])); + } + var elems = document.querySelectorAll(afw.elemSelector); + var srcset = { values: [], presplit: false }; + var src = { values: [] }; + var elem, srcv, mod; + for (i = 0; i < elems.length; ++i) { + elem = elems[i]; + // we want the original src value in order to resolve URLs in the worker when needed + srcv = elem.src ? elem.src : null; + // a from value of 1 indicates images and a 2 indicates audio/video + mod = afw.rwMod(elem); + if (elem.srcset) { + srcset.values.push({ + srcset: afw.getSrcset(elem), + mod: mod, + tagSrc: srcv + }); + } + if (elem.dataset.srcset) { + srcset.values.push({ + srcset: elem.dataset.srcset, + mod: mod, + tagSrc: srcv + }); + } + if (elem.dataset.src) { + src.values.push({ src: elem.dataset.src, mod: mod }); + } + if (elem.tagName === 'SOURCE' && srcv) { + src.values.push({ src: srcv, mod: mod }); + } + } + if (media.length) { + msg.media = media; + } + if (srcset.values.length) { + msg.srcset = srcset; + } + if (src.values.length) { + msg.src = src; + } + if (msg.media || msg.srcset || msg.src) { + afw.postMessage(msg); + } + }); +}; diff --git a/wombat/src/autoFetchWorkerProxyMode.js b/wombat/src/autoFetcherProxyMode.js similarity index 85% rename from wombat/src/autoFetchWorkerProxyMode.js rename to wombat/src/autoFetcherProxyMode.js index 50db6e21..0b9d49fd 100755 --- a/wombat/src/autoFetchWorkerProxyMode.js +++ b/wombat/src/autoFetcherProxyMode.js @@ -3,65 +3,54 @@ import { autobind } from './wombatUtils'; /** * Create a new instance of AutoFetchWorkerProxyMode * @param {Wombat} wombat - * @param {boolean} isTop + * @param {{isTop: boolean, workerURL: string}} config */ -export default function AutoFetchWorkerProxyMode(wombat, isTop) { - if (!(this instanceof AutoFetchWorkerProxyMode)) { - return new AutoFetchWorkerProxyMode(wombat, isTop); +export default function AutoFetcherProxyMode(wombat, config) { + if (!(this instanceof AutoFetcherProxyMode)) { + return new AutoFetcherProxyMode(wombat, config); } - /** - * @type {Wombat} - */ + /** @type {Wombat} */ this.wombat = wombat; - /** - * @type {boolean} - */ - this.isTop = isTop; - - /** - * @type {?MutationObserver} - */ + /** @type {?MutationObserver} */ this.mutationObz = null; + /** @type {?HTMLStyleElement} */ + this.styleTag = null; // specifically target the elements we desire + /** @type {string} */ this.elemSelector = 'img[srcset], img[data-srcset], img[data-src], video[srcset], video[data-srcset], video[data-src], audio[srcset], audio[data-srcset], audio[data-src], ' + 'picture > source[srcset], picture > source[data-srcset], picture > source[data-src], ' + 'video > source[srcset], video > source[data-srcset], video > source[data-src], ' + 'audio > source[srcset], audio > source[data-srcset], audio > source[data-src]'; - this.mutationOpts = { - characterData: false, - characterDataOldValue: false, - attributes: true, - attributeOldValue: true, - subtree: true, - childList: true, - attributeFilter: ['src', 'srcset'] - }; autobind(this); - this._init(true); + this._init(config, true); } /** * Initialize the auto fetch worker + * @param {{isTop: boolean, workerURL: string}} config + * @param {boolean} [first] * @private */ -AutoFetchWorkerProxyMode.prototype._init = function(first) { +AutoFetcherProxyMode.prototype._init = function(config, first) { var afwpm = this; + var wombat = this.wombat; if (document.readyState === 'complete') { this.styleTag = document.createElement('style'); this.styleTag.id = '$wrStyleParser$'; document.head.appendChild(this.styleTag); - if (this.isTop) { + if (config.isTop) { // Cannot directly load our worker from the proxy origin into the current origin // however we fetch it from proxy origin and can blob it into the current origin :) - fetch(this.wombat.wbAutoFetchWorkerPrefix).then(function(res) { + fetch(config.workerURL).then(function(res) { res .text() .then(function(text) { var blob = new Blob([text], { type: 'text/javascript' }); - afwpm.worker = new afwpm.wombat.$wbwindow.Worker( - URL.createObjectURL(blob) + afwpm.worker = new wombat.$wbwindow.Worker( + URL.createObjectURL(blob), + { type: 'classic', credentials: 'include' } ); afwpm.startChecking(); }) @@ -79,7 +68,7 @@ AutoFetchWorkerProxyMode.prototype._init = function(first) { if (!msg.wb_type) { msg = { wb_type: 'aaworker', msg: msg }; } - afwpm.wombat.$wbwindow.top.postMessage(msg, '*'); + wombat.$wbwindow.top.postMessage(msg, '*'); }, terminate: function() {} }; @@ -90,7 +79,7 @@ AutoFetchWorkerProxyMode.prototype._init = function(first) { if (!first) return; var i = setInterval(function() { if (document.readyState === 'complete') { - afwpm._init(); + afwpm._init(config); clearInterval(i); } }, 1000); @@ -99,16 +88,24 @@ AutoFetchWorkerProxyMode.prototype._init = function(first) { /** * Initializes the mutation observer */ -AutoFetchWorkerProxyMode.prototype.startChecking = function() { +AutoFetcherProxyMode.prototype.startChecking = function() { this.extractFromLocalDoc(); this.mutationObz = new MutationObserver(this.mutationCB); - this.mutationObz.observe(document, this.mutationOpts); + this.mutationObz.observe(document.documentElement, { + characterData: false, + characterDataOldValue: false, + attributes: true, + attributeOldValue: true, + subtree: true, + childList: true, + attributeFilter: ['src', 'srcset'] + }); }; /** * Terminate the worker, a no op when not replay top */ -AutoFetchWorkerProxyMode.prototype.terminate = function() { +AutoFetcherProxyMode.prototype.terminate = function() { this.worker.terminate(); }; @@ -116,7 +113,7 @@ AutoFetchWorkerProxyMode.prototype.terminate = function() { * Sends the supplied array of URLs to the backing worker * @param {Array} urls */ -AutoFetchWorkerProxyMode.prototype.justFetch = function(urls) { +AutoFetcherProxyMode.prototype.justFetch = function(urls) { this.worker.postMessage({ type: 'fetch-all', values: urls }); }; @@ -124,7 +121,7 @@ AutoFetchWorkerProxyMode.prototype.justFetch = function(urls) { * Sends the supplied msg to the backing worker * @param {Object} msg */ -AutoFetchWorkerProxyMode.prototype.postMessage = function(msg) { +AutoFetcherProxyMode.prototype.postMessage = function(msg) { this.worker.postMessage(msg); }; @@ -136,7 +133,7 @@ AutoFetchWorkerProxyMode.prototype.postMessage = function(msg) { * @param {boolean} [text] * @return {void} */ -AutoFetchWorkerProxyMode.prototype.handleMutatedStyleElem = function( +AutoFetcherProxyMode.prototype.handleMutatedStyleElem = function( elem, accum, text @@ -166,7 +163,7 @@ AutoFetchWorkerProxyMode.prototype.handleMutatedStyleElem = function( * @param {*} elem * @param {Object} accum */ -AutoFetchWorkerProxyMode.prototype.handleMutatedElem = function(elem, accum) { +AutoFetcherProxyMode.prototype.handleMutatedElem = function(elem, accum) { var baseURI = document.baseURI; if (elem.nodeType === Node.TEXT_NODE) { return this.handleMutatedStyleElem(elem, accum, true); @@ -189,10 +186,7 @@ AutoFetchWorkerProxyMode.prototype.handleMutatedElem = function(elem, accum) { * @param {Array} mutationList * @param {MutationObserver} observer */ -AutoFetchWorkerProxyMode.prototype.mutationCB = function( - mutationList, - observer -) { +AutoFetcherProxyMode.prototype.mutationCB = function(mutationList, observer) { var accum = { type: 'values', srcset: [], src: [], media: [], deferred: [] }; for (var i = 0; i < mutationList.length; i++) { var mutation = mutationList[i]; @@ -212,7 +206,6 @@ AutoFetchWorkerProxyMode.prototype.mutationCB = function( Promise.all(deferred).then(this.handleDeferredSheetResults); } if (accum.srcset.length || accum.src.length || accum.media.length) { - console.log('msg', Date.now(), accum); this.postMessage(accum); } }; @@ -222,7 +215,7 @@ AutoFetchWorkerProxyMode.prototype.mutationCB = function( * @param {StyleSheet} sheet * @return {boolean} */ -AutoFetchWorkerProxyMode.prototype.shouldSkipSheet = function(sheet) { +AutoFetcherProxyMode.prototype.shouldSkipSheet = function(sheet) { // we skip extracting rules from sheets if they are from our parsing style or come from pywb if (sheet.id === '$wrStyleParser$') return true; return !!( @@ -236,7 +229,7 @@ AutoFetchWorkerProxyMode.prototype.shouldSkipSheet = function(sheet) { * @param {?string} srcV * @return {null|string} */ -AutoFetchWorkerProxyMode.prototype.validateSrcV = function(srcV) { +AutoFetcherProxyMode.prototype.validateSrcV = function(srcV) { if (!srcV || srcV.indexOf('data:') === 0 || srcV.indexOf('blob:') === 0) { return null; } @@ -250,7 +243,7 @@ AutoFetchWorkerProxyMode.prototype.validateSrcV = function(srcV) { * @param {string} cssURL * @return {Promise} */ -AutoFetchWorkerProxyMode.prototype.fetchCSSAndExtract = function(cssURL) { +AutoFetcherProxyMode.prototype.fetchCSSAndExtract = function(cssURL) { var url = location.protocol + '//' + @@ -276,10 +269,7 @@ AutoFetchWorkerProxyMode.prototype.fetchCSSAndExtract = function(cssURL) { * @param {string} baseURI * @return {Array} */ -AutoFetchWorkerProxyMode.prototype.extractMediaRules = function( - sheet, - baseURI -) { +AutoFetcherProxyMode.prototype.extractMediaRules = function(sheet, baseURI) { // We are in proxy mode and must include a URL to resolve relative URLs in media rules var results = []; if (!sheet) return results; @@ -306,7 +296,7 @@ AutoFetchWorkerProxyMode.prototype.extractMediaRules = function( * @param {Element} elem * @return {string} */ -AutoFetchWorkerProxyMode.prototype.rwMod = function(elem) { +AutoFetcherProxyMode.prototype.rwMod = function(elem) { switch (elem.tagName) { case 'SOURCE': if (elem.parentElement && elem.parentElement.tagName === 'PICTURE') { @@ -326,7 +316,7 @@ AutoFetchWorkerProxyMode.prototype.rwMod = function(elem) { * @param {string} baseURI * @param {?Object} acum */ -AutoFetchWorkerProxyMode.prototype.handleDomElement = function( +AutoFetcherProxyMode.prototype.handleDomElement = function( elem, baseURI, acum @@ -368,7 +358,7 @@ AutoFetchWorkerProxyMode.prototype.handleDomElement = function( * @param {string} baseURI * @param {Object} [acum] */ -AutoFetchWorkerProxyMode.prototype.extractSrcSrcsetFrom = function( +AutoFetcherProxyMode.prototype.extractSrcSrcsetFrom = function( fromElem, baseURI, acum @@ -391,9 +381,7 @@ AutoFetchWorkerProxyMode.prototype.extractSrcSrcsetFrom = function( * Sends the extracted media values to the backing worker * @param {Array>} results */ -AutoFetchWorkerProxyMode.prototype.handleDeferredSheetResults = function( - results -) { +AutoFetcherProxyMode.prototype.handleDeferredSheetResults = function(results) { if (results.length === 0) return; var len = results.length; var media = []; @@ -411,7 +399,7 @@ AutoFetchWorkerProxyMode.prototype.handleDeferredSheetResults = function( * contexts document object * @param {?Document} [doc] */ -AutoFetchWorkerProxyMode.prototype.checkStyleSheets = function(doc) { +AutoFetcherProxyMode.prototype.checkStyleSheets = function(doc) { var media = []; var deferredMediaExtraction = []; var styleSheets = (doc || document).styleSheets; @@ -457,7 +445,7 @@ AutoFetchWorkerProxyMode.prototype.checkStyleSheets = function(doc) { /** * Performs extraction from the current contexts document */ -AutoFetchWorkerProxyMode.prototype.extractFromLocalDoc = function() { +AutoFetcherProxyMode.prototype.extractFromLocalDoc = function() { // check for data-[src,srcset] and auto-fetched elems with srcset first this.extractSrcSrcsetFrom( this.wombat.$wbwindow.document, diff --git a/wombat/src/customStorage.js b/wombat/src/customStorage.js index e131526b..2a76178e 100755 --- a/wombat/src/customStorage.js +++ b/wombat/src/customStorage.js @@ -1,8 +1,4 @@ -import { - addToStringTagToClass, - ensureNumber, - ThrowExceptions -} from './wombatUtils'; +import { addToStringTagToClass, ensureNumber, ThrowExceptions } from './wombatUtils'; /** * A re-implementation of the Storage interface. diff --git a/wombat/src/wombat.js b/wombat/src/wombat.js index 5942a4b6..484bca1c 100755 --- a/wombat/src/wombat.js +++ b/wombat/src/wombat.js @@ -2,7 +2,7 @@ import FuncMap from './funcMap'; import Storage from './customStorage'; import WombatLocation from './wombatLocation'; -import AutoFetchWorker from './autoFetchWorker'; +import AutoFetcher from './autoFetcher'; import { wrapEventListener, wrapSameOriginEventListener } from './listeners'; import { addToStringTagToClass, @@ -58,7 +58,7 @@ function Wombat($wbwindow, wbinfo) { /** @type {function(): string} */ this.wb_funToString = Function.prototype.toString; - /** @type {AutoFetchWorker} */ + /** @type {AutoFetcher} */ this.WBAutoFetchWorker = null; /** @type {boolean} */ @@ -1983,12 +1983,12 @@ Wombat.prototype.rewriteSrcset = function(value, elem) { var split = value.split(this.srcsetRe); var values = []; - + var mod = this.rwModForElement(elem, 'srcset'); for (var i = 0; i < split.length; i++) { // Filter removes non-truthy values like null, undefined, and "" if (split[i]) { var trimmed = split[i].trim(); - if (trimmed) values.push(this.rewriteUrl(trimmed)); + if (trimmed) values.push(this.rewriteUrl(trimmed, true, mod)); } } @@ -3141,6 +3141,7 @@ Wombat.prototype.overrideFuncArgProxyToObj = function( if (!cls || !cls.prototype) return; var argIndex = argumentIdx || 0; var orig = cls.prototype[method]; + if (!orig) return; var wombat = this; cls.prototype[method] = function deproxyFnArg() { var args = new Array(arguments.length); @@ -4782,7 +4783,6 @@ Wombat.prototype.initHashChange = function() { var wombat = this; var receive_hash_change = function receive_hash_change(event) { - if (!event.data || !event.data.from_top) { return; } @@ -5219,7 +5219,6 @@ Wombat.prototype.initDisableNotificationsGeoLocation = function() { callback ) { if (callback) { - // eslint-disable-next-line standard/no-callback-literal callback('denied'); } @@ -5448,7 +5447,21 @@ Wombat.prototype.initDocumentObjProxy = function($document) { */ Wombat.prototype.initAutoFetchWorker = function() { if (!this.wbUseAFWorker) return; - this.WBAutoFetchWorker = new AutoFetchWorker(this); + var af = new AutoFetcher(this, { + isTop: this.$wbwindow === this.$wbwindow.__WB_replay_top, + workerURL: + (this.wb_info.auto_fetch_worker_prefix || this.wb_info.static_prefix) + + 'autoFetchWorker.js?init=' + + encodeURIComponent( + JSON.stringify({ + mod: this.wb_info.mod, + prefix: this.wb_abs_prefix, + rwRe: this.wb_unrewrite_rx.source + }) + ) + }); + this.WBAutoFetchWorker = af; + this.$wbwindow.$WBAutoFetchWorker$ = af; var wombat = this; this.utilFns.wbSheetMediaQChecker = function checkStyle() { // used only for link[rel='stylesheet'] so we remove our listener diff --git a/wombat/src/wombatLite.js b/wombat/src/wombatLite.js index eb31b376..257583fb 100755 --- a/wombat/src/wombatLite.js +++ b/wombat/src/wombatLite.js @@ -1,5 +1,5 @@ /* eslint-disable camelcase */ -import AutoFetchWorkerProxyMode from './autoFetchWorkerProxyMode'; +import AutoFetcherProxyMode from './autoFetcherProxyMode'; /** * Wombat lite for proxy-mode @@ -12,9 +12,6 @@ export default function WombatLite($wbwindow, wbinfo) { this.$wbwindow = $wbwindow; this.wb_info.top_host = this.wb_info.top_host || '*'; this.wb_info.wombat_opts = this.wb_info.wombat_opts || {}; - this.wbAutoFetchWorkerPrefix = - (this.wb_info.auto_fetch_worker_prefix || this.wb_info.static_prefix) + - 'autoFetchWorkerProxyMode.js'; this.WBAutoFetchWorker = null; } @@ -157,7 +154,6 @@ WombatLite.prototype.initDisableNotifications = function() { callback ) { if (callback) { - // eslint-disable-next-line standard/no-callback-literal callback('denied'); } @@ -201,9 +197,14 @@ WombatLite.prototype.initAutoFetchWorker = function() { if (!this.$wbwindow.Worker) { return; } - var isTop = this.$wbwindow.self === this.$wbwindow.top; + var config = { + isTop: this.$wbwindow.self === this.$wbwindow.top, + workerURL: + (this.wb_info.auto_fetch_worker_prefix || this.wb_info.static_prefix) + + 'autoFetchWorker.js' + }; if (this.$wbwindow.$WBAutoFetchWorker$ == null) { - this.WBAutoFetchWorker = new AutoFetchWorkerProxyMode(this, isTop); + this.WBAutoFetchWorker = new AutoFetcherProxyMode(this, config); // expose the WBAutoFetchWorker Object.defineProperty(this.$wbwindow, '$WBAutoFetchWorker$', { enumerable: false, @@ -212,7 +213,7 @@ WombatLite.prototype.initAutoFetchWorker = function() { } else { this.WBAutoFetchWorker = this.$wbwindow.$WBAutoFetchWorker$; } - if (isTop) { + if (config.isTop) { var wombatLite = this; this.$wbwindow.addEventListener( 'message', diff --git a/wombat/yarn.lock b/wombat/yarn.lock index 0a4c32d4..79cea94a 100644 --- a/wombat/yarn.lock +++ b/wombat/yarn.lock @@ -404,10 +404,10 @@ resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== -"@types/fs-extra@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-7.0.0.tgz#9c4ad9e1339e7448a76698829def1f159c1b636c" - integrity sha512-ndoMMbGyuToTy4qB6Lex/inR98nPiNHacsgMPvy+zqMLgSxbt8VtWpDArpGp69h1fEDQHn1KB+9DWD++wgbwYA== +"@types/fs-extra@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.0.0.tgz#d3e2c313ca29f95059f198dd60d1f774642d4b25" + integrity sha512-bCtL5v9zdbQW86yexOlXWTEGvLNqWxMFyi7gQA7Gcthbezr2cPSOb8SkESVKA937QD5cIwOFLDFt0MQoXOEr9Q== dependencies: "@types/node" "*" @@ -457,7 +457,7 @@ acorn@^6.0.7, acorn@^6.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== -ajv@^6.8.1, ajv@^6.9.1, ajv@^6.9.2: +ajv@^6.10.0, ajv@^6.8.1, ajv@^6.9.1, ajv@^6.9.2: version "6.10.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg== @@ -1150,17 +1150,6 @@ chokidar@^3.0.1: optionalDependencies: fsevents "^2.0.6" -chrome-launcher@^0.10.7: - version "0.10.7" - resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-0.10.7.tgz#5e2a9e99f212e0501d9c7024802acd01a812f5d5" - integrity sha512-IoQLp64s2n8OQuvKZwt77CscVj3UlV2Dj7yZtd1EBMld9mSdGcsGy9fN5hd/r4vJuWZR09it78n1+A17gB+AIQ== - dependencies: - "@types/node" "*" - is-wsl "^1.1.0" - lighthouse-logger "^1.0.0" - mkdirp "0.5.1" - rimraf "^2.6.1" - chrome-remote-interface-extra@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/chrome-remote-interface-extra/-/chrome-remote-interface-extra-1.1.1.tgz#f82a5c9ee731e9301dd922360d140840f806b64a" @@ -1460,7 +1449,7 @@ date-time@^2.1.0: dependencies: time-zone "^1.0.0" -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: +debug@2.6.9, debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -1689,10 +1678,10 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -eslint-config-prettier@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-5.0.0.tgz#f7a94b2b8ae7cbf25842c36fa96c6d32cd0a697c" - integrity sha512-c17Aqiz5e8LEqoc/QPmYnaxQFAHTx2KlCZBPxXXjEMmNchOLnV/7j0HoPZuC+rL/tDC9bazUYOKJW9bOhftI/w== +eslint-config-prettier@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.0.0.tgz#f429a53bde9fc7660e6353910fd996d6284d3c25" + integrity sha512-vDrcCFE3+2ixNT5H83g28bO/uYAwibJxerXPj+E7op4qzBCsAV36QfvdAyVOoNxKAH2Os/e01T/2x++V0LPukA== dependencies: get-stdin "^6.0.0" @@ -1721,13 +1710,13 @@ eslint-visitor-keys@^1.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== -eslint@^5.16.0: - version "5.16.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" - integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== +eslint@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.0.1.tgz#4a32181d72cb999d6f54151df7d337131f81cda7" + integrity sha512-DyQRaMmORQ+JsWShYsSg4OPTjY56u1nCjAmICrE8vLWqyLKxhFXOthwMj1SA8xwfrv0CofLNVnqbfyhwCkaO0w== dependencies: "@babel/code-frame" "^7.0.0" - ajv "^6.9.1" + ajv "^6.10.0" chalk "^2.1.0" cross-spawn "^6.0.5" debug "^4.0.1" @@ -1735,18 +1724,19 @@ eslint@^5.16.0: eslint-scope "^4.0.3" eslint-utils "^1.3.1" eslint-visitor-keys "^1.0.0" - espree "^5.0.1" + espree "^6.0.0" esquery "^1.0.1" esutils "^2.0.2" file-entry-cache "^5.0.1" functional-red-black-tree "^1.0.1" - glob "^7.1.2" + glob-parent "^3.1.0" globals "^11.7.0" ignore "^4.0.6" import-fresh "^3.0.0" imurmurhash "^0.1.4" inquirer "^6.2.2" - js-yaml "^3.13.0" + is-glob "^4.0.0" + js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" lodash "^4.17.11" @@ -1754,7 +1744,6 @@ eslint@^5.16.0: mkdirp "^0.5.1" natural-compare "^1.4.0" optionator "^0.8.2" - path-is-inside "^1.0.2" progress "^2.0.0" regexpp "^2.0.1" semver "^5.5.1" @@ -1778,10 +1767,10 @@ espower-location-detector@^1.0.0: source-map "^0.5.0" xtend "^4.0.0" -espree@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" - integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== +espree@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.0.0.tgz#716fc1f5a245ef5b9a7fdb1d7b0d3f02322e75f6" + integrity sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q== dependencies: acorn "^6.0.7" acorn-jsx "^5.0.0" @@ -2001,10 +1990,10 @@ fastify-static@^2.5.0: readable-stream "^3.4.0" send "^0.16.0" -fastify@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/fastify/-/fastify-2.5.0.tgz#24de69394231fc1b2eb82a9d932e909aa89ba56f" - integrity sha512-51z51VlbGw+ZJp8MJeZVqLtwAMMUiobo/YcAgyA7guRzflDa5tyw7yhZUDLfOng2YQIrVWZzWX7jPPvbQPQBxg== +fastify@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/fastify/-/fastify-2.6.0.tgz#45397b760f75278633fe0dcb30fcb4a26d1f66f6" + integrity sha512-3GxGV2P8731o2S5T6ng5NMJ9S7vFpZA4mk2mJEbMbhQ5aj1HhNGBOe39TYa2gWRrJVJuXxYYYIlY/5cFhiHpNg== dependencies: abstract-logging "^1.0.0" ajv "^6.9.2" @@ -2173,16 +2162,7 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= -fs-extra@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" - integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-extra@^8.0.1: +fs-extra@^7.0.0, fs-extra@^8.0.1, fs-extra@~8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.0.1.tgz#90294081f978b1f182f347a440a209154344285b" integrity sha512-W+XLrggcDzlle47X/XnS7FXrXu9sDo+Ze9zpndeBxdgv88FHLm1HtmkhEwavruS6koanBjp098rUpHs65EmG7A== @@ -2283,7 +2263,7 @@ glob-to-regexp@^0.3.0: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= -glob@^7.0.3, glob@^7.1.2, glob@^7.1.3: +glob@^7.0.3, glob@^7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== @@ -2791,11 +2771,6 @@ is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -is-wsl@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= - is-wsl@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.0.0.tgz#32849d5bf66413883ce07fada2e924f5505ed493" @@ -2868,10 +2843,10 @@ js-yaml@^3.10.0: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@^3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.0.tgz#38ee7178ac0eea2c97ff6d96fff4b18c7d8cf98e" - integrity sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ== +js-yaml@^3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== dependencies: argparse "^1.0.7" esprima "^4.0.0" @@ -2987,14 +2962,6 @@ light-my-request@^3.2.0: ajv "^6.8.1" readable-stream "^3.1.1" -lighthouse-logger@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/lighthouse-logger/-/lighthouse-logger-1.2.0.tgz#b76d56935e9c137e86a04741f6bb9b2776e886ca" - integrity sha512-wzUvdIeJZhRsG6gpZfmSCfysaxNEr43i+QT+Hie94wvHDKFLi4n7C2GqZ4sTC+PH5b5iktmXJvU87rWvhP3lHw== - dependencies: - debug "^2.6.8" - marky "^1.2.0" - load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" @@ -3162,11 +3129,6 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" -marky@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.1.tgz#a3fcf82ffd357756b8b8affec9fdbf3a30dc1b02" - integrity sha512-md9k+Gxa3qLH6sUKpeC2CNkJK/Ld+bEz5X96nYwloqphQE0CKCVEKco/6jxEZixinqNdz5RFi/KaCyfbMDMAXQ== - matcher@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/matcher/-/matcher-2.0.0.tgz#85fe38d97670dbd2a46590cf099401e2ffb4755c" @@ -3313,7 +3275,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.1, mkdirp@^0.5.1: +mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -3650,7 +3612,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-is-inside@^1.0.1, path-is-inside@^1.0.2: +path-is-inside@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= @@ -4061,10 +4023,10 @@ resolve@^1.10.0, resolve@^1.3.2: dependencies: path-parse "^1.0.6" -resolve@^1.10.1, resolve@^1.11.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.0.tgz#4014870ba296176b86343d50b60f3b50609ce232" - integrity sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw== +resolve@^1.11.0, resolve@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" + integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== dependencies: path-parse "^1.0.6" @@ -4111,7 +4073,7 @@ rfdc@^1.1.2: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.2.tgz#e6e72d74f5dc39de8f538f65e00c36c18018e349" integrity sha512-92ktAgvZhBzYTIK0Mja9uen5q5J3NRVMoDkJL2VMwq6SXjVCgqvQeVP2XAaUY6HT+XpQYeLSjb3UoitBryKmdA== -rimraf@2.6.3, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3: +rimraf@2.6.3, rimraf@^2.6.2, rimraf@^2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== @@ -4137,27 +4099,27 @@ rollup-plugin-cleanup@^3.1.1: js-cleanup "^1.0.1" rollup-pluginutils "^2.3.3" -rollup-plugin-commonjs@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.0.0.tgz#58901ebe7ca44c2a03f0056de9bf9eb4a2dc8990" - integrity sha512-B8MoX5GRpj3kW4+YaFO/di2JsZkBxNjVmZ9LWjUoTAjq8N9wc7HObMXPsrvolVV9JXVtYSscflXM14A19dXPNQ== +rollup-plugin-commonjs@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.0.1.tgz#fbfcadf4ce2e826068e056a9f5c19287d9744ddf" + integrity sha512-x0PcCVdEc4J8igv1qe2vttz8JKAKcTs3wfIA3L8xEty3VzxgORLrzZrNWaVMc+pBC4U3aDOb9BnWLAQ8J11vkA== dependencies: - estree-walker "^0.6.0" + estree-walker "^0.6.1" is-reference "^1.1.2" magic-string "^0.25.2" - resolve "^1.10.1" - rollup-pluginutils "^2.7.0" + resolve "^1.11.0" + rollup-pluginutils "^2.8.1" -rollup-plugin-node-resolve@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.0.3.tgz#5e90fbd04a33fa1e4e1ed6d9b54afbe45af944f1" - integrity sha512-Mhhmf0x493xgUPEsRELnU1VM+4+WO82knWkAbZ0d2DvZQZJMbhzyQK/hqtpVscoRru1EqlK3TM1kK9ro469wPw== +rollup-plugin-node-resolve@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.1.0.tgz#49608b6ecaf2b776ab83e317d39b282d65d21b76" + integrity sha512-2hwwHNj0s8UEtUNT+lJq8rFWEznP7yJm3GCHBicadF6hiNX1aRARRZIjz2doeTlTGg/hOvJr4C/8+3k9Y/J5Hg== dependencies: "@types/resolve" "0.0.8" builtin-modules "^3.1.0" is-module "^1.0.0" - resolve "^1.11.0" - rollup-pluginutils "^2.8.0" + resolve "^1.11.1" + rollup-pluginutils "^2.8.1" rollup-plugin-uglify-es@^0.0.1: version "0.0.1" @@ -4184,17 +4146,17 @@ rollup-pluginutils@^2.3.3: estree-walker "^0.6.0" micromatch "^3.1.10" -rollup-pluginutils@^2.7.0, rollup-pluginutils@^2.8.0: +rollup-pluginutils@^2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz#8fa6dd0697344938ef26c2c09d2488ce9e33ce97" integrity sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg== dependencies: estree-walker "^0.6.1" -rollup@^1.15.6: - version "1.15.6" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.15.6.tgz#caf0ed28d2d78e3a59c1398e5a3695fb600a0ef0" - integrity sha512-s3Vn3QJQ5YVFfIG4nXoG9VdL1I37IZsft+4ZyeBhxE0df1kCFz9e+4bEAbR4mKH3pvBO9e9xjdxWPhhIp0r9ow== +rollup@^1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.16.2.tgz#959aeae4b06c8e540749bac442d6d37aefb9217d" + integrity sha512-UAZxaQvH0klYZdF+90xv9nGb+m4p8jdoaow1VL5/RzDK/gN/4CjvaMmJNcOIv1/+gtzswKhAg/467mzF0sLpAg== dependencies: "@types/estree" "0.0.39" "@types/node" "^12.0.8"