text: /**
   * Copyright 2018 The Subscribe with Google 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.
   */
  /** Version: 0.1.22.173 */
  /**
   * Copyright 2018 The Subscribe with Google 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.
   */
  
  // NOTE: Please don't edit this file directly!
  //   This document describes how to change i18n strings in swg-js: https://docs.google.com/document/d/1FMEKJ_TmjHhqON0krE4xhDbTEj0I0DnvzxMzB2cWUWA/edit?resourcekey=0-TQ7hPOzAD4hX8x9PfweGSg#heading=h.q9gi7t4h1tyj
  
  const I18N_STRINGS = {
    'SHOWCASE_REGWALL_TITLE': {
      'bn': 'Google-এ আরও অনেক কিছুর সুবিধা পান',
      'cs': 'Získejte s&nbsp;Googlem víc',
      'de': 'Immer gut informiert mit Google',
      'en': 'Get more with Google',
      'es': 'Disfruta de más artículos con Google',
      'es-ar': 'Disfruta más artículos con Google',
      'fr': 'Plus de contenus avec Google',
      'hi': 'Google की मदद से ज़्यादा मुफ़्त लेख पाएं',
      'it': 'Con Google puoi avere di più',
      'ja': 'Google からのプレゼント',
      'kn': 'Google ನಿಂದ ಹೆಚ್ಚಿನ ಪ್ರಯೋಜನ ಪಡೆಯಿರಿ',
      'ml': 'Google ഉപയോഗിച്ച് കൂടുതൽ പ്രയോജനങ്ങൾ നേടൂ',
      'mr': 'Google वापरून बरेच काही मिळवा',
      'nl': 'Krijg meer met Google',
      'pt-br': 'Veja mais com o Google',
      'pt-pt': 'Obtenha mais com a Google',
      'ta': 'Google மூலம் மேலும் பல கட்டுரைகளைப் படியுங்கள்',
      'te': 'Googleతో మరిన్ని ప్రయోజనాలను పొందండి',
    },
    'SHOWCASE_REGWALL_DESCRIPTION': {
      'bn': '<strong></strong>এই কন্টেন্ট অ্যাক্সেস করার জন্য সাধারণত পেমেন্ট করতে হয় কিন্তু Google আপনাকে এই নিবন্ধ ফ্রিতে অ্যাক্সেস করতে এবং সেইসাথে অনেক কিছু পেতে সাহায্য করছে। এই সুবিধা পাওয়ার জন্য Google অ্যাকাউন্ট ব্যবহার করে আপনাকে <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>-এ রেজিস্টার করতে হবে।',
      'cs': '<strong></strong>Tento obsah je obvykle zpoplatněn, ale pokud se do publikace <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> zaregistrujete pomocí účtu Google, získáte od Googlu přístup zdarma.',
      'de': '<strong></strong>Dieser Inhalt ist normalerweise kostenpflichtig. Google gewährt dir jedoch kostenlos Zugriff auf diesen Artikel und andere Inhalte, wenn du dich mit deinem Google-Konto bei <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> registrierst.',
      'en': '<strong></strong>This content usually requires payment, but Google is giving you free access to this article and more when you register with <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> using your Google Account.',
      'es': '<strong></strong>Normalmente, es necesario pagar para ver este contenido, pero Google te ofrece acceso gratuito a este y otros artículos si te registras en <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> con tu cuenta de Google.',
      'es-ar':
        '<strong></strong>Normalmente, es necesario pagar para ver este contenido, pero Google te ofrece acceso gratuito a este y otros artículos si te registras en <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> con tu Cuenta&nbsp;de&nbsp;Google.',
      'fr': '<strong></strong>Ce contenu est généralement payant, mais vous pouvez lire cet article et d\'autres contenus gratuitement grâce à Google en vous inscrivant sur <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> avec votre compte Google.',
      'hi': '<strong></strong>इस कॉन्टेंट को पढ़ने के लिए पैसे चुकाने पड़ते हैं, लेकिन आप Google की मदद से इस लेख और अन्य कॉन्टेंट को मुफ़्त में पढ़ सकते हैं. इसके लिए, आपको Google खाते का इस्तेमाल करके, <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> में रजिस्टर करना होगा.',
      'it': '<strong></strong>Generalmente questi contenuti sono a pagamento, ma Google ti offre accesso gratuito a questo articolo e ad altri articoli se ti registri a <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> usando il tuo Account Google.',
      'ja': '<strong></strong>通常、この記事をお読みいただくにはお支払いが必要ですが、お使いの Google アカウントで <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> に登録すると、この記事を無料でお読みいただけます。',
      'kn': '<strong></strong>ಸಾಮಾನ್ಯವಾಗಿ ಈ ವಿಷಯಕ್ಕಾಗಿ ಹಣ ಪಾವತಿಸಬೇಕಾಗುತ್ತದೆ, ಆದರೆ ನೀವು <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> ಗೆ ನಿಮ್ಮ Google ಖಾತೆಯ ಮೂಲಕ ನೋಂದಾಯಿಸಿಕೊಂಡಾಗ Google ಈ ಲೇಖನ ಮತ್ತು ಇನ್ನಷ್ಟು ವಿಷಯಗಳಿಗೆ ನಿಮಗೆ ಉಚಿತವಾದ ಪ್ರವೇಶವನ್ನು ನೀಡುತ್ತದೆ.',
      'ml': '<strong></strong>സാധാരണ ഈ ഉള്ളടക്കത്തിന് പണം നൽകേണ്ടതുണ്ട്, എന്നാൽ Google അക്കൗണ്ട് ഉപയോഗിച്ച് <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> എന്നതിൽ രജിസ്‌റ്റർ ചെയ്യുമ്പോൾ, ഈ ലേഖനത്തിലേക്കും മറ്റും Google നിങ്ങൾക്ക് സൗജന്യ ആക്‌സസ് നൽകുന്നു.',
      'mr': '<strong></strong>या आशयासाठी सामान्यतः पेमेंट आवश्यक असते पण तुम्ही तुमचे Google खाते वापरून <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> मध्ये नोंदणी करता तेव्हा, Google तुम्हाला या लेखाचा आणि आणखी बऱ्याच आशयाचा विनामूल्य ॲक्सेस देते.',
      'nl': '<strong></strong>Voor deze content moet je eigenlijk betalen. Maar Google geeft je kosteloos toegang tot dit artikel en andere content als je je registreert bij <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> via je Google-account.',
      'pt-br':
        '<strong></strong>Normalmente, é preciso pagar por este conteúdo. Porém, basta você se registrar na publicação <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> usando sua Conta do Google para ter acesso gratuito a esta matéria e muito mais.',
      'pt-pt':
        '<strong></strong>Geralmente, este conteúdo requer um pagamento, mas a Google concede-lhe acesso gratuito a este artigo e muito mais ao registar-se na publicação <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> com a sua Conta Google.',
      'ta': '<strong></strong>வழக்கமாக இந்த உள்ளடக்கத்தை வாசிக்க கட்டணம் செலுத்த வேண்டியிருக்கும். ஆனால் <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph> இல் உங்கள் Google கணக்கைப் பயன்படுத்திப் பதிவுசெய்யும்போது இந்தக் கட்டுரைக்கும் மேலும் பலவற்றுக்கும் Google இலவச அணுகலை வழங்குகிறது.',
      'te': '<strong></strong>ఈ కంటెంట్‌కు మీరు సాధారణంగా పేమెంట్ చేయాల్సి ఉంటుంది, కానీ మీరు Google ఖాతాను ఉపయోగించి <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>తో రిజిస్టర్ చేసుకున్నప్పుడు, ఈ వార్తా కథనానికి ఇంకా మరెన్నో వాటికి Google, ఉచిత యాక్సెస్‌ను ఇస్తుంది.',
    },
    'SHOWCASE_REGWALL_PUBLISHER_SIGN_IN_BUTTON': {
      'bn': 'আপনার কি আগে থেকেই অ্যাকাউন্ট আছে?',
      'cs': 'Už máte účet?',
      'de': 'Du hast bereits ein Konto?',
      'en': 'Already have an account?',
      'es': '¿Ya tienes una cuenta?',
      'es-ar': '¿Ya tienes una cuenta?',
      'fr': 'Vous avez déjà un compte&nbsp;?',
      'hi': 'क्या आपके पास पहले से कोई प्रकाशक खाता है?',
      'it': 'Hai già un account?',
      'ja': 'すでにアカウントをお持ちですか？',
      'kn': 'ಈಗಾಗಲೇ ಖಾತೆಯೊಂದನ್ನು ಹೊಂದಿದ್ದೀರಾ?',
      'ml': 'മുമ്പേ അക്കൗണ്ടുണ്ടോ?',
      'mr': 'आधीपासून खाते आहे?',
      'nl': 'Heb je al een account?',
      'pt-br': 'Já tem uma conta?',
      'pt-pt': 'Já tem uma conta?',
      'ta': 'ஏற்கெனவே கணக்கு உள்ளதா?',
      'te': 'ఇప్పటికే ఖాతా ఉందా?',
    },
    'SHOWCASE_REGWALL_GOOGLE_SIGN_IN_BUTTON': {
      'bn': 'Google দিয়ে সাইন-ইন করুন',
      'cs': 'Přihlásit se přes Google',
      'de': 'Über Google anmelden',
      'en': 'Sign in with Google',
      'es': 'Iniciar sesión con Google',
      'es-ar': 'Acceder con Google',
      'fr': 'Se connecter avec Google',
      'hi': 'Google से साइन इन करें',
      'it': 'Accedi con Google',
      'ja': 'Google でログイン',
      'kn': 'Google ಖಾತೆ ಬಳಸಿಕೊಂಡು ಸೈನ್ ಇನ್ ಮಾಡಿ',
      'ml': 'Google ഉപയോഗിച്ച് സൈൻ ഇൻ ചെയ്യുക',
      'mr': 'Google वापरून साइन इन करा',
      'nl': 'Inloggen met Google',
      'pt-br': 'Fazer login com o Google',
      'pt-pt': 'Iniciar sessão com o Google',
      'ta': 'Google மூலம் உள்நுழைக',
      'te': 'Googleతో సైన్ ఇన్ చేయండి',
    },
    'SHOWCASE_REGWALL_CASL': {
      'bn': 'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'cs': 'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'de': 'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'en': 'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'es': 'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'fr': 'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'hi': 'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'it': 'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'ja': 'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'kn': 'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'ml': 'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'mr': 'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'nl': 'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'pt-br':
        'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'pt-pt':
        'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'ta': 'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
      'te': 'Review <ph name="PUBLICATION"><ex>AP News</ex>{publication}</ph>\'s <ph name="LINK_START"><ex>&lt;a&gt;</ex></ph>Terms and CASL consent<ph name="LINK_END"><ex>&lt;/a&gt;</ex></ph>',
    },
  };
  
  /**
   * Copyright 2018 The Subscribe with Google 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.
   */
  /** @enum {number} */
  const AnalyticsEvent = {
    UNKNOWN: 0,
    IMPRESSION_PAYWALL: 1,
    IMPRESSION_AD: 2,
    IMPRESSION_OFFERS: 3,
    IMPRESSION_SUBSCRIBE_BUTTON: 4,
    IMPRESSION_SMARTBOX: 5,
    IMPRESSION_SWG_BUTTON: 6,
    IMPRESSION_CLICK_TO_SHOW_OFFERS: 7,
    IMPRESSION_CLICK_TO_SHOW_OFFERS_OR_ALREADY_SUBSCRIBED: 8,
    IMPRESSION_SUBSCRIPTION_COMPLETE: 9,
    IMPRESSION_ACCOUNT_CHANGED: 10,
    IMPRESSION_PAGE_LOAD: 11,
    IMPRESSION_LINK: 12,
    IMPRESSION_SAVE_SUBSCR_TO_GOOGLE: 13,
    IMPRESSION_GOOGLE_UPDATED: 14,
    IMPRESSION_SHOW_OFFERS_SMARTBOX: 15,
    IMPRESSION_SHOW_OFFERS_SWG_BUTTON: 16,
    IMPRESSION_SELECT_OFFER_SMARTBOX: 17,
    IMPRESSION_SELECT_OFFER_SWG_BUTTON: 18,
    IMPRESSION_SHOW_CONTRIBUTIONS_SWG_BUTTON: 19,
    IMPRESSION_SELECT_CONTRIBUTION_SWG_BUTTON: 20,
    IMPRESSION_METER_TOAST: 21,
    IMPRESSION_REGWALL: 22,
    IMPRESSION_SHOWCASE_REGWALL: 23,
    IMPRESSION_SWG_SUBSCRIPTION_MINI_PROMPT: 24,
    IMPRESSION_SWG_CONTRIBUTION_MINI_PROMPT: 25,
    IMPRESSION_CONTRIBUTION_OFFERS: 26,
    ACTION_SUBSCRIBE: 1000,
    ACTION_PAYMENT_COMPLETE: 1001,
    ACTION_ACCOUNT_CREATED: 1002,
    ACTION_ACCOUNT_ACKNOWLEDGED: 1003,
    ACTION_SUBSCRIPTIONS_LANDING_PAGE: 1004,
    ACTION_PAYMENT_FLOW_STARTED: 1005,
    ACTION_OFFER_SELECTED: 1006,
    ACTION_SWG_BUTTON_CLICK: 1007,
    ACTION_VIEW_OFFERS: 1008,
    ACTION_ALREADY_SUBSCRIBED: 1009,
    ACTION_NEW_DEFERRED_ACCOUNT: 1010,
    ACTION_LINK_CONTINUE: 1011,
    ACTION_LINK_CANCEL: 1012,
    ACTION_GOOGLE_UPDATED_CLOSE: 1013,
    ACTION_USER_CANCELED_PAYFLOW: 1014,
    ACTION_SAVE_SUBSCR_TO_GOOGLE_CONTINUE: 1015,
    ACTION_SAVE_SUBSCR_TO_GOOGLE_CANCEL: 1016,
    ACTION_SWG_BUTTON_SHOW_OFFERS_CLICK: 1017,
    ACTION_SWG_BUTTON_SELECT_OFFER_CLICK: 1018,
    ACTION_SWG_BUTTON_SHOW_CONTRIBUTIONS_CLICK: 1019,
    ACTION_SWG_BUTTON_SELECT_CONTRIBUTION_CLICK: 1020,
    ACTION_USER_CONSENT_DEFERRED_ACCOUNT: 1021,
    ACTION_USER_DENY_DEFERRED_ACCOUNT: 1022,
    ACTION_DEFERRED_ACCOUNT_REDIRECT: 1023,
    ACTION_GET_ENTITLEMENTS: 1024,
    ACTION_METER_TOAST_SUBSCRIBE_CLICK: 1025,
    ACTION_METER_TOAST_EXPANDED: 1026,
    ACTION_METER_TOAST_CLOSED_BY_ARTICLE_INTERACTION: 1027,
    ACTION_METER_TOAST_CLOSED_BY_SWIPE_DOWN: 1028,
    ACTION_METER_TOAST_CLOSED_BY_X_CLICKED: 1029,
    ACTION_SWG_SUBSCRIPTION_MINI_PROMPT_CLICK: 1030,
    ACTION_SWG_CONTRIBUTION_MINI_PROMPT_CLICK: 1031,
    ACTION_SWG_SUBSCRIPTION_MINI_PROMPT_CLOSE: 1032,
    ACTION_SWG_CONTRIBUTION_MINI_PROMPT_CLOSE: 1033,
    ACTION_CONTRIBUTION_OFFER_SELECTED: 1034,
    ACTION_SHOWCASE_REGWALL_GSI_CLICK: 1035,
    ACTION_SHOWCASE_REGWALL_EXISTING_ACCOUNT_CLICK: 1036,
    EVENT_PAYMENT_FAILED: 2000,
    EVENT_CUSTOM: 3000,
    EVENT_CONFIRM_TX_ID: 3001,
    EVENT_CHANGED_TX_ID: 3002,
    EVENT_GPAY_NO_TX_ID: 3003,
    EVENT_GPAY_CANNOT_CONFIRM_TX_ID: 3004,
    EVENT_GOOGLE_UPDATED: 3005,
    EVENT_NEW_TX_ID: 3006,
    EVENT_UNLOCKED_BY_SUBSCRIPTION: 3007,
    EVENT_UNLOCKED_BY_METER: 3008,
    EVENT_NO_ENTITLEMENTS: 3009,
    EVENT_HAS_METERING_ENTITLEMENTS: 3010,
    EVENT_OFFERED_METER: 3011,
    EVENT_UNLOCKED_FREE_PAGE: 3012,
    EVENT_SUBSCRIPTION_STATE: 4000,
  };
  /** @enum {number} */
  const EventOriginator = {
    UNKNOWN_CLIENT: 0,
    SWG_CLIENT: 1,
    AMP_CLIENT: 2,
    PROPENSITY_CLIENT: 3,
    SWG_SERVER: 4,
    PUBLISHER_CLIENT: 5,
    SHOWCASE_CLIENT: 6,
  };
  
  /**
   * Copyright 2018 The Subscribe with Google 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.
   */
  
  /**
   * Returns a map-like object.
   * If initial is provided, copies its own properties into the
   * newly created object.
   * @param {Object=} initial This should typically be an object literal.
   * @return {!Object}
   * @template T
   */
  function map(initial) {
    const obj = Object.create(null);
    if (initial) {
      Object.assign(obj, initial);
    }
    return obj;
  }
  
  /**
   * Implements `Array.find()` method that's not yet available in all browsers.
   *
   * @param {?Array<T>} array
   * @param {function(T, number, !Array<T>):boolean} predicate
   * @return {?T}
   * @template T
   */
  function findInArray(array, predicate) {
    if (!array) {
      return null;
    }
    const len = array.length || 0;
    if (len > 0) {
      for (let i = 0; i < len; i++) {
        const other = array[i];
        if (predicate(other, i, array)) {
          return other;
        }
      }
    }
    return null;
  }
  
  /**
   * Copyright 2018 The Subscribe with Google 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 This module declares JSON types as defined in the
   * {@link http://json.org/}.
   */
  
  /**
   * Simple wrapper around JSON.parse that casts the return value
   * to JsonObject.
   * Create a new wrapper if an array return value is desired.
   * @param {*} json JSON string to parse
   * @return {?JsonObject|undefined} May be extend to parse arrays.
   */
  function parseJson(json) {
    return /** @type {?JsonObject} */ (JSON.parse(/** @type {string} */ (json)));
  }
  
  /**
   * Copyright 2018 The Subscribe with Google 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.
   */
  
  /**
   * @param  {...*} var_args [description]
   */
  function warn(var_args) {
    console.warn.apply(console, arguments);
  }
  
  /**
   * Copyright 2018 The Subscribe with Google 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.
   */
  /* eslint-enable no-unused-vars */
  
  /** @enum {string} */
  const ShowcaseEvent = {
    // Events indicating content could potentially be unlocked
    EVENT_SHOWCASE_METER_OFFERED: 'EVENT_SHOWCASE_METER_OFFERED', // This event is only required if the user can choose not to use a publisher meter
  
    // Events indicating content was unlocked
    EVENT_SHOWCASE_UNLOCKED_BY_SUBSCRIPTION:
      'EVENT_SHOWCASE_UNLOCKED_BY_SUBSCRIPTION', // Publisher managed subscriptions only
    EVENT_SHOWCASE_UNLOCKED_BY_METER: 'EVENT_SHOWCASE_UNLOCKED_BY_METER', // Publisher managed meters only
    EVENT_SHOWCASE_UNLOCKED_FREE_PAGE: 'EVENT_SHOWCASE_UNLOCKED_FREE_PAGE', // When the article is free for any reason (lead article, etc)
  
    // Events indicating the user must take action to view content
    EVENT_SHOWCASE_NO_ENTITLEMENTS_REGWALL:
      'EVENT_SHOWCASE_NO_ENTITLEMENTS_REGWALL', // When the user must register (or log in) to view the article
  
    // Events indicating the user must subscribe to view content
    EVENT_SHOWCASE_INELIGIBLE_PAYWALL: 'EVENT_SHOWCASE_INELIGIBLE_PAYWALL', // When the user is not eligible for showcase entitlements
    EVENT_SHOWCASE_NO_ENTITLEMENTS_PAYWALL:
      'EVENT_SHOWCASE_NO_ENTITLEMENTS_PAYWALL', // When the user has no remaining showcase entitlements
  };
  
  /**
   * Copyright 2018 The Subscribe with Google 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.
   */
  
  /**
   * Cached a-tag to avoid memory allocation during URL parsing.
   * @type {HTMLAnchorElement}
   */
  let a;
  
  /**
   * We cached all parsed URLs. As of now there are no use cases
   * of AMP docs that would ever parse an actual large number of URLs,
   * but we often parse the same one over and over again.
   * @type {Object<string, !LocationDef>}
   */
  let cache;
  
  /**
   * Returns a Location-like object for the given URL. If it is relative,
   * the URL gets resolved.
   * Consider the returned object immutable. This is enforced during
   * testing by freezing the object.
   * @param {string} url
   * @return {!LocationDef}
   */
  function parseUrl(url) {
    if (!a) {
      a = /** @type {!HTMLAnchorElement} */ (self.document.createElement('a'));
      cache = self.UrlCache || (self.UrlCache = Object.create(null));
    }
  
    const fromCache = cache[url];
    if (fromCache) {
      return fromCache;
    }
  
    const info = parseUrlWithA(a, url);
  
    return (cache[url] = info);
  }
  
  /**
   * Returns a Location-like object for the given URL. If it is relative,
   * the URL gets resolved.
   * @param {!HTMLAnchorElement} a
   * @param {string} url
   * @return {!LocationDef}
   */
  function parseUrlWithA(a, url) {
    a.href = url;
  
    // IE11 doesn't provide full URL components when parsing relative URLs.
    // Assigning to itself again does the trick.
    if (!a.protocol) {
      a.href = a.href;
    }
  
    /** @type {!LocationDef} */
    const info = {
      href: a.href,
      protocol: a.protocol,
      host: a.host,
      hostname: a.hostname,
      port: a.port == '0' ? '' : a.port,
      pathname: a.pathname,
      search: a.search,
      hash: a.hash,
      origin: '', // Set below.
    };
  
    // Some IE11 specific polyfills.
    // 1) IE11 strips out the leading '/' in the pathname.
    if (info.pathname[0] !== '/') {
      info.pathname = '/' + info.pathname;
    }
  
    // 2) For URLs with implicit ports, IE11 parses to default ports while
    // other browsers leave the port field empty.
    if (
      (info.protocol == 'http:' && info.port == 80) ||
      (info.protocol == 'https:' && info.port == 443)
    ) {
      info.port = '';
      info.host = info.hostname;
    }
  
    // For data URI a.origin is equal to the string 'null' which is not useful.
    // We instead return the actual origin which is the full URL.
    if (a.origin && a.origin != 'null') {
      info.origin = a.origin;
    } else if (info.protocol == 'data:' || !info.host) {
      info.origin = info.href;
    } else {
      info.origin = info.protocol + '//' + info.host;
    }
    return info;
  }
  
  /**
   * Parses and builds Object of URL query string.
   * @param {string} query The URL query string.
   * @return {!Object<string, string>}
   */
  function parseQueryString(query) {
    if (!query) {
      return {};
    }
    return (/^[?#]/.test(query) ? query.slice(1) : query)
      .split('&')
      .reduce((params, param) => {
        const item = param.split('=');
        try {
          const key = decodeURIComponent(item[0] || '');
          const value = decodeURIComponent(item[1] || '');
          if (key) {
            params[key] = value;
          }
        } catch (err) {
          // eslint-disable-next-line no-console
          warn(`SwG could not parse a URL query param: ${item[0]}`);
        }
        return params;
      }, {});
  }
  
  /**
   * Adds a parameter to a query string.
   * @param {string} url
   * @param {string} param
   * @param {string} value
   * @return {string}
   */
  function addQueryParam(url, param, value) {
    const queryIndex = url.indexOf('?');
    const fragmentIndex = url.indexOf('#');
    let fragment = '';
    if (fragmentIndex != -1) {
      fragment = url.substring(fragmentIndex);
      url = url.substring(0, fragmentIndex);
    }
    if (queryIndex == -1) {
      url += '?';
    } else if (queryIndex < url.length - 1) {
      url += '&';
    }
    url += encodeURIComponent(param) + '=' + encodeURIComponent(value);
    return url + fragment;
  }
  
  parseUrl(self.window.location.href);
  parseUrl(self.document.referrer);
  
  /**
   * Copyright 2018 The Subscribe with Google 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.
   */
  
  /** English is the default language. */
  const DEFAULT_LANGUAGE_CODE = 'en';
  
  /**
   * Gets a message for a given language code, from a map of messages.
   * @param {!Object<string, string>} map
   * @param {?string|?Element} languageCodeOrElement
   * @return {?string}
   */
  function msg(map, languageCodeOrElement) {
    const defaultMsg = map[DEFAULT_LANGUAGE_CODE];
  
    // Verify params.
    if (typeof map !== 'object' || !languageCodeOrElement) {
      return defaultMsg;
    }
  
    // Get language code.
    let languageCode =
      typeof languageCodeOrElement === 'string'
        ? languageCodeOrElement
        : getLanguageCodeFromElement(languageCodeOrElement);
  
    // Normalize language code.
    languageCode = languageCode.toLowerCase();
    languageCode = languageCode.replace(/_/g, '-');
  
    // Search for a message matching the language code.
    // If a message can't be found, try again with a less specific language code.
    const languageCodeSegments = languageCode.split('-');
    while (languageCodeSegments.length) {
      const key = languageCodeSegments.join('-');
      if (key in map) {
        return map[key];
      }
  
      // Simplify language code.
      // Ex: "en-US-SF" => "en-US"
      languageCodeSegments.pop();
    }
  
    // There was an attempt.
    return defaultMsg;
  }
  
  /**
   * Gets a language code (ex: "en-US") from a given Element.
   * @param {!Element} element
   * @return {string}
   */
  function getLanguageCodeFromElement(element) {
    if (element.lang) {
      // Get language from element itself.
      return element.lang;
    }
  
    if (element.ownerDocument && element.ownerDocument.documentElement.lang) {
      // Get language from element's document.
      return element.ownerDocument.documentElement.lang;
    }
  
    // There was an attempt.
    return DEFAULT_LANGUAGE_CODE;
  }
  
  /**
   * Copyright 2018 The Subscribe with Google 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.
   */
  
  /**
   * Polyfill for String.prototype.startsWith.
   * @param {string} string
   * @param {string} prefix
   * @return {boolean}
   */
  function startsWith(string, prefix) {
    if (prefix.length > string.length) {
      return false;
    }
    return string.lastIndexOf(prefix, 0) == 0;
  }
  
  /**
   * Copyright 2018 The Subscribe with Google 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.
   */
  
  /** @type {Object<string, string>} */
  let propertyNameCache;
  
  /** @const {!Array<string>} */
  const vendorPrefixes = ['Webkit', 'webkit', 'Moz', 'moz', 'ms', 'O', 'o'];
  
  /**
   * @param {string} camelCase camel cased string
   * @return {string} title cased string
   */
  function camelCaseToTitleCase(camelCase) {
    return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
  }
  
  /**
   * Checks the style if a prefixed version of a property exists and returns
   * it or returns an empty string.
   * @private
   * @param {!Object} style
   * @param {string} titleCase the title case version of a css property name
   * @return {string} the prefixed property name or null.
   */
  function getVendorJsPropertyName_(style, titleCase) {
    for (let i = 0; i < vendorPrefixes.length; i++) {
      const propertyName = vendorPrefixes[i] + titleCase;
      if (style[propertyName] !== undefined) {
        return propertyName;
      }
    }
    return '';
  }
  
  /**
   * Returns the possibly prefixed JavaScript property name of a style property
   * (ex. WebkitTransitionDuration) given a camelCase'd version of the property
   * (ex. transitionDuration).
   * @param {!Object} style
   * @param {string} camelCase the camel cased version of a css property name
   * @param {boolean=} bypassCache bypass the memoized cache of property
   *   mapping
   * @return {string}
   */
  function getVendorJsPropertyName(style, camelCase, bypassCache) {
    if (startsWith(camelCase, '--')) {
      // CSS vars are returned as is.
      return camelCase;
    }
    if (!propertyNameCache) {
      propertyNameCache = map();
    }
    let propertyName = propertyNameCache[camelCase];
    if (!propertyName || bypassCache) {
      propertyName = camelCase;
      if (style[camelCase] === undefined) {
        const titleCase = camelCaseToTitleCase(camelCase);
        const prefixedPropertyName = getVendorJsPropertyName_(style, titleCase);
  
        if (style[prefixedPropertyName] !== undefined) {
          propertyName = prefixedPropertyName;
        }
      }
      if (!bypassCache) {
        propertyNameCache[camelCase] = propertyName;
      }
    }
    return propertyName;
  }
  
  /**
   * Sets the CSS styles of the specified element with !important. The styles
   * are specified as a map from CSS property names to their values.
   * @param {!Element} element
   * @param {!Object<string, string|number>} styles
   */
  function setImportantStyles(element, styles) {
    for (const k in styles) {
      element.style.setProperty(
        getVendorJsPropertyName(styles, k),
        styles[k].toString(),
        'important'
      );
    }
  }
  
  /**
   * Copyright 2019 The Subscribe with Google 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.
   */
  
  /** @const {!Object<string,?Array<AnalyticsEvent>>} */
  const ShowcaseEvents = {
    // Events related to content being potentially unlockable
    [ShowcaseEvent.EVENT_SHOWCASE_METER_OFFERED]: [
      AnalyticsEvent.EVENT_HAS_METERING_ENTITLEMENTS,
      AnalyticsEvent.EVENT_OFFERED_METER,
    ],
  
    // Events related to content being unlocked
    [ShowcaseEvent.EVENT_SHOWCASE_UNLOCKED_BY_SUBSCRIPTION]: [
      AnalyticsEvent.EVENT_UNLOCKED_BY_SUBSCRIPTION,
    ],
    [ShowcaseEvent.EVENT_SHOWCASE_UNLOCKED_BY_METER]: [
      AnalyticsEvent.EVENT_HAS_METERING_ENTITLEMENTS,
      AnalyticsEvent.EVENT_UNLOCKED_BY_METER,
    ],
    [ShowcaseEvent.EVENT_SHOWCASE_UNLOCKED_FREE_PAGE]: [
      AnalyticsEvent.EVENT_UNLOCKED_FREE_PAGE,
    ],
  
    // Events requiring user action to unlock content
    [ShowcaseEvent.EVENT_SHOWCASE_NO_ENTITLEMENTS_REGWALL]: [
      AnalyticsEvent.EVENT_NO_ENTITLEMENTS,
      AnalyticsEvent.IMPRESSION_REGWALL,
      AnalyticsEvent.IMPRESSION_SHOWCASE_REGWALL,
    ],
  
    // Events requiring subscription to unlock content
    [ShowcaseEvent.EVENT_SHOWCASE_NO_ENTITLEMENTS_PAYWALL]: [
      AnalyticsEvent.EVENT_NO_ENTITLEMENTS,
      AnalyticsEvent.IMPRESSION_PAYWALL,
    ],
    [ShowcaseEvent.EVENT_SHOWCASE_INELIGIBLE_PAYWALL]: [
      // TODO(b/181690059): Create showcase ineligible AnalyticsEvent
      AnalyticsEvent.IMPRESSION_PAYWALL,
    ],
  };
  
  /**
   * Converts a publisher entitlement event enum into an array analytics events.
   * @param {!ShowcaseEvent} event
   * @returns {!Array<AnalyticsEvent>}
   */
  function showcaseEventToAnalyticsEvents(event) {
    return ShowcaseEvents[event] || [];
  }
  
  /**
   * Copyright 2020 The Subscribe with Google 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.
   */
  
  /** Stamp for post messages. */
  const POST_MESSAGE_STAMP = 'swg-gaa-post-message-stamp';
  
  /** Introduction command for post messages. */
  const POST_MESSAGE_COMMAND_INTRODUCTION = 'introduction';
  
  /** User command for post messages. */
  const POST_MESSAGE_COMMAND_USER = 'user';
  
  /** Error command for post messages. */
  const POST_MESSAGE_COMMAND_ERROR = 'error';
  
  /** ID for the Google Sign-In iframe element. */
  const GOOGLE_SIGN_IN_IFRAME_ID = 'swg-google-sign-in-iframe';
  
  /** ID for the Google Sign-In button element. */
  const GOOGLE_SIGN_IN_BUTTON_ID = 'swg-google-sign-in-button';
  
  /** ID for the Publisher sign-in button element. */
  const PUBLISHER_SIGN_IN_BUTTON_ID = 'swg-publisher-sign-in-button';
  
  /** ID for the Regwall container element. */
  const REGWALL_CONTAINER_ID = 'swg-regwall-container';
  
  /** ID for the Regwall dialog element. */
  const REGWALL_DIALOG_ID = 'swg-regwall-dialog';
  
  /** ID for the Regwall title element. */
  const REGWALL_TITLE_ID = 'swg-regwall-title';
  
  /**
   * HTML for the metering regwall dialog, where users can sign in with Google.
   * The script creates a dialog based on this HTML.
   *
   * The HTML includes an iframe that loads the Google Sign-In button.
   * This iframe can live on a different origin.
   */
  const REGWALL_HTML = `
  <style>
    .gaa-metering-regwall--dialog-spacer,
    .gaa-metering-regwall--dialog,
    .gaa-metering-regwall--logo,
    .gaa-metering-regwall--title,
    .gaa-metering-regwall--description,
    .gaa-metering-regwall--description strong,
    .gaa-metering-regwall--iframe,
    .gaa-metering-regwall--casl,
    .gaa-metering-regwall--publisher-no-thanks-button {
      all: initial;
      box-sizing: border-box;
      font-family: Roboto, arial, sans-serif;
    }
  
    .gaa-metering-regwall--dialog-spacer {
      background: linear-gradient(0, #808080, transparent);
      bottom: 0;
      display: block;
      position: fixed;
      width: 100%;
    }
  
    @keyframes slideUp {
      from {transform: translate(0, 200px);}
      to {transform: translate(0, 0);}
    }
  
    .gaa-metering-regwall--dialog {
      animation: slideUp 0.5s;
      background: white;
      border-radius: 12px 12px 0 0;
      box-shadow: 0px -2px 6px rgba(0, 0, 0, 0.3);
      display: block;
      margin: 0 auto;
      max-width: 100%;
      padding: 24px 20px;
      pointer-events: auto;
      width: 410px;
    }
  
    .gaa-metering-regwall--logo {
      display: block;
      margin: 0 auto 24px;
    }
  
    .gaa-metering-regwall--title {
      color: #000;
      display: block;
      font-size: 16px;
      margin: 0 0 8px;
    }
    
    .gaa-metering-regwall--description {
      color: #646464;
      display: block;
      font-size: 14px;
      line-height: 19px;
      margin: 0 0 30px;
    }
  
    .gaa-metering-regwall--description strong {
      color: #646464;
      font-size: 14px;
      line-height: 19px;
      font-weight: bold;
    }
  
    .gaa-metering-regwall--iframe {
      border: none;
      display: block;
      height: 36px;
      margin: 0 0 30px;
      width: 100%;
    }
  
    .gaa-metering-regwall--casl {
      color: #646464;
      display: block;
      font-size: 12px;
      text-align: center;
      margin: -16px auto 32px;
    }
  
    .gaa-metering-regwall--casl a {
      color: #1967d2;
    }
  
    .gaa-metering-regwall--line {
      background-color: #ddd;
      display: block;
      height: 1px;
      margin: 0 0 24px;
    }
  
    .gaa-metering-regwall--publisher-sign-in-button,
    .gaa-metering-regwall--publisher-no-thanks-button {
      color: #1967d2;
      display: block;
      cursor: pointer;
      font-size: 12px;
    }
  
    .gaa-metering-regwall--publisher-sign-in-button {
    }
  
    .gaa-metering-regwall--publisher-no-thanks-button {
      display: none;
      float: right;
    }
  
    .gaa-metering-regwall--google-sign-in-button {
      height: 36px;
      margin: 0 auto 30px;
    }
  
    .gaa-metering-regwall--google-sign-in-button > div {
      animation: swgGoogleSignInButtonfadeIn 0.32s;
    }
  
    @keyframes swgGoogleSignInButtonfadeIn {
      from {
        opacity: 0;
      }
      to {
        opacity: 1;
      }
    }
  </style>
  
  <div class="gaa-metering-regwall--dialog-spacer">
    <div role="dialog" aria-modal="true" class="gaa-metering-regwall--dialog" id="${REGWALL_DIALOG_ID}" aria-labelledby="${REGWALL_TITLE_ID}">
      <img alt="Google" class="gaa-metering-regwall--logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDc0IDI0Ij48cGF0aCBmaWxsPSIjNDI4NUY0IiBkPSJNOS4yNCA4LjE5djIuNDZoNS44OGMtLjE4IDEuMzgtLjY0IDIuMzktMS4zNCAzLjEtLjg2Ljg2LTIuMiAxLjgtNC41NCAxLjgtMy42MiAwLTYuNDUtMi45Mi02LjQ1LTYuNTRzMi44My02LjU0IDYuNDUtNi41NGMxLjk1IDAgMy4zOC43NyA0LjQzIDEuNzZMMTUuNCAyLjVDMTMuOTQgMS4wOCAxMS45OCAwIDkuMjQgMCA0LjI4IDAgLjExIDQuMDQuMTEgOXM0LjE3IDkgOS4xMyA5YzIuNjggMCA0LjctLjg4IDYuMjgtMi41MiAxLjYyLTEuNjIgMi4xMy0zLjkxIDIuMTMtNS43NSAwLS41Ny0uMDQtMS4xLS4xMy0xLjU0SDkuMjR6Ii8+PHBhdGggZmlsbD0iI0VBNDMzNSIgZD0iTTI1IDYuMTljLTMuMjEgMC01LjgzIDIuNDQtNS44MyA1LjgxIDAgMy4zNCAyLjYyIDUuODEgNS44MyA1LjgxczUuODMtMi40NiA1LjgzLTUuODFjMC0zLjM3LTIuNjItNS44MS01LjgzLTUuODF6bTAgOS4zM2MtMS43NiAwLTMuMjgtMS40NS0zLjI4LTMuNTIgMC0yLjA5IDEuNTItMy41MiAzLjI4LTMuNTJzMy4yOCAxLjQzIDMuMjggMy41MmMwIDIuMDctMS41MiAzLjUyLTMuMjggMy41MnoiLz48cGF0aCBmaWxsPSIjNDI4NUY0IiBkPSJNNTMuNTggNy40OWgtLjA5Yy0uNTctLjY4LTEuNjctMS4zLTMuMDYtMS4zQzQ3LjUzIDYuMTkgNDUgOC43MiA0NSAxMmMwIDMuMjYgMi41MyA1LjgxIDUuNDMgNS44MSAxLjM5IDAgMi40OS0uNjIgMy4wNi0xLjMyaC4wOXYuODFjMCAyLjIyLTEuMTkgMy40MS0zLjEgMy40MS0xLjU2IDAtMi41My0xLjEyLTIuOTMtMi4wN2wtMi4yMi45MmMuNjQgMS41NCAyLjMzIDMuNDMgNS4xNSAzLjQzIDIuOTkgMCA1LjUyLTEuNzYgNS41Mi02LjA1VjYuNDloLTIuNDJ2MXptLTIuOTMgOC4wM2MtMS43NiAwLTMuMS0xLjUtMy4xLTMuNTIgMC0yLjA1IDEuMzQtMy41MiAzLjEtMy41MiAxLjc0IDAgMy4xIDEuNSAzLjEgMy41NC4wMSAyLjAzLTEuMzYgMy41LTMuMSAzLjV6Ii8+PHBhdGggZmlsbD0iI0ZCQkMwNSIgZD0iTTM4IDYuMTljLTMuMjEgMC01LjgzIDIuNDQtNS44MyA1LjgxIDAgMy4zNCAyLjYyIDUuODEgNS44MyA1LjgxczUuODMtMi40NiA1LjgzLTUuODFjMC0zLjM3LTIuNjItNS44MS01LjgzLTUuODF6bTAgOS4zM2MtMS43NiAwLTMuMjgtMS40NS0zLjI4LTMuNTIgMC0yLjA5IDEuNTItMy41MiAzLjI4LTMuNTJzMy4yOCAxLjQzIDMuMjggMy41MmMwIDIuMDctMS41MiAzLjUyLTMuMjggMy41MnoiLz48cGF0aCBmaWxsPSIjMzRBODUzIiBkPSJNNTggLjI0aDIuNTF2MTcuNTdINTh6Ii8+PHBhdGggZmlsbD0iI0VBNDMzNSIgZD0iTTY4LjI2IDE1LjUyYy0xLjMgMC0yLjIyLS41OS0yLjgyLTEuNzZsNy43Ny0zLjIxLS4yNi0uNjZjLS40OC0xLjMtMS45Ni0zLjctNC45Ny0zLjctMi45OSAwLTUuNDggMi4zNS01LjQ4IDUuODEgMCAzLjI2IDIuNDYgNS44MSA1Ljc2IDUuODEgMi42NiAwIDQuMi0xLjYzIDQuODQtMi41N2wtMS45OC0xLjMyYy0uNjYuOTYtMS41NiAxLjYtMi44NiAxLjZ6bS0uMTgtNy4xNWMxLjAzIDAgMS45MS41MyAyLjIgMS4yOGwtNS4yNSAyLjE3YzAtMi40NCAxLjczLTMuNDUgMy4wNS0zLjQ1eiIvPjwvc3ZnPg==" />
  
      <div class="gaa-metering-regwall--title" id="${REGWALL_TITLE_ID}" tabindex="0">$SHOWCASE_REGWALL_TITLE$</div>
  
      <div class="gaa-metering-regwall--description">
        $SHOWCASE_REGWALL_DESCRIPTION$
      </div>
  
      <iframe
          id="${GOOGLE_SIGN_IN_IFRAME_ID}"
          class="gaa-metering-regwall--iframe"
          src="$iframeUrl$">
      </iframe>
  
      $SHOWCASE_REGWALL_CASL$
  
      <div class="gaa-metering-regwall--line"></div>
  
      <a
          id="${PUBLISHER_SIGN_IN_BUTTON_ID}"
          class="gaa-metering-regwall--publisher-sign-in-button"
          tabindex="0"
          href="#">
        $SHOWCASE_REGWALL_PUBLISHER_SIGN_IN_BUTTON$
      </a>
    </div>
  </div>
  `;
  
  /**
   * HTML for the CASL blurb.
   * CASL stands for Canadian Anti-Spam Law.
   */
  const CASL_HTML = `
  <div class="gaa-metering-regwall--casl">
    $SHOWCASE_REGWALL_CASL$
  </div>
  `;
  
  /** Styles for the Google Sign-In button iframe. */
  const GOOGLE_SIGN_IN_IFRAME_STYLES = `
  body {
    margin: 0;
    overflow: hidden;
  }
  #${GOOGLE_SIGN_IN_BUTTON_ID} {
    margin: 0 auto;
  }
  #${GOOGLE_SIGN_IN_BUTTON_ID} > div {
    animation: fadeIn 0.32s;
  }
  @keyframes fadeIn {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }
  #${GOOGLE_SIGN_IN_BUTTON_ID} .abcRioButton.abcRioButtonBlue {
    background-color: #1A73E8;
    box-shadow: none;
    -webkit-box-shadow: none;
    border-radius: 4px;
    width: 100% !important;
  }
  #${GOOGLE_SIGN_IN_BUTTON_ID} .abcRioButton.abcRioButtonBlue .abcRioButtonIcon {
    display: none;
  }
  /** Hides default "Sign in with Google" text. */
  #${GOOGLE_SIGN_IN_BUTTON_ID} .abcRioButton.abcRioButtonBlue .abcRioButtonContents span[id^=not_signed_] {
    font-size: 0 !important;
  }
  /** Renders localized "Sign in with Google" text instead. */
  #${GOOGLE_SIGN_IN_BUTTON_ID} .abcRioButton.abcRioButtonBlue .abcRioButtonContents span[id^=not_signed_]::before {
    content: '$SHOWCASE_REGWALL_GOOGLE_SIGN_IN_BUTTON$';
    font-size: 15px;
  }
  `;
  
  /**
   * User object that Publisher JS receives after users sign in.
   * @typedef {{
   *   idToken: string,
   *   name: string,
   *   givenName: string,
   *   familyName: string,
   *   imageUrl: string,
   *   email: string,
   * }} GaaUserDef
   */
  let GaaUserDef;
  
  /**
   * GoogleUser object that Google Sign-In returns after users sign in.
   * https://developers.google.com/identity/sign-in/web/reference#googleusergetbasicprofile
   * @typedef {{
   *   getAuthResponse: function(): {id_token: string},
   *   getBasicProfile: function(): {
   *     getName: function(): string,
   *     getGivenName: function(): string,
   *     getFamilyName: function(): string,
   *     getImageUrl: function(): string,
   *     getEmail: function(): string,
   *   },
   * }} GoogleUserDef
   */
  let GoogleUserDef;
  
  /**
   * Returns true if the query string contains fresh Google Article Access (GAA) params.
   * @param {string} queryString
   * @param {boolean} allowAllAccessTypes
   * @return {boolean}
   */
  function queryStringHasFreshGaaParams(
    queryString,
    allowAllAccessTypes = false
  ) {
    const params = parseQueryString(queryString);
  
    // Verify GAA params exist.
    if (
      !params['gaa_at'] ||
      !params['gaa_n'] ||
      !params['gaa_sig'] ||
      !params['gaa_ts']
    ) {
      return false;
    }
  
    if (!allowAllAccessTypes) {
      // Verify access type.
      const noAccess = params['gaa_at'] === 'na';
      if (noAccess) {
        return false;
      }
    }
  
    // Verify timestamp isn't stale.
    const expirationTimestamp = parseInt(params['gaa_ts'], 16);
    const currentTimestamp = Date.now() / 1000;
    if (expirationTimestamp < currentTimestamp) {
      return false;
    }
  
    return true;
  }
  
  /** Renders Google Article Access (GAA) Metering Regwall. */
  class GaaMeteringRegwall {
    /**
     * Returns a promise for a Google Sign-In user object.
     * https://developers.google.com/identity/sign-in/web/reference#googleusergetbasicprofile
     *
     * This method opens a metering regwall dialog,
     * where users can sign in with Google.
     * @nocollapse
     * @param {{ iframeUrl: string, caslUrl: string }} params
     * @return {!Promise<!GaaUserDef>}
     */
    static show({iframeUrl, caslUrl}) {
      const queryString = GaaUtils.getQueryString();
      if (!queryStringHasFreshGaaParams(queryString)) {
        const errorMessage =
          '[swg-gaa.js:GaaMeteringRegwall.show]: URL needs fresh GAA params.';
        warn(errorMessage);
        return Promise.reject(errorMessage);
      }
  
      logEvent(ShowcaseEvent.EVENT_SHOWCASE_NO_ENTITLEMENTS_REGWALL);
  
      GaaMeteringRegwall.render_({iframeUrl, caslUrl});
      GaaMeteringRegwall.sendIntroMessageToGsiIframe_({iframeUrl});
      return GaaMeteringRegwall.getGaaUser_()
        .then((gaaUser) => {
          GaaMeteringRegwall.remove_();
          return gaaUser;
        })
        .catch((err) => {
          // Close the Regwall, since the flow failed.
          GaaMeteringRegwall.remove_();
  
          // Rethrow error.
          throw err;
        });
    }
  
    /**
     * Signs out of Google Sign-In.
     * This is useful for developers who are testing their
     * SwG integrations.
     * @nocollapse
     * @return {!Promise}
     */
    static signOut() {
      return configureGoogleSignIn().then(() =>
        self.gapi.auth2.getAuthInstance().signOut()
      );
    }
  
    /**
     * Renders the Regwall.
     * @private
     * @nocollapse
     * @param {{ iframeUrl: string, caslUrl: string }} params
     */
    static render_({iframeUrl, caslUrl}) {
      const languageCode = getLanguageCodeFromElement(self.document.body);
      const publisherName = GaaMeteringRegwall.getPublisherNameFromPageConfig_();
      const placeholderPatternForPublication = /<ph name="PUBLICATION".+?\/ph>/g;
      const placeholderPatternForLinkStart = /<ph name="LINK_START".+?\/ph>/g;
      const placeholderPatternForLinkEnd = /<ph name="LINK_END".+?\/ph>/g;
  
      // Tell the iframe which language to render.
      iframeUrl = addQueryParam(iframeUrl, 'lang', languageCode);
  
      // Create and style container element.
      const containerEl = /** @type {!HTMLDivElement} */ (
        self.document.createElement('div')
      );
      containerEl.id = REGWALL_CONTAINER_ID;
      setImportantStyles(containerEl, {
        'all': 'unset',
        'background-color': 'rgba(32, 33, 36, 0.6)',
        'border': 'none',
        'bottom': '0',
        'height': '100%',
        'left': '0',
        'opacity': '0',
        'pointer-events': 'none',
        'position': 'fixed',
        'right': '0',
        'transition': 'opacity 0.5s',
        'top': '0',
        'width': '100%',
        'z-index': 2147483646,
      });
  
      // Optionally include CASL HTML.
      let caslHtml = '';
      if (caslUrl) {
        caslHtml = CASL_HTML.replace(
          '$SHOWCASE_REGWALL_CASL$',
          msg(I18N_STRINGS['SHOWCASE_REGWALL_CASL'], languageCode)
        )
          // Update link.
          .replace(
            placeholderPatternForLinkStart,
            `<a href="${encodeURI(caslUrl)}" target="_blank">`
          )
          .replace(placeholderPatternForLinkEnd, '</a>')
          // Update publisher name.
          .replace(
            placeholderPatternForPublication,
            `<strong>${publisherName}</strong>`
          );
      }
  
      // Prepare HTML.
      containerEl./*OK*/ innerHTML = REGWALL_HTML.replace(
        '$iframeUrl$',
        iframeUrl
      )
        .replace(
          '$SHOWCASE_REGWALL_TITLE$',
          msg(I18N_STRINGS['SHOWCASE_REGWALL_TITLE'], languageCode)
        )
        .replace(
          '$SHOWCASE_REGWALL_DESCRIPTION$',
          msg(I18N_STRINGS['SHOWCASE_REGWALL_DESCRIPTION'], languageCode)
            // Update publisher name.
            .replace(placeholderPatternForPublication, publisherName)
        )
        .replace(
          '$SHOWCASE_REGWALL_PUBLISHER_SIGN_IN_BUTTON$',
          msg(
            I18N_STRINGS['SHOWCASE_REGWALL_PUBLISHER_SIGN_IN_BUTTON'],
            languageCode
          )
        )
        .replace('$SHOWCASE_REGWALL_CASL$', caslHtml);
  
      // Add container to DOM.
      self.document.body.appendChild(containerEl);
  
      // Trigger a fade-in transition.
      /** @suppress {suspiciousCode} */
      containerEl.offsetHeight; // Trigger a repaint (to prepare the CSS transition).
      setImportantStyles(containerEl, {'opacity': 1});
  
      // Listen for clicks.
      GaaMeteringRegwall.addClickListenerOnPublisherSignInButton_();
  
      // Focus on the title after the dialog animates in.
      // This helps people using screenreaders.
      const dialogEl = self.document.getElementById(REGWALL_DIALOG_ID);
      dialogEl.addEventListener('animationend', () => {
        const titleEl = self.document.getElementById(REGWALL_TITLE_ID);
        titleEl.focus();
      });
    }
  
    /**
     * Gets publisher name from page config.
     * @private
     * @nocollapse
     * @return {string}
     */
    static getPublisherNameFromPageConfig_() {
      const ldJsonElements = self.document.querySelectorAll(
        'script[type="application/ld+json"]'
      );
  
      for (let i = 0; i < ldJsonElements.length; i++) {
        const ldJsonElement = ldJsonElements[i];
        let ldJson = /** @type {*} */ (parseJson(ldJsonElement.textContent));
  
        if (!Array.isArray(ldJson)) {
          ldJson = [ldJson];
        }
  
        const publisherName = findInArray(
          ldJson,
          (entry) => entry?.publisher?.name
        )?.publisher.name;
  
        if (publisherName) {
          return publisherName;
        }
      }
  
      throw new Error('Article needs JSON-LD with a publisher name.');
    }
  
    /**
     * Adds a click listener on the publisher sign-in button.
     * @private
     * @nocollapse
     */
    static addClickListenerOnPublisherSignInButton_() {
      self.document
        .getElementById(PUBLISHER_SIGN_IN_BUTTON_ID)
        .addEventListener('click', (e) => {
          e.preventDefault();
  
          callSwg((swg) => swg.triggerLoginRequest({linkRequested: false}));
        });
    }
  
    /**
     * Returns the GAA user, after the user signs in.
     * @private
     * @nocollapse
     * @return {!Promise<!GoogleUserDef>}
     */
    static getGaaUser_() {
      // Listen for GAA user.
      return new Promise((resolve, reject) => {
        self.addEventListener('message', (e) => {
          if (e.data.stamp === POST_MESSAGE_STAMP) {
            if (e.data.command === POST_MESSAGE_COMMAND_USER) {
              // Pass along GAA user.
              resolve(e.data.gaaUser);
            }
  
            if (e.data.command === POST_MESSAGE_COMMAND_ERROR) {
              // Reject promise due to Google Sign-In error.
              reject('Google Sign-In could not render');
            }
          }
        });
      });
    }
  
    /**
     * Sends intro post message to Google Sign-In iframe.
     * @private
     * @nocollapse
     * @param {{ iframeUrl: string }} params
     */
    static sendIntroMessageToGsiIframe_({iframeUrl}) {
      // Introduce this window to the publisher's Google Sign-In iframe.
      // This lets the iframe send post messages back to this window.
      // Without the introduction, the iframe wouldn't have a reference to this window.
      const googleSignInIframe = /** @type {!HTMLIFrameElement} */ (
        self.document.getElementById(GOOGLE_SIGN_IN_IFRAME_ID)
      );
      googleSignInIframe.onload = () => {
        googleSignInIframe.contentWindow.postMessage(
          {
            stamp: POST_MESSAGE_STAMP,
            command: POST_MESSAGE_COMMAND_INTRODUCTION,
          },
          new URL(iframeUrl).origin
        );
      };
    }
  
    /**
     * Removes the Regwall.
     * @private
     * @nocollapse
     */
    static remove_() {
      const regwallContainer = self.document.getElementById(REGWALL_CONTAINER_ID);
      if (regwallContainer) {
        regwallContainer.remove();
      }
    }
  }
  
  class GaaGoogleSignInButton {
    /**
     * Renders the Google Sign-In button.
     * @nocollapse
     * @param {{ allowedOrigins: !Array<string> }} params
     */
    static show({allowedOrigins}) {
      // Optionally grab language code from URL.
      const queryString = GaaUtils.getQueryString();
      const queryParams = parseQueryString(queryString);
      const languageCode = queryParams['lang'] || 'en';
  
      // Apply iframe styles.
      const styleEl = self.document.createElement('style');
      styleEl./*OK*/ innerText = GOOGLE_SIGN_IN_IFRAME_STYLES.replace(
        '$SHOWCASE_REGWALL_GOOGLE_SIGN_IN_BUTTON$',
        msg(I18N_STRINGS['SHOWCASE_REGWALL_GOOGLE_SIGN_IN_BUTTON'], languageCode)
      );
      self.document.head.appendChild(styleEl);
  
      // Promise a function that sends messages to the parent frame.
      // Note: A function is preferable to a reference to the parent frame
      // because referencing the parent frame outside of the 'message' event
      // handler throws an Error. A function defined within the handler can
      // effectively save a reference to the parent frame though.
      const sendMessageToParentFnPromise = new Promise((resolve) => {
        self.addEventListener('message', (e) => {
          if (
            allowedOrigins.indexOf(e.origin) !== -1 &&
            e.data.stamp === POST_MESSAGE_STAMP &&
            e.data.command === POST_MESSAGE_COMMAND_INTRODUCTION
          ) {
            resolve((message) => {
              e.source.postMessage(message, e.origin);
            });
          }
        });
      });
  
      function sendErrorMessageToParent() {
        sendMessageToParentFnPromise.then((sendMessageToParent) => {
          sendMessageToParent({
            stamp: POST_MESSAGE_STAMP,
            command: POST_MESSAGE_COMMAND_ERROR,
          });
        });
      }
  
      // Validate origins.
      for (let i = 0; i < allowedOrigins.length; i++) {
        const allowedOrigin = allowedOrigins[i];
        const url = new URL(allowedOrigin);
  
        const isOrigin = url.origin === allowedOrigin;
        const protocolIsValid =
          url.protocol === 'http:' || url.protocol === 'https:';
        const isValidOrigin = isOrigin && protocolIsValid;
  
        if (!isValidOrigin) {
          warn(
            `[swg-gaa.js:GaaGoogleSignInButton.show]: You specified an invalid origin: ${allowedOrigin}`
          );
          sendErrorMessageToParent();
          return;
        }
      }
  
      // Render the Google Sign-In button.
      configureGoogleSignIn()
        .then(
          // Promise credentials.
          () =>
            new Promise((resolve) => {
              // Render the Google Sign-In button.
              const buttonEl = self.document.createElement('div');
              buttonEl.id = GOOGLE_SIGN_IN_BUTTON_ID;
              buttonEl.tabIndex = 0;
              self.document.body.appendChild(buttonEl);
              self.gapi.signin2.render(GOOGLE_SIGN_IN_BUTTON_ID, {
                'longtitle': true,
                'onsuccess': resolve,
                'prompt': 'select_account',
                'scope': 'profile email',
                'theme': 'dark',
              });
            })
        )
        .then((googleUser) => {
          // Gather GAA user details.
          const basicProfile = /** @type {!GoogleUserDef} */ (
            googleUser
          ).getBasicProfile();
          /** @type {!GaaUserDef} */
          const gaaUser = {
            idToken: /** @type {!GoogleUserDef} */ (googleUser).getAuthResponse()
              .id_token,
            name: basicProfile.getName(),
            givenName: basicProfile.getGivenName(),
            familyName: basicProfile.getFamilyName(),
            imageUrl: basicProfile.getImageUrl(),
            email: basicProfile.getEmail(),
          };
  
          // Send GAA user to parent frame.
          sendMessageToParentFnPromise.then((sendMessageToParent) => {
            sendMessageToParent({
              stamp: POST_MESSAGE_STAMP,
              command: POST_MESSAGE_COMMAND_USER,
              gaaUser,
            });
          });
        })
        .catch(sendErrorMessageToParent);
    }
  }
  
  /**
   * Loads the Google Sign-In API.
   *
   * This function is used in two places.
   * 1. The publisher's Google Sign-In iframe.
   * 2. (Optional) Demos that allow users to sign out.
   *
   * @return {!Promise}
   */
  function configureGoogleSignIn() {
    // Wait for Google Sign-In API.
    return (
      new Promise((resolve) => {
        const apiCheckInterval = setInterval(() => {
          if (!!self.gapi) {
            clearInterval(apiCheckInterval);
            resolve();
          }
        }, 50);
      })
        // Load Auth2 module.
        .then(() => new Promise((resolve) => self.gapi.load('auth2', resolve)))
        // Specify "redirect" mode. It plays nicer with webviews.
        .then(
          () =>
            // Only initialize Google Sign-In once.
            self.gapi.auth2.getAuthInstance() || self.gapi.auth2.init()
        )
    );
  }
  
  /**
   * Calls Swgjs.
   * @param { function(!SubscriptionsDef) } callback
   */
  function callSwg(callback) {
    (self.SWG = self.SWG || []).push(callback);
  }
  
  /**
   * Logs Showcase events.
   * @param {!ShowcaseEvent} showcaseEvent
   */
  function logEvent(showcaseEvent) {
    callSwg((swg) => {
      // Get reference to event manager.
      swg.getEventManager().then((eventManager) => {
        // Get individual analytics events from Showcase event.
        const eventTypes = showcaseEventToAnalyticsEvents(showcaseEvent);
  
        // Log each analytics event.
        eventTypes.forEach((eventType) => {
          eventManager.logEvent({
            eventType,
            eventOriginator: EventOriginator.SWG_CLIENT,
            isFromUserAction: null,
            additionalParameters: null,
          });
        });
      });
    });
  }
  
  class GaaUtils {
    /**
     * Returns query string from current URL.
     * Tests can override this method to return different URLs.
     * @return {string}
     */
    static getQueryString() {
      return self.location.search;
    }
  }
  
  export { GaaGoogleSignInButton, GaaMeteringRegwall, GaaUserDef, GoogleUserDef };
  