zeeTreehouses

More details of myths currently hosted in treehouses. Expiry times powered by sohcah's CuppaZee

目前為 2020-07-07 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         zeeTreehouses
// @namespace    none
// @version      2020.07.07.1038
// @description  More details of myths currently hosted in treehouses. Expiry times powered by sohcah's CuppaZee
// @author       technical13
// @supportURL   https://discord.me/TheShoeStore
// @match        https://www.munzee.com/m/*/*
// @match        https://www.munzee.com/flows/*
// @grant        none
// ==/UserScript==
// jshint esversion: 6

var isDebug = false;
var intVerbosity = 0;
const ver = '2020.07.07.1038';
const scriptName = 'zeeTreehouses v' + ver;

const apiBetaURL = 'https://server.cuppazee.app/munzee/bouncers/v1';//?munzee_id=
const apiPrimaryURL = 'https://flame.cuppazee.uk/munzee/bouncers/v1';//?username=&munzee=
const apiBackupURL = 'https://us-central1-cuppazeex.cloudfunctions.net/munzee';//?username=&munzee=

const thisDate = ( new Date() );
const objValueOfDateTimeMHQ = Date.parse( thisDate.toLocaleString( 'en-US', { timeZone: 'America/Chicago' } ) );
const objValueOfDateTimeLocal = thisDate.valueOf();
const intMsOffsetMHQ = ( Math.round( ( objValueOfDateTimeMHQ - objValueOfDateTimeLocal ) / 10000 ) * 10000 );
const objFullTimeStringHQ = {
    year: 'numeric', month: 'long', day: 'numeric',
    hour: 'numeric', minute: 'numeric', second: 'numeric',
    timeZone: 'America/Chicago', timeZoneName: 'short', hour12: false };
const objShorTimeStringHQ = {
    year: 'numeric', month: 'short', day: 'numeric',
    hour: 'numeric', minute: 'numeric', second: 'numeric',
    timeZone: 'America/Chicago', hour12: false };

function log( intV, strConsole, strLog, ...arrArgs ) {
    if ( strConsole === undefined ) { strConsole = 'log'; }
    if ( strLog === undefined ) { strLog = '%o'; }
    if ( intVerbosity >= intV && ( strConsole === 'groupEnd' ) ) { console[ strConsole ](); }
    if ( intV === 0 || ( isDebug && intVerbosity >= intV ) ) { console[ strConsole ]( '[%i]: %s: ' + strLog, intV, scriptName, ...arrArgs ); }
}
function toBoolean( val ) {
    const arrTrue = [ undefined, null, '', true, 'true', 1, '1', 'on', 'yes' ];
    val = ( typeof( val ) === 'string' ? val.toLowerCase() : val );

    log( 4, 'log', 'toBoolean() is returning: %o', ( arrTrue.indexOf( val ) !== -1 ? true : false ) );
    return ( arrTrue.indexOf( val ) !== -1 ? true : false );
}
var address = document.URL.replace( /https?:\/\/www\.munzee\.com\/?/i, '' ).split( '/' );
var isUserPage = false;
if ( address[ 0 ] === 'm' ) {
    isUserPage = true;
    address = address.slice( 1 );
}
const pageUserName = ( address[ 0 ] || undefined );
const subPage = ( address[ 1 ] || undefined );
const subSubPage = ( address[ 2 ] || undefined );
const isErrorPage = ( $( 'div#error' ).length === 0 ? false : true );
const intParamsStart = ( document.URL.indexOf( '?' ) + 1 );
const strParams = document.URL.substr( intParamsStart );
const arrParamSets = strParams.split( '&' );
var objParams = {};
arrParamSets.forEach( function( strParam ) {
    let arrParam = strParam.split( '=' );
    let strParamName = ( arrParam[ 0 ].toLowerCase() || '' );
    if ( strParamName === 'verbosity' ) {
        isDebug = toBoolean( arrParam[ 1 ] );
        intVerbosity = ( arrParam[ 1 ] ? ( parseInt( arrParam[ 1 ] ) < 0 ? 0 : ( parseInt( arrParam[ 1 ] ) > 9 ? 9 : parseInt( arrParam[ 1 ] ) ) ) : 9 );
    } else if ( strParamName === 'debug' ) {
        isDebug = toBoolean( arrParam[ 1 ] );
        intVerbosity = 1;
    } else if ( strParamName === 'report' ) {
        objParams.report = decodeURIComponent( arrParam[ 1 ] );
    }
} );

log( 1, 'warn', 'Debug mode is on with verbosity level: %o', intVerbosity );
log( 1, 'groupCollapsed', 'Verbosity options: (click to expand)' );
log( 1, 'log', '1) Summary\n2) Parameters retrieved from URL\n3) Variables set to objParams\n4) Function returns\n9) ALL debugging info and this notice.' );
log( 1, 'groupEnd' );

var arrUndefinedTypes = [
    'akvamariin', 'ametust', 'oniks', 'smaragd', 'teemant', 'topaas',//        // Funfinity Stones
    'banshee', 'harpybanshee', 'gorgon', 'retiredbanshee', 'witchbanshee',//   // Banshee
    'cyclops', 'balorcyclops', 'minotaurcyclops', 'ogre', 'retiredcyclops',//  // Cyclops
    'cherub',//                                                                // Cherub
    'chinesedragon', 'wyverndragon',//                                         // Dragon
    'dryadfairy', 'fairy', 'fairygodmother', 'retiredfairy', 'wildfirefairy',//// Fairy
    'centaurfaun', 'krampusfaun',//                                            // Faun
    'chimera', 'cthulhuhydra',//                                               // Hydra //, 'cerberushydra'
    'dwarfleprechaun', 'goblinleprechaun',//                                   // Leprechaun
    'magnetus',//                                                              // Magnetus
    'melusinemermaid',//                                                       // Mermaid
    'elfnymph', 'nymph', 'vampirenymph',//                                     // Nymph
    'alicornpegasus', 'firepegasus', 'griffinpegasus',//                       // Pegasus
    'pimedus',//                                                               // Pimedus
    'poseidon',//                                                              // Poseidon
    'hadavale', 'motherearth',//                                               // SOBs
    'trojanunicorn'//                                                          // Temp types
];
var objEvolutionTypes = {
    1240: [ 'tuli', 'tulimber', 'tuliferno' ],
    1370: [ 'vesi', 'vesial', 'vesisaur' ],
    1638: [ 'muru', 'muruchi', 'murutain' ],
    2240: [ 'puffle', 'pufrain', 'puflawn' ],
    2407: [ 'elekter', 'elekjoul', 'elektrivool' ]
};
var arrLimitTypes = [//  Auto-archive after 10 captures or 42 days.
    'limebutterfly', 'monarchbutterfly', 'morphobutterfly',//                  // Butterly
    'poisondartfrog', 'tomatofrog', 'treefrog',//                              // Frog
    'boxjellyfish', 'goldenjellyfish', 'pb&jellyfish',//                       // Jellyfish
    'seaturtle', 'snappingturtle', 'taekwondotortoise',//                      // Turtles
];
arrUndefinedTypes = arrUndefinedTypes.concat( arrLimitTypes );

var arrEvolutionNames = [];
Object.values( objEvolutionTypes ).forEach( ( arrEvoType, ndx ) => {
    let thisKey = Object.keys( objEvolutionTypes )[ ndx ];
    arrEvolutionNames = arrEvolutionNames.concat( objEvolutionTypes[ thisKey ] );
} );

function countDown( intRawSeconds ) {
    var intSeconds = parseInt( intRawSeconds );
    var intHours = Math.floor( intSeconds / 3600 );
    intSeconds = intSeconds - ( intHours * 3600 );
    var intMinutes = Math.floor( intSeconds / 60 );
    intSeconds = intSeconds - ( intMinutes * 60 );
    var strCountDown = '';
    if ( window.screen.width < 1200 ) {
        strCountDown = ( intHours.toLocaleString() <= 9 ? '0' : '' ) + intHours.toLocaleString() +
            ':' + ( intMinutes.toLocaleString() <= 9 ? '0' : '' ) + intMinutes.toLocaleString() +
            ':' + ( intSeconds.toLocaleString() <= 9 ? '0' : '' ) + intSeconds.toLocaleString();
    } else {
        strCountDown = ( intHours > 0 ? intHours.toLocaleString() +
                        ' hour' + ( intHours === 1 ? '' : 's' ) : '' ) +
            ( intMinutes > 0 ? ( intHours > 0 ? ', ' : '' ) +
             intMinutes.toLocaleString() + ' minute' + ( intMinutes === 1 ? '' : 's' ) : '' ) +
            ( intSeconds > 0 ? ( intHours > 0 || intMinutes > 0 ? ', ' : '' ) +
             intSeconds.toLocaleString() + ' second' + ( intSeconds === 1 ? '' : 's' ) : '' );
    }

    log( 4, 'log', 'countDown( %i ) is returning: %s', intRawSeconds, strCountDown );
    return strCountDown;
}
async function getBouncerData( strTempPOB ) {
    var objStats = {};
    await $.ajax( { url: strTempPOB } ).done( function( tmpPobData ) {
        var statGreen = $( tmpPobData ).find( 'div.user-stat.stat-green > a' );
        statGreen.each( ( intRow, statData ) => {
            var arrStat = $( statData ).text().trim().split( ' ' );
            if ( arrStat.length === 2 ) { objStats[ arrStat[ 1 ] ] = parseInt( arrStat[ 0 ] ); }
        } );
        objStats.deployed = ( new Date( $( tmpPobData ).find( 'p.status-date > span.deployed-at' )[ 0 ].dataset.deployedAt ) );
        var intAge = ( new Date() ).valueOf() - objStats.deployed.valueOf();
        objStats.ageDays = Math.ceil( intAge / 1000 / 60 / 60 / 24 );
    } );
    return objStats;
}
async function getTempDays( strTempPOB ) {
    var tempStats = await getBouncerData( strTempPOB );
    return '<img src="https://munzee.global.ssl.fastly.net/images/pins/temporaryvirtual.png" style="width: 24px; height: 24px;"' +
        ' title="This temporary bouncer will auto-archive in:\n\t' +
        ( 42 - tempStats.ageDays ) + ' of 42 day' + ( ( 42 - tempStats.ageDays ) === 1 ? '' : 's' ) + '\n\t' +
        ( 10 - tempStats.Capture ) + ' of 10 capture' + ( ( 10 - tempStats.Capture ) === 1 ? '' : 's' ) + '" />';
}
async function getPouchDays( strPouchURL ) {
    var thisDate = ( new Date() ), isCappedToday = false, wasCappedYesterday = false, wasCappedDayBefore = false;
    await $.ajax( { url: strPouchURL } ).done( function( capData ) {
        var logSections = $( capData ).find( 'div#munzee-holder > section:not( .entry-holder )' );
        logSections.each( ( logNumber, logSection ) => {
            var thenMidnight = new Date( thisDate.getFullYear(), thisDate.getMonth(), thisDate.getDate(), 0, 0, 0 ),
                intLastMidnight = objValueOfDateTimeLocal - ( ( thisDate.getTime() - thenMidnight.getTime() ) + intMsOffsetMHQ ),
                intMidnightBefore = intLastMidnight - ( 1000 * 60 * 60 * 24 ),
                intMidnightThree = intMidnightBefore - ( 1000 * 60 * 60 * 24 );
            log( 4, 'log', '\n\tlastMidnight: %o\n\tmidnightBefore: %o\n\tmidnightThree: %o', ( new Date( intLastMidnight ) ), ( new Date( intMidnightBefore ) ), ( new Date( intMidnightThree ) ) );
            var strEntryDateTime = $( logSection ).find( 'span.captured-at' ).attr( 'title' );
            var objDate = ( new Date( strEntryDateTime ) );
            var intLogDate = objDate.valueOf();
            var intCapToday = ( intLogDate - intLastMidnight - 86400000 ),
                intCapYesterday = ( intLogDate - intMidnightBefore - 86400000 ),
                intCapDayBefore = ( intLogDate - intMidnightThree - 86400000 );
            log( 5, 'log', '\n\t%o: %o (%o):\n\t%o|%o|%o\n\t(%o|%o|%o)\n\t(%o|%o|%o)', logNumber, objDate.toLocaleString(), intLogDate,
                        isCappedToday, wasCappedYesterday, wasCappedDayBefore,
                        intLogDate - intLastMidnight - 86400000, intLogDate - intMidnightBefore - 86400000, intLogDate - intMidnightThree - 86400000,
                        intLastMidnight, intMidnightBefore, intMidnightThree,
                       );
            log( 4, 'log', '\n\tisCappedToday[ %o ]: %o\n\twasCappedYesterday[ %o ]: %o\n\twasCappedDayBefore[ %o ]: %o',
                        logNumber, ( intCapToday > -86400000 && intCapToday <= 0 ? true : false ),
                        logNumber, ( intCapYesterday > -86400000 && intCapYesterday <= 0 ? true : false ),
                        logNumber, ( intCapDayBefore > -86400000 && intCapDayBefore <= 0 ? true : false )
                       );
            isCappedToday = ( isCappedToday ? true : ( intCapToday > -86400000 && intCapToday <= 0 ? true : false ) );
            wasCappedYesterday = ( wasCappedYesterday ? true : ( intCapYesterday > -86400000 && intCapYesterday <= 0 ? true : false ) );
            wasCappedDayBefore = ( wasCappedDayBefore ? true : ( intCapDayBefore > -86400000 && intCapDayBefore <= 0 ? true : false ) );
        } );
    } );
    if ( isCappedToday && wasCappedYesterday && wasCappedDayBefore ) {
        return ' <abbr title="Capped today, streak day: 3+" style="color: #008000">✓✓✓</abbr> '; }
    if ( isCappedToday && wasCappedYesterday && !wasCappedDayBefore ) {
        return ' <abbr title="Capped today, streak day: 2" style="color: #008000">✓✓</abbr> '; }
    if ( isCappedToday && !wasCappedYesterday ) {
        return ' <abbr title="Capped today, streak day: 1" style="color: #008000">✓</abbr> '; }
    if ( !isCappedToday && !wasCappedYesterday && !wasCappedDayBefore ) {
        return ' <abbr title="Uncapped in 3+ days." style="color: #FF00FF">☹</abbr> '; }
    if ( !isCappedToday && !wasCappedYesterday && wasCappedDayBefore ) {
        return ' <abbr title="Uncapped in 2 days." style="color: #FF00FF">☹</abbr> '; }
    if ( !isCappedToday && wasCappedYesterday && wasCappedDayBefore ) {
        return ' <abbr title="Needs to be capped!"><span style="color: #FF0000">✗</span><span style="color: #008000">✓✓</span></abbr> '; }
    if ( !isCappedToday && wasCappedYesterday ) {
        return ' <abbr title="Needs to be capped!"><span style="color: #FF0000">✗</span><span style="color: #008000">✓</span></abbr> '; }
    return ' <abbr title="unknown streak status" style="color: #FF0000">؟</abbr> ';
}

( function() {
    'use strict';
    log( 0, 'info', 'Script loaded.' );

    try {
        log( 3, 'info', '\npageUserName: %s\nobjParams.report: %o\n!isNaN( parseInt( subPage ) ): %o\nsubPage: %o\n!isErrorPage: %o',
            pageUserName, objParams.report, !isNaN( parseInt( subPage ) ), subPage, !isErrorPage );
        if ( pageUserName === 'flows' && objParams.report ) {
            log( 1, 'log', 'Do error report...' );
            $( 'textarea#message' ).val( objParams.report );
        }
        else if ( !isNaN( parseInt( subPage ) ) && subPage !== undefined && pageUserName !== 'flows' && !isErrorPage ) {
            log( 1, 'log', 'Process main script.' );
            const pinSrc = $( 'div#munzee-name > a > img.pin' ).attr( 'src' );
            const arrPinSrc = pinSrc.split( '/' );
            const isTreehouse = ( arrPinSrc[ ( arrPinSrc.length - 1 ) ].split( '.' )[ 0 ].slice( 0, 9 ) === 'treehouse' ? true : false );
            const isSkyland = ( arrPinSrc[ ( arrPinSrc.length - 1 ) ].split( '.' )[ 0 ].slice( 0, 7 ) === 'skyland' ? true : false );
            const intHosting = parseInt( ( isTreehouse || isSkyland ? arrPinSrc[ ( arrPinSrc.length - 1 ) ].split( '.' )[ 0 ].slice( 9 ) : 1 ) === '' ? 0 : ( isTreehouse || isSkyland ? arrPinSrc[ ( arrPinSrc.length - 1 ) ].split( '.' )[ 0 ].slice( 9 ) : 1 ) );
            log( 3, 'info', '\npinSrc: %o\narrPinSrc: %o\nisTreehouse: %o\nisSkyland: %o\nintHosting', pinSrc, arrPinSrc, isTreehouse, isSkyland, intHosting );

            if ( isTreehouse || isSkyland ) {
                $( 'head' ).append( '<style type="text/css">div.unicorn { margin: 5px; font-size: 16px; font-weight: bold; }</style>' );
                $.get( { url: apiPrimaryURL + '?munzee=' + subPage + '&username=' + pageUserName } )
                    .done( cuppaZee => {
                    log( 8, 'info', 'Response from: %s : %o',
                        apiPrimaryURL + '?munzee=' + subPage + '&username=' + pageUserName, cuppaZee );
                    $( 'div.unicorn' ).each( async ( ndx, unicorn ) => {
                        let isPouch = false;
                        let bouncer = cuppaZee.data[ ndx ];
                        var objExpires = new Date( moment( bouncer.good_until * 1000 ).format() );
                        var intSecondsUntilExpires = Math.floor( ( objExpires.valueOf() - ( new Date() ).valueOf() ) / 1000 );
                        var strNewExpires = ' expiring in <span id="expires-countdown-treehouse' + ( ndx + 1 ) + '" title="' + objExpires.toLocaleDateString( 'en-US', objShorTimeStringHQ ) + '">' + countDown( intSecondsUntilExpires ) + '</span>';
                        if ( arrUndefinedTypes.indexOf( bouncer.mythological_type ) !== -1 ) {
                            $( unicorn ).find( 'img' ).attr( 'src', bouncer.munzee_logo.replace( bouncer.mythological_type, bouncer.mythological_type + ( isTreehouse ? '_physical' : '_virtual' ) ) );
                        }
                        if ( Object.keys( objEvolutionTypes ).indexOf( bouncer.mythological_capture_type.toString() ) !== -1 ) {
                            isPouch = true;
                            $( unicorn ).find( 'img' ).attr( 'src', bouncer.munzee_logo.replace( bouncer.mythological_type, objEvolutionTypes[ bouncer.mythological_capture_type ][ bouncer.unicorn_munzee.evolution - 1 ] ) );
                        }
                        $( unicorn ).html( $( unicorn ).html().replace( 'This Munzee is c', 'C' ) );
                        let thisUnicorn = $( unicorn ).find( 'a' );
                        let thisUnicornURL = thisUnicorn.attr( 'href' ).replace( 'http://', 'https://' );
                        let owner = thisUnicornURL.split( /https?:\/\/www\.munzee\.com\/m\//i )[ 1 ].split( '/' )[ 0 ];
                        thisUnicorn.before( '<a href="https://www.munzee.com/m/' + owner + '">' + owner + '</a>\'s ' );
                        thisUnicorn.after( strNewExpires );
                        if ( isPouch ) {
                            var pouchStatus = await getPouchDays( thisUnicornURL );
                            log( 3, 'log', 'pouchStatus: %o', pouchStatus );
                            thisUnicorn.after( pouchStatus );
                        }
                        if ( arrLimitTypes.indexOf( bouncer.mythological_type ) !== -1 ) {
                           var tempStatus = await getTempDays( thisUnicornURL );
                            log( 3, 'log', 'tempStatus: %o', tempStatus );
                            thisUnicorn.before( tempStatus );
                        }

                        setInterval( function() {
                            intSecondsUntilExpires = Math.floor( ( objExpires.valueOf() - ( new Date() ).valueOf() ) / 1000 );
                            if ( intSecondsUntilExpires > 0 ) {
                                $( 'span#expires-countdown-treehouse' + ( ndx + 1 ) + '' ).text( countDown( intSecondsUntilExpires ) );
                            } else { location.reload(); }
                        }, 1000 );
                    } );
                } ).fail( errCuppaZee => {
                    log( 0, 'error', 'Failed to get response from: %s : %o',
                        apiPrimaryURL + '?munzee=' + subPage + '&username=' + pageUserName, errCuppaZee );
                    var notifyCZ = confirm( scriptName + '\n\tERROR!\t(details in console)\n\tFailed to get bouncer from: flame.cuppazee.uk\n\tPlease press [Cancel] and update the script\n\t\tbefore pressing [OK] to notify the API author\n\t\tas there may already be a fix!\n\n\t\t\t\tThanks!' );
                    if ( notifyCZ ) {
                        window.location.href = 'https://www.munzee.com/flows/?username=sohcah&report=' + encodeURIComponent( 'Version: ' + scriptName + '\nPage: ' + window.location.href + '\nUserAgent: ' + navigator.userAgent + '\nError: ' + errCuppaZee + 'Request: https://flame.cuppazee.uk/munzee/bouncers/v1?munzee=' + subPage + '&username=' + pageUserName + '\n Reporter comments: none' );
                    }
                    $.get( { url: apiBackupURL + '?munzee=' + subPage + '&user=' + pageUserName } )
                        .done( oldCuppaZee => {
                        $( 'div.unicorn' ).each( ( ndx, unicorn ) => {
                            let bouncer = oldCuppaZee.details.bouncers[ ndx ];
                            var objExpires = new Date( moment( bouncer.good_until * 1000 ).format() );
                            var intSecondsUntilExpires = Math.floor( ( objExpires.valueOf() - ( new Date() ).valueOf() ) / 1000 );
                            var strNewExpires = ' expiring in <span id="expires-countdown-treehouse' + ( ndx + 1 ) + '" title="' + objExpires.toLocaleDateString( 'en-US', objShorTimeStringHQ ) + '">' + countDown( intSecondsUntilExpires ) + '</span>';
                            if ( arrUndefinedTypes.indexOf( bouncer.mythological_type ) !== -1 ) {
                                $( unicorn ).find( 'img' ).attr( 'src', bouncer.munzee_logo.replace( bouncer.mythological_type, bouncer.mythological_type + ( isTreehouse ? '_physical' : '_virtual' ) ) );
                            }
                            if ( Object.keys( objEvolutionTypes ).indexOf( bouncer.mythological_capture_type.toString() ) !== -1 ) {
                                $( unicorn ).find( 'img' ).attr( 'src', bouncer.munzee_logo.replace( bouncer.mythological_type, objEvolutionTypes[ bouncer.mythological_capture_type ][ bouncer.unicorn_munzee.evolution - 1 ] ) );
                            }
                            $( unicorn ).html( $( unicorn ).html().replace( 'This Munzee is c', 'C' ) );
                            let thisUnicorn = $( unicorn ).find( 'a' );
                            let owner = thisUnicorn.attr( 'href' ).split( /https?:\/\/www\.munzee\.com\/m\//i )[ 1 ].split( '/' )[ 0 ];
                            thisUnicorn.before( '<a href="https://www.munzee.com/m/' + owner + '">' + owner + '</a>\'s ' );
                            thisUnicorn.after( strNewExpires );

                            setInterval( function() {
                                intSecondsUntilExpires = Math.floor( ( objExpires.valueOf() - ( new Date() ).valueOf() ) / 1000 );
                                if ( intSecondsUntilExpires > 0 ) {
                                    $( 'span#expires-countdown-treehouse' + ( ndx + 1 ) + '' ).text( countDown( intSecondsUntilExpires ) );
                                } else {
                                    location.reload();
                                }
                            }, 1000 );
                        } );
                    } ).fail( errOldCuppaZee => {
                        log( 0, 'error', 'Failed to get response from: %s : %o',
                            apiBackupURL + '?munzee=' + subPage + '&user=' + pageUserName, errOldCuppaZee );
                        var notifyCZ = confirm( scriptName + '\n\tERROR!\tFailed to get bouncer from us-central1-cuppazeex.cloudfunctions.net backup API\n\t\t\t(details in console)\n\tPlease press [Cancel] and update the script\n\t\tbefore pressing [OK] to notify the API author\n\t\tas there may already be a fix!\n\n\t\t\t\tThanks!' );
                        if ( notifyCZ ) {
                            window.location.href = 'https://www.munzee.com/flows/?username=sohcah&report=' + encodeURIComponent( 'Version: ' + scriptName + '\nPage: ' + window.location.href + '\nUserAgent: ' + navigator.userAgent + '\nError: ' + errCuppaZee + 'Request: https://us-central1-cuppazeex.cloudfunctions.net/munzee?munzee=' + subPage + '&user=' + pageUserName + '\n Reporter comments: none' );
                        }
                        $( 'div.unicorn:first' ).before( '<div id="czFailed" class="unicorn"><img style="height: 32px;" src="https://gardenpainter.ide.sk/delete_munzee.png"> ' + scriptName + ' failed to get response from CuppaZee.</div>' );
                        $( 'div.unicorn' ).each( ( ndx, unicorn ) => {
                            $( unicorn ).html( $( unicorn ).html().replace( 'This Munzee is c', 'C' ) );
                            let thisUnicorn = $( unicorn ).find( 'a' );
                            let owner = thisUnicorn.attr( 'href' ).split( /https?:\/\/www\.munzee\.com\/m\//i )[ 1 ].split( '/' )[ 0 ];
                            thisUnicorn.before( '<a href="https://www.munzee.com/m/' + owner + '">' + owner + '</a>\'s ' );
                            let pinIcon = $( unicorn ).find( 'img' );
                            let guessEvoType = thisUnicorn.eq( 1 ).text().split( / #\d+/ )[ 0 ];
                            if ( arrEvolutionNames.indexOf( guessEvoType ) !== -1 ) {
                                let evolution = 0, evoTypeID = 0;
                                evolution = ( ( arrEvolutionNames.indexOf( guessEvoType ) % 3 ) + 1 );
                                evoTypeID = Object.keys( objEvolutionTypes )[ arrEvolutionNames.indexOf( guessEvoType ) / 3 ];
                                if ( Object.keys( objEvolutionTypes ).indexOf( evoTypeID.toString() ) !== -1 ) {
                                    pinIcon.attr( 'src', pinIcon.attr( 'src' ).replace( guessEvoType, objEvolutionTypes[ evoTypeID ][ evolution - 1 ] ) );
                                }
                            }
                            let guessType = pinIcon.attr( 'src' ).split( /https?:\/\/munzee\.global\.ssl\.fastly\.net\/images\/pins\//i )[ 1 ].split( '.' )[ 0 ];
                            if ( arrUndefinedTypes.indexOf( guessType ) !== -1 ) {
                                pinIcon.attr( 'src', pinIcon.attr( 'src' ).replace( guessType, guessType + ( isTreehouse ? '_physical' : '_virtual' ) ) );
                            }
                        } );
                    } );
                } );
            }
        }
    } catch ( errScript ) {
        log( 0, 'error', 'Encountered an error: %o', errScript );
        var notifyAuthor = confirm( scriptName + '\n\tERROR!\t\t(details in console)\n\tPlease press [Cancel] and update the script\n\t\tbefore pressing [OK] to notify the author\n\t\tas there may already be a fix!\n\n\t\t\t\tThanks!' );
        if ( notifyAuthor ) {
            window.location.href = 'https://www.munzee.com/flows/?username=technical13&report=' + encodeURIComponent( 'Version: ' + scriptName + '\nPage: ' + window.location.href + '\nUserAgent: ' + navigator.userAgent + '\nError: ' + errScript + '\n Reporter comments: none' );
        }
    }
} )();