<commit_before>/* Meteor Falls v0.8 Scripts.
    By: [VP]Blade, TheUnknownOne, Ethan
    Credit to: Max, Lutra
*/

var Config = {
    // Configuration for the script.
    maintainers: ['[VP]Blade', 'Ethan', 'TheUnknownOne'],

    // Repo to load plugins from.
    repourl: "https://raw.github.com/meteor-falls/Scripts/master/plugins/",
    // Repo to load data (announcement/description + tiers) from.
    dataurl: "https://raw.github.com/meteor-falls/Server-Shit/master/",

    // Plugin directory.
    plugindir: "plugins/",

    // Do not touch unless you are adding a new plugin.
    // Plugins to load on script load.
    plugins: ['bot', 'reg', 'utils', 'emotes', 'feedmon', 'lists', 'init', 'commands', 'events', 'mathjs'],

    // Whether or not to load plugins from repourl. If set to false, they will load locally.
    load_from_web: true,
    // If HTML should be stripped from channel messages outputted onto the server window.
    stripHtmlFromChannelMessages: true,
    // If emotes are enabled.
    emotesEnabled: true
};

var GLOBAL = this;

(function() {
    var dir = Config.plugindir;
    sys.makeDir(dir);

    require = function require(name, webcall, noCache) {
        if ((name in require.cache) && !webcall && (require.meta[name] ? (!require.meta[name].preferCache && !noCache) : !noCache)) {
            return require.cache[name];
        }

        var fileContent,
            resp;

        if (webcall) {
            resp = sys.synchronousWebCall(Config.repourl + name);
            sys.writeToFile(dir + name, resp);
        }

        fileContent = sys.getFileContent(dir + name);

        if (!fileContent) {
            return false;
        }

        var module = {
            exports: {},
            reload: function () { return false; },
            name: name
        };
        var exports = module.exports;

        try {
            sys.eval(fileContent, dir + name);
        } catch (e) {
            sys.sendAll("Error loading module " + name + ": " + e + " on line " + e.lineNumber);
            print(e.backtracetext);
            throw e;
        }

        print("Loaded module " + name);

        require.cache[name] = module.exports;
        require.meta[name] = module;
        return module.exports;
    };

    require.reload = function require_reload(name) {
        require(name, false, false);
        return require.meta[name].reload();
    };

    if (typeof require.cache === 'undefined' || (typeof FULLRELOAD === 'boolean' && FULLRELOAD === true)) {
        require.cache = {};
        require.meta  = {};
    }

    FULLRELOAD = false;

    require.callPlugins = function require_callPlugins(event) {
        var args = [].slice.call(arguments, 1);
        var plugins = this.meta,
            plugin,
            exports;

        for (plugin in plugins) {
            exports = plugins[plugin].exports;
            if (exports.hasOwnProperty(event)) {
                try {
                    exports[event].apply(exports, args);
                } catch (e) {
                    print("Plugin error (" + plugins[plugin].name + ") on line " + e.lineNumber + ": " + e);
                    print(e.backtracetext);
                }
            }
        }
    };

    var plugin,
        i;

    for (i = 0; i < Config.plugins.length; i += 1) {
        plugin = Config.plugins[i] + ".js";
        require(plugin, Config.load_from_web);
    }
}());

var ignoreNextChanMsg = false;

function poUser(id) {
    var ip = sys.ip(id);

    this.id = id;
    this.ip = ip;
    this.floodCount = 0;
    this.caps = 0;
    this.muted = false;

    this.originalName = sys.name(id);
    this.megauser = false;

    // This is an array so we can track multiple emotes in their last message.
    this.lastEmote = [];
}

function poChannel(chanId) {
    this.id = chanId;
    this.name = sys.channel(chanId);

    this.bots = true;
}

SESSION.identifyScriptAs("Meteor Falls Script v0.8");
SESSION.registerUserFactory(poUser);
SESSION.registerChannelFactory(poChannel);
SESSION.refill();

var poScript;
poScript = ({
    serverStartUp: function serverStartUp() {
        startUpTime = +sys.time();
        script.init();
    },
    init: function init() {
        require.reload('utils.js');

        require.reload('reg.js');
        require.reload('bot.js');
        require.reload('feedmon.js');

        require.reload('init.js');

        require.reload('emotes.js');
        require.reload('lists.js');

        MathJS = require('mathjs.js');
    },
    warning: function warning(func, message, backtrace) {
        require.callPlugins("warning", func, message, backtrace);
    },
    beforeNewMessage: function beforeNewMessage(message) {
        require.callPlugins("beforeNewMessage", message);
    },

    afterNewMessage: function afterNewMessage(message) {
        require.callPlugins("afterNewMessage", message);
    },

    beforeServerMessage: function (message) {
        require.callPlugins("beforeServerMessage", message);
    },

    beforeChannelJoin: function beforeChannelJoin(src, channel) {
        require.callPlugins("beforeChannelJoin", src, channel);
    },

    beforeChannelDestroyed: function beforeChannelDestroyed(channel) {
        require.callPlugins("beforeChannelDestroyed", channel);
    },

    megauserCheck: function megauserCheck(src) {
        SESSION.users(src).megauser = MegaUsers.hasOwnProperty(sys.name(src).toLowerCase());
    },

    afterChannelCreated: function afterChannelCreated(chan, name, src) {
    },

    afterChannelJoin: function afterChannelJoin(src, chan) {
        require.callPlugins("afterChannelJoin", src, chan);
    },

    beforeLogIn: function beforeLogIn(src) {
        require.callPlugins("beforeLogIn", src);
    },
    afterLogIn: function afterLogIn(src, defaultChan) {
        require.callPlugins("afterLogIn", src, defaultChan);
    },
    beforeChangeTier: function(src, team, oldtier, newtier) {
        require.callPlugins("beforeChangeTier", src, team, oldtier, newtier);
    },

    beforeChangeTeam: function beforeChangeTeam(src) {
        require.callPlugins("beforeChangeTeam", src);
    },

    beforeChatMessage: function beforeChatMessage(src, message, chan) {
        require.callPlugins("beforeChatMessage", src, message, chan);
    },

    beforeLogOut: function beforeLogOut(src) {
        require.callPlugins("beforeLogOut", src);
    },

    afterChangeTeam: function afterChangeTeam(src) {
        require.callPlugins("afterChangeTeam", src);
    },

    beforePlayerKick: function beforePlayerKick(src, bpl) {
        require.callPlugins("beforePlayerKick", src, bpl);
    },

    beforePlayerBan: function beforePlayerBan(src, bpl, time) {
        require.callPlugins("beforePlayerBan", src, bpl, time);
    },

    beforeChallengeIssued: function beforeChallengeIssued(src, dest) {
        require.callPlugins("beforeChallengeIssued", src, dest);
    },

    afterPlayerAway: function afterPlayerAway(src, mode) {
    },

    beforeBattleMatchup: function beforeBattleMatchup(src, dest, clauses, rated, mode, team1, team2) {
        require.callPlugins("beforeBattleMatchup", src, dest, clauses, rated, mode, team1, team2);
    },

    tourSpots: function tourSpots() {
        return tournumber - tourmembers.length;
    },

    roundPairing: function roundPairing() {
        roundnumber += 1;
        battlesStarted = [];
        tourbattlers = [];
        battlesLost = [];
        if (tourmembers.length === 1) {
            sys.sendHtmlAll("

Congratulations, " + Utils.escapeHtml(tourplayers[tourmembers[0]]) + "!

You won the tournament! You win " + prize + "!

", 0);
            tourmode = 0;
            isFinals = false;
            return;
        }
        var str;
        var finals = tourmembers.length === 2;
        if (!finals) {
            str = "

Round " + roundnumber + " of " + tourtier + " tournament!
Current Matchups
";
        } else {
            isFinals = true;
            str = "

Finals of " + tourtier + " tournament!
Matchup
";
        }
        var i = 0;
        while (tourmembers.length >= 2) {
            i += 1;
            var x1 = sys.rand(0, tourmembers.length);
            tourbattlers.push(tourmembers[x1]);
            var name1 = tourplayers[tourmembers[x1]];
            tourmembers.splice(x1, 1);
            x1 = sys.rand(0, tourmembers.length);
            tourbattlers.push(tourmembers[x1]);
            var name2 = tourplayers[tourmembers[x1]];
            tourmembers.splice(x1, 1);
            battlesStarted.push(false);
            str += Utils.escapeHtml(name1) + " vs " + Utils.escapeHtml(name2) + "
";
        }
        if (tourmembers.length > 0) {
            str += "
" + Utils.escapeHtml(tourplayers[tourmembers[0]]) + " is randomly selected to go next round!
";
        }
        str += "

";
        sys.sendHtmlAll(str, 0);
    },

    isInTourney: function isInTourney(name) {
        return tourplayers.hasOwnProperty(name.toLowerCase());
    },

    tourOpponent: function tourOpponent(nam) {
        var name = nam.toLowerCase();
        var x = tourbattlers.indexOf(name);
        if (x !== -1) {
            if (x % 2 === 0) {
                return tourbattlers[x + 1];
            } else {
                return tourbattlers[x - 1];
            }
        }
        return "";
    },

    areOpponentsForTourBattle: function areOpponentsForTourBattle(src, dest) {
        return script.isInTourney(sys.name(src)) && script.isInTourney(sys.name(dest)) && script.tourOpponent(sys.name(src)) === sys.name(dest).toLowerCase();
    },

    areOpponentsForTourBattle2: function areOpponentsForTourBattle2(src, dest) {
        return script.isInTourney(src) && script.isInTourney(dest) && script.tourOpponent(src) === dest.toLowerCase();
    },

    ongoingTourneyBattle: function ongoingTourneyBattle(name) {
        return tourbattlers.indexOf(name.toLowerCase()) !== -1 && battlesStarted[Math.floor(tourbattlers.indexOf(name.toLowerCase()) / 2)] === true;
    },

    afterBattleStarted: function afterBattleStarted(src, dest, info, id, t1, t2) {
        if (tourmode === 2) {
            if (script.areOpponentsForTourBattle(src, dest)) {
                if (getTier(src, tourtier) && getTier(dest, tourtier)) {
                    battlesStarted[Math.floor(tourbattlers.indexOf(sys.name(src).toLowerCase()) / 2)] = true;
                }
            }
        }
    },

    afterBattleEnded: function afterBattleEnded(src, dest, desc) {
        if (tourmode !== 2 || desc === "tie") {
            return;
        }

        script.tourBattleEnd(sys.name(src), sys.name(dest));
    },

    afterChatMessage: function afterChatMessage(src, message, chan) {
        require.callPlugins("afterChatMessage", src, message, chan);
    },

    beforePlayerRegister: function (src) {
        Utils.watch.notify(Utils.nameIp(src) + " registered.");
    },

    tourBattleEnd: function tourBattleEnd(src, dest) {
        if (!script.areOpponentsForTourBattle2(src, dest) || !script.ongoingTourneyBattle(src)) {
            return;
        }

        battlesLost.push(src);
        battlesLost.push(dest);
        var srcL = src.toLowerCase();
        var destL = dest.toLowerCase();
        battlesStarted.splice(Math.floor(tourbattlers.indexOf(srcL) / 2), 1);
        tourbattlers.splice(tourbattlers.indexOf(srcL), 1);
        tourbattlers.splice(tourbattlers.indexOf(destL), 1);
        tourmembers.push(srcL);
        delete tourplayers[destL];
        var str = "";
        if (tourbattlers.length !== 0 || tourmembers.length > 1) {
            str = "

Battle Completed!

";
            str += "" + Utils.escapeHtml(Utils.toCorrectCase(src)) + " won their battle and moves on to the next round.

" + Utils.escapeHtml(Utils.toCorrectCase(dest)) + " lost their battle and is out of the tournament.";
        }
        if (tourbattlers.length > 0) {
            str += "

" + tourbattlers.length / 2 + "  battle(s) remaining!";
            str += "

";
            sys.sendHtmlAll(str, 0);
            return;
        }

        if (str.length > 0) {
            sys.sendHtmlAll(str + "

", 0);
        }

        script.roundPairing();
    },

    dreamAbilityCheck: function dreamAbilityCheck(src) {
        var bannedAbilities = {
            'chandelure': ['shadow tag']
        };

        var i;
        for (i = 0; i < sys.teamCount(src); i += 1) {
            var ability = sys.ability(sys.teamPokeAbility(src, i, i));
            var lability = ability.toLowerCase();
            var poke = sys.pokemon(sys.teamPoke(src, i, i));
            var lpoke = poke.toLowerCase();
            if (bannedAbilities.hasOwnProperty(lpoke) && bannedAbilities[lpoke].indexOf(lability) !== -1) {
                bot.sendMessage(src, poke + " is not allowed to have ability " + ability + " in 5th Gen x Tier. Please change it in Teambuilder. You are now in the Random Battle tier.");
                return true;
            }
        }

        return false;
    }
});
<commit_msg>Init: reset profiles<commit_after>/* Meteor Falls v0.8 Scripts.
    By: [VP]Blade, TheUnknownOne, Ethan
    Credit to: Max, Lutra
*/

var Config = {
    // Configuration for the script.
    maintainers: ['[VP]Blade', 'Ethan', 'TheUnknownOne'],

    // Repo to load plugins from.
    repourl: "https://raw.github.com/meteor-falls/Scripts/master/plugins/",
    // Repo to load data (announcement/description + tiers) from.
    dataurl: "https://raw.github.com/meteor-falls/Server-Shit/master/",

    // Plugin directory.
    plugindir: "plugins/",

    // Do not touch unless you are adding a new plugin.
    // Plugins to load on script load.
    plugins: ['bot', 'reg', 'utils', 'emotes', 'feedmon', 'lists', 'init', 'commands', 'events', 'mathjs'],

    // Whether or not to load plugins from repourl. If set to false, they will load locally.
    load_from_web: true,
    // If HTML should be stripped from channel messages outputted onto the server window.
    stripHtmlFromChannelMessages: true,
    // If emotes are enabled.
    emotesEnabled: true
};

var GLOBAL = this;

(function() {
    var dir = Config.plugindir;
    sys.makeDir(dir);

    require = function require(name, webcall, noCache) {
        if ((name in require.cache) && !webcall && (require.meta[name] ? (!require.meta[name].preferCache && !noCache) : !noCache)) {
            return require.cache[name];
        }

        var fileContent,
            resp;

        if (webcall) {
            resp = sys.synchronousWebCall(Config.repourl + name);
            sys.writeToFile(dir + name, resp);
        }

        fileContent = sys.getFileContent(dir + name);

        if (!fileContent) {
            return false;
        }

        var module = {
            exports: {},
            reload: function () { return false; },
            name: name
        };
        var exports = module.exports;

        try {
            sys.eval(fileContent, dir + name);
        } catch (e) {
            sys.sendAll("Error loading module " + name + ": " + e + " on line " + e.lineNumber);
            print(e.backtracetext);
            throw e;
        }

        print("Loaded module " + name);

        require.cache[name] = module.exports;
        require.meta[name] = module;
        return module.exports;
    };

    require.reload = function require_reload(name) {
        require(name, false, false);
        return require.meta[name].reload();
    };

    if (typeof require.cache === 'undefined' || (typeof FULLRELOAD === 'boolean' && FULLRELOAD === true)) {
        require.cache = {};
        require.meta  = {};
    }

    FULLRELOAD = false;

    require.callPlugins = function require_callPlugins(event) {
        var args = [].slice.call(arguments, 1);
        var plugins = this.meta,
            plugin,
            exports;

        for (plugin in plugins) {
            exports = plugins[plugin].exports;
            if (exports.hasOwnProperty(event)) {
                try {
                    exports[event].apply(exports, args);
                } catch (e) {
                    print("Plugin error (" + plugins[plugin].name + ") on line " + e.lineNumber + ": " + e);
                    print(e.backtracetext);
                }
            }
        }
    };

    var plugin,
        i;

    for (i = 0; i < Config.plugins.length; i += 1) {
        plugin = Config.plugins[i] + ".js";
        require(plugin, Config.load_from_web);
    }
}());

var ignoreNextChanMsg = false;

function poUser(id) {
    var ip = sys.ip(id);

    this.id = id;
    this.ip = ip;
    this.floodCount = 0;
    this.caps = 0;
    this.muted = false;

    this.originalName = sys.name(id);
    this.megauser = false;

    // This is an array so we can track multiple emotes in their last message.
    this.lastEmote = [];
}

function poChannel(chanId) {
    this.id = chanId;
    this.name = sys.channel(chanId);

    this.bots = true;
}

SESSION.identifyScriptAs("Meteor Falls Script v0.8");
SESSION.registerUserFactory(poUser);
SESSION.registerChannelFactory(poChannel);
SESSION.refill();

var poScript;
poScript = ({
    serverStartUp: function serverStartUp() {
        startUpTime = +sys.time();
        script.init();
    },
    init: function init() {
        require.reload('utils.js');

        require.reload('reg.js');
        require.reload('bot.js');
        require.reload('feedmon.js');

        require.reload('init.js');

        require.reload('emotes.js');
        require.reload('lists.js');

        MathJS = require('mathjs.js');
        sys.resetProfiling();
    },
    warning: function warning(func, message, backtrace) {
        require.callPlugins("warning", func, message, backtrace);
    },
    beforeNewMessage: function beforeNewMessage(message) {
        require.callPlugins("beforeNewMessage", message);
    },

    afterNewMessage: function afterNewMessage(message) {
        require.callPlugins("afterNewMessage", message);
    },

    beforeServerMessage: function (message) {
        require.callPlugins("beforeServerMessage", message);
    },

    beforeChannelJoin: function beforeChannelJoin(src, channel) {
        require.callPlugins("beforeChannelJoin", src, channel);
    },

    beforeChannelDestroyed: function beforeChannelDestroyed(channel) {
        require.callPlugins("beforeChannelDestroyed", channel);
    },

    megauserCheck: function megauserCheck(src) {
        SESSION.users(src).megauser = MegaUsers.hasOwnProperty(sys.name(src).toLowerCase());
    },

    afterChannelCreated: function afterChannelCreated(chan, name, src) {
    },

    afterChannelJoin: function afterChannelJoin(src, chan) {
        require.callPlugins("afterChannelJoin", src, chan);
    },

    beforeLogIn: function beforeLogIn(src) {
        require.callPlugins("beforeLogIn", src);
    },
    afterLogIn: function afterLogIn(src, defaultChan) {
        require.callPlugins("afterLogIn", src, defaultChan);
    },
    beforeChangeTier: function(src, team, oldtier, newtier) {
        require.callPlugins("beforeChangeTier", src, team, oldtier, newtier);
    },

    beforeChangeTeam: function beforeChangeTeam(src) {
        require.callPlugins("beforeChangeTeam", src);
    },

    beforeChatMessage: function beforeChatMessage(src, message, chan) {
        require.callPlugins("beforeChatMessage", src, message, chan);
    },

    beforeLogOut: function beforeLogOut(src) {
        require.callPlugins("beforeLogOut", src);
    },

    afterChangeTeam: function afterChangeTeam(src) {
        require.callPlugins("afterChangeTeam", src);
    },

    beforePlayerKick: function beforePlayerKick(src, bpl) {
        require.callPlugins("beforePlayerKick", src, bpl);
    },

    beforePlayerBan: function beforePlayerBan(src, bpl, time) {
        require.callPlugins("beforePlayerBan", src, bpl, time);
    },

    beforeChallengeIssued: function beforeChallengeIssued(src, dest) {
        require.callPlugins("beforeChallengeIssued", src, dest);
    },

    afterPlayerAway: function afterPlayerAway(src, mode) {
    },

    beforeBattleMatchup: function beforeBattleMatchup(src, dest, clauses, rated, mode, team1, team2) {
        require.callPlugins("beforeBattleMatchup", src, dest, clauses, rated, mode, team1, team2);
    },

    tourSpots: function tourSpots() {
        return tournumber - tourmembers.length;
    },

    roundPairing: function roundPairing() {
        roundnumber += 1;
        battlesStarted = [];
        tourbattlers = [];
        battlesLost = [];
        if (tourmembers.length === 1) {
            sys.sendHtmlAll("

Congratulations, " + Utils.escapeHtml(tourplayers[tourmembers[0]]) + "!

You won the tournament! You win " + prize + "!

", 0);
            tourmode = 0;
            isFinals = false;
            return;
        }
        var str;
        var finals = tourmembers.length === 2;
        if (!finals) {
            str = "

Round " + roundnumber + " of " + tourtier + " tournament!
Current Matchups
";
        } else {
            isFinals = true;
            str = "

Finals of " + tourtier + " tournament!
Matchup
";
        }
        var i = 0;
        while (tourmembers.length >= 2) {
            i += 1;
            var x1 = sys.rand(0, tourmembers.length);
            tourbattlers.push(tourmembers[x1]);
            var name1 = tourplayers[tourmembers[x1]];
            tourmembers.splice(x1, 1);
            x1 = sys.rand(0, tourmembers.length);
            tourbattlers.push(tourmembers[x1]);
            var name2 = tourplayers[tourmembers[x1]];
            tourmembers.splice(x1, 1);
            battlesStarted.push(false);
            str += Utils.escapeHtml(name1) + " vs " + Utils.escapeHtml(name2) + "
";
        }
        if (tourmembers.length > 0) {
            str += "
" + Utils.escapeHtml(tourplayers[tourmembers[0]]) + " is randomly selected to go next round!
";
        }
        str += "

";
        sys.sendHtmlAll(str, 0);
    },

    isInTourney: function isInTourney(name) {
        return tourplayers.hasOwnProperty(name.toLowerCase());
    },

    tourOpponent: function tourOpponent(nam) {
        var name = nam.toLowerCase();
        var x = tourbattlers.indexOf(name);
        if (x !== -1) {
            if (x % 2 === 0) {
                return tourbattlers[x + 1];
            } else {
                return tourbattlers[x - 1];
            }
        }
        return "";
    },

    areOpponentsForTourBattle: function areOpponentsForTourBattle(src, dest) {
        return script.isInTourney(sys.name(src)) && script.isInTourney(sys.name(dest)) && script.tourOpponent(sys.name(src)) === sys.name(dest).toLowerCase();
    },

    areOpponentsForTourBattle2: function areOpponentsForTourBattle2(src, dest) {
        return script.isInTourney(src) && script.isInTourney(dest) && script.tourOpponent(src) === dest.toLowerCase();
    },

    ongoingTourneyBattle: function ongoingTourneyBattle(name) {
        return tourbattlers.indexOf(name.toLowerCase()) !== -1 && battlesStarted[Math.floor(tourbattlers.indexOf(name.toLowerCase()) / 2)] === true;
    },

    afterBattleStarted: function afterBattleStarted(src, dest, info, id, t1, t2) {
        if (tourmode === 2) {
            if (script.areOpponentsForTourBattle(src, dest)) {
                if (getTier(src, tourtier) && getTier(dest, tourtier)) {
                    battlesStarted[Math.floor(tourbattlers.indexOf(sys.name(src).toLowerCase()) / 2)] = true;
                }
            }
        }
    },

    afterBattleEnded: function afterBattleEnded(src, dest, desc) {
        if (tourmode !== 2 || desc === "tie") {
            return;
        }

        script.tourBattleEnd(sys.name(src), sys.name(dest));
    },

    afterChatMessage: function afterChatMessage(src, message, chan) {
        require.callPlugins("afterChatMessage", src, message, chan);
    },

    beforePlayerRegister: function (src) {
        Utils.watch.notify(Utils.nameIp(src) + " registered.");
    },

    tourBattleEnd: function tourBattleEnd(src, dest) {
        if (!script.areOpponentsForTourBattle2(src, dest) || !script.ongoingTourneyBattle(src)) {
            return;
        }

        battlesLost.push(src);
        battlesLost.push(dest);
        var srcL = src.toLowerCase();
        var destL = dest.toLowerCase();
        battlesStarted.splice(Math.floor(tourbattlers.indexOf(srcL) / 2), 1);
        tourbattlers.splice(tourbattlers.indexOf(srcL), 1);
        tourbattlers.splice(tourbattlers.indexOf(destL), 1);
        tourmembers.push(srcL);
        delete tourplayers[destL];
        var str = "";
        if (tourbattlers.length !== 0 || tourmembers.length > 1) {
            str = "

Battle Completed!

";
            str += "" + Utils.escapeHtml(Utils.toCorrectCase(src)) + " won their battle and moves on to the next round.

" + Utils.escapeHtml(Utils.toCorrectCase(dest)) + " lost their battle and is out of the tournament.";
        }
        if (tourbattlers.length > 0) {
            str += "

" + tourbattlers.length / 2 + "  battle(s) remaining!";
            str += "

";
            sys.sendHtmlAll(str, 0);
            return;
        }

        if (str.length > 0) {
            sys.sendHtmlAll(str + "

", 0);
        }

        script.roundPairing();
    },

    dreamAbilityCheck: function dreamAbilityCheck(src) {
        var bannedAbilities = {
            'chandelure': ['shadow tag']
        };

        var i;
        for (i = 0; i < sys.teamCount(src); i += 1) {
            var ability = sys.ability(sys.teamPokeAbility(src, i, i));
            var lability = ability.toLowerCase();
            var poke = sys.pokemon(sys.teamPoke(src, i, i));
            var lpoke = poke.toLowerCase();
            if (bannedAbilities.hasOwnProperty(lpoke) && bannedAbilities[lpoke].indexOf(lability) !== -1) {
                bot.sendMessage(src, poke + " is not allowed to have ability " + ability + " in 5th Gen x Tier. Please change it in Teambuilder. You are now in the Random Battle tier.");
                return true;
            }
        }

        return false;
    }
});
<|endoftext|>


<commit_before>/* By Luke Cahill - 10/11/15*/

$(document).ready(function() {

	var lastMessage = 0;
	$('.welcome').hide();
	//getMessages();

	function getMessages() {
		// get the message here

		$.ajax({
			method: 'POST',
			url: 'get.php',
			data: { lastmessage: lastMessage}
		}).done(function(message) {
			var $chatbox = $('#chatbox');
			$chatbox.append(message);
			$chatbox.animate({ scrollTop: $chatbox.prop('scrollHeight')}, 750)
		});
	};

	function checkForNewMessage() {
		$.ajax({
			method: 'POST',
			url: 'check.php',
			data: { lastmessage: lastMessage }
		}).done(function(data) {
			var recievedData = $.parseJSON(data);
			$('.loading').hide();
			if(recievedData.result == true) {
				getMessages();
				lastMessage = (recievedData.rownumber);
				recievedData = '';
			}

		}).fail(function() {
			console.log("Failed to check for new messages");
		});
	};

	function sendMessage() {
		// post the message here
		var message = $('#message').val()
		var name = $('#name').val();

		$.ajax({
		   method: 'POST',
		   url: 'post.php',
		   data: { message: message, name: name}
		}).done(function(done) {
		   checkForNewMessage();
		});
	};

	// Get the new messages every 2.5 seconds. Trying to reduce the database load.
	var getMessageInterval = setInterval(function() {
		checkForNewMessage();
	}, 2500);

	var stop = function() {
		clearInterval(getMessageInterval);
	};

	// Used to clear the message box.
	var clearTextbox = function() {
		$('#message').val('');
		$('#wordCount').html('');
	};

	var checkForName = function() {
		$name = $.trim($('#name').val());
		if($name == '') {
			return false;
		} else {
			return true;
		}
	};

	var setName = function() {
		$name = $.trim($('#name').val());
		$welcome = $('.welcome');
		if($name !== '') {
			$welcome.html('Welcome, ' + $name + '');
			$('#setYourName').hide();
			$welcome.show();
		} else {
			alert('Name cannot be blank!');
		}
	};

	// When the send message button is clicked.
    $('#sendMessage').on('click', function() {
		if(checkForName()) {
			sendMessage();
			clearTextbox();
		} else {
			alert("Please enter your name");
		}
    });

	// When the enter key is clicked.
	$('#message').on('keyup', function(event) {
		if(event.keyCode == 13) {
			if(checkForName()) {
				sendMessage();
				clearTextbox();
			} else {
				alert("Please enter your name");
			}
		}

		var re = new RegExp("\s+");
		var $message = $('#message');
		if($message.val().indexOf(' ') > -1) {
			var split = $message.val().split(' ');
			var length = split.length - 1;
			$('#wordCount').html('Current length: ' + length);
		} else {
			console.log("wut")
		}
	});

	// Set your chat name
	$('#setName').on('click', function() {
		setName();
	});

	$('#name').on('keyup', function(event) {
		if(event.keyCode == 13) {
			setName();
		}
	});

	$('#aboutButton').on('click', function() {
		alert('Created using HTML, CSS using bootstrap, JavaScript with jQuery, and PHP for the backend to post into the MySQL database.\n\nGets the new messages every 2.5 seconds, this could be improved, but this is mostly just a prototype.');
	});

	$('#chatbox').delegate('.unread', 'mouseover', function() {
		$(this).removeClass('unread');
	});
});<commit_msg>Remove redundant else statement<commit_after>/* By Luke Cahill - 10/11/15*/

$(document).ready(function() {

	var lastMessage = 0;
	$('.welcome').hide();
	//getMessages();

	function getMessages() {
		// get the message here

		$.ajax({
			method: 'POST',
			url: 'get.php',
			data: { lastmessage: lastMessage}
		}).done(function(message) {
			var $chatbox = $('#chatbox');
			$chatbox.append(message);
			$chatbox.animate({ scrollTop: $chatbox.prop('scrollHeight')}, 750)
		});
	};

	function checkForNewMessage() {
		$.ajax({
			method: 'POST',
			url: 'check.php',
			data: { lastmessage: lastMessage }
		}).done(function(data) {
			var recievedData = $.parseJSON(data);
			$('.loading').hide();
			if(recievedData.result == true) {
				getMessages();
				lastMessage = (recievedData.rownumber);
				recievedData = '';
			}

		}).fail(function() {
			console.log("Failed to check for new messages");
		});
	};

	function sendMessage() {
		// post the message here
		var message = $('#message').val()
		var name = $('#name').val();

		$.ajax({
		   method: 'POST',
		   url: 'post.php',
		   data: { message: message, name: name}
		}).done(function(done) {
		   checkForNewMessage();
		});
	};

	// Get the new messages every 2.5 seconds. Trying to reduce the database load.
	var getMessageInterval = setInterval(function() {
		checkForNewMessage();
	}, 2500);

	var stop = function() {
		clearInterval(getMessageInterval);
	};

	// Used to clear the message box.
	var clearTextbox = function() {
		$('#message').val('');
		$('#wordCount').html('');
	};

	var checkForName = function() {
		$name = $.trim($('#name').val());
		if($name == '') {
			return false;
		} else {
			return true;
		}
	};

	var setName = function() {
		$name = $.trim($('#name').val());
		$welcome = $('.welcome');
		if($name !== '') {
			$welcome.html('Welcome, ' + $name + '');
			$('#setYourName').hide();
			$welcome.show();
		} else {
			alert('Name cannot be blank!');
		}
	};

	// When the send message button is clicked.
    $('#sendMessage').on('click', function() {
		if(checkForName()) {
			sendMessage();
			clearTextbox();
		} else {
			alert("Please enter your name");
		}
    });

	// When the enter key is clicked.
	$('#message').on('keyup', function(event) {
		if(event.keyCode == 13) {
			if(checkForName()) {
				sendMessage();
				clearTextbox();
			} else {
				alert("Please enter your name");
			}
		}

		var re = new RegExp("\s+");
		var $message = $('#message');
		if($message.val().indexOf(' ') > -1) {
			var split = $message.val().split(' ');
			var length = split.length - 1;
			$('#wordCount').html('Current length: ' + length);
		}
	});

	// Set your chat name
	$('#setName').on('click', function() {
		setName();
	});

	$('#name').on('keyup', function(event) {
		if(event.keyCode == 13) {
			setName();
		}
	});

	$('#aboutButton').on('click', function() {
		alert('Created using HTML, CSS using bootstrap, JavaScript with jQuery, and PHP for the backend to post into the MySQL database.\n\nGets the new messages every 2.5 seconds, this could be improved, but this is mostly just a prototype.');
	});

	$('#chatbox').delegate('.unread', 'mouseover', function() {
		$(this).removeClass('unread');
	});
});<|endoftext|>


<commit_before>/*jslint on: true, eqeqeq: true */
/*
	TODOs:

	Fo sho:
		- The buffer is actually loading all the images at the same time, only load the next one on page.onload
		- Show a progress bar when buffering
		- use document.body.offsetWidth where present? (instead of window.innerWidth, the former excludes the width of scrollbars)
		- scroll two pages at a time in double page mode
		- manga mode
		- page controls
		- thumbnail browser
		- chrome frame

	Nice 2 have:
		- remember position (use localStorage)
		- maybe use local storage for the pages array too? might be easier to implement manga mode with that
		- offline mode
		- page turn animation

*/

/**
 * Merge two arrays. Any properties in b will replace the same properties in
 * a. New properties from b will be added to a.
 *
 * @param a {Object}
 * @param b {Object}
 */
function merge(a, b) {

	var prop;

	if (typeof b === "undefined") { b = {}; }

	for (prop in a) {
		if (a.hasOwnProperty(prop)) {
			if (prop in b) { continue; }
			b[prop] = a[prop];
		}
	}

	return b;
}

function ComicBook(id, srcs, opts) {

	this.id = id;		// canvas element id
	this.srcs = srcs;	// array of image srcs for pages

	var defaults = {
		displayMode: "double",	// single / double
		zoomMode: "fitWidth"	// manual / fitWidth
	};

	var options = merge(defaults, opts); // options array for internal use

	var pages = [];		// array of preloaded Image objects
	var canvas;			// the HTML5 canvas object
	var context;		// the 2d drawing context

	var buffer = 4;		// image preload buffer level
	var pointer = 0;	// the current page
	var loaded = 0;		// the amount of images that have been loaded so far

	var scale = 1;		// page zoom scale, 1 = 100%

	/**
	 * Figure out the cursor position relative to the canvas.
	 *
	 * Thanks to: Mark Pilgrim & http://diveintohtml5.org/canvas.html
	 */
	function getCursorPosition(e) {

		var x; // horizontal cursor position

		// check if page relative positions exist, if not figure them out
		if (e.pageX) {
			x = e.pageX;
		} else {
			x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
		}

		// make the position relative to the canvas
		x -= canvas.offsetLeft;

		// check if the user clicked on the left or right side
		return (x <= canvas.width / 2) ? 'left' : 'right';
	}

	/*
	 * @param {String} id The canvas ID to draw the comic on.
	 * @param {Object} srcs An array of all the comic page srcs, in order
	 * @see #preload
	 */
	ComicBook.prototype.draw = function () {

		// setup canvas
		canvas = document.getElementById(this.id);
		context = canvas.getContext("2d");

		// preload images if needed
		if (pages.length !== this.srcs.length) { this.preload(this.srcs); }
		else { this.drawPage(); }

		// add page controls
		canvas.addEventListener("click", ComicBook.prototype.navigation, false);
	};

	/*
	 * Zoom the canvas
	 *
	 * @param new_scale {Number} Scale the canvas to this ratio
	 */
	ComicBook.prototype.zoom = function (new_scale) {
		options.zoomMode = "manual";
		scale = new_scale;
		if (typeof pages[pointer] === "object") { this.drawPage(); }
	};

	/**
	 * Preload all images, draw the page only after a given number have been loaded.
	 *
	 * @param srcs {Object} srcs
	 * @see #drawPage
	 */
	ComicBook.prototype.preload = function (srcs) {

		if (srcs.length < buffer) { buffer = srcs.length; } // don't get stuck if the buffer level is higher than the number of pages

		var i = 0; // the current page counter for this method

		// I am using recursion instead of a forEach loop so that the next image is
		// only loaded when the previous one has completely finished
		function preload(i) {

			var page = new Image();

			console.info("starting to load: " + srcs[i]);

			page.src = srcs[i];

			page.onload = function () {

				console.info("loaded: " + srcs[i]);

				pages[i] = this;
				loaded += 1;

				// there are still more pages to load, do it
				if (loaded < srcs.length) {
					i += 1;
					preload(i);
				}

				// start rendering the comic when the buffer level has been reached
				if (loaded === buffer + 1) { ComicBook.prototype.drawPage(); }
			};
		}

		if (i === 0) { preload(i); }
	};

	/**
	 * Draw the current page in the canvas
	 *
	 * TODO: break this down into drawSinglePage() & drawDoublePage()
	 * TODO: if the current browser doesn't have canvas support, use img tags
	 */
	ComicBook.prototype.drawPage = function () {

		var zoom_scale;
		var offsetW = 0, offsetH = 0;

		var page = pages[pointer];
		var page2 = pages[pointer + 1];

		if (typeof page !== "object") { throw "invalid page type '"+ typeof page +"'"; }

		var width = page.width;

		if (options.displayMode === "double") {

			// for double page spreads, factor in the width of both pages
			if (typeof page2 === "object") { width += page2.width; }

			// if this is the last page and there is no page2, still keep the canvas wide
			else { width += width; }
		}

		// update the page scale if a non manual mode has been chosen
		switch(options.zoomMode) {

			case "manual":
				zoom_scale = (options.displayMode === "double") ? scale * 2 : scale;
				break;

			case "fitWidth":
				zoom_scale =  (window.innerWidth > width) ? ((window.innerWidth - width) / window.innerWidth) + 1 // scale up if the window is wider than the page
					  : window.innerWidth / width; // scale down if the window is narrower than the page
				break;

			default:throw "invalid zoomMode";
		}

		var canvas_width  = page.width * zoom_scale;
		var canvas_height = page.height * zoom_scale;

		var page_width = (options.zoomMode === "manual") ? page.width * scale : canvas_width;
		var page_height = (options.zoomMode === "manual") ? page.height * scale : canvas_height;

		canvas_height = page_height;

		// make sure the canvas is always at least full screen, even if the page is more narrow than the screen
		canvas.width = (canvas_width < window.innerWidth) ? window.innerWidth : canvas_width;
		canvas.height = (canvas_height < window.innerHeight) ? window.innerHeight : canvas_height;

		// work out a horizonal position that will keep the pages always centred
		if (canvas_width < window.innerWidth && options.zoomMode === "manual") {
			offsetW = (window.innerWidth - page_width) / 2;
			if (options.displayMode === "double") { offsetW = offsetW - page_width / 2; }
		}

		// work out a vertical position that will keep the pages always centred
		if (canvas_height < window.innerHeight && options.zoomMode === "manual") {
			offsetH = (window.innerHeight - page_height) / 2;
		}

		// draw the page(s)
		context.drawImage(page, offsetW, offsetH, page_width, page_height);
		if (options.displayMode === "double" && typeof page2 === "object") { context.drawImage(page2, page_width + offsetW, offsetH, page_width, page_height); }

	};

	/**
	 * Increment the counter and draw the page in the canvas
	 *
	 * @see #drawPage
	 */
	ComicBook.prototype.drawNextPage = function () {
		if (pointer + 1 < pages.length) {
			pointer++;
			this.drawPage();
		}
	};

	/**
	 * Decrement the counter and draw the page in the canvas
	 *
	 * @see #drawPage
	 */
	ComicBook.prototype.drawPrevPage = function () {
		if (pointer > 0) {
			pointer--;
			this.drawPage();
		}
	};

	ComicBook.prototype.navigation = function (e) {

		if (e.type === "click") {
			switch (getCursorPosition(e)) {
				case "left": ComicBook.prototype.drawPrevPage(); break;
				case "right": ComicBook.prototype.drawNextPage(); break;
			}
		}
	};
}

var book;

window.onload = function() {

	var pages = [
		"http://dev.justforcomics.com/get/image/?f=comics/extracted/oni_whiteout_melt_1/00.jpg",
		"http://dev.justforcomics.com/get/image/?f=comics/extracted/oni_whiteout_melt_1/01.jpg",
		"http://dev.justforcomics.com/get/image/?f=comics/extracted/oni_whiteout_melt_1/02.jpg",
		"http://dev.justforcomics.com/get/image/?f=comics/extracted/oni_whiteout_melt_1/03.jpg",
		"http://dev.justforcomics.com/get/image/?f=comics/extracted/oni_whiteout_melt_1/04.jpg",
		"http://dev.justforcomics.com/get/image/?f=comics/extracted/oni_whiteout_melt_1/05.jpg",
		"http://dev.justforcomics.com/get/image/?f=comics/extracted/oni_whiteout_melt_1/06.jpg"
	];

	var options = {
		displayMode: "double",
		zoomMode: "fitWidth"
	};

	book = new ComicBook("comic", pages, options);
	book.draw();
};

window.onresize = function() {
	book.draw();
};
<commit_msg>image preloader now only loads one image at a time<commit_after>/*jslint on: true, eqeqeq: true */
/*
	TODOs:

	Fo sho:
		- The buffer is actually loading all the images at the same time, only load the next one on page.onload
		- Show a progress bar when buffering
		- use document.body.offsetWidth where present? (instead of window.innerWidth, the former excludes the width of scrollbars)
		- scroll two pages at a time in double page mode
		- manga mode
		- page controls
		- thumbnail browser
		- chrome frame

	Nice 2 have:
		- remember position (use localStorage)
		- maybe use local storage for the pages array too? might be easier to implement manga mode with that
		- offline mode
		- page turn animation

*/

/**
 * Merge two arrays. Any properties in b will replace the same properties in
 * a. New properties from b will be added to a.
 *
 * @param a {Object}
 * @param b {Object}
 */
function merge(a, b) {

	var prop;

	if (typeof b === "undefined") { b = {}; }

	for (prop in a) {
		if (a.hasOwnProperty(prop)) {
			if (prop in b) { continue; }
			b[prop] = a[prop];
		}
	}

	return b;
}

function ComicBook(id, srcs, opts) {

	this.id = id;		// canvas element id
	this.srcs = srcs;	// array of image srcs for pages

	var defaults = {
		displayMode: "double",	// single / double
		zoomMode: "fitWidth"	// manual / fitWidth
	};

	var options = merge(defaults, opts); // options array for internal use

	var pages = [];		// array of preloaded Image objects
	var canvas;			// the HTML5 canvas object
	var context;		// the 2d drawing context

	var buffer = 4;		// image preload buffer level
	var pointer = 0;	// the current page
	var loaded = 0;		// the amount of images that have been loaded so far

	var scale = 1;		// page zoom scale, 1 = 100%

	/**
	 * Figure out the cursor position relative to the canvas.
	 *
	 * Thanks to: Mark Pilgrim & http://diveintohtml5.org/canvas.html
	 */
	function getCursorPosition(e) {

		var x; // horizontal cursor position

		// check if page relative positions exist, if not figure them out
		if (e.pageX) {
			x = e.pageX;
		} else {
			x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
		}

		// make the position relative to the canvas
		x -= canvas.offsetLeft;

		// check if the user clicked on the left or right side
		return (x <= canvas.width / 2) ? 'left' : 'right';
	}

	/*
	 * @param {String} id The canvas ID to draw the comic on.
	 * @param {Object} srcs An array of all the comic page srcs, in order
	 * @see #preload
	 */
	ComicBook.prototype.draw = function () {

		// setup canvas
		canvas = document.getElementById(this.id);
		context = canvas.getContext("2d");

		// preload images if needed
		if (pages.length !== this.srcs.length) { this.preload(this.srcs); }
		else { this.drawPage(); }

		// add page controls
		canvas.addEventListener("click", ComicBook.prototype.navigation, false);
	};

	/*
	 * Zoom the canvas
	 *
	 * @param new_scale {Number} Scale the canvas to this ratio
	 */
	ComicBook.prototype.zoom = function (new_scale) {
		options.zoomMode = "manual";
		scale = new_scale;
		if (typeof pages[pointer] === "object") { this.drawPage(); }
	};

	/**
	 * Preload all images, draw the page only after a given number have been loaded.
	 *
	 * @param srcs {Object} srcs
	 * @see #drawPage
	 */
	ComicBook.prototype.preload = function (srcs) {

		if (srcs.length < buffer) { buffer = srcs.length; } // don't get stuck if the buffer level is higher than the number of pages

		var i = 0; // the current page counter for this method

		// I am using recursion instead of a forEach loop so that the next image is
		// only loaded when the previous one has completely finished
		function preload(i) {

			var page = new Image();

			// console.log("starting to load: " + srcs[i]);

			page.src = srcs[i];

			page.onload = function () {

				// console.info("loaded: " + srcs[i]);

				pages[i] = this;
				loaded += 1;

				// there are still more pages to load, do it
				if (loaded < srcs.length) {
					i += 1;
					preload(i);
				}

				// start rendering the comic when the buffer level has been reached
				if (loaded === buffer + 1) { ComicBook.prototype.drawPage(); }
				if (loaded === srcs.length) { /* console.log("all loaded"); */ }
			};
		}

		if (i === 0) { preload(i); }
	};

	/**
	 * Draw the current page in the canvas
	 *
	 * TODO: break this down into drawSinglePage() & drawDoublePage()
	 * TODO: if the current browser doesn't have canvas support, use img tags
	 */
	ComicBook.prototype.drawPage = function () {

		var zoom_scale;
		var offsetW = 0, offsetH = 0;

		var page = pages[pointer];
		var page2 = pages[pointer + 1];

		if (typeof page !== "object") { throw "invalid page type '"+ typeof page +"'"; }

		var width = page.width;

		if (options.displayMode === "double") {

			// for double page spreads, factor in the width of both pages
			if (typeof page2 === "object") { width += page2.width; }

			// if this is the last page and there is no page2, still keep the canvas wide
			else { width += width; }
		}

		// update the page scale if a non manual mode has been chosen
		switch(options.zoomMode) {

			case "manual":
				zoom_scale = (options.displayMode === "double") ? scale * 2 : scale;
				break;

			case "fitWidth":
				zoom_scale =  (window.innerWidth > width) ? ((window.innerWidth - width) / window.innerWidth) + 1 // scale up if the window is wider than the page
					  : window.innerWidth / width; // scale down if the window is narrower than the page
				break;

			default:throw "invalid zoomMode";
		}

		var canvas_width  = page.width * zoom_scale;
		var canvas_height = page.height * zoom_scale;

		var page_width = (options.zoomMode === "manual") ? page.width * scale : canvas_width;
		var page_height = (options.zoomMode === "manual") ? page.height * scale : canvas_height;

		canvas_height = page_height;

		// make sure the canvas is always at least full screen, even if the page is more narrow than the screen
		canvas.width = (canvas_width < window.innerWidth) ? window.innerWidth : canvas_width;
		canvas.height = (canvas_height < window.innerHeight) ? window.innerHeight : canvas_height;

		// work out a horizonal position that will keep the pages always centred
		if (canvas_width < window.innerWidth && options.zoomMode === "manual") {
			offsetW = (window.innerWidth - page_width) / 2;
			if (options.displayMode === "double") { offsetW = offsetW - page_width / 2; }
		}

		// work out a vertical position that will keep the pages always centred
		if (canvas_height < window.innerHeight && options.zoomMode === "manual") {
			offsetH = (window.innerHeight - page_height) / 2;
		}

		// draw the page(s)
		context.drawImage(page, offsetW, offsetH, page_width, page_height);
		if (options.displayMode === "double" && typeof page2 === "object") { context.drawImage(page2, page_width + offsetW, offsetH, page_width, page_height); }

	};

	/**
	 * Increment the counter and draw the page in the canvas
	 *
	 * @see #drawPage
	 */
	ComicBook.prototype.drawNextPage = function () {
		if (pointer + 1 < pages.length) {
			pointer++;
			this.drawPage();
		}
	};

	/**
	 * Decrement the counter and draw the page in the canvas
	 *
	 * @see #drawPage
	 */
	ComicBook.prototype.drawPrevPage = function () {
		if (pointer > 0) {
			pointer--;
			this.drawPage();
		}
	};

	ComicBook.prototype.navigation = function (e) {

		if (e.type === "click") {
			switch (getCursorPosition(e)) {
				case "left": ComicBook.prototype.drawPrevPage(); break;
				case "right": ComicBook.prototype.drawNextPage(); break;
			}
		}
	};
}

var book;

window.onload = function() {

	var pages = [
		"http://dev.justforcomics.com/get/image/?f=comics/extracted/oni_whiteout_melt_1/00.jpg",
		"http://dev.justforcomics.com/get/image/?f=comics/extracted/oni_whiteout_melt_1/01.jpg",
		"http://dev.justforcomics.com/get/image/?f=comics/extracted/oni_whiteout_melt_1/02.jpg",
		"http://dev.justforcomics.com/get/image/?f=comics/extracted/oni_whiteout_melt_1/03.jpg",
		"http://dev.justforcomics.com/get/image/?f=comics/extracted/oni_whiteout_melt_1/04.jpg",
		"http://dev.justforcomics.com/get/image/?f=comics/extracted/oni_whiteout_melt_1/05.jpg",
		"http://dev.justforcomics.com/get/image/?f=comics/extracted/oni_whiteout_melt_1/06.jpg"
	];

	var options = {
		displayMode: "double",
		zoomMode: "fitWidth"
	};

	book = new ComicBook("comic", pages, options);
	book.draw();
};

window.onresize = function() {
	book.draw();
};
<|endoftext|>


<commit_before>var Star = new Class({
    initialize: function(options) {
        this.options = options;
        this.x = options.x;
        this.y = options.y;
        this.brightness = options.brightness || 1;
        this.color = options.color || "white";
    },
    draw: function(context, width, height, step) {
        var x = this.x * width / 1000;
        var y = this.y * height / 1000;
        if (typeof(step) === 'number') {
            x = width / 2 + (step / 100) * (x - width / 2);
            y = height / 2 + (step / 100) * (y - height / 2);
        }

        context.save();
        context.fillStyle = this.color;
        context.beginPath();
        context.arc(x, y, this.brightness, 0, 2*Math.PI, null);
        context.fill();
        context.closePath();
        context.restore();
    },
});

function makeStars(canvasId, numStars, otherLocations) {
    var canvas = document.getElementById(canvasId);
    var context = canvas.getContext("2d");
    var stars = [];
    var i = 0, c = 0, tmp, color;
    for (i = 0; i < numStars; i += 1) {
        c = Math.floor(Math.random() * 255);
        color = "#";
        tmp = c.toString(16);
        color += ((tmp.length === 1)?"0":"") + tmp;
        color += "80";
        tmp = (255-c).toString(16);
        color += ((tmp.length === 1)?"0":"") + tmp;

        if (otherLocations && i < otherLocations.length) {
            tmp = otherLocations[i];
            stars[stars.length] = new Star({
                x: tmp[0],
                y: tmp[1],
                brightness: 2,
                color: "#bbbbbb",
            });
        } else {
            stars[stars.length] = new Star({
                x: Math.random() * 1000,
                y: Math.random() * 1000,
                brightness: Math.random() * Math.random() * 2,
                color: color,
            });
        }
    }

    function drawStatic () {
        var width = window.innerWidth;
        var height = window.innerHeight;
        canvas.width = width;
        canvas.height = height;

        Array.each(stars, function(star){ star.draw(context, width, height, null); });
    }

    return {
        draw: drawStatic,
        bang: function(whenFinished) {
            function drawStep(step) {
                var width = window.innerWidth;
                var height = window.innerHeight;
                if (step === 0) {
                    canvas.width = width;
                    canvas.height = height;
                }
                context.clearRect(0, 0, width, height);

                Array.each(stars, function(star) {
                    star.draw(context, width, height, step);
                });

                if (step < 100) {
                    setTimeout(function(){drawStep(step+5);}, 5);
                } else {
                    whenFinished();
                }
            }
            drawStep(0);
        },
    };
}

<commit_msg>A tiny bit more prettification.<commit_after>var Star = new Class({
    initialize: function(options) {
        this.options = options;
        this.x = options.x;
        this.y = options.y;
        this.brightness = options.brightness || 1;
        this.color = options.color || "white";
    },
    draw: function(context, width, height, step) {
        var x = this.x * width / 1000;
        var y = this.y * height / 1000;
        if (typeof(step) === 'number') {
            x = width / 2 + (step / 100) * (x - width / 2);
            y = height / 2 + (step / 100) * (y - height / 2);
        }

        context.save();
        context.fillStyle = this.color;
        context.beginPath();
        context.arc(x, y, this.brightness, 0, 2*Math.PI, null);
        context.fill();
        context.closePath();
        context.restore();
    },
});

function makeStars(canvasId, numStars, otherLocations) {
    var canvas = document.getElementById(canvasId);
    var context = canvas.getContext("2d");
    var stars = [];
    var i = 0, c = 0, tmp, color;
    for (i = 0; i < numStars; i += 1) {
        c = Math.floor(Math.random() * 255);
        color = "#";
        tmp = c.toString(16);
        color += ((tmp.length === 1)?"0":"") + tmp;
        color += "80";
        tmp = (255-c).toString(16);
        color += ((tmp.length === 1)?"0":"") + tmp;

        if (otherLocations && i < otherLocations.length) {
            tmp = otherLocations[i];
            stars[stars.length] = new Star({
                x: tmp[0],
                y: tmp[1],
                brightness: 2,
                color: "#bbbbbb",
            });
        } else {
            stars[stars.length] = new Star({
                x: Math.random() * 1000,
                y: Math.random() * 1000,
                brightness: Math.random() * Math.random() * 2,
                color: color,
            });
        }
    }

    return {
        draw: function () {
            var width = window.innerWidth;
            var height = window.innerHeight;
            canvas.width = width;
            canvas.height = height;

            Array.each(stars, function (star) {
                star.draw(context, width, height);
            });
        },
        bang: function(whenFinished) {
            function drawStep(step) {
                var width = window.innerWidth;
                var height = window.innerHeight;
                if (step === 0) {
                    canvas.width = width;
                    canvas.height = height;
                }
                context.clearRect(0, 0, width, height);

                Array.each(stars, function(star) {
                    star.draw(context, width, height, step);
                });

                if (step < 100) {
                    setTimeout(function(){drawStep(step+5);}, 5);
                } else {
                    whenFinished();
                }
            }
            drawStep(0);
        },
    };
}

<|endoftext|>


<commit_before>
// actions
function doStash( coords, selectedMode ) {

    if (selectedMode === undefined) selectedMode = window.lastSelected;
    if (selectedMode === undefined) selectedMode = window.defaultStashView;
    var container = $('#inner-stash-box');

    container.html('');
    code = encode( $.extend({}, coords, {mode: selectedMode}) );

    var dropdown = $('<select/>', {'class': 'form-control', id: 'mode-selector'});

    var formGroup = $('<div/>', {'class': 'form-group'});

    for( var opt in window.stashViews ) {
        var name = window.stashViews[opt].name;
        $('<option/>', {value: opt, text: name}).appendTo(dropdown);
    }

    dropdown.val( selectedMode );

    dropdown.change( function () {
        var selected = $('#mode-selector').val();
        window.lastSelected = selected;
        doStash( coords, selected );
    } );

    formGroup.append(dropdown);
    container.append(formGroup);

    if ($('#preview-frame-box').is(':hidden')) {
        container.append(buildButton( 'Preview', 'btn-default preview-button', function() {
            showPreview( coords, selectedMode );
            $('.preview-button').hide();
            window.location.href = '#preview';
        }));
    }

    container = $('#inner-publish-box');
    container.html('');

    var form = $('<form/>', {
        action: "http://tinyurl.com/create.php",
        method: "post",
        id: 'tinyurl-form' });
    var formGroup = $('<div/>', {'class': 'form-group'});

    var input = $('<textarea/>', {
        id: 'tinyurl-input',
        'class': 'form-control',
        rows: 4,
        name: 'url' });
    input.val( urlWithoutQueryString() + buildQueryString( {code: code} ) );
    formGroup.append( input );
    form.append(formGroup);

    formGroup = $('<div/>', {'class': 'form-group'});

    formGroup.append( buildLinkButton( {
        text: "Open link & try puzzle",
        href: buildQueryString( {code: code} )
    }, 'btn-default btn-block') );

    formGroup.append( $('<input/>', {
        type: 'submit',
        name: 'submit',
        'class': 'btn btn-danger btn-block',
        value: "Submit to tinyurl.com" }));
    form.append(formGroup);

    container.append(form);
    if ($('#preview-frame-box').is(':visible')) {
        showPreview( coords, selectedMode );
    }
}

function hidePreview() {
    $('#inner-preview-frame-box').html('');
    $('#preview-frame-box').hide();
    $('.preview-button').show();
}

function showPreview( coords, selectedMode ) {

    var container = $('#inner-preview-frame-box');
    $('#preview-frame-box').show();

    var codeActual = encode( $.extend({}, coords, {mode: selectedMode}) );
    var codeDebug = encode( $.extend({}, coords, {mode: 'bothOnMap'}) );

    container.html('');

    container.append( buildButton( 'Hide preview', '', hidePreview ) );

    container.append($('<b/>', { text: 'Preview' } ));
    if (codeActual != codeDebug) {
        container.append($('<iframe/>', {
            width: '100%',
            height: '350px',
            seamless: true,
            src: buildQueryString( {code: codeActual} )
        }));

        container.append($('<b/>', { text: 'Debug' } ));
    }

    container.append($('<iframe/>', {
        width: '100%',
        height: '500px',
        seamless: true,
        src: buildQueryString( {code: codeDebug} )
    }));
}

// views
function beginStashed( stashedData ) {

    var mode = stashedData.mode;
    var view = window.stashViews[mode];
    if (view)
    {
        $('#header').hide();
        $('.explain-box').hide();
        $('body').addClass('stashed');
        $('body').addClass(mode);

        var el = $('#inner-primary-box');
        el.html(buildLoadingIndicator());

        var firstRender = true;
        watchLocation( function (loc) {
            if (firstRender) {
                el.html('');
                if (view.initializer !== undefined)
                    view.initializer( el, stashedData, loc.coords );
            }
            view.renderer( el, stashedData, loc.coords );
            firstRender = false;
        } );
    }
    else showError( "Did not recongize stash view" );
}

function beginNewStash() {

    var container = $('#inner-primary-box');
    container.html('');

    var stashButton = buildLinkButton(
        {text: 'Stash', href: '#stash', id: "stash-button"},
        'btn-primary btn-block' );

    stashButton.click( showStashBox );

    container.append(stashButton);
    var resultBox = $('<div/>', {id: 'result-box'});
    container.append(resultBox);
    resultBox.append(buildLoadingIndicator());

    getLocation( function (loc) {
        renderNewStash( loc.coords );
    } );

    $('#stash-box').hide();
    $('#preview-frame-box').hide();
}

function showStashBox() {
    $('#stash-box').show();
    $('#stash-button').hide();
}

function renderNewStash( coords ) {

    var previewBox = $('#result-box');
    previewBox.html('');

    var btnGroup = $('<div/>', {'class': 'btn-group btn-group-justified'} );

    var leftBtnGroup = $('<div/>', {'class': 'btn-group'} );
    leftBtnGroup.append(buildButton( 'Refresh location', 'btn-default', function() {
        $('#inner-preview-frame-box').html('');
        leftBtnGroup.addClass('disabled');
        getLocation( function (loc) { renderNewStash( loc.coords ); } );
    }));
    btnGroup.append(leftBtnGroup);
    previewBox.append(btnGroup);

    var coordBox = $('<div/>');
    var mapBox = $('<div/>');
    coordBox.append(buildEditableCoordinateBox(coords, true));
    mapBox.append(buildGoogleMap( coords ));
    previewBox.append(coordBox);
    previewBox.append(mapBox);

    var rightBtnGroup = $('<div/>', {'class': 'btn-group'} );
    rightBtnGroup.append(buildButton( 'Track location', 'btn-default', function() {
        $('#inner-preview-frame-box').html('');
        $('#stash-box').hide();
        $('#stash-button').hide();
        var watchId = watchLocation( function (loc) {
            coordBox.html('');
            coordBox.append(buildEditableCoordinateBox(loc.coords, false));
        });
        leftBtnGroup.html(buildButton( 'Show on map', 'btn-default', function() {
            mapBox.html('');
            mapBox.append(buildGoogleMap( window.lastWatchCoords ));
        } ));
        rightBtnGroup.html(buildButton( 'Stop & stash', 'btn-primary', function() {
            stopWatching( watchId );
            renderNewStash( window.lastWatchCoords );
            $('#stash-box').show();
            window.location.href = '#stash';
        } ));
    }));
    btnGroup.append(rightBtnGroup);

    doStash(coords);
}

function buildLoadingIndicator() {
    var container = $('<div/>', {'class': 'loading-outer'});
    container.append( $('<div/>', {
        'class': 'loading-inner',
        text: 'Loading...' }) );
    return container;
}

function buildButton( text, classes, action ) {
    var button = $('<input/>', {
        type: 'button',
        'class': 'btn btn-block btn-and-space '+classes,
        value: text });
    button.click( action );
    return button;
}

function buildLinkButton( params, classes ) {
    return $('<a/>', $.extend({
        'class': 'btn btn-and-space '+classes,
        role: "button",
    },params));
}

function buildEditableCoordinateBox( coords, editable ) {

    var coordinateBox = $('<div/>',  {
        'id': 'preview-coordinate-box',
        'class': 'panel panel-default coordinate-box'
    });
    var innerCoordinateBox = $('<div/>', {
        'class': 'panel-body',
    });
    innerCoordinateBox.append($('<p/>', {text: 'Latitude: '+coords.latitude}));
    innerCoordinateBox.append($('<p/>', {text: 'Longitude: '+coords.longitude}));

    if (editable) {
        var editButton = $('<input/>', {
            type: 'button',
            'class': 'btn btn-default btn-xs pull-right',
            value: 'Edit' });

        editButton.click( function () {
            var box = $('#preview-coordinate-box');
            box.html('');

            var innerBox = $('<div/>', {
                'class': 'panel-body',
            });

            var buildInput = function ( id, label, value ) {
                var formGroup = $('<div/>', {'class': 'form-group'});
                formGroup.append($('<label/>', {text: label}));
                formGroup.append($('<input/>', {
                    id: id,
                    type: 'text',
                    value: value,
                    'class': 'form-control'
                }));
                return formGroup;
            };

            var value = coords.latitude+", "+coords.longitude
            innerBox.append( buildInput( 'lat-long-edit', 'Latitude, Longitude', value) );
            innerBox.append( buildButton( 'Stash these', 'btn-primary', function() {
                var lalo = $('#lat-long-edit').val().split(',');
                var la = $.trim(lalo[0]);
                var lo = $.trim(lalo[1]);
                var newCoords = $.extend({}, coords, { latitude: la, longitude: lo });
                renderNewStash( newCoords );
                showStashBox();
                window.location.href = '#stash';
            }));
            box.append(innerBox);
        });

        coordinateBox.append( editButton );
    }
    coordinateBox.append(innerCoordinateBox);

    return coordinateBox;
}

function buildGoogleMap( params ) {

    var lat = params.latitude;
    var long = params.longitude;
    var markers = [ "color:red|"+lat + "," + long ];
    if (params.extraMarker) {
        var m = params.extraMarker
        markers.push( "color:"+m.color+"|"+m.latitude+","+m.longitude );
    }

    queryParams = {
        center: lat + ',' + long,
        markers: markers,
        zoom: "15",
        size: "300x300",
        sensor: "false"
    };

    var image = $('<img/>', {
        src: "http://maps.googleapis.com/maps/api/staticmap"+buildQueryString(queryParams)
    });

    var container = $('<div/>', {'class': 'img-container'});
    container.append(image);
    return container;
}

// useful helpers
function encode( obj ) {
    return btoa(JSON.stringify( {la: obj.latitude, lo: obj.longitude, mo: obj.mode } ));
}

function decodeQuery( ) {
    var code = parseQueryString().code;
    if (code === undefined) return undefined;
    var obj = JSON.parse(atob(code));
    return { latitude: obj.la, longitude: obj.lo, mode: obj.mo };
}

commonGeoOptions = {
    enableHighAccuracy: true,
    timeout:60000
};

function watchLocation( callback )
{
    var opts = $.extend({}, commonGeoOptions, { maximumAge: 5000 });
    window.watchId = navigator.geolocation.watchPosition( function ( loc ) {
        window.lastWatchCoords = loc.coords;
        callback(loc);
    }, showGeoError, opts );
    return window.watchId;
}

function stopWatching( watchId ) {
    if (watchId === undefined) watchId = window.watchId;
    navigator.geolocation.clearWatch(watchId);
}

function getLocation( callback )
{
    navigator.geolocation.getCurrentPosition(callback, showGeoError, commonGeoOptions);
}

function showError( errorText ) {
    var x = $('#error-box');
    x.show();
    x.html(errorText);
}

function showGeoError(error)
{
    switch(error.code)
    {
    case error.PERMISSION_DENIED:
      showError("User denied the request for Geolocation.");
      break;
    case error.POSITION_UNAVAILABLE:
      showError("Location information is unavailable.");
      break;
    case error.TIMEOUT:
      showError("The request to get user location timed out.");
      break;
    case error.UNKNOWN_ERROR:
      showError("An unknown error occurred.");
      break;
    }
}

// stupid helpers
function parseQueryString() {
    var params = {};
    var qstring = window.location.search.split('?')[1];
    if (qstring === undefined) return params;
    qstring = qstring.split('/')[0];
    var strs = qstring.split('&');
    for (var i in strs) {
        var nameAndValue = strs[i].split('=');
        params[nameAndValue[0]] = decodeURIComponent(nameAndValue[1]);
    }
    return params;
}

function buildQueryString( obj ) {
    var arr = [];
    for (var param in obj) {
        var value = obj[param];
        if ($.isArray(value)) {
            for (var i in value)
                arr.push( param + '=' + encodeURIComponent(value[i]) );
        }
        else
            arr.push( param + "=" + encodeURIComponent(value) );
    }
    if (arr.length == 0) return '';
    return '?'+arr.join('&');
}

function urlWithoutQueryString() {
    var url = window.location;
    return url.protocol + "//" + url.host + url.pathname
}
<commit_msg>HTTP -> HTTPS in Google Maps and Tinyurl APIs<commit_after>
// actions
function doStash( coords, selectedMode ) {

    if (selectedMode === undefined) selectedMode = window.lastSelected;
    if (selectedMode === undefined) selectedMode = window.defaultStashView;
    var container = $('#inner-stash-box');

    container.html('');
    code = encode( $.extend({}, coords, {mode: selectedMode}) );

    var dropdown = $('<select/>', {'class': 'form-control', id: 'mode-selector'});

    var formGroup = $('<div/>', {'class': 'form-group'});

    for( var opt in window.stashViews ) {
        var name = window.stashViews[opt].name;
        $('<option/>', {value: opt, text: name}).appendTo(dropdown);
    }

    dropdown.val( selectedMode );

    dropdown.change( function () {
        var selected = $('#mode-selector').val();
        window.lastSelected = selected;
        doStash( coords, selected );
    } );

    formGroup.append(dropdown);
    container.append(formGroup);

    if ($('#preview-frame-box').is(':hidden')) {
        container.append(buildButton( 'Preview', 'btn-default preview-button', function() {
            showPreview( coords, selectedMode );
            $('.preview-button').hide();
            window.location.href = '#preview';
        }));
    }

    container = $('#inner-publish-box');
    container.html('');

    var form = $('<form/>', {
        action: "https://tinyurl.com/create.php",
        method: "post",
        id: 'tinyurl-form' });
    var formGroup = $('<div/>', {'class': 'form-group'});

    var input = $('<textarea/>', {
        id: 'tinyurl-input',
        'class': 'form-control',
        rows: 4,
        name: 'url' });
    input.val( urlWithoutQueryString() + buildQueryString( {code: code} ) );
    formGroup.append( input );
    form.append(formGroup);

    formGroup = $('<div/>', {'class': 'form-group'});

    formGroup.append( buildLinkButton( {
        text: "Open link & try puzzle",
        href: buildQueryString( {code: code} )
    }, 'btn-default btn-block') );

    formGroup.append( $('<input/>', {
        type: 'submit',
        name: 'submit',
        'class': 'btn btn-danger btn-block',
        value: "Submit to tinyurl.com" }));
    form.append(formGroup);

    container.append(form);
    if ($('#preview-frame-box').is(':visible')) {
        showPreview( coords, selectedMode );
    }
}

function hidePreview() {
    $('#inner-preview-frame-box').html('');
    $('#preview-frame-box').hide();
    $('.preview-button').show();
}

function showPreview( coords, selectedMode ) {

    var container = $('#inner-preview-frame-box');
    $('#preview-frame-box').show();

    var codeActual = encode( $.extend({}, coords, {mode: selectedMode}) );
    var codeDebug = encode( $.extend({}, coords, {mode: 'bothOnMap'}) );

    container.html('');

    container.append( buildButton( 'Hide preview', '', hidePreview ) );

    container.append($('<b/>', { text: 'Preview' } ));
    if (codeActual != codeDebug) {
        container.append($('<iframe/>', {
            width: '100%',
            height: '350px',
            seamless: true,
            src: buildQueryString( {code: codeActual} )
        }));

        container.append($('<b/>', { text: 'Debug' } ));
    }

    container.append($('<iframe/>', {
        width: '100%',
        height: '500px',
        seamless: true,
        src: buildQueryString( {code: codeDebug} )
    }));
}

// views
function beginStashed( stashedData ) {

    var mode = stashedData.mode;
    var view = window.stashViews[mode];
    if (view)
    {
        $('#header').hide();
        $('.explain-box').hide();
        $('body').addClass('stashed');
        $('body').addClass(mode);

        var el = $('#inner-primary-box');
        el.html(buildLoadingIndicator());

        var firstRender = true;
        watchLocation( function (loc) {
            if (firstRender) {
                el.html('');
                if (view.initializer !== undefined)
                    view.initializer( el, stashedData, loc.coords );
            }
            view.renderer( el, stashedData, loc.coords );
            firstRender = false;
        } );
    }
    else showError( "Did not recongize stash view" );
}

function beginNewStash() {

    var container = $('#inner-primary-box');
    container.html('');

    var stashButton = buildLinkButton(
        {text: 'Stash', href: '#stash', id: "stash-button"},
        'btn-primary btn-block' );

    stashButton.click( showStashBox );

    container.append(stashButton);
    var resultBox = $('<div/>', {id: 'result-box'});
    container.append(resultBox);
    resultBox.append(buildLoadingIndicator());

    getLocation( function (loc) {
        renderNewStash( loc.coords );
    } );

    $('#stash-box').hide();
    $('#preview-frame-box').hide();
}

function showStashBox() {
    $('#stash-box').show();
    $('#stash-button').hide();
}

function renderNewStash( coords ) {

    var previewBox = $('#result-box');
    previewBox.html('');

    var btnGroup = $('<div/>', {'class': 'btn-group btn-group-justified'} );

    var leftBtnGroup = $('<div/>', {'class': 'btn-group'} );
    leftBtnGroup.append(buildButton( 'Refresh location', 'btn-default', function() {
        $('#inner-preview-frame-box').html('');
        leftBtnGroup.addClass('disabled');
        getLocation( function (loc) { renderNewStash( loc.coords ); } );
    }));
    btnGroup.append(leftBtnGroup);
    previewBox.append(btnGroup);

    var coordBox = $('<div/>');
    var mapBox = $('<div/>');
    coordBox.append(buildEditableCoordinateBox(coords, true));
    mapBox.append(buildGoogleMap( coords ));
    previewBox.append(coordBox);
    previewBox.append(mapBox);

    var rightBtnGroup = $('<div/>', {'class': 'btn-group'} );
    rightBtnGroup.append(buildButton( 'Track location', 'btn-default', function() {
        $('#inner-preview-frame-box').html('');
        $('#stash-box').hide();
        $('#stash-button').hide();
        var watchId = watchLocation( function (loc) {
            coordBox.html('');
            coordBox.append(buildEditableCoordinateBox(loc.coords, false));
        });
        leftBtnGroup.html(buildButton( 'Show on map', 'btn-default', function() {
            mapBox.html('');
            mapBox.append(buildGoogleMap( window.lastWatchCoords ));
        } ));
        rightBtnGroup.html(buildButton( 'Stop & stash', 'btn-primary', function() {
            stopWatching( watchId );
            renderNewStash( window.lastWatchCoords );
            $('#stash-box').show();
            window.location.href = '#stash';
        } ));
    }));
    btnGroup.append(rightBtnGroup);

    doStash(coords);
}

function buildLoadingIndicator() {
    var container = $('<div/>', {'class': 'loading-outer'});
    container.append( $('<div/>', {
        'class': 'loading-inner',
        text: 'Loading...' }) );
    return container;
}

function buildButton( text, classes, action ) {
    var button = $('<input/>', {
        type: 'button',
        'class': 'btn btn-block btn-and-space '+classes,
        value: text });
    button.click( action );
    return button;
}

function buildLinkButton( params, classes ) {
    return $('<a/>', $.extend({
        'class': 'btn btn-and-space '+classes,
        role: "button",
    },params));
}

function buildEditableCoordinateBox( coords, editable ) {

    var coordinateBox = $('<div/>',  {
        'id': 'preview-coordinate-box',
        'class': 'panel panel-default coordinate-box'
    });
    var innerCoordinateBox = $('<div/>', {
        'class': 'panel-body',
    });
    innerCoordinateBox.append($('<p/>', {text: 'Latitude: '+coords.latitude}));
    innerCoordinateBox.append($('<p/>', {text: 'Longitude: '+coords.longitude}));

    if (editable) {
        var editButton = $('<input/>', {
            type: 'button',
            'class': 'btn btn-default btn-xs pull-right',
            value: 'Edit' });

        editButton.click( function () {
            var box = $('#preview-coordinate-box');
            box.html('');

            var innerBox = $('<div/>', {
                'class': 'panel-body',
            });

            var buildInput = function ( id, label, value ) {
                var formGroup = $('<div/>', {'class': 'form-group'});
                formGroup.append($('<label/>', {text: label}));
                formGroup.append($('<input/>', {
                    id: id,
                    type: 'text',
                    value: value,
                    'class': 'form-control'
                }));
                return formGroup;
            };

            var value = coords.latitude+", "+coords.longitude
            innerBox.append( buildInput( 'lat-long-edit', 'Latitude, Longitude', value) );
            innerBox.append( buildButton( 'Stash these', 'btn-primary', function() {
                var lalo = $('#lat-long-edit').val().split(',');
                var la = $.trim(lalo[0]);
                var lo = $.trim(lalo[1]);
                var newCoords = $.extend({}, coords, { latitude: la, longitude: lo });
                renderNewStash( newCoords );
                showStashBox();
                window.location.href = '#stash';
            }));
            box.append(innerBox);
        });

        coordinateBox.append( editButton );
    }
    coordinateBox.append(innerCoordinateBox);

    return coordinateBox;
}

function buildGoogleMap( params ) {

    var lat = params.latitude;
    var long = params.longitude;
    var markers = [ "color:red|"+lat + "," + long ];
    if (params.extraMarker) {
        var m = params.extraMarker
        markers.push( "color:"+m.color+"|"+m.latitude+","+m.longitude );
    }

    queryParams = {
        center: lat + ',' + long,
        markers: markers,
        zoom: "15",
        size: "300x300",
        sensor: "false"
    };

    var image = $('<img/>', {
        src: "https://maps.googleapis.com/maps/api/staticmap"+buildQueryString(queryParams)
    });

    var container = $('<div/>', {'class': 'img-container'});
    container.append(image);
    return container;
}

// useful helpers
function encode( obj ) {
    return btoa(JSON.stringify( {la: obj.latitude, lo: obj.longitude, mo: obj.mode } ));
}

function decodeQuery( ) {
    var code = parseQueryString().code;
    if (code === undefined) return undefined;
    var obj = JSON.parse(atob(code));
    return { latitude: obj.la, longitude: obj.lo, mode: obj.mo };
}

commonGeoOptions = {
    enableHighAccuracy: true,
    timeout:60000
};

function watchLocation( callback )
{
    var opts = $.extend({}, commonGeoOptions, { maximumAge: 5000 });
    window.watchId = navigator.geolocation.watchPosition( function ( loc ) {
        window.lastWatchCoords = loc.coords;
        callback(loc);
    }, showGeoError, opts );
    return window.watchId;
}

function stopWatching( watchId ) {
    if (watchId === undefined) watchId = window.watchId;
    navigator.geolocation.clearWatch(watchId);
}

function getLocation( callback )
{
    navigator.geolocation.getCurrentPosition(callback, showGeoError, commonGeoOptions);
}

function showError( errorText ) {
    var x = $('#error-box');
    x.show();
    x.html(errorText);
}

function showGeoError(error)
{
    switch(error.code)
    {
    case error.PERMISSION_DENIED:
      showError("User denied the request for Geolocation.");
      break;
    case error.POSITION_UNAVAILABLE:
      showError("Location information is unavailable.");
      break;
    case error.TIMEOUT:
      showError("The request to get user location timed out.");
      break;
    case error.UNKNOWN_ERROR:
      showError("An unknown error occurred.");
      break;
    }
}

// stupid helpers
function parseQueryString() {
    var params = {};
    var qstring = window.location.search.split('?')[1];
    if (qstring === undefined) return params;
    qstring = qstring.split('/')[0];
    var strs = qstring.split('&');
    for (var i in strs) {
        var nameAndValue = strs[i].split('=');
        params[nameAndValue[0]] = decodeURIComponent(nameAndValue[1]);
    }
    return params;
}

function buildQueryString( obj ) {
    var arr = [];
    for (var param in obj) {
        var value = obj[param];
        if ($.isArray(value)) {
            for (var i in value)
                arr.push( param + '=' + encodeURIComponent(value[i]) );
        }
        else
            arr.push( param + "=" + encodeURIComponent(value) );
    }
    if (arr.length == 0) return '';
    return '?'+arr.join('&');
}

function urlWithoutQueryString() {
    var url = window.location;
    return url.protocol + "//" + url.host + url.pathname
}
<|endoftext|>