<commit_before>// ==UserScript==
// @name         Slither.io-bot
// @namespace    http://slither.io/
// @version      0.4.1
// @description  Slither.io bot
// @author       Ermiya Eskandary & Théophile Cailliau
// @match        http://slither.io/
// @grant        none
// ==/UserScript==
// Functions needed for the bot
// Custom logging function - disabled by default
window.log = function() {
    if (window.logDebugging) {
        console.log.apply(console, arguments);
    }
};
// Appends divs to the page - used to display things on the screen
window.appendDiv = function(id, className, style) {
    // Create a div
    var div = document.createElement('div');
    // Check for id
    if (id) {
        // Set the id
        div.id = id;
    }
    // Check for class name
    if (className) {
        // Set the class name
        div.className = className;
    }
    // Check for css styles
    if (style) {
        // Set the css styles
        div.style = style;
    }
    // Append the div to the page
    document.body.appendChild(div);
};
// Set fake mouse coordinates
window.setMouseCoordinates = function(x, y) {
    window.xm = x;
    window.ym = y;
};
// Coordinates relative to the center (snake position).
window.mouseRelativeToCenter = function(x, y) {
    var mapX = x - window.getHeight() / 2;
    var mapY = y - window.getWidth() / 2;
    return [mapX, mapY];
};
// Mouse coordinates to screen coordinates
window.mouseToScreen = function(x, y) {
    var screenX = x + (window.getHeight() / 2);
    var screenY = y + (window.getWidth() / 2);
    return [screenX, screenY];
};
window.screenToCanvas = function(x, y) {
    var canvasX = window.csc * (x * window.canvasRatio[0] - parseInt(window.mc.style.left));
    var canvasY = window.csc * (y * window.canvasRatio[1] - parseInt(window.mc.style.top));
    return [canvasX, canvasY];
};
// Map to mouse coordinates
window.mapToMouse = function(x, y) {
    var mouseX = (x - window.getX()) * window.gsc;
    var mouseY = (y - window.getY()) * window.gsc;
    return [mouseX, mouseY];
};
// Canvas width
window.getWidth = function() {
    return window.ww;
};
// Canvas height
window.getHeight = function() {
    return window.hh;
};
// X coordinates on the screen
window.getX = function() {
    return window.snake.xx;
};
// Y coordinates on the screen
window.getY = function() {
    return window.snake.yy;
};
// Updates the relation between the screen and the canvas
window.onresize = function() {
    window.resize();
    // Canvas different size from the screen (often bigger). Gives a ratio so we can convert
    window.canvasRatio = [window.mc.height / window.getHeight(), window.mc.width / window.getWidth()];
};
// Lets you zoom in and out using the mouse wheel
window.setZoom = function(e) {
    // Scaling ratio
    if (window.gsc) {
        window.gsc *= Math.pow(0.9, e.wheelDelta / -120 || e.detail / 2 || 0);
    }
};
// Get scaling ratio
window.getScale = function() {
    return window.gsc;
};
// Snake length
window.getSnakeLength = function() {
    return (Math.floor(150 * (window.fpsls[window.snake.sct] + window.snake.fam / window.fmlts[window.snake.sct] - 1) - 50) / 10);
};
// Save the original slither.io onmousemove function so we can re enable it back later
window.mousemovelistener = window.onmousemove;

// Starts the bot
window.launchBot = function(d) {
    window.log('Starting Bot.');
    window.isBotRunning = true;
    // Removed the onmousemove listener so we can move the snake manually by setting coordinates
    window.onmousemove = function() {};
    window.botInterval = setInterval(window.loop, d);
    return window.botInterval;
};
// Stops the bot
window.stopBot = function() {
    window.log('Stopping Bot.');
    // Re enable the original onmousemove function
    window.onmousemove = window.mousemovelistener;
    window.isBotRunning = false;
    // Clear the interval which starts the bot
    return clearInterval(window.botInterval);
};

// Connects the bot
window.connectBot = function() {
    // Stop the bot
    window.stopBot();
    window.log('Connecting...');
    // Connect the bot
    window.connect();
    // Check if bot can start
    window.botCanStart = setInterval(function() {
        if (window.playing) {
            window.launchBot(5);
            clearInterval(window.botCanStart);
        }
    }, 100);
};

// Save variable to local storage
window.savePreference = function(item, value) {
    window.localStorage.setItem(item, value);
};

// Load all variables from local storage
window.loadPreferences = function() {
    if (window.localStorage.getItem('logDebugging') !== null) {
        if (window.localStorage.getItem('logDebugging') == 'true') {
            window.logDebugging = true;
        }
        else {
            window.logDebugging = false;
        }
        window.log('Setting found for debugging: ' + window.logDebugging);
    }
};
// Save the original slither.io onkeydown function so we can add stuff to it
document.oldKeyDown = document.onkeydown;
// Re write the function with our function
document.onkeydown = function(e) {
    // Original slither.io onkeydown function + whatever is under it
    document.oldKeyDown(e);
    // Letter `T` to toggle bot
    if (e.keyCode === 84) {
        if (window.isBotRunning) {
            window.stopBot();
            window.isBotEnabled = false;
        } else {
            window.launchBot(5);
            window.isBotEnabled = true;
        }
    }
    // Letter 'U' to toggle debugging (console)
    if (e.keyCode === 85) {
        window.logDebugging = !window.logDebugging;
        console.log('Debugging set to: ' + window.logDebugging);
        window.savePreference('logDebugging', window.logDebugging);
    }
};
// Sorting function for food, from property 'distance'
window.sortFood = function(a, b) {
    // a.sz & b.sz - size
    // Divide distance by size so bigger food is prioritised over smaller food
    return a.distance / a.sz - b.distance / b.sz;
};

// Given an object (of which properties xx and yy are not null), return the object with an additional property 'distance'
window.getDistanceFromMe = function(point) {
    if (point === null) return null;
    point.distance = window.getDistance(window.getX(), window.getY(), point.xx, point.yy);
    return point;
};

// Get a distance from point (x1; y1) to point (x2; y2).
window.getDistance = function(x1, y1, x2, y2) {
    // Calculate the vector coordinates.
    var xDistance = (x1 - x2);
    var yDistance = (y1 - y2);
    // Get the absolute value of each coordinate
    xDistance = xDistance < 0 ? xDistance * -1 : xDistance;
    yDistance = yDistance < 0 ? yDistance * -1 : yDistance;
    //Add the coordinates of the vector to get a distance. Not the real distance, but reliable for distance comparison.
    var distance = xDistance + yDistance;
    // Real distance but not needed. Here for reference -
    // var distance = Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
    return distance;
};

// Sort food based on distance
window.getSortedFood = function() {
    // Filters the nearest food by getting the distance
    return window.foods.filter(function(val) {
        return val !== null;
    }).map(window.getDistanceFromMe).sort(window.sortFood);
};
// Draw dots on the canvas
window.drawDot = function(x, y, radius, colour) {
    var context = window.mc.getContext('2d');
    context.beginPath();
    context.arc(x, y, radius, 0, Math.PI * 2);
    context.closePath();
    context.fillStyle = ('green red white yellow black cyan blue'.indexOf(colour) < 0) ? 'white' : colour;
    context.fill();
    context.fillStyle = 'black';
};

// Draw lines on the canvas
window.drawLine = function(x2, y2, colour) {
    var context = window.mc.getContext('2d');
    var center = [window.mc.height / 2, window.mc.width / 2];
    context.lineWidth = 5;
    context.strokeStyle = (colour === 'green') ? '#00FF00' : '#FF0000';
    context.moveTo(center[1], center[0]);
    context.lineTo(x2, y2);
    context.stroke();
    context.strokeStyle = '#000000';
};
// Save the original slither.io oef function so we can add things to it later
window.oldOef = window.oef;
window.oef = function() {
    // Original slither.io oef function + whatever is under it
    window.oldOef();
    window.onFrameUpdate();
};
window.onFrameUpdate = function() {
    if (window.playing) {
        if (window.isBotRunning) {
            // Check to see if there is a position overlay
            if (window.position_overlay) {
                // Display the X and Y of the snake
                window.position_overlay.textContent = 'X: ' + (Math.round(window.snake.xx) || 0) + ' Y: ' + (Math.round(window.snake.yy) || 0);
            }
            var foodCoordinates = window.mapToMouse(window.currentFood.xx, window.currentFood.yy);
            foodCoordinates = window.mouseToScreen(foodCoordinates[0], foodCoordinates[1]);
            foodCoordinates = window.screenToCanvas(foodCoordinates[0], foodCoordinates[1]);
            window.drawLine(foodCoordinates[0], foodCoordinates[1], 'green');
            for (var i = 0; i < 1; i++) {
                var item = window.sortedFood[i];
                foodCoordinates = window.mapToMouse(item.xx, item.yy);
                foodCoordinates = window.mouseToScreen(foodCoordinates[0], foodCoordinates[1]);
                foodCoordinates = window.screenToCanvas(foodCoordinates[0], foodCoordinates[1]);
                window.drawDot(foodCoordinates[0], foodCoordinates[1], 5, 'red');
            }
        }
    }
};
// Actual bot code

// Loop for running the bot
window.loop = function() {
    // If the game and the bot are running
    if (window.playing && window.isBotEnabled) {
        window.ranOnce = true;
        // Sort the food and enemies based on their distance relative to player's snake
        window.sortedFood = window.getSortedFood();
        window.currentFood = window.sortedFood[0];
        // Convert coordinates of the closest food using mapToMouse
        var coordinatesOfClosestFood = window.mapToMouse(window.currentFood.xx, window.currentFood.yy);
        // Set the mouse coordinates to the coordinates of the closest food
        window.setMouseCoordinates(coordinatesOfClosestFood[0], coordinatesOfClosestFood[1]);

    } else {
        window.startInterval = setInterval(window.startInterval, 1000);
    }
};
window.startInterval = function() {
    if (!window.playing && window.isBotEnabled && window.ranOnce) {
        window.connectBot();
        clearInterval(window.startInterval);
    }
};
window.initBot = function() { // This is what we run to initialize the bot
    window.ranOnce = false;
    window.logDebugging = false;
    window.isBotRunning = false;
    window.isBotEnabled = true;
    // Overlays
    window.generalstyle = 'color: #FFF; font-family: Arial, \'Helvetica Neue\', Helvetica, sans-serif; font-size: 14px; position: fixed; opacity: 0.35; z-index: 7;';
    window.appendDiv('position_overlay', 'nsi', window.generalstyle + 'right: 30; bottom: 120px;');
    window.position_overlay = document.getElementById('position_overlay');
    // Listener for mouse wheel scroll - used for setZoom function
    document.body.addEventListener('mousewheel', window.setZoom);
    document.body.addEventListener('DOMMouseScroll', window.setZoom);
    // Canvas Ratio
    window.canvasRatio = [window.mc.height / window.getHeight(), window.mc.width / window.getWidth()];
    // Unblocks all skins without the need for FB sharing.
    window.localStorage.setItem('edttsg', '1');
    window.loadPreferences();
    window.launchBot(50);
};
window.initBot();
// Enemy code - not used for now
/*
// Sort enemies based on distance
window.getSortedEnemies = function() {
    Filters the nearest food by getting the distance
    return window.snakes.filter(function(val) {
        return val !== null && val.id !== window.snake.id;
    }).map(window.getDistanceFromMe).sort(window.sortEnemy);
};
// Sorting function for enemies, from property 'distance'
window.sortEnemy = function(a, b) {
    return a.distance - b.distance;
};
        window.sortedEnemies = window.getSortedEnemies();
        // Take the closest of each
        window.closestEnemy = window.sortedEnemies[0];
        if (window.closestEnemy.distance < 300) {
        window.log('close enemy! (distance = ' + window.closestEnemy.distance);
        // !handle close enemies!
         }
*/
// Better food hunting algorithm but not implemented yet
/*
window.isInFoods = function (foodObject) {
    return (foodObject === null) ? false : (window.foods.indexOf(foodObject) >= 0);
};
window.currentFood = null;
window.sortedFood = getSortedFood();
window.loop = function () {
    if (!isInFoods(currentFood)) {
        window.sortedFood = getSortedFood();
        window.currentFood = sortedFood[0];
        var coordinatesOfClosestFood = window.mapToMouse(window.sortedFood[0].xx, window.sortedFood[0].yy);
        window.setMouseCoordinates(coordinatesOfClosestFood[0], coordinatesOfClosestFood[1]);
    }
};
*/
<commit_msg>Getting closer to solving the offset issue.<commit_after>// ==UserScript==
// @name         Slither.io-bot
// @namespace    http://slither.io/
// @version      0.4.1
// @description  Slither.io bot
// @author       Ermiya Eskandary & Théophile Cailliau
// @match        http://slither.io/
// @grant        none
// ==/UserScript==
// Functions needed for the bot
// Custom logging function - disabled by default
window.log = function() {
    if (window.logDebugging) {
        console.log.apply(console, arguments);
    }
};
// Appends divs to the page - used to display things on the screen
window.appendDiv = function(id, className, style) {
    // Create a div
    var div = document.createElement('div');
    // Check for id
    if (id) {
        // Set the id
        div.id = id;
    }
    // Check for class name
    if (className) {
        // Set the class name
        div.className = className;
    }
    // Check for css styles
    if (style) {
        // Set the css styles
        div.style = style;
    }
    // Append the div to the page
    document.body.appendChild(div);
};
// Set fake mouse coordinates
window.setMouseCoordinates = function(x, y) {
    window.xm = x;
    window.ym = y;
};
// Coordinates relative to the center (snake position).
window.mouseRelativeToCenter = function(x, y) {
    var mapX = x - window.getHeight() / 2;
    var mapY = y - window.getWidth() / 2;
    return [mapX, mapY];
};
// Mouse coordinates to screen coordinates
window.mouseToScreen = function(x, y) {
    var screenX = x + (window.getHeight() / 2);
    var screenY = y + (window.getWidth() / 2);
    return [screenX, screenY];
};
window.screenToCanvas = function(x, y) {
    var canvasX = window.csc * (x * window.canvasRatio[0]) - parseInt(window.mc.style.left);
    var canvasY = window.csc * (y * window.canvasRatio[1]) - parseInt(window.mc.style.top);
    return [canvasX, canvasY];
};
// Map to mouse coordinates
window.mapToMouse = function(x, y) {
    var mouseX = (x - window.getX()) * window.gsc;
    var mouseY = (y - window.getY()) * window.gsc;
    return [mouseX, mouseY];
};
// Canvas width
window.getWidth = function() {
    return window.ww;
};
// Canvas height
window.getHeight = function() {
    return window.hh;
};
// X coordinates on the screen
window.getX = function() {
    return window.snake.xx;
};
// Y coordinates on the screen
window.getY = function() {
    return window.snake.yy;
};
// Updates the relation between the screen and the canvas
window.onresize = function() {
    window.resize();
    // Canvas different size from the screen (often bigger). Gives a ratio so we can convert
    window.canvasRatio = [window.mc.height / window.getHeight(), window.mc.width / window.getWidth()];
};
// Lets you zoom in and out using the mouse wheel
window.setZoom = function(e) {
    // Scaling ratio
    if (window.gsc) {
        window.gsc *= Math.pow(0.9, e.wheelDelta / -120 || e.detail / 2 || 0);
    }
};
// Get scaling ratio
window.getScale = function() {
    return window.gsc;
};
// Snake length
window.getSnakeLength = function() {
    return (Math.floor(150 * (window.fpsls[window.snake.sct] + window.snake.fam / window.fmlts[window.snake.sct] - 1) - 50) / 10);
};
// Save the original slither.io onmousemove function so we can re enable it back later
window.mousemovelistener = window.onmousemove;

// Starts the bot
window.launchBot = function(d) {
    window.log('Starting Bot.');
    window.isBotRunning = true;
    // Removed the onmousemove listener so we can move the snake manually by setting coordinates
    window.onmousemove = function() {};
    window.botInterval = setInterval(window.loop, d);
    return window.botInterval;
};
// Stops the bot
window.stopBot = function() {
    window.log('Stopping Bot.');
    // Re enable the original onmousemove function
    window.onmousemove = window.mousemovelistener;
    window.isBotRunning = false;
    // Clear the interval which starts the bot
    return clearInterval(window.botInterval);
};

// Connects the bot
window.connectBot = function() {
    // Stop the bot
    window.stopBot();
    window.log('Connecting...');
    // Connect the bot
    window.connect();
    // Check if bot can start
    window.botCanStart = setInterval(function() {
        if (window.playing) {
            window.launchBot(5);
            clearInterval(window.botCanStart);
        }
    }, 100);
};

// Save variable to local storage
window.savePreference = function(item, value) {
    window.localStorage.setItem(item, value);
};

// Load all variables from local storage
window.loadPreferences = function() {
    if (window.localStorage.getItem('logDebugging') !== null) {
        if (window.localStorage.getItem('logDebugging') == 'true') {
            window.logDebugging = true;
        }
        else {
            window.logDebugging = false;
        }
        window.log('Setting found for debugging: ' + window.logDebugging);
    }
};
// Save the original slither.io onkeydown function so we can add stuff to it
document.oldKeyDown = document.onkeydown;
// Re write the function with our function
document.onkeydown = function(e) {
    // Original slither.io onkeydown function + whatever is under it
    document.oldKeyDown(e);
    // Letter `T` to toggle bot
    if (e.keyCode === 84) {
        if (window.isBotRunning) {
            window.stopBot();
            window.isBotEnabled = false;
        } else {
            window.launchBot(5);
            window.isBotEnabled = true;
        }
    }
    // Letter 'U' to toggle debugging (console)
    if (e.keyCode === 85) {
        window.logDebugging = !window.logDebugging;
        console.log('Debugging set to: ' + window.logDebugging);
        window.savePreference('logDebugging', window.logDebugging);
    }
};
// Sorting function for food, from property 'distance'
window.sortFood = function(a, b) {
    // a.sz & b.sz - size
    // Divide distance by size so bigger food is prioritised over smaller food
    return a.distance / a.sz - b.distance / b.sz;
};

// Given an object (of which properties xx and yy are not null), return the object with an additional property 'distance'
window.getDistanceFromMe = function(point) {
    if (point === null) return null;
    point.distance = window.getDistance(window.getX(), window.getY(), point.xx, point.yy);
    return point;
};

// Get a distance from point (x1; y1) to point (x2; y2).
window.getDistance = function(x1, y1, x2, y2) {
    // Calculate the vector coordinates.
    var xDistance = (x1 - x2);
    var yDistance = (y1 - y2);
    // Get the absolute value of each coordinate
    xDistance = xDistance < 0 ? xDistance * -1 : xDistance;
    yDistance = yDistance < 0 ? yDistance * -1 : yDistance;
    //Add the coordinates of the vector to get a distance. Not the real distance, but reliable for distance comparison.
    var distance = xDistance + yDistance;
    // Real distance but not needed. Here for reference -
    // var distance = Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
    return distance;
};

// Sort food based on distance
window.getSortedFood = function() {
    // Filters the nearest food by getting the distance
    return window.foods.filter(function(val) {
        return val !== null;
    }).map(window.getDistanceFromMe).sort(window.sortFood);
};
// Draw dots on the canvas
window.drawDot = function(x, y, radius, colour) {
    var context = window.mc.getContext('2d');
    context.beginPath();
    context.arc(x, y, radius, 0, Math.PI * 2);
    context.closePath();
    context.fillStyle = ('green red white yellow black cyan blue'.indexOf(colour) < 0) ? 'white' : colour;
    context.fill();
    context.fillStyle = 'black';
};

// Draw lines on the canvas
window.drawLine = function(x2, y2, colour) {
    var context = window.mc.getContext('2d');
    var center = [window.mc.height / 2, window.mc.width / 2];
    context.lineWidth = 5;
    context.strokeStyle = (colour === 'green') ? '#00FF00' : '#FF0000';
    context.moveTo(center[1], center[0]);
    context.lineTo(x2, y2);
    context.stroke();
    context.strokeStyle = '#000000';
};
// Save the original slither.io oef function so we can add things to it later
window.oldOef = window.oef;
window.oef = function() {
    // Original slither.io oef function + whatever is under it
    window.oldOef();
    window.onFrameUpdate();
};
window.onFrameUpdate = function() {
    if (window.playing) {
        if (window.isBotRunning) {
            // Check to see if there is a position overlay
            if (window.position_overlay) {
                // Display the X and Y of the snake
                window.position_overlay.textContent = 'X: ' + (Math.round(window.snake.xx) || 0) + ' Y: ' + (Math.round(window.snake.yy) || 0);
            }
            var foodCoordinates = window.mapToMouse(window.currentFood.xx, window.currentFood.yy);
            foodCoordinates = window.mouseToScreen(foodCoordinates[0], foodCoordinates[1]);
            foodCoordinates = window.screenToCanvas(foodCoordinates[0], foodCoordinates[1]);
            window.drawLine(foodCoordinates[0], foodCoordinates[1], 'green');
            for (var i = 0; i < 1; i++) {
                var item = window.sortedFood[i];
                foodCoordinates = window.mapToMouse(item.xx, item.yy);
                foodCoordinates = window.mouseToScreen(foodCoordinates[0], foodCoordinates[1]);
                foodCoordinates = window.screenToCanvas(foodCoordinates[0], foodCoordinates[1]);
                window.drawDot(foodCoordinates[0], foodCoordinates[1], 5, 'red');
            }
        }
    }
};
// Actual bot code

// Loop for running the bot
window.loop = function() {
    // If the game and the bot are running
    if (window.playing && window.isBotEnabled) {
        window.ranOnce = true;
        // Sort the food and enemies based on their distance relative to player's snake
        window.sortedFood = window.getSortedFood();
        window.currentFood = window.sortedFood[0];
        // Convert coordinates of the closest food using mapToMouse
        var coordinatesOfClosestFood = window.mapToMouse(window.currentFood.xx, window.currentFood.yy);
        // Set the mouse coordinates to the coordinates of the closest food
        window.setMouseCoordinates(coordinatesOfClosestFood[0], coordinatesOfClosestFood[1]);

    } else {
        window.startInterval = setInterval(window.startInterval, 1000);
    }
};
window.startInterval = function() {
    if (!window.playing && window.isBotEnabled && window.ranOnce) {
        window.connectBot();
        clearInterval(window.startInterval);
    }
};
window.initBot = function() { // This is what we run to initialize the bot
    window.ranOnce = false;
    window.logDebugging = false;
    window.isBotRunning = false;
    window.isBotEnabled = true;
    // Overlays
    window.generalstyle = 'color: #FFF; font-family: Arial, \'Helvetica Neue\', Helvetica, sans-serif; font-size: 14px; position: fixed; opacity: 0.35; z-index: 7;';
    window.appendDiv('position_overlay', 'nsi', window.generalstyle + 'right: 30; bottom: 120px;');
    window.position_overlay = document.getElementById('position_overlay');
    // Listener for mouse wheel scroll - used for setZoom function
    document.body.addEventListener('mousewheel', window.setZoom);
    document.body.addEventListener('DOMMouseScroll', window.setZoom);
    // Canvas Ratio
    window.canvasRatio = [window.mc.height / window.getHeight(), window.mc.width / window.getWidth()];
    // Unblocks all skins without the need for FB sharing.
    window.localStorage.setItem('edttsg', '1');
    window.loadPreferences();
    window.launchBot(50);
};
window.initBot();
// Enemy code - not used for now
/*
// Sort enemies based on distance
window.getSortedEnemies = function() {
    Filters the nearest food by getting the distance
    return window.snakes.filter(function(val) {
        return val !== null && val.id !== window.snake.id;
    }).map(window.getDistanceFromMe).sort(window.sortEnemy);
};
// Sorting function for enemies, from property 'distance'
window.sortEnemy = function(a, b) {
    return a.distance - b.distance;
};
        window.sortedEnemies = window.getSortedEnemies();
        // Take the closest of each
        window.closestEnemy = window.sortedEnemies[0];
        if (window.closestEnemy.distance < 300) {
        window.log('close enemy! (distance = ' + window.closestEnemy.distance);
        // !handle close enemies!
         }
*/
// Better food hunting algorithm but not implemented yet
/*
window.isInFoods = function (foodObject) {
    return (foodObject === null) ? false : (window.foods.indexOf(foodObject) >= 0);
};
window.currentFood = null;
window.sortedFood = getSortedFood();
window.loop = function () {
    if (!isInFoods(currentFood)) {
        window.sortedFood = getSortedFood();
        window.currentFood = sortedFood[0];
        var coordinatesOfClosestFood = window.mapToMouse(window.sortedFood[0].xx, window.sortedFood[0].yy);
        window.setMouseCoordinates(coordinatesOfClosestFood[0], coordinatesOfClosestFood[1]);
    }
};
*/
<|endoftext|>


<commit_before>var config = new Config();
var uninstallList = [];

window.addEventListener("load", function(ev) {
  config.load();
  loadControls();

  if (!config.scripts.length == 0) {
    populateChooser();
    chooseScript(0);
  }
}, false);

function handleOkButton() {
  for (var i = 0, script = null; (script = uninstallList[i]); i++) {
    var idx = config.find(script.namespace, script.name);
    config.scripts.splice(idx, 1);
  }
  config.save();

  var chkUninstallPrefs = document.getElementById('chkUninstallPrefs');
  for (var i = 0, script = null; (script = uninstallList[i]); i++) {
    file = getScriptBasedir(script);
    if (!file.equals(getScriptDir())) {
      if (file.exists()) {
        file.remove(true); // file==base directory recursive delete
      }
    } else {
      file = getScriptFile(script);
      if (file.exists()) {
        file.remove(false);
      }
    }
    if (chkUninstallPrefs.checked) {
       // Remove saved preferences
       var scriptPrefRoot = ["scriptvals.",
                  script.namespace,
                  "/",
                  script.name,
                  "."].join("");
       GM_prefRoot.remove(scriptPrefRoot);
    }
  }
  return true;
};

var listbox, header, description, chkEnabled, btnEdit, btnUninstall;
var selectedScript;
var pagesControl;

function loadControls() {
  listbox = document.getElementById("lstScripts");
  header = document.getElementById("ctlHeader");
  description = document.getElementById("ctlDescription");
  btnEdit = document.getElementById("btnEdit");
  btnUninstall = document.getElementById("btnUninstall");
  pagesControl = new PagesControl(document.getElementById("pages-control"));
  chkEnabled = document.getElementById("chkEnabled");

  listbox.addEventListener("select", function() { updateDetails(); }, false);
  btnEdit.addEventListener("command", function() { handleEditButton(); }, false);
  btnUninstall.addEventListener("command", function() { handleUninstallButton(); }, false);
  chkEnabled.addEventListener("command", function() {
     if (selectedScript) {
       selectedScript.enabled = chkEnabled.checked;
       if (selectedScript.enabled) {
         listbox.selectedItem.style.color = '';
       } else {
         listbox.selectedItem.style.color = 'gray';
       }
     }
  }, false);
};

function updateDetails() {
  if (listbox.selectedCount == 0) {
    selectedScript = null;
    header.textContent = " ";
    description.textContent = " ";
    chkEnabled.checked = true;
    pagesControl.clear();
    document.documentElement.getButton("accept").disabled = false;
  } else {
    selectedScript = listbox.getSelectedItem(0).script;

    // make sure one word isn't too long to fit ... a too-long word
    // will bump the interface out wider than the window
    var wordLen = 50;
    var desc = selectedScript.description.split(/\s+/);
    for (var i = 0; i < desc.length; i++) {
      if (desc[i].length > wordLen) {
        for (var j = desc[i].length; j > 0; j -= wordLen) {
          desc[i] = desc[i].substr(0,j) + '\u200B' + desc[i].substr(j);
        }
      }
    }
    desc = desc.join(' ');

    header.textContent = selectedScript.name;
    description.textContent = desc;
    chkEnabled.checked = selectedScript.enabled;
    pagesControl.populate(selectedScript);
  }
};

function handleEditButton() {
  openInEditor(getScriptFile(selectedScript),
  document.getElementById("gm-manage-bundle").getString("editor.prompt"));
};

function handleUninstallButton() {
  var index=listbox.selectedIndex;

  // mark script to be uninstalled on "OK"
  uninstallList.push(selectedScript);

  // remove it from the display
  listbox.removeChild(listbox.childNodes[index]);

  if (listbox.childNodes.length > 0) {
    chooseScript(Math.max(Math.min(listbox.selectedIndex, listbox.childNodes.length - 1), 0));
  }
};

function populateChooser() {
  for (var i = 0, script = null; (script = config.scripts[i]); i++) {
    var listitem = document.createElement("listitem");

    listitem.setAttribute("label", script.name);
    listitem.setAttribute("crop", "end");
    listitem.script = script;
    listitem.index = i;

    if (!script.enabled) {
      listitem.style.color = 'gray';
    }

  listbox.appendChild(listitem);
  }
};

function chooseScript(index) {
  listbox.selectedIndex = index;
  listbox.focus();
};

function toggleScript(index, enableFlag) {
  var listitem = listbox.childNodes[index];
  if (enableFlag) {
    listitem.script.enabled = true;
    listitem.style.color = '';
  } else {
    listitem.script.enabled = false;
    listitem.style.color = 'gray';
  }
};

function reorderScript(from, to) {
  // make sure to and from are in range
  if (from < 0 || to < 0 ||
    from > config.scripts.length || to > config.scripts.length
  ) {
    return false;
  }

  // REORDER CONFIG:
  // save item-to-move
  var tmp = config.scripts[from];
  // remove it
  config.scripts.splice(from, 1);
  // put it back in the new spot
  config.scripts.splice(to, 0, tmp);

  // REORDER DISPLAY:
  var tmp = listbox.childNodes[from];
  listbox.removeChild(tmp);
  listbox.insertBefore(tmp, listbox.childNodes[to]);
  // fix the listbox indexes
  for (var i=0, node=null; node=listbox.childNodes[i]; i++) {
    node.index=i;
  }

  // then re-select the dropped script
  listbox.selectedIndex = to;

  return true;
};

// allow reordering scripts with keyboard (alt- up and down)
function listboxKeypress(event) {
  if (0 == listbox.selectedCount) return;
  if (!event.altKey) return;

  var index = listbox.selectedIndex;

  if (KeyEvent.DOM_VK_UP == event.keyCode) {
    if (0 == index) return;

    !reorderScript(index, index - 1);
    listbox.selectedIndex = index - 1;
  } else if (KeyEvent.DOM_VK_DOWN == event.keyCode) {
    if (index == config.scripts.length - 1) return;

    !reorderScript(index, index + 1);
    listbox.selectedIndex = index + 1;
  }
};

// allow reordering scripts with drag-and-drop
var dndObserver = {
  lastFeedbackIndex: null,

  getSupportedFlavours: function () {
    var flavours = new FlavourSet();
    flavours.appendFlavour("text/unicode");
    return flavours;
  },

  onDragStart: function (event, transferData, action) {
    if ('listitem' != event.target.tagName ) return false;

    transferData.data = new TransferData();
    transferData.data.addDataForFlavour("text/unicode", event.target.index);

    return true;
  },

  onDragOver: function (event, flavour, session) {
    if (listbox.selectedIndex == event.target.index) {
      this.clearFeedback();
      return false;
    }

    return this.setFeedback(event);
  },

  onDrop: function (event, dropdata, session) {
    // clean up the feedback
    this.lastFeedbackIndex = null;
    this.clearFeedback();

    // figure out how to move
    var newIndex = this.findNewIndex(event);
    if (null === newIndex) return;
    var index = parseInt(dropdata.data);
    if (newIndex > index) newIndex--;

    // do the move
    reorderScript(index, newIndex);
  },

  //////////////////////////////////////////////////////////////////////////////

  setFeedback: function(event) {
    var newIndex = this.findNewIndex(event);

    // don't do anything if we haven't changed
    if (newIndex === this.lastFeedbackIndex) return false; // NOTE: possible incongruent logic
    this.lastFeedbackIndex = newIndex;

    // clear any previous feedback
    this.clearFeedback();

    // and set the current feedback
    if (null === newIndex) {
      return false;
    } else if (listbox.selectedIndex == newIndex) {
      return false;
    } else {
      if (0 == newIndex) {
        listbox.firstChild.setAttribute('dragover', 'top');
      } else if (newIndex >= listbox.childNodes.length) {
        listbox.lastChild.setAttribute('dragover', 'bottom');
      } else {
        listbox.childNodes[newIndex - 1].setAttribute('dragover', 'bottom');
      }
    }

    return true;
  },

  clearFeedback: function() {
    var box = document.getElementById('lstScripts');
    for (var i = 0, el; el = box.childNodes[i]; i++) {
      el.removeAttribute('dragover');
    }
  },

  findNewIndex: function(event) {
    var target = event.target;

    // not in the list box? forget it!
    if (listbox != target && listbox != target.parentNode) return null;

    var targetBox = target.boxObject
      .QueryInterface(Components.interfaces.nsIBoxObject);

    if (listbox == target) {
      // here, we are hovering over the listbox, not a particular listitem
      // check if we are very near the top (y + 4), return zero, else return end
      if (event.clientY < targetBox.y + 4) {
        return 0;
      } else {
        return listbox.childNodes.length;
      }
    } else {
      var targetMid = targetBox.y + (targetBox.height / 2);

      if (event.clientY >= targetMid) {
        return target.index + 1;
      } else {
        return target.index;
      }
    }

    // should never get here, but in case
    return null;
  }
};<commit_msg>Fix another form of issue 63 that happened on windows this time.<commit_after>var config = new Config();
var uninstallList = [];

window.addEventListener("load", function(ev) {
  config.load();
  loadControls();

  if (!config.scripts.length == 0) {
    populateChooser();
    chooseScript(0);
  }
}, false);

function handleOkButton() {
  for (var i = 0, script = null; (script = uninstallList[i]); i++) {
    var idx = config.find(script.namespace, script.name);
    config.scripts.splice(idx, 1);
  }
  config.save();

  var chkUninstallPrefs = document.getElementById('chkUninstallPrefs');
  for (var i = 0, script = null; (script = uninstallList[i]); i++) {
    file = getScriptBasedir(script);
    file.normalize();
    if (!file.equals(getScriptDir())) {
      if (file.exists()) {
        file.remove(true); // file==base directory recursive delete
      }
    } else {
      file = getScriptFile(script);
      if (file.exists()) {
        file.remove(false);
      }
    }
    if (chkUninstallPrefs.checked) {
       // Remove saved preferences
       var scriptPrefRoot = ["scriptvals.",
                  script.namespace,
                  "/",
                  script.name,
                  "."].join("");
       GM_prefRoot.remove(scriptPrefRoot);
    }
  }
  return true;
};

var listbox, header, description, chkEnabled, btnEdit, btnUninstall;
var selectedScript;
var pagesControl;

function loadControls() {
  listbox = document.getElementById("lstScripts");
  header = document.getElementById("ctlHeader");
  description = document.getElementById("ctlDescription");
  btnEdit = document.getElementById("btnEdit");
  btnUninstall = document.getElementById("btnUninstall");
  pagesControl = new PagesControl(document.getElementById("pages-control"));
  chkEnabled = document.getElementById("chkEnabled");

  listbox.addEventListener("select", function() { updateDetails(); }, false);
  btnEdit.addEventListener("command", function() { handleEditButton(); }, false);
  btnUninstall.addEventListener("command", function() { handleUninstallButton(); }, false);
  chkEnabled.addEventListener("command", function() {
     if (selectedScript) {
       selectedScript.enabled = chkEnabled.checked;
       if (selectedScript.enabled) {
         listbox.selectedItem.style.color = '';
       } else {
         listbox.selectedItem.style.color = 'gray';
       }
     }
  }, false);
};

function updateDetails() {
  if (listbox.selectedCount == 0) {
    selectedScript = null;
    header.textContent = " ";
    description.textContent = " ";
    chkEnabled.checked = true;
    pagesControl.clear();
    document.documentElement.getButton("accept").disabled = false;
  } else {
    selectedScript = listbox.getSelectedItem(0).script;

    // make sure one word isn't too long to fit ... a too-long word
    // will bump the interface out wider than the window
    var wordLen = 50;
    var desc = selectedScript.description.split(/\s+/);
    for (var i = 0; i < desc.length; i++) {
      if (desc[i].length > wordLen) {
        for (var j = desc[i].length; j > 0; j -= wordLen) {
          desc[i] = desc[i].substr(0,j) + '\u200B' + desc[i].substr(j);
        }
      }
    }
    desc = desc.join(' ');

    header.textContent = selectedScript.name;
    description.textContent = desc;
    chkEnabled.checked = selectedScript.enabled;
    pagesControl.populate(selectedScript);
  }
};

function handleEditButton() {
  openInEditor(getScriptFile(selectedScript),
  document.getElementById("gm-manage-bundle").getString("editor.prompt"));
};

function handleUninstallButton() {
  var index=listbox.selectedIndex;

  // mark script to be uninstalled on "OK"
  uninstallList.push(selectedScript);

  // remove it from the display
  listbox.removeChild(listbox.childNodes[index]);

  if (listbox.childNodes.length > 0) {
    chooseScript(Math.max(Math.min(listbox.selectedIndex, listbox.childNodes.length - 1), 0));
  }
};

function populateChooser() {
  for (var i = 0, script = null; (script = config.scripts[i]); i++) {
    var listitem = document.createElement("listitem");

    listitem.setAttribute("label", script.name);
    listitem.setAttribute("crop", "end");
    listitem.script = script;
    listitem.index = i;

    if (!script.enabled) {
      listitem.style.color = 'gray';
    }

  listbox.appendChild(listitem);
  }
};

function chooseScript(index) {
  listbox.selectedIndex = index;
  listbox.focus();
};

function toggleScript(index, enableFlag) {
  var listitem = listbox.childNodes[index];
  if (enableFlag) {
    listitem.script.enabled = true;
    listitem.style.color = '';
  } else {
    listitem.script.enabled = false;
    listitem.style.color = 'gray';
  }
};

function reorderScript(from, to) {
  // make sure to and from are in range
  if (from < 0 || to < 0 ||
    from > config.scripts.length || to > config.scripts.length
  ) {
    return false;
  }

  // REORDER CONFIG:
  // save item-to-move
  var tmp = config.scripts[from];
  // remove it
  config.scripts.splice(from, 1);
  // put it back in the new spot
  config.scripts.splice(to, 0, tmp);

  // REORDER DISPLAY:
  var tmp = listbox.childNodes[from];
  listbox.removeChild(tmp);
  listbox.insertBefore(tmp, listbox.childNodes[to]);
  // fix the listbox indexes
  for (var i=0, node=null; node=listbox.childNodes[i]; i++) {
    node.index=i;
  }

  // then re-select the dropped script
  listbox.selectedIndex = to;

  return true;
};

// allow reordering scripts with keyboard (alt- up and down)
function listboxKeypress(event) {
  if (0 == listbox.selectedCount) return;
  if (!event.altKey) return;

  var index = listbox.selectedIndex;

  if (KeyEvent.DOM_VK_UP == event.keyCode) {
    if (0 == index) return;

    !reorderScript(index, index - 1);
    listbox.selectedIndex = index - 1;
  } else if (KeyEvent.DOM_VK_DOWN == event.keyCode) {
    if (index == config.scripts.length - 1) return;

    !reorderScript(index, index + 1);
    listbox.selectedIndex = index + 1;
  }
};

// allow reordering scripts with drag-and-drop
var dndObserver = {
  lastFeedbackIndex: null,

  getSupportedFlavours: function () {
    var flavours = new FlavourSet();
    flavours.appendFlavour("text/unicode");
    return flavours;
  },

  onDragStart: function (event, transferData, action) {
    if ('listitem' != event.target.tagName ) return false;

    transferData.data = new TransferData();
    transferData.data.addDataForFlavour("text/unicode", event.target.index);

    return true;
  },

  onDragOver: function (event, flavour, session) {
    if (listbox.selectedIndex == event.target.index) {
      this.clearFeedback();
      return false;
    }

    return this.setFeedback(event);
  },

  onDrop: function (event, dropdata, session) {
    // clean up the feedback
    this.lastFeedbackIndex = null;
    this.clearFeedback();

    // figure out how to move
    var newIndex = this.findNewIndex(event);
    if (null === newIndex) return;
    var index = parseInt(dropdata.data);
    if (newIndex > index) newIndex--;

    // do the move
    reorderScript(index, newIndex);
  },

  //////////////////////////////////////////////////////////////////////////////

  setFeedback: function(event) {
    var newIndex = this.findNewIndex(event);

    // don't do anything if we haven't changed
    if (newIndex === this.lastFeedbackIndex) return false; // NOTE: possible incongruent logic
    this.lastFeedbackIndex = newIndex;

    // clear any previous feedback
    this.clearFeedback();

    // and set the current feedback
    if (null === newIndex) {
      return false;
    } else if (listbox.selectedIndex == newIndex) {
      return false;
    } else {
      if (0 == newIndex) {
        listbox.firstChild.setAttribute('dragover', 'top');
      } else if (newIndex >= listbox.childNodes.length) {
        listbox.lastChild.setAttribute('dragover', 'bottom');
      } else {
        listbox.childNodes[newIndex - 1].setAttribute('dragover', 'bottom');
      }
    }

    return true;
  },

  clearFeedback: function() {
    var box = document.getElementById('lstScripts');
    for (var i = 0, el; el = box.childNodes[i]; i++) {
      el.removeAttribute('dragover');
    }
  },

  findNewIndex: function(event) {
    var target = event.target;

    // not in the list box? forget it!
    if (listbox != target && listbox != target.parentNode) return null;

    var targetBox = target.boxObject
      .QueryInterface(Components.interfaces.nsIBoxObject);

    if (listbox == target) {
      // here, we are hovering over the listbox, not a particular listitem
      // check if we are very near the top (y + 4), return zero, else return end
      if (event.clientY < targetBox.y + 4) {
        return 0;
      } else {
        return listbox.childNodes.length;
      }
    } else {
      var targetMid = targetBox.y + (targetBox.height / 2);

      if (event.clientY >= targetMid) {
        return target.index + 1;
      } else {
        return target.index;
      }
    }

    // should never get here, but in case
    return null;
  }
};<|endoftext|>


<commit_before>'use strict';

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    define([ 'underscore', 'jquery', 'backbone' ], factory);
  }
}(this, function (_, $, Backbone) {
  Backbone.cache = (function () {
    var cache = { lifetime = 30000 },
        ajax = Backbone.ajax,
        requests = new Backbone.Collection();

    cache.ajax = function (url, options) {
      if (typeof url === 'object') options = url;

      var cachable = options.type === 'GET';

      // If anything other than a GET request is
      // fired we reset our position to neutral
      if (!cachable) requests.reset();

      var cached = cache.findWhere({ url: options.url });

      // We need to fool Backbone into thinking that
      // the request has succeeded in a normal fashion
      var triggerSuccess = function (xhr) {
        options.success(xhr.responseJSON, 'success', xhr);
      };

      // We need the cached requests to remove themselves
      // after an alotted amount of time has passed
      var startCacheReaper = function () {
        _.delay(function () {
          requests.remove([ cache.findWhere({ url: options.url }) ]);
        }, Cache.lifetime);
      };

      // We need to add the request to the cache if it was
      // cacheable and it was successful
      var cacheRequest = function (response, status, xhr) {
        if (cachable && status === 'success') {
          requests.add({ url: options.url, xhr: xhr });
        }
      };

      if (cachable && options.success && cached) {
        var xhr = cached.get('xhr');

        // We need to defer our success to the end of the
        // current event loop stack due to Backbone.sync
        // firing a request event after calling this method
        _.defer(triggerSuccess, xhr);
      } else {
        var xhr = ajax.apply(this, arguments)
          .done(cacheRequest)
          .done(startCacheReaper);
      }

      return xhr;
    };

    // We need to replace the existing
    // ajax method with the caching one
    Backbone.ajax = cache.ajax;

    return cache;
  })(Backbone, $, _);
}));
<commit_msg>Update backbone.cache.js<commit_after>'use strict';

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    define([ 'underscore', 'jquery', 'backbone' ], factory);
  }
}(this, function (_, $, Backbone) {
  Backbone.cache = (function () {
    var cache = { lifetime = 30000 },
        ajax = Backbone.ajax,
        requests = new Backbone.Collection();

    cache.ajax = function (url, options) {
      if (typeof url === 'object') options = url;

      var cachable = options.type === 'GET';

      // If anything other than a GET request is
      // fired we reset our position to neutral
      if (!cachable) requests.reset();

      var cached = cache.findWhere({ url: options.url });

      // We need to fool Backbone into thinking that
      // the request has succeeded in a normal fashion
      var triggerSuccess = function (xhr) {
        options.success(xhr.responseJSON, 'success', xhr);
      };

      // We need the cached requests to remove themselves
      // after an alotted amount of time has passed
      var startCacheReaper = function () {
        _.delay(function () {
          requests.remove([ cache.findWhere({ url: options.url }) ]);
        }, cache.lifetime);
      };

      // We need to add the request to the cache if it was
      // cacheable and it was successful
      var cacheRequest = function (response, status, xhr) {
        if (cachable && status === 'success') {
          requests.add({ url: options.url, xhr: xhr });
        }
      };

      if (cachable && options.success && cached) {
        var xhr = cached.get('xhr');

        // We need to defer our success to the end of the
        // current event loop stack due to Backbone.sync
        // firing a request event after calling this method
        _.defer(triggerSuccess, xhr);
      } else {
        var xhr = ajax.apply(this, arguments)
          .done(cacheRequest)
          .done(startCacheReaper);
      }

      return xhr;
    };

    // We need to replace the existing
    // ajax method with the caching one
    Backbone.ajax = cache.ajax;

    return cache;
  })(Backbone, $, _);
}));
<|endoftext|>


<commit_before>module.exports = function(grunt) {
    grunt.util.linefeed = '\n';

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        config: grunt.file.readYAML('../config/config.yml'),

        filesBoltJs: [
            'lib/bolt/console.js',
            'lib/bolt/fnc-helpers.js',
            'lib/bolt/activity.js',
            'lib/bolt/bind-fileupload.js',
            'lib/bolt/make-uri-slug.js',
            'lib/bolt/video-embed.js',
            'lib/bolt/geolocation.js',
            'lib/bolt/upload-files.js',
            'lib/bolt/obj-sidebar.js',
            'lib/bolt/obj-navpopups.js',
            'lib/bolt/obj-moments.js',
            'lib/bolt/obj-files.js',
            'lib/bolt/obj-stack.js',
            'lib/bolt/obj-folders.js',
            'lib/bolt/obj-datetime.js',
            'lib/bolt/extend.js',
            'lib/bolt/init.js',
            'lib/bolt/start.js'
        ],

        /*
         * WATCH: Run predefined tasks whenever watched file patterns are added, changed or deleted
         */
        watch: {
            options: {
                spawn: false,
                livereload: true
            },
            sass: {
                files: [
                    'sass/*.scss',
                    'sass/**/*.scss'
                ],
                tasks: [
                    'sass:boltCss',
                    'eol:boltCss'
                ]
            },
            boltJs: {
                files: [
                    "<%= filesBoltJs %>"
                ],
                tasks: [
                    'jshint:boltJs',
                    'uglify:boltJs'
                ]
            },
            gruntfile: {
                files: [
                    'Gruntfile.js'
                ],
                options: {
                    reload: true
                }
            }
        },

        /*
         * SASS: Compile Sass to CSS
         */
        sass: {
            boltCss: {
                options: {
                    outputStyle: 'compressed',
                    includePaths: [
                        'node_modules/bootstrap-sass/assets/stylesheets/',
                        'node_modules/font-awesome/scss/'
                    ],
                    lineNumbers: false,
                    unixNewlines: true,
                    banner: "/**\n" +
                            " * These are Bolt's COMPILED CSS files!\n" +
                            " * Do not edit these files, because all changes will be lost.\n" +
                            " * You can edit ../scss/app.scss & ../scss/app-old-ie.scss, and run 'grunt' to generate this file.\n" +
                            " */\n",
                    precision: 5
                },
                files: {
                    'css/bolt-old-ie.css': 'sass/app-old-ie.scss',
                    'css/bolt.css': 'sass/app.scss'
                }
            }
        },

        /*
         * EOL: Convert line endings
         */
        eol: {
            boltCss: {
                options: {
                    eol: 'lf',
                    replace: true
                },
                files: {
                    src: [
                        'css/bolt-old-ie.css',
                        'css/bolt.css'
                    ]
                }
            },
        },

        /*
         * COPY: Copy files and folders
         */
        copy: {
            installFonts: {
                files: [{
                    expand: true,
                    flatten: true,
                    src: [
                        'node_modules/font-awesome/fonts/*'
                    ],
                    filter: 'isFile',
                    dest: 'fonts/'
                }]
            }
        },

        /*
         * CONCAT: Concatenate files
         */
        concat: {
            installLibJs: {
                options: {
                    separator: '\n\n'
                },
                nonull: true,
                src: [
                    'lib/jquery-1.11.2/jquery.min.js',                              //  96 kb
                    'lib/jquery-ui-1.10.3/jquery-ui.custom.min.js',                 //  96 kb
                    'lib/bootstrap-file-input/bootstrap-file-input.min.js',         //   1 kb
                    'lib/jquery-tagcloud/jquery-tagcloud.min.js',                   //   1 kb
                    'lib/jquery-hotkeys/jquery-hotkeys.min.js',                     //   2 kb
                    'lib/jquery-watchchanges/jquery-watchchanges.min.js',           //   1 kb
                    'lib/jquery-cookie-1.4.0/jquery-cookie.min.js',                 //   1 kb
                    'lib/jquery-formatdatetime-1.1.4/jquery-formatdatetime.min.js', //   3 kb
                    'lib/jquery-fileupload-5.26/jquery-iframe-transport.min.js',    //   2 kb
                    'lib/jquery-fileupload-5.26/jquery-fileupload.min.js',          //  15 kb
                    'lib/underscore-1.7.0/underscore-min.js',                       //  16 kb
                    'lib/backbone/backbone-min.js',                                 //  20 kb
                    'lib/bootstrap-sass.generated/bootstrap.min.js',                //   2 kb
                    'lib/magnific-popup-1.0.0/magnific-popup.min.js',               //  21 kb
                    'lib/select2-3.5.1/select2.min.js',                             //  66 kb
                    'node_modules/moment/min/moment.min.js',                        //  35 kb
                    'lib/bootbox-4.3.0/bootbox.min.js',                             //   9 kb
                    'lib/modernizr-2.8.3/modernizr.custom.min.js'                   //   5 kb
                ],
                dest: 'js/lib.min.js'
            }
        },

        /*
         * CSSMIN: Compress CSS files
         */
        cssmin: {
            installLibCss: {
                options: {
                    compatibility: 'ie8',
                    relativeTo: 'css/',
                    target: 'css/'
                },
                files: {
                    'css/lib.css': [
                        'lib/jquery-ui-1.10.3/jquery-ui.custom.min.css',      // 20 kb
                        'lib/magnific-popup-1.0.0/magnific-popup.css',        //  9 kb
                        'lib/select2-3.5.1/select2.css',                      // 19 kb
                        'lib/jquery-fileupload-5.26/jquery-fileupload-ui.css' //  2 kb
                    ]
                }
            }
        },

        /*
         * UGLIFY: Minify files with UglifyJS
         */
        uglify: {
            prepareLibJs: {
                options: {
                    preserveComments: 'some'
                },
                files: [{
                    expand: true,
                    ext: '.min.js',
                    src: [
                        'lib/bootstrap-file-input/bootstrap-file-input.js',
                        'lib/jquery-cookie-1.4.0/jquery-cookie.js',
                        'lib/jquery-fileupload-5.26/jquery-fileupload.js',
                        'lib/jquery-fileupload-5.26/jquery-iframe-transport.js',
                        'lib/jquery-formatdatetime-1.1.4/jquery-formatdatetime.js',
                        'lib/jquery-hotkeys/jquery-hotkeys.js',
                        'lib/jquery-tagcloud/jquery-tagcloud.js',
                        'lib/jquery-watchchanges/jquery-watchchanges.js'
                    ]
                }]
            },
            installLocaleDatepicker: {
                options: {
                    preserveComments: 'some'
                },
                files: [{
                    expand: true,
                    ext: '.min.js',
                    cwd: 'lib/datepicker',
                    src: '*.js',
                    dest: 'js/locale/datepicker',
                    rename: function (destBase, destPath) {
                        return destBase + '/' + destPath.replace('datepicker-', '').replace('-', '_');
                    }
                }]
            },
            installLocaleMoment: {
                options: {
                    preserveComments: 'some'
                },
                files: [{
                    expand: true,
                    ext: '.min.js',
                    cwd: 'node_modules/moment/locale',
                    src: '*.js',
                    dest: 'js/locale/moment',
                    rename: function (destBase, destPath) {
                        return destBase + '/' + destPath.replace(/([a-z]+)-([a-z]+)/, function (_, a, b) {
                            return a + '_' + b.toUpperCase();
                        });
                    }
                }]
            },
            prepareBootstrapJs: {
                files: {
                    'lib/bootstrap-sass.generated/bootstrap.min.js': [
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/alert.js',
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/button.js',
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/dropdown.js',
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/tab.js',
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/transition.js',
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/modal.js',
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/tooltip.js',
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/popover.js'
                    ]
                }
            },
            boltJs: {
                options: {
                    banner: "/**\n" +
                            " * These are Bolt's COMPILED JS files!\n" +
                            " * You can edit files in <js/src/*.js> and run 'grunt' to generate this file.\n" +
                            " */",
                    sourceMap: true
                },
                files: {
                    'js/bolt.min.js': ["<%= filesBoltJs %>"]
                }
            }
        },

        /*
         * JSHINT: Validates files with JSHint
         */
        jshint: {
            boltJs: {
                options: {
                    browser: true,      // Defines globals exposed by modern browsers
                    curly: true,        // Always put curly braces around blocks
                    devel: true,        // Defines globals that are usually used for logging/debugging
                    immed: true,        // Prohibits the use of immediate function invocations without parentheses
                    indent: 4,          // Tab width
                    latedef: true,      // Prohibits the use of a variable before it was defined
                    maxlen: 120,        // Maximum length of a line
                    noarg: true,        // Prohibits the use of arguments.caller and arguments.callee
                    nonbsp: true,       // Warns about "non-breaking whitespace" characters
                    singleGroups: true, // Prohibits the use of the grouping operator for single-expression statements
                    undef: true,        // Prohibits the use of undeclared variables
                    globals: {
                        // Bolt
                        bolt: true,                 // src/console.js
                        FilelistHolder: true,       // src/upload-files.js
                        Files: true,                // src/obj-files.js
                        Folders: true,              // src/obj-folders.js
                        init: true,                 // src/init.js
                        Moments: true,              // src/obj-moments.js
                        Navpopups: true,            // src/obj-navpopups.js
                        Sidebar: true,              // src/obj-sidebar.js
                        Stack: true,                // src/obj-stack.js
                        site: true,                 // src/extend.js/extend.twig
                        baseurl: true,              // src/extend.js/extend.twig
                        rootpath: true,             // src/extend.js/extend.twig
                        // Bolt global functions
                        bindFileUpload: true,       // src/bindfileuploads.js
                        bindGeolocation: true,      // src/geolocation.js
                        bindVideoEmbed: true,       // src/video-embed.js
                        getSelectedItems: true,     // src/fnc-helpers.js
                        makeUri: true,              // src/make-uri-slug.js
                        makeUriAjax: true,          // src/make-uri-slug.js
                        stopMakeUri: true,          // src/make-uri-slug.js
                        updateLatestActivity: true, // src/activity.js
                        validateContent: true,      // src/fnc-helpers.js
                        // Vendor
                        $: true,                    // jQuery
                        _: true,                    // underscore.js
                        Backbone: true,             // backbone.min.js
                        bootbox: true,              // bootbox.min.js
                        CKEDITOR: true,             // ckeditor.js
                        CodeMirror: true,           // ckeditor.js
                        google: true,               // Google
                        jQuery: true,               // jQuery
                        moment: true,               // moment.min.js
                        UAParser: true              // ua-parser.min.js
                    }
                },
                src: ["<%= filesBoltJs %>"]
            }
        },

        /*
         * REMOVE: Remove directory and files
         */
        remove: {
            prepareCkeditor: {
                dirList: [
                    'lib/ckeditor-4.4.7/adapters',
                    'lib/ckeditor-4.4.7/samples'
                ]
            }
        }
    });

    require('load-grunt-tasks')(grunt);

    /*** DEFAULT TASK:  Watches for changes of Bolts own css and js files ***/
    grunt.registerTask(
        'default',
        [
            'watch'
        ]
    );

    /*** UPDATE BOLT TASK:  Creates Bolts own css and js files ***/
    grunt.registerTask(
        'updateBolt',
        [
            'sass:boltCss',
            'eol:boltCss',
            'jshint:boltJs',
            'uglify:boltJs'
        ]
    );

    /*** UPDATE LIB TASK:  Builds library css/js. Run after one of the externals is updated ***/
    grunt.registerTask(
        'updateLib',
        [
            // Prepare
            'uglify:prepareBootstrapJs',        // Concat bootstrap scripts into one minified file
            'uglify:prepareLibJs',              // Create minified versions of library scripts that don't have them
            'remove:prepareCkeditor',           // Remove unneeded direcories from downloaded ckeditor
            // Install
            'copy:installFonts',                // Copies fonts                       => view/fonts/*
            'cssmin:installLibCss',             // Concats and minifies library css   => view/css/lib.css
            'concat:installLibJs',              // Concats minified library scripts   => view/js/lib.min.js
            'uglify:installLocaleDatepicker',   // Copies minified datepicker locale  => view/js/locale/datepicker/*
            'uglify:installLocaleMoment'        // Copies minified moment.js locale   => view/js/locale/datepicker/*
        ]
    );
};
<commit_msg>Add BOM removal<commit_after>module.exports = function(grunt) {
    grunt.util.linefeed = '\n';

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        config: grunt.file.readYAML('../config/config.yml'),

        filesBoltJs: [
            'lib/bolt/console.js',
            'lib/bolt/fnc-helpers.js',
            'lib/bolt/activity.js',
            'lib/bolt/bind-fileupload.js',
            'lib/bolt/make-uri-slug.js',
            'lib/bolt/video-embed.js',
            'lib/bolt/geolocation.js',
            'lib/bolt/upload-files.js',
            'lib/bolt/obj-sidebar.js',
            'lib/bolt/obj-navpopups.js',
            'lib/bolt/obj-moments.js',
            'lib/bolt/obj-files.js',
            'lib/bolt/obj-stack.js',
            'lib/bolt/obj-folders.js',
            'lib/bolt/obj-datetime.js',
            'lib/bolt/extend.js',
            'lib/bolt/init.js',
            'lib/bolt/start.js'
        ],

        /*
         * WATCH: Run predefined tasks whenever watched file patterns are added, changed or deleted
         */
        watch: {
            options: {
                spawn: false,
                livereload: true
            },
            sass: {
                files: [
                    'sass/*.scss',
                    'sass/**/*.scss'
                ],
                tasks: [
                    'sass:boltCss',
                    'eol:boltCss'
                ]
            },
            boltJs: {
                files: [
                    "<%= filesBoltJs %>"
                ],
                tasks: [
                    'jshint:boltJs',
                    'uglify:boltJs'
                ]
            },
            gruntfile: {
                files: [
                    'Gruntfile.js'
                ],
                options: {
                    reload: true
                }
            }
        },

        /*
         * SASS: Compile Sass to CSS
         */
        sass: {
            boltCss: {
                options: {
                    outputStyle: 'compressed',
                    includePaths: [
                        'node_modules/bootstrap-sass/assets/stylesheets/',
                        'node_modules/font-awesome/scss/'
                    ],
                    lineNumbers: false,
                    unixNewlines: true,
                    banner: "/**\n" +
                            " * These are Bolt's COMPILED CSS files!\n" +
                            " * Do not edit these files, because all changes will be lost.\n" +
                            " * You can edit ../scss/app.scss & ../scss/app-old-ie.scss, and run 'grunt' to generate this file.\n" +
                            " */\n",
                    precision: 5
                },
                files: {
                    'css/bolt-old-ie.css': 'sass/app-old-ie.scss',
                    'css/bolt.css': 'sass/app.scss'
                }
            }
        },

        /*
         * EOL: Convert line endings
         */
        eol: {
            boltCss: {
                options: {
                    eol: 'lf',
                    replace: true
                },
                files: {
                    src: [
                        'css/bolt-old-ie.css',
                        'css/bolt.css'
                    ]
                }
            },
        },

        /*
         * COPY: Copy files and folders
         */
        copy: {
            installFonts: {
                files: [{
                    expand: true,
                    flatten: true,
                    src: [
                        'node_modules/font-awesome/fonts/*'
                    ],
                    filter: 'isFile',
                    dest: 'fonts/'
                }]
            }
        },

        /*
         * CONCAT: Concatenate files
         */
        concat: {
            installLibJs: {
                options: {
                    separator: '\n\n'
                },
                nonull: true,
                src: [
                    'lib/jquery-1.11.2/jquery.min.js',                              //  96 kb
                    'lib/jquery-ui-1.10.3/jquery-ui.custom.min.js',                 //  96 kb
                    'lib/bootstrap-file-input/bootstrap-file-input.min.js',         //   1 kb
                    'lib/jquery-tagcloud/jquery-tagcloud.min.js',                   //   1 kb
                    'lib/jquery-hotkeys/jquery-hotkeys.min.js',                     //   2 kb
                    'lib/jquery-watchchanges/jquery-watchchanges.min.js',           //   1 kb
                    'lib/jquery-cookie-1.4.0/jquery-cookie.min.js',                 //   1 kb
                    'lib/jquery-formatdatetime-1.1.4/jquery-formatdatetime.min.js', //   3 kb
                    'lib/jquery-fileupload-5.26/jquery-iframe-transport.min.js',    //   2 kb
                    'lib/jquery-fileupload-5.26/jquery-fileupload.min.js',          //  15 kb
                    'lib/underscore-1.7.0/underscore-min.js',                       //  16 kb
                    'lib/backbone/backbone-min.js',                                 //  20 kb
                    'lib/bootstrap-sass.generated/bootstrap.min.js',                //   2 kb
                    'lib/magnific-popup-1.0.0/magnific-popup.min.js',               //  21 kb
                    'lib/select2-3.5.1/select2.min.js',                             //  66 kb
                    'node_modules/moment/min/moment.min.js',                        //  35 kb
                    'lib/bootbox-4.3.0/bootbox.min.js',                             //   9 kb
                    'lib/modernizr-2.8.3/modernizr.custom.min.js'                   //   5 kb
                ],
                dest: 'js/lib.min.js'
            }
        },

        /*
         * CSSMIN: Compress CSS files
         */
        cssmin: {
            installLibCss: {
                options: {
                    compatibility: 'ie8',
                    relativeTo: 'css/',
                    target: 'css/'
                },
                files: {
                    'css/lib.css': [
                        'lib/jquery-ui-1.10.3/jquery-ui.custom.min.css',      // 20 kb
                        'lib/magnific-popup-1.0.0/magnific-popup.css',        //  9 kb
                        'lib/select2-3.5.1/select2.css',                      // 19 kb
                        'lib/jquery-fileupload-5.26/jquery-fileupload-ui.css' //  2 kb
                    ]
                }
            }
        },

        /*
         * UGLIFY: Minify files with UglifyJS
         */
        uglify: {
            prepareLibJs: {
                options: {
                    preserveComments: 'some'
                },
                files: [{
                    expand: true,
                    ext: '.min.js',
                    src: [
                        'lib/bootstrap-file-input/bootstrap-file-input.js',
                        'lib/jquery-cookie-1.4.0/jquery-cookie.js',
                        'lib/jquery-fileupload-5.26/jquery-fileupload.js',
                        'lib/jquery-fileupload-5.26/jquery-iframe-transport.js',
                        'lib/jquery-formatdatetime-1.1.4/jquery-formatdatetime.js',
                        'lib/jquery-hotkeys/jquery-hotkeys.js',
                        'lib/jquery-tagcloud/jquery-tagcloud.js',
                        'lib/jquery-watchchanges/jquery-watchchanges.js'
                    ]
                }]
            },
            installLocaleDatepicker: {
                options: {
                    preserveComments: 'some'
                },
                files: [{
                    expand: true,
                    ext: '.min.js',
                    cwd: 'lib/datepicker',
                    src: '*.js',
                    dest: 'js/locale/datepicker',
                    rename: function (destBase, destPath) {
                        return destBase + '/' + destPath.replace('datepicker-', '').replace('-', '_');
                    }
                }]
            },
            installLocaleMoment: {
                options: {
                    preserveComments: 'some'
                },
                files: [{
                    expand: true,
                    ext: '.min.js',
                    cwd: 'node_modules/moment/locale',
                    src: '*.js',
                    dest: 'js/locale/moment',
                    rename: function (destBase, destPath) {
                        return destBase + '/' + destPath.replace(/([a-z]+)-([a-z]+)/, function (_, a, b) {
                            return a + '_' + b.toUpperCase();
                        });
                    }
                }]
            },
            prepareBootstrapJs: {
                files: {
                    'lib/bootstrap-sass.generated/bootstrap.min.js': [
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/alert.js',
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/button.js',
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/dropdown.js',
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/tab.js',
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/transition.js',
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/modal.js',
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/tooltip.js',
                        'node_modules/bootstrap-sass/assets/javascripts/bootstrap/popover.js'
                    ]
                }
            },
            boltJs: {
                options: {
                    banner: "/**\n" +
                            " * These are Bolt's COMPILED JS files!\n" +
                            " * You can edit files in <js/src/*.js> and run 'grunt' to generate this file.\n" +
                            " */",
                    sourceMap: true
                },
                files: {
                    'js/bolt.min.js': ["<%= filesBoltJs %>"]
                }
            }
        },

        /*
         * JSHINT: Validates files with JSHint
         */
        jshint: {
            boltJs: {
                options: {
                    browser: true,      // Defines globals exposed by modern browsers
                    curly: true,        // Always put curly braces around blocks
                    devel: true,        // Defines globals that are usually used for logging/debugging
                    immed: true,        // Prohibits the use of immediate function invocations without parentheses
                    indent: 4,          // Tab width
                    latedef: true,      // Prohibits the use of a variable before it was defined
                    maxlen: 120,        // Maximum length of a line
                    noarg: true,        // Prohibits the use of arguments.caller and arguments.callee
                    nonbsp: true,       // Warns about "non-breaking whitespace" characters
                    singleGroups: true, // Prohibits the use of the grouping operator for single-expression statements
                    undef: true,        // Prohibits the use of undeclared variables
                    globals: {
                        // Bolt
                        bolt: true,                 // src/console.js
                        FilelistHolder: true,       // src/upload-files.js
                        Files: true,                // src/obj-files.js
                        Folders: true,              // src/obj-folders.js
                        init: true,                 // src/init.js
                        Moments: true,              // src/obj-moments.js
                        Navpopups: true,            // src/obj-navpopups.js
                        Sidebar: true,              // src/obj-sidebar.js
                        Stack: true,                // src/obj-stack.js
                        site: true,                 // src/extend.js/extend.twig
                        baseurl: true,              // src/extend.js/extend.twig
                        rootpath: true,             // src/extend.js/extend.twig
                        // Bolt global functions
                        bindFileUpload: true,       // src/bindfileuploads.js
                        bindGeolocation: true,      // src/geolocation.js
                        bindVideoEmbed: true,       // src/video-embed.js
                        getSelectedItems: true,     // src/fnc-helpers.js
                        makeUri: true,              // src/make-uri-slug.js
                        makeUriAjax: true,          // src/make-uri-slug.js
                        stopMakeUri: true,          // src/make-uri-slug.js
                        updateLatestActivity: true, // src/activity.js
                        validateContent: true,      // src/fnc-helpers.js
                        // Vendor
                        $: true,                    // jQuery
                        _: true,                    // underscore.js
                        Backbone: true,             // backbone.min.js
                        bootbox: true,              // bootbox.min.js
                        CKEDITOR: true,             // ckeditor.js
                        CodeMirror: true,           // ckeditor.js
                        google: true,               // Google
                        jQuery: true,               // jQuery
                        moment: true,               // moment.min.js
                        UAParser: true              // ua-parser.min.js
                    }
                },
                src: ["<%= filesBoltJs %>"]
            }
        },

        /*
         * REMOVE: Remove directory and files
         */
        remove: {
            prepareCkeditor: {
                dirList: [
                    'lib/ckeditor-4.4.7/adapters',
                    'lib/ckeditor-4.4.7/samples'
                ]
            }
        },

        /*
         * BOM: Byte Order Mark (BOM) removal
         */
        bom: {
            prepareCkeditor: {
                src: [
                    'lib/ckeditor-*/*.js',
                    'lib/ckeditor-*/**/*.js'
                ]
            }
        }
    });

    require('load-grunt-tasks')(grunt);

    /*** DEFAULT TASK:  Watches for changes of Bolts own css and js files ***/
    grunt.registerTask(
        'default',
        [
            'watch'
        ]
    );

    /*** UPDATE BOLT TASK:  Creates Bolts own css and js files ***/
    grunt.registerTask(
        'updateBolt',
        [
            'sass:boltCss',
            'eol:boltCss',
            'jshint:boltJs',
            'uglify:boltJs'
        ]
    );

    /*** UPDATE LIB TASK:  Builds library css/js. Run after one of the externals is updated ***/
    grunt.registerTask(
        'updateLib',
        [
            // Prepare
            'uglify:prepareBootstrapJs',        // Concat bootstrap scripts into one minified file
            'uglify:prepareLibJs',              // Create minified versions of library scripts that don't have them
            'remove:prepareCkeditor',           // Remove unneeded direcories from downloaded ckeditor
            'bom:prepareCkeditor',              // Remove unneeded bom from downloaded ckeditor
            // Install
            'copy:installFonts',                // Copies fonts                       => view/fonts/*
            'cssmin:installLibCss',             // Concats and minifies library css   => view/css/lib.css
            'concat:installLibJs',              // Concats minified library scripts   => view/js/lib.min.js
            'uglify:installLocaleDatepicker',   // Copies minified datepicker locale  => view/js/locale/datepicker/*
            'uglify:installLocaleMoment'        // Copies minified moment.js locale   => view/js/locale/datepicker/*
        ]
    );
};
<|endoftext|>


<commit_before>$(function(){
	var postURLs;
	var isFetchingPosts = false;
	var shouldFetchPosts = true;
	var postsToLoad = $(".post-list").children().length/3;
	var loadNewPostsThreshold = 3000;

	// Load the JSON file containing all URLs
	var getJsonRes = function(data){
					postURLs = data["posts"];
					// If there aren't any more posts available to load
					//than already visible, disable fetching
					if (postURLs.length <= postsToLoad)
					  disableFetching();
				};
	$.getJSON('/all-posts.json', getJsonRes);

	// If there's no spinner, it's not a page where posts should be fetched
	if ($(".infinite-spinner").length < 1)
		shouldFetchPosts = false;

	// Are we close to the end of the page? If we are, load more posts
	var scrollAndLoad = function(e){
					if (!shouldFetchPosts || isFetchingPosts) return;
					var windowHeight = $(window).height();
        			var windowScrollPosition = $(window).scrollTop();
        			var bottomScrollPosition = windowHeight + windowScrollPosition;
        			var documentHeight = $(document).height();
					// If we've scrolled past the loadNewPostsThreshold,
					//fetch posts
					if ((documentHeight - loadNewPostsThreshold) < bottomScrollPosition)
						fetchPosts();
				};
	//$(window).scroll(scrollAndLoad);

	//get more button
	$(function(){
		$('#morebtn').click(function() {fetchPosts();});
	});

	// Fetch a chunk of posts
	function fetchPosts() {
		 // Exit if postURLs haven't been loaded
		if (!postURLs) return;
		isFetchingPosts = true;

		// Load as many posts as there were present on the page when it loaded
		// After successfully loading a post, load the next one
		var loadedPosts = 0;
		var postCount = $(".post-list").children().length/3;
		var callback = function() {
					loadedPosts++;
					var postIndex = postCount + loadedPosts;
					if (postIndex > postURLs.length-1) {
						disableFetching();
						return;
					}
					if (loadedPosts < postsToLoad) {
					    fetchPostWithIndex(postIndex, callback);
					} else {
						isFetchingPosts = false;
					}
				};
		fetchPostWithIndex(postCount + loadedPosts, callback);
	}

	function fetchPostWithIndex(index, callback) {
		var postURL = postURLs[index];
		/*var getUrlData = function(data) {
					var postHeading = $(data).find(".post-heading");
					postHeading.appendTo(".post-list");
					callback();
				};*/
		$.get(postURL, getUrlData);
	}

	function getUrlData(data){
		var postHeading = $(data).find(".post-heading");
		postHeading.appendTo(".post-list");
		callback();
	}

	function disableFetching() {
		shouldFetchPosts = false;
		isFetchingPosts = false;
		$(".infinite-spinner").fadeOut();
	}
});<commit_msg>infinite loading<commit_after>$(function(){
	var postURLs;
	var isFetchingPosts = false;
	var shouldFetchPosts = true;
	var postsToLoad = $(".post-list").children().length/3;
	var loadNewPostsThreshold = 3000;

	// Load the JSON file containing all URLs
	var getJsonRes = function(data){
					postURLs = data["posts"];
					// If there aren't any more posts available to load
					//than already visible, disable fetching
					if (postURLs.length <= postsToLoad)
					  disableFetching();
				};
	$.getJSON('/all-posts.json', getJsonRes);

	// If there's no spinner, it's not a page where posts should be fetched
	if ($(".infinite-spinner").length < 1)
		shouldFetchPosts = false;

	// Are we close to the end of the page? If we are, load more posts
	var scrollAndLoad = function(e){
					if (!shouldFetchPosts || isFetchingPosts) return;
					var windowHeight = $(window).height();
        			var windowScrollPosition = $(window).scrollTop();
        			var bottomScrollPosition = windowHeight + windowScrollPosition;
        			var documentHeight = $(document).height();
					// If we've scrolled past the loadNewPostsThreshold,
					//fetch posts
					if ((documentHeight - loadNewPostsThreshold) < bottomScrollPosition)
						fetchPosts();
				};
	//$(window).scroll(scrollAndLoad);

	//get more button
	$(function(){
		$('#morebtn').click(function() {fetchPosts();});
	});

	// Fetch a chunk of posts
	function fetchPosts() {
		 // Exit if postURLs haven't been loaded
		if (!postURLs) return;
		isFetchingPosts = true;

		// Load as many posts as there were present on the page when it loaded
		// After successfully loading a post, load the next one
		var loadedPosts = 0;
		var postCount = $(".post-list").children().length/3;
		var callback = function() {
					loadedPosts++;
					var postIndex = postCount + loadedPosts;
					if (postIndex > postURLs.length-1) {
						disableFetching();
						return;
					}
					if (loadedPosts < postsToLoad) {
					    fetchPostWithIndex(postIndex, callback);
					} else {
						isFetchingPosts = false;
					}
				};
		fetchPostWithIndex(postCount + loadedPosts, callback);
	}

	function fetchPostWithIndex(index, callback) {
		var postURL = postURLs[index];
		var getUrlData = function(data) {
					var postHeading = $(data).find(".post-heading");
					console.log(postHeading);
					postHeading.appendTo(".post-list");
					callback();
				};
		$.get(postURL, getUrlData);
	}

	function disableFetching() {
		shouldFetchPosts = false;
		isFetchingPosts = false;
		$(".infinite-spinner").fadeOut();
	}
});<|endoftext|>


<commit_before>import { should } from 'chai';

should();

describe('Array', function() {
  describe('#indexOf()', function() {
    it('should return -1 when the value is not present', function() {
      [1,2,3].indexOf(5).should.equal(-1);
      [1,2,3].indexOf(0).should.equal(-1);
    });
  });
});<commit_msg>delete unused<commit_after><|endoftext|>


<commit_before>// ==UserScript==
// @name         Slither.io-bot
// @namespace    http://slither.io/
// @version      0.1.4
// @description  Slither.io bot
// @author       Ermiya Eskandary & Théophile Cailliau
// @match        http://slither.io/
// @grant        none
// ==/UserScript==
// Functions needed for the bot
// Set fake mouse coordinates
window.setMouseCoordinates = function (x, y) {
    window.xm = x;
    window.ym = y;
};
// Return the coordinates relative to the center (snake position).
window.mouseRelativeToCenter = function (x, y) {
    mapX = x - getHeight() / 2;
    mapY = y - getWidth() / 2;
    return [mapX, mapY];
};
// Map to mouse coordinates
window.mapToMouse = function (x, y) {
    mouseX = (x - getX()) * gsc;
    mouseY = (y - getY()) * gsc;
    return [mouseX, mouseY];
};
// Canvas width
window.getWidth = function () {
    return window.ww;
};
// Canvas height
window.getHeight = function () {
    return window.hh;
};
// X coordinates on the screen
window.getX = function () {
    return window.px;
};
// Y coordinates on the screen
window.getY = function () {
    return window.py;
};
// Get scaling ratio
window.getScale = function () {
        return window.gsc;
};
var isBotRunning = null;
    // Sets the interval for the bot loop
window.launchBot = function (d) {
    isBotRunning = true;
    window.mousemovelistener = window.onmousemove;
    window.onmousemove = undefined;
    return window.botInterval = setInterval(window.loop, d);
};

window.stopBot = function () {
    window.onmousemove = window.mousemovelistener;
    isBotRunning = false;
    return clearInterval(window.botInterval);
};

document.oldKeyDown = document.onkeydown;
document.onkeydown = function (e) {
    document.oldKeyDown(e);
    if(e.keyCode === 84) isBotRunning ? window.stopBot() : window.launchBot(5);
};

// Sorting function, from property 'distance'
window.sortFood = function (a, b) {
    return a.distance - b.distance;
};

// Given an object (of which properties xx and yy are not null), return the object with an additional property 'distance'
window.getDistanceFromMe = function (point) {
    if (point === null) return null;
    point.distance = getDistance(px, py, point.xx, point.yy);
    return point;
};

// Get a distance from point (x1; y1) to point (x2; y2).
window.getDistance = function (x1, y1, x2, y2) {
    // Calculate the vector coordinates.
    var xDistance = (x1 - x2);
    var yDistance = (y1 - y2);
    // Get the absolute value of each coordinate
    xDistance = xDistance < 0 ? xDistance * -1 : xDistance;
    yDistance = yDistance < 0 ? yDistance * -1 : yDistance;
    //Add the coordinates of the vector to get a distance. Not the real distance, but reliable for distance comparison.
    var distance = Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
    return distance;
};
// Sort food based on distance
window.getSortedFood = function () {
    return window.foods.filter(function (val) {
        return val !== null;
    }).map(getDistanceFromMe).sort(sortFood);
};

/*
window.isInFoods = function (foodObject) {
    return (foodObject === null) ? false : (window.foods.indexOf(foodObject) >= 0);
};

window.currentFood = null;
window.sortedFood = getSortedFood();
window.loop = function () {
    if (!isInFoods(currentFood)) {
        window.sortedFood = getSortedFood();
        window.currentFood = sortedFood[0];
        var coordinatesOfClosestFood = window.mapToMouse(window.sortedFood[0].xx, window.sortedFood[0].yy);
        window.setMouseCoordinates(coordinatesOfClosestFood[0], coordinatesOfClosestFood[1]);
    }
};
*/
// Removed the onemousemove listener so we can move the snake manually by setting coordinates
window.onmousemove = function (e) {
    /*if (e = e || window.event) {
      if ("undefined" != typeof e.clientX) {
        xm = e.clientX - ww / 2;
        ym = e.clientY - hh / 2;
      }
    }*/
};
// Actual bot code

// Loop for running the bot
window.loop = function () {
        // If the game is running
        if (playing) {
            // Sort the food based on distance
            var sortedFood = getSortedFood();
            // Convert coordinates of the closest food using mapToMouse
            var coordinatesOfClosestFood = window.mapToMouse(sortedFood[0].xx, sortedFood[0].yy);
            // Set the mouse coordinates to the coordinates of the closest food
            window.setMouseCoordinates(coordinatesOfClosestFood[0], coordinatesOfClosestFood[1]);

        }
    };
    // Start the bot
window.launchBot(5);
<commit_msg>Console log<commit_after>// ==UserScript==
// @name         Slither.io-bot
// @namespace    http://slither.io/
// @version      0.1.4
// @description  Slither.io bot
// @author       Ermiya Eskandary & Théophile Cailliau
// @match        http://slither.io/
// @grant        none
// ==/UserScript==
// Functions needed for the bot
// Set fake mouse coordinates
window.setMouseCoordinates = function (x, y) {
    window.xm = x;
    window.ym = y;
};
// Return the coordinates relative to the center (snake position).
window.mouseRelativeToCenter = function (x, y) {
    mapX = x - getHeight() / 2;
    mapY = y - getWidth() / 2;
    return [mapX, mapY];
};
// Map to mouse coordinates
window.mapToMouse = function (x, y) {
    mouseX = (x - getX()) * gsc;
    mouseY = (y - getY()) * gsc;
    return [mouseX, mouseY];
};
// Canvas width
window.getWidth = function () {
    return window.ww;
};
// Canvas height
window.getHeight = function () {
    return window.hh;
};
// X coordinates on the screen
window.getX = function () {
    return window.px;
};
// Y coordinates on the screen
window.getY = function () {
    return window.py;
};
// Get scaling ratio
window.getScale = function () {
        return window.gsc;
};
var isBotRunning = null;
    // Sets the interval for the bot loop
window.launchBot = function (d) {
    console.log("Starting Bot.");
    isBotRunning = true;
    window.mousemovelistener = window.onmousemove;
    window.onmousemove = undefined;
    return window.botInterval = setInterval(window.loop, d);
};

window.stopBot = function () {
    console.log("Stopping Bot.");
    window.onmousemove = window.mousemovelistener;
    isBotRunning = false;
    return clearInterval(window.botInterval);
};

document.oldKeyDown = document.onkeydown;
document.onkeydown = function (e) {
    document.oldKeyDown(e);
    if(e.keyCode === 84) isBotRunning ? window.stopBot() : window.launchBot(5);
};

// Sorting function, from property 'distance'
window.sortFood = function (a, b) {
    return a.distance - b.distance;
};

// Given an object (of which properties xx and yy are not null), return the object with an additional property 'distance'
window.getDistanceFromMe = function (point) {
    if (point === null) return null;
    point.distance = getDistance(px, py, point.xx, point.yy);
    return point;
};

// Get a distance from point (x1; y1) to point (x2; y2).
window.getDistance = function (x1, y1, x2, y2) {
    // Calculate the vector coordinates.
    var xDistance = (x1 - x2);
    var yDistance = (y1 - y2);
    // Get the absolute value of each coordinate
    xDistance = xDistance < 0 ? xDistance * -1 : xDistance;
    yDistance = yDistance < 0 ? yDistance * -1 : yDistance;
    //Add the coordinates of the vector to get a distance. Not the real distance, but reliable for distance comparison.
    var distance = Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
    return distance;
};
// Sort food based on distance
window.getSortedFood = function () {
    return window.foods.filter(function (val) {
        return val !== null;
    }).map(getDistanceFromMe).sort(sortFood);
};

/*
window.isInFoods = function (foodObject) {
    return (foodObject === null) ? false : (window.foods.indexOf(foodObject) >= 0);
};

window.currentFood = null;
window.sortedFood = getSortedFood();
window.loop = function () {
    if (!isInFoods(currentFood)) {
        window.sortedFood = getSortedFood();
        window.currentFood = sortedFood[0];
        var coordinatesOfClosestFood = window.mapToMouse(window.sortedFood[0].xx, window.sortedFood[0].yy);
        window.setMouseCoordinates(coordinatesOfClosestFood[0], coordinatesOfClosestFood[1]);
    }
};
*/
// Removed the onemousemove listener so we can move the snake manually by setting coordinates
window.onmousemove = function (e) {
    /*if (e = e || window.event) {
      if ("undefined" != typeof e.clientX) {
        xm = e.clientX - ww / 2;
        ym = e.clientY - hh / 2;
      }
    }*/
};
// Actual bot code

// Loop for running the bot
window.loop = function () {
        // If the game is running
        if (playing) {
            // Sort the food based on distance
            var sortedFood = getSortedFood();
            // Convert coordinates of the closest food using mapToMouse
            var coordinatesOfClosestFood = window.mapToMouse(sortedFood[0].xx, sortedFood[0].yy);
            // Set the mouse coordinates to the coordinates of the closest food
            window.setMouseCoordinates(coordinatesOfClosestFood[0], coordinatesOfClosestFood[1]);

        }
    };
    // Start the bot
window.launchBot(5);
<|endoftext|>


<commit_before>//Module
angular.module('myApp', ['ui-deni-grid']);

//Controller
angular.module('myApp').controller('ExampleCtrl', function($scope, $http) {

    $scope.gridOptions = {
        url: 'https://denimar.github.io/static-data/employees/01000.json',
        columns: [{
            header: 'Name',
            name: 'name',
            width: '50%',
        }, {
            header: 'Age',
            name: 'age',
            width: '10%',
            align: 'right'
        }, {
            header: 'Gender',
            name: 'gender',
            width: '30%',
        }, {
            width: '5%',
            action: {
                icon: 'https://denimar.github.io/ui-deni-grid/examples/images/edit.png',
                tooltip: 'Edit that employee...',
                fn: function(record) {
                    alert('Editing user "' + record.name + '"...');
                }
            }
        }, {
            width: '5%',
            action: {
                icon: 'https://denimar.github.io/ui-deni-grid/examples/images/delete.png',
                tooltip: 'Delete that employee...',
                fn: function(record) {
                    alert('Deleting user "' + record.name + '"...');
                }
            }
        }, ]
    };

});
<commit_msg>Fixing Scrutinizer...<commit_after>//Module
angular.module('myApp', ['ui-deni-grid']);

//Controller
angular.module('myApp').controller('ExampleCtrl', function($scope) {

    $scope.gridOptions = {
        url: 'https://denimar.github.io/static-data/employees/01000.json',
        columns: [{
            header: 'Name',
            name: 'name',
            width: '50%',
        }, {
            header: 'Age',
            name: 'age',
            width: '10%',
            align: 'right'
        }, {
            header: 'Gender',
            name: 'gender',
            width: '30%',
        }, {
            width: '5%',
            action: {
                icon: 'https://denimar.github.io/ui-deni-grid/examples/images/edit.png',
                tooltip: 'Edit that employee...',
                fn: function(record) {
                    alert('Editing user "' + record.name + '"...');
                }
            }
        }, {
            width: '5%',
            action: {
                icon: 'https://denimar.github.io/ui-deni-grid/examples/images/delete.png',
                tooltip: 'Delete that employee...',
                fn: function(record) {
                    alert('Deleting user "' + record.name + '"...');
                }
            }
        }, ]
    };

});
<|endoftext|>


<commit_before>module.exports = {
	plugins: [
		`gatsby-plugin-react-helmet`,
		`gatsby-plugin-sass`,
		`gatsby-transformer-sharp`,
		`gatsby-plugin-sharp`,
		`gatsby-plugin-styled-components`,
		{
			resolve: `gatsby-source-filesystem`,
			options: {
				name: `blog`,
				path: `${__dirname}/blog`,
			},
		},
		{
			resolve: `gatsby-source-filesystem`,
			options: {
				name: `projects`,
				path: `${__dirname}/projects`,
			},
		},
		{
			resolve: `gatsby-transformer-remark`,
			options: {
				plugins: [
					`gatsby-remark-prismjs`,
					`gatsby-remark-responsive-iframe`,
					`gatsby-remark-copy-linked-files`,
					`gatsby-remark-external-links`,
					{
						resolve: `gatsby-remark-images`,
						options: {
							maxWidth: 960,
							linkImagesToOriginal: false,
							quality: 100,
						},
					},
				],
			},
		},
	],
}
<commit_msg>fixing gatsby config<commit_after>module.exports = {
	plugins: [
		`gatsby-plugin-react-helmet`,
		`gatsby-plugin-sass`,
		`gatsby-transformer-sharp`,
		`gatsby-plugin-sharp`,
		`gatsby-plugin-styled-components`,
		{
			resolve: `gatsby-source-filesystem`,
			options: {
				name: `blog`,
				path: `${__dirname}/blog`,
			},
		},
		{
			resolve: `gatsby-transformer-remark`,
			options: {
				plugins: [
					`gatsby-remark-prismjs`,
					`gatsby-remark-responsive-iframe`,
					`gatsby-remark-copy-linked-files`,
					`gatsby-remark-external-links`,
					{
						resolve: `gatsby-remark-images`,
						options: {
							maxWidth: 960,
							linkImagesToOriginal: false,
							quality: 100,
						},
					},
				],
			},
		},
	],
}
<|endoftext|>