<commit_before>
// ----------------------------------------------------------------
// Common Class

class CommonClass {
  constructor(
    _initSetting = {},
    _common = {
      NAME: 'Common Class',
      VIEW_NAME: false
    }
  ) {
    Object.assign(this, _common, _initSetting);

    if (this.NAME != null && this.VIEW_NAME) {
      this.viewNameModel(this.NAME);
    }
  }

  viewName(_name) {
    // Draw line
    Log.log();
    // Check name
    if (_name != null) {
      // Exists name
      // Write name
      Log.log(_name, Log.ALIGN_CENTER);
      return;
    } else {
      // Not exists name
      // Write this name
      Log.log(this.NAME, Log.ALIGN_CENTER);
    }
  }

  viewNameModel(_name, _model) {
    // Write name
    this.viewName(_name);

    // Check model
    if (_model != null) {
      // Exists model
      // Write model
      Log.logObj(_model);
    } else {
      // Not exists model
      // Write this
      Log.logObj(this);
    }
  }
}

// ----------------------------------------------------------------
// Model

class CommonModel extends CommonClass {
  constructor(
    _initSetting = {},
    _common = {
      NAME: 'Common Object',
      VIEW_NAME: false
    }
  ) {
    super(_initSetting, _common);

    this.ACTIVE = 'active';
    this.HOVER = 'hover';

    this.SPEED_REMOVE = 200;

    this.ALERT_SUCCESS = 'success';
    this.ALERT_INFO = 'info';
    this.ALERT_WARNING = 'warning';
    this.ALERT_DANGER = 'danger';

    this.DISPLAY_NONE = 'display-none';
    this.CURRENT = 'current';

    this.BODY = 'html, body';
    this.TEMPLATE_LOADING = '#loading-template';
    this.TEMPLATE_ALERT = '#alert-template';
    this.TEMPLATE_RUBY = '#ruby-template';
  }

  // Add var to Instance
  setKey(_key = 'KEY', _val = 'VALUE') {
    this[_key] = _val;
  }

  // Get var from Instance
  getKey(_key = 'KEY') {
    return this[_key];
  }

  // Remove var from Instance
  removeKey(_key = 'KEY') {
    this[_key] = undefined;
  }
}

class CommonView extends CommonClass {
  constructor(
    _initSetting = {},
    _common = {
      NAME: 'Common View',
      VIEW_NAME: false
    }
  ) {
    super(_initSetting, _common);
  }

  getTemplate(
    _template = null,
    _model = null
  ) {
    if (_template == null) {
      return null;
    }
    const template = $(_template).text();
    const compiled = _.template(template);
    return compiled(_model);
  }

  generateLoading(
    _selector = null,
    _header = null,
    _message = null
  ) {
    if (_selector == null) {
      Log.logCaution(this.NAME, 'generateLoading', 'Undefined selector');
      return;
    }
    $(_selector).empty();
    $(_selector).append(this.getTemplate(
      $(this.MODEL.TEMPLATE_LOADING),
      {
        header: _header,
        message: _message
      }
    ));
  }

  generateAlert(
    _selector = null,
    _type = 'success',
    _message = null,
    _close = true
  ) {
    if (_selector == null) {
      Log.logCaution(this.NAME, 'generateAlert', 'Undefined selector');
      return;
    }
    if (_message != null) {
      $(_selector).append(this.getTemplate(
        $(this.MODEL.TEMPLATE_ALERT),
        {
          type: _type,
          message: _message,
          close: _close
        }
      ));
    }
  }
}

// ----------------------------------------------------------------
// Event

class CommonEvent extends CommonClass {
  constructor(
    _initSetting = {},
    _common = {
      NAME: 'Common Event',
      VIEW_NAME: false
    }
  ) {
    super(_initSetting, _common);
  }

  setOn(
    _trigger = 'click',
    _selector = null,
    _func = () => {}
  ) {
    if (_selector != null) {
      $(document).on(_trigger, _selector, _func);
    } else {
      $(document).on(_trigger, _func);
    }
  }

  setOff(
    _trigger = 'click',
    _selector = null
  ) {
    if (_selector != null) {
      $(document).off(_trigger, _selector);
    } else {
      $(document).off(_trigger);
    }
  }
}

// ----------------------------------------------------------------
// Controller

class CommonController extends CommonClass {
  constructor(
    _model = {},
    _initSetting = {},
    _common = {
      NAME: 'Common Controller',
      VIEW_NAME: false,
      VIEW_OBJECT: true,
      MODEL: new CommonModel(),
      VIEW: new CommonView(),
      EVENT: new CommonEvent()
    }
  ) {
    super(_initSetting, _common);
    Object.assign(this.MODEL, _model);

    if (this.VIEW_OBJECT) {
      super.viewNameModel(this.MODEL.NAME);
    }

    this.applyObject();
  }

  applyObject() {
    this.CONTROLLER = this;

    this.VIEW.MODEL = this.MODEL;
    this.VIEW.VIEW = this.VIEW;
    this.VIEW.EVENT = this.EVENT;
    this.VIEW.CONTROLLER = this;

    this.EVENT.MODEL = this.MODEL;
    this.EVENT.VIEW = this.VIEW;
    this.EVENT.EVENT = this.EVENT;
    this.EVENT.CONTROLLER = this;
  }
}

// ----------------------------------------------------------------
// Process

class CommonProcess extends CommonClass {
  constructor(
    _initSetting = {},
    _common = {
      NAME: 'Common Process',
      VIEW_NAME: true
    }
  ) {
    super(_initSetting, _common);
  }
}
<commit_msg>Add function removeHTML in CommonView<commit_after>
// ----------------------------------------------------------------
// Common Class

class CommonClass {
  constructor(
    _initSetting = {},
    _common = {
      NAME: 'Common Class',
      VIEW_NAME: false
    }
  ) {
    Object.assign(this, _common, _initSetting);

    if (this.NAME != null && this.VIEW_NAME) {
      this.viewNameModel(this.NAME);
    }
  }

  viewName(_name) {
    // Draw line
    Log.log();
    // Check name
    if (_name != null) {
      // Exists name
      // Write name
      Log.log(_name, Log.ALIGN_CENTER);
      return;
    } else {
      // Not exists name
      // Write this name
      Log.log(this.NAME, Log.ALIGN_CENTER);
    }
  }

  viewNameModel(_name, _model) {
    // Write name
    this.viewName(_name);

    // Check model
    if (_model != null) {
      // Exists model
      // Write model
      Log.logObj(_model);
    } else {
      // Not exists model
      // Write this
      Log.logObj(this);
    }
  }
}

// ----------------------------------------------------------------
// Model

class CommonModel extends CommonClass {
  constructor(
    _initSetting = {},
    _common = {
      NAME: 'Common Object',
      VIEW_NAME: false
    }
  ) {
    super(_initSetting, _common);

    this.ACTIVE = 'active';
    this.HOVER = 'hover';

    this.SPEED_REMOVE = 200;

    this.ALERT_SUCCESS = 'success';
    this.ALERT_INFO = 'info';
    this.ALERT_WARNING = 'warning';
    this.ALERT_DANGER = 'danger';

    this.DISPLAY_NONE = 'display-none';
    this.CURRENT = 'current';

    this.BODY = 'html, body';
    this.TEMPLATE_LOADING = '#loading-template';
    this.TEMPLATE_ALERT = '#alert-template';
    this.TEMPLATE_RUBY = '#ruby-template';
  }

  // Add var to Instance
  setKey(_key = 'KEY', _val = 'VALUE') {
    this[_key] = _val;
  }

  // Get var from Instance
  getKey(_key = 'KEY') {
    return this[_key];
  }

  // Remove var from Instance
  removeKey(_key = 'KEY') {
    this[_key] = undefined;
  }
}

class CommonView extends CommonClass {
  constructor(
    _initSetting = {},
    _common = {
      NAME: 'Common View',
      VIEW_NAME: false
    }
  ) {
    super(_initSetting, _common);
  }

  getTemplate(
    _template = null,
    _model = null
  ) {
    if (_template == null) {
      return null;
    }
    const template = $(_template).text();
    const compiled = _.template(template);
    return compiled(_model);
  }

  generateLoading(
    _selector = null,
    _header = null,
    _message = null
  ) {
    if (_selector == null) {
      Log.logCaution(this.NAME, 'generateLoading', 'Undefined selector');
      return;
    }
    $(_selector).empty();
    $(_selector).append(this.getTemplate(
      $(this.MODEL.TEMPLATE_LOADING),
      {
        header: _header,
        message: _message
      }
    ));
  }

  generateAlert(
    _selector = null,
    _type = 'success',
    _message = null,
    _close = true
  ) {
    if (_selector == null) {
      Log.logCaution(this.NAME, 'generateAlert', 'Undefined selector');
      return;
    }
    if (_message != null) {
      $(_selector).append(this.getTemplate(
        $(this.MODEL.TEMPLATE_ALERT),
        {
          type: _type,
          message: _message,
          close: _close
        }
      ));
    }
  }

  removeHTML(_selector = null, _speed = null) {
    if (_selector == null) {
      return false;
    }
    if (_speed == null) {
      _speed = this.MODEL.SPEED_REMOVE;
    }
    $(_selector).hide(_speed, () => {
      $(_selector).remove();
    });
    return true;
  }
}

// ----------------------------------------------------------------
// Event

class CommonEvent extends CommonClass {
  constructor(
    _initSetting = {},
    _common = {
      NAME: 'Common Event',
      VIEW_NAME: false
    }
  ) {
    super(_initSetting, _common);
  }

  setOn(
    _trigger = 'click',
    _selector = null,
    _func = () => {}
  ) {
    if (_selector != null) {
      $(document).on(_trigger, _selector, _func);
    } else {
      $(document).on(_trigger, _func);
    }
  }

  setOff(
    _trigger = 'click',
    _selector = null
  ) {
    if (_selector != null) {
      $(document).off(_trigger, _selector);
    } else {
      $(document).off(_trigger);
    }
  }
}

// ----------------------------------------------------------------
// Controller

class CommonController extends CommonClass {
  constructor(
    _model = {},
    _initSetting = {},
    _common = {
      NAME: 'Common Controller',
      VIEW_NAME: false,
      VIEW_OBJECT: true,
      MODEL: new CommonModel(),
      VIEW: new CommonView(),
      EVENT: new CommonEvent()
    }
  ) {
    super(_initSetting, _common);
    Object.assign(this.MODEL, _model);

    if (this.VIEW_OBJECT) {
      super.viewNameModel(this.MODEL.NAME);
    }

    this.applyObject();
  }

  applyObject() {
    this.CONTROLLER = this;

    this.VIEW.MODEL = this.MODEL;
    this.VIEW.VIEW = this.VIEW;
    this.VIEW.EVENT = this.EVENT;
    this.VIEW.CONTROLLER = this;

    this.EVENT.MODEL = this.MODEL;
    this.EVENT.VIEW = this.VIEW;
    this.EVENT.EVENT = this.EVENT;
    this.EVENT.CONTROLLER = this;
  }
}

// ----------------------------------------------------------------
// Process

class CommonProcess extends CommonClass {
  constructor(
    _initSetting = {},
    _common = {
      NAME: 'Common Process',
      VIEW_NAME: true
    }
  ) {
    super(_initSetting, _common);
  }
}
<|endoftext|>


<commit_before>config = {
  'roomServer': 'ws://199.21.79.248:444/slither', // Set this to your preferred room.
  'mapServer': 'ws://websocket_server:8000', // Set this to the location of the running web server
  'color': 'red', // Each player should choose a color.
  'name': 'kainar' // Each player should put their username.
}

denSocket = null;
denSnakes = null;
denLbh = null;
denLbs = null;
denReset = null;

denReset = function() {
  denSocket && denSocket.close();
  denSocket = null;
  denLbh = document.getElementById("leaderboardTag");
  denLbs = document.getElementById("leaderboardScores");
  if (denLbh) denLbh.remove();
  if (denLbs) denLbs.remove();

  var oldSnakes = document.getElementsByClassName("denSnake");
  for (var i=0; i < oldSnakes.length; i++) {
    oldSnakes[i].remove();
  }
  denSnakes = {};
}

denSetup = function() {
  denReset();
  ws = new WebSocket(config.roomServer);

  // Setup init.
  denSocket = new WebSocket(config.mapServer);
  denSnakes = {};

  // Setup socket
  denSocket.onmessage = function(e) {
    var data = JSON.parse(e.data);
    if (data.event === 'delete') {
      var denSnake = denSnakes[data.id];
      denSnake.remove();
      delete denSnakes[data.id];
      return;
    }
    if (denSnakes[data.id]) {
      var denSnake = denSnakes[data.id];
      denSnake.style.top = data.top;
      denSnake.style.left = data.left;
      denSnake.score = Math.floor(15 * (fpsls[data.sct] + data.fam / fmlts[data.sct] - 1) - 5) / 1
    } else {
      denSnake = document.createElement("img");
      lc.width = lc.height = 14;
      ctx = lc.getContext("2d");
      ctx.fillStyle = data.color;
      ctx.strokeStyle = "#000000";
      ctx.lineWidth = 2;
      ctx.beginPath();
      ctx.arc(7, 7, 2.5, 0, pi2);
      ctx.stroke();
      ctx.fill();
      denSnake.src = lc.toDataURL();
        denSnake.classList.add("nsi");
        denSnake.classList.add("denSnake");
      denSnake.style.position = "absolute";
      denSnake.style.left = data.left;
      denSnake.style.top = data.top;
      denSnake.style.opacity = 1;
      denSnake.style.zIndex = 13;
      denSnake.name = data.name;
      denSnake.color = data.color;
        denSnake.score = 0;
      denSnakes[data.id] = denSnake;
      trf(myloc, agpu);
      loch.appendChild(denSnake);
    }
  }
  // Setup leaderboard.

  denLbh = document.createElement("div");
  denLbh.className = "nsi";
  denLbh.setAttribute('id', 'leaderboardTag');
  denLbh.style.position = "fixed";
  denLbh.style.left = "4px";
  denLbh.style.top = "4px";
  denLbh.style.textAlign = "center";
  denLbh.style.width = "255px";
  denLbh.style.height = "28px";
  denLbh.style.color = "#ffffff";
  denLbh.style.fontFamily = 'Arial, "Helvetica Neue", Helvetica, sans-serif';
  denLbh.style.fontSize = "21px";
  denLbh.style.fontWeight = "bold";
  denLbh.style.overflow = "hidden";
  denLbh.style.opacity = .7;
  denLbh.style.zIndex = 7;
  denLbh.style.cursor = "default";
  var lstr = "Den Leaderboard";
  "de" == lang ? lstr = "Bestenliste" : "fr" == lang ? lstr = "Gagnants" : "pt" == lang && (lstr = "L\u00edderes");
  denLbh.textContent = lstr;
  trf(denLbh, agpu);
  document.body.appendChild(denLbh);

  denLbs = document.createElement("div");
  denLbs.className = "nsi";
  denLbs.setAttribute('id', 'leaderboardScores');
  denLbs.style.position = "fixed";
  denLbs.style.textAlign = "center";
  denLbs.style.left = "20px";
  denLbs.style.top = "32px";
  denLbs.style.width = "150px";
  denLbs.style.height = "800px";
  denLbs.style.color = "#ffffff";
  denLbs.style.fontFamily = 'Arial, "Helvetica Neue", Helvetica, sans-serif';
  denLbs.style.fontSize = "12px";
  denLbs.style.overflow = "hidden";
  denLbs.style.opacity = .7;
  denLbs.style.zIndex = 7;
  denLbs.style.cursor = "default";
  denLbs.style.lineHeight = "150%";
  trf(denLbs, agpu);
  document.body.appendChild(denLbs);
  return setInterval(updateUi, 1000);
}

updateLocation = function() {
  denSocket.send(JSON.stringify({
    top: myloc.style.top,
    left: myloc.style.left,
    color: config.color,
    name: config.name,
    // Internal score representation
    sct: snake.sct,
    fam: snake.fam,
  }));
}

updateLeaderboard = function() {
  var scores = "";
  var sortedSnakes = [];
  denLbs.innerHTML = '';

  for (var denSnakeId in denSnakes) {
    if (!denSnakes.hasOwnProperty(denSnakeId)) {
      continue;
    }
    var denSnake = denSnakes[denSnakeId];
    sortedSnakes.push([denSnake, denSnake.score]);
  }
  sortedSnakes.sort(function(a, b) {
    return b[1] - a[1]
  })

  for (var idx in sortedSnakes) {
    var denSnake = sortedSnakes[idx][0];
    var rank = 1 + parseFloat(idx);
    var rankText = '# ' + rank + '    ';
    scores += '' + rankText + denSnake.name + ': ' + denSnake.score + "
";
  }
  denLbs.innerHTML = scores;
}

updateUi = function() {
  if (!connected) {
    denReset();
    clearInterval(denPeriodic);
  } else {
    updateLocation();
    updateLeaderboard();
  }
}

denPeriodic = denSetup();
<commit_msg>beautify<commit_after>config = {
  'roomServer': 'ws://199.21.79.248:444/slither', // Set this to your preferred room.
  'mapServer': 'ws://websocket_server:8000', // Set this to the location of the running web server
  'color': 'red', // Each player should choose a color.
  'name': 'kainar' // Each player should put their username.
}

denSocket = null;
denSnakes = null;
denLbh = null;
denLbs = null;
denReset = null;

denReset = function() {
  denSocket && denSocket.close();
  denSocket = null;
  denLbh = document.getElementById("leaderboardTag");
  denLbs = document.getElementById("leaderboardScores");
  if (denLbh) denLbh.remove();
  if (denLbs) denLbs.remove();

  var oldSnakes = document.getElementsByClassName("denSnake");
  for (var i = 0; i < oldSnakes.length; i++) {
    oldSnakes[i].remove();
  }
  denSnakes = {};
}

denSetup = function() {
  denReset();
  ws = new WebSocket(config.roomServer);

  // Setup init.
  denSocket = new WebSocket(config.mapServer);
  denSnakes = {};

  // Setup socket
  denSocket.onmessage = function(e) {
      var data = JSON.parse(e.data);
      if (data.event === 'delete') {
        var denSnake = denSnakes[data.id];
        denSnake.remove();
        delete denSnakes[data.id];
        return;
      }
      if (denSnakes[data.id]) {
        var denSnake = denSnakes[data.id];
        denSnake.style.top = data.top;
        denSnake.style.left = data.left;
        denSnake.score = Math.floor(15 * (fpsls[data.sct] + data.fam / fmlts[data.sct] - 1) - 5) / 1
      } else {
        denSnake = document.createElement("img");
        lc.width = lc.height = 14;
        ctx = lc.getContext("2d");
        ctx.fillStyle = data.color;
        ctx.strokeStyle = "#000000";
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.arc(7, 7, 2.5, 0, pi2);
        ctx.stroke();
        ctx.fill();
        denSnake.src = lc.toDataURL();
        denSnake.classList.add("nsi");
        denSnake.classList.add("denSnake");
        denSnake.style.position = "absolute";
        denSnake.style.left = data.left;
        denSnake.style.top = data.top;
        denSnake.style.opacity = 1;
        denSnake.style.zIndex = 13;
        denSnake.name = data.name;
        denSnake.color = data.color;
        denSnake.score = 0;
        denSnakes[data.id] = denSnake;
        trf(myloc, agpu);
        loch.appendChild(denSnake);
      }
    }
    // Setup leaderboard.

  denLbh = document.createElement("div");
  denLbh.className = "nsi";
  denLbh.setAttribute('id', 'leaderboardTag');
  denLbh.style.position = "fixed";
  denLbh.style.left = "4px";
  denLbh.style.top = "4px";
  denLbh.style.textAlign = "center";
  denLbh.style.width = "255px";
  denLbh.style.height = "28px";
  denLbh.style.color = "#ffffff";
  denLbh.style.fontFamily = 'Arial, "Helvetica Neue", Helvetica, sans-serif';
  denLbh.style.fontSize = "21px";
  denLbh.style.fontWeight = "bold";
  denLbh.style.overflow = "hidden";
  denLbh.style.opacity = .7;
  denLbh.style.zIndex = 7;
  denLbh.style.cursor = "default";
  var lstr = "Den Leaderboard";
  "de" == lang ? lstr = "Bestenliste" : "fr" == lang ? lstr = "Gagnants" : "pt" == lang && (lstr = "L\u00edderes");
  denLbh.textContent = lstr;
  trf(denLbh, agpu);
  document.body.appendChild(denLbh);

  denLbs = document.createElement("div");
  denLbs.className = "nsi";
  denLbs.setAttribute('id', 'leaderboardScores');
  denLbs.style.position = "fixed";
  denLbs.style.textAlign = "center";
  denLbs.style.left = "20px";
  denLbs.style.top = "32px";
  denLbs.style.width = "150px";
  denLbs.style.height = "800px";
  denLbs.style.color = "#ffffff";
  denLbs.style.fontFamily = 'Arial, "Helvetica Neue", Helvetica, sans-serif';
  denLbs.style.fontSize = "12px";
  denLbs.style.overflow = "hidden";
  denLbs.style.opacity = .7;
  denLbs.style.zIndex = 7;
  denLbs.style.cursor = "default";
  denLbs.style.lineHeight = "150%";
  trf(denLbs, agpu);
  document.body.appendChild(denLbs);
  return setInterval(updateUi, 1000);
}

updateLocation = function() {
  denSocket.send(JSON.stringify({
    top: myloc.style.top,
    left: myloc.style.left,
    color: config.color,
    name: config.name,
    // Internal score representation
    sct: snake.sct,
    fam: snake.fam,
  }));
}

updateLeaderboard = function() {
  var scores = "";
  var sortedSnakes = [];
  denLbs.innerHTML = '';

  for (var denSnakeId in denSnakes) {
    if (!denSnakes.hasOwnProperty(denSnakeId)) {
      continue;
    }
    var denSnake = denSnakes[denSnakeId];
    sortedSnakes.push([denSnake, denSnake.score]);
  }
  sortedSnakes.sort(function(a, b) {
    return b[1] - a[1]
  })

  for (var idx in sortedSnakes) {
    var denSnake = sortedSnakes[idx][0];
    var rank = 1 + parseFloat(idx);
    var rankText = '# ' + rank + '    ';
    scores += '' + rankText + denSnake.name + ': ' + denSnake.score + "
";
  }
  denLbs.innerHTML = scores;
}

updateUi = function() {
  if (!connected) {
    denReset();
    clearInterval(denPeriodic);
  } else {
    updateLocation();
    updateLeaderboard();
  }
}

denPeriodic = denSetup();
<|endoftext|>


<commit_before>/*
Copyright 2018 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { _t } from '../../../languageHandler';
import Widgets from '../../../utils/widgets';
import AppTile from '../elements/AppTile';
import ContextualMenu from '../../structures/ContextualMenu';
import MatrixClientPeg from '../../../MatrixClientPeg';
import Modal from '../../../Modal';
import sdk from '../../../index';
import SdkConfig from '../../../SdkConfig';
import ScalarAuthClient from '../../../ScalarAuthClient';
import dis from '../../../dispatcher';

const widgetType = 'm.stickerpicker';

export default class Stickerpicker extends React.Component {
    constructor(props) {
        super(props);
        this._onShowStickersClick = this._onShowStickersClick.bind(this);
        this._onHideStickersClick = this._onHideStickersClick.bind(this);
        this._launchManageIntegrations = this._launchManageIntegrations.bind(this);
        this._removeStickerpickerWidgets = this._removeStickerpickerWidgets.bind(this);
        this._onWidgetAction = this._onWidgetAction.bind(this);
        this.onFinished = this.onFinished.bind(this);

        this.popoverWidth = 300;
        this.popoverHeight = 300;

        this.state = {
            stickersContent: this.defaultStickersContent(),
            showStickers: false,
            imError: null,
        };
    }

    defaultStickersContent() {
        return (

{ _t("You don't currently have any stickerpacks enabled") }

{ _t("Click") }  { _t("here") } { _t("to add some!") }

        );
    }

    _removeStickerpickerWidgets() {
        console.warn('Removing Stickerpicker widgets');
        if (this.widgetId) {
            this.scalarClient.disableWidgetAssets(widgetType, this.widgetId).then(() => {
                console.warn('Assets disabled');
            }).catch((err) => {
                console.error('Failed to disable assets');
            });
        } else {
            console.warn('No widget ID specified, not disabling assets');
        }

        // Wrap this in a timeout in order to avoid the DOM node from being pulled from under its feet
        setTimeout(() => this.stickersMenu.close());
        Widgets.removeStickerpickerWidgets().then(() => {
            this._getStickerPickerWidget();
        }).catch((e) => {
            console.error('Failed to remove sticker picker widget', e);
        });
    }

    componentDidMount() {
        this.scalarClient = null;
        if (SdkConfig.get().integrations_ui_url && SdkConfig.get().integrations_rest_url) {
            this.scalarClient = new ScalarAuthClient();
            this.scalarClient.connect().then(() => {
                this.forceUpdate();
            }).catch((e) => {
                this._imError("Failed to connect to integrations server", e);
            });
        }

        if (!this.state.imError) {
            this._getStickerPickerWidget();
            this.dispatcherRef = dis.register(this._onWidgetAction);
        }
    }

    componentWillUnmount() {
        if (this.dispatcherRef) {
            dis.unregister(this.dispatcherRef);
        }
    }

    _imError(errorMsg, e) {
        console.error(errorMsg, e);
        const imErrorContent =

 { errorMsg }

;
        this.setState({
            showStickers: false,
            imError: errorMsg,
            stickersContent: imErrorContent,
        });
    }

    _onWidgetAction(payload) {
        if (payload.action === "user_widget_updated") {
            this._getStickerPickerWidget();
            return;
        } else if (payload.action === "stickerpicker_close") {
            // Wrap this in a timeout in order to avoid the DOM node from being pulled from under its feet
            setTimeout(() => this.stickersMenu.close());
        }
    }

    _getStickerPickerWidget() {
        // Stickers
        // TODO - Add support for Stickerpickers from multiple app stores.
        // Render content from multiple stickerpack sources, each within their own iframe, within the stickerpicker UI element.
        const stickerpickerWidget = Widgets.getStickerpickerWidgets()[0];
        let stickersContent;

        // Load stickerpack content
        if (stickerpickerWidget && stickerpickerWidget.content && stickerpickerWidget.content.url) {
            // Set default name
            stickerpickerWidget.content.name = stickerpickerWidget.name || _t("Stickerpack");
            this.widgetId = stickerpickerWidget.id;

            stickersContent = (

                        <AppTile
                            id={stickerpickerWidget.id}
                            url={stickerpickerWidget.content.url}
                            name={stickerpickerWidget.content.name}
                            room={this.props.room}
                            type={stickerpickerWidget.content.type}
                            fullWidth={true}
                            userId={stickerpickerWidget.sender || MatrixClientPeg.get().credentials.userId}
                            creatorUserId={MatrixClientPeg.get().credentials.userId}
                            waitForIframeLoad={true}
                            show={true}
                            showMenubar={true}
                            onEditClick={this._launchManageIntegrations}
                            onDeleteClick={this._removeStickerpickerWidgets}
                            showTitle={false}
                            showMinimise={true}
                            showDelete={false}
                            onMinimiseClick={this._onHideStickersClick}
                            handleMinimisePointerEvents={true}
                            whitelistCapabilities={['m.sticker']}
                        />

            );
        } else {
            // Default content to show if stickerpicker widget not added
            console.warn("No available sticker picker widgets");
            stickersContent = this.defaultStickersContent();
            this.widgetId = null;
            this.forceUpdate();
        }
        this.setState({
            showStickers: false,
            stickersContent: stickersContent,
        });
    }

    /**
     * Show the sticker picker overlay
     * If no stickerpacks have been added, show a link to the integration manager add sticker packs page.
     * @param  {Event} e Event that triggered the function
     */
    _onShowStickersClick(e) {
        this._getStickerPickerWidget();
        const GenericElementContextMenu = sdk.getComponent('context_menus.GenericElementContextMenu');
        const buttonRect = e.target.getBoundingClientRect();

        // The window X and Y offsets are to adjust position when zoomed in to page
        const x = buttonRect.right + window.pageXOffset - 42;
        const y = (buttonRect.top + (buttonRect.height / 2) + window.pageYOffset) - 19;
        // const self = this;
        this.stickersMenu = ContextualMenu.createMenu(GenericElementContextMenu, {
            chevronOffset: 10,
            chevronFace: 'bottom',
            left: x,
            top: y,
            menuWidth: this.popoverWidth,
            menuHeight: this.popoverHeight,
            element: this.state.stickersContent,
            onFinished: this.onFinished,
            menuPaddingTop: 0,
        });

        this.setState({showStickers: true});
    }

    /**
     * Trigger hiding of the sticker picker overlay
     * @param  {Event} ev Event that triggered the function call
     */
    _onHideStickersClick(ev) {
        setTimeout(() => this.stickersMenu.close());
    }

    /**
     * The stickers picker was hidden
     */
    onFinished() {
        this.setState({showStickers: false});
    }

    /**
     * Launch the integrations manager on the stickers integration page
     */
    _launchManageIntegrations() {
        const IntegrationsManager = sdk.getComponent("views.settings.IntegrationsManager");
        const src = (this.scalarClient !== null && this.scalarClient.hasCredentials()) ?
                this.scalarClient.getScalarInterfaceUrlForRoom(
                    this.props.room,
                    'type_' + widgetType,
                    this.widgetId,
                ) :
                null;
        Modal.createTrackedDialog('Integrations Manager', '', IntegrationsManager, {
            src: src,
        }, "mx_IntegrationsManager");

        // Wrap this in a timeout in order to avoid the DOM node from being pulled from under its feet
        setTimeout(() => this.stickersMenu.close());
    }

    render() {
        const TintableSvg = sdk.getComponent("elements.TintableSvg");
        let stickersButton;
        if (this.state.showStickers) {
            // Show hide-stickers button
            stickersButton =

                    <TintableSvg src="img/icons-hide-stickers.svg" width="35" height="35" />

;
        } else {
            // Show show-stickers button
            stickersButton =

                    <TintableSvg src="img/icons-show-stickers.svg" width="35" height="35" />

;
        }
        return stickersButton;
    }
}
<commit_msg>Use AccessibleButton.<commit_after>/*
Copyright 2018 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { _t } from '../../../languageHandler';
import Widgets from '../../../utils/widgets';
import AppTile from '../elements/AppTile';
import ContextualMenu from '../../structures/ContextualMenu';
import MatrixClientPeg from '../../../MatrixClientPeg';
import Modal from '../../../Modal';
import sdk from '../../../index';
import SdkConfig from '../../../SdkConfig';
import ScalarAuthClient from '../../../ScalarAuthClient';
import dis from '../../../dispatcher';
import AccessibleButton from '../elements/AccessibleButton';

const widgetType = 'm.stickerpicker';

export default class Stickerpicker extends React.Component {
    constructor(props) {
        super(props);
        this._onShowStickersClick = this._onShowStickersClick.bind(this);
        this._onHideStickersClick = this._onHideStickersClick.bind(this);
        this._launchManageIntegrations = this._launchManageIntegrations.bind(this);
        this._removeStickerpickerWidgets = this._removeStickerpickerWidgets.bind(this);
        this._onWidgetAction = this._onWidgetAction.bind(this);
        this.onFinished = this.onFinished.bind(this);

        this.popoverWidth = 300;
        this.popoverHeight = 300;

        this.state = {
            stickersContent: this.defaultStickersContent(),
            showStickers: false,
            imError: null,
        };
    }

    defaultStickersContent() {
        return (
            <AccessibleButton onClick={this._launchManageIntegrations}
                className='mx_Stickers_contentPlaceholder'>

{ _t("You don't currently have any stickerpacks enabled") }

Add some now

            </AccessibleButton>
        );
    }

    _removeStickerpickerWidgets() {
        console.warn('Removing Stickerpicker widgets');
        if (this.widgetId) {
            this.scalarClient.disableWidgetAssets(widgetType, this.widgetId).then(() => {
                console.warn('Assets disabled');
            }).catch((err) => {
                console.error('Failed to disable assets');
            });
        } else {
            console.warn('No widget ID specified, not disabling assets');
        }

        // Wrap this in a timeout in order to avoid the DOM node from being pulled from under its feet
        setTimeout(() => this.stickersMenu.close());
        Widgets.removeStickerpickerWidgets().then(() => {
            this._getStickerPickerWidget();
        }).catch((e) => {
            console.error('Failed to remove sticker picker widget', e);
        });
    }

    componentDidMount() {
        this.scalarClient = null;
        if (SdkConfig.get().integrations_ui_url && SdkConfig.get().integrations_rest_url) {
            this.scalarClient = new ScalarAuthClient();
            this.scalarClient.connect().then(() => {
                this.forceUpdate();
            }).catch((e) => {
                this._imError("Failed to connect to integrations server", e);
            });
        }

        if (!this.state.imError) {
            this._getStickerPickerWidget();
            this.dispatcherRef = dis.register(this._onWidgetAction);
        }
    }

    componentWillUnmount() {
        if (this.dispatcherRef) {
            dis.unregister(this.dispatcherRef);
        }
    }

    _imError(errorMsg, e) {
        console.error(errorMsg, e);
        const imErrorContent =

 { errorMsg }

;
        this.setState({
            showStickers: false,
            imError: errorMsg,
            stickersContent: imErrorContent,
        });
    }

    _onWidgetAction(payload) {
        if (payload.action === "user_widget_updated") {
            this._getStickerPickerWidget();
            return;
        } else if (payload.action === "stickerpicker_close") {
            // Wrap this in a timeout in order to avoid the DOM node from being pulled from under its feet
            setTimeout(() => this.stickersMenu.close());
        }
    }

    _getStickerPickerWidget() {
        // Stickers
        // TODO - Add support for Stickerpickers from multiple app stores.
        // Render content from multiple stickerpack sources, each within their own iframe, within the stickerpicker UI element.
        const stickerpickerWidget = Widgets.getStickerpickerWidgets()[0];
        let stickersContent;

        // Load stickerpack content
        if (stickerpickerWidget && stickerpickerWidget.content && stickerpickerWidget.content.url) {
            // Set default name
            stickerpickerWidget.content.name = stickerpickerWidget.name || _t("Stickerpack");
            this.widgetId = stickerpickerWidget.id;

            stickersContent = (

                        <AppTile
                            id={stickerpickerWidget.id}
                            url={stickerpickerWidget.content.url}
                            name={stickerpickerWidget.content.name}
                            room={this.props.room}
                            type={stickerpickerWidget.content.type}
                            fullWidth={true}
                            userId={stickerpickerWidget.sender || MatrixClientPeg.get().credentials.userId}
                            creatorUserId={MatrixClientPeg.get().credentials.userId}
                            waitForIframeLoad={true}
                            show={true}
                            showMenubar={true}
                            onEditClick={this._launchManageIntegrations}
                            onDeleteClick={this._removeStickerpickerWidgets}
                            showTitle={false}
                            showMinimise={true}
                            showDelete={false}
                            onMinimiseClick={this._onHideStickersClick}
                            handleMinimisePointerEvents={true}
                            whitelistCapabilities={['m.sticker']}
                        />

            );
        } else {
            // Default content to show if stickerpicker widget not added
            console.warn("No available sticker picker widgets");
            stickersContent = this.defaultStickersContent();
            this.widgetId = null;
            this.forceUpdate();
        }
        this.setState({
            showStickers: false,
            stickersContent: stickersContent,
        });
    }

    /**
     * Show the sticker picker overlay
     * If no stickerpacks have been added, show a link to the integration manager add sticker packs page.
     * @param  {Event} e Event that triggered the function
     */
    _onShowStickersClick(e) {
        this._getStickerPickerWidget();
        const GenericElementContextMenu = sdk.getComponent('context_menus.GenericElementContextMenu');
        const buttonRect = e.target.getBoundingClientRect();

        // The window X and Y offsets are to adjust position when zoomed in to page
        const x = buttonRect.right + window.pageXOffset - 42;
        const y = (buttonRect.top + (buttonRect.height / 2) + window.pageYOffset) - 19;
        // const self = this;
        this.stickersMenu = ContextualMenu.createMenu(GenericElementContextMenu, {
            chevronOffset: 10,
            chevronFace: 'bottom',
            left: x,
            top: y,
            menuWidth: this.popoverWidth,
            menuHeight: this.popoverHeight,
            element: this.state.stickersContent,
            onFinished: this.onFinished,
            menuPaddingTop: 0,
        });

        this.setState({showStickers: true});
    }

    /**
     * Trigger hiding of the sticker picker overlay
     * @param  {Event} ev Event that triggered the function call
     */
    _onHideStickersClick(ev) {
        setTimeout(() => this.stickersMenu.close());
    }

    /**
     * The stickers picker was hidden
     */
    onFinished() {
        this.setState({showStickers: false});
    }

    /**
     * Launch the integrations manager on the stickers integration page
     */
    _launchManageIntegrations() {
        const IntegrationsManager = sdk.getComponent("views.settings.IntegrationsManager");
        const src = (this.scalarClient !== null && this.scalarClient.hasCredentials()) ?
                this.scalarClient.getScalarInterfaceUrlForRoom(
                    this.props.room,
                    'type_' + widgetType,
                    this.widgetId,
                ) :
                null;
        Modal.createTrackedDialog('Integrations Manager', '', IntegrationsManager, {
            src: src,
        }, "mx_IntegrationsManager");

        // Wrap this in a timeout in order to avoid the DOM node from being pulled from under its feet
        setTimeout(() => this.stickersMenu.close());
    }

    render() {
        const TintableSvg = sdk.getComponent("elements.TintableSvg");
        let stickersButton;
        if (this.state.showStickers) {
            // Show hide-stickers button
            stickersButton =

                    <TintableSvg src="img/icons-hide-stickers.svg" width="35" height="35" />

;
        } else {
            // Show show-stickers button
            stickersButton =

                    <TintableSvg src="img/icons-show-stickers.svg" width="35" height="35" />

;
        }
        return stickersButton;
    }
}
<|endoftext|>


<commit_before>var bookController = function(bookService) {
	var getIndex = function(req, res) {
		var url = 'mongodb://localhost:27017/libraryApp';
		mongodb.connect(url, function(err, db) {
			var collection = db.collection('books');
			collection.find({}).toArray(function(err, results) {
				res.render('book', {
					title: 'Book',
					nav: [{
						Link: '/authors',
						Text: 'Authors'
					}],
					Books: results
				});
			});
		});
	}
	var getById = function(req, res) {
		var id = new objectId(req.params.id);
		var url = 'mongodb://localhost:27017/libraryApp';
		mongodb.connect(url, function(err, db) {
			var collection = db.collection('books');
			collection.findOne({
					_id: id
				},
				function(err, results) {
					console.log(results);
					res.render('bookView', {
						title: 'Book',
						nav: [{
							Link: '/authors',
							Text: 'Authors'
						}],
						Book: results
					});
				}
			);
		});
	}
	return {
		getIndex: getIndex,
		getById: getById
	}
}<commit_msg>"[GIT AUTO COMMIT]: Tue Jun 20 2017 15:04:09 GMT+0530 (India Standard Time)"<commit_after>var mongodb = require('mongodb').MongoClient;
var objectId = require('mongodb').ObjectID;
var bookController = function(bookService) {
	var getIndex = function(req, res) {
		var url = 'mongodb://localhost:27017/libraryApp';
		mongodb.connect(url, function(err, db) {
			var collection = db.collection('books');
			collection.find({}).toArray(function(err, results) {
				res.render('book', {
					title: 'Book',
					nav: [{
						Link: '/authors',
						Text: 'Authors'
					}],
					Books: results
				});
			});
		});
	}
	var getById = function(req, res) {
		var id = new objectId(req.params.id);
		var url = 'mongodb://localhost:27017/libraryApp';
		mongodb.connect(url, function(err, db) {
			var collection = db.collection('books');
			collection.findOne({
					_id: id
				},
				function(err, results) {
					console.log(results);
					res.render('bookView', {
						title: 'Book',
						nav: [{
							Link: '/authors',
							Text: 'Authors'
						}],
						Book: results
					});
				}
			);
		});
	}
	return {
		getIndex: getIndex,
		getById: getById
	}
}
module.exports = bookController;<|endoftext|>


<commit_before>import { takeLatest, call, put, all, select, take } from 'redux-saga/effects';
import { URLS } from 'common/urls';
import { fetch } from 'common/utils';
import { showModalAction, HIDE_MODAL } from 'controllers/modal';
import { concatFetchDataAction, createFetchPredicate } from 'controllers/fetch';
import { activeProjectSelector } from 'controllers/user';
import {
  activeRetryIdSelector,
  isLaunchLogSelector,
  logViewModeSelector,
  activeRetrySelector,
} from 'controllers/log/selectors';
import { DETAILED_LOG_VIEW } from 'controllers/log/constants';
import { JSON as JSON_TYPE } from 'common/constants/fileTypes';
import { PAGE_KEY, SIZE_KEY } from 'controllers/pagination';
import {
  ATTACHMENT_IMAGE_MODAL_ID,
  ATTACHMENT_CODE_MODAL_ID,
  ATTACHMENT_HAR_FILE_MODAL_ID,
  OPEN_ATTACHMENT_ACTION,
  FETCH_ATTACHMENTS_CONCAT_ACTION,
  ATTACHMENTS_NAMESPACE,
  DEFAULT_PAGE_SIZE,
  DEFAULT_LOADED_PAGES,
  FETCH_FIRST_ATTACHMENTS_ACTION,
} from './constants';
import { setActiveAttachmentAction } from './actionCreators';
import { getAttachmentModalId, extractExtension } from './utils';

function* getAttachmentURL() {
  const activeProject = yield select(activeProjectSelector);
  const isLaunchLog = yield select(isLaunchLogSelector);
  const activeLogItemId = yield select(activeRetryIdSelector);
  if (isLaunchLog) {
    return URLS.launchLogs(activeProject, activeLogItemId);
  }
  const logViewMode = yield select(logViewModeSelector);
  if (logViewMode === DETAILED_LOG_VIEW) {
    const activeRetry = yield select(activeRetrySelector);
    return URLS.logsUnderPath(activeProject, activeRetry.path);
  }
  return URLS.logItems(activeProject, activeLogItemId);
}

function* fetchAttachmentsConcat({ payload: { params, concat } }) {
  const url = yield call(getAttachmentURL);
  yield put(concatFetchDataAction(ATTACHMENTS_NAMESPACE, concat)(url, { params }));
  yield take(createFetchPredicate(ATTACHMENTS_NAMESPACE));
}

function* fetchFirstAttachments({ payload }) {
  const params = {
    'filter.ex.binaryContent': true,
    [SIZE_KEY]: DEFAULT_PAGE_SIZE * DEFAULT_LOADED_PAGES,
    [PAGE_KEY]: 1,
    ...payload.params,
  };
  yield put(setActiveAttachmentAction(null));
  yield call(fetchAttachmentsConcat, { payload: { params } });
}

export function fetchImageData({ binaryId }) {
  return fetch(URLS.getFileById(binaryId), { responseType: 'blob' });
}

export function fetchData({ binaryId }) {
  return fetch(URLS.getFileById(binaryId));
}

/* IMAGE */
function* openImageModalsWorker({ binaryId }) {
  const data = yield call(fetchImageData, { binaryId });
  const imageURL = URL.createObjectURL(data);
  yield put(showModalAction({ id: ATTACHMENT_IMAGE_MODAL_ID, data: { image: imageURL } }));
  yield take(HIDE_MODAL);
  URL.revokeObjectURL(imageURL);
}

/* HAR */
function* openHarModalsWorker(data) {
  const harData = yield call(fetchData, data);
  yield put(showModalAction({ id: ATTACHMENT_HAR_FILE_MODAL_ID, data: { harData } }));
}

/* BINARY */
function* openBinaryModalsWorker(data) {
  const binaryData = yield call(fetchData, data);
  const content = data.extension === JSON_TYPE ? JSON.stringify(binaryData, null, 4) : binaryData;
  yield put(
    showModalAction({
      id: ATTACHMENT_CODE_MODAL_ID,
      data: { extension: data.extension, content },
    }),
  );
}

const ATTACHMENT_MODAL_WORKERS = {
  [ATTACHMENT_IMAGE_MODAL_ID]: openImageModalsWorker,
  [ATTACHMENT_HAR_FILE_MODAL_ID]: openHarModalsWorker,
  [ATTACHMENT_CODE_MODAL_ID]: openBinaryModalsWorker,
};

function* openAttachment({ payload: { id, contentType } }) {
  const modalId = getAttachmentModalId(contentType);
  if (modalId) {
    const data = { binaryId: id, extension: extractExtension(contentType) };
    try {
      yield call(ATTACHMENT_MODAL_WORKERS[modalId], data);
    } catch (e) {} // eslint-disable-line no-empty
  } else {
    const data = yield call(fetch, URLS.getFileById(id), { responseType: 'blob' });
    const url = URL.createObjectURL(data);
    window.open(url);
    URL.revokeObjectURL(url);
  }
}

function* watchFetchAttachments() {
  yield takeLatest(FETCH_ATTACHMENTS_CONCAT_ACTION, fetchAttachmentsConcat);
}

function* watchFetchFirstAttachments() {
  yield takeLatest(FETCH_FIRST_ATTACHMENTS_ACTION, fetchFirstAttachments);
}

function* watchOpenAttachment() {
  yield takeLatest(OPEN_ATTACHMENT_ACTION, openAttachment);
}

export function* attachmentSagas() {
  yield all([watchOpenAttachment(), watchFetchAttachments(), watchFetchFirstAttachments()]);
}
<commit_msg>EPMRPP-40149: React: Js error on attempt to open attachment with .html extension on Edge browser<commit_after>import { takeLatest, call, put, all, select, take } from 'redux-saga/effects';
import { URLS } from 'common/urls';
import { fetch } from 'common/utils';
import { showModalAction, HIDE_MODAL } from 'controllers/modal';
import { concatFetchDataAction, createFetchPredicate } from 'controllers/fetch';
import { activeProjectSelector } from 'controllers/user';
import {
  activeRetryIdSelector,
  isLaunchLogSelector,
  logViewModeSelector,
  activeRetrySelector,
} from 'controllers/log/selectors';
import { DETAILED_LOG_VIEW } from 'controllers/log/constants';
import { JSON as JSON_TYPE } from 'common/constants/fileTypes';
import { PAGE_KEY, SIZE_KEY } from 'controllers/pagination';
import {
  ATTACHMENT_IMAGE_MODAL_ID,
  ATTACHMENT_CODE_MODAL_ID,
  ATTACHMENT_HAR_FILE_MODAL_ID,
  OPEN_ATTACHMENT_ACTION,
  FETCH_ATTACHMENTS_CONCAT_ACTION,
  ATTACHMENTS_NAMESPACE,
  DEFAULT_PAGE_SIZE,
  DEFAULT_LOADED_PAGES,
  FETCH_FIRST_ATTACHMENTS_ACTION,
} from './constants';
import { setActiveAttachmentAction } from './actionCreators';
import { getAttachmentModalId, extractExtension } from './utils';

function* getAttachmentURL() {
  const activeProject = yield select(activeProjectSelector);
  const isLaunchLog = yield select(isLaunchLogSelector);
  const activeLogItemId = yield select(activeRetryIdSelector);
  if (isLaunchLog) {
    return URLS.launchLogs(activeProject, activeLogItemId);
  }
  const logViewMode = yield select(logViewModeSelector);
  if (logViewMode === DETAILED_LOG_VIEW) {
    const activeRetry = yield select(activeRetrySelector);
    return URLS.logsUnderPath(activeProject, activeRetry.path);
  }
  return URLS.logItems(activeProject, activeLogItemId);
}

function* fetchAttachmentsConcat({ payload: { params, concat } }) {
  const url = yield call(getAttachmentURL);
  yield put(concatFetchDataAction(ATTACHMENTS_NAMESPACE, concat)(url, { params }));
  yield take(createFetchPredicate(ATTACHMENTS_NAMESPACE));
}

function* fetchFirstAttachments({ payload }) {
  const params = {
    'filter.ex.binaryContent': true,
    [SIZE_KEY]: DEFAULT_PAGE_SIZE * DEFAULT_LOADED_PAGES,
    [PAGE_KEY]: 1,
    ...payload.params,
  };
  yield put(setActiveAttachmentAction(null));
  yield call(fetchAttachmentsConcat, { payload: { params } });
}

export function fetchImageData({ binaryId }) {
  return fetch(URLS.getFileById(binaryId), { responseType: 'blob' });
}

export function fetchData({ binaryId }) {
  return fetch(URLS.getFileById(binaryId));
}

/* IMAGE */
function* openImageModalsWorker({ binaryId }) {
  const data = yield call(fetchImageData, { binaryId });
  const imageURL = URL.createObjectURL(data);
  yield put(showModalAction({ id: ATTACHMENT_IMAGE_MODAL_ID, data: { image: imageURL } }));
  yield take(HIDE_MODAL);
  URL.revokeObjectURL(imageURL);
}

/* HAR */
function* openHarModalsWorker(data) {
  const harData = yield call(fetchData, data);
  yield put(showModalAction({ id: ATTACHMENT_HAR_FILE_MODAL_ID, data: { harData } }));
}

/* BINARY */
function* openBinaryModalsWorker(data) {
  const binaryData = yield call(fetchData, data);
  const content = data.extension === JSON_TYPE ? JSON.stringify(binaryData, null, 4) : binaryData;
  yield put(
    showModalAction({
      id: ATTACHMENT_CODE_MODAL_ID,
      data: { extension: data.extension, content },
    }),
  );
}

const ATTACHMENT_MODAL_WORKERS = {
  [ATTACHMENT_IMAGE_MODAL_ID]: openImageModalsWorker,
  [ATTACHMENT_HAR_FILE_MODAL_ID]: openHarModalsWorker,
  [ATTACHMENT_CODE_MODAL_ID]: openBinaryModalsWorker,
};

function* openAttachment({ payload: { id, contentType } }) {
  const modalId = getAttachmentModalId(contentType);
  if (modalId) {
    const data = { binaryId: id, extension: extractExtension(contentType) };
    try {
      yield call(ATTACHMENT_MODAL_WORKERS[modalId], data);
    } catch (e) {} // eslint-disable-line no-empty
  } else {
    const data = yield call(fetch, URLS.getFileById(id), { responseType: 'blob' });

    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
      window.navigator.msSaveOrOpenBlob(data);
    } else {
      const url = URL.createObjectURL(data);
      window.open(url);
      URL.revokeObjectURL(url);
    }
  }
}

function* watchFetchAttachments() {
  yield takeLatest(FETCH_ATTACHMENTS_CONCAT_ACTION, fetchAttachmentsConcat);
}

function* watchFetchFirstAttachments() {
  yield takeLatest(FETCH_FIRST_ATTACHMENTS_ACTION, fetchFirstAttachments);
}

function* watchOpenAttachment() {
  yield takeLatest(OPEN_ATTACHMENT_ACTION, openAttachment);
}

export function* attachmentSagas() {
  yield all([watchOpenAttachment(), watchFetchAttachments(), watchFetchFirstAttachments()]);
}
<|endoftext|>


<commit_before>// var markerData = [
//   {lat: 47.604, lng: -122.33},
//   {lat: 47.671, lng: -122.28},
//   {lat: 47.610, lng: -122.33}
// ];

var map;

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 47.604, lng: -122.33},
    zoom: 8
  });
}

function displayMarkers(markerData) {
  var bounds = new google.maps.LatLngBounds();

  for (var i = 0; i < markerData.length; i++) {
    var latlng = new google.maps.LatLng(markerData[i].lat, markerData[i].lng);
    var dateTime = markersData[i].dateTime;
    var address = markersData[i].address;
    var type = markersData[i].type;
    var incidentNum = markersData[i].incidentNum;
    createMarker(latlng, dateTime, address, type, incidentNum);
    bounds.extend(latlng);
  }

  map.fitBounds(bounds);
}

function createMarker(latlng) {
  var marker = new google.maps.Marker({
    map: map,
    position: latlng
  });
}
<commit_msg>Rendering info window<commit_after>var map;
var infoWindow;

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 47.604, lng: -122.33},
    zoom: 8
  });

  infoWindow = new google.maps.InfoWindow();
  google.maps.event.addListener(map, 'click', function() {
    infoWindow.close();
  });
}

function displayMarkers(markersData) {
  var bounds = new google.maps.LatLngBounds();

  for (var i = 0; i < markersData.length; i++) {
    var latlng = new google.maps.LatLng(markersData[i].lat, markersData[i].lng);
    var dateTime = markersData[i].dateTime;
    var address = markersData[i].address;
    var type = markersData[i].type;
    var incidentNum = markersData[i].incidentNum;
    createMarker(latlng, dateTime, address, type, incidentNum);
    bounds.extend(latlng);
  }

  map.fitBounds(bounds);
}

function createMarker(latlng, dateTime, address, type, incidentNum) {
  var marker = new google.maps.Marker({
    map: map,
    position: latlng,
    title: type
  });

  google.maps.event.addListener(marker, 'click', function() {
    var content = '
Type: ' + type + '
' +
      '
Date: ' + dateTime + '
' +
      'Address: ' + address + '
' +
      'Incident Number: ' + incidentNum + '
';

    infoWindow.setContent(content);

    infoWindow.open(map, marker);
  });
}
<|endoftext|>


<commit_before>"use strict";

/*global module, require*/

var d3 = require("d3"),
    blank = "#D0D0D0";

var scale = function(data, colour) {
    var numeric = [];
    var len = data.length;
    for (var i = 0; i < len; i++) {
	var r = parseFloat(data[i]);
	if (data[i] && isNaN(r)) {
	    return d3.scale.category20();
	} else {
	    numeric.push(r);
	}
    }

    return d3.scale.linear()
	.domain([d3.min(numeric), d3.max(numeric)])
	.range(["white", colour])
	.interpolate(d3.interpolateLab);
};

/*
 Used to make readable foreground colours against a coloured background.
 */
var reverse = function(colour) {
    var rgb = d3.rgb(colour),
	lab = d3.lab(rgb.toString()),
	newL = (lab.l + 50) % 100;

    if (Math.abs(lab.a - lab.b) < 20) {
	return d3.lab(
	    newL,
	    lab.a + 128,
	    lab.b - 128
	);

    } else {
	return d3.lab(
	    newL,
		-lab.a,
		-lab.b
	);
    }
};

module.exports = {
    scale: scale,
    reverse: reverse
};
<commit_msg>Slightly less garish colours.<commit_after>"use strict";

/*global module, require*/

var d3 = require("d3"),
    blank = "#D0D0D0";

var scale = function(data, colour) {
    var numeric = [];
    var len = data.length;
    for (var i = 0; i < len; i++) {
	var r = parseFloat(data[i]);
	if (data[i] && isNaN(r)) {
	    return d3.scale.category20();
	} else {
	    numeric.push(r);
	}
    }

    return d3.scale.linear()
	.domain([d3.min(numeric), d3.max(numeric)])
	.range(["white", colour])
	.interpolate(d3.interpolateLab);
};

/*
 Used to make readable foreground colours against a coloured background.
 */
var reverse = function(colour) {
    var rgb = d3.rgb(colour),
	lab = d3.lab(rgb.toString()),
	newL = (lab.l + 50) % 100;

    if (Math.abs(lab.a - lab.b) < 20) {
	return d3.lab(
	    newL,
	    lab.a + 64,
	    lab.b - 64
	);

    } else {
	return d3.lab(
	    newL,
		-lab.a,
		-lab.b
	);
    }
};

module.exports = {
    scale: scale,
    reverse: reverse
};
<|endoftext|>


<commit_before>var Client = function () {
    'use strict';

    var commandMap = {
        240: 'SE',
        241: 'NOP',
        242: 'Data Mark',
        243: 'BRK',
        244: 'IP',
        245: 'AO',
        246: 'AYT',
        247: 'EC',
        248: 'EL',
        249: 'GA',
        250: 'SB',
        251: 'WILL',
        252: "WON'T",
        253: 'DO',
        254: "DON'T",
        255: 'IAC',
    };

    var commandToString = function (command) {
        if (!commandMap.hasOwnProperty(command)) {
            return sprintf('Unknown <%d>', command);
            throw {
                name: 'ValueError',
                message: 'Invalid command detected: ' + command.toString(),
            };
        }
        return commandMap[command];
    };

    return {
        socket: null,
        outputElem: null,
        currentLine: null,
        continueLine: false,  // Probably not used so often with MUDs...
        passwordPrompt: false,
        shouldAutoScroll: true,
        currentCommand: null,
        outputBuffer: null,
        maxBufferLines: 1000,
        ansiState: {
            parsing: false,
            currentCode: [],
            outputState: {},
        },
        initialize: function (outputElem) {
            this.currentCommand = [];
            this.outputBuffer = "";
            this.outputElem = outputElem;
            var client = this;
            this.outputElem.addEventListener('scroll', function () {
                client.shouldAutoScroll = (
                    client.outputElem.scrollTop ===
                    client.outputElem.scrollHeight - client.outputElem.clientHeight
                );
            });
        },
        connect: function (addr) {
            this.socket = new WebSocket(addr, ["telnet"]);
            this.socket.addEventListener('message', this.onMessage.bind(this));
            return this.socket;
        },
        sendInput: function (userInput) {
            /* Sends input to the MUD.

               This function returns true if the input received should
               be retained, and false if it should not (i.e. if this
               input was believed to be in response to a password
               prompt).
             */
            this.socket.send(userInput + '\n');

            // Dunno if we were continuing a previous line, but we
            // aren't now.
            this.continueLine = false;
            this.createNewLine();
            if (this.passwordPrompt) {
                return false;
            } else {
                this.appendLine(userInput);
                return true;
            }
        },
        onMessage: function (event) {
            var fr = new FileReader();
            var client = this;
            fr.addEventListener('loadend', function () {
                return client.handleMessage(fr.result);
            });
            fr.readAsArrayBuffer(event.data);
        },
        handleMessage: function (buffer) {
            var rawOutputBuffer = []
            var uint8 = new Uint8Array(buffer, 0, buffer.length);
            for (var i=0; i<uint8.length; i++) {
                var byte = uint8[i];
                if (this.currentCommand.length === 0) {
                    if (byte === 255) {  // Interpret as Command (IAC)
                        this.currentCommand.push(byte);
                    } else {
                        rawOutputBuffer.push(byte);
                    }
                } else {
                    this.currentCommand.push(byte);
                    if (this.currentCommand.length === 2) {
                        if (byte < 240) {
                            // Invalid telnet command
                            console.log(this.currentCommand.map(commandToString));
                            this.currentCommand = [];
                        } else if (240 <= byte && byte <= 250) {
                            // Valid 2-byte telnet command
                            console.log(this.currentCommand.map(commandToString));
                            // TO DO: do something with this ;)
                            this.currentCommand = [];
                        } else if (251 <= byte && byte <= 254) {
                            // Second byte of a 3-byte command; do nothing yet
                        } else if (byte === 255) {
                            // Literal byte 255
                            rawOutputBuffer.push(byte)
                            this.currentCommand = [];
                        }
                    } else if (this.currentCommand.length === 3) {
                        console.log(this.currentCommand.map(commandToString));
                        // TO DO: do something with this ;)
                        this.currentCommand = [];
                    }
                    // Try to interpret command
                }
            }
            var output = String.fromCharCode.apply(null, rawOutputBuffer);
            this.pushOutput(output);
        },
        pushOutput: function (output) {
            var client = this;
            // Precede output with any leftover bits from previous packets
            output = client.outputBuffer + output;
            var lines = output.split('\n\r');
            lines.forEach(function (line) {
                var lineElem;
                if (client.continueLine) {
                    lineElem = client.currentLine;
                    client.continueLine = false;
                } else {
                    lineElem = client.createNewLine();
                    if (line.trim().length === 0) {
                        // Workaround for empty lines
                        lineElem.innerHTML = ' ';
                        return;
                    }
                }
                if (line.charAt(line.length-1) === '\n') {
                    client.outputBuffer = '\n';
                    line = line.slice(0, line.length-2);
                }
                client.appendLine(line);
            });
            // If we ended on a new line, our final line in the
            // line list should be empty.  If this is *not* true,
            // then we should continue from the current line on
            // the next call.
            client.continueLine = lines[lines.length-1] !== '';
        },
        createNewLine: function () {
            var lineElem = document.createElement('div');
            lineElem.classList.add('output-line');
            var shouldScroll = this.shouldAutoScroll;
            while (this.maxBufferLines <= this.outputElem.querySelectorAll('div.output-line').length) {
                this.outputElem.removeChild(this.outputElem.querySelector('div.output-line'));
            }
            this.outputElem.appendChild(lineElem);
            this.currentLine = lineElem;
            if (shouldScroll) {
                // Seems we need to release to the browser to allow redrawing/resizing.
                setTimeout(this.autoScroll.bind(this), 0);
            }
            return lineElem;
        },
        appendLine: function (output) {
            var shouldScroll = this.shouldAutoScroll;
            var coloredOutput = this.getColoredOutput(output);
            this.currentLine.innerHTML += coloredOutput;
            this.detectPasswordPrompt(output);  // Could break on partial packets...
            if (shouldScroll) {
                setTimeout(this.autoScroll.bind(this), 0);
            }
        },
        getColoredOutput: function (output) {
            /*
              - Track current ANSI "state".
              - For each ANSI code encountered:
                - Update the state.
                - Close the previous span (if needed)
              - For each normal character encountered:
                - Open a new span based on the current state (if needed)
                - Append the HTML-escaped character
             */
            var result = [];
            var i, c;
            var client = this;
            var inSpan = false;
            for (i=0; i<output.length; i++) {
                c = output.charCodeAt(i);
                if (!client.ansiState.parsing) {
                    if (c === 27) {
                        client.ansiState.parsing = true;
                        client.ansiState.currentCode = [];
                    } else {
                        if (client.ansiState.changed === true) {
                            client.ansiState.changed = false;
                            if (inSpan) {
                                result.push('');
                            }
                            if (0 < Object.keys(client.ansiState.outputState).length) {
                                inSpan = true;
                                // TO DO: Create the *real* span.
                                var spanClasses = [];
                                if (client.ansiState.outputState.fgColor) {
                                    spanClasses.push(client.ansiState.outputState.fgColor);
                                }
                                if (client.ansiState.outputState.fgIntensity) {
                                    spanClasses.push('intense');
                                }
                                if (client.ansiState.outputState.bgColor) {
                                    spanClasses.push(sprintf('bg-%s', client.ansiState.outputState.bgColor));
                                }
                                spanClasses = spanClasses.join(' ');
                                result.push(
                                    _.template(
                                        '<span<% if (classes.length > 0) { %> class="<%- classes %>"<% } %>>'
                                    )({classes: spanClasses})
                                );
                            }
                        }
                        // TO DO: close previous span if needed
                        // TO DO: open new span if needed
                        result.push(client.escapeChar(String.fromCharCode(c)));
                    }
                } else {
                    if (client.ansiState.currentCode.length === 0) {
                        if (c === 91) {  // [
                            client.ansiState.currentCode.push(c);
                        } else if (64 <= c && c <= 95) {
                            // Not sure if I need any of these for now.
                            console.error(sprintf('Two character ansi sequence: [27, %d]', c));
                        } else {
                            // Wikipedia implies client is invalid.
                            console.error(sprintf('Unexpected ansi sequence: [27, %d]', c));
                        }
                    } else {
                        if (64 <= c && c <= 126) {
                            if (c === 109) {  // m ("SGR - Select Graphic Rendition")
                                var params = client.ansiState.currentCode.slice(1);
                                params = params.map(function (charCode) {return String.fromCharCode(charCode)});
                                params = params.join('').split(';');
                                if (params.length === 1 && params[0] === '') {
                                    params = ['0'];
                                }
                                params = params.map(function (param) {
                                    return parseInt(param);
                                });
                                client._handleSGR(params);
                            } else {
                                client.ansiState.currentCode.push(c);
                                console.log('ANSI CSI sequence:',
                                            client.ansiState.currentCode.map(String.fromCharCode).join(''));
                            }
                            //console.log('Current output state:', client.ansiState.outputState);
                            client.ansiState.parsing = false;
                        } else {
                            client.ansiState.currentCode.push(c);
                        }
                    }
                }
            }
            if (inSpan) {
                result.push('');
            }
            return result.join('');
        },
        _handleSGR: function (params) {
            var client = this;
            params.forEach(function (param) {
                if (client.ansiState.parsingExtendedColor) {
                    if (!client.ansiState.extendedColor) {
                        client.ansiState.extendedColor = [param];
                    } else if (client.ansiState.extendedColor[0] === 5) {
                        // xterm 256 color mode
                        var colorClass = sprintf('xterm-%d', param);
                        if (client.ansiState.parsingExtendedFgColor) {
                            client.ansiState.outputState.fgColor = colorClass;
                        } else {
                            client.ansiState.outputState.bgColor = colorClass;
                        }
                        client.ansiState.parsingExtendedColor = false;
                        client.ansiState.extendedColor = null;
                        client.ansiState.changed = true;
                    } else if (client.ansiState.extendedColor[0] === 2) {
                        // 24-bit color mode... not yet supported, but
                        // we should at least collect the bytes.
                        client.ansiState.extendedColor.push(param);
                        if (client.ansiState.extendedColor.length === 4) {
                            console.log('Received 24-bit color code (unsupported):', client.ansiState.extendedColor.slice(1));
                            client.ansiState.parsingExtendedColor = false;
                            client.ansiState.extendedColor = null;
                        }
                    } else {
                        console.error('Unexpected extended color prefix:', client.ansiState.extendedColor[0]);
                        client.ansiState.parsingExtendedColor = false;
                        client.ansiState.extendedColor = null;
                    }
                } else {
                    if (param === 0) {
                        client.ansiState.outputState = {};
                        client.ansiState.changed = true;
                    } else if (param === 1) {
                        client.ansiState.outputState.fgIntensity = true;
                        client.ansiState.changed = true;
                    } else if (30 <= param && param <= 37) {
                        // FG colors
                        client.ansiState.outputState.fgColor = client.getColor(param % 10);
                        client.ansiState.changed = true;
                    } else if (param === 38) {
                        // FG extended color
                        client.ansiState.parsingExtendedColor = true;
                        client.ansiState.parsingExtendedFgColor = true;
                    } else if (param === 39) {
                        delete client.ansiState.outputState.fgColor;
                        client.ansiState.changed = true;
                    } else if (40 <= param && param <= 47) {
                        // BG colors
                        client.ansiState.outputState.bgColor = client.getColor(param % 10);
                        client.ansiState.changed = true;
                    } else if (param === 48) {
                        // BG extended color
                        client.ansiState.parsingExtendedColor = true;
                        client.ansiState.parsingExtendedBgColor = true;
                    } else if (param === 49) {
                        delete client.ansiState.outputState.bgColor;
                        client.ansiState.changed = true;
                    } else {
                        console.log(
                            sprintf(
                                'SGR: %s contains unexpected param at index %d',
                                client.ansiState.currentCode.map(String.fromCharCode).join('') + 'm',
                                index
                            )
                        );
                    }
                }
            });
        },
        getColor: function (i) {
            return {
                0: 'black',
                1: 'red',
                2: 'green',
                3: 'yellow',
                4: 'blue',
                5: 'magenta',
                6: 'cyan',
                7: 'white',
            }[i];
        },
        escapeChar: function (c) {
            // ONLY for use as the *content* of an element.
            // DO NOT USE IN ATTRIBUTES!
            // For more robust escaping: http://wonko.com/post/html-escaping
            if (c === '<') {
                return '<';
            } else if (c === '>') {
                return '>';
            } else {
                return c;
            }
        },
        detectPasswordPrompt: function (output) {
            this.passwordPrompt = (output.toLowerCase().indexOf('password') === 0);
        },
        autoScroll: function () {
            var newScrollTop = this.outputElem.scrollHeight - this.outputElem.clientHeight;
            this.outputElem.scrollTop = this.outputElem.scrollHeight - this.outputElem.clientHeight;
        },
    };
}();
<commit_msg>Minor tweaks related to input of passwords or blank lines.  Also started to add support for MUDs which send text frames instead of binary frames (although I am not confident this is good/correct, at least not yet).<commit_after>var Client = function () {
    'use strict';

    var commandMap = {
        240: 'SE',
        241: 'NOP',
        242: 'Data Mark',
        243: 'BRK',
        244: 'IP',
        245: 'AO',
        246: 'AYT',
        247: 'EC',
        248: 'EL',
        249: 'GA',
        250: 'SB',
        251: 'WILL',
        252: "WON'T",
        253: 'DO',
        254: "DON'T",
        255: 'IAC',
    };

    var commandToString = function (command) {
        if (!commandMap.hasOwnProperty(command)) {
            return sprintf('Unknown <%d>', command);
            throw {
                name: 'ValueError',
                message: 'Invalid command detected: ' + command.toString(),
            };
        }
        return commandMap[command];
    };

    return {
        socket: null,
        outputElem: null,
        currentLine: null,
        continueLine: false,  // Probably not used so often with MUDs...
        passwordPrompt: false,
        shouldAutoScroll: true,
        currentCommand: null,
        outputBuffer: null,
        maxBufferLines: 1000,
        ansiState: {
            parsing: false,
            currentCode: [],
            outputState: {},
        },
        initialize: function (outputElem) {
            this.currentCommand = [];
            this.outputBuffer = "";
            this.outputElem = outputElem;
            var client = this;
            this.outputElem.addEventListener('scroll', function () {
                client.shouldAutoScroll = (
                    client.outputElem.scrollTop ===
                    client.outputElem.scrollHeight - client.outputElem.clientHeight
                );
            });
        },
        connect: function (addr) {
            this.socket = new WebSocket(addr, ["telnet"]);
            this.socket.addEventListener('message', this.onMessage.bind(this));
            return this.socket;
        },
        sendInput: function (userInput) {
            /* Sends input to the MUD.

               This function returns true if the input received should
               be retained, and false if it should not (i.e. if this
               input was believed to be in response to a password
               prompt).
             */
            this.socket.send(userInput + '\n');

            // Dunno if we were continuing a previous line, but we
            // aren't now.
            this.continueLine = false;
            this.createNewLine();
            if (this.passwordPrompt) {
                this.appendLine(' ');  // Hope this won't break later w/ escaping changes...
                return false;
            } else {
                if (userInput.trim().length === 0) {
                    this.appendLine(' ');  // Hope this won't break later w/ escaping changes...
                } else {
                    this.appendLine(userInput);
                }
                return true;
            }
        },
        onMessage: function (event) {
            var client = this;
            if (event.data.size) {
                // event.data is likely a blob
                var fr = new FileReader();
                fr.addEventListener('loadend', function () {
                    var uint8 = new Uint8Array(fr.result, 0, fr.result.length);
                    client.handleMessage(uint8);
                });
                fr.readAsArrayBuffer(event.data);
            } else {
                // event.data is likely text
                // Attempt to convert to bytes
                var encoder = new TextEncoder('utf-8');  // Not sure if this is quite right...
                var uint8 = encoder.encode(event.data);
                client.handleMessage(uint8);
            }
        },
        handleMessage: function (buffer) {
            var rawOutputBuffer = []
            for (var i=0; i<buffer.length; i++) {
                var byte = buffer[i];
                if (this.currentCommand.length === 0) {
                    if (byte === 255) {  // Interpret as Command (IAC)
                        this.currentCommand.push(byte);
                    } else {
                        rawOutputBuffer.push(byte);
                    }
                } else {
                    this.currentCommand.push(byte);
                    if (this.currentCommand.length === 2) {
                        if (byte < 240) {
                            // Invalid telnet command
                            console.log(this.currentCommand.map(commandToString));
                            this.currentCommand = [];
                        } else if (240 <= byte && byte <= 250) {
                            // Valid 2-byte telnet command
                            console.log(this.currentCommand.map(commandToString));
                            // TO DO: do something with this ;)
                            this.currentCommand = [];
                        } else if (251 <= byte && byte <= 254) {
                            // Second byte of a 3-byte command; do nothing yet
                        } else if (byte === 255) {
                            // Literal byte 255
                            rawOutputBuffer.push(byte)
                            this.currentCommand = [];
                        }
                    } else if (this.currentCommand.length === 3) {
                        console.log(this.currentCommand.map(commandToString));
                        // TO DO: do something with this ;)
                        this.currentCommand = [];
                    }
                    // Try to interpret command
                }
            }
            var output = String.fromCharCode.apply(null, rawOutputBuffer);
            this.pushOutput(output);
        },
        pushOutput: function (output) {
            var client = this;
            // Precede output with any leftover bits from previous packets
            output = client.outputBuffer + output;
            var lines = output.split('\n\r');
            lines.forEach(function (line) {
                var lineElem;
                if (client.continueLine) {
                    lineElem = client.currentLine;
                    client.continueLine = false;
                } else {
                    lineElem = client.createNewLine();
                    if (line.trim().length === 0) {
                        // Workaround for empty lines
                        lineElem.innerHTML = ' ';
                        return;
                    }
                }
                if (line.charAt(line.length-1) === '\n') {
                    client.outputBuffer = '\n';
                    line = line.slice(0, line.length-2);
                }
                client.appendLine(line);
            });
            // If we ended on a new line, our final line in the
            // line list should be empty.  If this is *not* true,
            // then we should continue from the current line on
            // the next call.
            client.continueLine = lines[lines.length-1] !== '';
        },
        createNewLine: function () {
            var lineElem = document.createElement('div');
            lineElem.classList.add('output-line');
            var shouldScroll = this.shouldAutoScroll;
            while (this.maxBufferLines <= this.outputElem.querySelectorAll('div.output-line').length) {
                this.outputElem.removeChild(this.outputElem.querySelector('div.output-line'));
            }
            this.outputElem.appendChild(lineElem);
            this.currentLine = lineElem;
            if (shouldScroll) {
                // Seems we need to release to the browser to allow redrawing/resizing.
                setTimeout(this.autoScroll.bind(this), 0);
            }
            return lineElem;
        },
        appendLine: function (output) {
            var shouldScroll = this.shouldAutoScroll;
            var coloredOutput = this.getColoredOutput(output);
            this.currentLine.innerHTML += coloredOutput;
            this.detectPasswordPrompt(output);  // Could break on partial packets...
            if (shouldScroll) {
                setTimeout(this.autoScroll.bind(this), 0);
            }
        },
        getColoredOutput: function (output) {
            /*
              - Track current ANSI "state".
              - For each ANSI code encountered:
                - Update the state.
                - Close the previous span (if needed)
              - For each normal character encountered:
                - Open a new span based on the current state (if needed)
                - Append the HTML-escaped character
             */
            var result = [];
            var i, c;
            var client = this;
            var inSpan = false;
            for (i=0; i<output.length; i++) {
                c = output.charCodeAt(i);
                if (!client.ansiState.parsing) {
                    if (c === 27) {
                        client.ansiState.parsing = true;
                        client.ansiState.currentCode = [];
                    } else {
                        if (client.ansiState.changed === true) {
                            client.ansiState.changed = false;
                            if (inSpan) {
                                result.push('');
                            }
                            if (0 < Object.keys(client.ansiState.outputState).length) {
                                inSpan = true;
                                // TO DO: Create the *real* span.
                                var spanClasses = [];
                                if (client.ansiState.outputState.fgColor) {
                                    spanClasses.push(client.ansiState.outputState.fgColor);
                                }
                                if (client.ansiState.outputState.fgIntensity) {
                                    spanClasses.push('intense');
                                }
                                if (client.ansiState.outputState.bgColor) {
                                    spanClasses.push(sprintf('bg-%s', client.ansiState.outputState.bgColor));
                                }
                                spanClasses = spanClasses.join(' ');
                                result.push(
                                    _.template(
                                        '<span<% if (classes.length > 0) { %> class="<%- classes %>"<% } %>>'
                                    )({classes: spanClasses})
                                );
                            }
                        }
                        // TO DO: close previous span if needed
                        // TO DO: open new span if needed
                        result.push(client.escapeChar(String.fromCharCode(c)));
                    }
                } else {
                    if (client.ansiState.currentCode.length === 0) {
                        if (c === 91) {  // [
                            client.ansiState.currentCode.push(c);
                        } else if (64 <= c && c <= 95) {
                            // Not sure if I need any of these for now.
                            console.error(sprintf('Two character ansi sequence: [27, %d]', c));
                        } else {
                            // Wikipedia implies client is invalid.
                            console.error(sprintf('Unexpected ansi sequence: [27, %d]', c));
                        }
                    } else {
                        if (64 <= c && c <= 126) {
                            if (c === 109) {  // m ("SGR - Select Graphic Rendition")
                                var params = client.ansiState.currentCode.slice(1);
                                params = params.map(function (charCode) {return String.fromCharCode(charCode)});
                                params = params.join('').split(';');
                                if (params.length === 1 && params[0] === '') {
                                    params = ['0'];
                                }
                                params = params.map(function (param) {
                                    return parseInt(param);
                                });
                                client._handleSGR(params);
                            } else {
                                client.ansiState.currentCode.push(c);
                                console.log('ANSI CSI sequence:',
                                            client.ansiState.currentCode.map(String.fromCharCode).join(''));
                            }
                            //console.log('Current output state:', client.ansiState.outputState);
                            client.ansiState.parsing = false;
                        } else {
                            client.ansiState.currentCode.push(c);
                        }
                    }
                }
            }
            if (inSpan) {
                result.push('');
            }
            return result.join('');
        },
        _handleSGR: function (params) {
            var client = this;
            params.forEach(function (param) {
                if (client.ansiState.parsingExtendedColor) {
                    if (!client.ansiState.extendedColor) {
                        client.ansiState.extendedColor = [param];
                    } else if (client.ansiState.extendedColor[0] === 5) {
                        // xterm 256 color mode
                        var colorClass = sprintf('xterm-%d', param);
                        if (client.ansiState.parsingExtendedFgColor) {
                            client.ansiState.outputState.fgColor = colorClass;
                        } else {
                            client.ansiState.outputState.bgColor = colorClass;
                        }
                        client.ansiState.parsingExtendedColor = false;
                        client.ansiState.extendedColor = null;
                        client.ansiState.changed = true;
                    } else if (client.ansiState.extendedColor[0] === 2) {
                        // 24-bit color mode... not yet supported, but
                        // we should at least collect the bytes.
                        client.ansiState.extendedColor.push(param);
                        if (client.ansiState.extendedColor.length === 4) {
                            console.log('Received 24-bit color code (unsupported):', client.ansiState.extendedColor.slice(1));
                            client.ansiState.parsingExtendedColor = false;
                            client.ansiState.extendedColor = null;
                        }
                    } else {
                        console.error('Unexpected extended color prefix:', client.ansiState.extendedColor[0]);
                        client.ansiState.parsingExtendedColor = false;
                        client.ansiState.extendedColor = null;
                    }
                } else {
                    if (param === 0) {
                        client.ansiState.outputState = {};
                        client.ansiState.changed = true;
                    } else if (param === 1) {
                        client.ansiState.outputState.fgIntensity = true;
                        client.ansiState.changed = true;
                    } else if (30 <= param && param <= 37) {
                        // FG colors
                        client.ansiState.outputState.fgColor = client.getColor(param % 10);
                        client.ansiState.changed = true;
                    } else if (param === 38) {
                        // FG extended color
                        client.ansiState.parsingExtendedColor = true;
                        client.ansiState.parsingExtendedFgColor = true;
                    } else if (param === 39) {
                        delete client.ansiState.outputState.fgColor;
                        client.ansiState.changed = true;
                    } else if (40 <= param && param <= 47) {
                        // BG colors
                        client.ansiState.outputState.bgColor = client.getColor(param % 10);
                        client.ansiState.changed = true;
                    } else if (param === 48) {
                        // BG extended color
                        client.ansiState.parsingExtendedColor = true;
                        client.ansiState.parsingExtendedBgColor = true;
                    } else if (param === 49) {
                        delete client.ansiState.outputState.bgColor;
                        client.ansiState.changed = true;
                    } else {
                        console.log(
                            sprintf(
                                'SGR: %s contains unexpected param at index %d',
                                client.ansiState.currentCode.map(String.fromCharCode).join('') + 'm',
                                index
                            )
                        );
                    }
                }
            });
        },
        getColor: function (i) {
            return {
                0: 'black',
                1: 'red',
                2: 'green',
                3: 'yellow',
                4: 'blue',
                5: 'magenta',
                6: 'cyan',
                7: 'white',
            }[i];
        },
        escapeChar: function (c) {
            // ONLY for use as the *content* of an element.
            // DO NOT USE IN ATTRIBUTES!
            // For more robust escaping: http://wonko.com/post/html-escaping
            if (c === '<') {
                return '<';
            } else if (c === '>') {
                return '>';
            } else {
                return c;
            }
        },
        detectPasswordPrompt: function (output) {
            this.passwordPrompt = (output.toLowerCase().indexOf('password') === 0);
        },
        autoScroll: function () {
            var newScrollTop = this.outputElem.scrollHeight - this.outputElem.clientHeight;
            this.outputElem.scrollTop = this.outputElem.scrollHeight - this.outputElem.clientHeight;
        },
    };
}();
<|endoftext|>