/**
 * Copyright 2015 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Registers all known ad network factories and then executes
 * one of them.
 *
 * This files gets minified and published to
 * https://3p.ampproject.net/$version/f.js
 */

// src/polyfills.js must be the first import.
import './polyfills'; // eslint-disable-line sort-imports-es6-autofix/sort-imports-es6

import {IntegrationAmpContext} from './ampcontext-integration';
import {dict} from '../src/utils/object.js';
import {endsWith} from '../src/string';
import {getAmpConfig, getEmbedType, getLocation} from './frame-metadata';
import {getMode} from '../src/mode';
import {getSourceUrl, isProxyOrigin, parseUrlDeprecated} from '../src/url';
import {
  initLogConstructor,
  isUserErrorMessage,
  setReportError,
  userAssert,
} from '../src/log';
import {installEmbedStateListener, manageWin} from './environment';
import {internalRuntimeVersion} from '../src/internal-version';
import {parseJson} from '../src/json';
import {register, run, setExperimentToggles} from './3p';
import {startsWith} from '../src/string.js';
import {urls} from '../src/config';

// 3P - please keep in alphabetic order
import {beopinion} from './beopinion';
import {bodymovinanimation} from './bodymovinanimation';
import {embedly} from './embedly';
import {facebook} from './facebook';
import {github} from './github';
import {gltfViewer} from './3d-gltf/index';
import {mathml} from './mathml';
import {reddit} from './reddit';
import {twitter} from './twitter';
import {viqeoplayer} from './viqeoplayer';
import {yotpo} from './yotpo';

import {_ping_} from '../ads/_ping_';

// 3P Ad Networks - please keep in alphabetic order
import {_1wo} from '../ads/1wo';
import {_24smi} from '../ads/24smi';
import {a8} from '../ads/a8';
import {a9} from '../ads/a9';
import {accesstrade} from '../ads/accesstrade';
import {adagio} from '../ads/adagio';
import {adblade, industrybrains} from '../ads/adblade';
import {adbutler} from '../ads/adbutler';
import {adform} from '../ads/adform';
import {adfox} from '../ads/adfox';
import {adgeneration} from '../ads/adgeneration';
import {adglare} from '../ads/adglare';
import {adhese} from '../ads/adhese';
import {adincube} from '../ads/adincube';
import {adition} from '../ads/adition';
import {adman} from '../ads/adman';
import {admanmedia} from '../ads/admanmedia';
import {admixer} from '../ads/admixer';
import {adocean} from '../ads/adocean';
import {adop} from '../ads/adop';
import {adpicker} from '../ads/adpicker';
import {adplugg} from '../ads/adplugg';
import {adpon} from '../ads/adpon';
import {adreactor} from '../ads/adreactor';
import {adsensor} from '../ads/adsensor';
import {adservsolutions} from '../ads/adservsolutions';
import {adsloom} from '../ads/adsloom';
import {adsnative} from '../ads/adsnative';
import {adspeed} from '../ads/adspeed';
import {adspirit} from '../ads/adspirit';
import {adstir} from '../ads/adstir';
import {adstyle} from '../ads/adstyle';
import {adtech} from '../ads/adtech';
import {adthrive} from '../ads/adthrive';
import {adunity} from '../ads/adunity';
import {aduptech} from '../ads/aduptech';
import {adventive} from '../ads/adventive';
import {adverline} from '../ads/adverline';
import {adverticum} from '../ads/adverticum';
import {advertserve} from '../ads/advertserve';
import {adyoulike} from '../ads/adyoulike';
import {affiliateb} from '../ads/affiliateb';
import {aja} from '../ads/aja';
import {amoad} from '../ads/amoad';
import {aniview} from '../ads/aniview';
import {appnexus} from '../ads/appnexus';
import {appvador} from '../ads/appvador';
import {atomx} from '../ads/atomx';
import {baidu} from '../ads/baidu';
import {beaverads} from '../ads/beaverads';
import {bidtellect} from '../ads/bidtellect';
import {blade} from '../ads/blade';
import {brainy} from '../ads/brainy';
import {bringhub} from '../ads/bringhub';
import {broadstreetads} from '../ads/broadstreetads';
import {caajainfeed} from '../ads/caajainfeed';
import {capirs} from '../ads/capirs';
import {caprofitx} from '../ads/caprofitx';
import {cedato} from '../ads/cedato';
import {chargeads, nws} from '../ads/nws';
import {colombia} from '../ads/colombia';
import {conative} from '../ads/conative';
import {connatix} from '../ads/connatix';
import {contentad} from '../ads/contentad';
import {criteo} from '../ads/criteo';
import {csa} from '../ads/google/csa';
import {dable} from '../ads/dable';
import {directadvert} from '../ads/directadvert';
import {distroscale} from '../ads/distroscale';
import {dotandads} from '../ads/dotandads';
import {dynad} from '../ads/dynad';
import {eadv} from '../ads/eadv';
import {eas} from '../ads/eas';
import {empower} from '../ads/empower';
import {engageya} from '../ads/engageya';
import {epeex} from '../ads/epeex';
import {eplanning} from '../ads/eplanning';
import {ezoic} from '../ads/ezoic';
import {f1e} from '../ads/f1e';
import {f1h} from '../ads/f1h';
import {felmat} from '../ads/felmat';
import {flite} from '../ads/flite';
import {fluct} from '../ads/fluct';
import {forkmedia} from '../ads/forkmedia';
import {freewheel} from '../ads/freewheel';
import {fusion} from '../ads/fusion';
import {genieessp} from '../ads/genieessp';
import {giraff} from '../ads/giraff';
import {gmossp} from '../ads/gmossp';
import {gumgum} from '../ads/gumgum';
import {holder} from '../ads/holder';
import {ibillboard} from '../ads/ibillboard';
import {idealmedia} from '../ads/idealmedia';
import {imaVideo} from '../ads/google/imaVideo';
import {imedia} from '../ads/imedia';
import {imobile} from '../ads/imobile';
import {imonomy} from '../ads/imonomy';
import {improvedigital} from '../ads/improvedigital';
import {inmobi} from '../ads/inmobi';
import {innity} from '../ads/innity';
import {insticator} from '../ads/insticator';
import {invibes} from '../ads/invibes';
import {ix} from '../ads/ix';
import {jubna} from '../ads/jubna';
import {kargo} from '../ads/kargo';
import {kiosked} from '../ads/kiosked';
import {kixer} from '../ads/kixer';
import {kuadio} from '../ads/kuadio';
import {lentainform} from '../ads/lentainform';
import {ligatus} from '../ads/ligatus';
import {lockerdome} from '../ads/lockerdome';
import {logly} from '../ads/logly';
import {loka} from '../ads/loka';
import {mads} from '../ads/mads';
import {mantisDisplay, mantisRecommend} from '../ads/mantis';
import {medianet} from '../ads/medianet';
import {mediavine} from '../ads/mediavine';
import {medyanet} from '../ads/medyanet';
import {meg} from '../ads/meg';
import {mgid} from '../ads/mgid';
import {microad} from '../ads/microad';
import {miximedia} from '../ads/miximedia';
import {mixpo} from '../ads/mixpo';
import {monetizer101} from '../ads/monetizer101';
import {mox} from '../ads/mox';
import {mytarget} from '../ads/mytarget';
import {mywidget} from '../ads/mywidget';
import {nativeroll} from '../ads/nativeroll';
import {nativery} from '../ads/nativery';
import {nativo} from '../ads/nativo';
import {navegg} from '../ads/navegg';
import {nend} from '../ads/nend';
import {netletix} from '../ads/netletix';
import {noddus} from '../ads/noddus';
import {nokta} from '../ads/nokta';
import {onead} from '../ads/onead';
import {onnetwork} from '../ads/onnetwork';
import {openadstream} from '../ads/openadstream';
import {openx} from '../ads/openx';
import {opinary} from '../ads/opinary';
import {outbrain} from '../ads/outbrain';
import {pixels} from '../ads/pixels';
import {plista} from '../ads/plista';
import {polymorphicads} from '../ads/polymorphicads';
import {popin} from '../ads/popin';
import {postquare} from '../ads/postquare';
import {pressboard} from '../ads/pressboard';
import {promoteiq} from '../ads/promoteiq';
import {pubexchange} from '../ads/pubexchange';
import {pubguru} from '../ads/pubguru';
import {pubmatic} from '../ads/pubmatic';
import {pubmine} from '../ads/pubmine';
import {puffnetwork} from '../ads/puffnetwork';
import {pulsepoint} from '../ads/pulsepoint';
import {purch} from '../ads/purch';
import {quoraad} from '../ads/quoraad';
import {rbinfox} from '../ads/rbinfox';
import {readmo} from '../ads/readmo';
import {realclick} from '../ads/realclick';
import {recomad} from '../ads/recomad';
import {relap} from '../ads/relap';
import {revcontent} from '../ads/revcontent';
import {revjet} from '../ads/revjet';
import {rfp} from '../ads/rfp';
import {rnetplus} from '../ads/rnetplus';
import {rubicon} from '../ads/rubicon';
import {runative} from '../ads/runative';
import {sas} from '../ads/sas';
import {seedingalliance} from '../ads/seedingalliance';
import {sekindo} from '../ads/sekindo';
import {sharethrough} from '../ads/sharethrough';
import {shemedia} from '../ads/shemedia';
import {sklik} from '../ads/sklik';
import {slimcutmedia} from '../ads/slimcutmedia';
import {smartadserver} from '../ads/smartadserver';
import {smartclip} from '../ads/smartclip';
import {smi2} from '../ads/smi2';
import {smilewanted} from '../ads/smilewanted';
import {sogouad} from '../ads/sogouad';
import {sortable} from '../ads/sortable';
import {sovrn} from '../ads/sovrn';
import {speakol} from '../ads/speakol';
import {spotx} from '../ads/spotx';
import {springAds} from '../ads/springAds';
import {ssp} from '../ads/ssp';
import {strossle} from '../ads/strossle';
import {sulvo} from '../ads/sulvo';
import {sunmedia} from '../ads/sunmedia';
import {svknative} from '../ads/svknative';
import {swoop} from '../ads/swoop';
import {taboola} from '../ads/taboola';
import {tcsemotion} from '../ads/tcsemotion';
import {teads} from '../ads/teads';
import {torimochi} from '../ads/torimochi';
import {tracdelight} from '../ads/tracdelight';
import {triplelift} from '../ads/triplelift';
import {trugaze} from '../ads/trugaze';
import {uas} from '../ads/uas';
import {ucfunnel} from '../ads/ucfunnel';
import {unruly} from '../ads/unruly';
import {uzou} from '../ads/uzou';
import {valuecommerce} from '../ads/valuecommerce';
import {vdoai} from '../ads/vdoai';
import {videointelligence} from '../ads/videointelligence';
import {videonow} from '../ads/videonow';
import {viralize} from '../ads/viralize';
import {vmfive} from '../ads/vmfive';
import {webediads} from '../ads/webediads';
import {weboramaDisplay} from '../ads/weborama';
import {widespace} from '../ads/widespace';
import {wisteria} from '../ads/wisteria';
import {wpmedia} from '../ads/wpmedia';
import {xlift} from '../ads/xlift';
import {yahoo} from '../ads/yahoo';
import {yahoojp} from '../ads/yahoojp';
import {yahoonativeads} from '../ads/yahoonativeads';
import {yandex} from '../ads/yandex';
import {yengo} from '../ads/yengo';
import {yieldbot} from '../ads/yieldbot';
import {yieldmo} from '../ads/yieldmo';
import {yieldone} from '../ads/yieldone';
import {yieldpro} from '../ads/yieldpro';
import {zedo} from '../ads/zedo';
import {zen} from '../ads/zen';
import {zergnet} from '../ads/zergnet';
import {zucks} from '../ads/zucks';

/**
 * Whether the embed type may be used with amp-embed tag.
 * @const {!Object<string, boolean>}
 */
const AMP_EMBED_ALLOWED = {
  _ping_: true,
  '1wo': true,
  '24smi': true,
  adsloom: true,
  adstyle: true,
  bringhub: true,
  dable: true,
  engageya: true,
  epeex: true,
  forkmedia: true,
  idealmedia: true,
  insticator: true,
  jubna: true,
  kuadio: true,
  'mantis-recommend': true,
  mgid: true,
  miximedia: true,
  mywidget: true,
  nativery: true,
  lentainform: true,
  opinary: true,
  outbrain: true,
  plista: true,
  postquare: true,
  pubexchange: true,
  rbinfox: true,
  readmo: true,
  runative: true,
  smartclip: true,
  smi2: true,
  speakol: true,
  strossle: true,
  svknative: true,
  taboola: true,
  yahoonativeads: true,
  zen: true,
  zergnet: true,
};

init(window);

if (getMode().test || getMode().localDev) {
  register('_ping_', _ping_);
}

// Keep the list in alphabetic order
register('1wo', _1wo);
register('24smi', _24smi);
register('3d-gltf', gltfViewer);
register('a8', a8);
register('a9', a9);
register('accesstrade', accesstrade);
register('adagio', adagio);
register('adblade', adblade);
register('adbutler', adbutler);
register('adform', adform);
register('adfox', adfox);
register('adgeneration', adgeneration);
register('adglare', adglare);
register('adhese', adhese);
register('adincube', adincube);
register('adition', adition);
register('adman', adman);
register('admanmedia', admanmedia);
register('admixer', admixer);
register('adocean', adocean);
register('adop', adop);
register('adpicker', adpicker);
register('adplugg', adplugg);
register('adpon', adpon);
register('adreactor', adreactor);
register('adsensor', adsensor);
register('adservsolutions', adservsolutions);
register('adsloom', adsloom);
register('adsnative', adsnative);
register('adspeed', adspeed);
register('adspirit', adspirit);
register('adstir', adstir);
register('adstyle', adstyle);
register('adtech', adtech);
register('adthrive', adthrive);
register('adunity', adunity);
register('aduptech', aduptech);
register('adventive', adventive);
register('adverline', adverline);
register('adverticum', adverticum);
register('advertserve', advertserve);
register('adyoulike', adyoulike);
register('affiliateb', affiliateb);
register('aja', aja);
register('amoad', amoad);
register('aniview', aniview);
register('appnexus', appnexus);
register('appvador', appvador);
register('atomx', atomx);
register('baidu', baidu);
register('beaverads', beaverads);
register('beopinion', beopinion);
register('bidtellect', bidtellect);
register('blade', blade);
register('bodymovinanimation', bodymovinanimation);
register('brainy', brainy);
register('bringhub', bringhub);
register('broadstreetads', broadstreetads);
register('caajainfeed', caajainfeed);
register('capirs', capirs);
register('caprofitx', caprofitx);
register('cedato', cedato);
register('chargeads', chargeads);
register('colombia', colombia);
register('conative', conative);
register('connatix', connatix);
register('contentad', contentad);
register('criteo', criteo);
register('csa', csa);
register('dable', dable);
register('directadvert', directadvert);
register('distroscale', distroscale);
register('dotandads', dotandads);
register('dynad', dynad);
register('eadv', eadv);
register('eas', eas);
register('embedly', embedly);
register('empower', empower);
register('engageya', engageya);
register('epeex', epeex);
register('eplanning', eplanning);
register('ezoic', ezoic);
register('f1e', f1e);
register('f1h', f1h);
register('facebook', facebook);
register('felmat', felmat);
register('flite', flite);
register('fluct', fluct);
register('forkmedia', forkmedia);
register('freewheel', freewheel);
register('fusion', fusion);
register('genieessp', genieessp);
register('giraff', giraff);
register('github', github);
register('gmossp', gmossp);
register('gumgum', gumgum);
register('holder', holder);
register('ibillboard', ibillboard);
register('idealmedia', idealmedia);
register('ima-video', imaVideo);
register('imedia', imedia);
register('imobile', imobile);
register('imonomy', imonomy);
register('improvedigital', improvedigital);
register('industrybrains', industrybrains);
register('inmobi', inmobi);
register('innity', innity);
register('insticator', insticator);
register('invibes', invibes);
register('ix', ix);
register('jubna', jubna);
register('kargo', kargo);
register('kiosked', kiosked);
register('kixer', kixer);
register('kuadio', kuadio);
register('lentainform', lentainform);
register('ligatus', ligatus);
register('lockerdome', lockerdome);
register('logly', logly);
register('loka', loka);
register('mads', mads);
register('mantis-display', mantisDisplay);
register('mantis-recommend', mantisRecommend);
register('mathml', mathml);
register('medianet', medianet);
register('mediavine', mediavine);
register('medyanet', medyanet);
register('meg', meg);
register('mgid', mgid);
register('microad', microad);
register('miximedia', miximedia);
register('mixpo', mixpo);
register('monetizer101', monetizer101);
register('mox', mox);
register('mytarget', mytarget);
register('mywidget', mywidget);
register('nativeroll', nativeroll);
register('nativery', nativery);
register('nativo', nativo);
register('navegg', navegg);
register('nend', nend);
register('netletix', netletix);
register('noddus', noddus);
register('nokta', nokta);
register('nws', nws);
register('onead', onead);
register('onnetwork', onnetwork);
register('openadstream', openadstream);
register('openx', openx);
register('opinary', opinary);
register('outbrain', outbrain);
register('pixels', pixels);
register('plista', plista);
register('polymorphicads', polymorphicads);
register('popin', popin);
register('postquare', postquare);
register('pressboard', pressboard);
register('promoteiq', promoteiq);
register('pubexchange', pubexchange);
register('pubguru', pubguru);
register('pubmatic', pubmatic);
register('pubmine', pubmine);
register('puffnetwork', puffnetwork);
register('pulsepoint', pulsepoint);
register('purch', purch);
register('quoraad', quoraad);
register('rbinfox', rbinfox);
register('readmo', readmo);
register('realclick', realclick);
register('reddit', reddit);
register('recomad', recomad);
register('relap', relap);
register('revcontent', revcontent);
register('revjet', revjet);
register('rfp', rfp);
register('rnetplus', rnetplus);
register('rubicon', rubicon);
register('runative', runative);
register('sas', sas);
register('seedingalliance', seedingalliance);
register('sekindo', sekindo);
register('sharethrough', sharethrough);
register('shemedia', shemedia);
register('sklik', sklik);
register('ssp', ssp);
register('slimcutmedia', slimcutmedia);
register('smartadserver', smartadserver);
register('smartclip', smartclip);
register('smi2', smi2);
register('smilewanted', smilewanted);
register('sogouad', sogouad);
register('sortable', sortable);
register('sovrn', sovrn);
register('spotx', spotx);
register('springAds', springAds);
register('strossle', strossle);
register('sulvo', sulvo);
register('sunmedia', sunmedia);
register('svknative', svknative);
register('swoop', swoop);
register('taboola', taboola);
register('tcsemotion', tcsemotion);
register('teads', teads);
register('torimochi', torimochi);
register('tracdelight', tracdelight);
register('triplelift', triplelift);
register('trugaze', trugaze);
register('twitter', twitter);
register('uas', uas);
register('ucfunnel', ucfunnel);
register('unruly', unruly);
register('uzou', uzou);
register('valuecommerce', valuecommerce);
register('vdoai', vdoai);
register('videointelligence', videointelligence);
register('videonow', videonow);
register('viqeoplayer', viqeoplayer);
register('viralize', viralize);
register('vmfive', vmfive);
register('webediads', webediads);
register('weborama-display', weboramaDisplay);
register('widespace', widespace);
register('wisteria', wisteria);
register('wpmedia', wpmedia);
register('xlift', xlift);
register('yahoo', yahoo);
register('yahoojp', yahoojp);
register('yahoonativeads', yahoonativeads);
register('yandex', yandex);
register('yengo', yengo);
register('yieldbot', yieldbot);
register('yieldmo', yieldmo);
register('yieldone', yieldone);
register('yieldpro', yieldpro);
register('yotpo', yotpo);
register('zedo', zedo);
register('zen', zen);
register('zergnet', zergnet);
register('zucks', zucks);
register('speakol', speakol);

// For backward compat, we always allow these types without the iframe
// opting in.
const defaultAllowedTypesInCustomFrame = [
  // Entries must be reasonably safe and not allow overriding the injected
  // JS URL.
  // Each custom iframe can override this through the second argument to
  // draw3p. See amp-ad docs.
  'facebook',
  'twitter',
  'doubleclick',
  'yieldbot',
  '_ping_',
];

/**
 * Initialize 3p frame.
 * @param {!Window} win
 */
function init(win) {
  initLogConstructor();
  const config = getAmpConfig();

  // Overriding to short-circuit src/mode#getMode()
  win.__AMP_MODE = config.mode;

  setReportError(console.error.bind(console));

  setExperimentToggles(config.experimentToggles);
}

/**
 * Visible for testing.
 * Draws a 3p embed to the window. Expects the data to include the 3p type.
 * @param {!Window} win
 * @param {!Object} data
 * @param {function(!Object, function(!Object))|undefined} configCallback
 *     Optional callback that allows user code to manipulate the incoming
 *     configuration. See
 *     https://github.com/ampproject/amphtml/issues/1210 for some context
 *     on this.
 */
export function draw3p(win, data, configCallback) {
  const type = data['type'];

  userAssert(
    isTagNameAllowed(type, win.context.tagName),
    'Embed type %s not allowed with tag %s',
    type,
    win.context.tagName
  );
  if (configCallback) {
    configCallback(data, data => {
      userAssert(data, 'Expected configuration to be passed as first argument');
      run(type, win, data);
    });
  } else {
    run(type, win, data);
  }
}

/**
 * Draws an embed, optionally synchronously, to the DOM.
 * @param {function(!Object, function(!Object))} opt_configCallback If provided
 *     will be invoked with two arguments:
 *     1. The configuration parameters supplied to this embed.
 *     2. A callback that MUST be called for rendering to proceed. It takes
 *        no arguments. Configuration is expected to be modified in-place.
 * @param {!Array<string>=} opt_allowed3pTypes List of advertising network
 *     types you expect.
 * @param {!Array<string>=} opt_allowedEmbeddingOrigins List of domain suffixes
 *     that are allowed to embed this frame.
 */
window.draw3p = function(
  opt_configCallback,
  opt_allowed3pTypes,
  opt_allowedEmbeddingOrigins
) {
  try {
    const location = getLocation();

    ensureFramed(window);
    validateParentOrigin(window, location);
    validateAllowedTypes(window, getEmbedType(), opt_allowed3pTypes);
    if (opt_allowedEmbeddingOrigins) {
      validateAllowedEmbeddingOrigins(window, opt_allowedEmbeddingOrigins);
    }
    window.context = new IntegrationAmpContext(window);
    manageWin(window);
    installEmbedStateListener();

    // Ugly type annotation is due to Event.prototype.data being blacklisted
    // and the compiler not being able to discern otherwise
    // TODO(alanorozco): Do this more elegantly once old impl is cleaned up.
    draw3p(
      window,
      /** @type {!IntegrationAmpContext} */ (window.context).data || {},
      opt_configCallback
    );

    window.context.bootstrapLoaded();
  } catch (e) {
    if (window.context && window.context.report3pError) {
      // window.context has initiated yet
      if (e.message && isUserErrorMessage(e.message)) {
        // report user error to parent window
        window.context.report3pError(e);
      }
    }

    const c = window.context || {mode: {test: false}};
    if (!c.mode.test) {
      lightweightErrorReport(e, c.canary);
      throw e;
    }
  }
};

/**
 * Throws if the current frame's parent origin is not equal to
 * the claimed origin.
 * Only check for browsers that support ancestorOrigins
 * @param {!Window} window
 * @param {!Location} parentLocation
 * @visibleForTesting
 */
export function validateParentOrigin(window, parentLocation) {
  const ancestors = window.location.ancestorOrigins;
  // Currently only webkit and blink based browsers support
  // ancestorOrigins. In that case we proceed but mark the origin
  // as non-validated.
  if (!ancestors || !ancestors.length) {
    return;
  }
  userAssert(
    ancestors[0] == parentLocation.origin,
    'Parent origin mismatch: %s, %s',
    ancestors[0],
    parentLocation.origin
  );
}

/**
 * Check that this iframe intended this particular ad type to run.
 * @param {!Window} window
 * @param {string} type 3p type
 * @param {!Array<string>|undefined} allowedTypes May be undefined.
 * @visibleForTesting
 */
export function validateAllowedTypes(window, type, allowedTypes) {
  const thirdPartyHost = parseUrlDeprecated(urls.thirdParty).hostname;

  // Everything allowed in default iframe.
  if (window.location.hostname == thirdPartyHost) {
    return;
  }
  if (urls.thirdPartyFrameRegex.test(window.location.hostname)) {
    return;
  }
  if (window.location.hostname == 'ads.localhost') {
    return;
  }
  if (defaultAllowedTypesInCustomFrame.indexOf(type) != -1) {
    return;
  }
  userAssert(
    allowedTypes && allowedTypes.indexOf(type) != -1,
    'Non-whitelisted 3p type for custom iframe: %s',
    type
  );
}

/**
 * Check that parent host name was whitelisted.
 * @param {!Window} window
 * @param {!Array<string>} allowedHostnames Suffixes of allowed host names.
 * @visibleForTesting
 */
export function validateAllowedEmbeddingOrigins(window, allowedHostnames) {
  if (!window.document.referrer) {
    throw new Error('Referrer expected: ' + window.location.href);
  }
  const ancestors = window.location.ancestorOrigins;
  // We prefer the unforgable ancestorOrigins, but referrer is better than
  // nothing.
  const ancestor = ancestors ? ancestors[0] : window.document.referrer;
  let {hostname} = parseUrlDeprecated(ancestor);
  if (isProxyOrigin(ancestor)) {
    // If we are on the cache domain, parse the source hostname from
    // the referrer. The referrer is used because it should be
    // trustable.
    hostname = parseUrlDeprecated(getSourceUrl(window.document.referrer))
      .hostname;
  }
  for (let i = 0; i < allowedHostnames.length; i++) {
    // Either the hostname is exactly as whitelisted…
    if (allowedHostnames[i] == hostname) {
      return;
    }
    // Or it ends in .$hostname (aka is a sub domain of the whitelisted domain.
    if (endsWith(hostname, '.' + allowedHostnames[i])) {
      return;
    }
  }
  throw new Error(
    'Invalid embedding hostname: ' + hostname + ' not in ' + allowedHostnames
  );
}

/**
 * Throws if this window is a top level window.
 * @param {!Window} window
 * @visibleForTesting
 */
export function ensureFramed(window) {
  if (window == window.parent) {
    throw new Error('Must be framed: ' + window.location.href);
  }
}

/**
 * Expects the fragment to contain JSON.
 * @param {string} fragment Value of location.fragment
 * @return {?JsonObject}
 * @visibleForTesting
 */
export function parseFragment(fragment) {
  try {
    let json = fragment.substr(1);
    // Some browser, notably Firefox produce an encoded version of the fragment
    // while most don't. Since we know how the string should start, this is easy
    // to detect.
    if (startsWith(json, '{%22')) {
      json = decodeURIComponent(json);
    }
    return /** @type {!JsonObject} */ (json ? parseJson(json) : dict());
  } catch (err) {
    return null;
  }
}

/**
 * Not all types of embeds are allowed to be used with all tag names on the
 * AMP side. This function checks whether the current usage is permissible.
 * @param {string} type
 * @param {string|undefined} tagName The tagName that was used to embed this
 *     3p-frame.
 * @return {boolean}
 */
export function isTagNameAllowed(type, tagName) {
  if (tagName == 'AMP-EMBED') {
    return !!AMP_EMBED_ALLOWED[type];
  }
  return true;
}

/**
 * Reports an error to the server. Must only be called once per page.
 * Not for use in event handlers.
 *
 * We don't use the default error in error.js handler because it has
 * too many deps for this small JS binary.
 *
 * @param {!Error} e
 * @param {boolean} isCanary
 */
function lightweightErrorReport(e, isCanary) {
  new Image().src =
    urls.errorReporting +
    '?3p=1&v=' +
    encodeURIComponent(internalRuntimeVersion()) +
    '&m=' +
    encodeURIComponent(e.message) +
    '&ca=' +
    (isCanary ? 1 : 0) +
    '&r=' +
    encodeURIComponent(document.referrer) +
    '&s=' +
    encodeURIComponent(e.stack || '');
}
