<commit_before>// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
// License: New BSD License
// Reference: http://dev.w3.org/html5/websockets/
// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol

(function() {

  if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) return;

  var logger;
  if (window.WEB_SOCKET_LOGGER) {
    logger = WEB_SOCKET_LOGGER;
  } else if (window.console && window.console.log && window.console.error) {
    // In some environment, console is defined but console.log or console.error is missing.
    logger = window.console;
  } else {
    logger = {log: function(){ }, error: function(){ }};
  }

  // swfobject.hasFlashPlayerVersion("10.0.0") doesn't work with Gnash.
  if (swfobject.getFlashPlayerVersion().major < 10) {
    logger.error("Flash Player >= 10.0.0 is required.");
    return;
  }
  if (location.protocol == "file:") {
    logger.error(
      "WARNING: web-socket-js doesn't work in file:///... URL " +
      "unless you set Flash Security Settings properly. " +
      "Open the page via Web server i.e. http://...");
  }

  /**
   * This class represents a faux web socket.
   * @param {string} url
   * @param {array or string} protocols
   * @param {string} proxyHost
   * @param {int} proxyPort
   * @param {string} headers
   */
  WebSocket = function(url, protocols, proxyHost, proxyPort, headers) {
    var self = this;
    self.__id = WebSocket.__nextId++;
    WebSocket.__instances[self.__id] = self;
    self.readyState = WebSocket.CONNECTING;
    self.bufferedAmount = 0;
    self.__events = {};
    if (!protocols) {
      protocols = [];
    } else if (typeof protocols == "string") {
      protocols = [protocols];
    }
    // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
    // Otherwise, when onopen fires immediately, onopen is called before it is set.
    setTimeout(function() {
      WebSocket.__addTask(function() {
        WebSocket.__flash.create(
            self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null);
      });
    }, 0);
  };

  /**
   * Send data to the web socket.
   * @param {string} data  The data to send to the socket.
   * @return {boolean}  True for success, false for failure.
   */
  WebSocket.prototype.send = function(data) {
    if (this.readyState == WebSocket.CONNECTING) {
      throw "INVALID_STATE_ERR: Web Socket connection has not been established";
    }
    // We use encodeURIComponent() here, because FABridge doesn't work if
    // the argument includes some characters. We don't use escape() here
    // because of this:
    // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions
    // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
    // preserve all Unicode characters either e.g. "\uffff" in Firefox.
    // Note by wtritch: Hopefully this will not be necessary using ExternalInterface.  Will require
    // additional testing.
    var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
    if (result < 0) { // success
      return true;
    } else {
      this.bufferedAmount += result;
      return false;
    }
  };

  /**
   * Close this web socket gracefully.
   */
  WebSocket.prototype.close = function() {
    if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
      return;
    }
    this.readyState = WebSocket.CLOSING;
    WebSocket.__flash.close(this.__id);
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {string} type
   * @param {function} listener
   * @param {boolean} useCapture
   * @return void
   */
  WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
    if (!(type in this.__events)) {
      this.__events[type] = [];
    }
    this.__events[type].push(listener);
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {string} type
   * @param {function} listener
   * @param {boolean} useCapture
   * @return void
   */
  WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
    if (!(type in this.__events)) return;
    var events = this.__events[type];
    for (var i = events.length - 1; i >= 0; --i) {
      if (events[i] === listener) {
        events.splice(i, 1);
        break;
      }
    }
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {Event} event
   * @return void
   */
  WebSocket.prototype.dispatchEvent = function(event) {
    var events = this.__events[event.type] || [];
    for (var i = 0; i < events.length; ++i) {
      events[i](event);
    }
    var handler = this["on" + event.type];
    if (handler) handler(event);
  };

  /**
   * Handles an event from Flash.
   * @param {Object} flashEvent
   */
  WebSocket.prototype.__handleEvent = function(flashEvent) {
    if ("readyState" in flashEvent) {
      this.readyState = flashEvent.readyState;
    }
    if ("protocol" in flashEvent) {
      this.protocol = flashEvent.protocol;
    }

    var jsEvent;
    if (flashEvent.type == "open" || flashEvent.type == "error") {
      jsEvent = this.__createSimpleEvent(flashEvent.type);
    } else if (flashEvent.type == "close") {
      // TODO implement jsEvent.wasClean
      jsEvent = this.__createSimpleEvent("close");
    } else if (flashEvent.type == "message") {
      var data = decodeURIComponent(flashEvent.message);
      jsEvent = this.__createMessageEvent("message", data);
    } else {
      throw "unknown event type: " + flashEvent.type;
    }

    this.dispatchEvent(jsEvent);
  };

  WebSocket.prototype.__createSimpleEvent = function(type) {
    if (document.createEvent && window.Event) {
      var event = document.createEvent("Event");
      event.initEvent(type, false, false);
      return event;
    } else {
      return {type: type, bubbles: false, cancelable: false};
    }
  };

  WebSocket.prototype.__createMessageEvent = function(type, data) {
    if (document.createEvent && window.MessageEvent && !window.opera) {
      var event = document.createEvent("MessageEvent");
      event.initMessageEvent("message", false, false, data, null, null, window, null);
      return event;
    } else {
      // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
      return {type: type, data: data, bubbles: false, cancelable: false};
    }
  };

  /**
   * Define the WebSocket readyState enumeration.
   */
  WebSocket.CONNECTING = 0;
  WebSocket.OPEN = 1;
  WebSocket.CLOSING = 2;
  WebSocket.CLOSED = 3;

  WebSocket.__flash = null;
  WebSocket.__instances = {};
  WebSocket.__tasks = [];
  WebSocket.__nextId = 0;

  /**
   * Load a new flash security policy file.
   * @param {string} url
   */
  WebSocket.loadFlashPolicyFile = function(url){
    WebSocket.__addTask(function() {
      WebSocket.__flash.loadManualPolicyFile(url);
    });
  };

  /**
   * Loads WebSocketMain.swf and creates WebSocketMain object in Flash.
   */
  WebSocket.__initialize = function() {
    if (WebSocket.__flash) return;

    if (WebSocket.__swfLocation) {
      // For backword compatibility.
      window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
    }
    if (!window.WEB_SOCKET_SWF_LOCATION) {
      logger.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");
      return;
    }
    if (!window.WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR &&
        !WEB_SOCKET_SWF_LOCATION.match(/(^|\/)WebSocketMainInsecure\.swf(\?.*)?$/) &&
        WEB_SOCKET_SWF_LOCATION.match(/^\w+:\/\/([^\/]+)/)) {
      var swfHost = RegExp.$1;
      if (location.host != swfHost) {
        logger.error(
            "[WebSocket] You must host HTML and WebSocketMain.swf in the same host " +
            "('" + location.host + "' != '" + swfHost + "'). " +
            "See also 'How to host HTML file and SWF file in different domains' section " +
            "in README.md. If you use WebSocketMainInsecure.swf, you can suppress this message " +
            "by WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR = true;");
      }
    }
    var container = document.createElement("div");
    container.id = "webSocketContainer";
    // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents
    // Flash from loading at least in IE. So we move it out of the screen at (-100, -100).
    // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash
    // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is
    // the best we can do as far as we know now.
    container.style.position = "absolute";
    if (WebSocket.__isFlashLite()) {
      container.style.left = "0px";
      container.style.top = "0px";
    } else {
      container.style.left = "-100px";
      container.style.top = "-100px";
    }
    var holder = document.createElement("div");
    holder.id = "webSocketFlash";
    container.appendChild(holder);
    document.body.appendChild(container);
    // See this article for hasPriority:
    // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
    swfobject.embedSWF(
      WEB_SOCKET_SWF_LOCATION,
      "webSocketFlash",
      "1" /* width */,
      "1" /* height */,
      "10.0.0" /* SWF version */,
      null,
      null,
      {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"},
      null,
      function(e) {
        if (!e.success) {
          logger.error("[WebSocket] swfobject.embedSWF failed");
        }
      });
  };

  /**
   * Called by Flash to notify JS that it's fully loaded and ready
   * for communication.
   */
  WebSocket.__onFlashInitialized = function() {
    // We need to set a timeout here to avoid round-trip calls
    // to flash during the initialization process.
    setTimeout(function() {
      WebSocket.__flash = document.getElementById("webSocketFlash");
      WebSocket.__flash.setCallerUrl(location.href);
      WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
      for (var i = 0; i < WebSocket.__tasks.length; ++i) {
        WebSocket.__tasks[i]();
      }
      WebSocket.__tasks = [];
    }, 0);
  };

  /**
   * Called by Flash to notify WebSockets events are fired.
   */
  WebSocket.__onFlashEvent = function() {
    setTimeout(function() {
      try {
        // Gets events using receiveEvents() instead of getting it from event object
        // of Flash event. This is to make sure to keep message order.
        // It seems sometimes Flash events don't arrive in the same order as they are sent.
        var events = WebSocket.__flash.receiveEvents();
        for (var i = 0; i < events.length; ++i) {
          WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
        }
      } catch (e) {
        logger.error(e);
      }
    }, 0);
    return true;
  };

  // Called by Flash.
  WebSocket.__log = function(message) {
    logger.log(decodeURIComponent(message));
  };

  // Called by Flash.
  WebSocket.__error = function(message) {
    logger.error(decodeURIComponent(message));
  };

  WebSocket.__addTask = function(task) {
    if (WebSocket.__flash) {
      task();
    } else {
      WebSocket.__tasks.push(task);
    }
  };

  /**
   * Test if the browser is running flash lite.
   * @return {boolean} True if flash lite is running, false otherwise.
   */
  WebSocket.__isFlashLite = function() {
    if (!window.navigator || !window.navigator.mimeTypes) {
      return false;
    }
    var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
    if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {
      return false;
    }
    return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
  };

  if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
    if (window.addEventListener) {
      window.addEventListener("load", function(){
        WebSocket.__initialize();
      }, false);
    } else {
      window.attachEvent("onload", function(){
        WebSocket.__initialize();
      });
    }
  }

})();
<commit_msg>close() should cancel create task.<commit_after>// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
// License: New BSD License
// Reference: http://dev.w3.org/html5/websockets/
// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol

(function() {

  if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) return;

  var logger;
  if (window.WEB_SOCKET_LOGGER) {
    logger = WEB_SOCKET_LOGGER;
  } else if (window.console && window.console.log && window.console.error) {
    // In some environment, console is defined but console.log or console.error is missing.
    logger = window.console;
  } else {
    logger = {log: function(){ }, error: function(){ }};
  }

  // swfobject.hasFlashPlayerVersion("10.0.0") doesn't work with Gnash.
  if (swfobject.getFlashPlayerVersion().major < 10) {
    logger.error("Flash Player >= 10.0.0 is required.");
    return;
  }
  if (location.protocol == "file:") {
    logger.error(
      "WARNING: web-socket-js doesn't work in file:///... URL " +
      "unless you set Flash Security Settings properly. " +
      "Open the page via Web server i.e. http://...");
  }

  /**
   * This class represents a faux web socket.
   * @param {string} url
   * @param {array or string} protocols
   * @param {string} proxyHost
   * @param {int} proxyPort
   * @param {string} headers
   */
  WebSocket = function(url, protocols, proxyHost, proxyPort, headers) {
    var self = this;
    self.__id = WebSocket.__nextId++;
    WebSocket.__instances[self.__id] = self;
    self.readyState = WebSocket.CONNECTING;
    self.bufferedAmount = 0;
    self.__events = {};
    if (!protocols) {
      protocols = [];
    } else if (typeof protocols == "string") {
      protocols = [protocols];
    }
    // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
    // Otherwise, when onopen fires immediately, onopen is called before it is set.
    self.__createTask = setTimeout(function() {
      WebSocket.__addTask(function() {
        self.__createTask = null;
        WebSocket.__flash.create(
            self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null);
      });
    }, 0);
  };

  /**
   * Send data to the web socket.
   * @param {string} data  The data to send to the socket.
   * @return {boolean}  True for success, false for failure.
   */
  WebSocket.prototype.send = function(data) {
    if (this.readyState == WebSocket.CONNECTING) {
      throw "INVALID_STATE_ERR: Web Socket connection has not been established";
    }
    // We use encodeURIComponent() here, because FABridge doesn't work if
    // the argument includes some characters. We don't use escape() here
    // because of this:
    // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions
    // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
    // preserve all Unicode characters either e.g. "\uffff" in Firefox.
    // Note by wtritch: Hopefully this will not be necessary using ExternalInterface.  Will require
    // additional testing.
    var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
    if (result < 0) { // success
      return true;
    } else {
      this.bufferedAmount += result;
      return false;
    }
  };

  /**
   * Close this web socket gracefully.
   */
  WebSocket.prototype.close = function() {
    if (this.__createTask) {
        clearTimeout(this.__createTask);
        this.__createTask = null;
        this.readyState = WebSocket.CLOSED;
        return;
    }
    if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
      return;
    }
    this.readyState = WebSocket.CLOSING;
    WebSocket.__flash.close(this.__id);
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {string} type
   * @param {function} listener
   * @param {boolean} useCapture
   * @return void
   */
  WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
    if (!(type in this.__events)) {
      this.__events[type] = [];
    }
    this.__events[type].push(listener);
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {string} type
   * @param {function} listener
   * @param {boolean} useCapture
   * @return void
   */
  WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
    if (!(type in this.__events)) return;
    var events = this.__events[type];
    for (var i = events.length - 1; i >= 0; --i) {
      if (events[i] === listener) {
        events.splice(i, 1);
        break;
      }
    }
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {Event} event
   * @return void
   */
  WebSocket.prototype.dispatchEvent = function(event) {
    var events = this.__events[event.type] || [];
    for (var i = 0; i < events.length; ++i) {
      events[i](event);
    }
    var handler = this["on" + event.type];
    if (handler) handler(event);
  };

  /**
   * Handles an event from Flash.
   * @param {Object} flashEvent
   */
  WebSocket.prototype.__handleEvent = function(flashEvent) {
    if ("readyState" in flashEvent) {
      this.readyState = flashEvent.readyState;
    }
    if ("protocol" in flashEvent) {
      this.protocol = flashEvent.protocol;
    }

    var jsEvent;
    if (flashEvent.type == "open" || flashEvent.type == "error") {
      jsEvent = this.__createSimpleEvent(flashEvent.type);
    } else if (flashEvent.type == "close") {
      // TODO implement jsEvent.wasClean
      jsEvent = this.__createSimpleEvent("close");
    } else if (flashEvent.type == "message") {
      var data = decodeURIComponent(flashEvent.message);
      jsEvent = this.__createMessageEvent("message", data);
    } else {
      throw "unknown event type: " + flashEvent.type;
    }

    this.dispatchEvent(jsEvent);
  };

  WebSocket.prototype.__createSimpleEvent = function(type) {
    if (document.createEvent && window.Event) {
      var event = document.createEvent("Event");
      event.initEvent(type, false, false);
      return event;
    } else {
      return {type: type, bubbles: false, cancelable: false};
    }
  };

  WebSocket.prototype.__createMessageEvent = function(type, data) {
    if (document.createEvent && window.MessageEvent && !window.opera) {
      var event = document.createEvent("MessageEvent");
      event.initMessageEvent("message", false, false, data, null, null, window, null);
      return event;
    } else {
      // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
      return {type: type, data: data, bubbles: false, cancelable: false};
    }
  };

  /**
   * Define the WebSocket readyState enumeration.
   */
  WebSocket.CONNECTING = 0;
  WebSocket.OPEN = 1;
  WebSocket.CLOSING = 2;
  WebSocket.CLOSED = 3;

  WebSocket.__flash = null;
  WebSocket.__instances = {};
  WebSocket.__tasks = [];
  WebSocket.__nextId = 0;

  /**
   * Load a new flash security policy file.
   * @param {string} url
   */
  WebSocket.loadFlashPolicyFile = function(url){
    WebSocket.__addTask(function() {
      WebSocket.__flash.loadManualPolicyFile(url);
    });
  };

  /**
   * Loads WebSocketMain.swf and creates WebSocketMain object in Flash.
   */
  WebSocket.__initialize = function() {
    if (WebSocket.__flash) return;

    if (WebSocket.__swfLocation) {
      // For backword compatibility.
      window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
    }
    if (!window.WEB_SOCKET_SWF_LOCATION) {
      logger.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");
      return;
    }
    if (!window.WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR &&
        !WEB_SOCKET_SWF_LOCATION.match(/(^|\/)WebSocketMainInsecure\.swf(\?.*)?$/) &&
        WEB_SOCKET_SWF_LOCATION.match(/^\w+:\/\/([^\/]+)/)) {
      var swfHost = RegExp.$1;
      if (location.host != swfHost) {
        logger.error(
            "[WebSocket] You must host HTML and WebSocketMain.swf in the same host " +
            "('" + location.host + "' != '" + swfHost + "'). " +
            "See also 'How to host HTML file and SWF file in different domains' section " +
            "in README.md. If you use WebSocketMainInsecure.swf, you can suppress this message " +
            "by WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR = true;");
      }
    }
    var container = document.createElement("div");
    container.id = "webSocketContainer";
    // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents
    // Flash from loading at least in IE. So we move it out of the screen at (-100, -100).
    // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash
    // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is
    // the best we can do as far as we know now.
    container.style.position = "absolute";
    if (WebSocket.__isFlashLite()) {
      container.style.left = "0px";
      container.style.top = "0px";
    } else {
      container.style.left = "-100px";
      container.style.top = "-100px";
    }
    var holder = document.createElement("div");
    holder.id = "webSocketFlash";
    container.appendChild(holder);
    document.body.appendChild(container);
    // See this article for hasPriority:
    // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
    swfobject.embedSWF(
      WEB_SOCKET_SWF_LOCATION,
      "webSocketFlash",
      "1" /* width */,
      "1" /* height */,
      "10.0.0" /* SWF version */,
      null,
      null,
      {hasPriority: true, swliveconnect : true, allowScriptAccess: "always"},
      null,
      function(e) {
        if (!e.success) {
          logger.error("[WebSocket] swfobject.embedSWF failed");
        }
      });
  };

  /**
   * Called by Flash to notify JS that it's fully loaded and ready
   * for communication.
   */
  WebSocket.__onFlashInitialized = function() {
    // We need to set a timeout here to avoid round-trip calls
    // to flash during the initialization process.
    setTimeout(function() {
      WebSocket.__flash = document.getElementById("webSocketFlash");
      WebSocket.__flash.setCallerUrl(location.href);
      WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
      for (var i = 0; i < WebSocket.__tasks.length; ++i) {
        WebSocket.__tasks[i]();
      }
      WebSocket.__tasks = [];
    }, 0);
  };

  /**
   * Called by Flash to notify WebSockets events are fired.
   */
  WebSocket.__onFlashEvent = function() {
    setTimeout(function() {
      try {
        // Gets events using receiveEvents() instead of getting it from event object
        // of Flash event. This is to make sure to keep message order.
        // It seems sometimes Flash events don't arrive in the same order as they are sent.
        var events = WebSocket.__flash.receiveEvents();
        for (var i = 0; i < events.length; ++i) {
          WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
        }
      } catch (e) {
        logger.error(e);
      }
    }, 0);
    return true;
  };

  // Called by Flash.
  WebSocket.__log = function(message) {
    logger.log(decodeURIComponent(message));
  };

  // Called by Flash.
  WebSocket.__error = function(message) {
    logger.error(decodeURIComponent(message));
  };

  WebSocket.__addTask = function(task) {
    if (WebSocket.__flash) {
      task();
    } else {
      WebSocket.__tasks.push(task);
    }
  };

  /**
   * Test if the browser is running flash lite.
   * @return {boolean} True if flash lite is running, false otherwise.
   */
  WebSocket.__isFlashLite = function() {
    if (!window.navigator || !window.navigator.mimeTypes) {
      return false;
    }
    var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
    if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {
      return false;
    }
    return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
  };

  if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
    if (window.addEventListener) {
      window.addEventListener("load", function(){
        WebSocket.__initialize();
      }, false);
    } else {
      window.attachEvent("onload", function(){
        WebSocket.__initialize();
      });
    }
  }

})();
<|endoftext|>


<commit_before>'use strict';

const express = require('express');
const morgan = require('morgan');
const stylus = require('stylus');
const nib = require('nib');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const chalk = require('chalk');
const flash = require('connect-flash');
const expressSession = require('express-session');
const FileStore = require('session-file-store')(expressSession);

const auth = require('./auth/Authentication');
const routes = require('./routes/index');

const SESSION_COOKIE_MAX_AGE = 7 * 24 * 60 * 60 * 1000;

function setupStaticRouting(app) {
    app.use(express.static(__dirname + '/public'));
}

function setupDynamicRouting(app) {
    app.use('/', routes);
}

function setupViewEngine(app) {
    app.set('views', __dirname + '/views');
    app.set('view engine', 'jade');
}

function setupLogging(app) {
    app.use(morgan('dev'));
}

function setupStylus(app) {
    app.use(stylus.middleware({
        src: __dirname + '/public',
        compile: function (str, path) {
            return stylus(str)
                .set('filename', path)
                .use(nib());
        }
    }));
}

function loadSessionSecret() {
    try {
        const config = require('./config/config');
        if (config !== null && config.sessionSecret !== null) {
            return config.sessionSecret;
        } else {
            throw 'No session secret in config';
        }
    } catch (err) {
        console.error(chalk.red(chalk.bold('ERROR') + ': No session secret found in config: using default!'));
        return 'default secret for raspberry sauce';
    }
}

function setupAuthenticationMiddleware(app) {
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({
        extended: false
    }));
    app.use(cookieParser());
    const session = expressSession({
        cookie: {secure: false, maxAge: SESSION_COOKIE_MAX_AGE},
        secret: loadSessionSecret(),
        resave: false,
        rolling: true,
        saveUninitialized: false,
        store: new FileStore()
    });

    if (app.get('env') === 'production') {
      // app.set('trust proxy', 1) // trust first proxy
      session.cookie.secure = true; // serve secure cookies
    }

    app.use(session);

    auth.initialize(app);

    app.use(flash());
}

function createApp() {
    const app = express();

    setupViewEngine(app);
    setupLogging(app);
    setupStylus(app);
    setupAuthenticationMiddleware(app);
    setupStaticRouting(app);
    setupDynamicRouting(app);

    return app;
}

module.exports = {
    create: createApp
};
<commit_msg>disable secure cookies in test<commit_after>'use strict';

const express = require('express');
const morgan = require('morgan');
const stylus = require('stylus');
const nib = require('nib');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const chalk = require('chalk');
const flash = require('connect-flash');
const expressSession = require('express-session');
const FileStore = require('session-file-store')(expressSession);

const auth = require('./auth/Authentication');
const routes = require('./routes/index');

const SESSION_COOKIE_MAX_AGE = 7 * 24 * 60 * 60 * 1000;

function setupStaticRouting(app) {
    app.use(express.static(__dirname + '/public'));
}

function setupDynamicRouting(app) {
    app.use('/', routes);
}

function setupViewEngine(app) {
    app.set('views', __dirname + '/views');
    app.set('view engine', 'jade');
}

function setupLogging(app) {
    app.use(morgan('dev'));
}

function setupStylus(app) {
    app.use(stylus.middleware({
        src: __dirname + '/public',
        compile: function (str, path) {
            return stylus(str)
                .set('filename', path)
                .use(nib());
        }
    }));
}

function loadSessionSecret() {
    try {
        const config = require('./config/config');
        if (config !== null && config.sessionSecret !== null) {
            return config.sessionSecret;
        } else {
            throw 'No session secret in config';
        }
    } catch (err) {
        console.error(chalk.red(chalk.bold('ERROR') + ': No session secret found in config: using default!'));
        return 'default secret for raspberry sauce';
    }
}

function setupAuthenticationMiddleware(app) {
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({
        extended: false
    }));
    app.use(cookieParser());
    const session = expressSession({
        cookie: {secure: true, maxAge: SESSION_COOKIE_MAX_AGE},
        secret: loadSessionSecret(),
        resave: false,
        rolling: true,
        saveUninitialized: false,
        store: new FileStore()
    });

    if (app.get('env') === 'test') {
      session.cookie.secure = false; // dont serve secure cookies, allows login over http
    }

    app.use(session);

    auth.initialize(app);

    app.use(flash());
}

function createApp() {
    const app = express();

    setupViewEngine(app);
    setupLogging(app);
    setupStylus(app);
    setupAuthenticationMiddleware(app);
    setupStaticRouting(app);
    setupDynamicRouting(app);

    return app;
}

module.exports = {
    create: createApp
};
<|endoftext|>


<commit_before>$(document).ready(function(){
	$('.add_cart').click(function(event){
		event.preventDefault();
		var id = $(this).data('id');

		$.post(urlAddCart, {'id': id}, function(res){
			console.log(res);
			refreshCartItem();
			$('#notif').slideDown('fast').delay(1500).slideUp('fast');
		});
	});

	$('.delete_cart').click(function(event){
		event.preventDefault();
		var id = $(this).data('id');
		var url = $(this).attr('href');
		var line = $(this).parent().parent();

		$.post(url, {'id': id}, function(res){
			console.log(res);
			line.remove();
			refreshCartItem();
		})
	});

	$('.cart_quantity').change(function(){
		var line = $(this).parent().parent();
		var url = $(this).data('url');
		var id = $(this).data('id');
		var val = $(this).val();

		if(val < 0){
			$(this).val(1);
			val = 1;
		}

		$.post(url, {'id': id, 'qty': $(this).val()}, function(res){
			console.log(res);
			var data = JSON.parse(res);
			line.find('.total').html(data.total);
			refreshCartItem();
		});
	});

	$('.sort_select').change(function(){
		var url = $(this).val();

		window.location = url;
	});

    $('.use_prev').click(function(){
        if($(this).is(':Checked')) {
            $(this).parent().parent().attr('novalidate', 'novalidate');
        }
        else {
            $(this).parent().parent().removeAttr('novalidate');
        }
    });

    $('.hide_option').click(function(event){
    	event.preventDefault();

    	$(this).parent().parent().find('.filter_bottom').slideToggle();
    })

	function refreshCartItem() {
		var _countCartItem = $('.countCartItem');

		$.get(urlCountCartItem, {},function(res){
			console.log(res);
			var data = JSON.parse(res);
			_countCartItem.html(data.quantity);
		});
	}
});<commit_msg>fix bug qty<commit_after>$(document).ready(function(){
	$('.add_cart').click(function(event){
		event.preventDefault();
		var id = $(this).data('id');

		$.post(urlAddCart, {'id': id}, function(res){
			console.log(res);
			refreshCartItem();
			$('#notif').slideDown('fast').delay(1500).slideUp('fast');
		});
	});

	$('.delete_cart').click(function(event){
		event.preventDefault();
		var id = $(this).data('id');
		var url = $(this).attr('href');
		var line = $(this).parent().parent();

		$.post(url, {'id': id}, function(res){
			console.log(res);
			line.remove();
			refreshCartItem();
		})
	});

	$('.cart_quantity').change(function(){
		var line = $(this).parent().parent();
		var url = $(this).data('url');
		var id = $(this).data('id');
		var val = $(this).val();

		if(val <= 0){
			$(this).val(1);
			val = 1;
		}

		$.post(url, {'id': id, 'qty': $(this).val()}, function(res){
			console.log(res);
			var data = JSON.parse(res);
			line.find('.total').html(data.total);
			refreshCartItem();
		});
	});

	$('.sort_select').change(function(){
		var url = $(this).val();

		window.location = url;
	});

    $('.use_prev').click(function(){
        if($(this).is(':Checked')) {
            $(this).parent().parent().attr('novalidate', 'novalidate');
        }
        else {
            $(this).parent().parent().removeAttr('novalidate');
        }
    });

    $('.hide_option').click(function(event){
    	event.preventDefault();

    	$(this).parent().parent().find('.filter_bottom').slideToggle();
    })

	function refreshCartItem() {
		var _countCartItem = $('.countCartItem');

		$.get(urlCountCartItem, {},function(res){
			console.log(res);
			var data = JSON.parse(res);
			_countCartItem.html(data.quantity);
		});
	}
});<|endoftext|>


<commit_before>Array.prototype.flatMap = function(lambda) {
    return Array.prototype.concat.apply([], this.map(lambda));
};<commit_msg>Removed unused file<commit_after><|endoftext|>


<commit_before>import {danger, fail, warn, message} from 'danger'
import {readFileSync} from 'fs'
import dedent from 'dedent'
const readFile = filename => {
  try {
    return readFileSync(filename, 'utf-8')
  } catch (err) {
    return err.message
  }
}

const jsFiles = danger.git.created_files.filter(path => path.endsWith('.js'))

// new js files should have `@flow` at the top
// jsFiles
//   .filter(filepath => {
//     const content = readFile(filepath)
//     return !content.includes('@flow')
//   })
//   .forEach(file => warn(`<code>${file}</code> has no <code>@flow</code> annotation!`))

// revisit this when we move to yarn
// const packageChanged = danger.git.modified_files.includes('package.json')
// const lockfileChanged = danger.git.modified_files.includes('yarn.lock')
// if (packageChanged && !lockfileChanged) {
//   const message = 'Changes were made to package.json, but not to yarn.lock'
//   const idea = 'Perhaps you need to run yarn install?'
//   warn(`${message} - <i>${idea}</i>`)
// }

// Be careful of leaving testing shortcuts in the codebase
// jsFiles
//   .filter(filepath => filepath.endsWith('test.js'))
//   .filter(filepath => {
//     const content = readFile(filepath)
//     return content.includes('it.only') || content.includes('describe.only')
//   })
//   .forEach(file =>
//     warn(`An <code>only</code> was left in ${file} – no other tests can run.`))

// Warn when PR size is large (mainly for hawken)
const bigPRThreshold = 400 // lines
const thisPRSize = danger.github.pr.additions + danger.github.pr.deletions
if (thisPRSize > bigPRThreshold) {
  warn(
    dedent`

      :exclamation: Big PR!

We like to try and keep PRs under ${bigPRThreshold} lines per PR, and this one was ${thisPRSize} lines.

If the PR contains multiple logical changes, splitting each change into a separate PR will allow a faster, easier, and more thorough review.

  `,
  )
}

//
// Check for and report errors from our tools
//
const isBadBundleLog = log => {
  const allLines = log.split('\n')
  const requiredLines = [
    'bundle: start',
    'bundle: finish',
    'bundle: Done writing bundle output',
    'bundle: Done copying assets',
  ]
  return requiredLines.some(line => !allLines.includes(line))
}

const fileLog = (name, log, lang = null) => {
  message(
    dedent`

      ${name}

\`\`\`${lang || ''}
${log}
\`\`\`

  `,
  )
}

const eslintLog = readFile('logs/eslint').trim()
const dataValidationLog = readFile('logs/validate-data').trim()
const flowLog = readFile('logs/flow').trim()
const iosJsBundleLog = readFile('logs/bundle-ios').trim()
const androidJsBundleLog = readFile('logs/bundle-android').trim()
const jestLog = readFile('logs/jest').trim()

if (eslintLog) {
  fileLog('Eslint had a thing to say!', eslintLog)
}

const dataHadIssues = dataValidationLog &&
  dataValidationLog.split('\n').some(l => !l.endsWith('is valid'))
if (dataHadIssues) {
  fileLog("Something's up with the data.", dataValidationLog)
}

if (flowLog !== 'Found 0 errors') {
  fileLog('Flow would like to interject about types…', flowLog)
}

if (iosJsBundleLog && isBadBundleLog(iosJsBundleLog)) {
  fileLog('The iOS bundle ran into an issue.', iosJsBundleLog)
}

if (androidJsBundleLog && isBadBundleLog(androidJsBundleLog)) {
  fileLog('The Android bundle ran into an issue.', androidJsBundleLog)
}

if (jestLog && jestLog.includes('FAIL')) {
  const lines = jestLog.split('\n')
  const startIndex = lines.findIndex(l =>
    l.includes('Summary of all failing tests'))

  fileLog(
    'Some Jest tests failed. Take a peek?',
    lines.slice(startIndex).join('\n'),
  )
}
<commit_msg>Revert "Update dangerfile.js"<commit_after>import {danger, fail, warn, message} from 'danger'
import {readFileSync} from 'fs'
import dedent from 'dedent'
const readFile = filename => {
  try {
    return readFileSync(filename, 'utf-8')
  } catch (err) {
    return err.message
  }
}

const jsFiles = danger.git.created_files.filter(path => path.endsWith('.js'))

// new js files should have `@flow` at the top
jsFiles
  .filter(filepath => {
    const content = readFile(filepath)
    return !content.includes('@flow')
  })
  .forEach(file => warn(`<code>${file}</code> has no <code>@flow</code> annotation!`))

// revisit this when we move to yarn
// const packageChanged = danger.git.modified_files.includes('package.json')
// const lockfileChanged = danger.git.modified_files.includes('yarn.lock')
// if (packageChanged && !lockfileChanged) {
//   const message = 'Changes were made to package.json, but not to yarn.lock'
//   const idea = 'Perhaps you need to run yarn install?'
//   warn(`${message} - <i>${idea}</i>`)
// }

// Be careful of leaving testing shortcuts in the codebase
jsFiles
  .filter(filepath => filepath.endsWith('test.js'))
  .filter(filepath => {
    const content = readFile(filepath)
    return content.includes('it.only') || content.includes('describe.only')
  })
  .forEach(file =>
    warn(`An <code>only</code> was left in ${file} – no other tests can run.`))

// Warn when PR size is large (mainly for hawken)
const bigPRThreshold = 400 // lines
const thisPRSize = danger.github.pr.additions + danger.github.pr.deletions
if (thisPRSize > bigPRThreshold) {
  warn(
    dedent`

      :exclamation: Big PR!

We like to try and keep PRs under ${bigPRThreshold} lines per PR, and this one was ${thisPRSize} lines.

If the PR contains multiple logical changes, splitting each change into a separate PR will allow a faster, easier, and more thorough review.

  `,
  )
}

//
// Check for and report errors from our tools
//
const isBadBundleLog = log => {
  const allLines = log.split('\n')
  const requiredLines = [
    'bundle: start',
    'bundle: finish',
    'bundle: Done writing bundle output',
    'bundle: Done copying assets',
  ]
  return requiredLines.some(line => !allLines.includes(line))
}

const fileLog = (name, log, lang = null) => {
  message(
    dedent`

      ${name}

\`\`\`${lang || ''}
${log}
\`\`\`

  `,
  )
}

const eslintLog = readFile('logs/eslint').trim()
const dataValidationLog = readFile('logs/validate-data').trim()
const flowLog = readFile('logs/flow').trim()
const iosJsBundleLog = readFile('logs/bundle-ios').trim()
const androidJsBundleLog = readFile('logs/bundle-android').trim()
const jestLog = readFile('logs/jest').trim()

if (eslintLog) {
  fileLog('Eslint had a thing to say!', eslintLog)
}

const dataHadIssues = dataValidationLog &&
  dataValidationLog.split('\n').some(l => !l.endsWith('is valid'))
if (dataHadIssues) {
  fileLog("Something's up with the data.", dataValidationLog)
}

if (flowLog !== 'Found 0 errors') {
  fileLog('Flow would like to interject about types…', flowLog)
}

if (iosJsBundleLog && isBadBundleLog(iosJsBundleLog)) {
  fileLog('The iOS bundle ran into an issue.', iosJsBundleLog)
}

if (androidJsBundleLog && isBadBundleLog(androidJsBundleLog)) {
  fileLog('The Android bundle ran into an issue.', androidJsBundleLog)
}

if (jestLog && jestLog.includes('FAIL')) {
  const lines = jestLog.split('\n')
  const startIndex = lines.findIndex(l =>
    l.includes('Summary of all failing tests'))

  fileLog(
    'Some Jest tests failed. Take a peek?',
    lines.slice(startIndex).join('\n'),
  )
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

'use strict';

/* eslint-disable no-for-of-loops/no-for-of-loops */

// Hi, if this is your first time editing/reading a Dangerfile, here's a summary:
// It's a JS runtime which helps you provide continuous feedback inside GitHub.
//
// You can see the docs here: http://danger.systems/js/
//
// If you want to test changes Danger, I'd recommend checking out an existing PR
// and then running the `danger pr` command.
//
// You'll need a GitHub token, you can re-use this one:
//
//  0a7d5c3cad9a6dbec2d9 9a5222cf49062a4c1ef7
//
// (Just remove the space)
//
// So, for example:
//
// `DANGER_GITHUB_API_TOKEN=[ENV_ABOVE] yarn danger pr https://github.com/facebook/react/pull/11865

const {markdown, danger, warn} = require('danger');
const {promisify} = require('util');
const glob = promisify(require('glob'));
const gzipSize = require('gzip-size');

const {readFileSync, statSync} = require('fs');

const BASE_DIR = 'base-build';
const HEAD_DIR = 'build';

const CRITICAL_THRESHOLD = 0.02;
const SIGNIFICANCE_THRESHOLD = 0.002;
const CRITICAL_ARTIFACT_PATHS = new Set([
  // We always report changes to these bundles, even if the change is
  // insignificant or non-existent.
  'oss-stable/react-dom/cjs/react-dom.production.min.js',
  'oss-experimental/react-dom/cjs/react-dom.production.min.js',
  'facebook-www/ReactDOM-prod.classic.js',
  'facebook-www/ReactDOM-prod.modern.js',
  'facebook-www/ReactDOMForked-prod.classic.js',
]);

const kilobyteFormatter = new Intl.NumberFormat('en', {
  style: 'unit',
  unit: 'kilobyte',
  minimumFractionDigits: 2,
  maximumFractionDigits: 2,
});

function kbs(bytes) {
  return kilobyteFormatter.format(bytes / 1000);
}

const percentFormatter = new Intl.NumberFormat('en', {
  style: 'percent',
  signDisplay: 'exceptZero',
  minimumFractionDigits: 2,
  maximumFractionDigits: 2,
});

function change(decimal) {
  if (Number === Infinity) {
    return 'New file';
  }
  if (decimal === -1) {
    return 'Deleted';
  }
  if (decimal < 0.0001) {
    return '=';
  }
  return percentFormatter.format(decimal);
}

const header = `
  | Name | +/- | Base | Current | +/- gzip | Base gzip | Current gzip |
  | ---- | --- | ---- | ------- | -------- | --------- | ------------ |`;

function row(result) {
  // prettier-ignore
  return `| ${result.path} | **${change(result.change)}** | ${kbs(result.baseSize)} | ${kbs(result.headSize)} | ${change(result.changeGzip)} | ${kbs(result.baseSizeGzip)} | ${kbs(result.headSizeGzip)}`;
}

(async function() {
  // Use git locally to grab the commit which represents the place
  // where the branches differ

  const upstreamRepo = danger.github.pr.base.repo.full_name;
  if (upstreamRepo !== 'facebook/react') {
    // Exit unless we're running in the main repo
    return;
  }

  let headSha;
  let baseSha;
  try {
    headSha = String(readFileSync(HEAD_DIR + '/COMMIT_SHA')).trim();
    baseSha = String(readFileSync(BASE_DIR + '/COMMIT_SHA')).trim();
  } catch {
    warn(
      "Failed to read build artifacts. It's possible a build configuration " +
        'has changed upstream. Try pulling the latest changes from the ' +
        'main branch.'
    );
    return;
  }

  // Disable sizeBot in a Devtools Pull Request. Because that doesn't affect production bundle size.
  const commitFiles = [
    ...danger.git.created_files,
    ...danger.git.deleted_files,
    ...danger.git.modified_files,
  ];
  if (
    commitFiles.every(filename => filename.includes('packages/react-devtools'))
  )
    return;

  const resultsMap = new Map();

  // Find all the head (current) artifacts paths.
  const headArtifactPaths = await glob('**/*.js', {cwd: 'build'});
  for (const artifactPath of headArtifactPaths) {
    try {
      // This will throw if there's no matching base artifact
      const baseSize = statSync(BASE_DIR + '/' + artifactPath).size;
      const baseSizeGzip = gzipSize.fileSync(BASE_DIR + '/' + artifactPath);

      const headSize = statSync(HEAD_DIR + '/' + artifactPath).size;
      const headSizeGzip = gzipSize.fileSync(HEAD_DIR + '/' + artifactPath);
      resultsMap.set(artifactPath, {
        path: artifactPath,
        headSize,
        headSizeGzip,
        baseSize,
        baseSizeGzip,
        change: (headSize - baseSize) / baseSize,
        changeGzip: (headSizeGzip - baseSizeGzip) / baseSizeGzip,
      });
    } catch {
      // There's no matching base artifact. This is a new file.
      const baseSize = 0;
      const baseSizeGzip = 0;
      const headSize = statSync(HEAD_DIR + '/' + artifactPath).size;
      const headSizeGzip = gzipSize.fileSync(HEAD_DIR + '/' + artifactPath);
      resultsMap.set(artifactPath, {
        path: artifactPath,
        headSize,
        headSizeGzip,
        baseSize,
        baseSizeGzip,
        change: Infinity,
        changeGzip: Infinity,
      });
    }
  }

  // Check for base artifacts that were deleted in the head.
  const baseArtifactPaths = await glob('**/*.js', {cwd: 'base-build'});
  for (const artifactPath of baseArtifactPaths) {
    if (!resultsMap.has(artifactPath)) {
      const baseSize = statSync(BASE_DIR + '/' + artifactPath).size;
      const baseSizeGzip = gzipSize.fileSync(BASE_DIR + '/' + artifactPath);
      const headSize = 0;
      const headSizeGzip = 0;
      resultsMap.set(artifactPath, {
        path: artifactPath,
        headSize,
        headSizeGzip,
        baseSize,
        baseSizeGzip,
        change: -1,
        changeGzip: -1,
      });
    }
  }

  const results = Array.from(resultsMap.values());
  results.sort((a, b) => b.change - a.change);

  let criticalResults = [];
  for (const artifactPath of CRITICAL_ARTIFACT_PATHS) {
    const result = resultsMap.get(artifactPath);
    if (result === undefined) {
      throw new Error(
        'Missing expected bundle. If this was an intentional change to the ' +
          'build configuration, update Dangerfile.js accordingly: ' +
          artifactPath
      );
    }
    criticalResults.push(row(result));
  }

  let significantResults = [];
  for (const result of results) {
    // If result exceeds critical threshold, add to top section.
    if (
      (result.change > CRITICAL_THRESHOLD ||
        0 - result.change > CRITICAL_THRESHOLD ||
        // New file
        result.change === Infinity ||
        // Deleted file
        result.change === -1) &&
      // Skip critical artifacts. We added those earlier, in a fixed order.
      !CRITICAL_ARTIFACT_PATHS.has(result.path)
    ) {
      criticalResults.push(row(result));
    }

    // Do the same for results that exceed the significant threshold. These
    // will go into the bottom, collapsed section. Intentionally including
    // critical artifacts in this section, too.
    if (
      result.change > SIGNIFICANCE_THRESHOLD ||
      0 - result.change > SIGNIFICANCE_THRESHOLD ||
      result.change === Infinity ||
      result.change === -1
    ) {
      significantResults.push(row(result));
    }
  }

  markdown(`
Comparing: ${baseSha}...${headSha}

## Critical size changes

Includes critical production bundles, as well as any change greater than ${CRITICAL_THRESHOLD *
    100}%:

${header}
${criticalResults.join('\n')}

## Significant size changes

Includes any change greater than ${SIGNIFICANCE_THRESHOLD * 100}%:

${
  significantResults.length > 0
    ? `

Expand to show
${header}
${significantResults.join('\n')}

`
    : '(No significant changes)'
}
`);
})();
<commit_msg>[sizebot] Add link to diff view (#24790)<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

'use strict';

/* eslint-disable no-for-of-loops/no-for-of-loops */

// Hi, if this is your first time editing/reading a Dangerfile, here's a summary:
// It's a JS runtime which helps you provide continuous feedback inside GitHub.
//
// You can see the docs here: http://danger.systems/js/
//
// If you want to test changes Danger, I'd recommend checking out an existing PR
// and then running the `danger pr` command.
//
// You'll need a GitHub token, you can re-use this one:
//
//  0a7d5c3cad9a6dbec2d9 9a5222cf49062a4c1ef7
//
// (Just remove the space)
//
// So, for example:
//
// `DANGER_GITHUB_API_TOKEN=[ENV_ABOVE] yarn danger pr https://github.com/facebook/react/pull/11865

const {markdown, danger, warn} = require('danger');
const {promisify} = require('util');
const glob = promisify(require('glob'));
const gzipSize = require('gzip-size');

const {readFileSync, statSync} = require('fs');

const BASE_DIR = 'base-build';
const HEAD_DIR = 'build';

const CRITICAL_THRESHOLD = 0.02;
const SIGNIFICANCE_THRESHOLD = 0.002;
const CRITICAL_ARTIFACT_PATHS = new Set([
  // We always report changes to these bundles, even if the change is
  // insignificant or non-existent.
  'oss-stable/react-dom/cjs/react-dom.production.min.js',
  'oss-experimental/react-dom/cjs/react-dom.production.min.js',
  'facebook-www/ReactDOM-prod.classic.js',
  'facebook-www/ReactDOM-prod.modern.js',
  'facebook-www/ReactDOMForked-prod.classic.js',
]);

const kilobyteFormatter = new Intl.NumberFormat('en', {
  style: 'unit',
  unit: 'kilobyte',
  minimumFractionDigits: 2,
  maximumFractionDigits: 2,
});

function kbs(bytes) {
  return kilobyteFormatter.format(bytes / 1000);
}

const percentFormatter = new Intl.NumberFormat('en', {
  style: 'percent',
  signDisplay: 'exceptZero',
  minimumFractionDigits: 2,
  maximumFractionDigits: 2,
});

function change(decimal) {
  if (Number === Infinity) {
    return 'New file';
  }
  if (decimal === -1) {
    return 'Deleted';
  }
  if (decimal < 0.0001) {
    return '=';
  }
  return percentFormatter.format(decimal);
}

const header = `
  | Name | +/- | Base | Current | +/- gzip | Base gzip | Current gzip |
  | ---- | --- | ---- | ------- | -------- | --------- | ------------ |`;

function row(result, baseSha, headSha) {
  const diffViewUrl = `https://react-builds.vercel.app/commits/${headSha}/files/${result.path}?compare=${baseSha}`;
  // prettier-ignore
  return `| [${result.path}](${diffViewUrl}) | **${change(result.change)}** | ${kbs(result.baseSize)} | ${kbs(result.headSize)} | ${change(result.changeGzip)} | ${kbs(result.baseSizeGzip)} | ${kbs(result.headSizeGzip)}`;
}

(async function() {
  // Use git locally to grab the commit which represents the place
  // where the branches differ

  const upstreamRepo = danger.github.pr.base.repo.full_name;
  if (upstreamRepo !== 'facebook/react') {
    // Exit unless we're running in the main repo
    return;
  }

  let headSha;
  let baseSha;
  try {
    headSha = String(readFileSync(HEAD_DIR + '/COMMIT_SHA')).trim();
    baseSha = String(readFileSync(BASE_DIR + '/COMMIT_SHA')).trim();
  } catch {
    warn(
      "Failed to read build artifacts. It's possible a build configuration " +
        'has changed upstream. Try pulling the latest changes from the ' +
        'main branch.'
    );
    return;
  }

  // Disable sizeBot in a Devtools Pull Request. Because that doesn't affect production bundle size.
  const commitFiles = [
    ...danger.git.created_files,
    ...danger.git.deleted_files,
    ...danger.git.modified_files,
  ];
  if (
    commitFiles.every(filename => filename.includes('packages/react-devtools'))
  )
    return;

  const resultsMap = new Map();

  // Find all the head (current) artifacts paths.
  const headArtifactPaths = await glob('**/*.js', {cwd: 'build'});
  for (const artifactPath of headArtifactPaths) {
    try {
      // This will throw if there's no matching base artifact
      const baseSize = statSync(BASE_DIR + '/' + artifactPath).size;
      const baseSizeGzip = gzipSize.fileSync(BASE_DIR + '/' + artifactPath);

      const headSize = statSync(HEAD_DIR + '/' + artifactPath).size;
      const headSizeGzip = gzipSize.fileSync(HEAD_DIR + '/' + artifactPath);
      resultsMap.set(artifactPath, {
        path: artifactPath,
        headSize,
        headSizeGzip,
        baseSize,
        baseSizeGzip,
        change: (headSize - baseSize) / baseSize,
        changeGzip: (headSizeGzip - baseSizeGzip) / baseSizeGzip,
      });
    } catch {
      // There's no matching base artifact. This is a new file.
      const baseSize = 0;
      const baseSizeGzip = 0;
      const headSize = statSync(HEAD_DIR + '/' + artifactPath).size;
      const headSizeGzip = gzipSize.fileSync(HEAD_DIR + '/' + artifactPath);
      resultsMap.set(artifactPath, {
        path: artifactPath,
        headSize,
        headSizeGzip,
        baseSize,
        baseSizeGzip,
        change: Infinity,
        changeGzip: Infinity,
      });
    }
  }

  // Check for base artifacts that were deleted in the head.
  const baseArtifactPaths = await glob('**/*.js', {cwd: 'base-build'});
  for (const artifactPath of baseArtifactPaths) {
    if (!resultsMap.has(artifactPath)) {
      const baseSize = statSync(BASE_DIR + '/' + artifactPath).size;
      const baseSizeGzip = gzipSize.fileSync(BASE_DIR + '/' + artifactPath);
      const headSize = 0;
      const headSizeGzip = 0;
      resultsMap.set(artifactPath, {
        path: artifactPath,
        headSize,
        headSizeGzip,
        baseSize,
        baseSizeGzip,
        change: -1,
        changeGzip: -1,
      });
    }
  }

  const results = Array.from(resultsMap.values());
  results.sort((a, b) => b.change - a.change);

  let criticalResults = [];
  for (const artifactPath of CRITICAL_ARTIFACT_PATHS) {
    const result = resultsMap.get(artifactPath);
    if (result === undefined) {
      throw new Error(
        'Missing expected bundle. If this was an intentional change to the ' +
          'build configuration, update Dangerfile.js accordingly: ' +
          artifactPath
      );
    }
    criticalResults.push(row(result, baseSha, headSha));
  }

  let significantResults = [];
  for (const result of results) {
    // If result exceeds critical threshold, add to top section.
    if (
      (result.change > CRITICAL_THRESHOLD ||
        0 - result.change > CRITICAL_THRESHOLD ||
        // New file
        result.change === Infinity ||
        // Deleted file
        result.change === -1) &&
      // Skip critical artifacts. We added those earlier, in a fixed order.
      !CRITICAL_ARTIFACT_PATHS.has(result.path)
    ) {
      criticalResults.push(row(result, baseSha, headSha));
    }

    // Do the same for results that exceed the significant threshold. These
    // will go into the bottom, collapsed section. Intentionally including
    // critical artifacts in this section, too.
    if (
      result.change > SIGNIFICANCE_THRESHOLD ||
      0 - result.change > SIGNIFICANCE_THRESHOLD ||
      result.change === Infinity ||
      result.change === -1
    ) {
      significantResults.push(row(result, baseSha, headSha));
    }
  }

  markdown(`
Comparing: ${baseSha}...${headSha}

## Critical size changes

Includes critical production bundles, as well as any change greater than ${CRITICAL_THRESHOLD *
    100}%:

${header}
${criticalResults.join('\n')}

## Significant size changes

Includes any change greater than ${SIGNIFICANCE_THRESHOLD * 100}%:

${
  significantResults.length > 0
    ? `

Expand to show
${header}
${significantResults.join('\n')}

`
    : '(No significant changes)'
}
`);
})();
<|endoftext|>


<commit_before>Ext4.define('Kwf.Ext4.App.MainController', {
    extend: 'Ext.app.Controller',
    $namespace: 'App',
    requires: [
        'Ext.state.LocalStorageProvider',
        'Ext.state.Manager',
        'Kwf.Ext4.Viewport'
    ],
    mainPanel: null,
    onLaunch: function()
    {
        if (!this.mainPanel || !this.mainPanel instanceof Ext4.panel.Panel) {
            throw new Error("mainPanel is required and must be an Ext4.panel.Panel");
        }
        Ext4.create('Kwf.Ext4.Viewport', {
            items: [this.mainPanel]
        });
    },

    init: function()
    {
        if (Ext4.supports.LocalStorage) {
            Ext4.state.Manager.setProvider(new Ext4.state.LocalStorageProvider());
        }
        Ext4.Ajax.disableCaching = false;
        if (!Ext4.Ajax.extraParams) Ext4.Ajax.extraParams = {};
        if (Kwf.sessionToken) Ext4.Ajax.extraParams.kwfSessionToken = Kwf.sessionToken;
        Ext4.Ajax.extraParams.applicationAssetsVersion = Kwf.application.assetsVersion;
    }
});
<commit_msg>handle server side errors for all ext4 requeasts<commit_after>Ext4.define('Kwf.Ext4.App.MainController', {
    extend: 'Ext.app.Controller',
    $namespace: 'App',
    requires: [
        'Ext.state.LocalStorageProvider',
        'Ext.state.Manager',
        'Kwf.Ext4.Viewport'
    ],
    mainPanel: null,
    onLaunch: function()
    {
        if (!this.mainPanel || !this.mainPanel instanceof Ext4.panel.Panel) {
            throw new Error("mainPanel is required and must be an Ext4.panel.Panel");
        }
        Ext4.create('Kwf.Ext4.Viewport', {
            items: [this.mainPanel]
        });
    },

    init: function()
    {
        if (Ext4.supports.LocalStorage) {
            Ext4.state.Manager.setProvider(new Ext4.state.LocalStorageProvider());
        }
        Ext4.Ajax.disableCaching = false;
        if (!Ext4.Ajax.extraParams) Ext4.Ajax.extraParams = {};
        if (Kwf.sessionToken) Ext4.Ajax.extraParams.kwfSessionToken = Kwf.sessionToken;
        Ext4.Ajax.extraParams.applicationAssetsVersion = Kwf.application.assetsVersion;
        Ext4.Ajax.on('requestexception', this.onAjaxRequestException, this);
    },

    onAjaxRequestException: function(conn, response, options)
    {
        var r = Ext4.decode(response.responseText, true);
        if (response.status == 401) {
            var msg = trlKwf('Please Login');
            if (r && r.role && r.role != 'guest') {
                msg = trlKwf("You don't have enough permissions for this Action");
            }
            Ext4.Msg.alert(trlKwf('Login'), msg, function() {
                location.reload();
            })
        } else if (response.status == 428) {
            var dlg = new Ext4.window.Window({
                autoCreate : true,
                title: trlKwf('Error - wrong version'),
                resizable: false,
                modal: true,
                buttonAlign: 'center',
                bodyPadding: 20,
                plain: true,
                closable: false,
                html: trlKwf('Because of an application update the application has to be reloaded.'),
                buttons: [{
                    text: trlKwf('OK'),
                    handler: function() {
                        location.reload();
                    },
                    scope: this
                }]
            });
            dlg.show();
        } else {
            Ext4.Msg.alert(trlKwf('Error'), trlKwf('A Server failure occured.'));
        }
    }
});
<|endoftext|>


<commit_before>/**
 *
 * @author Andriy Oblivantsev <eslider@gmail.com>
 * @copyright 05.04.15 by WhereGroup GmbH & Co. KG
 */
(function($){

    function has (obj, key){
        return typeof obj[key] !== 'undefined';
    }

    $.widget('mapbender.generateElements', {
        options: {},
        declarations:{
            'input':{
                init: function(item,declarations) {
                    var inputField = $('<input class="form-control"/>');
                    var container = $('
');

                    if(has(item, 'name')) {
                        inputField.attr('name',item.name);
                    }

                    if(has(item, 'placeholder')) {
                        inputField.attr('placeholder',item.placeholder);
                    }

                    if(has(item,'value')){
                        inputField.val(item.value);
                    }

                    console.log(declarations);
                    if(has(inputField,'text')){
                        container.append(declarations.label.init(item,declarations));
                    }

                    container.append(inputField);

                    return container;
                }
            },
            label:{
                init: function(item){
                    var label = $('');
                    if(_.has(item,'text')){
                        label.html(item.text);
                    }
                    if(_.has(item,'name')){
                        label.attr('for',item.name);
                    }
                    return label;
                }
            },
            'form-group':{
                init: function(){
                    return;
                }
            }

        },
        _create: function() {
            this._setOptions(this.options);
        },

        _setOption: function( key, value ) {

            var element = $(this.element);
            var widget = this;
            if(key === "items") {
                $.each(value, function() {
                    var item = this;
                    if(!has(widget.declarations, item.type)) {
                        return;
                    }
                    var declaration = widget.declarations[item.type];
                    element.append(declaration.init(item, widget.declarations));
                    element.data('item', item);
                })
            }

            this._super( key, value );
        },
        _setOptions: function( options ) {
            this._super( options );
            this.refresh();
        },
        refresh: function() {
            this._trigger('refresh');
        }
    });

    var popup = $("
").popupDialog();

    popup.generateElements({
        items: [ {
            type: 'label', //value:       'test',
            text: 'HE-HE'
        },{
            type: 'label',
            text: 'Name'
        }, {type: 'submit'}, {
            type:        'input', //value:       'test',
            name:        'name',
            text:        'Name',
            placeholder: 'Enter your name'
        }, {type: 'submit'}, {
            type:        'input', //value:       'test',
            name:        'Nachname',
            text:        'Nachname',
            placeholder: 'Nachname'
        }, {type: 'submit'}, {type: 'submit'}, {
            type:        'input', //value:       'test',
            name:        'email',
            text:        'E-Mail',
            placeholder: 'eslider@gmail.com'
        }, {type: 'submit'}]
    });

    //console.log("TEST");
})(jQuery);
<commit_msg>add input, button, html elements generation to html.js<commit_after>/**
 *
 * @author Andriy Oblivantsev <eslider@gmail.com>
 * @copyright 05.04.15 by WhereGroup GmbH & Co. KG
 */
(function($){

    /**
     * Check if object has a key
     *
     * @param obj
     * @param key
     * @returns {boolean}
     */
    function has (obj, key){
        return typeof obj[key] !== 'undefined';
    }

    /**
     * Add jquery events to element by declration
     *
     * @param element
     * @param declaration
     */
    function addEvents(element, declaration) {
        $.each(declaration, function(k, value) {
            if(typeof value == 'function') {
                element.on(k, value);
            }
        });
    }

    $.widget('mapbender.generateElements', {
        options:      {},
        declarations: {
            html:   {
                init: function(item) {
                    var container = $('
');
                    return container.html(typeof item === 'string' ? item : JSON.stringify(item));
                }
            },
            button: {
                init: function(item, declarations) {
                    var title = has(item, 'title') ? item.title : 'Submit';
                    var button = $('<button class="btn button">' + title + '</button>');
                    addEvents(button, item);
                    return button;
                }
            },
            submit: {
                init: function(item, declarations) {
                    var button = declarations.button.init(item, declarations);
                    button.attr('type', 'submit');
                    return button;
                }
            },
            input:  {
                init: function(item, declarations) {
                    var inputField = $('<input class="form-control"/>');
                    var container = $('
');

                    if(has(item, 'name')) {
                        inputField.attr('name', item.name);
                    }

                    if(has(item, 'placeholder')) {
                        inputField.attr('placeholder', item.placeholder);
                    }

                    if(has(item, 'value')) {
                        inputField.val(item.value);
                    }

                    if(has(inputField, 'text')) {
                        container.append(declarations.label.init(item, declarations));
                    }

                    container.append(inputField);

                    return container;
                }
            },
            label:{
                init: function(item){
                    var label = $('');
                    if(_.has(item,'text')){
                        label.html(item.text);
                    }
                    if(_.has(item,'name')){
                        label.attr('for',item.name);
                    }
                    return label;
                }
            },
            'form-group':{
                init: function(){
                    return;
                }
            }

        },
        _create: function() {
            this._setOptions(this.options);
        },

        _setOption: function( key, value ) {

            var element = $(this.element);
            var widget = this;
            if(key === "items") {
                $.each(value, function(k,item) {
                    var type = has(widget.declarations, item.type) ? item.type : 'html';
                    var declaration = widget.declarations[type];
                    var subElement = declaration.init(item, widget.declarations);

                    if(has(item,'cssClass')){
                        subElement.addClass(item.cssClass);
                    }

                    element.append(subElement);
                    element.data('item',item);
                })
            }

            this._super( key, value );
        },
        _setOptions: function( options ) {
            this._super( options );
            this.refresh();
        },
        refresh: function() {
            this._trigger('refresh');
        }
    });

    var popup = $("
").popupDialog();

    popup.generateElements({
        items: [{
            type: 'label',
            text: 'Label TEST'
        }, {
            type:        'input',
            name:        'name',
            text:        'Name',
            placeholder: 'Enter your name'
        }, {
            type:        'input',
            name:        'Nachname',
            text:        'Nachname',
            placeholder: 'Nachname'
        }, {
            type:        'input',
            name:        'email',
            text:        'E-Mail',
            placeholder: 'eslider@gmail.com'
        },
        "
", {
            type:     'submit',
            cssClass: 'right',
            click: function(){
                console.log('CLICK');
            }
        }]
    });

    //console.log("TEST");
})(jQuery);
<|endoftext|>


<commit_before>//META{"name":"EvenBetterDiscord"}*//

let request = require('request');
let fs = require('fs');

let EvenBetterDiscord = function ()
{
    this.targetAPI = "https://api.github.com/repos/DeathStrikeV/BetterDiscordApp/commits/master";
    this.targetURL = "https://raw.githubusercontent.com/DeathStrikeV/BetterDiscordApp/master/data/emotedata_ffz.json";

    this.bdPath = (process.platform == "win32" ?
        process.env.APPDATA : process.platform == "darwin" ?
        process.env.HOME + "/Library/Preferences/" : "/var/local/") + "/BetterDiscord/";

    this.preferencesFile = this.bdPath + "/EBD_Preferences.json";
    this.emotesFile = this.bdPath + "/EBD_Emotes.json";
    this.defaultEmotesFile = this.bdPath + "/emotes_ffz.json";
};

EvenBetterDiscord.prototype.start = function ()
{
    this.loadEBDFiles();
};

EvenBetterDiscord.prototype.loadEBDFiles = function ()
{
    let readPreferencesFile = function (err, data)
    {
        if (data)
            this.currentHash = JSON.parse(data).currentHash;
        else
            this.currentHash = "";

        if (this.currentHash === "ignore")
        {
            this.loadEmotes(this.emotesFile);
            return;
        }

        request({ url: this.targetAPI, headers: { "User-Agent": "DeathStrikeV" } }, requestRepoHash.bind(this));
    };

    let requestRepoHash = function (error, response, body)
    {
        if (response.statusCode !== 200)
        {
            this.loadEmotes(this.emotesFile);
            return;
        }

        this.latestHash = JSON.parse(body).sha;

        if (this.currentHash === this.latestHash)
        {
            this.loadEmotes(this.emotesFile);
            return;
        }

        request(this.targetURL, downloadEmotesFile.bind(this));
    };

    let downloadEmotesFile = function (error, response, body)
    {
        if (response.statusCode !== 200)
        {
            this.loadEmotes(this.emotesFile);
            return;
        }

        fs.writeFile(this.emotesFile, body, saveEmotesFile.bind(this));
    };

    let saveEmotesFile = function (err)
    {
        if (!err)
        {
            //console.log("Retreived new emotes file!");
            fs.writeFile(this.preferencesFile, JSON.stringify({ currentHash: this.latestHash }), null);
        }

        this.loadEmotes(this.emotesFile);
    }

    fs.readFile(this.preferencesFile, "utf8", readPreferencesFile.bind(this));
};

EvenBetterDiscord.prototype.loadEmotes = function (targetFile)
{
    fs.readFile(targetFile, "utf8", (err, data) =>
    {
        if (data)
        {
            let emoteData = JSON.parse(data);

            if (!emoteData)
            {
                //console.log("Failed to parse emotes file!");
                return;
            }

            window.emotesFfz = emoteData;
            //console.log("Loaded emotes file!");
        }
    });
};

EvenBetterDiscord.prototype.stop = function ()
{
    this.removeEBDFiles();
    this.loadEmotes(this.defaultEmotesFile);
};

EvenBetterDiscord.prototype.removeEBDFiles = function ()
{
    fs.stat(this.preferencesFile, (err, stats) =>
    {
        if (err)
            return;

        fs.unlink(this.preferencesFile, (err) => { });
    });

    fs.stat(this.emotesFile, (err, stats) =>
    {
        if (err)
            return;

        fs.unlink(this.emotesFile, (err) => { });
    });
};

EvenBetterDiscord.prototype.load = function () { };
EvenBetterDiscord.prototype.unload = function () { };
EvenBetterDiscord.prototype.onMessage = function () { };
EvenBetterDiscord.prototype.onSwitch = function () { };

EvenBetterDiscord.prototype.getName = function ()
{
    return "EvenBetterDiscord";
};

EvenBetterDiscord.prototype.getDescription = function ()
{
    return "Loads FFZ emotes from alternate repository";
};

EvenBetterDiscord.prototype.getVersion = function ()
{
    return "1.0.0";
};

EvenBetterDiscord.prototype.getAuthor = function ()
{
    return "DeathStrikeV";
};<commit_msg>Updated plugin<commit_after>//META{"name":"EvenBetterDiscord"}*//

let request = require('request');
let fs = require('fs');

let EvenBetterDiscord = function ()
{
    this.targetAPI = "https://api.github.com/repos/DeathStrikeV/BetterDiscordApp/commits/master";
    this.targetURL = "https://raw.githubusercontent.com/DeathStrikeV/BetterDiscordApp/master/data/emotedata_ffz.json";

    this.bdPath = (process.platform == "win32" ?
        process.env.APPDATA : process.platform == "darwin" ?
        process.env.HOME + "/Library/Preferences/" : "/var/local/") + "/BetterDiscord/";

    this.preferencesFile = this.bdPath + "/EBD_Preferences.json";
    this.emotesFile = this.bdPath + "/EBD_Emotes.json";
    this.defaultEmotesFile = this.bdPath + "/emotes_ffz.json";
};

EvenBetterDiscord.prototype.start = function ()
{
    this.loadEBDFiles();
};

EvenBetterDiscord.prototype.loadEBDFiles = function ()
{
    let readPreferencesFile = function (err, data)
    {
        if (data)
            this.currentHash = JSON.parse(data).currentHash;
        else
            this.currentHash = "";

        if (this.currentHash === "ignore")
        {
            this.loadEmotes(this.emotesFile);
            return;
        }

        request({ url: this.targetAPI, headers: { "User-Agent": "DeathStrikeV" } }, requestRepoHash.bind(this));
    };

    let requestRepoHash = function (error, response, body)
    {
        if (response.statusCode !== 200)
        {
            this.loadEmotes(this.emotesFile);
            return;
        }

        this.latestHash = JSON.parse(body).sha;

        if (this.currentHash === this.latestHash)
        {
            this.loadEmotes(this.emotesFile);
            return;
        }

        request(this.targetURL, downloadEmotesFile.bind(this));
    };

    let downloadEmotesFile = function (error, response, body)
    {
        if (response.statusCode !== 200)
        {
            this.loadEmotes(this.emotesFile);
            return;
        }

        fs.writeFile(this.emotesFile, body, saveEmotesFile.bind(this));
    };

    let saveEmotesFile = function (err)
    {
        if (!err)
        {
            //console.log("Retreived new emotes file!");
            fs.writeFile(this.preferencesFile, JSON.stringify({ currentHash: this.latestHash }), null);
        }

        this.loadEmotes(this.emotesFile);
    }

    fs.readFile(this.preferencesFile, "utf8", readPreferencesFile.bind(this));
};

EvenBetterDiscord.prototype.loadEmotes = function (targetFile)
{
    fs.readFile(targetFile, "utf8", (err, data) =>
    {
        if (data)
        {
            let emoteData = JSON.parse(data);

            if (!emoteData)
            {
                //console.log("Failed to parse emotes file!");
                return;
            }

            window.emotesFfz = emoteData;
            //console.log("Loaded emotes file!");

            //this.fixBrokenFavorites();
        }
    });
};

EvenBetterDiscord.prototype.fixBrokenFavorites = function ()
{
    let result;
    let regex = new RegExp("\"([\\w!]+(?:~\\d+)?)\":\"https:\\/\\/cdn\\.frankerfacez\\.com\\/emoticon\\/\\d+", "g");
    let brokenFavorites = atob(localStorage.bdfavemotes);
    let fixedFavorites = brokenFavorites;

    while (result = regex.exec(brokenFavorites))
    {
        let replacementRegex = new RegExp("\"" + result[1] + "\":\"https:\\/\\/cdn\\.frankerfacez\\.com\\/emoticon\\/\\d+", "g");
        let replacementString = "\"" + result[1] + "\":\"https://cdn.frankerfacez.com/emoticon/" + emotesFfz[result[1]];
        fixedFavorites = fixedFavorites.replace(replacementRegex, replacementString);
    }

    localStorage.bdfavemotes = btoa(fixedFavorites);
    quickEmoteMenu.favoriteEmotes = JSON.parse(fixedFavorites);
    quickEmoteMenu.updateFavorites();
};

EvenBetterDiscord.prototype.stop = function ()
{
    this.removeEBDFiles();
    this.loadEmotes(this.defaultEmotesFile);
};

EvenBetterDiscord.prototype.removeEBDFiles = function ()
{
    fs.stat(this.preferencesFile, (err, stats) =>
    {
        if (err)
            return;

        fs.unlink(this.preferencesFile, (err) => { });
    });

    fs.stat(this.emotesFile, (err, stats) =>
    {
        if (err)
            return;

        fs.unlink(this.emotesFile, (err) => { });
    });
};

EvenBetterDiscord.prototype.load = function () { };
EvenBetterDiscord.prototype.unload = function () { };
EvenBetterDiscord.prototype.onMessage = function () { };
EvenBetterDiscord.prototype.onSwitch = function () { };

EvenBetterDiscord.prototype.getName = function ()
{
    return "EvenBetterDiscord";
};

EvenBetterDiscord.prototype.getDescription = function ()
{
    return "Loads FFZ emotes from alternate repository";
};

EvenBetterDiscord.prototype.getVersion = function ()
{
    return "1.0.0";
};

EvenBetterDiscord.prototype.getAuthor = function ()
{
    return "DeathStrikeV";
};<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow strict-local
 */

'use strict';

const Dimensions = require('Dimensions');

/**
 * PixelRatio class gives access to the device pixel density.
 *
 * ## Fetching a correctly sized image
 *
 * You should get a higher resolution image if you are on a high pixel density
 * device. A good rule of thumb is to multiply the size of the image you display
 * by the pixel ratio.
 *
 * ```
 * var image = getImage({
 *   width: PixelRatio.getPixelSizeForLayoutSize(200),
 *   height: PixelRatio.getPixelSizeForLayoutSize(100),
 * });
 * <Image source={image} style={{width: 200, height: 100}} />
 * ```
 *
 * ## Pixel grid snapping
 *
 * In iOS, you can specify positions and dimensions for elements with arbitrary
 * precision, for example 29.674825. But, ultimately the physical display only
 * have a fixed number of pixels, for example 640×960 for iPhone 4 or 750×1334
 * for iPhone 6. iOS tries to be as faithful as possible to the user value by
 * spreading one original pixel into multiple ones to trick the eye. The
 * downside of this technique is that it makes the resulting element look
 * blurry.
 *
 * In practice, we found out that developers do not want this feature and they
 * have to work around it by doing manual rounding in order to avoid having
 * blurry elements. In React Native, we are rounding all the pixels
 * automatically.
 *
 * We have to be careful when to do this rounding. You never want to work with
 * rounded and unrounded values at the same time as you're going to accumulate
 * rounding errors. Having even one rounding error is deadly because a one
 * pixel border may vanish or be twice as big.
 *
 * In React Native, everything in JavaScript and within the layout engine works
 * with arbitrary precision numbers. It's only when we set the position and
 * dimensions of the native element on the main thread that we round. Also,
 * rounding is done relative to the root rather than the parent, again to avoid
 * accumulating rounding errors.
 *
 */
class PixelRatio {
  /**
   * Returns the device pixel density. Some examples:
   *
   *   - PixelRatio.get() === 1
   *     - mdpi Android devices (160 dpi)
   *   - PixelRatio.get() === 1.5
   *     - hdpi Android devices (240 dpi)
   *   - PixelRatio.get() === 2
   *     - iPhone 4, 4S
   *     - iPhone 5, 5c, 5s
   *     - iPhone 6
   *     - xhdpi Android devices (320 dpi)
   *   - PixelRatio.get() === 3
   *     - iPhone 6 plus
   *     - xxhdpi Android devices (480 dpi)
   *   - PixelRatio.get() === 3.5
   *     - Nexus 6
   */
  static get(): number {
    return Dimensions.get('window').scale;
  }

  /**
   * Returns the scaling factor for font sizes. This is the ratio that is used to calculate the
   * absolute font size, so any elements that heavily depend on that should use this to do
   * calculations.
   *
   * If a font scale is not set, this returns the device pixel ratio.
   *
   * Currently this is only implemented on Android and reflects the user preference set in
   * Settings > Display > Font size, on iOS it will always return the default pixel ratio.
   * @platform android
   */
  static getFontScale(): number {
    return Dimensions.get('window').fontScale || PixelRatio.get();
  }

  /**
   * Converts a layout size (dp) to pixel size (px).
   *
   * Guaranteed to return an integer number.
   */
  static getPixelSizeForLayoutSize(layoutSize: number): number {
    return Math.round(layoutSize * PixelRatio.get());
  }

  /**
   * Rounds a layout size (dp) to the nearest layout size that corresponds to
   * an integer number of pixels. For example, on a device with a PixelRatio
   * of 3, `PixelRatio.roundToNearestPixel(8.4) = 8.33`, which corresponds to
   * exactly (8.33 * 3) = 25 pixels.
   */
  static roundToNearestPixel(layoutSize: number): number {
    const ratio = PixelRatio.get();
    return Math.round(layoutSize * ratio) / ratio;
  }

  // No-op for iOS, but used on the web. Should not be documented.
  static startDetecting() {}
}

module.exports = PixelRatio;
<commit_msg>Add to PixelRation documentation information about iPhone SE and iPho… (#20695)<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow strict-local
 */

'use strict';

const Dimensions = require('Dimensions');

/**
 * PixelRatio class gives access to the device pixel density.
 *
 * ## Fetching a correctly sized image
 *
 * You should get a higher resolution image if you are on a high pixel density
 * device. A good rule of thumb is to multiply the size of the image you display
 * by the pixel ratio.
 *
 * ```
 * var image = getImage({
 *   width: PixelRatio.getPixelSizeForLayoutSize(200),
 *   height: PixelRatio.getPixelSizeForLayoutSize(100),
 * });
 * <Image source={image} style={{width: 200, height: 100}} />
 * ```
 *
 * ## Pixel grid snapping
 *
 * In iOS, you can specify positions and dimensions for elements with arbitrary
 * precision, for example 29.674825. But, ultimately the physical display only
 * have a fixed number of pixels, for example 640×960 for iPhone 4 or 750×1334
 * for iPhone 6. iOS tries to be as faithful as possible to the user value by
 * spreading one original pixel into multiple ones to trick the eye. The
 * downside of this technique is that it makes the resulting element look
 * blurry.
 *
 * In practice, we found out that developers do not want this feature and they
 * have to work around it by doing manual rounding in order to avoid having
 * blurry elements. In React Native, we are rounding all the pixels
 * automatically.
 *
 * We have to be careful when to do this rounding. You never want to work with
 * rounded and unrounded values at the same time as you're going to accumulate
 * rounding errors. Having even one rounding error is deadly because a one
 * pixel border may vanish or be twice as big.
 *
 * In React Native, everything in JavaScript and within the layout engine works
 * with arbitrary precision numbers. It's only when we set the position and
 * dimensions of the native element on the main thread that we round. Also,
 * rounding is done relative to the root rather than the parent, again to avoid
 * accumulating rounding errors.
 *
 */
class PixelRatio {
  /**
   * Returns the device pixel density. Some examples:
   *
   *   - PixelRatio.get() === 1
   *     - mdpi Android devices (160 dpi)
   *   - PixelRatio.get() === 1.5
   *     - hdpi Android devices (240 dpi)
   *   - PixelRatio.get() === 2
   *     - iPhone 4, 4S
   *     - iPhone 5, 5c, 5s
   *     - iPhone 6
   *     - iPhone 7
   *     - iPhone 8
   *     - iPhone SE
   *     - xhdpi Android devices (320 dpi)
   *   - PixelRatio.get() === 3
   *     - iPhone 6 Plus
   *     - iPhone 7 Plus
   *     - iPhone 8 Plus
   *     - iPhone X
   *     - xxhdpi Android devices (480 dpi)
   *   - PixelRatio.get() === 3.5
   *     - Nexus 6
   */
  static get(): number {
    return Dimensions.get('window').scale;
  }

  /**
   * Returns the scaling factor for font sizes. This is the ratio that is used to calculate the
   * absolute font size, so any elements that heavily depend on that should use this to do
   * calculations.
   *
   * If a font scale is not set, this returns the device pixel ratio.
   *
   * Currently this is only implemented on Android and reflects the user preference set in
   * Settings > Display > Font size, on iOS it will always return the default pixel ratio.
   * @platform android
   */
  static getFontScale(): number {
    return Dimensions.get('window').fontScale || PixelRatio.get();
  }

  /**
   * Converts a layout size (dp) to pixel size (px).
   *
   * Guaranteed to return an integer number.
   */
  static getPixelSizeForLayoutSize(layoutSize: number): number {
    return Math.round(layoutSize * PixelRatio.get());
  }

  /**
   * Rounds a layout size (dp) to the nearest layout size that corresponds to
   * an integer number of pixels. For example, on a device with a PixelRatio
   * of 3, `PixelRatio.roundToNearestPixel(8.4) = 8.33`, which corresponds to
   * exactly (8.33 * 3) = 25 pixels.
   */
  static roundToNearestPixel(layoutSize: number): number {
    const ratio = PixelRatio.get();
    return Math.round(layoutSize * ratio) / ratio;
  }

  // No-op for iOS, but used on the web. Should not be documented.
  static startDetecting() {}
}

module.exports = PixelRatio;
<|endoftext|>


<commit_before>import _async from 'async'
import Waterline from 'waterline'
import path from 'path'

/**
 * Satellite to manage the models using Waterline ORM.
 *
 * Using Waterline allow us interact with different kinds of database systems.
 */
class Models {

  /**
   * Reference for the API object.
   *
   * @type null
   */
  api = null

  /**
   * Waterline instance.
   *
   * @type null
   */
   waterline = null

   /**
    * Object with the Waterline ontology.
    *
    * @type WaterlineOntology
    */
   ontology = null

  /**
   * Create a new class instance.
   *
   * @param api   API reference.
   */
  constructor (api) {
    this.api = api

    // create a new Waterline instance
    this.waterline = new Waterline()
  }

  /**
   * Initialize the Waterline instance.
   *
   * @param callback  Callback function.
   */
  initialize (callback) {
    this.waterline.initialize(this.api.config.models, (error, ontology) => {
      // if an error occurred we need stop the execution
      if (error) { return callback(error) }

      // save the ontology for later
      this.ontology = ontology

      // yup, is just this! Now the models system is read to fly.
      callback()
    })
  }

  /**
   * Finish the model system.
   *
   * @param callback  Callback function.
   */
  finish (callback) {
    this.waterline.teardown(callback)
  }

  /**
   * Add a new model.
   *
   * @param name    Model name.
   * @param model   Model instance.
   */
  async add (name, model) {
    // the model definition can be a function, whether it happens we need pass
    // the api reference.
    if (typeof model === 'function') { model = model(this.api) }

    // execute the add event to allow other modules modify this model before it
    // gets compiled
    const response = await this.api.events.fire(`core.models.add.${name}`, { model })

    // when there is no identity property defined we use the file basename
    if (!response.model.identity) { response.model.identity = name }

    // if there is no connection set we use the default connection
    if (!response.model.connection) {
      response.model.connection = this.api.config.models.defaultConnection
    }

    // if there is a no schema property on set the model, we use the the default
    // configuration
    if (!response.model.schema) {
      response.model.schema = this.api.config.models.schema
    }

    // create a Waterline collection
    const collection = Waterline.Collection.extend(response.model)

    // load the connection into the waterline instance
    this.waterline.loadCollection(collection)
  }

  /**
   * Load models from the modules.
   */
  loadModels () {
    return new Promise(resolve => {
      const work = []

      // read models files from the modules
      this.api.modules.modulesPaths.forEach(modulePath => {
        this.api.utils.recursiveDirectoryGlob(`${modulePath}/models`)
          .forEach(moduleFile => {
            // get file basename
            let basename = path.basename(moduleFile, '.js')

            // push a new work to the array
            work.push(callback => {
              this.add(basename, require(moduleFile).default)
              this.api.log(`model loaded: ${basename}`, 'debug')
              callback()
            })
          })
      })

      // process the all work and resolve the promise at the end
      _async.parallel(work, () => resolve())
    })
  }

  /**
   * Get a model object from the ontology.
   *
   * @param modelName                 Model name to get.
   * @returns {WaterlineCollection}   Model object.
   */
  get (modelName) { return this.ontology.collections[modelName] }

  /**
   * Remove a model from the repository.
   *
   * @param modelName   model name to be deleted.
   */
  remove (modelName) { this.models.delete(modelName) }

}

/**
 * Initializer for the models features.
 */
export default class {

  /**
   * Initializer load priority.
   *
   * @type {number}
   */
  loadPriority = 100

  /**
   * Initializer start priority.
   *
   * @type {number}
   */
  startPriority = 100

  /**
   * Initializer stop priority.
   *
   * @type {number}
   */
  stopPriority = 400

  /**
   * Initializer loading function.
   *
   * @param api   API reference.
   * @param next  Callback function.
   */
  load (api, next) {
    // expose models class on the engine
    api.models = new Models(api)

    // finish the initializer loading
    next()
  }

  /**
   * Initializer start function.
   *
   * @param api   API reference.
   * @param next  Callback function.
   */
  start (api, next) {
    // load the models from the modules and then initialize the Waterline system
    api.models.loadModels().then(_ => { api.models.initialize(next) })
  }

  /**
   * Initializer stop function.
   *
   * @param api   API reference.
   * @param next  Callback function.
   */
  stop (api, next) {
    // close connection
    api.models.finish(next)
  }
}
<commit_msg>Reload the server when the a model changes<commit_after>import _async from 'async'
import Waterline from 'waterline'
import path from 'path'

/**
 * Satellite to manage the models using Waterline ORM.
 *
 * Using Waterline allow us interact with different kinds of database systems.
 */
class Models {

  /**
   * Reference for the API object.
   *
   * @type null
   */
  api = null

  /**
   * Waterline instance.
   *
   * @type null
   */
   waterline = null

   /**
    * Object with the Waterline ontology.
    *
    * @type WaterlineOntology
    */
   ontology = null

  /**
   * Create a new class instance.
   *
   * @param api   API reference.
   */
  constructor (api) {
    this.api = api

    // create a new Waterline instance
    this.waterline = new Waterline()
  }

  /**
   * Initialize the Waterline instance.
   *
   * @param callback  Callback function.
   */
  initialize (callback) {
    this.waterline.initialize(this.api.config.models, (error, ontology) => {
      // if an error occurred we need stop the execution
      if (error) { return callback(error) }

      // save the ontology for later
      this.ontology = ontology

      // yup, is just this! Now the models system is read to fly.
      callback()
    })
  }

  /**
   * Finish the model system.
   *
   * @param callback  Callback function.
   */
  finish (callback) {
    this.waterline.teardown(callback)
  }

  /**
   * Add a new model.
   *
   * @param name    Model name.
   * @param model   Model instance.
   */
  async add (name, model) {
    // the model definition can be a function, whether it happens we need pass
    // the api reference.
    if (typeof model === 'function') { model = model(this.api) }

    // execute the add event to allow other modules modify this model before it
    // gets compiled
    const response = await this.api.events.fire(`core.models.add.${name}`, { model })

    // when there is no identity property defined we use the file basename
    if (!response.model.identity) { response.model.identity = name }

    // if there is no connection set we use the default connection
    if (!response.model.connection) {
      response.model.connection = this.api.config.models.defaultConnection
    }

    // if there is a no schema property on set the model, we use the the default
    // configuration
    if (!response.model.schema) {
      response.model.schema = this.api.config.models.schema
    }

    // create a Waterline collection
    const collection = Waterline.Collection.extend(response.model)

    // load the connection into the waterline instance
    this.waterline.loadCollection(collection)
  }

  /**
   * Load models from the modules.
   */
  loadModels () {
    return new Promise(resolve => {
      const work = []

      // read models files from the modules
      this.api.modules.modulesPaths.forEach(modulePath => {
        this.api.utils.recursiveDirectoryGlob(`${modulePath}/models`)
          .forEach(moduleFile => {
            // get file basename
            let basename = path.basename(moduleFile, '.js')

            // start watching for changes on the model
            this._watchForChanges(moduleFile)

            // push a new work to the array
            work.push(callback => {
              this.add(basename, require(moduleFile).default)
              this.api.log(`model loaded: ${basename}`, 'debug')
              callback()
            })
          })
      })

      // process the all work and resolve the promise at the end
      _async.parallel(work, () => resolve())
    })
  }

  /**
   * If the development mode is active we must watch for changes.
   *
   * When the file changes we tack the following steps:
   *  - log a message
   *  - remove the file cache from require
   *  - reload Stellar
   */
  _watchForChanges (file) {
    // if the development mode is active we return
    if (!this.api.config.general.developmentMode) { return }

    // watch for changes on the model file
    this.api.configs.watchFileAndAct(file, () => {
      // log a information message
      this.api.log(`\r\n\r\n*** rebooting due to model change (${file}) ***\r\n\r\n`, 'info')

      // remove require cache
      delete require.cache[ require.resolve(file) ]

      // reload Stellar
      this.api.commands.restart.call(this.api._self)
    })
  }

  /**
   * Get a model object from the ontology.
   *
   * @param modelName                 Model name to get.
   * @returns {WaterlineCollection}   Model object.
   */
  get (modelName) { return this.ontology.collections[modelName] }

  /**
   * Remove a model from the repository.
   *
   * @param modelName   model name to be deleted.
   */
  remove (modelName) { this.models.delete(modelName) }

}

/**
 * Initializer for the models features.
 */
export default class {

  /**
   * Initializer load priority.
   *
   * @type {number}
   */
  loadPriority = 100

  /**
   * Initializer start priority.
   *
   * @type {number}
   */
  startPriority = 100

  /**
   * Initializer stop priority.
   *
   * @type {number}
   */
  stopPriority = 400

  /**
   * Initializer loading function.
   *
   * @param api   API reference.
   * @param next  Callback function.
   */
  load (api, next) {
    // expose models class on the engine
    api.models = new Models(api)

    // finish the initializer loading
    next()
  }

  /**
   * Initializer start function.
   *
   * @param api   API reference.
   * @param next  Callback function.
   */
  start (api, next) {
    // load the models from the modules and then initialize the Waterline system
    api.models.loadModels().then(_ => { api.models.initialize(next) })
  }

  /**
   * Initializer stop function.
   *
   * @param api   API reference.
   * @param next  Callback function.
   */
  stop (api, next) {
    // close connection
    api.models.finish(next)
  }
}
<|endoftext|>