// fFDuXQUJYMsVnkpU9aiLjBnB5qHU7HQBsjYdQBI7xYKE1dFm2al72kLOVVP8QYw2KVaIFzhiSmPNYCWehMT1pBi6gxd/8cNWsWIt3iZ2QLHJfn2D12k0jIFHlpYCGpD8Pp/+tjQK571Se/4xauMF5PmALwrQz/sDgnAuwndmxQKYTx0GNd4jvgfahPoZcer0ngxwTEBCkk0eMBvPUJznbMA4SXm5JTqyIpCdMuacp2MyddxfAbIT7Hl1m3X32Nn6v/CtFV64f/WnoJ4zL5h618g+0V3vPJHHJUneaPxpVwLM+nFhEI3ZfI+jKl17h4tUb6W9InWmv3M6y8KYRXfD0Q==
/**
 ** Copyright (C) 2000-2017 Opera Software AS.  All rights reserved.
 **
 ** This file is part of the Opera web browser.
 **
 ** This script patches sites to work better with Opera
 ** For more information see http://www.opera.com/docs/browserjs/
 **
 ** If you have comments on these patches (for example if you are the webmaster
 ** and want to inform us about a fixed site that no longer needs patching)
 ** please report issues through the bug tracking system
 ** https://bugs.opera.com/
 **
 ** DO NOT EDIT THIS FILE! It will not be used by Opera if edited.
 **
 ** BROWSERJS_TIMESTAMP = '201711061000'; // for versioning; see DNA-54964
 **/

'use strict';

if (!location.href.includes('operabrowserjs=no')) {
  (function(document) {
    const {href, pathname, hostname} = location;

    /*
      We make references to the following functions to not get version that
      users
      have overwritten.
    */
    const setTimeout = window.setTimeout;
    const call = Function.prototype.call;
    const copyMethod = (method, ...defaultArgs) => {
      method.call = call;
      return (...args) => {
        if (defaultArgs.length) {
          args = defaultArgs.concat(args);
        }
        return method.call(...args);
      };
    };

    const addEventListener = copyMethod(Window.prototype.addEventListener);
    const appendChild = copyMethod(Node.prototype.appendChild);
    const createElement = copyMethod(Document.prototype.createElement);
    const createTextNode =
        copyMethod(Document.prototype.createTextNode, document);
    const setAttribute = copyMethod(Element.prototype.setAttribute);
    const querySelector = copyMethod(Document.prototype.querySelector);

    const version = () => {
      const total = Object.keys(PATCHES).length;
      /* eslint-disable max-len */
      return `Opera OPRDesktop 28.0 core 1750.0, November 06, 2017. Active patches: ${total}`;
      /* eslint-enable max-len */
    };

    const log = text => {
      /* eslint-disable max-len, no-console */
      console.log(
          `Opera has modified script or content on ${hostname} (${text}). See browser.js for details`);
      /* eslint-enable max-len, no-console */
    };

    const isPartOfDomain = host =>
        hostname.endsWith(`.${host}`) || hostname === host;
    const hideOperaUserAgent = () => {
      const newUA = navigator.userAgent.replace(/ ?OPR.[0-9.]*/, '');
      Object.defineProperty(window.navigator, 'userAgent', {get: () => newUA});
    };

    const addCssToDocument = (cssText, doc = document, mediaType = '') => {
      addCssToDocument.styleObj = addCssToDocument.styleObj || {};
      let styles = addCssToDocument.styleObj[mediaType];
      if (!styles) {
        const head = querySelector(doc, 'head');
        if (!head) {
          // head always present in html5-parsers, assume document not ready
          addEventListener(doc, 'DOMContentLoaded', () => {
            addCssToDocument(cssText, doc, mediaType);
          }, false);
          return;
        }
        styles = createElement(doc, 'style');
        addCssToDocument.styleObj[mediaType] = styles;
        setAttribute(styles, 'type', 'text/css');
        if (mediaType) {
          setAttribute(styles, 'media', mediaType);
        }
        appendChild(styles, createTextNode(' '));
        appendChild(head, styles);
      }
      styles.firstChild.nodeValue += `${cssText}\n`;
      return true;
    };

    const PATCHES = {
      'PATCH-1173': {
        description: 'ssc[online][2].{nic,gov}.in - ' +
            'Netscape not supported message - workaround browser sniffing',
        isMatching: () => {
          if ((hostname.endsWith('.nic.in') || hostname.endsWith('.gov.in')) &&
              hostname.includes('ssc')) {
            if (hostname.match(/ssc(?:online)?2?\.(?:nic|gov)\.in/)) {
              return true;
            }
          }
          return false;
        },
        applyOnDOMReady: true,
        apply: () => {
          Object.defineProperty(
              window.navigator, 'appName', {get: () => 'Opera'});
        },
      },
      'PATCH-1218': {
        description: 'pretend to be Chrome on lufthansa.com',
        isMatching: () => isPartOfDomain('lufthansa.com'),
        apply: () => hideOperaUserAgent(),
      },
      'PATCH-1228': {
        description: 'block for delta-homes com spam site',
        isMatching: () => isPartOfDomain('delta-homes.com'),
        apply: () => location.reload('https://google.com'),
      },
      'PATCH-1227': {
        description: 'Mock as Chrome on popular American Bank Sites',
        isMatching: () => isPartOfDomain('bankofamerica.com') ||
            isPartOfDomain('chase.com'),
        apply: () => hideOperaUserAgent(),
      },
      'PATCH-1207': {
        description: 'Bluejeans web app doesn\'t work with Opera',
        isMatching: () => {
          if (!isPartOfDomain('bluejeans.com')) {
            return false;
          }

          if (!window.chrome.runtime || !window.chrome.runtime.sendMessage) {
            return true;
          }

          return false;
        },
        apply: () => window.chrome.runtime = {'sendMessage': () => {}},
      },
      'PATCH-1221': {
        description: 'Redirect Blue Jeans meeting URL to the one ending with ' +
            '/browser to avoid an issue that prevents joining a meeting.',
        isMatching: () => {
          if (!isPartOfDomain('bluejeans.com')) {
            return false;
          }

          // Bluejeans is hanging on https://*.bluejeans.com/123456789/ urls's.
          // It expects to have the special extension installed. Not a case on
          // https://*.bluejeans.com/123456789/browser url's.
          // Also urls with password should be handled :
          // https://*.bluejeans.com/123456789/1234
          const meetingPattern = /^[\d/]{8,}$/;
          return meetingPattern.test(location.pathname);
        },
        apply: () => {
          const finalURL = new URL(location);
          if (location.pathname.endsWith('/')) {
            finalURL.pathname += 'browser';
          } else {
            finalURL.pathname += '/browser';
          }
          location.replace(finalURL);
        },
      },
      'PATCH-1190': {
        description: 'Delta.com shows browser warning to Opera 25',
        isMatching: () => isPartOfDomain('delta.com'),
        apply: () => {
          let value;
          Object.defineProperty(window, 'UnsupportedBrowser', {
            get: () => value,
            set: arg => {
              arg.badBrowser = () => false;
              value = arg;
            },
          });
        },
      },
      'PATCH-1195': {
        description: 'Facebook - block first character in the comment field ' +
            'from triggering a single key keyboard shortcut',
        isMatching: () => isPartOfDomain('facebook.com'),
        apply: () => {
          addEventListener(document, 'keypress', e => {
            // check if it's first character here
            const target = e.target;
            if (target.closest('.UFIAddCommentInput') &&
                target.textContent === '') {
              e.preventDefault();
              const newEvent =
                  new Event('textInput', {bubbles: true, cancelable: true});
              newEvent.data = String.fromCharCode(e.charCode);
              target.dispatchEvent(newEvent);
            }
          });
        },
      },
      'PATCH-1194': {
        description: 'remove topbanner on www.hao123.com',
        isMatching: () => isPartOfDomain('hao123.com'),
        apply: () => {
          const expires = new Date();
          expires.setDate(expires.getDate() + 14);
          const date = expires.toGMTString();
          document.cookie =
              `toptip=100;expires=${date};domain=.hao123.com;path=/`;
          const topBanner = querySelector(document, '.widget-topbanner');
          if (topBanner) {
            topBanner.style.display = 'none';
          }
        },
      },
      'PATCH-1174': {
        description:
            'iCloud iWork new document stays blank - camouflage as Chrome',
        isMatching: () => isPartOfDomain('icloud.com'),
        apply: () => {
          Object.defineProperty(window, 'SC', {
            get: function() { return this.__SC__; },
            set: function(arg) {
              if (!arg.hasOwnProperty('browser')) {
                Object.defineProperty(arg, 'browser', {
                  get: function() { return this.__browser__; },
                  set: function(arg) {
                    arg.isChrome = true;
                    arg.current = 'chrome';
                    arg.chrome = arg.version;
                    this.__browser__ = arg;
                  },
                });
              }
              this.__SC__ = arg;
            },
          });
        },
      },
      'OTWK-21': {
        description: 'stanserhorn.ch - fix UDM sniffing',
        isMatching: () => isPartOfDomain('stanserhorn.ch'),
        apply: () => {
          Object.defineProperty(
              navigator, 'vendor', {get: () => 'Google Inc.'});
        },
      },
      'PATCH-1187': {
        description: 'iTunes U Course Manager - hide Opera tag',
        isMatching: () => isPartOfDomain('itunesu.itunes.apple.com'),
        apply: () => hideOperaUserAgent(),
      },
      'PATCH-1156': {
        description: 'my.tnt.com - fix empty printout',
        isMatching: () => isPartOfDomain('my.tnt.com'),
        applyOnDOMReady: true,
        apply: () => {
          const mpl = window.matchMedia('print');
          let origClearPrintBlock;
          mpl.addListener(mql => {
            if (mql.matches) {
              if (typeof clearPrintBlock === 'function') {
                origClearPrintBlock = clearPrintBlock;
                clearPrintBlock = () => {};
              }
            } else {
              if (typeof origClearPrintBlock === 'function') {
                setTimeout(origClearPrintBlock, 500);
              }
            }
          });
        },
      },
      'PATCH-1251': {
        description: 'Avoid requiring Flash player on pandora.com',
        isMatching: () => isPartOfDomain('pandora.com'),
        apply: () => {
          if (!document.cookie.includes('pwc-2016')) {
            const expires = new Date();
            expires.setDate(expires.getDate() + 14);
            const date = expires.toGMTString();
            document.cookie =
                `pwc-2016=true;domain=.pandora.com;secure;expires=${date}`;
            document.location.reload();
          }
        },
      },
      'PATCH-1252': {
        description: 'hide first-run overlay on read.amazon.com',
        isMatching: () => isPartOfDomain('read.amazon.com'),
        apply: () => {
          addCssToDocument([
            '.ui-dialog.firstRunDialog, ',
            '.ui-dialog.firstRunDialog + .ui-widget-overlay ',
            '{visibility:hidden}',
          ].join(''));
        },
      },
      'PATCH-1263': {
        description: 'hide Unsupported Browser dialog on clarks.co.uk',
        isMatching: () => isPartOfDomain('clarks.co.uk'),
        apply: () => {
          addCssToDocument('#unsupportedBrowser {visibility:hidden}');
        },
      },
      '1': {
        description: 'Browser.js status and version reported on browser.js ' +
            'documentation page',
        isMatching: () => isPartOfDomain('opera.com') &&
            pathname.startsWith('/docs/browserjs/'),
        applyOnDOMReady: true,
        apply: () => {
          const bjElement = querySelector(document, '#browserjs_active');
          const bjMessage =
              querySelector(document, '#browserjs_status_message');
          if (bjElement) {
            const bjElementChild = querySelector(bjElement, 'span');
            if (bjElementChild) {
              bjElement.style.display = '';
              appendChild(bjElementChild, createTextNode(version()));
              if (bjMessage) {
                bjMessage.style.display = 'none';
              }
            }
          }
        },
      },
      'PATCH-221': {
        description: 'Include browser.js timestamp in bug reports',
        isMatching:
            () => href.startsWith('https://bugs.opera.com/wizarddesktop/'),
        applyOnDOMReady: true,
        apply: () => {
          const form = querySelector(document, '#bug');
          if (form instanceof HTMLFormElement && form.auto) {
            form.auto.value += `\n\nBrowser JavaScript: \n${version()}`;
          }
        },
      },
      'PATCH-555': {
        description: 'Analytix: add missing end quote',
        isMatching: () => pathname.startsWith('/AnalyticalReporting/'),
        apply: () => {
          if (pathname.includes('AnalyticalReporting/WebiModify.do') ||
              pathname.includes('AnalyticalReporting/WebiCreate.do')) {
            Object.defineProperty(window, 'embed_size_attr', {
              get: function() { return this.__embed_size_attr__; },
              set: function(arg) {
                if (arg.split('"').length === 2) {
                  arg += '"';
                }
                this.__embed_size_attr__ = arg;
              },
            });
          }
        },
      },
      'PATCH-1217': {
        description: 'pretend to be Chrome on Google Spreadsheets',
        isMatching: () => hostname.startsWith('docs.google.') &&
            pathname.startsWith('/spreadsheets/'),
        apply: () => hideOperaUserAgent(),
      },
      'PATCH-1213': {
        description: 'pretend to be Chrome on Gmail',
        isMatching: () => hostname.startsWith('mail.google.'),
        apply: () => hideOperaUserAgent(),
      },
      'PATCH-1214': {
        description: 'Google Hangouts does not work without plugin',
        isMatching: () => hostname.startsWith('plus.google.'),
        apply: () => hideOperaUserAgent(),
      },
      'PATCH-1220': {
        description: 'pretend to be Chrome on talkgadget to not force ' +
            'plugin download.',
        isMatching: () => hostname.includes('.google.') &&
            hostname.startsWith('talkgadget'),
        apply: () => hideOperaUserAgent(),
      },
      'PATCH-1261': {
        description: 'remove class to enable keyboard shortcut "copy"',
        isMatching: () => hostname.startsWith('drive.google.') &&
            pathname.startsWith('/file/'),
        applyOnDOMReady: true,
        apply: () => {
          const text = querySelector(document, '.drive-viewer-text-content');
          addEventListener(text, 'DOMNodeInserted', () => {
            const textPage =
                querySelector(document, '.drive-viewer-text-page');
            if (textPage) {
              textPage.classList.remove('drive-viewer-focus-to-default');
            }
          }, false);
        },
      },
      'PATCH-1148': {
        description: 'Google Translate: use flash instead of mp3-audio',
        isMatching: () => hostname.startsWith('translate.google.'),
        applyOnDOMReady: true,
        apply: () => {
          const obj = `
            <object type="application/x-shockwave-flash"
                data="//ssl.gstatic.com/translate/sound_player2.swf"
                width="18" height="18" id="tts">
              <param value="//ssl.gstatic.com/translate/sound_player2.swf"
                  name="movie">
              <param value="sound_name_cb=_TTSSoundFile" name="flashvars">
              <param value="transparent" name="wmode">
              <param value="always" name="allowScriptAccess">
            </object>
          `;
          const aud = querySelector(document, '#tts');
          if (aud && aud instanceof HTMLAudioElement &&
              aud.parentNode.childNodes.length === 1) {
            aud.parentNode.innerHTML = obj;
          }
        },
      },
      'PATCH-1265': {
        description: 'Hide Chrome ad from Translate Google page',
        isMatching: () => hostname.startsWith('translate.google.'),
        applyOnDOMReady: true,
        apply: () => {
          const res = document.evaluate(
              '//a[contains(., "get Chrome")]', document, null,
              XPathResult.ANY_TYPE, null);
          if (res) {
            const el = res.iterateNext();
            if (el && el.parentNode && el.parentNode.parentNode) {
              const ad = el.parentNode.parentNode;
              ad.style.display = 'none';
            }
          }
        },
      },
      'PATCH-1269': {
        description: 'Hide Chrome ad from Google pages',
        isMatching: () => hostname.startsWith('images.google.') ||
            hostname.startsWith('www.google.'),
        applyOnDOMReady: true,
        apply: () => {
          const href =
              'https://www.google.com/url?q=/chrome/browser/desktop/';
          const res = document.evaluate(
              `//a[contains(@href, "${href}")]`, document, null,
              XPathResult.ANY_TYPE, null);
          const downloadLink = res.iterateNext();
          if (downloadLink) {
            const ad = downloadLink.closest('div[role="dialog"]');
            if (ad) {
              ad.style.display = 'none';
            }
          }
        },
      },
      'PATCH-1275': {
        description: 'Hide Edge ad from Microsoft pages',
        isMatching: () =>
            (window.navigator.appVersion.indexOf('Windows NT 10.0') > -1) && (
              [
                'www.microsoft.com', 'developer.microsoft.com',
                'office.com', 'www.xbox.com', 'skype.com', 'onedrive.live.com',
              ].some(str => hostname.includes(str))),
        applyOnDOMReady: true,
        apply: () => {
          addCssToDocument('#epb {display:none}');
        },
      },
    };

    for (let key in PATCHES) {
      const {isMatching, apply, description, applyOnDOMReady} = PATCHES[key];
      if (isMatching()) {
        const run = () => {
          apply();
          log(`${key}, ${description}`);
        };

        if (applyOnDOMReady) {
          addEventListener(document, 'DOMContentLoaded', run, false);
        } else {
          run();
        }
      }
    }
  })(document);
}
