<commit_before>/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* globals PDFView, scrollIntoView */

'use strict';

var DELAY_BEFORE_HIDING_CONTROLS = 3000; // in ms
var SELECTOR = 'presentationControls';

var PresentationMode = {
  active: false,
  args: null,
  contextMenuOpen: false,
//#if (GENERIC || CHROME)
  prevCoords: { x: null, y: null },
//#endif

  initialize: function presentationModeInitialize(options) {
    this.container = options.container;
    this.secondaryToolbar = options.secondaryToolbar;

    this.firstPage = options.firstPage;
    this.lastPage = options.lastPage;
    this.pageRotateCw = options.pageRotateCw;
    this.pageRotateCcw = options.pageRotateCcw;

    this.firstPage.addEventListener('click', function() {
      this.contextMenuOpen = false;
      this.secondaryToolbar.firstPageClick();
    }.bind(this));
    this.lastPage.addEventListener('click', function() {
      this.contextMenuOpen = false;
      this.secondaryToolbar.lastPageClick();
    }.bind(this));

    this.pageRotateCw.addEventListener('click', function() {
      this.contextMenuOpen = false;
      this.secondaryToolbar.pageRotateCwClick();
    }.bind(this));
    this.pageRotateCcw.addEventListener('click', function() {
      this.contextMenuOpen = false;
      this.secondaryToolbar.pageRotateCcwClick();
    }.bind(this));
  },

  get isFullscreen() {
    return (document.fullscreenElement ||
            document.mozFullScreen ||
            document.webkitIsFullScreen ||
            document.msFullscreenElement);
  },

  request: function presentationModeRequest() {
    if (!PDFView.supportsFullscreen || this.isFullscreen) {
      return false;
    }

    if (this.container.requestFullscreen) {
      this.container.requestFullscreen();
    } else if (this.container.mozRequestFullScreen) {
      this.container.mozRequestFullScreen();
    } else if (this.container.webkitRequestFullScreen) {
      this.container.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
    } else if (this.container.msRequestFullscreen) {
      this.container.msRequestFullscreen();
    } else {
      return false;
    }

    this.args = {
      page: PDFView.page,
      previousScale: PDFView.currentScaleValue
    };

    return true;
  },

  enter: function presentationModeEnter() {
    this.active = true;

    PDFView.page = this.args.page;
    PDFView.setScale('page-fit', true);

    window.addEventListener('mousemove', this.mouseMove, false);
    window.addEventListener('mousedown', this.mouseDown, false);
    window.addEventListener('contextmenu', this.contextMenu, false);

    this.showControls();
    this.contextMenuOpen = false;
    this.container.setAttribute('contextmenu', 'viewerContextMenu');
  },

  exit: function presentationModeExit() {
    this.active = false;

    var page = PDFView.page;
    PDFView.setScale(this.args.previousScale);
    PDFView.page = page;

    window.removeEventListener('mousemove', this.mouseMove, false);
    window.removeEventListener('mousedown', this.mouseDown, false);
    window.removeEventListener('contextmenu', this.contextMenu, false);

    this.hideControls();
    this.args = null;
    PDFView.clearMouseScrollState();
    this.container.removeAttribute('contextmenu');
    this.contextMenuOpen = false;

    // Ensure that the thumbnail of the current page is visible
    // when exiting presentation mode.
    scrollIntoView(document.getElementById('thumbnailContainer' + page));
  },

  showControls: function presentationModeShowControls() {
    if (this.controlsTimeout) {
      clearTimeout(this.controlsTimeout);
    } else {
      this.container.classList.add(SELECTOR);
    }
    this.controlsTimeout = setTimeout(function hideControlsTimeout() {
      this.container.classList.remove(SELECTOR);
      delete this.controlsTimeout;
    }.bind(this), DELAY_BEFORE_HIDING_CONTROLS);
  },

  hideControls: function presentationModeHideControls() {
    if (!this.controlsTimeout) {
      return;
    }
    this.container.classList.remove(SELECTOR);
    clearTimeout(this.controlsTimeout);
    delete this.controlsTimeout;
  },

  mouseMove: function presentationModeMouseMove(evt) {
//#if (GENERIC || CHROME)
    // Workaround for a bug in WebKit browsers that causes the 'mousemove' event
    // to be fired when the cursor is changed. For details, see:
    // http://code.google.com/p/chromium/issues/detail?id=103041.

    var currCoords = { x: evt.clientX, y: evt.clientY };
    var prevCoords = PresentationMode.prevCoords;
    PresentationMode.prevCoords = currCoords;

    if (currCoords.x === prevCoords.x && currCoords.y === prevCoords.y) {
      return;
    }
//#endif
    PresentationMode.showControls();
  },

  mouseDown: function presentationModeMouseDown(evt) {
    var self = PresentationMode;
    if (self.contextMenuOpen) {
      self.contextMenuOpen = false;
      evt.preventDefault();
      return;
    }

    if (evt.button === 0) {
      // Enable clicking of links in presentation mode. Please note:
      // Only links pointing to destinations in the current PDF document work.
      var isInternalLink = (evt.target.href &&
                            evt.target.classList.contains('internalLink'));
      if (!isInternalLink) {
        // Unless an internal link was clicked, advance one page.
        evt.preventDefault();
        PDFView.page += (evt.shiftKey ? -1 : 1);
      }
    }
  },

  contextMenu: function presentationModeContextMenu(evt) {
    PresentationMode.contextMenuOpen = true;
  }
};

(function presentationModeClosure() {
  function presentationModeChange(e) {
    if (PresentationMode.isFullscreen) {
      PresentationMode.enter();
    } else {
      PresentationMode.exit();
    }
  }

  window.addEventListener('fullscreenchange', presentationModeChange, false);
  window.addEventListener('mozfullscreenchange', presentationModeChange, false);
  window.addEventListener('webkitfullscreenchange', presentationModeChange,
                          false);
  window.addEventListener('MSFullscreenChange', presentationModeChange, false);
})();
<commit_msg>Disable Presentation Mode until the document has started rendering<commit_after>/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* globals PDFView, scrollIntoView */

'use strict';

var DELAY_BEFORE_HIDING_CONTROLS = 3000; // in ms
var SELECTOR = 'presentationControls';

var PresentationMode = {
  active: false,
  args: null,
  contextMenuOpen: false,
//#if (GENERIC || CHROME)
  prevCoords: { x: null, y: null },
//#endif

  initialize: function presentationModeInitialize(options) {
    this.container = options.container;
    this.secondaryToolbar = options.secondaryToolbar;

    this.viewer = this.container.firstElementChild;

    this.firstPage = options.firstPage;
    this.lastPage = options.lastPage;
    this.pageRotateCw = options.pageRotateCw;
    this.pageRotateCcw = options.pageRotateCcw;

    this.firstPage.addEventListener('click', function() {
      this.contextMenuOpen = false;
      this.secondaryToolbar.firstPageClick();
    }.bind(this));
    this.lastPage.addEventListener('click', function() {
      this.contextMenuOpen = false;
      this.secondaryToolbar.lastPageClick();
    }.bind(this));

    this.pageRotateCw.addEventListener('click', function() {
      this.contextMenuOpen = false;
      this.secondaryToolbar.pageRotateCwClick();
    }.bind(this));
    this.pageRotateCcw.addEventListener('click', function() {
      this.contextMenuOpen = false;
      this.secondaryToolbar.pageRotateCcwClick();
    }.bind(this));
  },

  get isFullscreen() {
    return (document.fullscreenElement ||
            document.mozFullScreen ||
            document.webkitIsFullScreen ||
            document.msFullscreenElement);
  },

  request: function presentationModeRequest() {
    if (!PDFView.supportsFullscreen || this.isFullscreen ||
        !this.viewer.hasChildNodes()) {
      return false;
    }

    if (this.container.requestFullscreen) {
      this.container.requestFullscreen();
    } else if (this.container.mozRequestFullScreen) {
      this.container.mozRequestFullScreen();
    } else if (this.container.webkitRequestFullScreen) {
      this.container.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
    } else if (this.container.msRequestFullscreen) {
      this.container.msRequestFullscreen();
    } else {
      return false;
    }

    this.args = {
      page: PDFView.page,
      previousScale: PDFView.currentScaleValue
    };

    return true;
  },

  enter: function presentationModeEnter() {
    this.active = true;

    PDFView.page = this.args.page;
    PDFView.setScale('page-fit', true);

    window.addEventListener('mousemove', this.mouseMove, false);
    window.addEventListener('mousedown', this.mouseDown, false);
    window.addEventListener('contextmenu', this.contextMenu, false);

    this.showControls();
    this.contextMenuOpen = false;
    this.container.setAttribute('contextmenu', 'viewerContextMenu');
  },

  exit: function presentationModeExit() {
    this.active = false;

    var page = PDFView.page;
    PDFView.setScale(this.args.previousScale);
    PDFView.page = page;

    window.removeEventListener('mousemove', this.mouseMove, false);
    window.removeEventListener('mousedown', this.mouseDown, false);
    window.removeEventListener('contextmenu', this.contextMenu, false);

    this.hideControls();
    this.args = null;
    PDFView.clearMouseScrollState();
    this.container.removeAttribute('contextmenu');
    this.contextMenuOpen = false;

    // Ensure that the thumbnail of the current page is visible
    // when exiting presentation mode.
    scrollIntoView(document.getElementById('thumbnailContainer' + page));
  },

  showControls: function presentationModeShowControls() {
    if (this.controlsTimeout) {
      clearTimeout(this.controlsTimeout);
    } else {
      this.container.classList.add(SELECTOR);
    }
    this.controlsTimeout = setTimeout(function hideControlsTimeout() {
      this.container.classList.remove(SELECTOR);
      delete this.controlsTimeout;
    }.bind(this), DELAY_BEFORE_HIDING_CONTROLS);
  },

  hideControls: function presentationModeHideControls() {
    if (!this.controlsTimeout) {
      return;
    }
    this.container.classList.remove(SELECTOR);
    clearTimeout(this.controlsTimeout);
    delete this.controlsTimeout;
  },

  mouseMove: function presentationModeMouseMove(evt) {
//#if (GENERIC || CHROME)
    // Workaround for a bug in WebKit browsers that causes the 'mousemove' event
    // to be fired when the cursor is changed. For details, see:
    // http://code.google.com/p/chromium/issues/detail?id=103041.

    var currCoords = { x: evt.clientX, y: evt.clientY };
    var prevCoords = PresentationMode.prevCoords;
    PresentationMode.prevCoords = currCoords;

    if (currCoords.x === prevCoords.x && currCoords.y === prevCoords.y) {
      return;
    }
//#endif
    PresentationMode.showControls();
  },

  mouseDown: function presentationModeMouseDown(evt) {
    var self = PresentationMode;
    if (self.contextMenuOpen) {
      self.contextMenuOpen = false;
      evt.preventDefault();
      return;
    }

    if (evt.button === 0) {
      // Enable clicking of links in presentation mode. Please note:
      // Only links pointing to destinations in the current PDF document work.
      var isInternalLink = (evt.target.href &&
                            evt.target.classList.contains('internalLink'));
      if (!isInternalLink) {
        // Unless an internal link was clicked, advance one page.
        evt.preventDefault();
        PDFView.page += (evt.shiftKey ? -1 : 1);
      }
    }
  },

  contextMenu: function presentationModeContextMenu(evt) {
    PresentationMode.contextMenuOpen = true;
  }
};

(function presentationModeClosure() {
  function presentationModeChange(e) {
    if (PresentationMode.isFullscreen) {
      PresentationMode.enter();
    } else {
      PresentationMode.exit();
    }
  }

  window.addEventListener('fullscreenchange', presentationModeChange, false);
  window.addEventListener('mozfullscreenchange', presentationModeChange, false);
  window.addEventListener('webkitfullscreenchange', presentationModeChange,
                          false);
  window.addEventListener('MSFullscreenChange', presentationModeChange, false);
})();
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Slither.io-bot
// @namespace    http://slither.io/
// @version      0.3.0
// @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.logDebugging = false;

window.log = function () {
    if (window.logDebugging === true) {
        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;
};
// Return the 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] - window.csc * parseInt(window.mc.style.left);
    var canvasY = window.csc * y * window.canvasRatio[1] - window.csc * 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 snake.xx;
};
// Y coordinates on the screen
window.getY = function () {
    return snake.yy;
};
window.onresize = function () {
    window.resize();
    window.canvasRatio = [window.mc.height / window.getHeight(), window.mc.width / window.getWidth()];
};
window.setZoom = function (e) {
    if (window.gsc) {
        window.gsc *= Math.pow(0.9, e.wheelDelta / -120 || e.detail / 2 || 0);
    }
};

// Overlays
window.position_overlay;
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');

document.body.addEventListener('mousewheel', window.setZoom);
document.body.addEventListener('DOMMouseScroll', window.setZoom);

// Get scaling ratio
window.getScale = function () {
    return window.gsc;
};

window.isBotRunning = false;
window.isBotEnabled = true;

// 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 onemousemove 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);
};

window.connectBot = function () {
    window.stopBot();
    window.log('Connecting...');
    window.connect();
    window.botCanStart = setInterval(function () {
        if (window.playing) {
            window.launchBot(5);
            clearInterval(window.botCanStart);
        }
    }, 100);
};

// 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);
    // If the letter 't' is pressed, check if the bot is running. If it is, stop the bot. If it isn't, start the bot.
    if (e.keyCode === 84) {
        if (window.isBotRunning) {
            window.stopBot();
            window.isBotEnabled = false;
        } else {
            window.launchBot(5);
            window.isBotEnabled = true;
        }
    }
};

// Sorting function, from property 'distance'
window.sortObjects = 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 = 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;
    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.sortObjects);
};

// 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.sortObjects);
};

// 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();
};

// 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();
};

window.oldOef = window.oef;

window.oef = function () {
    window.oldOef();
    window.onFrameUpdate();
};

window.canvasRatio = [window.mc.height / window.getHeight(), window.mc.width / window.getWidth()];
window.onFrameUpdate = function () {
    if (window.playing && window.isBotRunning) {
        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 < window.sortedFood.length; 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');
        }
    }
};

/*
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]);
    }
};
*/
// Actual bot code

// Loop for running the bot
window.loop = function () {
    // If the game and the bot are running
    if (window.playing && window.isBotEnabled) {
        // 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: ' + (~~snake.xx || 0) + ' Y: ' + (~~snake.yy || 0);
        }
        // Sort the food and enemies based on their distance relative to player's snake
        window.sortedFood = window.getSortedFood();
        window.sortedEnemies = window.getSortedEnemies();
        // Take the closest of each
        window.closestEnemy = window.sortedEnemies[0];
        window.currentFood = window.sortedFood[0];
        // Convert coordinates of the closest food using mapToMouse
        var coordinatesOfClosestFood = window.mapToMouse(window.currentFood.xx, window.currentFood.yy);
        if (window.closestEnemy.distance < 300) {
            window.log('close enemy! (distance = ' + window.closestEnemy.distance);
            // !handle close enemies!
        }
        // 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.stopBot();
    }
};

window.startInterval = function () {
    if (window.playing === false && window.isBotEnabled === true) {
        window.connectBot();
        clearInterval(window.startInterval);
    }
};
window.startInterval();
<commit_msg>Increased Versionnumber<commit_after>// ==UserScript==
// @name         Slither.io-bot
// @namespace    http://slither.io/
// @version      0.3.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.logDebugging = false;

window.log = function () {
    if (window.logDebugging === true) {
        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;
};
// Return the 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] - window.csc * parseInt(window.mc.style.left);
    var canvasY = window.csc * y * window.canvasRatio[1] - window.csc * 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 snake.xx;
};
// Y coordinates on the screen
window.getY = function () {
    return snake.yy;
};
window.onresize = function () {
    window.resize();
    window.canvasRatio = [window.mc.height / window.getHeight(), window.mc.width / window.getWidth()];
};
window.setZoom = function (e) {
    if (window.gsc) {
        window.gsc *= Math.pow(0.9, e.wheelDelta / -120 || e.detail / 2 || 0);
    }
};

// Overlays
window.position_overlay;
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');

document.body.addEventListener('mousewheel', window.setZoom);
document.body.addEventListener('DOMMouseScroll', window.setZoom);

// Get scaling ratio
window.getScale = function () {
    return window.gsc;
};

window.isBotRunning = false;
window.isBotEnabled = true;

// 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 onemousemove 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);
};

window.connectBot = function () {
    window.stopBot();
    window.log('Connecting...');
    window.connect();
    window.botCanStart = setInterval(function () {
        if (window.playing) {
            window.launchBot(5);
            clearInterval(window.botCanStart);
        }
    }, 100);
};

// 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);
    // If the letter 't' is pressed, check if the bot is running. If it is, stop the bot. If it isn't, start the bot.
    if (e.keyCode === 84) {
        if (window.isBotRunning) {
            window.stopBot();
            window.isBotEnabled = false;
        } else {
            window.launchBot(5);
            window.isBotEnabled = true;
        }
    }
};

// Sorting function, from property 'distance'
window.sortObjects = 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 = 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;
    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.sortObjects);
};

// 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.sortObjects);
};

// 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();
};

// 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();
};

window.oldOef = window.oef;

window.oef = function () {
    window.oldOef();
    window.onFrameUpdate();
};

window.canvasRatio = [window.mc.height / window.getHeight(), window.mc.width / window.getWidth()];
window.onFrameUpdate = function () {
    if (window.playing && window.isBotRunning) {
        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 < window.sortedFood.length; 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');
        }
    }
};

/*
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]);
    }
};
*/
// Actual bot code

// Loop for running the bot
window.loop = function () {
    // If the game and the bot are running
    if (window.playing && window.isBotEnabled) {
        // 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: ' + (~~snake.xx || 0) + ' Y: ' + (~~snake.yy || 0);
        }
        // Sort the food and enemies based on their distance relative to player's snake
        window.sortedFood = window.getSortedFood();
        window.sortedEnemies = window.getSortedEnemies();
        // Take the closest of each
        window.closestEnemy = window.sortedEnemies[0];
        window.currentFood = window.sortedFood[0];
        // Convert coordinates of the closest food using mapToMouse
        var coordinatesOfClosestFood = window.mapToMouse(window.currentFood.xx, window.currentFood.yy);
        if (window.closestEnemy.distance < 300) {
            window.log('close enemy! (distance = ' + window.closestEnemy.distance);
            // !handle close enemies!
        }
        // 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.stopBot();
    }
};

window.startInterval = function () {
    if (window.playing === false && window.isBotEnabled === true) {
        window.connectBot();
        clearInterval(window.startInterval);
    }
};
window.startInterval();
<|endoftext|>


<commit_before>'use strict';

const fs = require('fs');
const path = require('path');

const ROOMFAQ_FILE = path.resolve(__dirname, '../config/chat-plugins/faqs.json');
const ALLOWED_HTML = ['a', 'font', 'i', 'u', 'b', 'strong', 'em', 'small', 'sub', 'sup', 'ins', 'del'];

let roomFaqs = {};
try {
	roomFaqs = require(ROOMFAQ_FILE);
} catch (e) {
	if (e.code !== 'MODULE_NOT_FOUND') throw e;
}
if (!roomFaqs || typeof roomFaqs !== 'object') roomFaqs = {};

function saveRoomFaqs() {
	fs.writeFileSync(ROOMFAQ_FILE, JSON.stringify(roomFaqs));
}

// Aliases are implemented as a "regular" FAQ entry starting with a >. EX: {a: "text", b: ">a"}
// This is done to allow easy checking whether a key is associated with a value or alias as well as preserve backwards compatibility.
function getAlias(roomid, key) {
	if (!roomFaqs[roomid]) return false;
	let value = roomFaqs[roomid][key];
	if (value && value[0] === '>') return value.substr(1);
	return false;
}

exports.commands = {
	addfaq: function (target, room, user) {
		if (!this.canTalk()) return this.errorReply("You cannot do this while unable to talk.");
		if (!this.can('declare', null, room)) return false;
		if (!room.chatRoomData) return this.errorReply("This command is unavailable in temporary rooms.");
		let [topic, ...text] = target.split(',');

		topic = toId(topic);
		if (!(topic && text.length)) return this.parse('/help roomfaq');
		text = text.join(',').trim();
		if (topic.length > 25) return this.errorReply("FAQ topics should not exceed 25 characters.");
		if (text.length > 500) return this.errorReply("FAQ entries should not exceed 500 characters.");

		text = text.replace(/^>/, '>');

		let htmltags = text.toLowerCase().match(/<\/?(\w+)\b/g);
		if (htmltags && htmltags.some(val => !ALLOWED_HTML.includes(toId(val)))) {
			let tagList = ALLOWED_HTML.map(tag => `<${tag}>`).join(', ');
			return this.errorReply(`Disallowed HTML tags found. Allowed html tags: ${tagList}`);
		}

		text = this.canHTML(text);
		if (!text) return;

		if (!roomFaqs[room.id]) roomFaqs[room.id] = {};
		roomFaqs[room.id][topic] = text;
		saveRoomFaqs();
		this.sendReplyBox(text);
		this.privateModCommand(`(${user.name} added a FAQ for '${topic}')`);
	},
	removefaq: function (target, room, user) {
		if (!this.canTalk()) return this.errorReply("You cannot do this while unable to talk.");
		if (!this.can('declare', null, room)) return false;
		if (!room.chatRoomData) return this.errorReply("This command is unavailable in temporary rooms.");
		let topic = toId(target);
		if (!topic) return this.parse('/help roomfaq');

		if (!(roomFaqs[room.id] && roomFaqs[room.id][topic])) return this.errorReply("Invalid topic.");
		delete roomFaqs[room.id][topic];
		Object.keys(roomFaqs[room.id]).filter(val => getAlias(room.id, val) === topic).map(val => delete roomFaqs[room.id][val]);
		if (!Object.keys(roomFaqs[room.id]).length) delete roomFaqs[room.id];
		saveRoomFaqs();
		this.privateModCommand(`(${user.name} removed the FAQ for '${topic}')`);
	},
	addalias: function (target, room, user) {
		if (!this.canTalk()) return this.errorReply("You cannot do this while unable to talk.");
		if (!this.can('declare', null, room)) return false;
		if (!room.chatRoomData) return this.errorReply("This command is unavailable in temporary rooms.");
		let [alias, topic] = target.split(',').map(val => toId(val));

		if (!(alias && topic)) return this.parse('/help roomfaq');
		if (alias.length > 25) return this.errorReply("FAQ topics should not exceed 25 characters.");

		if (!(roomFaqs[room.id] && topic in roomFaqs[room.id])) return this.errorReply(`The topic ${topic} was not found in this room's faq list.`);
		if (getAlias(room.id, topic)) return this.errorReply(`You cannot make an alias of an alias. Use /addalias ${alias}, ${getAlias(room.id, topic)} instead.`);
		roomFaqs[room.id][alias] = `>${topic}`;
		saveRoomFaqs();
		this.privateModCommand(`(${user.name} added an alias for '${topic}: ${alias}')`);
	},
	roomfaq: function (target, room, user) {
		if (!roomFaqs[room.id]) return this.errorReply("This room has no FAQ topics.");
		let topic = toId(target);
		if (topic === 'constructor') return false;
		if (!topic) return this.sendReplyBox(`List of topics in this room: ${Object.keys(roomFaqs[room.id]).filter(val => !getAlias(room.id, val)).join(', ')}`);
		if (!roomFaqs[room.id][topic]) return this.errorReply("Invalid topic.");
		topic = getAlias(room.id, topic) || topic;

		if (!this.runBroadcast()) return;
		this.sendReplyBox(roomFaqs[room.id][topic]);
		if (!this.broadcasting && user.can('declare', null, room)) this.sendReplyBox('/addfaq ' + topic + ', ' + Chat.escapeHTML(roomFaqs[room.id][topic]) + '');
	},
	roomfaqhelp: [
		"/roomfaq - Shows the list of all available FAQ topics",
		"/roomfaq <topic> - Shows the FAQ for <topic>.",
		"/addfaq <topic>, <text> - Adds an entry for <topic> in this room or updates it. Requires: # & ~",
		"/addalias <alias>, <topic> - Adds <alias> as an alias for <topic>, displaying it when users use /roomfaq <alias>. Requires: # & ~",
		"/removefaq <topic> - Removes the entry for <topic> in this room. If used on an alias, removes the alias. Requires: # & ~",
	],
};
<commit_msg>FAQs: allow <commit_after>'use strict';

const fs = require('fs');
const path = require('path');

const ROOMFAQ_FILE = path.resolve(__dirname, '../config/chat-plugins/faqs.json');
const ALLOWED_HTML = ['a', 'font', 'i', 'u', 'b', 'strong', 'em', 'small', 'sub', 'sup', 'ins', 'del', 'code'];

let roomFaqs = {};
try {
	roomFaqs = require(ROOMFAQ_FILE);
} catch (e) {
	if (e.code !== 'MODULE_NOT_FOUND') throw e;
}
if (!roomFaqs || typeof roomFaqs !== 'object') roomFaqs = {};

function saveRoomFaqs() {
	fs.writeFileSync(ROOMFAQ_FILE, JSON.stringify(roomFaqs));
}

// Aliases are implemented as a "regular" FAQ entry starting with a >. EX: {a: "text", b: ">a"}
// This is done to allow easy checking whether a key is associated with a value or alias as well as preserve backwards compatibility.
function getAlias(roomid, key) {
	if (!roomFaqs[roomid]) return false;
	let value = roomFaqs[roomid][key];
	if (value && value[0] === '>') return value.substr(1);
	return false;
}

exports.commands = {
	addfaq: function (target, room, user) {
		if (!this.canTalk()) return this.errorReply("You cannot do this while unable to talk.");
		if (!this.can('declare', null, room)) return false;
		if (!room.chatRoomData) return this.errorReply("This command is unavailable in temporary rooms.");
		let [topic, ...text] = target.split(',');

		topic = toId(topic);
		if (!(topic && text.length)) return this.parse('/help roomfaq');
		text = text.join(',').trim();
		if (topic.length > 25) return this.errorReply("FAQ topics should not exceed 25 characters.");
		if (text.length > 500) return this.errorReply("FAQ entries should not exceed 500 characters.");

		text = text.replace(/^>/, '>');

		let htmltags = text.toLowerCase().match(/<\/?(\w+)\b/g);
		if (htmltags && htmltags.some(val => !ALLOWED_HTML.includes(toId(val)))) {
			let tagList = ALLOWED_HTML.map(tag => `<${tag}>`).join(', ');
			return this.errorReply(`Disallowed HTML tags found. Allowed html tags: ${tagList}`);
		}

		text = this.canHTML(text);
		if (!text) return;

		if (!roomFaqs[room.id]) roomFaqs[room.id] = {};
		roomFaqs[room.id][topic] = text;
		saveRoomFaqs();
		this.sendReplyBox(text);
		this.privateModCommand(`(${user.name} added a FAQ for '${topic}')`);
	},
	removefaq: function (target, room, user) {
		if (!this.canTalk()) return this.errorReply("You cannot do this while unable to talk.");
		if (!this.can('declare', null, room)) return false;
		if (!room.chatRoomData) return this.errorReply("This command is unavailable in temporary rooms.");
		let topic = toId(target);
		if (!topic) return this.parse('/help roomfaq');

		if (!(roomFaqs[room.id] && roomFaqs[room.id][topic])) return this.errorReply("Invalid topic.");
		delete roomFaqs[room.id][topic];
		Object.keys(roomFaqs[room.id]).filter(val => getAlias(room.id, val) === topic).map(val => delete roomFaqs[room.id][val]);
		if (!Object.keys(roomFaqs[room.id]).length) delete roomFaqs[room.id];
		saveRoomFaqs();
		this.privateModCommand(`(${user.name} removed the FAQ for '${topic}')`);
	},
	addalias: function (target, room, user) {
		if (!this.canTalk()) return this.errorReply("You cannot do this while unable to talk.");
		if (!this.can('declare', null, room)) return false;
		if (!room.chatRoomData) return this.errorReply("This command is unavailable in temporary rooms.");
		let [alias, topic] = target.split(',').map(val => toId(val));

		if (!(alias && topic)) return this.parse('/help roomfaq');
		if (alias.length > 25) return this.errorReply("FAQ topics should not exceed 25 characters.");

		if (!(roomFaqs[room.id] && topic in roomFaqs[room.id])) return this.errorReply(`The topic ${topic} was not found in this room's faq list.`);
		if (getAlias(room.id, topic)) return this.errorReply(`You cannot make an alias of an alias. Use /addalias ${alias}, ${getAlias(room.id, topic)} instead.`);
		roomFaqs[room.id][alias] = `>${topic}`;
		saveRoomFaqs();
		this.privateModCommand(`(${user.name} added an alias for '${topic}: ${alias}')`);
	},
	roomfaq: function (target, room, user) {
		if (!roomFaqs[room.id]) return this.errorReply("This room has no FAQ topics.");
		let topic = toId(target);
		if (topic === 'constructor') return false;
		if (!topic) return this.sendReplyBox(`List of topics in this room: ${Object.keys(roomFaqs[room.id]).filter(val => !getAlias(room.id, val)).join(', ')}`);
		if (!roomFaqs[room.id][topic]) return this.errorReply("Invalid topic.");
		topic = getAlias(room.id, topic) || topic;

		if (!this.runBroadcast()) return;
		this.sendReplyBox(roomFaqs[room.id][topic]);
		if (!this.broadcasting && user.can('declare', null, room)) this.sendReplyBox('/addfaq ' + topic + ', ' + Chat.escapeHTML(roomFaqs[room.id][topic]) + '');
	},
	roomfaqhelp: [
		"/roomfaq - Shows the list of all available FAQ topics",
		"/roomfaq <topic> - Shows the FAQ for <topic>.",
		"/addfaq <topic>, <text> - Adds an entry for <topic> in this room or updates it. Requires: # & ~",
		"/addalias <alias>, <topic> - Adds <alias> as an alias for <topic>, displaying it when users use /roomfaq <alias>. Requires: # & ~",
		"/removefaq <topic> - Removes the entry for <topic> in this room. If used on an alias, removes the alias. Requires: # & ~",
	],
};
<|endoftext|>


<commit_before>var mongoose     = require('mongoose');
var Schema       = mongoose.Schema;

var ObjectId = mongoose.Schema.Types.ObjectId;
var Location = require("./location_model");
var License = require("./license_model");
var SpaceType = require("./spacetype_model");
var Product = require("./product_model");
var Claylock = require("./claylock_model");

var SpaceSchema   = new Schema({
	name: String,
	location_id: { type: ObjectId, ref: 'Location' },
	meters_squared: Number,
	spacetype_id: { type: ObjectId, ref: 'SpaceType', required: true },
	product_id: { type: ObjectId, ref: 'Product' },
	claylock_id: [{ type: ObjectId, ref: 'Claylock' }],
	date_created: { type: Date, default: Date.now },
	seats: Number,
	hot_oversell: Number,
	occasional_oversell: Number,
	shared: { type: Boolean, default: true },
	budget_price: Number, // Use this to calculate individual line item amounts
	aesthetic: String,
	aesthetic_impact: Number,
	business_case: Number,
	business_case_date: Date,
	business_case_factor: Number,
	market_rate: Number,
	market_date: Date,
	twelve_month_discount: Number,
	tenant_installation_allowance: Number,
	_owner_id: ObjectId,
	_deleted: { type: Boolean, default: false, index: true },
}, {
	toObject: {
		virtuals: true
	},
	toJSON: {
		virtuals: true
	},
	timestamps: true
});

SpaceSchema.set("_perms", {
	admin: "crud",
	owner: "r",
	user: "r",
	all: "r"
});

SpaceSchema.index( { "$**": "text" } );

SpaceSchema.virtual("budget_value_per_m2").get(function() {
	return this.budget_price/this.meters_squared;
});

SpaceSchema.virtual("actual_value_per_m2").get(function() {
	return this.actual_price/this.meters_squared;
});

module.exports = mongoose.model('Space', SpaceSchema);
<commit_msg>Delete some crap and multiple rooms<commit_after>var mongoose     = require('mongoose');
var Schema       = mongoose.Schema;

var ObjectId = mongoose.Schema.Types.ObjectId;
var Location = require("./location_model");
var License = require("./license_model");
var SpaceType = require("./spacetype_model");
var Room = require("./room_model");
var Claylock = require("./claylock_model");

var SpaceSchema   = new Schema({
	name: String,
	spacetype_id: { type: ObjectId, ref: 'SpaceType', required: true },
	room_id: [{ type: ObjectId, ref: 'Room' }],
	claylock_id: [{ type: ObjectId, ref: 'Claylock' }],
	_owner_id: ObjectId,
	_deleted: { type: Boolean, default: false, index: true },
}, {
	toObject: {
		virtuals: true
	},
	toJSON: {
		virtuals: true
	},
	timestamps: true
});

SpaceSchema.set("_perms", {
	admin: "crud",
	owner: "r",
	user: "r",
	all: "r"
});

SpaceSchema.virtual("total_value").get(function() {
	return 0;
});

SpaceSchema.virtual("meters_squared").get(function() {
	return 0;
});

SpaceSchema.virtual("seats").get(function () {
	return 0;
});

module.exports = mongoose.model('Space', SpaceSchema);
<|endoftext|>


<commit_before>tinyMCEPopup.requireLangPack();

var DragMathDialog = {
		init : function(ed) {

		},

	insert : function(file, title) {

	    var ed = tinyMCEPopup.editor;
		var mathExpression = document.dragmath.getMathExpression();
	    //
	    // TBD any massaging needed here?
	    //
	    var text = mathExpression;
	    //
	    // Escape the expression
	    //
	    var text = '$$' + text + '$$';
	    ed.execCommand('mceInsertContent', false, text);

		tinyMCEPopup.close();
	}

};

tinyMCEPopup.onInit.add(DragMathDialog.init, DragMathDialog);
<commit_msg>MDL-19526 fixed inserting of < and ><commit_after>tinyMCEPopup.requireLangPack();

var DragMathDialog = {
		init : function(ed) {

		},

	insert : function(file, title) {

	    var ed = tinyMCEPopup.editor;
		var mathExpression = document.dragmath.getMathExpression();
	    //
	    // TBD any massaging needed here?
	    //
	    var text = mathExpression;
	    // convert < and > to entities
	    text = text.replace('<', '<');
	    text = text.replace('>', '>');
	    //
	    // Escape the expression
	    //
	    text = '$$' + text + '$$';
	    ed.execCommand('mceInsertContent', false, text);

		tinyMCEPopup.close();
	}

};

tinyMCEPopup.onInit.add(DragMathDialog.init, DragMathDialog);
<|endoftext|>


<commit_before>import DOMPurify from 'dompurify';

var Markdown = require('markdown-it')({
  html: true,
  linkify: true,
  typographer: true,
  breaks: true,
});

import markdownItMermaid from "@wekanteam/markdown-it-mermaid";

// Static URL Scheme Listing
var urlschemes = [
  "aodroplink",
  "thunderlink",
  "cbthunderlink",
  "onenote",
  "file",
  "abasurl",
  "conisio",
  "mailspring"
];

// Better would be a field in the admin backend to set this dynamically
// instead of putting all known or wanted url schemes here hard into code
// but i was not able to access those settings
// var urlschemes = currentSetting.automaticLinkedUrlSchemes.split('\n');

// put all url schemes into the linkify configuration to automatically make it clickable
for(var i=0; i<urlschemes.length;i++){
  Markdown.linkify.add(urlschemes[i]+":",'http:');
}

var emoji = require('markdown-it-emoji');
var mathjax = require('markdown-it-mathjax3');
Markdown.use(emoji);
Markdown.use(mathjax);

// Try to fix Mermaid Diagram error: Maximum call stack size exceeded.
// Added bigger text size for Diagram.
// https://github.com/wekan/wekan/issues/4251
// https://stackoverflow.com/questions/66825888/maximum-text-size-in-diagram-exceeded-mermaid-js
// https://github.com/mermaid-js/mermaid/blob/74b1219d62dd76d98d60abeeb36d4520f64faceb/src/defaultConfig.js#L39
// https://github.com/wekan/cli-table3
// https://www.npmjs.com/package/@wekanteam/markdown-it-mermaid
// https://github.com/wekan/markdown-it-mermaid
Markdown.use(markdownItMermaid,{
  maxTextSize: 100000,
});

if (Package.ui) {
  const Template = Package.templating.Template;
  const UI = Package.ui.UI;
  const HTML = Package.htmljs.HTML;
  const Blaze = Package.blaze.Blaze; // implied by `ui`

  UI.registerHelper('markdown', new Template('markdown', function () {
    const self = this;
    let text = '';
    if (self.templateContentBlock) {
      text = Blaze._toText(self.templateContentBlock, HTML.TEXTMODE.STRING);
    }

    return HTML.Raw(DOMPurify.sanitize(Markdown.render(text), {ALLOW_UNKNOWN_PROTOCOLS: true}));
  }));
}
<commit_msg>Try to fix Mermaid Diagram error in Chrome: Maximum call stack size exceeded.<commit_after>import DOMPurify from 'dompurify';

var Markdown = require('markdown-it')({
  html: true,
  linkify: true,
  typographer: true,
  breaks: true,
});

import markdownItMermaid from "@wekanteam/markdown-it-mermaid";

// Static URL Scheme Listing
var urlschemes = [
  "aodroplink",
  "thunderlink",
  "cbthunderlink",
  "onenote",
  "file",
  "abasurl",
  "conisio",
  "mailspring"
];

// Better would be a field in the admin backend to set this dynamically
// instead of putting all known or wanted url schemes here hard into code
// but i was not able to access those settings
// var urlschemes = currentSetting.automaticLinkedUrlSchemes.split('\n');

// put all url schemes into the linkify configuration to automatically make it clickable
for(var i=0; i<urlschemes.length;i++){
  Markdown.linkify.add(urlschemes[i]+":",'http:');
}

var emoji = require('markdown-it-emoji');
var mathjax = require('markdown-it-mathjax3');
Markdown.use(emoji);
Markdown.use(mathjax);

// Try to fix Mermaid Diagram error: Maximum call stack size exceeded.
// Added bigger text size for Diagram.
// https://github.com/wekan/wekan/issues/4251
// https://stackoverflow.com/questions/66825888/maximum-text-size-in-diagram-exceeded-mermaid-js
// https://github.com/mermaid-js/mermaid/blob/74b1219d62dd76d98d60abeeb36d4520f64faceb/src/defaultConfig.js#L39
// https://github.com/wekan/cli-table3
// https://www.npmjs.com/package/@wekanteam/markdown-it-mermaid
// https://github.com/wekan/markdown-it-mermaid
Markdown.use(markdownItMermaid,{
  maxTextSize: 200000,
});

if (Package.ui) {
  const Template = Package.templating.Template;
  const UI = Package.ui.UI;
  const HTML = Package.htmljs.HTML;
  const Blaze = Package.blaze.Blaze; // implied by `ui`

  UI.registerHelper('markdown', new Template('markdown', function () {
    const self = this;
    let text = '';
    if (self.templateContentBlock) {
      text = Blaze._toText(self.templateContentBlock, HTML.TEXTMODE.STRING);
    }

    return HTML.Raw(DOMPurify.sanitize(Markdown.render(text), {ALLOW_UNKNOWN_PROTOCOLS: true}));
  }));
}
<|endoftext|>


<commit_before>
var browser = {
    api_location : null,
    load_button : null,
    load_spinner : null,
    box_container : null,
    map_box_template : null,
    logo_button : null,

    last_loaded_id : null,

    init : function (configuration) {
        browser.api_location = configuration.api_location;
        browser.load_button = $("#load_more button");
        browser.load_spinner = $("#spinner");
        browser.box_container = $("#listing");
        browser.map_box_template = $("#listing .template")
        browser.logo_button = $("#logo_button")

        browser.map_box_template.detach()
        browser.map_box_template.removeClass('template')

        browser.load_button.bind('click', browser.getNextPage)
        browser.logo_button.bind('click', browser.reloadLatest)

        browser.load_spinner.hide()
    },

    getNextPage : function() {
        browser.load_button.hide()
        browser.load_spinner.show()
        if (browser.last_loaded_id === null) {
            $.get('/maps/listing', browser.appendLoadedData)
        } else {
            $.get('/maps/listing/' + browser.last_loaded_id, browser.appendLoadedData)
        }
    },

    appendLoadedData : function(data) {
        var array_length = data['maps'].length;
        for (var i = 0; i < array_length; i++) {
            if (browser.last_loaded_id === null || browser.last_loaded_id > data['maps'][i]['id']) {
                browser.last_loaded_id = data['maps'][i]['id'];
            }
            browser.box_container.append(browser.buildMapBox(data['maps'][i]));
        }
        browser.load_spinner.hide()
        if (browser.last_loaded_id > 0 && array_length == 20) {
            browser.load_button.show();
        }
    },

    buildMapBox : function(data) {
        var new_box = browser.map_box_template.clone()
        new_box.find('.nameAnchor').text(data['name'])
        new_box.find('.createdAnchor').text(data['created'])
        new_box.find('.codeAnchor').text(data['code'])
        new_box.find('.downloadsAnchor').text(data['downloads'])
        new_box.find('.imageAnchor').attr("src", "public/img/" + data['code'] + ".png")
        new_box.find('.moreAuthor').bind('click', function () {
            browser.loadAuthorMaps(data['code'])
        })

        return new_box
    },

    reloadLatest : function() {
        browser.clear()
        browser.last_loaded_id = null
        browser.getNextPage()
    },

    clear : function() {
        browser.box_container.empty()
    },

    loadAuthorMaps : function(map_code) {
        browser.clear()
        browser.load_button.hide()
        browser.load_spinner.show()
        $.get('/maps/author/' + map_code, browser.appendLoadedData)
    },

    appendLoadedAuthorMaps : function(data) {
        browser.appendLoadedData(data)
        browser.load_button.hide()
    },

    getMapCode : function() {
        var href = window.location.href
        var results = new RegExp('author_([a-zA-Z0-9]*).html').exec(href)

        if (results == null) {
            return ""
        }

        return results[1]
    },

    initPage : function() {
        var map_code = browser.getMapCode()

        if (map_code != "") {
            browser.loadAuthorMaps(map_code)
        } else {
            browser.getNextPage()
        }
    }
}

$(document).ready(function() {
    browser.init(configuration);

    browser.initPage()
});<commit_msg>Added hardlinks to map authors<commit_after>
var browser = {
    api_location : null,
    load_button : null,
    load_spinner : null,
    box_container : null,
    map_box_template : null,
    logo_button : null,

    last_loaded_id : null,

    init : function (configuration) {
        browser.api_location = configuration.api_location;
        browser.load_button = $("#load_more button");
        browser.load_spinner = $("#spinner");
        browser.box_container = $("#listing");
        browser.map_box_template = $("#listing .template")
        browser.logo_button = $("#logo_button")

        browser.map_box_template.detach()
        browser.map_box_template.removeClass('template')

        browser.load_button.bind('click', browser.getNextPage)
        browser.logo_button.bind('click', browser.reloadLatest)

        browser.load_spinner.hide()
    },

    getNextPage : function() {
        browser.load_button.hide()
        browser.load_spinner.show()
        if (browser.last_loaded_id === null) {
            $.get('/maps/listing', browser.appendLoadedData)
        } else {
            $.get('/maps/listing/' + browser.last_loaded_id, browser.appendLoadedData)
        }
    },

    appendLoadedData : function(data) {
        var array_length = data['maps'].length;
        for (var i = 0; i < array_length; i++) {
            if (browser.last_loaded_id === null || browser.last_loaded_id > data['maps'][i]['id']) {
                browser.last_loaded_id = data['maps'][i]['id'];
            }
            browser.box_container.append(browser.buildMapBox(data['maps'][i]));
        }
        browser.load_spinner.hide()
        if (browser.last_loaded_id > 0 && array_length == 20) {
            browser.load_button.show();
        }
    },

    buildMapBox : function(data) {
        var new_box = browser.map_box_template.clone()
        new_box.find('.nameAnchor').text(data['name'])
        new_box.find('.createdAnchor').text(data['created'])
        new_box.find('.codeAnchor').text(data['code'])
        new_box.find('.downloadsAnchor').text(data['downloads'])
        new_box.find('.imageAnchor').attr("src", "public/img/" + data['code'] + ".png")
        new_box.find('.moreAuthor').bind('click', function () {
            browser.loadAuthorMaps(data['code'])
        })
        new_box.find('.moreAuthor').attr('href', '/browser/author_' + data['code'] + '.html')

        return new_box
    },

    reloadLatest : function() {
        browser.clear()
        browser.last_loaded_id = null
        browser.getNextPage()
    },

    clear : function() {
        browser.box_container.empty()
    },

    loadAuthorMaps : function(map_code) {
        browser.clear()
        browser.load_button.hide()
        browser.load_spinner.show()
        $.get('/maps/author/' + map_code, browser.appendLoadedData)
    },

    appendLoadedAuthorMaps : function(data) {
        browser.appendLoadedData(data)
        browser.load_button.hide()
    },

    getMapCode : function() {
        var href = window.location.href
        var results = new RegExp('author_([a-zA-Z0-9]*).html').exec(href)

        if (results == null) {
            return ""
        }

        return results[1]
    },

    initPage : function() {
        var map_code = browser.getMapCode()

        if (map_code != "") {
            browser.loadAuthorMaps(map_code)
        } else {
            browser.getNextPage()
        }
    }
}

$(document).ready(function() {
    browser.init(configuration);

    browser.initPage()
});<|endoftext|>


<commit_before>'use strict'
const slapp = require('../slackSetup.js').slapp
const getRadius = require('../radius.js').getRadius
const tinyurl = require('tinyurl');
const request = require('request')
const where = require('node-where')

// route functions
const snapsByGeo = require('./routes/snapsByGeoRoute.js').snapsByGeo
const routeFuncs = require('./routes/routesIndex.js')
const yes = require('./routes/yes.js').yes
const addressToGeo = require('./routes/addressToGeo.js').addressToGeo
const appDl = require('./routes/appDlRoute.js').appDl
const teamSettings = require('../teamSettings.js').teamSettings

const notify = require('./notifySlash.js').notify

//db imports
const firebase    = require('../firebaseSetup.js'),
      db = firebase.db,
      snaps = firebase.snaps,
      tags = firebase.tags,
      users = firebase.users,
      slackDb = firebase.slackDb

let jayBtns={
  text: "",
  attachments: [{
    text: 'How can I help?',
    fallback: 'Where to today?',
    callback_id: 'jaywalk_callback',
    color: 'good',
    actions: [
      {
        name: 'answer',
        text: 'Find deals',
        type: 'button',
        value: 'address'
      },
      {
        name: 'answer',
        text: 'Notifications',
        type: 'button',
        value: 'notifications'
      },
      {
        name: 'answer',
        text: 'Settings',
        type: 'button',
        value: 'settings'
      },
      {
        name: 'answer',
        text: 'Download app',
        type: 'button',
        value: 'app'
      }
    ]
  }]
}

const jaywalk = function() {
  let state = { requested: Date.now() }
  let teamId = ''
  let teamInfo = {}
  let answer

  slapp.command('/jaywalk', (msg, text) => {
    teamInfo = slackDb
      .child(msg.body.team_id)
      .once("value")
      .then(function(obj){
        if(obj.val().lat){
          return teamInfo = obj.val()
        } else{
          // might make condition to change buttons displayed?
          // send to setup and add to db
          return teamInfo.team_id = msg.body.team_id
        }
      })
    msg.route('main', (msg, state) => {
      msg
        .respond(jayBtns)
        .route('requestToDatabase', state, 60)
    }

    msg
      .say(jayBtns)
      .route('requestToDatabase', state, 60)
  })

// slapp.action('jaywalk_callback', 'answer', (msg, value) => {

  .route('requestToDatabase', (msg, state) => {
    if(msg.body.actions==undefined){      // try callback then remove this
      msg.route('requestToDatabase', state, 60)
    }else{
      answer = msg.body.actions[0].value
      if(answer == 'app'){
        appDl(teamInfo,msg,state)
      }else if(answer == 'address'){
        yes(teamInfo,msg,state)
        //https://jaywalk-geo.herokuapp.com/geoloc.htm
        // .route('handleGeoLoc', state, 60)
      }else if(answer == 'settings'){
        teamSettings(teamInfo,msg,state)
      }else if(answer == 'notifications'){
        notify(teamInfo,msg,state)
      }else{ //handle error
        return msg
          .say("Whoops, you just have to pick a button...")
          .say('Click a button!')
          .route('requestToDatabase', state, 60)
      }
    } //end else(actions undefined checker)
  }) //end .route('requestToDatabase')
  // }) //end callback
  .route('relaventAsk', (msg,state) => {
    routeFuncs.relaventAsk(msg,state)
  })//end .route(relaventAsk)
  .route('address_geo', (msg,state) => {
    let text = (msg.body.event && msg.body.event.text) || ''
    where.is(text,function(err,result){
      /*
        result.get('')=>
        address,streetNumber, street,streetAddress,city,region,
        regionCode, postalCode, country, countryCode, lat, lng
      */
      if (result) {
        let lat = result.get('lat')
        let lng = result.get('lng')
        snapsByGeo(lat,lng,msg,state)
      }
    })
  })
}
module.exports = {
  jaywalk:jaywalk(),
  jayBtns:jayBtns
}

<commit_msg>back btn?<commit_after>'use strict'
const slapp = require('../slackSetup.js').slapp
const getRadius = require('../radius.js').getRadius
const tinyurl = require('tinyurl');
const request = require('request')
const where = require('node-where')

// route functions
const snapsByGeo = require('./routes/snapsByGeoRoute.js').snapsByGeo
const routeFuncs = require('./routes/routesIndex.js')
const yes = require('./routes/yes.js').yes
const addressToGeo = require('./routes/addressToGeo.js').addressToGeo
const appDl = require('./routes/appDlRoute.js').appDl
const teamSettings = require('../teamSettings.js').teamSettings

const notify = require('./notifySlash.js').notify

//db imports
const firebase    = require('../firebaseSetup.js'),
      db = firebase.db,
      snaps = firebase.snaps,
      tags = firebase.tags,
      users = firebase.users,
      slackDb = firebase.slackDb

let jayBtns={
  text: "",
  attachments: [{
    text: 'How can I help?',
    fallback: 'Where to today?',
    callback_id: 'jaywalk_callback',
    color: 'good',
    actions: [
      {
        name: 'answer',
        text: 'Find deals',
        type: 'button',
        value: 'address'
      },
      {
        name: 'answer',
        text: 'Notifications',
        type: 'button',
        value: 'notifications'
      },
      {
        name: 'answer',
        text: 'Settings',
        type: 'button',
        value: 'settings'
      },
      {
        name: 'answer',
        text: 'Download app',
        type: 'button',
        value: 'app'
      }
    ]
  }]
}

const jaywalk = function() {
  let state = { requested: Date.now() }
  let teamId = ''
  let teamInfo = {}
  let answer

  slapp.command('/jaywalk', (msg, text) => {
    teamInfo = slackDb
      .child(msg.body.team_id)
      .once("value")
      .then(function(obj){
        if(obj.val().lat){
          return teamInfo = obj.val()
        } else{
          // might make condition to change buttons displayed?
          // send to setup and add to db
          return teamInfo.team_id = msg.body.team_id
        }
      })
    msg.route('main', (msg, state) => {
      msg
        .respond(jayBtns)
        .route('requestToDatabase', state, 60)
    })

    msg
      .say(jayBtns)
      .route('requestToDatabase', state, 60)
  })

// slapp.action('jaywalk_callback', 'answer', (msg, value) => {

  .route('requestToDatabase', (msg, state) => {
    if(msg.body.actions==undefined){      // try callback then remove this
      msg.route('requestToDatabase', state, 60)
    }else{
      answer = msg.body.actions[0].value
      if(answer == 'app'){
        appDl(teamInfo,msg,state)
      }else if(answer == 'address'){
        yes(teamInfo,msg,state)
        //https://jaywalk-geo.herokuapp.com/geoloc.htm
        // .route('handleGeoLoc', state, 60)
      }else if(answer == 'settings'){
        teamSettings(teamInfo,msg,state)
      }else if(answer == 'notifications'){
        notify(teamInfo,msg,state)
      }else{ //handle error
        return msg
          .say("Whoops, you just have to pick a button...")
          .say('Click a button!')
          .route('requestToDatabase', state, 60)
      }
    } //end else(actions undefined checker)
  }) //end .route('requestToDatabase')
  // }) //end callback
  .route('relaventAsk', (msg,state) => {
    routeFuncs.relaventAsk(msg,state)
  })//end .route(relaventAsk)
  .route('address_geo', (msg,state) => {
    let text = (msg.body.event && msg.body.event.text) || ''
    where.is(text,function(err,result){
      /*
        result.get('')=>
        address,streetNumber, street,streetAddress,city,region,
        regionCode, postalCode, country, countryCode, lat, lng
      */
      if (result) {
        let lat = result.get('lat')
        let lng = result.get('lng')
        snapsByGeo(lat,lng,msg,state)
      }
    })
  })
}
module.exports = {
  jaywalk:jaywalk(),
  jayBtns:jayBtns
}

<|endoftext|>


<commit_before>/**
* The Studio: Artist of the Day Plugin
* This is a daily activity where users get to nominate an artist to be Artist of the day, and it's randomly selected
* Only works in a room with the id "thestudio"
*/

exports.commands = {
	startaotd: function () {
		return this.parse('/toggleaotd on');
	},

	endaotd: function () {
		return this.parse('/toggleaotd off');
	},

	taotd: 'toggleaotd',
	toggleaotd: function (target, room, user) {
		if (room.id !== 'goldenrodradiotower') return this.sendReply("This command can only be used in goldenrodradiotower.");
		if (!this.canTalk()) return;
		if (!this.can('mute', null, room)) return;
		if (!target) {
			return this.sendReply("/toggleaotd [on / off] - If on, this will start AOTD, if off, this will no longer allow people to use /naotd.");
		}
		if (target === 'on') {
			if (room.aotdOn) return this.sendReply("The Artist of the Day has already started.");
			room.addRaw(
				'
' +
					'
Artist of the Day has started!
' +
					"
(Started by " + Tools.escapeHTML(user.name) + ")
" +
					"
Use /naotd [artist] to nominate an artist!
" +
				'
'
			);
			room.aotdOn = true;
			this.logModCommand("Artist of the Day was started by " + Tools.escapeHTML(user.name) + ".");
		}
		if (target === 'off') {
			if (!room.aotdOn) return this.sendReply("The Artist of the Day has already ended.");
			room.addRaw("Nominations are over! (Turned off by " + Tools.escapeHTML(user.name) + ")");
			room.aotdOn = false;
		}
	},

	aotdfaq: 'aotdhelp',
	aotdhelp: function (target, room) {
		if (!this.canBroadcast()) return;
		if (room.id !== 'goldenrodradiotower') return this.sendReply("This command can only be used in goldenrodradiotower.");
		this.sendReplyBox(
			"
Artist of the Day:
" +
			"
This is a room activity for The Studio where users nominate artists for the title of 'Artist of the Day'.
" +
			'
' +
				"Command List:" +
				'
' +
					"
/naotd (artist) - This will nominate your artist of the day; only do this once, please.
" +
					"
/aotd - This allows you to see who the current Artist of the Day is.
" +
					"
/aotd (artist) - Sets an artist of the day. (requires %, @, #)
" +
					"
/startaotd - Will start AOTD (requires %, @, #)
" +
					"
/endaotd - Will turn off the use of /naotd, ending AOTD (requires %, @, #)
" +
				'
' +
			'
' +
			"
More information on Artist of the Day and these commands.
"
		);
	},

	nominateartistoftheday: 'naotd',
	naotd: function (target, room, user) {
		if (room.id !== 'goldenrodradiotower') return this.sendReply("This command can only be used in goldenrodradiotower.");
		if (!room.aotdOn) return this.sendReply("The Artist of the Day has already been chosen.");
		if (!target) return this.sendReply("/naotd [artist] - Nominates an artist for Artist of the Day.");
		if (target.length > 25) return this.sendReply("This Artist's name is too long; it cannot exceed 25 characters.");
		if (!this.canTalk()) return;
		room.addRaw(Tools.escapeHTML(user.name) + "'s nomination for Artist of the Day is: " + Tools.escapeHTML(target) + "");
	},

	artistoftheday: 'aotd',
	aotd: function (target, room, user) {
		if (room.id !== 'goldenrodradiotower') return this.sendReply("This command can only be used in goldenrodradiotower.");
		if (!target) {
			if (!this.canBroadcast()) return;
			this.sendReplyBox("The current Artist of the Day is: " + Tools.escapeHTML(room.aotd) + "");
			return;
		}
		if (!this.canTalk()) return;
		if (target.length > 25) return this.sendReply("This Artist\'s name is too long; it cannot exceed 25 characters.");
		if (!this.can('mute', null, room)) return;
		room.aotd = target;
		room.addRaw(
			'
' +
				"
The Artist of the Day is now " + Tools.escapeHTML(target) + "
" +
				"
(Set by " + Tools.escapeHTML(user.name) + ".)
" +
				"
This Artist will be posted on our Artist of the Day page.
" +
			'
'
		);
		room.aotdOn = false;
		this.logModCommand("The Artist of the Day was changed to " + Tools.escapeHTML(target) + " by " + Tools.escapeHTML(user.name) + ".");
	}
};
<commit_msg>update links<commit_after>/**
* The Studio: Artist of the Day Plugin
* This is a daily activity where users get to nominate an artist to be Artist of the day, and it's randomly selected
* Only works in a room with the id "thestudio"
*/

exports.commands = {
	startaotd: function () {
		return this.parse('/toggleaotd on');
	},

	endaotd: function () {
		return this.parse('/toggleaotd off');
	},

	taotd: 'toggleaotd',
	toggleaotd: function (target, room, user) {
		if (room.id !== 'goldenrodradiotower') return this.sendReply("This command can only be used in goldenrodradiotower.");
		if (!this.canTalk()) return;
		if (!this.can('mute', null, room)) return;
		if (!target) {
			return this.sendReply("/toggleaotd [on / off] - If on, this will start AOTD, if off, this will no longer allow people to use /naotd.");
		}
		if (target === 'on') {
			if (room.aotdOn) return this.sendReply("The Artist of the Day has already started.");
			room.addRaw(
				'
' +
					'
Artist of the Day has started!
' +
					"
(Started by " + Tools.escapeHTML(user.name) + ")
" +
					"
Use /naotd [artist] to nominate an artist!
" +
				'
'
			);
			room.aotdOn = true;
			this.logModCommand("Artist of the Day was started by " + Tools.escapeHTML(user.name) + ".");
		}
		if (target === 'off') {
			if (!room.aotdOn) return this.sendReply("The Artist of the Day has already ended.");
			room.addRaw("Nominations are over! (Turned off by " + Tools.escapeHTML(user.name) + ")");
			room.aotdOn = false;
		}
	},

	aotdfaq: 'aotdhelp',
	aotdhelp: function (target, room) {
		if (!this.canBroadcast()) return;
		if (room.id !== 'goldenrodradiotower') return this.sendReply("This command can only be used in goldenrodradiotower.");
		this.sendReplyBox(
			"
Artist of the Day:
" +
			"
This is a room activity for The Studio where users nominate artists for the title of 'Artist of the Day'.
" +
			'
' +
				"Command List:" +
				'
' +
					"
/naotd (artist) - This will nominate your artist of the day; only do this once, please.
" +
					"
/aotd - This allows you to see who the current Artist of the Day is.
" +
					"
/aotd (artist) - Sets an artist of the day. (requires %, @, #)
" +
					"
/startaotd - Will start AOTD (requires %, @, #)
" +
					"
/endaotd - Will turn off the use of /naotd, ending AOTD (requires %, @, #)
" +
				'
' +
			'
' +
			"
More information on Artist of the Day and these commands.
"
		);
	},

	nominateartistoftheday: 'naotd',
	naotd: function (target, room, user) {
		if (room.id !== 'goldenrodradiotower') return this.sendReply("This command can only be used in goldenrodradiotower.");
		if (!room.aotdOn) return this.sendReply("The Artist of the Day has already been chosen.");
		if (!target) return this.sendReply("/naotd [artist] - Nominates an artist for Artist of the Day.");
		if (target.length > 25) return this.sendReply("This Artist's name is too long; it cannot exceed 25 characters.");
		if (!this.canTalk()) return;
		room.addRaw(Tools.escapeHTML(user.name) + "'s nomination for Artist of the Day is: " + Tools.escapeHTML(target) + "");
	},

	artistoftheday: 'aotd',
	aotd: function (target, room, user) {
		if (room.id !== 'goldenrodradiotower') return this.sendReply("This command can only be used in goldenrodradiotower.");
		if (!target) {
			if (!this.canBroadcast()) return;
			this.sendReplyBox("The current Artist of the Day is: " + Tools.escapeHTML(room.aotd) + "");
			return;
		}
		if (!this.canTalk()) return;
		if (target.length > 25) return this.sendReply("This Artist\'s name is too long; it cannot exceed 25 characters.");
		if (!this.can('mute', null, room)) return;
		room.aotd = target;
		room.addRaw(
			'
' +
				"
The Artist of the Day is now " + Tools.escapeHTML(target) + "
" +
				"
(Set by " + Tools.escapeHTML(user.name) + ".)
" +
				"
This Artist will be posted on our Artist of the Day page.
" +
			'
'
		);
		room.aotdOn = false;
		this.logModCommand("The Artist of the Day was changed to " + Tools.escapeHTML(target) + " by " + Tools.escapeHTML(user.name) + ".");
	}
};
<|endoftext|>


<commit_before>exports.BattleMovedex = {
	"divingtalon": {
		num: 704,
		accuracy: 100,
		basePower: 40,
		category: "Physical",
		desc: "Deals damage to one adjacent target. Makes contact. Priority +1.",
		shortDesc: "Usually goes first.",
		id: "divingtalon",
		isViable: true,
		name: "Diving Talon",
		pp: 20,
		priority: 1,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Flying"
	},
	"firerocket": {
		num: 703,
		accuracy: 100,
		basePower: 40,
		category: "Physical",
		desc: "Deals damage to one adjacent target. Makes contact. Priority +1.",
		shortDesc: "Usually goes first.",
		id: "firerocket",
		isViable: true,
		name: "Fire Rocket",
		pp: 20,
		priority: 1,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Fire"
	},
	"rabidfrenzy": {
		num: 370,
		accuracy: 100,
		basePower: 120,
		category: "Physical",
		desc: "Deals damage to one adjacent target and lowers the user's Defense and Special Defense by 1 stage. Makes contact.",
		shortDesc: "Lowers the user's Defense and Sp. Def by 1.",
		id: "rapidfrenzy",
		isViable: true,
		name: "Rabid Frenzy",
		pp: 5,
		priority: 0,
		isContact: true,
		self: {
			boosts: {
				def: -1,
				spd: -1
			}
		},
		secondary: false,
		target: "normal",
		type: "Dark"
	},
	"rootbomb": {
		num: 510,
		accuracy: 100,
		basePower: 30,
		category: "Physical",
		desc: "Deals damage to all adjacent foes and changes type to Grass before hitting.",
		shortDesc: "Changes foes type to Grass before hitting.",
		id: "rootbomb",
		name: "Root Bomb",
		pp: 15,
		priority: 0,
		onTryPrimaryHit: function(target) {
			this.add('-start', target, 'typechange', 'Grass');
			target.types = ['Grass'];
		},
		secondary: false,
		target: "normal",
		type: "Fire"
	},
	"shadowsword": {
		num: 610,
		accuracy: 100,
		basePower: 85,
		category: "Physical",
		desc: "Deals damage to one adjacent target with a 20% chance to lower its Defense by 1 stage. Makes contact.",
		shortDesc: "20% chance to lower the target's Defense by 1",
		id: "shadowsword",
		name: "Shadow Sword",
		pp: 20,
		priority: 0,
		isContact: true,
		secondary: {
			chance: 20,
			boosts: {
				def: -1
			}
		},
		target: "ghost",
		type: "Ghost"
	},
	"shortcircuit": {
		num: 705,
		accuracy: 100,
		basePower: 40,
		category: "Special",
		desc: "Deals damage to one adjacent target. Makes contact. Priority +1.",
		shortDesc: "Usually goes first.",
		id: "shortcircuit",
		isViable: true,
		name: "Short Circuit",
		pp: 20,
		priority: 1,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Electric"
	},
        "vendetta": {
                num: 702,
                accuracy: 85,
                basePower: 120,
                category: "Special",
                desc: "Deals damage to one adjacent target with a 20 chance to hit it with Spite.",
                shortDesc: "20% chance to spite the target.",
                id: "vendetta",
                isViable: true,
                name: "Vendetta",
                pp: 5,
                priority: 0,
                onHit: function(target) {
                        var spiteroll = this.random(100);
                        if (spiteroll > 80) {
                                if (target.deductPP(target.lastMove, 4)) {
                                        this.add("-activate", target, 'move: vendetta', target.lastMove, 4);
                                        return;
                                }
                        }
                        return false;
                },
                target: "normal",
                type: "Ghost"
        },
	"voidhorn": {
		num: 701,
		accuracy: 85,
		basePower: 120,
		category: "Physical",
		desc: "Deals damage to one adjacent target",
		shortDesc: "Strong Ghost-Type Move",
		id: "voidhorn",
		isViable: true,
		name: "Void Horn",
		pp: 10,
		priority: 0,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Ghost"
	},
};
<commit_msg>root bomb<commit_after>exports.BattleMovedex = {
	"divingtalon": {
		num: 704,
		accuracy: 100,
		basePower: 40,
		category: "Physical",
		desc: "Deals damage to one adjacent target. Makes contact. Priority +1.",
		shortDesc: "Usually goes first.",
		id: "divingtalon",
		isViable: true,
		name: "Diving Talon",
		pp: 20,
		priority: 1,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Flying"
	},
	"firerocket": {
		num: 703,
		accuracy: 100,
		basePower: 40,
		category: "Physical",
		desc: "Deals damage to one adjacent target. Makes contact. Priority +1.",
		shortDesc: "Usually goes first.",
		id: "firerocket",
		isViable: true,
		name: "Fire Rocket",
		pp: 20,
		priority: 1,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Fire"
	},
	"rabidfrenzy": {
		num: 370,
		accuracy: 100,
		basePower: 120,
		category: "Physical",
		desc: "Deals damage to one adjacent target and lowers the user's Defense and Special Defense by 1 stage. Makes contact.",
		shortDesc: "Lowers the user's Defense and Sp. Def by 1.",
		id: "rapidfrenzy",
		isViable: true,
		name: "Rabid Frenzy",
		pp: 5,
		priority: 0,
		isContact: true,
		self: {
			boosts: {
				def: -1,
				spd: -1
			}
		},
		secondary: false,
		target: "normal",
		type: "Dark"
	},
	"rootbomb": {
		num: 510,
		accuracy: 100,
		basePower: 30,
		category: "Physical",
		desc: "Deals damage to all adjacent foes and changes type to Grass before hitting.",
		shortDesc: "Changes foes type to Grass before hitting.",
		id: "rootbomb",
		name: "Root Bomb",
		pp: 15,
		priority: 0,
		onHit: function(target) {
			this.add('-start', target, 'typechange', 'Grass');
			target.types = ['Grass'];
		},
		secondary: false,
		target: "normal",
		type: "Fire"
	},
	"shadowsword": {
		num: 610,
		accuracy: 100,
		basePower: 85,
		category: "Physical",
		desc: "Deals damage to one adjacent target with a 20% chance to lower its Defense by 1 stage. Makes contact.",
		shortDesc: "20% chance to lower the target's Defense by 1",
		id: "shadowsword",
		name: "Shadow Sword",
		pp: 20,
		priority: 0,
		isContact: true,
		secondary: {
			chance: 20,
			boosts: {
				def: -1
			}
		},
		target: "ghost",
		type: "Ghost"
	},
	"shortcircuit": {
		num: 705,
		accuracy: 100,
		basePower: 40,
		category: "Special",
		desc: "Deals damage to one adjacent target. Makes contact. Priority +1.",
		shortDesc: "Usually goes first.",
		id: "shortcircuit",
		isViable: true,
		name: "Short Circuit",
		pp: 20,
		priority: 1,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Electric"
	},
        "vendetta": {
                num: 702,
                accuracy: 85,
                basePower: 120,
                category: "Special",
                desc: "Deals damage to one adjacent target with a 20 chance to hit it with Spite.",
                shortDesc: "20% chance to spite the target.",
                id: "vendetta",
                isViable: true,
                name: "Vendetta",
                pp: 5,
                priority: 0,
                onHit: function(target) {
                        var spiteroll = this.random(100);
                        if (spiteroll > 80) {
                                if (target.deductPP(target.lastMove, 4)) {
                                        this.add("-activate", target, 'move: vendetta', target.lastMove, 4);
                                        return;
                                }
                        }
                        return false;
                },
                target: "normal",
                type: "Ghost"
        },
	"voidhorn": {
		num: 701,
		accuracy: 85,
		basePower: 120,
		category: "Physical",
		desc: "Deals damage to one adjacent target",
		shortDesc: "Strong Ghost-Type Move",
		id: "voidhorn",
		isViable: true,
		name: "Void Horn",
		pp: 10,
		priority: 0,
		isContact: true,
		secondary: false,
		target: "normal",
		type: "Ghost"
	},
};
<|endoftext|>


<commit_before>

var   mac = require('./icons.mac')
    , web = require('./icons.web')
    , ios = require('./icons.ios')
    , android = require('./icons.android')
    , windows = require('./icons.windows')

var internal = {};

exports.run = function run(flow, data, done) {

    var prepared = flow.project.prepared.source;

        //don't care if there is no icon node
    var has_icon = (prepared.project.app && prepared.project.app.icon);
    if(!has_icon) {
        return;
    }

    var icon = {
        dest : 'icon',
        source : prepared.project.app.icon
    };

    icon = internal.parse_path(flow, icon);

    icon.source = path.join(prepared.project.app._icon.__path, icon.source);

    prepared.project.app._icon = icon;

    switch(flow.target) {
        case 'mac':
                mac.convert(flow, icon, done);
            break;
        case 'web':
                web.convert(flow, icon, done);
            break;
        case 'ios':
                ios.convert(flow, icon, done);
            break;
        case 'android':
                android.convert(flow, icon, done);
            break;
        case 'windows':
                windows.convert(flow, icon, done);
            break;
        default:{
                flow.log(2, 'no icon convert just yet for ', flow.target);
            break;
        }
    } //flow.target

} //run

internal.parse_path = function(flow, icon) {
    var parts = icon.source.split('=>');

    icon.source = parts[0].trim();
    if(parts.length > 1) {
        icon.dest = parts[1].trim();
    }

    return icon;

} //parse_path

exports.verify = function verify(flow, done) {

    flow.project.do_prepare(flow);

    done(null, null);

} //verify

exports.error = function(flow, err) {

} //error
<commit_msg>fix bug where projects without icons stall the build<commit_after>

var   mac = require('./icons.mac')
    , web = require('./icons.web')
    , ios = require('./icons.ios')
    , android = require('./icons.android')
    , windows = require('./icons.windows')

var internal = {};

exports.run = function run(flow, data, done) {

    var prepared = flow.project.prepared.source;

        //don't care if there is no icon node
    var has_icon = (prepared.project.app && prepared.project.app.icon);
    if(!has_icon) {

        if(done) {
            done();
        }

        return;

    } //has_icon

    var icon = {
        dest : 'icon',
        source : prepared.project.app.icon
    };

    icon = internal.parse_path(flow, icon);

    icon.source = path.join(prepared.project.app._icon.__path, icon.source);

    prepared.project.app._icon = icon;

    switch(flow.target) {
        case 'mac':
                mac.convert(flow, icon, done);
            break;
        case 'web':
                web.convert(flow, icon, done);
            break;
        case 'ios':
                ios.convert(flow, icon, done);
            break;
        case 'android':
                android.convert(flow, icon, done);
            break;
        case 'windows':
                windows.convert(flow, icon, done);
            break;
        default:{
                flow.log(2, 'no icon convert just yet for ', flow.target);
            break;
        }
    } //flow.target

} //run

internal.parse_path = function(flow, icon) {
    var parts = icon.source.split('=>');

    icon.source = parts[0].trim();
    if(parts.length > 1) {
        icon.dest = parts[1].trim();
    }

    return icon;

} //parse_path

exports.verify = function verify(flow, done) {

    flow.project.do_prepare(flow);

    done(null, null);

} //verify

exports.error = function(flow, err) {

} //error
<|endoftext|>


<commit_before>import _ from 'underscore';

// settings endpoints
RocketChat.API.v1.addRoute('settings.public', { authRequired: false }, {
	get() {
		const { offset, count } = this.getPaginationItems();
		const { sort, fields, query } = this.parseJsonQuery();

		let ourQuery = {
			hidden: { $ne: true },
			'public': true
		};

		ourQuery = Object.assign({}, query, ourQuery);

		const settings = RocketChat.models.Settings.find(ourQuery, {
			sort: sort ? sort : { _id: 1 },
			skip: offset,
			limit: count,
			fields: Object.assign({ _id: 1, value: 1 }, fields)
		}).fetch();

		return RocketChat.API.v1.success({
			settings,
			count: settings.length,
			offset,
			total: RocketChat.models.Settings.find(ourQuery).count()
		});
	}
});

RocketChat.API.v1.addRoute('settings.oauth', { authRequired: false }, {
	get() {
		const mountOAuthServices = () => {
			const oAuthServicesEnabled = ServiceConfiguration.configurations.find({}, { fields: { secret: 0 } }).fetch();

			return oAuthServicesEnabled.map((service) => {
				if (service.custom) {
					return { ...service };
				}
				return {
					_id: service._id,
					name: service.service,
					clientId: service.appId || service.clientId || service.consumerKey,
					buttonLabelText: service.buttonLabelText || '',
					buttonColor: service.buttonColor || '',
					buttonLabelColor: service.buttonLabelColor || '',
					custom: false
				};
			});
		};

		return RocketChat.API.v1.success({
			services: mountOAuthServices()
		});
	}
});

RocketChat.API.v1.addRoute('settings', { authRequired: true }, {
	get() {
		const { offset, count } = this.getPaginationItems();
		const { sort, fields, query } = this.parseJsonQuery();

		let ourQuery = {
			hidden: { $ne: true }
		};

		if (!RocketChat.authz.hasPermission(this.userId, 'view-privileged-setting')) {
			ourQuery.public = true;
		}

		ourQuery = Object.assign({}, query, ourQuery);

		const settings = RocketChat.models.Settings.find(ourQuery, {
			sort: sort ? sort : { _id: 1 },
			skip: offset,
			limit: count,
			fields: Object.assign({ _id: 1, value: 1 }, fields)
		}).fetch();

		return RocketChat.API.v1.success({
			settings,
			count: settings.length,
			offset,
			total: RocketChat.models.Settings.find(ourQuery).count()
		});
	}
});

RocketChat.API.v1.addRoute('settings/:_id', { authRequired: true }, {
	get() {
		if (!RocketChat.authz.hasPermission(this.userId, 'view-privileged-setting')) {
			return RocketChat.API.v1.unauthorized();
		}

		return RocketChat.API.v1.success(_.pick(RocketChat.models.Settings.findOneNotHiddenById(this.urlParams._id), '_id', 'value'));
	},
	post() {
		if (!RocketChat.authz.hasPermission(this.userId, 'edit-privileged-setting')) {
			return RocketChat.API.v1.unauthorized();
		}

		check(this.bodyParams, {
			value: Match.Any
		});

		if (RocketChat.models.Settings.updateValueNotHiddenById(this.urlParams._id, this.bodyParams.value)) {
			return RocketChat.API.v1.success();
		}

		return RocketChat.API.v1.failure();
	}
});

RocketChat.API.v1.addRoute('service.configurations', { authRequired: false }, {
	get() {
		const ServiceConfiguration = Package['service-configuration'].ServiceConfiguration;

		return RocketChat.API.v1.success({
			configurations: ServiceConfiguration.configurations.find({}, { fields: { secret: 0 } }).fetch()
		});
	}
});
<commit_msg>Fix /api/v1/settings.oauth not sending needed info for SAML & CAS (#10596)<commit_after>import _ from 'underscore';

// settings endpoints
RocketChat.API.v1.addRoute('settings.public', { authRequired: false }, {
	get() {
		const { offset, count } = this.getPaginationItems();
		const { sort, fields, query } = this.parseJsonQuery();

		let ourQuery = {
			hidden: { $ne: true },
			'public': true
		};

		ourQuery = Object.assign({}, query, ourQuery);

		const settings = RocketChat.models.Settings.find(ourQuery, {
			sort: sort ? sort : { _id: 1 },
			skip: offset,
			limit: count,
			fields: Object.assign({ _id: 1, value: 1 }, fields)
		}).fetch();

		return RocketChat.API.v1.success({
			settings,
			count: settings.length,
			offset,
			total: RocketChat.models.Settings.find(ourQuery).count()
		});
	}
});

RocketChat.API.v1.addRoute('settings.oauth', { authRequired: false }, {
	get() {
		const mountOAuthServices = () => {
			const oAuthServicesEnabled = ServiceConfiguration.configurations.find({}, { fields: { secret: 0 } }).fetch();

			return oAuthServicesEnabled.map((service) => {
				if (service.custom || ['saml', 'cas'].includes(service.service)) {
					return { ...service };
				}

				return {
					_id: service._id,
					name: service.service,
					clientId: service.appId || service.clientId || service.consumerKey,
					buttonLabelText: service.buttonLabelText || '',
					buttonColor: service.buttonColor || '',
					buttonLabelColor: service.buttonLabelColor || '',
					custom: false
				};
			});
		};

		return RocketChat.API.v1.success({
			services: mountOAuthServices()
		});
	}
});

RocketChat.API.v1.addRoute('settings', { authRequired: true }, {
	get() {
		const { offset, count } = this.getPaginationItems();
		const { sort, fields, query } = this.parseJsonQuery();

		let ourQuery = {
			hidden: { $ne: true }
		};

		if (!RocketChat.authz.hasPermission(this.userId, 'view-privileged-setting')) {
			ourQuery.public = true;
		}

		ourQuery = Object.assign({}, query, ourQuery);

		const settings = RocketChat.models.Settings.find(ourQuery, {
			sort: sort ? sort : { _id: 1 },
			skip: offset,
			limit: count,
			fields: Object.assign({ _id: 1, value: 1 }, fields)
		}).fetch();

		return RocketChat.API.v1.success({
			settings,
			count: settings.length,
			offset,
			total: RocketChat.models.Settings.find(ourQuery).count()
		});
	}
});

RocketChat.API.v1.addRoute('settings/:_id', { authRequired: true }, {
	get() {
		if (!RocketChat.authz.hasPermission(this.userId, 'view-privileged-setting')) {
			return RocketChat.API.v1.unauthorized();
		}

		return RocketChat.API.v1.success(_.pick(RocketChat.models.Settings.findOneNotHiddenById(this.urlParams._id), '_id', 'value'));
	},
	post() {
		if (!RocketChat.authz.hasPermission(this.userId, 'edit-privileged-setting')) {
			return RocketChat.API.v1.unauthorized();
		}

		check(this.bodyParams, {
			value: Match.Any
		});

		if (RocketChat.models.Settings.updateValueNotHiddenById(this.urlParams._id, this.bodyParams.value)) {
			return RocketChat.API.v1.success();
		}

		return RocketChat.API.v1.failure();
	}
});

RocketChat.API.v1.addRoute('service.configurations', { authRequired: false }, {
	get() {
		const ServiceConfiguration = Package['service-configuration'].ServiceConfiguration;

		return RocketChat.API.v1.success({
			configurations: ServiceConfiguration.configurations.find({}, { fields: { secret: 0 } }).fetch()
		});
	}
});
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import Gallery from '../../../src/js/index';

const app = document.getElementById('app');

/* eslint-disable */
const images = [
  [require('../img/01.jpg'), require('../img/01-thumb.jpg'), 'New York moving'],
  [require('../img/02.jpg'), require('../img/02-thumb.jpg'), 'New York traffic'],
  [require('../img/03.jpg'), require('../img/03-thumb.jpg'), 'Street dancers'],
  [require('../img/04.jpg'), require('../img/04-thumb.jpg'), 'Lights'],
  [require('../img/05.jpg'), require('../img/05-thumb.jpg'), 'NBC Studio'],
  [require('../img/06.jpg'), require('../img/06-thumb.jpg'), 'New York by night'],
  [require('../img/07.jpg'), require('../img/07-thumb.jpg'), 'Empire State Building'],
  [require('../img/08.jpg'), require('../img/08-thumb.jpg'), 'New York Promenade'],
  [require('../img/09.jpg'), require('../img/09-thumb.jpg'), 'Ellis Island Flag'],
  [require('../img/10.jpg'), require('../img/10-thumb.jpg'), 'Central Park'],
  [require('../img/11.jpg'), require('../img/11-thumb.jpg'), 'Statue of Liberty'],
  [require('../img/12.jpg'), require('../img/12-thumb.jpg'), 'Shoes'],
  [require('../img/13.jpg'), require('../img/13-thumb.jpg'), 'Shoes'],
  [require('../img/14.jpg'), require('../img/14-thumb.jpg'), 'Shoes'],
  [require('../img/15.jpg'), require('../img/15-thumb.jpg'), 'Shoes'],
  [require('../img/16.jpg'), require('../img/16-thumb.jpg'), 'Shoes'],
  [require('../img/17.jpg'), require('../img/17-thumb.jpg'), 'Shoes'],
  [require('../img/18.jpg'), require('../img/18-thumb.jpg'), 'Shoes'],
  [require('../img/19.jpg'), require('../img/19-thumb.jpg'), 'Shoes'],
  [require('../img/20.jpg'), require('../img/20-thumb.jpg'), 'Shoes'],
].map(([imageUrl, thumbnailUrl, title]) => ({
  imageUrl,
  thumbnailUrl,
  title,
  alt: title,
}));

ReactDOM.render(<Gallery images={images} />, app);
<commit_msg>Added jScrollPane CSS require to example (since it's no longer in the actual distributable)<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import Gallery from '../../../src/js/index';

const app = document.getElementById('app');

// Include jScrollPane styles (either like this or with a link in your HTML)
require('../../../node_modules/jscrollpane/style/jquery.jscrollpane.css');

/* eslint-disable */
const images = [
  [require('../img/01.jpg'), require('../img/01-thumb.jpg'), 'New York moving'],
  [require('../img/02.jpg'), require('../img/02-thumb.jpg'), 'New York traffic'],
  [require('../img/03.jpg'), require('../img/03-thumb.jpg'), 'Street dancers'],
  [require('../img/04.jpg'), require('../img/04-thumb.jpg'), 'Lights'],
  [require('../img/05.jpg'), require('../img/05-thumb.jpg'), 'NBC Studio'],
  [require('../img/06.jpg'), require('../img/06-thumb.jpg'), 'New York by night'],
  [require('../img/07.jpg'), require('../img/07-thumb.jpg'), 'Empire State Building'],
  [require('../img/08.jpg'), require('../img/08-thumb.jpg'), 'New York Promenade'],
  [require('../img/09.jpg'), require('../img/09-thumb.jpg'), 'Ellis Island Flag'],
  [require('../img/10.jpg'), require('../img/10-thumb.jpg'), 'Central Park'],
  [require('../img/11.jpg'), require('../img/11-thumb.jpg'), 'Statue of Liberty'],
  [require('../img/12.jpg'), require('../img/12-thumb.jpg'), 'Shoes'],
  [require('../img/13.jpg'), require('../img/13-thumb.jpg'), 'Shoes'],
  [require('../img/14.jpg'), require('../img/14-thumb.jpg'), 'Shoes'],
  [require('../img/15.jpg'), require('../img/15-thumb.jpg'), 'Shoes'],
  [require('../img/16.jpg'), require('../img/16-thumb.jpg'), 'Shoes'],
  [require('../img/17.jpg'), require('../img/17-thumb.jpg'), 'Shoes'],
  [require('../img/18.jpg'), require('../img/18-thumb.jpg'), 'Shoes'],
  [require('../img/19.jpg'), require('../img/19-thumb.jpg'), 'Shoes'],
  [require('../img/20.jpg'), require('../img/20-thumb.jpg'), 'Shoes'],
].map(([imageUrl, thumbnailUrl, title]) => ({
  imageUrl,
  thumbnailUrl,
  title,
  alt: title,
}));

ReactDOM.render(<Gallery images={images} />, app);
<|endoftext|>