<commit_before>var giphy = require('../giphy.js')('dc6zaTOxFJmzC');
var chuckJokes = require('../chuckJokes.js');

module.exports = function (txt, msg, postMessage) {

    function handleMessage(txt){
        if (/^joke$/.test(txt)) {
            tellAJoke();
            return;
        }

        //Easter Egg images

        if (/facepalm/.test(txt)) {
            tellGifJoke('marvel-wolverine-facepalm');
            return;
        }

        if (/potato/.test(txt)) {
            tellGifJoke('yellow-minions-potato');
            return;
        }

        if (/^gumby$/.test(txt)) {
            tellGifJoke('unf-gumby');
            return;
        }

        if (/rocketsnail/.test(txt)) {
            tellGifJoke('SQgbkziuGrNxS');
            return;
        }

        if (/^matched\steam\swild\ssnails$/.test(txt)) {
            tellGifJoke('SQgbkziuGrNxS');
            return;
        }

        if (/cowbell/.test(txt)) {
            tellGifJoke('whOs1JywNpe6c');
            return;
        }

        if (/^boom$/.test(txt)) {
            tellGifJoke('yNf9JjErqMcve');
            return;
        }

        if (/hots\sfavorite/.test(txt)) {
            tellGifJoke('TuQUMaAji7pkY');
            return;
        }

        if (/banana/.test(txt)) {
            tellGifJoke('cw8Nr4u28tVKw');
            return;
        }

        //Raven Easter Egg responses

        if (/^raven\sis\sa\spretty\sbird$/.test(txt)) {
            postMessage('Did I hear Hots?  Here, have some candy.');
            return;
        }

        //Norm Jokes

        if (/^norm$/.test(txt)) {
            postMessage('Evening Everybody');
            return;
        }

        if (/^how\sabout\sa\sbeer\snorm$/.test(txt)) {
            postMessage('OK, but stop me at one... Make that one thirty.');
            return;
        }

        if (/^whats\sshakin\snorm$/.test(txt)) {
            postMessage('All four cheeks and a couple of chins.');
            return;
        }

        //Known Joke Images

        if (/^minions$/.test(txt)) {
            tellGifJoke();
            return;
        }

        var gifRgx = /^gif\s(.*)+$/;
        if (gifRgx.test(txt)) {
            var match = gifRgx.exec(txt);
            tellGifJoke(match[1]);
            return;
        }
    }

    function tellAJoke() {

        chuckJokes.getJoke().then(function (joke) {
            postMessage(joke);
        }.bind(this))
    }

    function tellGifJoke(theme) {

        theme = typeof(theme) == 'string' ? theme : 'minions';
        giphy.random(encodeURI(theme), function (err, response) {
            if (err == null) {
                postMessage('', response.data.image_url);
            } else {
                postMessage('could not find this theme.');

            }
        })
    }

    handleMessage(txt);

}<commit_msg>matched the ancients<commit_after>var giphy = require('../giphy.js')('dc6zaTOxFJmzC');
var chuckJokes = require('../chuckJokes.js');

module.exports = function (txt, msg, postMessage) {

    function handleMessage(txt){
        if (/^joke$/.test(txt)) {
            tellAJoke();
            return;
        }

        //Easter Egg images

        if (/facepalm/.test(txt)) {
            tellGifJoke('marvel-wolverine-facepalm');
            return;
        }

        if (/potato/.test(txt)) {
            tellGifJoke('yellow-minions-potato');
            return;
        }

        if (/^gumby$/.test(txt)) {
            tellGifJoke('unf-gumby');
            return;
        }

        if (/rocketsnail/.test(txt)) {
            tellGifJoke('SQgbkziuGrNxS');
            return;
        }

        if (/^matched\steam\swild\ssnails$/.test(txt)) {
            tellGifJoke('SQgbkziuGrNxS');
            return;
        }

        if (/cowbell/.test(txt)) {
            tellGifJoke('whOs1JywNpe6c');
            return;
        }

        if (/^boom$/.test(txt)) {
            tellGifJoke('yNf9JjErqMcve');
            return;
        }

        if (/hots\sfavorite/.test(txt)) {
            tellGifJoke('TuQUMaAji7pkY');
            return;
        }

        if (/banana/.test(txt)) {
            tellGifJoke('cw8Nr4u28tVKw');
            return;
        }

        //Raven Easter Egg responses

        if (/^raven\sis\sa\spretty\sbird$/.test(txt)) {
            postMessage('Did I hear Hots?  Here, have some candy.');
            return;
        }

        //Norm Jokes

        if (/^norm$/.test(txt)) {
            postMessage('Evening Everybody');
            return;
        }

        if (/^how\sabout\sa\sbeer\snorm$/.test(txt)) {
            postMessage('OK, but stop me at one... Make that one thirty.');
            return;
        }

        if (/^whats\sshakin\snorm$/.test(txt)) {
            postMessage('All four cheeks and a couple of chins.');
            return;
        }

        //Tribute to DJ - 22 May 2015 war

        if (/^matched\sthe\sancients$/.test(txt)) {
            postMessage('We fight in memory of DJ. To show your respect, we ask that you fight us with honour, do not hold back and give only 1 love tap to DJ.');
            return;
        }

        //Known Joke Images

        if (/^minions$/.test(txt)) {
            tellGifJoke();
            return;
        }

        var gifRgx = /^gif\s(.*)+$/;
        if (gifRgx.test(txt)) {
            var match = gifRgx.exec(txt);
            tellGifJoke(match[1]);
            return;
        }
    }

    function tellAJoke() {

        chuckJokes.getJoke().then(function (joke) {
            postMessage(joke);
        }.bind(this))
    }

    function tellGifJoke(theme) {

        theme = typeof(theme) == 'string' ? theme : 'minions';
        giphy.random(encodeURI(theme), function (err, response) {
            if (err == null) {
                postMessage('', response.data.image_url);
            } else {
                postMessage('could not find this theme.');

            }
        })
    }

    handleMessage(txt);

}<|endoftext|>


<commit_before>/**
 * Created by yuqy on 2017/9/29.
 */
var MG = {
    layers: [], /* 画布层 */
    dataMap: [], /* 雷区地图 */
    currentLevel: 0, /* 当前游戏级别 */
    cg: null, /* 当前游戏 */
    residualMines: 20, /* 剩余雷数 */
    elapsedTime: 0, /* 经过时间 */
    timer: 0, /* 计时器 */
    timeout: 0, /* 计时器句柄 */
    score: 0 /* 得分 */
};

MG.levels = [
    {
        level: 0,
        width: 400,
        height: 400,
        cellWidth: 50,
        mineCount: 20,
        range: {
            rows: 8,
            columns: 8
        }
    }
];

/**
 * 格子
 * @constructor
 */
function Cell() {
    this.data = 0;
    this.isOpened = false;
    this.isFlag = false;
}

/**
 * 随机生成格子地址
 * @returns {*[]}
 */
function getRandomPosition() {
    return {
        x: getRandom(MG.cg.range.rows),
        y: getRandom(MG.cg.range.columns)
    };
}

/**
 * 生成雷区地图
 */
function createGameData() {
    initDataMap();
    createMines();
}

/**
 * 生成空白地图
 */
function initDataMap() {
    for (var r = 0; r < MG.cg.range.rows; r++) {
        MG.dataMap[r] = Array.apply(null, Array(MG.cg.range.columns)).map(function (i) {
            return new Cell();
        });
    }
}

/**
 * 生成地雷
 * 扫描地雷周围，生成格子周围地雷数
 */
function createMines() {
    var mineCount = MG.cg.mineCount;
    var tempArr = {};
    while (mineCount > 0) {
        var pos = getRandomPosition();
        var key = pos.x + "=" + pos.y;
        if (!tempArr[key]) {
            tempArr[key] = 1;
            MG.dataMap[pos.x][pos.y].data = -1;
            scanAroundCell(pos);
            mineCount--;
        }
    }
    tempArr = null;
}

/**
 * 扫描当前格子周围8格，更新地雷数
 * @param pos
 */
function scanAroundCell(pos) {
    var rows = MG.cg.range.rows;
    var columns = MG.cg.range.columns;
    for (var ri = -1; ri < 2; ri++) {
        var r = pos.x + ri;
        if (r > -1 && r < rows) {
            for (var ci = -1; ci < 2; ci++) {
                var c = pos.y + ci;
                if (c > -1 && c < columns && !(r == pos.x && c == pos.y) && MG.dataMap[r][c].data > -1) {
                    MG.dataMap[r][c].data++;
                }
            }
        }
    }
}

//////////////////////////////////////////////////
//// 画布相关
//////////////////////////////////////////////////
/**
 * 初始化游戏画布
 */
function initLayers() {
    MG.layers.forEach(function (i) {
            //MG.layers[i].canvas.oncontextmenu = function (e) {
            //    if (document.all) {
            //        window.event.returnValue = false;
            //    } else {
            //        event.preventDefault();
            //    }
            //}
        }
    );

    $("#elapsed_time").text(MG.elapsedTime);
    MG.timer = setInterval(function () {
        MG.elapsedTime++;
        $("#elapsed_time").text(MG.elapsedTime);
    }, 1000);
    $("#residual_mines").text(MG.residualMines);
}

/**
 * 绑定事件
 */
function bindEvent() {
    var layers = $("#layers");
    layers.oncontextmenu = disableRightClick;
    layers.mousedown(function (e) {
        var canvasPosition = $(this).offset();
        var mouseX = (e.pageX - canvasPosition.left) || 0;
        var mouseY = (e.pageY - canvasPosition.top) || 0;
        var ri = Math.floor(mouseX / MG.cg.cellWidth);
        var ci = Math.floor(mouseY / MG.cg.cellWidth);
        //var isLeftButtonClicked = event.button == 0;

        MG.timeout = setTimeout(function (e) {
            drawFlag(ri, ci);
            //if (isLeftButtonClicked) {
            //    openCell(mouseX, mouseY);
            //} else {
            //    drawFlag(mouseX, mouseY);
            //}
            MG.timeout = 0;
        }, 1000);
    });
    layers.mousemove(function (e) {
        clearTimeout(MG.timeout);
        MG.timeout = 0;
    });
    layers.mouseup(function (e) {
        clearTimeout(MG.timeout);
        if (MG.timeout != 0) {
            var canvasPosition = $(this).offset();
            var mouseX = (e.pageX - canvasPosition.left) || 0;
            var mouseY = (e.pageY - canvasPosition.top) || 0;
            var ri = Math.floor(mouseX / MG.cg.cellWidth);
            var ci = Math.floor(mouseY / MG.cg.cellWidth);
            openCell(ri, ci);
        }
    });
}

/**
 * 判断是否是雷区
 * @param ri
 * @param ci
 * @param isFlag
 */
function checkMine(ri, ci, isFlag) {
    if (isFlag) {
        // 正确标旗
        if (MG.dataMap[ri][ci].data < 0) {
            addScore(true);
        } else {
            drawBoomCell(ri, ci);
            stopGame(false);
        }
    } else {
        // 正确打开格子
        if (MG.dataMap[ri][ci].data > -1) {
            addScore(false);
        } else {
            drawBoomCell(ri, ci);
            stopGame(false);
        }
    }
}

/**
 * 计算分数
 */
function addScore(isFlag) {
    if (isFlag) {
        MG.residualMines--;
        $("#residual_mines").text(MG.residualMines);
    }
    MG.score++;
    $("#score").text(MG.score);
}

/**
 * 清除画布
 * @param ctx
 */
function clear(ctx) {
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}

/**
 * 绘制格子线
 */
function drawGridCells() {
    var cellWidth = MG.cg.cellWidth;
    var rows = MG.cg.range.rows + 1;
    var columns = MG.cg.range.columns + 1;
    var ctx = MG.layers[0];

    clear(ctx);

    for (var ri = 0; ri < rows; ri++) {
        ctx.moveTo(0, ri * cellWidth);
        ctx.lineTo(MG.cg.range.columns * cellWidth, ri * cellWidth);
        ctx.stroke();
    }
    for (var ci = 0; ci < columns; ci++) {
        ctx.moveTo(ci * cellWidth, 0);
        ctx.lineTo(ci * cellWidth, MG.cg.range.rows * cellWidth);
        ctx.stroke();
    }
}

/**
 * 绘制格子
 */
function drawDataMap() {
    var rows = MG.cg.range.rows;
    var columns = MG.cg.range.columns;

    for (var ri = 0; ri < rows; ri++) {
        for (var ci = 0; ci < columns; ci++) {
            drawCell(ri, ci);
        }
    }
}

/**
 * 绘制遮罩
 */
function drawMask() {
    var cellWidth = MG.cg.cellWidth;
    var rows = MG.cg.range.rows;
    var columns = MG.cg.range.columns;
    var ctx = MG.layers[1];

    for (var ri = 0; ri < rows; ri++) {
        for (var ci = 0; ci < columns; ci++) {
            ctx.fillStyle = "lightblue";
            ctx.fillRect(ri * cellWidth + 1, ci * cellWidth + 1, cellWidth - 1, cellWidth - 1);
        }
    }
}

/**
 * 绘制格子
 * @param ri
 * @param ci
 */
function drawCell(ri, ci) {
    var cellWidth = MG.cg.cellWidth;
    var ctx = MG.layers[0];
    ctx.textAlign = "center";
    ctx.font = "30px Arial";
    var msg = "";

    if (MG.dataMap[ri][ci].data < 0) {
        ctx.fillStyle = "lightgray";
        msg = "M";
    } else if (MG.dataMap[ri][ci].data > 0) {
        ctx.fillStyle = "blue";
        msg = MG.dataMap[ri][ci].data;
    } else {
        ctx.fillStyle = "green";
        msg = "";
    }
    ctx.fillRect(ri * cellWidth + 1, ci * cellWidth + 1, cellWidth - 2, cellWidth - 2);
    ctx.fillStyle = "#f00";
    ctx.fillText(msg, ri * cellWidth + cellWidth / 2, ci * cellWidth + (cellWidth / 1.4));
}

/**
 * 绘制爆炸格子
 * @param ri
 * @param ci
 */
function drawBoomCell(ri, ci) {
    var cellWidth = MG.cg.cellWidth;
    var ctx = MG.layers[0];
    ctx.textAlign = "center";
    ctx.font = "30px Arial";
    var msg = "";

    if (MG.dataMap[ri][ci].data < 0) {
        ctx.fillStyle = "red";
        msg = "M";
    } else if (MG.dataMap[ri][ci].data > 0) {
        ctx.fillStyle = "red";
        msg = MG.dataMap[ri][ci].data;
    }
    ctx.fillRect(ri * cellWidth + 1, ci * cellWidth + 1, cellWidth - 2, cellWidth - 2);
    ctx.fillStyle = "darkgray";
    ctx.fillText(msg, ri * cellWidth + cellWidth / 2, ci * cellWidth + (cellWidth / 1.4));
}

/**
 * 打开所有格子
 */
function openAllCell() {
    var cellWidth = MG.cg.cellWidth;
    var rows = MG.cg.range.rows;
    var columns = MG.cg.range.columns;
    var ctx = MG.layers[1];

    for (var ri = 0; ri < rows; ri++) {
        for (var ci = 0; ci < columns; ci++) {
            ctx.clearRect(ri * cellWidth + 1, ci * cellWidth + 1, cellWidth - 1, cellWidth - 1);
        }
    }
}

/**
 * 打开格子
 * @param ri
 * @param ci
 */
function openCell(ri, ci) {
    if (!MG.dataMap[ri][ci].isOpened && !MG.dataMap[ri][ci].isFlag) {
        var cellWidth = MG.cg.cellWidth;
        var ctx = MG.layers[1];
        ctx.clearRect(ri * cellWidth + 1, ci * cellWidth + 1, cellWidth - 1, cellWidth - 1);
        MG.dataMap[ri][ci].isOpened = true;
        checkMine(ri, ci, false);
    }
}

/**
 * 标记旗子
 * @param ri
 * @param ci
 */
function drawFlag(ri, ci) {
    var ctx = MG.layers[1];

    if (MG.dataMap[ri][ci].isOpened) {
        return;
    }

    var cellWidth = MG.cg.cellWidth;

    MG.dataMap[ri][ci].isFlag = !MG.dataMap[ri][ci].isFlag;
    if (MG.dataMap[ri][ci].isFlag) {
        ctx.fillStyle = "#abc";
        ctx.fillRect(ri * cellWidth + cellWidth / 4, ci * cellWidth + cellWidth / 4, cellWidth / 2 - 1, cellWidth / 2 - 1);
        checkMine(ri, ci, true);
    } else {
        ctx.clearRect(ri * cellWidth + cellWidth / 4, ci * cellWidth + cellWidth / 4, cellWidth / 2 - 1, cellWidth / 2 - 1);
        ctx.fillStyle = "lightblue";
        ctx.fillRect(ri * cellWidth + cellWidth / 4 - 1, ci * cellWidth + cellWidth / 4 - 1, cellWidth / 2, cellWidth / 2 + 1);
    }
}

/**
 * 屏蔽右键事件
 * @param e
 */
function disableRightClick(e) {
    if (document.all) {
        window.event.returnValue = false;
    } else {
        event.preventDefault();
    }
}

/**
 * 初始化游戏
 */
function initGame() {
    MG.timeout = 0;
    MG.layers = [];
    var canvas_bg = document.getElementById("bg");
    MG.layers[0] = canvas_bg.getContext("2d");
    canvas_bg.oncontextmenu = disableRightClick;
    var canvas_game = document.getElementById("game");
    MG.layers[1] = canvas_game.getContext("2d");
    canvas_game.oncontextmenu = disableRightClick;

    MG.dataMap = [];
    MG.currentLevel = 0;
    MG.residualMines = 20;
    MG.score = 0;

    $("#residual_mines").text(0);
    $("#score").text(MG.score);
    stopInterval();

    setCurrentGame();
    drawGridCells();
    drawMask();
}

function setCurrentGame() {
    MG.cg = MG.levels[MG.currentLevel];
}

/**
 * 开始游戏
 */
function startGame() {
    initLayers();
    bindEvent();
    createGameData();
    drawDataMap();
}

/**
 * 停止计时器
 */
function stopInterval() {
    clearInterval(MG.timer);
    MG.timer = 0;
    MG.elapsedTime = 0;
    $("#elapsed_time").text(MG.elapsedTime);
}

/**
 * 结束游戏
 * @param isWon
 */
function stopGame(isWon) {
    var msg = "";
    if (isWon) {
        msg = "你赢了";
    } else {
        msg = "你输了";
    }
    if (confirm(msg)) {
        stopInterval();
        openAllCell();
    }
}

/**
 * 游戏入口
 */
$(function () {
    initGame();
});
<commit_msg>积分版完成V0<commit_after>/**
 * Created by yuqy on 2017/9/29.
 */
var MG = {
    layers: [], /* 画布层 */
    dataMap: [], /* 雷区地图 */
    currentLevel: 0, /* 当前游戏级别 */
    cg: null, /* 当前游戏 */
    residualMines: 20, /* 剩余雷数 */
    elapsedTime: 0, /* 经过时间 */
    timer: 0, /* 计时器 */
    timeout: 0, /* 计时器句柄 */
    score: 0 /* 得分 */
};

MG.levels = [
    {
        level: 0,
        width: 400,
        height: 400,
        cellWidth: 50,
        mineCount: 20,
        range: {
            rows: 8,
            columns: 8
        }
    }
];

/**
 * 格子
 * @constructor
 */
function Cell() {
    this.data = 0;
    this.isOpened = false;
    this.isFlag = false;
}

/**
 * 随机生成格子地址
 * @returns {*[]}
 */
function getRandomPosition() {
    return {
        x: getRandom(MG.cg.range.rows),
        y: getRandom(MG.cg.range.columns)
    };
}

/**
 * 生成雷区地图
 */
function createGameData() {
    initDataMap();
    createMines();
}

/**
 * 生成空白地图
 */
function initDataMap() {
    for (var r = 0; r < MG.cg.range.rows; r++) {
        MG.dataMap[r] = Array.apply(null, Array(MG.cg.range.columns)).map(function (i) {
            return new Cell();
        });
    }
}

/**
 * 生成地雷
 * 扫描地雷周围，生成格子周围地雷数
 */
function createMines() {
    var mineCount = MG.cg.mineCount;
    var tempArr = {};
    while (mineCount > 0) {
        var pos = getRandomPosition();
        var key = pos.x + "=" + pos.y;
        if (!tempArr[key]) {
            tempArr[key] = 1;
            MG.dataMap[pos.x][pos.y].data = -1;
            scanAroundCell(pos);
            mineCount--;
        }
    }
    tempArr = null;
}

/**
 * 扫描当前格子周围8格，更新地雷数
 * @param pos
 */
function scanAroundCell(pos) {
    var rows = MG.cg.range.rows;
    var columns = MG.cg.range.columns;
    for (var ri = -1; ri < 2; ri++) {
        var r = pos.x + ri;
        if (r > -1 && r < rows) {
            for (var ci = -1; ci < 2; ci++) {
                var c = pos.y + ci;
                if (c > -1 && c < columns && !(r == pos.x && c == pos.y) && MG.dataMap[r][c].data > -1) {
                    MG.dataMap[r][c].data++;
                }
            }
        }
    }
}

//////////////////////////////////////////////////
//// 画布相关
//////////////////////////////////////////////////
/**
 * 初始化游戏画布
 */
function initLayers() {
    MG.layers.forEach(function (i) {
            //MG.layers[i].canvas.oncontextmenu = function (e) {
            //    if (document.all) {
            //        window.event.returnValue = false;
            //    } else {
            //        event.preventDefault();
            //    }
            //}
        }
    );

    $("#elapsed_time").text(MG.elapsedTime);
    MG.timer = setInterval(function () {
        MG.elapsedTime++;
        $("#elapsed_time").text(MG.elapsedTime);
    }, 1000);
    $("#residual_mines").text(MG.residualMines);
}

/**
 * 绑定事件
 */
function bindEvent() {
    var layers = $("#layers");
    layers.oncontextmenu = disableRightClick;
    layers.mousedown(function (e) {
        var canvasPosition = $(this).offset();
        var mouseX = (e.pageX - canvasPosition.left) || 0;
        var mouseY = (e.pageY - canvasPosition.top) || 0;
        var ri = Math.floor(mouseX / MG.cg.cellWidth);
        var ci = Math.floor(mouseY / MG.cg.cellWidth);
        ri = ri >= MG.cg.range.rows ? MG.cg.range.rows - 1 : ri;
        ci = ci >= MG.cg.range.columns ? MG.cg.range.columns - 1 : ci;

        MG.timeout = setTimeout(function (e) {
            checkMine(ri, ci, true);
            MG.timeout = 0;
        }, 1000);
    });
    layers.mousemove(function (e) {
        clearTimeout(MG.timeout);
        MG.timeout = 0;
    });
    layers.mouseup(function (e) {
        clearTimeout(MG.timeout);
        if (MG.timeout != 0) {
            var canvasPosition = $(this).offset();
            var mouseX = (e.pageX - canvasPosition.left) || 0;
            var mouseY = (e.pageY - canvasPosition.top) || 0;
            var ri = Math.floor(mouseX / MG.cg.cellWidth);
            var ci = Math.floor(mouseY / MG.cg.cellWidth);
            ri = ri >= MG.cg.range.rows ? MG.cg.range.rows - 1 : ri;
            ci = ci >= MG.cg.range.columns ? MG.cg.range.columns - 1 : ci;

            checkMine(ri, ci, false);
        }
    });
}

/**
 * 判断输赢
 */
function checkWin() {
}

/**
 * 判断是否是雷区
 * @param ri
 * @param ci
 * @param isFlag
 */
function checkMine(ri, ci, isFlag) {
    if (MG.dataMap[ri][ci].isFlag || MG.dataMap[ri][ci].isOpened) {
        return;
    }

    // 判断是否是标旗动作
    if (isFlag) {
        // 正确标旗
        if (MG.dataMap[ri][ci].data < 0) {
            drawFlag(ri, ci);
            addScore(true);
        } else {
            openCell(ri, ci);
            drawBoomCell(ri, ci);
            //stopGame(true);
            subtractScore(true);
        }
    } else {
        openCell(ri, ci);
        // 正确打开格子
        if (MG.dataMap[ri][ci].data > -1) {
            addScore(false);
        } else {
            drawBoomCell(ri, ci);
            //stopGame(false);
            subtractScore(false);
        }
    }

    // 雷区全部清除后，停止计时
    if (MG.residualMines == 0) {
        stopInterval();
        if (confirm("你的得分：" + MG.score)) {
            resetGame();
        }
    }
}

/**
 * 加分数
 * @param isFlag
 */
function addScore(isFlag) {
    if (isFlag) {
        MG.residualMines--;
        $("#residual_mines").text(MG.residualMines);
    }
    MG.score++;
    $("#score").text(MG.score);
}

/**
 * 减分数
 * @param isFlag
 */
function subtractScore(isFlag) {
    if (!isFlag) {
        MG.residualMines--;
        $("#residual_mines").text(MG.residualMines);
    }
    MG.score--;
    $("#score").text(MG.score);
}

/**
 * 清除画布
 * @param ctx
 */
function clear(ctx) {
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}

/**
 * 绘制格子线
 */
function drawGridCells() {
    var cellWidth = MG.cg.cellWidth;
    var rows = MG.cg.range.rows + 1;
    var columns = MG.cg.range.columns + 1;
    var ctx = MG.layers[0];

    clear(ctx);

    for (var ri = 0; ri < rows; ri++) {
        ctx.moveTo(0, ri * cellWidth);
        ctx.lineTo(MG.cg.range.columns * cellWidth, ri * cellWidth);
        ctx.stroke();
    }
    for (var ci = 0; ci < columns; ci++) {
        ctx.moveTo(ci * cellWidth, 0);
        ctx.lineTo(ci * cellWidth, MG.cg.range.rows * cellWidth);
        ctx.stroke();
    }
}

/**
 * 绘制格子
 */
function drawDataMap() {
    var rows = MG.cg.range.rows;
    var columns = MG.cg.range.columns;

    for (var ri = 0; ri < rows; ri++) {
        for (var ci = 0; ci < columns; ci++) {
            drawCell(ri, ci);
        }
    }
}

/**
 * 绘制遮罩
 */
function drawMask() {
    var cellWidth = MG.cg.cellWidth;
    var rows = MG.cg.range.rows;
    var columns = MG.cg.range.columns;
    var ctx = MG.layers[1];

    for (var ri = 0; ri < rows; ri++) {
        for (var ci = 0; ci < columns; ci++) {
            ctx.fillStyle = "lightblue";
            ctx.fillRect(ri * cellWidth + 1, ci * cellWidth + 1, cellWidth - 1, cellWidth - 1);
        }
    }
}

/**
 * 绘制格子
 * @param ri
 * @param ci
 */
function drawCell(ri, ci) {
    var cellWidth = MG.cg.cellWidth;
    var ctx = MG.layers[0];
    ctx.textAlign = "center";
    ctx.font = "30px Arial";
    var msg = "";

    if (MG.dataMap[ri][ci].data < 0) {
        ctx.fillStyle = "lightgray";
        msg = "M";
    } else if (MG.dataMap[ri][ci].data > 0) {
        ctx.fillStyle = "blue";
        msg = MG.dataMap[ri][ci].data;
    } else {
        ctx.fillStyle = "green";
        msg = "";
    }
    ctx.fillRect(ri * cellWidth + 1, ci * cellWidth + 1, cellWidth - 2, cellWidth - 2);
    ctx.fillStyle = "#f00";
    ctx.fillText(msg, ri * cellWidth + cellWidth / 2, ci * cellWidth + (cellWidth / 1.4));
}

/**
 * 绘制爆炸格子
 * @param ri
 * @param ci
 */
function drawBoomCell(ri, ci) {
    var cellWidth = MG.cg.cellWidth;
    var ctx = MG.layers[0];
    ctx.textAlign = "center";
    ctx.font = "30px Arial";
    var msg = "";

    if (MG.dataMap[ri][ci].data < 0) {
        ctx.fillStyle = "red";
        msg = "M";
    } else if (MG.dataMap[ri][ci].data > 0) {
        ctx.fillStyle = "red";
        msg = MG.dataMap[ri][ci].data;
    }
    ctx.fillRect(ri * cellWidth + 1, ci * cellWidth + 1, cellWidth - 2, cellWidth - 2);
    ctx.fillStyle = "darkgray";
    ctx.fillText(msg, ri * cellWidth + cellWidth / 2, ci * cellWidth + (cellWidth / 1.4));
}

/**
 * 打开所有格子
 */
function openAllCell() {
    var cellWidth = MG.cg.cellWidth;
    var rows = MG.cg.range.rows;
    var columns = MG.cg.range.columns;
    var ctx = MG.layers[1];

    for (var ri = 0; ri < rows; ri++) {
        for (var ci = 0; ci < columns; ci++) {
            ctx.clearRect(ri * cellWidth + 1, ci * cellWidth + 1, cellWidth - 1, cellWidth - 1);
        }
    }
}

/**
 * 打开格子
 * @param ri
 * @param ci
 */
function openCell(ri, ci) {
    if (!MG.dataMap[ri][ci].isOpened && !MG.dataMap[ri][ci].isFlag) {
        var cellWidth = MG.cg.cellWidth;
        var ctx = MG.layers[1];
        ctx.clearRect(ri * cellWidth + 1, ci * cellWidth + 1, cellWidth - 1, cellWidth - 1);
        MG.dataMap[ri][ci].isOpened = true;
    }
}

/**
 * 标记旗子
 * @param ri
 * @param ci
 */
function drawFlag(ri, ci) {
    var ctx = MG.layers[1];

    if (MG.dataMap[ri][ci].isOpened) {
        return;
    }

    var cellWidth = MG.cg.cellWidth;

    MG.dataMap[ri][ci].isFlag = !MG.dataMap[ri][ci].isFlag;
    if (MG.dataMap[ri][ci].isFlag) {
        ctx.fillStyle = "#abc";
        ctx.fillRect(ri * cellWidth + cellWidth / 4, ci * cellWidth + cellWidth / 4, cellWidth / 2 - 1, cellWidth / 2 - 1);
    } else {
        ctx.clearRect(ri * cellWidth + cellWidth / 4, ci * cellWidth + cellWidth / 4, cellWidth / 2 - 1, cellWidth / 2 - 1);
        ctx.fillStyle = "lightblue";
        ctx.fillRect(ri * cellWidth + cellWidth / 4 - 1, ci * cellWidth + cellWidth / 4 - 1, cellWidth / 2, cellWidth / 2 + 1);
    }
}

/**
 * 屏蔽右键事件
 * @param e
 */
function disableRightClick(e) {
    if (document.all) {
        window.event.returnValue = false;
    } else {
        event.preventDefault();
    }
}

/**
 * 初始化游戏
 */
function initGame() {
    MG.timeout = 0;
    MG.layers = [];
    var canvas_bg = document.getElementById("bg");
    MG.layers[0] = canvas_bg.getContext("2d");
    canvas_bg.oncontextmenu = disableRightClick;
    var canvas_game = document.getElementById("game");
    MG.layers[1] = canvas_game.getContext("2d");
    canvas_game.oncontextmenu = disableRightClick;

    MG.dataMap = [];
    MG.currentLevel = 0;
    MG.residualMines = 20;
    MG.score = 0;

    $("#residual_mines").text(0);
    $("#score").text(MG.score);
    stopInterval();

    setCurrentGame();
    drawGridCells();
    drawMask();
}

function setCurrentGame() {
    MG.cg = MG.levels[MG.currentLevel];
}

/**
 * 开始游戏
 */
function startGame() {
    initLayers();
    bindEvent();
    createGameData();
    drawDataMap();
}

/**
 * 重置游戏
 */
function resetGame() {
    initGame();
    startGame();
}

/**
 * 停止计时器
 */
function stopInterval() {
    clearInterval(MG.timer);
    MG.timer = 0;
    MG.elapsedTime = 0;
    $("#elapsed_time").text(MG.elapsedTime);
}

/**
 * 结束游戏
 * @param isWon
 */
function stopGame(isWon) {
    var msg = "";
    if (isWon) {
        msg = "你赢了";
    } else {
        msg = "你输了";
    }
    if (confirm(msg)) {
        stopInterval();
        openAllCell();
    }
}

/**
 * 游戏入口
 */
$(function () {
    initGame();
});
<|endoftext|>


<commit_before>var
	i18n = require('enyo/i18n'),
	platform = require('enyo/platform');

var
	Locale = require('enyo-ilib/Locale');

/**
* `moon-fonts` is the locale-specific font generator, allowing any locale to have its own custom
* font. Each locale-font from the configuration block (defined in this file) is generated at
* run-time. If the locale you're currently in is in the locale-font list an additional
* `@font-face` rule will be generated that will override the standard "Moonstone LG Display"
* font.
*
* Below is example genarated-output of the Urdu ("ur") locale-font.
*
* ```css
* @font-face {
* 	font-family: 'Moonstone LG Display ur';
* 	font-weight: normal;
* 	src: local('LG Display_Urdu');
* 	unicode-range: U+0600-U+06FF, U+FE70-U+FEFE, U+FB50-U+FDFF;
* }
* @font-face {
* 	font-family: 'Moonstone LG Display ur Bold';
* 	font-weight: normal;
* 	src: local('LG Display_Urdu');
* 	unicode-range: U+0600-U+06FF, U+FE70-U+FEFE, U+FB50-U+FDFF;
* }
* @font-face {
* 	font-family: 'Moonstone LG Display ur Light';
* 	font-weight: normal;
* 	src: local('LG Display_Urdu');
* 	unicode-range: U+0600-U+06FF, U+FE70-U+FEFE, U+FB50-U+FDFF;
* }
* ```
*
* @name International Fonts
* @public
*/

function funLocaleSpecificFonts () {
	var loc = new Locale(),
		language = loc.getLanguage(),
		region = loc.getRegion(),
		styleId = 'enyo-localization-font-override',
		styleElem = document.getElementById(styleId),
		fontDefinitionCss = '',
		// Locale Configuration Block
		fonts = {
			'NonLatin': {
				regular: 'LG Display-Light',
				bold:    'LG Display-Regular'
			},
			'ja': {
				regular: 'LG Display_JP',
				unicodeRanges:
					'U+0000-U+00FF,' +
					'U+2E80-U+2EFF,' +
					'U+2F00-U+2FDF,' +
					'U+3000-U+303F,' +
					'U+3040-U+309F,' +
					'U+30A0-U+30FF,' +
					'U+3200-U+33FF,' +
					'U+3400-U+4DBF,' +
					'U+4E00-U+9FFF,' +
					'U+E000-U+FAFF,' +
					'U+FF00-U+FFEF'
			},
			'en-JP': {
				regular: 'LG Display_JP',
				unicodeRanges:
					'U+20-7E,U+A0-FF,U+131,U+141-142,U+152-153,U+160-161,U+178,U+17D-17E,U+391-3A1,' +
					'U+3A3-3A9,U+3B1-3C1,U+3C3-3C9,U+2010,U+2012-2015,U+2018-201A,U+201C-201E,' +
					'U+2020-2022,U+2025-2026,U+2030,U+2032-2033,U+2039-203C,U+203E,U+2044,U+2049,' +
					'U+2103,U+2109-210A,U+2113,U+2116,U+2121-2122,U+212B,U+213B,U+2200,U+2202-2203,' +
					'U+2207-2208,U+220B,U+2211-2212,U+221A,U+221D-2220,U+2225,U+2227-222E,' +
					'U+2234-2235,U+223C-223D,U+2252,U+2260-2261,U+2266-2267,U+226A-226B,' +
					'U+2282-2283,U+2286-2287,U+22A5,U+22BF,U+22EF,U+2312,U+E040-E04B,U+E080-E095,' +
					'U+E0C9-E0CE,U+E0D0-E0D3,U+E0D8-E0D9,U+E0DC-E0F0,U+E0F5-E0FF,U+E180-E19C,' +
					'U+E1A7-E1D7,U+E285-E2C6,U+E2CA-E2E2,U+E2E5-E2F7,U+E2F9-E2FB,U+E2FF,' +
					'U+E380-E3A5,U+E3A7-E3A8,U+FB01-FB02'
			},
			'ur': {
				regular: 'LG Display_Urdu',
				unicodeRanges:
					'U+0600-U+06FF, ' +
					'U+FE70-U+FEFE, ' +
					'U+FB50-U+FDFF'
			},
			'zh-HK': {
				regular: 'LG Display GP4_HK-Light',
				bold:    'LG Display GP4_HK-Regular',
				unicodeRanges:
					'U+0000-U+00FF,' +
					'U+2E80-U+2EFF,' +
					'U+3000-U+303F,' +
					'U+3200-U+33FF,' +
					'U+3400-U+4DBF,' +
					'U+4E00-U+9FFF,' +
					'U+E000-U+FAFF,' +
					'U+FF00-U+FFEF'
			}
		};

	// Duplications and alternate locale names
	fonts['zh-TW'] = fonts['zh-HK'];

	// Generate a single font-face rule
	this.buildFont = function(inOptions) {
		if (!inOptions && !inOptions.name) {
			return '';
		}
		var strOut = '@font-face { \n' +
			'  font-family: "' + inOptions.name + '";\n' +
			'  font-weight: ' + ( inOptions.weight || 'normal' ) + ';\n';

		if (inOptions.localName) {
			strOut+= '  src: local("' + inOptions.localName + '");\n';
		}
		if (inOptions.unicodeRanges) {
			strOut+= '  unicode-range: ' + inOptions.unicodeRanges + ';\n';
		}
		strOut+= '} \n';
		return strOut;
	};

	// Generate a collection of font-face rules, in multiple font-variants
	this.buildFontSet = function(strLang, bitDefault) {
		var strOut = '',
			name = (bitDefault) ? '' : ' ' + strLang;

		if (fonts[strLang].regular) {
			// Build Regular
			strOut+= this.buildFont({
				name: 'Moonstone LG Display' + name,
				localName: fonts[strLang].regular,
				unicodeRanges: fonts[strLang].unicodeRanges
			});

			// Build Bold
			strOut+= this.buildFont({
				name: 'Moonstone LG Display' + name + ' Bold',
				localName: fonts[strLang].bold || fonts[strLang].regular,
				unicodeRanges: fonts[strLang].unicodeRanges
			});

			// Build Light
			strOut+= this.buildFont({
				name: 'Moonstone LG Display' + name + ' Light',
				localName: fonts[strLang].light || fonts[strLang].regular,
				unicodeRanges: fonts[strLang].unicodeRanges
			});
		}
		return strOut;
	};

	if (!styleElem) {
		styleElem = document.createElement('style');
		styleElem.setAttribute('id', styleId);
		if (platform.ie === 8) {
			// ENYO-3944: Using getElementsByTagName('head') for IE8 Sampler support
			document.getElementsByTagName('head')[0].appendChild(styleElem);
		} else {
			document.head.appendChild(styleElem);
		}
	}

	// Build all the fonts so they could be explicitly called
	for (var lang in fonts) {
		fontDefinitionCss+= this.buildFontSet(lang);
	}

	// Set up the override so "Moonstone LG Display" becomes the local-specific font.
	if (language === 'ja') {
		fontDefinitionCss+= this.buildFontSet('ja', true);
	}
	else if (language === 'en' && region === 'JP') {
		fontDefinitionCss+= this.buildFontSet('en-JP', true);
	}
	else if (language === 'ur') {
		fontDefinitionCss+= this.buildFontSet('ur', true);
	}
	else if (language === 'zh' && region === 'HK') {
		fontDefinitionCss+= this.buildFontSet('zh-HK', true);
	}
	else if (language === 'zh' && region === 'TW') {
		fontDefinitionCss+= this.buildFontSet('zh-TW', true);
	}

	// ENYO-3944: IE8 Sampler support - IE8 does not allow innerHTML modification of <style> elements
	if (platform.ie !== 8) {
		styleElem.innerHTML = fontDefinitionCss;
	}
}

i18n.updateLocale.extend(function (sup) {
	return function() {
		sup.apply(this, arguments);
		funLocaleSpecificFonts();
	};
});

funLocaleSpecificFonts();<commit_msg>Corrected some mistakes in the unicodeRange definitions, and simplified some zero-padded ranges. https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/unicode-range<commit_after>var
	i18n = require('enyo/i18n'),
	platform = require('enyo/platform');

var
	Locale = require('enyo-ilib/Locale');

/**
* `moon-fonts` is the locale-specific font generator, allowing any locale to have its own custom
* font. Each locale-font from the configuration block (defined in this file) is generated at
* run-time. If the locale you're currently in is in the locale-font list an additional
* `@font-face` rule will be generated that will override the standard "Moonstone LG Display"
* font.
*
* Below is example genarated-output of the Urdu ("ur") locale-font.
*
* ```css
* @font-face {
* 	font-family: 'Moonstone LG Display ur';
* 	font-weight: normal;
* 	src: local('LG Display_Urdu');
* 	unicode-range: U+0600-U+06FF, U+FE70-U+FEFE, U+FB50-U+FDFF;
* }
* @font-face {
* 	font-family: 'Moonstone LG Display ur Bold';
* 	font-weight: normal;
* 	src: local('LG Display_Urdu');
* 	unicode-range: U+0600-U+06FF, U+FE70-U+FEFE, U+FB50-U+FDFF;
* }
* @font-face {
* 	font-family: 'Moonstone LG Display ur Light';
* 	font-weight: normal;
* 	src: local('LG Display_Urdu');
* 	unicode-range: U+0600-U+06FF, U+FE70-U+FEFE, U+FB50-U+FDFF;
* }
* ```
*
* @name International Fonts
* @public
*/

function funLocaleSpecificFonts () {
	var loc = new Locale(),
		language = loc.getLanguage(),
		region = loc.getRegion(),
		styleId = 'enyo-localization-font-override',
		styleElem = document.getElementById(styleId),
		fontDefinitionCss = '',
		// Locale Configuration Block
		fonts = {
			'NonLatin': {
				regular: 'LG Display-Light',
				bold:    'LG Display-Regular'
			},
			'ja': {
				regular: 'LG Display_JP',
				unicodeRanges:
					'U+0-FF,' +
					'U+2E80-2EFF,' +
					'U+2F00-2FDF,' +
					'U+3000-303F,' +
					'U+3040-309F,' +
					'U+30A0-30FF,' +
					'U+3200-33FF,' +
					'U+3400-4DBF,' +
					'U+4E00-9FFF,' +
					'U+E000-FAFF,' +
					'U+FF00-FFEF'
			},
			'en-JP': {
				regular: 'LG Display_JP',
				unicodeRanges:
					'U+20-7E,U+A0-FF,U+131,U+141-142,U+152-153,U+160-161,U+178,U+17D-17E,U+391-3A1,' +
					'U+3A3-3A9,U+3B1-3C1,U+3C3-3C9,U+2010,U+2012-2015,U+2018-201A,U+201C-201E,' +
					'U+2020-2022,U+2025-2026,U+2030,U+2032-2033,U+2039-203C,U+203E,U+2044,U+2049,' +
					'U+2103,U+2109-210A,U+2113,U+2116,U+2121-2122,U+212B,U+213B,U+2200,U+2202-2203,' +
					'U+2207-2208,U+220B,U+2211-2212,U+221A,U+221D-2220,U+2225,U+2227-222E,' +
					'U+2234-2235,U+223C-223D,U+2252,U+2260-2261,U+2266-2267,U+226A-226B,' +
					'U+2282-2283,U+2286-2287,U+22A5,U+22BF,U+22EF,U+2312,U+E040-E04B,U+E080-E095,' +
					'U+E0C9-E0CE,U+E0D0-E0D3,U+E0D8-E0D9,U+E0DC-E0F0,U+E0F5-E0FF,U+E180-E19C,' +
					'U+E1A7-E1D7,U+E285-E2C6,U+E2CA-E2E2,U+E2E5-E2F7,U+E2F9-E2FB,U+E2FF,' +
					'U+E380-E3A5,U+E3A7-E3A8,U+FB01-FB02'
			},
			'ur': {
				regular: 'LG Display_Urdu',
				unicodeRanges:
					'U+600-6FF,' +
					'U+FE70-FEFE,' +
					'U+FB50-FDFF'
			},
			'zh-HK': {
				regular: 'LG Display GP4_HK-Light',
				bold:    'LG Display GP4_HK-Regular',
				unicodeRanges:
					'U+0-FF,' +
					'U+2E80-2EFF,' +
					'U+3000-303F,' +
					'U+3200-33FF,' +
					'U+3400-4DBF,' +
					'U+4E00-9FFF,' +
					'U+E000-FAFF,' +
					'U+FF00-FFEF'
			}
		};

	// Duplications and alternate locale names
	fonts['zh-TW'] = fonts['zh-HK'];

	// Generate a single font-face rule
	this.buildFont = function(inOptions) {
		if (!inOptions && !inOptions.name) {
			return '';
		}
		var strOut = '@font-face { \n' +
			'  font-family: "' + inOptions.name + '";\n' +
			'  font-weight: ' + ( inOptions.weight || 'normal' ) + ';\n';

		if (inOptions.localName) {
			strOut+= '  src: local("' + inOptions.localName + '");\n';
		}
		if (inOptions.unicodeRanges) {
			strOut+= '  unicode-range: ' + inOptions.unicodeRanges + ';\n';
		}
		strOut+= '} \n';
		return strOut;
	};

	// Generate a collection of font-face rules, in multiple font-variants
	this.buildFontSet = function(strLang, bitDefault) {
		var strOut = '',
			name = (bitDefault) ? '' : ' ' + strLang;

		if (fonts[strLang].regular) {
			// Build Regular
			strOut+= this.buildFont({
				name: 'Moonstone LG Display' + name,
				localName: fonts[strLang].regular,
				unicodeRanges: fonts[strLang].unicodeRanges
			});

			// Build Bold
			strOut+= this.buildFont({
				name: 'Moonstone LG Display' + name + ' Bold',
				localName: fonts[strLang].bold || fonts[strLang].regular,
				unicodeRanges: fonts[strLang].unicodeRanges
			});

			// Build Light
			strOut+= this.buildFont({
				name: 'Moonstone LG Display' + name + ' Light',
				localName: fonts[strLang].light || fonts[strLang].regular,
				unicodeRanges: fonts[strLang].unicodeRanges
			});
		}
		return strOut;
	};

	if (!styleElem) {
		styleElem = document.createElement('style');
		styleElem.setAttribute('id', styleId);
		if (platform.ie === 8) {
			// ENYO-3944: Using getElementsByTagName('head') for IE8 Sampler support
			document.getElementsByTagName('head')[0].appendChild(styleElem);
		} else {
			document.head.appendChild(styleElem);
		}
	}

	// Build all the fonts so they could be explicitly called
	for (var lang in fonts) {
		fontDefinitionCss+= this.buildFontSet(lang);
	}

	// Set up the override so "Moonstone LG Display" becomes the local-specific font.
	if (language === 'ja') {
		fontDefinitionCss+= this.buildFontSet('ja', true);
	}
	else if (language === 'en' && region === 'JP') {
		fontDefinitionCss+= this.buildFontSet('en-JP', true);
	}
	else if (language === 'ur') {
		fontDefinitionCss+= this.buildFontSet('ur', true);
	}
	else if (language === 'zh' && region === 'HK') {
		fontDefinitionCss+= this.buildFontSet('zh-HK', true);
	}
	else if (language === 'zh' && region === 'TW') {
		fontDefinitionCss+= this.buildFontSet('zh-TW', true);
	}

	// ENYO-3944: IE8 Sampler support - IE8 does not allow innerHTML modification of <style> elements
	if (platform.ie !== 8) {
		styleElem.innerHTML = fontDefinitionCss;
	}
}

i18n.updateLocale.extend(function (sup) {
	return function() {
		sup.apply(this, arguments);
		funLocaleSpecificFonts();
	};
});

funLocaleSpecificFonts();<|endoftext|>


<commit_before>(function( factory ) {
    if( typeof define === 'function' && define.amd )
    {
        define( 'image-filename', factory );
    }
    else if( typeof module === 'object' && module.exports )
    {
        module.exports = factory();
    }
}( function() {

        'use strict';

        var imageFilename = {};

        var FORMAT_VERSION = '2';

        var base58 = (function() {
            /**
             * @url https://gist.github.com/inflammable/2929362
             */
            var bs58 = (function( alphabet ) {
                var base = alphabet.length;
                return {
                    encode: function( enc ) {
                        if( typeof enc !== 'number' || enc !== parseInt( enc ) )
                            throw '"encode" only accepts integers.';
                        var encoded = '';
                        while( enc )
                        {
                            var remainder = enc % base;
                            enc = Math.floor( enc / base );
                            encoded = alphabet[remainder].toString() + encoded;
                        }
                        return encoded;
                    },
                    decode: function( dec ) {
                        if( typeof dec !== 'string' )
                            throw '"decode" only accepts strings.';
                        var decoded = 0;
                        while( dec )
                        {
                            var alphabetPosition = alphabet.indexOf( dec[0] );
                            if( alphabetPosition < 0 )
                                throw '"decode" can\'t find "' + dec[0] + '" in the alphabet: "' + alphabet + '"';
                            var powerOf = dec.length - 1;
                            decoded += alphabetPosition * (Math.pow( base, powerOf ));
                            dec = dec.substring( 1 );
                        }
                        return decoded;
                    }
                };
            })( '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' );

            return {
                encode: function( num, fixedLength ) {
                    var b58 = bs58.encode( parseInt( num ) );
                    if( !fixedLength ) return b58;
                    if( b58.length > fixedLength ) return new Error( 'number length is more than required' );
                    while( b58.length < fixedLength ) b58 = '1' + b58;
                    return b58;
                },
                decode: function( b58 ) {
                    return bs58.decode( b58 );
                }
            }
        })();

        imageFilename.decode = function( filename ) {
            var reL1 = /(\w+)(\w)(-o[\w-]*)(\.\w{3,4})?$/,
                reL2 = /-(o|t|r|f)(\w*)/g,
                reL3,
                fileinfo = {},
                matchL1, matchL2, matchL3;

            matchL1 = filename.match( reL1 );
            if( !matchL1 || matchL1.length !== 5 ) return null;
            if( !matchL1[2] ) return null;
            if( matchL1[2] !== FORMAT_VERSION ) return null;

            fileinfo.hash = matchL1[1];
            fileinfo.ext = matchL1[4];

            while( (matchL2 = reL2.exec( matchL1[3] )) !== null )
            {
                switch( matchL2[1] )
                {
                    case 'o':
                        reL3 = new RegExp( '.{1,' + matchL2[2].length / 2 + '}', 'g' );
                        matchL3 = matchL2[2].match( reL3 );
                        fileinfo.originalWidth = base58.decode( matchL3[0] );
                        fileinfo.originalHeight = base58.decode( matchL3[1] );
                        break;
                    case 't':
                        reL3 = new RegExp( '.{1,' + matchL2[2].length / 2 + '}', 'g' );
                        matchL3 = matchL2[2].match( reL3 );
                        fileinfo.width = base58.decode( matchL3[0] );
                        fileinfo.height = base58.decode( matchL3[1] );
                        break;
                    case 'r':
                        fileinfo.rotation = base58.decode( matchL2[2] );
                        break;
                    case 'f':
                        fileinfo.flip = true;
                        break;
                }
            }
            return fileinfo;
        };

        imageFilename.encode = function( fileinfo, withoutExt ) {
            if( !(fileinfo.hash && fileinfo.ext && fileinfo.originalWidth && fileinfo.originalHeight) )
            {
                return null;
            }

            var filename = [],
                fixedLength;

            filename.push( fileinfo.hash, FORMAT_VERSION );
            if( fileinfo.originalWidth && fileinfo.originalHeight )
            {
                fixedLength = fileinfo.originalWidth > 3363 || fileinfo.originalHeight > 3363 ? 3 : 2;
                filename.push( '-o',
                    base58.encode( fileinfo.originalWidth, fixedLength ),
                    base58.encode( fileinfo.originalHeight, fixedLength )
                );
            }
            if( fileinfo.width && fileinfo.height )
            {
                fixedLength = fileinfo.width > 3363 || fileinfo.height > 3363 ? 3 : 2;
                filename.push( '-t',
                    base58.encode( fileinfo.width, fixedLength ),
                    base58.encode( fileinfo.height, fixedLength )
                );
            }
            if( fileinfo.rotation )
            {
                filename.push( '-r',
                    base58.encode( fileinfo.rotation )
                );
            }
            if( fileinfo.flip )
            {
                filename.push( '-f' );
            }
            if( !withoutExt )
            {
                filename.push( fileinfo.ext );
            }

            return filename.join( '' );
        };

        imageFilename.original = function( filename, withoutExt ) {
            var imageinfo = imageFilename.decode( filename );
            return imageFilename.encode( {
                hash: imageinfo.hash,
                ext: imageinfo.ext,
                originalWidth: imageinfo.originalWidth,
                originalHeight: imageinfo.originalHeight
            }, withoutExt );
        };

        imageFilename.thumbnail = function( filename, maxDimension, withoutExt ) {
            var imageinfo = imageFilename.decode( filename ),
                aspectRatio = imageinfo.width && imageinfo.height
                    ? imageinfo.width / imageinfo.height
                    : imageinfo.originalWidth / imageinfo.originalHeight;
            imageinfo.width = aspectRatio > 1 ? maxDimension : parseInt( maxDimension * aspectRatio );
            imageinfo.height = aspectRatio > 1 ? parseInt( maxDimension / aspectRatio ) : maxDimension;
            return imageFilename.encode( imageinfo, withoutExt );
        };

        imageFilename.autoOrientation = function( filename, exifOrientation, withoutExt ) {
            var imageinfo = imageFilename.decode( filename ),
                w = imageinfo.width,
                h = imageinfo.height;
            /*
             exif orientation
             N  | rotation cw | rotation code | flip-x
             1  |       0     |       0       |   no
             2  |       0     |       0       |   yes
             6  |      90     |       1       |   no
             5  |      90     |       1       |   yes
             3  |     180     |       2       |   no
             4  |     180     |       2       |   yes
             8  |     270     |       3       |   no
             7  |     270     |       3       |   yes
             */

            switch( exifOrientation )
            {
                case 2:
                    imageinfo.flip = true;
                    break;
                case 6:
                    imageinfo.rotation = 90;
                    imageinfo.flip = false;
                    break;
                case 5:
                    imageinfo.rotation = 90;
                    imageinfo.flip = true;
                    break;
                case 3:
                    imageinfo.rotation = 180;
                    imageinfo.flip = false;
                    break;
                case 4:
                    imageinfo.rotation = 180;
                    imageinfo.flip = true;
                    break;
                case 8:
                    imageinfo.rotation = 270;
                    imageinfo.flip = false;
                    break;
                case 7:
                    imageinfo.rotation = 270;
                    imageinfo.flip = true;
                    break;
            }

            imageinfo.width = imageinfo.rotation % 180 ? h : w;
            imageinfo.height = imageinfo.rotation % 180 ? w : h;

            return imageFilename.encode( imageinfo, withoutExt );
        };

        imageFilename.urlParser = function( url ) {
            /* https://regex101.com/r/yU1oN3/4 */
            var re = new RegExp( '(.+\/)([0-9A-Za-z]{8})\/([0-9A-Za-z]+'
                    + FORMAT_VERSION
                    + '-o[-0-9A-Za-z]+)\\/([^\\/]+)(\\.[a-z]{2,4})$' ),
                urlParser = url.match( re );
            if( !urlParser ) return null;

            return {
                baseUrl: urlParser[1],
                filenameHmac: urlParser[2],
                encodedFilename: urlParser[3],
                originalFilename: urlParser[4],
                ext: urlParser[5]
            };
        };

        return imageFilename;
    }
))
;<commit_msg>modified image URL parser regex<commit_after>(function( factory ) {
    if( typeof define === 'function' && define.amd )
    {
        define( 'image-filename', factory );
    }
    else if( typeof module === 'object' && module.exports )
    {
        module.exports = factory();
    }
}( function() {

        'use strict';

        var imageFilename = {};

        var FORMAT_VERSION = '2';

        var base58 = (function() {
            /**
             * @url https://gist.github.com/inflammable/2929362
             */
            var bs58 = (function( alphabet ) {
                var base = alphabet.length;
                return {
                    encode: function( enc ) {
                        if( typeof enc !== 'number' || enc !== parseInt( enc ) )
                            throw '"encode" only accepts integers.';
                        var encoded = '';
                        while( enc )
                        {
                            var remainder = enc % base;
                            enc = Math.floor( enc / base );
                            encoded = alphabet[remainder].toString() + encoded;
                        }
                        return encoded;
                    },
                    decode: function( dec ) {
                        if( typeof dec !== 'string' )
                            throw '"decode" only accepts strings.';
                        var decoded = 0;
                        while( dec )
                        {
                            var alphabetPosition = alphabet.indexOf( dec[0] );
                            if( alphabetPosition < 0 )
                                throw '"decode" can\'t find "' + dec[0] + '" in the alphabet: "' + alphabet + '"';
                            var powerOf = dec.length - 1;
                            decoded += alphabetPosition * (Math.pow( base, powerOf ));
                            dec = dec.substring( 1 );
                        }
                        return decoded;
                    }
                };
            })( '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' );

            return {
                encode: function( num, fixedLength ) {
                    var b58 = bs58.encode( parseInt( num ) );
                    if( !fixedLength ) return b58;
                    if( b58.length > fixedLength ) return new Error( 'number length is more than required' );
                    while( b58.length < fixedLength ) b58 = '1' + b58;
                    return b58;
                },
                decode: function( b58 ) {
                    return bs58.decode( b58 );
                }
            }
        })();

        imageFilename.decode = function( filename ) {
            var reL1 = /(\w+)(\w)(-o[\w-]*)(\.\w{3,4})?$/,
                reL2 = /-(o|t|r|f)(\w*)/g,
                reL3,
                fileinfo = {},
                matchL1, matchL2, matchL3;

            matchL1 = filename.match( reL1 );
            if( !matchL1 || matchL1.length !== 5 ) return null;
            if( !matchL1[2] ) return null;
            if( matchL1[2] !== FORMAT_VERSION ) return null;

            fileinfo.hash = matchL1[1];
            fileinfo.ext = matchL1[4];

            while( (matchL2 = reL2.exec( matchL1[3] )) !== null )
            {
                switch( matchL2[1] )
                {
                    case 'o':
                        reL3 = new RegExp( '.{1,' + matchL2[2].length / 2 + '}', 'g' );
                        matchL3 = matchL2[2].match( reL3 );
                        fileinfo.originalWidth = base58.decode( matchL3[0] );
                        fileinfo.originalHeight = base58.decode( matchL3[1] );
                        break;
                    case 't':
                        reL3 = new RegExp( '.{1,' + matchL2[2].length / 2 + '}', 'g' );
                        matchL3 = matchL2[2].match( reL3 );
                        fileinfo.width = base58.decode( matchL3[0] );
                        fileinfo.height = base58.decode( matchL3[1] );
                        break;
                    case 'r':
                        fileinfo.rotation = base58.decode( matchL2[2] );
                        break;
                    case 'f':
                        fileinfo.flip = true;
                        break;
                }
            }
            return fileinfo;
        };

        imageFilename.encode = function( fileinfo, withoutExt ) {
            if( !(fileinfo.hash && fileinfo.ext && fileinfo.originalWidth && fileinfo.originalHeight) )
            {
                return null;
            }

            var filename = [],
                fixedLength;

            filename.push( fileinfo.hash, FORMAT_VERSION );
            if( fileinfo.originalWidth && fileinfo.originalHeight )
            {
                fixedLength = fileinfo.originalWidth > 3363 || fileinfo.originalHeight > 3363 ? 3 : 2;
                filename.push( '-o',
                    base58.encode( fileinfo.originalWidth, fixedLength ),
                    base58.encode( fileinfo.originalHeight, fixedLength )
                );
            }
            if( fileinfo.width && fileinfo.height )
            {
                fixedLength = fileinfo.width > 3363 || fileinfo.height > 3363 ? 3 : 2;
                filename.push( '-t',
                    base58.encode( fileinfo.width, fixedLength ),
                    base58.encode( fileinfo.height, fixedLength )
                );
            }
            if( fileinfo.rotation )
            {
                filename.push( '-r',
                    base58.encode( fileinfo.rotation )
                );
            }
            if( fileinfo.flip )
            {
                filename.push( '-f' );
            }
            if( !withoutExt )
            {
                filename.push( fileinfo.ext );
            }

            return filename.join( '' );
        };

        imageFilename.original = function( filename, withoutExt ) {
            var imageinfo = imageFilename.decode( filename );
            return imageFilename.encode( {
                hash: imageinfo.hash,
                ext: imageinfo.ext,
                originalWidth: imageinfo.originalWidth,
                originalHeight: imageinfo.originalHeight
            }, withoutExt );
        };

        imageFilename.thumbnail = function( filename, maxDimension, withoutExt ) {
            var imageinfo = imageFilename.decode( filename ),
                aspectRatio = imageinfo.width && imageinfo.height
                    ? imageinfo.width / imageinfo.height
                    : imageinfo.originalWidth / imageinfo.originalHeight;
            imageinfo.width = aspectRatio > 1 ? maxDimension : parseInt( maxDimension * aspectRatio );
            imageinfo.height = aspectRatio > 1 ? parseInt( maxDimension / aspectRatio ) : maxDimension;
            return imageFilename.encode( imageinfo, withoutExt );
        };

        imageFilename.autoOrientation = function( filename, exifOrientation, withoutExt ) {
            var imageinfo = imageFilename.decode( filename ),
                w = imageinfo.width,
                h = imageinfo.height;
            /*
             exif orientation
             N  | rotation cw | rotation code | flip-x
             1  |       0     |       0       |   no
             2  |       0     |       0       |   yes
             6  |      90     |       1       |   no
             5  |      90     |       1       |   yes
             3  |     180     |       2       |   no
             4  |     180     |       2       |   yes
             8  |     270     |       3       |   no
             7  |     270     |       3       |   yes
             */

            switch( exifOrientation )
            {
                case 2:
                    imageinfo.flip = true;
                    break;
                case 6:
                    imageinfo.rotation = 90;
                    imageinfo.flip = false;
                    break;
                case 5:
                    imageinfo.rotation = 90;
                    imageinfo.flip = true;
                    break;
                case 3:
                    imageinfo.rotation = 180;
                    imageinfo.flip = false;
                    break;
                case 4:
                    imageinfo.rotation = 180;
                    imageinfo.flip = true;
                    break;
                case 8:
                    imageinfo.rotation = 270;
                    imageinfo.flip = false;
                    break;
                case 7:
                    imageinfo.rotation = 270;
                    imageinfo.flip = true;
                    break;
            }

            imageinfo.width = imageinfo.rotation % 180 ? h : w;
            imageinfo.height = imageinfo.rotation % 180 ? w : h;

            return imageFilename.encode( imageinfo, withoutExt );
        };

        imageFilename.urlParser = function( url ) {
            /* https://regex101.com/r/yU1oN3/4 */
            var re = new RegExp( '(.+\/)([0-9A-Za-z]{8})\/([0-9A-Za-z]+'
                    + FORMAT_VERSION
                    + '-o[-0-9A-Za-z]+)\\/?([^\\/]+)?(\\.[a-z]{2,4})$' ),
                urlParser = url.match( re );
            if( !urlParser ) return null;

            return {
                baseUrl: urlParser[1],
                filenameHmac: urlParser[2],
                encodedFilename: urlParser[3],
                originalFilename: urlParser[4],
                ext: urlParser[5]
            };
        };

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


<commit_before>angular.module('ui.select', ['ui.keypress']).directive('uiSelect', function($document){
  return {
    restrict: 'E',
    /* jshint multistr: true */
    template: '
 \
      <input type="{{type}}" ui-keydown="{up: \'up()\', down: \'down()\', esc: \'close()\', enter: \'$select((data.items|filter: $select.search)[$select.index].title)\'}" ng-model="$select.search" ng-click="activate()"> \

 \

',
    replace: true,
    require: 'ngModel',
    transclude: true,
    // scope: true,
    link: function($scope, $elm, $attrs, ngModel){

      //Setting keybindings to scope wasn't working, since ui-keydown directive
      //from the template is $compiling before getting here, so no bindings created
      //$scope.keybindings = {up: 'up()', down: 'down()'};

      input = $elm.find('input');
      $scope.type = 'button';
      $scope.activate = function(){
        $scope.open = true;
        $scope.type = 'text';
        input.focus();
      };
      $scope.$watch('$select.search', function(){
        $scope.$select.index = 0;
      });
      $scope.up = function(){
        if ($scope.$select.index > 0)
          $scope.$select.index--;
      };
      $scope.down = function(){
        items = $elm.find('ul').children().length;
        if ($scope.$select.index < items) {
          $scope.$select.index++;
        } else {
          $scope.$select.index = items;
        }
      };
      $scope.$select = function(item){
        ngModel.$setViewValue(item);
        ngModel.$render(item);
        $scope.close();
      };
      $scope.close = function() {
        $scope.open = false;
        $scope.type = 'button';
      };
      var dismissClickHandler = function (evt) {
        if ($elm[0] !== evt.target.parentElement) {
          $scope.close();
          $scope.$digest();
        }
      };
      $document.bind('click', dismissClickHandler);
      ngModel.$render = function(){
        $scope.$select.search = ngModel.$viewValue;
      };
    }
  };
});
<commit_msg>Use transcludeFn instead of ng-transclude<commit_after>angular.module('ui.select', ['ui.keypress']).directive('uiSelect', function($document){
  return {
    restrict: 'E',
    /* jshint multistr: true */
    template: '
 \
      <input type="{{type}}" ui-keydown="{up: \'up()\', down: \'down()\', esc: \'close()\', enter: \'$select((data.items|filter: $select.search)[$select.index].title)\'}" ng-model="$select.search" ng-click="activate()"> \

',
    replace: true,
    require: 'ngModel',
    transclude: true,
    scope: true,
    compile: function(tElement, tAttrs, transcludeFn) {
      return function($scope, $elm, $attrs, ngModel){
        transcludeFn($scope, function(clone) {
          var choices = $("
").append(clone);
          tElement.append(choices);
          input = $elm.find('input');
          $scope.type = 'button';
          $scope.activate = function(){
            $scope.open = true;
            $scope.type = 'text';
            input.focus();
          };
          $scope.$watch('$select.search', function(){
            $scope.$select.index = 0;
          });
          $scope.up = function(){
            if ($scope.$select.index > 0)
              $scope.$select.index--;
          };
          $scope.down = function(){
            items = $elm.find('ul').children().length;
            if ($scope.$select.index < items) {
              $scope.$select.index++;
            } else {
              $scope.$select.index = items;
            }
          };
          $scope.$select = function(item){
            ngModel.$setViewValue(item);
            ngModel.$render(item);
            $scope.close();
          };
          $scope.close = function() {
            $scope.open = false;
            $scope.type = 'button';
          };
          var dismissClickHandler = function (evt) {
            if ($elm[0] !== evt.target.parentElement) {
              $scope.close();
              $scope.$digest();
            }
          };
          $document.bind('click', dismissClickHandler);
          ngModel.$render = function(){
            $scope.$select.search = ngModel.$viewValue;
          };
        });
      };
    }
  };
});
<|endoftext|>


<commit_before>/**
 * @file changelog command
 * @author Sankarsan Kampa (a.k.a k3rn31p4nic)
 * @license MIT
 */

exports.exec = (Bastion, message) => {
  const CHANGES = require('../../changes.json');

  let changes = [];
  for (let section in CHANGES) {
    if (CHANGES.hasOwnProperty(section)) {
      if (section === 'date' || section === 'image' || !CHANGES[section].length) continue;

      changes.push({
        name: section,
        value: `- ${CHANGES[section].join('\n- ')}`
      });
    }
  }

  message.channel.send({
    embed: {
      color: Bastion.colors.BLUE,
      title: `Bastion Bot v${Bastion.package.version} Changelog`,
      url: 'https://github.com/TheBastionBot/Bastion/releases',
      description: 'Missed an update? [Check out our previous change logs](https://github.com/TheBastionBot/Bastion/releases)' +
                   '\nJoin our [officia server](https://discord.gg/fzx8fkt) and never miss an update: https://discord.gg/fzx8fkt' +
                   '\n\nSupport the development of Bastion and keep it running forever by [becoming a patron](https://patreon.com/bastionbot) or [donating via PayPal](https://paypal.me/snkrsnkampa)',
      fields: changes,
      image: {
        url: CHANGES.image
      },
      footer: {
        text: CHANGES.date
      }
    }
  }).catch(e => {
    Bastion.log.error(e);
  });
};

exports.config = {
  aliases: [ 'clog', 'changes' ],
  enabled: true
};

exports.help = {
  name: 'changelog',
  botPermission: '',
  userTextPermission: '',
  userVoicePermission: '',
  usage: 'changelog',
  example: []
};
<commit_msg>fix: typo in changelog command<commit_after>/**
 * @file changelog command
 * @author Sankarsan Kampa (a.k.a k3rn31p4nic)
 * @license MIT
 */

exports.exec = (Bastion, message) => {
  const CHANGES = require('../../changes.json');

  let changes = [];
  for (let section in CHANGES) {
    if (CHANGES.hasOwnProperty(section)) {
      if (section === 'date' || section === 'image' || !CHANGES[section].length) continue;

      changes.push({
        name: section,
        value: `- ${CHANGES[section].join('\n- ')}`
      });
    }
  }

  message.channel.send({
    embed: {
      color: Bastion.colors.BLUE,
      title: `Bastion Bot v${Bastion.package.version} Changelog`,
      url: 'https://github.com/TheBastionBot/Bastion/releases',
      description: 'Missed an update? [Check out our previous change logs](https://github.com/TheBastionBot/Bastion/releases)' +
                   '\nJoin [Bastion HQ](https://discord.gg/fzx8fkt) and never miss an update: https://discord.gg/fzx8fkt' +
                   '\n\nSupport the development of Bastion and keep it running forever by [becoming a patron](https://patreon.com/bastionbot) or [donating via PayPal](https://paypal.me/snkrsnkampa)',
      fields: changes,
      image: {
        url: CHANGES.image
      },
      footer: {
        text: CHANGES.date
      }
    }
  }).catch(e => {
    Bastion.log.error(e);
  });
};

exports.config = {
  aliases: [ 'clog', 'changes' ],
  enabled: true
};

exports.help = {
  name: 'changelog',
  botPermission: '',
  userTextPermission: '',
  userVoicePermission: '',
  usage: 'changelog',
  example: []
};
<|endoftext|>


<commit_before>document.observe("dom:loaded", function() {
  var authToken = $$('meta[name=csrf-token]').first().readAttribute('content'),
    authParam = $$('meta[name=csrf-param]').first().readAttribute('content'),
    formTemplate = '<form method="#{method}" action="#{action}">\
      #{realmethod}<input name="#{param}" value="#{token}" type="hidden">\
      </form>',
    realmethodTemplate = '<input name="_method" value="#{method}" type="hidden">';

  function handleRemote(element) {
    var method, url, params;

    if (element.tagName.toLowerCase() == 'form') {
      method = element.readAttribute('method') || 'post';
      url    = element.readAttribute('action');
      params = element.serialize(true);
    } else {
      method = element.readAttribute('data-method') || 'get';
      // TODO: data-url support is going away, just use href
      url    = element.readAttribute('data-url') || element.readAttribute('href');
      params = {};
    }

    var event = element.fire("ajax:before");
    if (event.stopped) return false;

    new Ajax.Request(url, {
      method: method,
      parameters: params,
      asynchronous: true,
      evalScripts: true,

      onLoading:     function(request) { element.fire("ajax:loading", {request: request}); },
      onLoaded:      function(request) { element.fire("ajax:loaded", {request: request}); },
      onInteractive: function(request) { element.fire("ajax:interactive", {request: request}); },
      onComplete:    function(request) { element.fire("ajax:complete", {request: request}); },
      onSuccess:     function(request) { element.fire("ajax:success", {request: request}); },
      onFailure:     function(request) { element.fire("ajax:failure", {request: request}); }
    });

    element.fire("ajax:after");
  }

  $(document.body).observe("click", function(event) {
    var message = event.element().readAttribute('data-confirm');
    if (message && !confirm(message)) {
      event.stop();
      return false;
    }

    var element = event.findElement("a[data-remote=true]");
    if (element) {
      handleRemote(element);
      event.stop();
    }

    var element = event.findElement("a[data-method]");
    if (element && element.readAttribute('data-remote') != 'true') {
      var method = element.readAttribute('data-method'),
        piggyback = method.toLowerCase() != 'post',
        formHTML = formTemplate.interpolate({
          method: 'POST',
          realmethod: piggyback ? realmethodTemplate.interpolate({ method: method }) : '',
          action: element.readAttribute('href'),
          token: authToken,
          param: authParam
        });

      var form = new Element('div').update(formHTML).down().hide();
      this.insert({ bottom: form });

      form.submit();
      event.stop();
    }
  });

  // TODO: I don't think submit bubbles in IE
  $(document.body).observe("submit", function(event) {
    var message = event.element().readAttribute('data-confirm');
    if (message && !confirm(message)) {
      event.stop();
      return false;
    }

    var inputs = event.element().select("input[type=submit][data-disable-with]");
    inputs.each(function(input) {
      input.disabled = true;
      input.writeAttribute('data-original-value', input.value);
      input.value = input.readAttribute('data-disable-with');
    });

    var element = event.findElement("form[data-remote=true]");
    if (element) {
      handleRemote(element);
      event.stop();
    }
  });

  $(document.body).observe("ajax:complete", function(event) {
    var element = event.element();

    if (element.tagName.toLowerCase() == 'form') {
      var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
      inputs.each(function(input) {
        input.value = input.readAttribute('data-original-value');
        input.writeAttribute('data-original-value', null);
        input.disabled = false;
      });
    }
  });
});
<commit_msg>do not support 'data-url' anymore, just use 'href' [#4236 state:resolved]<commit_after>document.observe("dom:loaded", function() {
  var authToken = $$('meta[name=csrf-token]').first().readAttribute('content'),
    authParam = $$('meta[name=csrf-param]').first().readAttribute('content'),
    formTemplate = '<form method="#{method}" action="#{action}">\
      #{realmethod}<input name="#{param}" value="#{token}" type="hidden">\
      </form>',
    realmethodTemplate = '<input name="_method" value="#{method}" type="hidden">';

  function handleRemote(element) {
    var method, url, params;

    if (element.tagName.toLowerCase() == 'form') {
      method = element.readAttribute('method') || 'post';
      url    = element.readAttribute('action');
      params = element.serialize(true);
    } else {
      method = element.readAttribute('data-method') || 'get';
      url    = element.readAttribute('href');
      params = {};
    }

    var event = element.fire("ajax:before");
    if (event.stopped) return false;

    new Ajax.Request(url, {
      method: method,
      parameters: params,
      asynchronous: true,
      evalScripts: true,

      onLoading:     function(request) { element.fire("ajax:loading", {request: request}); },
      onLoaded:      function(request) { element.fire("ajax:loaded", {request: request}); },
      onInteractive: function(request) { element.fire("ajax:interactive", {request: request}); },
      onComplete:    function(request) { element.fire("ajax:complete", {request: request}); },
      onSuccess:     function(request) { element.fire("ajax:success", {request: request}); },
      onFailure:     function(request) { element.fire("ajax:failure", {request: request}); }
    });

    element.fire("ajax:after");
  }

  $(document.body).observe("click", function(event) {
    var message = event.element().readAttribute('data-confirm');
    if (message && !confirm(message)) {
      event.stop();
      return false;
    }

    var element = event.findElement("a[data-remote=true]");
    if (element) {
      handleRemote(element);
      event.stop();
    }

    var element = event.findElement("a[data-method]");
    if (element && element.readAttribute('data-remote') != 'true') {
      var method = element.readAttribute('data-method'),
        piggyback = method.toLowerCase() != 'post',
        formHTML = formTemplate.interpolate({
          method: 'POST',
          realmethod: piggyback ? realmethodTemplate.interpolate({ method: method }) : '',
          action: element.readAttribute('href'),
          token: authToken,
          param: authParam
        });

      var form = new Element('div').update(formHTML).down().hide();
      this.insert({ bottom: form });

      form.submit();
      event.stop();
    }
  });

  // TODO: I don't think submit bubbles in IE
  $(document.body).observe("submit", function(event) {
    var message = event.element().readAttribute('data-confirm');
    if (message && !confirm(message)) {
      event.stop();
      return false;
    }

    var inputs = event.element().select("input[type=submit][data-disable-with]");
    inputs.each(function(input) {
      input.disabled = true;
      input.writeAttribute('data-original-value', input.value);
      input.value = input.readAttribute('data-disable-with');
    });

    var element = event.findElement("form[data-remote=true]");
    if (element) {
      handleRemote(element);
      event.stop();
    }
  });

  $(document.body).observe("ajax:complete", function(event) {
    var element = event.element();

    if (element.tagName.toLowerCase() == 'form') {
      var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
      inputs.each(function(input) {
        input.value = input.readAttribute('data-original-value');
        input.writeAttribute('data-original-value', null);
        input.disabled = false;
      });
    }
  });
});
<|endoftext|>


<commit_before>'use strict';

var async = require('async');
var request = require('supertest');

var config = require('../config/configuration.js');

var getSubFolder = function getSubFolder(serviceData, cursor, id, cb) {
  var apiUrl = "https://api.box.com/2.0/";
  var url = "/folders/" + id;

  request(apiUrl)
  .get(url)
  .set('Content-Type', 'application/x-www-form-urlencoded')
  .set('Authorization', 'Bearer ' + serviceData.access_token)
  .expect(200)
  .end(function(err, res) {
    if(err) {
      cb(err);
    }
    else {
      var allFilesId = [];
      var total = res.body.item_collection.total_count;
      if(total === 0) {
        cb(null, allFilesId);
      }
      var processed = 0;
      res.body.item_collection.entries.forEach(function(item) {
        if(item.type === 'folder') {
          console.log('Folder = ' + item.name);
          getSubFolder(serviceData, cursor, item.id, function(err, filesId) {
            allFilesId = allFilesId.concat(filesId);
            if(++processed === total) {
              cb(null, allFilesId);
            }
          });
        }
        else {
          console.log('File = ' + item.name);
          allFilesId.push(item.id);
          if(++processed === total) {
            cb(null, allFilesId);
          }
        }
      });
    }
  });
};

module.exports = function updateAccount(serviceData, cursor, queues, cb) {

  async.waterfall([
    function refreshToken(cb) {
      var apiUrl = "https://api.box.com/oauth2/";
      var url = '/token';
      request(apiUrl)
      .post(url)
      .set('Content-Type', 'application/x-www-form-urlencoded')
      .send({grant_type: 'refresh_token',
        refresh_token: serviceData.refresh_token,
        client_secret: config.box.secret,
        client_id: config.box.api})
      .expect(200)
      .end(cb);
    },
    function parseFolders(folders, cb) {
      getSubFolder(serviceData, cursor, 0, cb);
    },
    function sendFiles(files, cb) {
      console.log(files);
      cb(null);
    }
    ], function(err) {
      console.log('ERROR ____________' + err);
      cb(null, new Date(), serviceData);
    });
};
<commit_msg>Async waterfall ftw<commit_after>'use strict';

var async = require('async');
var request = require('supertest');

var config = require('../config/configuration.js');

var getSubFolder = function getSubFolder(serviceData, cursor, id, cb) {
  var apiUrl = "https://api.box.com/2.0/";
  var url = "/folders/" + id;

  async.waterfall([
    function getFolderContent(cb) {
      request(apiUrl)
      .get(url)
      .set('Content-Type', 'application/x-www-form-urlencoded')
      .set('Authorization', 'Bearer ' + serviceData.access_token)
      .expect(200)
      .end(cb);
    },
    function processFolderContent(content, cb) {
      var allFilesId = [];
      var total = content.body.item_collection.total_count;
      if(total === 0) {
        cb(null, allFilesId);
      }
      var processed = 0;
      content.body.item_collection.entries.forEach(function(item) {
        if(item.type === 'folder') {
          console.log('Folder = ' + item.name);
          getSubFolder(serviceData, cursor, item.id, function(err, filesId) {
            allFilesId = allFilesId.concat(filesId);
            if(++processed === total) {
              cb(null, allFilesId);
            }
          });
        }
        else {
          console.log('File = ' + item.name);
          allFilesId.push(item.id);
          if(++processed === total) {
            cb(null, allFilesId);
          }
        }
      });
    }
    ], cb);
};

module.exports = function updateAccount(serviceData, cursor, queues, cb) {

  async.waterfall([
    function refreshToken(cb) {
      var apiUrl = "https://api.box.com/oauth2/";
      var url = '/token';
      request(apiUrl)
      .post(url)
      .set('Content-Type', 'application/x-www-form-urlencoded')
      .send({grant_type: 'refresh_token',
        refresh_token: serviceData.refresh_token,
        client_secret: config.box.secret,
        client_id: config.box.api})
      .expect(200)
      .end(cb);
    },
    function parseFolders(folders, cb) {
      getSubFolder(serviceData, cursor, 0, cb);
    },
    function sendFiles(files, cb) {
      console.log(files);
      cb(null);
    }
    ], function(err) {
      console.log('ERROR ____________' + err);
      cb(null, new Date(), serviceData);
    });
};
<|endoftext|>


<commit_before>var debug = true;

var tmDropdownString = '<option>  ↓ Mink has TimeMaps for... ↓</option>';
var tmDropdownNoTimemapsString = '<option>--- No TimeMaps available ---</option>';

function restore_options(){
    chrome.storage.local.get('blacklist', function(items) {
      $(items.blacklist).each(function(i, v){
        $("#options").append(getListItemHTML(v, 'glyphicon-remove'));
      });
      updateSaveButtonStatus();
      updateRemoveAllBlacklistButtonStatus();

      $(".remove").click(function(){
        if($(this).hasClass('glyphicon-remove')){
          var uriToStrike = $(this).parent().text();
          $(this).parent().addClass("strike");
          $(this).toggleClass('glyphicon-remove glyphicon-ok');
        }else {
          $(this).toggleClass('glyphicon-ok glyphicon-remove');
          $(this).parent().removeClass("strike");
        }
        updateSaveButtonStatus();
        updateRemoveAllBlacklistButtonStatus();

      });
    });
}

function getListItemHTML(uri, classIn, buttonText){
  if(!buttonText) {
    buttonText = '';
  }
  return '
<button class="btn btn-default btn-xs glyphicon ' + classIn + ' remove" type="button">' + buttonText + '</button>' + uri + '
';
}

function clearBlacklist() {
  chrome.storage.local.set({'blacklist': []});
  document.location.reload();
}

function saveBlacklist(dontReload){
  var blacklistJSON = {};
  var uris = [];
  $('#options li:not(.strike) span').each(function(){
    uris.push($(this).text());
  });

  blacklistJSON.blacklist = uris;
  chrome.storage.local.set(blacklistJSON);
  $('.newEntry').removeClass('newEntry'); // Disable indicator for unsaved data
  updateSaveButtonStatus();

  if(!dontReload) {
    document.location.reload();
  }
}

function updateSaveButtonStatus(){
  var saveBlacklistButton = $('#saveBlacklist');
  if($('.glyphicon-ok').length > 0 || $('.newEntry').length > 0) {
    saveBlacklistButton.removeAttr('disabled').removeClass('disabled');
  }else {
    saveBlacklistButton.attr('disabled','disabled').addClass('disabled');
  }
}

function updateRemoveAllBlacklistButtonStatus() {
  var clearBlacklistButton = $('#clearBlacklist');
  if(debug){
    console.log($('#options li').length);
    console.log($('#options li'));
  }
  if($('#options li').length > 0) {
    clearBlacklistButton.removeAttr('disabled').removeClass('disabled');
  }else {
    clearBlacklistButton.attr('disabled','disabled').addClass('disabled');
  }
}

function createAddURIBinder(){
    $("#add").click(function(){
      addMinkBlacklistToBeSavedLI();
      bindAddBlacklistEntryUI();
    });
}

function bindAddBlacklistEntryUI() {
  $('.uriTextField').keyup(function() {
    var uriFieldValue = $(this).val();
    if(uriFieldValue.length === 0) {
      $(this).parent().find('button.addToBlacklist').attr('disabled',true);
    }else {
      $(this).parent().find('button.addToBlacklist').removeAttr('disabled');
    }
  });
  $('.addToBlacklist').click(addToBlacklistToBeSaved);
  $('.cancelAddToBlacklist').click(removeFromBlacklistToBeSaved);
}

function addMinkBlacklistToBeSavedLI(valIn) {
  if(!valIn) {
    valIn = '';
  }
  $("#options").prepend('
<input type="text" placeholder="http://"  class="uriTextField" id="newURI" "' + valIn + '"/><button class="addToBlacklist" disabled>Add to Blacklist</button><button class="cancelAddToBlacklist">Cancel</button>
');
}

function addToBlacklistToBeSaved() {
  var uri = $(this).parent().find('.uriTextField').val();
  if(uri.substr(0,4) !== 'http') {
    uri = 'http://' + uri;
  }

  $(this).parent().replaceWith(getListItemHTML(uri, 'glyphicon-remove newItem'));
  $('.newItem').click(removeEntry);
  $('.newItem').removeClass('newItem').parent().addClass('newEntry');
  // $('.newEntry').append('<button  class="btn btn-default btn-xs glyphicon glyphicon-chevron-left" style="font-size: 12px; margin-left: 1.0em;">Nevermind</button>');
  updateSaveButtonStatus();
}

function removeFromBlacklistToBeSaved() {
  $(this).parent().remove();
}

function removeEntry() {
  $(this).parent().remove();
  updateSaveButtonStatus();
}

function populatedCachedTimeMapsUI() {
  chrome.storage.local.get('timemaps',function(items) {
    if(debug){
      console.log('items in the TM localstorage');
      console.log(items);
    }

    var tms = items.timemaps;

    var keys = tms ? Object.keys(tms) : 0;
    var uriPluralityString = keys.length === 1 ? 'URI' : 'URIs';

    if(keys.length) {
		$('#cachedTimemaps').append(tmDropdownString);
		for(var tm = 0; tm < keys.length; tm++) {
		  var originalURI = tms[keys[tm]].original_uri;
		  if(!tms[keys[tm]].original_uri) {
		    originalURI = keys[tm];
		  }
		  $('#cachedTimemaps').append('<option>' + originalURI + '</option>');
		}
		enableRemoveButtons(false,'#removeAllTMsFromCache');
		$('#cachedTimemaps').change(enableRemoveButtonsBasedOnDropdown);
	}else {
	    $('#cachedTimemaps').append(tmDropdownNoTimemapsString);
	    enableRemoveButtons(true, '#cachedTimemaps, #removeAllTMsFromCache');
	}
	enableRemoveButtonsBasedOnDropdown();
  });
}

function updateMementoCount() {
  chrome.storage.local.get('timemaps',function(items) {
    console.log(items.timemaps);
    console.log(items.timemaps[$('#cachedTimemaps').val()]);
	$('#mementoCount').html(items.timemaps[$('#cachedTimemaps').val()].mementos.list.length + ' mementos available');
  });
}

function resetMementoCount() {
  $('#mementoCount').html('');
}

function enableRemoveButtons(disable, additionalIdsIn) {
  var additionalIds = '';
  if(additionalIdsIn) {
    additionalIds = ',' + additionalIdsIn;
  }
  var buttonIds = '#removeSelectedTMFromCache, #removeSelectedTMFromCacheAndBlacklist' + additionalIds;
  $(buttonIds).prop('disabled', disable);
}

function enableRemoveButtonsBasedOnDropdown() {
  var selectedIndex = $(this).find('option:selected').index();
  if(selectedIndex > 0) { // -1 would be valid with the verbose conditional
    enableRemoveButtons(false);
    updateMementoCount();
  }else { // selected index is 0, disable
    enableRemoveButtons(true);
    resetMementoCount();
  }
}

function removeTMFromCache(originalURI) {
  chrome.storage.local.get('timemaps', function(items) {
    var tms = items.timemaps;
    delete tms[originalURI];
    chrome.storage.local.set({'timemaps':tms},
      function() {
        console.log('Cache updated, updating UI');
        $('#cachedTimemaps').empty();
        populatedCachedTimeMapsUI();
      }
    );
  });
}

function clearTimemapCache() {
  chrome.storage.local.set({'timemaps':{}},
      function() {
        console.log('Remove all cached TMs');
        $('#cachedTimemaps').empty();
        populatedCachedTimeMapsUI();
      }
    );

  chrome.storage.local.set({'headers':{}},
     function() {
       console.log('Remove headers');
     }
  );
}

function saveAndCloseOptionsPanel() {
  saveBlacklist();
  window.close();
}

function restoreDefaults() {
  clearBlacklist();
  clearTimemapCache();
}

function removeSelectedURIFromTimeMapCache() {
  var oURI = $('#cachedTimemaps option:selected').text();
  removeTMFromCache(oURI);
}

function addSelectedURIToBlacklist() {
  var oURI = $('#cachedTimemaps option:selected').text();
  $('#options').append('
' + oURI + '
');

}

document.addEventListener('DOMContentLoaded', restore_options);
document.addEventListener('DOMContentLoaded', createAddURIBinder);
document.addEventListener('DOMContentLoaded', populatedCachedTimeMapsUI);

$('#removeSelectedTMFromCache').click(removeSelectedURIFromTimeMapCache);
$('#removeSelectedTMFromCacheAndBlacklist').click(function() {
  addSelectedURIToBlacklist();
  var dontReloadAfterSavingBlacklist = true;
  saveBlacklist(dontReloadAfterSavingBlacklist);
  removeSelectedURIFromTimeMapCache();
});

$('#removeAllTMsFromCache').click(clearTimemapCache);

$('#saveBlacklist').click(saveBlacklist);
$('#clearBlacklist').click(clearBlacklist);
$('#doneButton').click(saveAndCloseOptionsPanel);
$('#restoreDefaultsButton').click(restoreDefaults);
//document.getElementById('save').addEventListener('click',
//    save_options);
<commit_msg>Apply JS standard to options.js<commit_after>/* global chrome, $ */

var debug = true

var tmDropdownString = '<option>  ↓ Mink has TimeMaps for... ↓</option>'
var tmDropdownNoTimemapsString = '<option>--- No TimeMaps available ---</option>'

function restore_options () {
  chrome.storage.local.get('blacklist', function (items) {
    $(items.blacklist).each(function (i, v) {
      $('#options').append(getListItemHTML(v, 'glyphicon-remove'))
    })
    updateSaveButtonStatus()
    updateRemoveAllBlacklistButtonStatus()

    $('.remove').click(function () {
      if ($(this).hasClass('glyphicon-remove')) {
        // var uriToStrike = $(this).parent().text()
        $(this).parent().addClass('strike')
        $(this).toggleClass('glyphicon-remove glyphicon-ok')
      } else {
        $(this).toggleClass('glyphicon-ok glyphicon-remove')
        $(this).parent().removeClass('strike')
      }
      updateSaveButtonStatus()
      updateRemoveAllBlacklistButtonStatus()
    })
  })
}

function getListItemHTML (uri, classIn, buttonText) {
  if (!buttonText) {
    buttonText = ''
  }
  return '
<button class="btn btn-default btn-xs glyphicon ' + classIn + ' remove" type="button">' + buttonText + '</button>' + uri + '
'
}

function clearBlacklist () {
  chrome.storage.local.set({'blacklist': []})
  document.location.reload()
}

function saveBlacklist (dontReload) {
  var blacklistJSON = {}
  var uris = []
  $('#options li:not(.strike) span').each(function () {
    uris.push($(this).text())
  })

  blacklistJSON.blacklist = uris
  chrome.storage.local.set(blacklistJSON)
  $('.newEntry').removeClass('newEntry') // Disable indicator for unsaved data
  updateSaveButtonStatus()

  if (!dontReload) {
    document.location.reload()
  }
}

function updateSaveButtonStatus () {
  var saveBlacklistButton = $('#saveBlacklist')
  if ($('.glyphicon-ok').length > 0 || $('.newEntry').length > 0) {
    saveBlacklistButton.removeAttr('disabled').removeClass('disabled')
  } else {
    saveBlacklistButton.attr('disabled', 'disabled').addClass('disabled')
  }
}

function updateRemoveAllBlacklistButtonStatus () {
  var clearBlacklistButton = $('#clearBlacklist')
  if (debug) {
    console.log($('#options li').length)
    console.log($('#options li'))
  }
  if ($('#options li').length > 0) {
    clearBlacklistButton.removeAttr('disabled').removeClass('disabled')
  } else {
    clearBlacklistButton.attr('disabled', 'disabled').addClass('disabled')
  }
}

function createAddURIBinder () {
  $('#add').click(function () {
    addMinkBlacklistToBeSavedLI()
    bindAddBlacklistEntryUI()
  })
}

function bindAddBlacklistEntryUI () {
  $('.uriTextField').keyup(function () {
    var uriFieldValue = $(this).val()
    if (uriFieldValue.length === 0) {
      $(this).parent().find('button.addToBlacklist').attr('disabled', true)
    } else {
      $(this).parent().find('button.addToBlacklist').removeAttr('disabled')
    }
  })
  $('.addToBlacklist').click(addToBlacklistToBeSaved)
  $('.cancelAddToBlacklist').click(removeFromBlacklistToBeSaved)
}

function addMinkBlacklistToBeSavedLI (valIn) {
  if (!valIn) {
    valIn = ''
  }
  $('#options').prepend('
<input type="text" placeholder="http://"  class="uriTextField" id="newURI" "' + valIn + '"/><button class="addToBlacklist" disabled>Add to Blacklist</button><button class="cancelAddToBlacklist">Cancel</button>
')
}

function addToBlacklistToBeSaved () {
  var uri = $(this).parent().find('.uriTextField').val()
  if (uri.substr(0, 4) !== 'http') {
    uri = 'http://' + uri
  }

  $(this).parent().replaceWith(getListItemHTML(uri, 'glyphicon-remove newItem'))
  $('.newItem').click(removeEntry)
  $('.newItem').removeClass('newItem').parent().addClass('newEntry')
  // $('.newEntry').append('<button  class="btn btn-default btn-xs glyphicon glyphicon-chevron-left" style="font-size: 12px; margin-left: 1.0em;">Nevermind</button>');
  updateSaveButtonStatus()
}

function removeFromBlacklistToBeSaved () {
  $(this).parent().remove()
}

function removeEntry () {
  $(this).parent().remove()
  updateSaveButtonStatus()
}

function populatedCachedTimeMapsUI () {
  chrome.storage.local.get('timemaps', function (items) {
    if (debug) {
      console.log('items in the TM localstorage')
      console.log(items)
    }

    var tms = items.timemaps

    var keys = tms ? Object.keys(tms) : 0
    // var uriPluralityString = keys.length === 1 ? 'URI' : 'URIs'

    if (keys.length) {
      $('#cachedTimemaps').append(tmDropdownString)
      for (var tm = 0; tm < keys.length; tm++) {
        var originalURI = tms[keys[tm]].original_uri
        if (!tms[keys[tm]].original_uri) {
          originalURI = keys[tm]
        }
        $('#cachedTimemaps').append('<option>' + originalURI + '</option>')
      }
      enableRemoveButtons(false, '#removeAllTMsFromCache')
      $('#cachedTimemaps').change(enableRemoveButtonsBasedOnDropdown)
    } else {
      $('#cachedTimemaps').append(tmDropdownNoTimemapsString)
      enableRemoveButtons(true, '#cachedTimemaps, #removeAllTMsFromCache')
    }
    enableRemoveButtonsBasedOnDropdown()
  })
}

function updateMementoCount () {
  chrome.storage.local.get('timemaps', function (items) {
    console.log(items.timemaps)
    console.log(items.timemaps[$('#cachedTimemaps').val()])
    $('#mementoCount').html(items.timemaps[$('#cachedTimemaps').val()].mementos.list.length + ' mementos available')
  })
}

function resetMementoCount () {
  $('#mementoCount').html('')
}

function enableRemoveButtons (disable, additionalIdsIn) {
  var additionalIds = ''
  if (additionalIdsIn) {
    additionalIds = ',' + additionalIdsIn
  }
  var buttonIds = '#removeSelectedTMFromCache, #removeSelectedTMFromCacheAndBlacklist' + additionalIds
  $(buttonIds).prop('disabled', disable)
}

function enableRemoveButtonsBasedOnDropdown () {
  var selectedIndex = $(this).find('option:selected').index()
  if (selectedIndex > 0) { // -1 would be valid with the verbose conditional
    enableRemoveButtons(false)
    updateMementoCount()
  } else { // Selected index is 0, disable
    enableRemoveButtons(true)
    resetMementoCount()
  }
}

function removeTMFromCache (originalURI) {
  chrome.storage.local.get('timemaps', function (items) {
    var tms = items.timemaps
    delete tms[originalURI]
    chrome.storage.local.set({'timemaps': tms},
      function () {
        console.log('Cache updated, updating UI')
        $('#cachedTimemaps').empty()
        populatedCachedTimeMapsUI()
      }
    )
  })
}

function clearTimemapCache () {
  chrome.storage.local.set({'timemaps': {}},
      function () {
        console.log('Remove all cached TMs')
        $('#cachedTimemaps').empty()
        populatedCachedTimeMapsUI()
      }
    )

  chrome.storage.local.set({'headers': {}},
     function () {
       console.log('Remove headers')
     }
  )
}

function saveAndCloseOptionsPanel () {
  saveBlacklist()
  window.close()
}

function restoreDefaults () {
  clearBlacklist()
  clearTimemapCache()
}

function removeSelectedURIFromTimeMapCache () {
  var oURI = $('#cachedTimemaps option:selected').text()
  removeTMFromCache(oURI)
}

function addSelectedURIToBlacklist () {
  var oURI = $('#cachedTimemaps option:selected').text()
  $('#options').append('
' + oURI + '
')
}

document.addEventListener('DOMContentLoaded', restore_options)
document.addEventListener('DOMContentLoaded', createAddURIBinder)
document.addEventListener('DOMContentLoaded', populatedCachedTimeMapsUI)

$('#removeSelectedTMFromCache').click(removeSelectedURIFromTimeMapCache)
$('#removeSelectedTMFromCacheAndBlacklist').click(function () {
  addSelectedURIToBlacklist()
  var dontReloadAfterSavingBlacklist = true
  saveBlacklist(dontReloadAfterSavingBlacklist)
  removeSelectedURIFromTimeMapCache()
})

$('#removeAllTMsFromCache').click(clearTimemapCache)

$('#saveBlacklist').click(saveBlacklist)
$('#clearBlacklist').click(clearBlacklist)
$('#doneButton').click(saveAndCloseOptionsPanel)
$('#restoreDefaultsButton').click(restoreDefaults)
// document.getElementById('save').addEventListener('click', save_options)
<|endoftext|>