<commit_before>/*
 * Copyright (C) 2014 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration. All Rights Reserved.
 */
/**
 * Illustrates how to display text at screen positions. Uses offsets to align the text relative to its position.
 *
 * @version $Id: ScreenText.js 3320 2015-07-15 20:53:05Z dcollins $
 */

requirejs(['../src/WorldWind',
        './LayerManager'],
    function (ww,
              LayerManager) {
        "use strict";

        // Tell World Wind to log only warnings.
        WorldWind.Logger.setLoggingLevel(WorldWind.Logger.LEVEL_WARNING);

        // Create the World Window.
        var wwd = new WorldWind.WorldWindow("canvasOne");

        /**
         * Added imagery layers.
         */
        var layers = [
            {layer: new WorldWind.BMNGLayer(), enabled: true},
            {layer: new WorldWind.BMNGLandsatLayer(), enabled: false},
            {layer: new WorldWind.BingAerialWithLabelsLayer(null), enabled: true},
            {layer: new WorldWind.OpenStreetMapImageLayer(null), enabled: false},
            {layer: new WorldWind.CompassLayer(), enabled: true},
            {layer: new WorldWind.CoordinatesDisplayLayer(wwd), enabled: true},
            {layer: new WorldWind.ViewControlsLayer(wwd), enabled: true}
        ];

        for (var l = 0; l < layers.length; l++) {
            layers[l].layer.enabled = layers[l].enabled;
            wwd.addLayer(layers[l].layer);
        }

        var screenText,
            textAttributes = new WorldWind.TextAttributes(null),
            textLayer = new WorldWind.RenderableLayer("Screen Text");

        // Set up the common text attributes.
        textAttributes.color = WorldWind.Color.RED;

        // Create a screen text shape and its attributes.
        screenText = new WorldWind.ScreenText(
            new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 0, WorldWind.OFFSET_FRACTION, 1), "Upper Left");
        textAttributes = new WorldWind.TextAttributes(textAttributes);
        // Use offset to position the upper left corner of the text string at the shape's screen location.
        textAttributes.offset = new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 0, WorldWind.OFFSET_FRACTION, 1);
        screenText.attributes = textAttributes;
        textLayer.addRenderable(screenText);

        screenText = new WorldWind.ScreenText(
            new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 0, WorldWind.OFFSET_FRACTION, 0), "Lower Left");
        textAttributes = new WorldWind.TextAttributes(textAttributes);
        // Use offset to position the lower left corner of the text string at the shape's screen location.
        textAttributes.offset = new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 0, WorldWind.OFFSET_FRACTION, 0);
        screenText.attributes = textAttributes;
        textLayer.addRenderable(screenText);

        screenText = new WorldWind.ScreenText(
            new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 1, WorldWind.OFFSET_FRACTION, 1), "Upper Right");
        textAttributes = new WorldWind.TextAttributes(textAttributes);
        // Use offset to position the upper right corner of the text string at the shape's screen location.
        textAttributes.offset = new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 1, WorldWind.OFFSET_FRACTION, 1);
        screenText.attributes = textAttributes;
        textLayer.addRenderable(screenText);

        screenText = new WorldWind.ScreenText(
            new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 1, WorldWind.OFFSET_FRACTION, 0), "Lower Right");
        textAttributes = new WorldWind.TextAttributes(textAttributes);
        // Use offset to position the lower right corner of the text string at the shape's screen location.
        textAttributes.offset = new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 1, WorldWind.OFFSET_FRACTION, 0);
        screenText.attributes = textAttributes;
        textLayer.addRenderable(screenText);

        screenText = new WorldWind.ScreenText(
            new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 0.5, WorldWind.OFFSET_FRACTION, 0.5), "Center");
        textAttributes = new WorldWind.TextAttributes(textAttributes);
        // Use offset to position the center of the text string at the shape's screen location.
        textAttributes.offset = new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 0.5, WorldWind.OFFSET_FRACTION, 0.5);
        screenText.attributes = textAttributes;
        textLayer.addRenderable(screenText);

        // Add the text layer to the World Window's layer list.
        wwd.addLayer(textLayer);

        // Create a layer manager for controlling layer visibility.
        var layerManger = new LayerManager(wwd);
    });<commit_msg>Added picking to ScreenText example.<commit_after>/*
 * Copyright (C) 2014 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration. All Rights Reserved.
 */
/**
 * Illustrates how to display text at screen positions. Uses offsets to align the text relative to its position.
 *
 * @version $Id: ScreenText.js 3320 2015-07-15 20:53:05Z dcollins $
 */

requirejs(['../src/WorldWind',
        './LayerManager'],
    function (ww,
              LayerManager) {
        "use strict";

        // Tell World Wind to log only warnings.
        WorldWind.Logger.setLoggingLevel(WorldWind.Logger.LEVEL_WARNING);

        // Create the World Window.
        var wwd = new WorldWind.WorldWindow("canvasOne");

        /**
         * Added imagery layers.
         */
        var layers = [
            {layer: new WorldWind.BMNGLayer(), enabled: true},
            {layer: new WorldWind.BMNGLandsatLayer(), enabled: false},
            {layer: new WorldWind.BingAerialWithLabelsLayer(null), enabled: true},
            {layer: new WorldWind.OpenStreetMapImageLayer(null), enabled: false},
            {layer: new WorldWind.CompassLayer(), enabled: true},
            {layer: new WorldWind.CoordinatesDisplayLayer(wwd), enabled: true},
            {layer: new WorldWind.ViewControlsLayer(wwd), enabled: true}
        ];

        for (var l = 0; l < layers.length; l++) {
            layers[l].layer.enabled = layers[l].enabled;
            wwd.addLayer(layers[l].layer);
        }

        var screenText,
            textAttributes = new WorldWind.TextAttributes(null),
            textLayer = new WorldWind.RenderableLayer("Screen Text");

        // Set up the common text attributes.
        textAttributes.color = WorldWind.Color.RED;

        // Create a screen text shape and its attributes.
        screenText = new WorldWind.ScreenText(
            new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 0, WorldWind.OFFSET_FRACTION, 1), "Upper Left");
        textAttributes = new WorldWind.TextAttributes(textAttributes);
        // Use offset to position the upper left corner of the text string at the shape's screen location.
        textAttributes.offset = new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 0, WorldWind.OFFSET_FRACTION, 1);
        screenText.attributes = textAttributes;
        textLayer.addRenderable(screenText);

        screenText = new WorldWind.ScreenText(
            new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 0, WorldWind.OFFSET_FRACTION, 0), "Lower Left");
        textAttributes = new WorldWind.TextAttributes(textAttributes);
        // Use offset to position the lower left corner of the text string at the shape's screen location.
        textAttributes.offset = new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 0, WorldWind.OFFSET_FRACTION, 0);
        screenText.attributes = textAttributes;
        textLayer.addRenderable(screenText);

        screenText = new WorldWind.ScreenText(
            new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 1, WorldWind.OFFSET_FRACTION, 1), "Upper Right");
        textAttributes = new WorldWind.TextAttributes(textAttributes);
        // Use offset to position the upper right corner of the text string at the shape's screen location.
        textAttributes.offset = new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 1, WorldWind.OFFSET_FRACTION, 1);
        screenText.attributes = textAttributes;
        textLayer.addRenderable(screenText);

        screenText = new WorldWind.ScreenText(
            new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 1, WorldWind.OFFSET_FRACTION, 0), "Lower Right");
        textAttributes = new WorldWind.TextAttributes(textAttributes);
        // Use offset to position the lower right corner of the text string at the shape's screen location.
        textAttributes.offset = new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 1, WorldWind.OFFSET_FRACTION, 0);
        screenText.attributes = textAttributes;
        textLayer.addRenderable(screenText);

        screenText = new WorldWind.ScreenText(
            new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 0.5, WorldWind.OFFSET_FRACTION, 0.5), "Center");
        textAttributes = new WorldWind.TextAttributes(textAttributes);
        // Use offset to position the center of the text string at the shape's screen location.
        textAttributes.offset = new WorldWind.Offset(WorldWind.OFFSET_FRACTION, 0.5, WorldWind.OFFSET_FRACTION, 0.5);
        screenText.attributes = textAttributes;
        textLayer.addRenderable(screenText);

        // Add the text layer to the World Window's layer list.
        wwd.addLayer(textLayer);

        // Create a layer manager for controlling layer visibility.
        var layerManger = new LayerManager(wwd);

        // Set up to handle picking.
        var handlePick = (function (o) {
            var pickPoint = wwd.canvasCoordinates(o.clientX, o.clientY);

            var pickList = wwd.pick(pickPoint);
            if (pickList.objects.length > 0) {
                for (var p = 0; p < pickList.objects.length; p++) {
                    var pickedObject = pickList.objects[p];
                    if (!pickedObject.isTerrain) {
                        if (pickedObject.userObject instanceof WorldWind.ScreenText) {
                            console.log(pickedObject.userObject.text);
                        }
                    }
                }
            }
        }).bind(this);

        // Listen for mouse moves and highlight text that the cursor rolls over.
        wwd.addEventListener("mousemove", handlePick);

        // Listen for taps on mobile devices and highlight text that the user taps.
        var tapRecognizer = new WorldWind.TapRecognizer(wwd, handlePick);
    });<|endoftext|>


<commit_before>/*
 *
 * Description:
 * This file holds the controller logic.  It manages the connection to the Atmega328.
 *
 */
var path = require('path'), spawn = require('child_process').spawn, CONFIG = require('./config'), StatusReader = require('./StatusReader'), ArduinoPhysics = require('./ArduinoPhysics'), logger = require('./logger').create(CONFIG), EventEmitter = require('events').EventEmitter, Hardware = require('../' + CONFIG.Hardware);
var setup_serial = function () {
  var location = path.join(__dirname, '..', './linux');
  logger.log('Starting the script from ' + location + ' to setup UART1...');
  var setuart_process = spawn('sudo', [path.join(location, 'setuart.sh')]);
  setuart_process.on('error', function (err) {
    logger.log('Error while starting the UART1 setup scipt!\nThe error was: ' + err);
  });
};
var statusdata = {};
var settingsCollection = {
    smoothingIncriment: 0,
    deadZone_min: 0,
    deadZone_max: 0
  };

var rovsys = { capabilities: 0 };

var OpenROVController = function (eventLoop, client) {
  var controller = this;
  var serial;
  var globalEventLoop = eventLoop;
  this.physics = new ArduinoPhysics();
  this.hardware = new Hardware();
  this.cockpit = client;

  setInterval(function () {
    controller.emit('status', statusdata);
  }, 1000);

  this.hardware.on('serial-recieved', function (data) {
    globalEventLoop.emit('serial-recieved', data);
  });

  this.hardware.on('status', function (status) {
    for (var i in status) {
      statusdata[i] = status[i];
    }
    if ('ver' in status) {
      controller.ArduinoFirmwareVersion = status.ver;
    }
    if ('TSET' in status) {
      console.log(status.settings);
      var setparts = status.settings.split(',');
      settingsCollection.smoothingIncriment = setparts[0];
      settingsCollection.deadZone_min = setparts[1];
      settingsCollection.deadZone_max = setparts[2];
      controller.emit('Arduino-settings-reported', settingsCollection);
    }
    if ('CAPA' in status) {
      var s = rovsys;
      console.log('RovSys: ' + status.CAPA);
      s.capabilities = parseInt(status.CAPA);
      controller.Capabilities = s.capabilities;
      controller.emit('rovsys', s);
    }
    if ('cmd' in status) {
      if (status.com != 'ping(0)'){
        console.log('cmd: ' + status.cmd);
        controller.emit('command', status.cmd);
      }
    }
    if ('log' in status) {
      console.log('log: ' + status.log);
    }
    if ('boot' in status){
      this.Capabilities = 0;
      controller.updateSetting();
      controller.requestSettings();
      controller.requestCapabilities();
    }
  });
  setup_serial();
  this.hardware.connect();
  controller.ArduinoFirmwareVersion = 0;
  controller.Capabilities = 0;

  controller.notSafeToControl = function () {
    //Arduino is OK to accept commands. After the Capabilities was added, all future updates require
    //being backward safe compatible (meaning you cannot send a command that does something unexpected but
    //instead it should do nothing).
    if (controller.Capabilities !== 0)
      return false;
    //This feature added after the swap to ms on the Arduino
    console.log('Waiting for the capability response from Arduino before sending command.');
    console.log('Arduno Version: ' + controller.ArduinoFirmwareVersion);
    console.log('Capability bitmap: ' + controller.Capabilities);
    return true;
  };

  globalEventLoop.on('register-ArdunoFirmwareVersion', function (val) {
    controller.ArduinoFirmwareVersion = val;
  });
  globalEventLoop.on('register-ArduinoCapabilities', function (val) {
    controller.Capabilities = val;
  });

  globalEventLoop.on('SerialMonitor_toggle_rawSerial', function () {
    controller.hardware.toggleRawSerialData();
  });

  globalEventLoop.on('serial-stop', function () {
    logger.log('Closing serial connection for firmware upload');
    controller.hardware.close();
  });

  globalEventLoop.on('serial-start', function () {
    controller.hardware.connect();
    controller.updateSetting();
    logger.log('Opened serial connection after firmware upload');
  });

  controller.updateSetting();
  //Every few seconds we check to see if capabilities or settings changes on the arduino.
  //This handles the cases where we have garbled communication or a firmware update of the arduino.
  controller.requestSettings();
  controller.requestCapabilities();

  setInterval(function () {
    if (!controller.notSafeToControl()) return;
      controller.updateSetting();
      controller.requestSettings();
      controller.requestCapabilities();
  }, 10000);

  return controller;
};
OpenROVController.prototype = new EventEmitter();
OpenROVController.prototype.constructor = OpenROVController;

OpenROVController.prototype.send = function (cmd) {
  var controller = this;
  if (controller.notSafeToControl())
    return;

  var command = cmd + ';';
  console.log('Sending command to arduino: ' + command);

  controller.hardware.write(command);
};

OpenROVController.prototype.requestCapabilities = function () {
  console.log('Sending rcap to arduino');
  var command = 'rcap();';
  this.hardware.write(command);
};

OpenROVController.prototype.requestSettings = function () {
  var command = 'reportSetting();';
  this.hardware.write(command);
  command = 'rmtrmod();';
  this.hardware.write(command);
};

OpenROVController.prototype.updateSetting = function () {

  var command = 'updateSetting(' + CONFIG.preferences.get('smoothingIncriment') + ',' + CONFIG.preferences.get('deadzone_neg') + ',' + CONFIG.preferences.get('deadzone_pos') + ',' + CONFIG.preferences.get('water_type') + ';';
  this.hardware.write(command);
  //This is the multiplier used to make the motor act linear fashion.
  //for example: the props generate twice the thrust in the positive direction
  //than the negative direction.  To make it linear we have to multiply the
  //negative direction * 2.
  var port = CONFIG.preferences.get('thrust_modifier_port');
  var vertical = CONFIG.preferences.get('thrust_modifier_vertical');
  var starbord = CONFIG.preferences.get('thrust_modifier_starbord');
  var nport = CONFIG.preferences.get('thrust_modifier_nport');
  var nvertical = CONFIG.preferences.get('thrust_modifier_nvertical');
  var nstarbord = CONFIG.preferences.get('thrust_modifier_nstarbord');
  if (CONFIG.preferences.get('reverse_port_thruster')) {
    port = port * -1;
    nport = nport * -1;
  }
  if (CONFIG.preferences.get('reverse_lift_thruster')) {
    vertical = vertical * -1;
    nvertical = nvertical * -1;
  }
  if (CONFIG.preferences.get('reverse_starbord_thruster')) {
    starbord = starbord * -1;
    nstarbord = nstarbord * -1;
  }
  //API to Arduino to pass a percent in 2 decimal accuracy requires multipling by 100 before sending.
  command = 'mtrmod(' + port * 100 + ',' + vertical * 100 + ',' + starbord * 100 + ',' + nport * 100 + ',' + nvertical * 100 + ',' + nstarbord * 100 + ');';
  this.hardware.write(command);
};

OpenROVController.prototype.sendMotorTest = function (port, starbord, vertical) {
  var command = 'go(' + this.physics.mapRawMotor(port) + ',' +
    this.physics.mapRawMotor(vertical) + ',' +
    this.physics.mapRawMotor(starbord) + ',1)';
  //the 1 bypasses motor smoothing
  this.send(command);
};

OpenROVController.prototype.sendCommand = function (throttle, yaw, vertical) {
  var motorCommands = this.physics.mapMotors(throttle, yaw, vertical);
  var command = 'go(' + motorCommands.port + ','
    + motorCommands.vertical + ','
    + motorCommands.starbord + ')';
  this.send(command);
};

OpenROVController.prototype.stop = function (value) {
  var command = 'stop()';
  this.send(command);
};

OpenROVController.prototype.start = function (value) {
  var command = 'start()';
  this.send(command);
};

OpenROVController.prototype.registerPassthrough = function(config) {
  var self = this;
  if (config) {
    if (!config.messagePrefix) {
      throw new Error('You need to specify a messagePrefix that is used to emit and receive message.');
    }
    var messagePrefix = config.messagePrefix
    if (config.fromROV) {
      if (Array.isArray(config.fromROV)) {
        config.fromROV.forEach(function(item) {
          self.on('status', function (data) {
            if (item in data) {
              self.cockpit.emit(messagePrefix+'.'+item, data[item]);
            }
          });
        });
      }
      else { throw new Error('config.fromROV needs to be an array.'); }
    }
    if (config.toROV) {
      if (Array.isArray(config.toROV)) {
        config.toROV.forEach(function(item) {
          self.cockpit.on(messagePrefix+'.'+item, function(data) {
            var arguments = Array.isArray(data) ? data.join() : data;
            var command = item + '(' + arguments + ')';
            self.send(command);
          });
        });
      }
      else { throw new Error('config.fromROV needs to be an array.'); }
    }
  }
};

module.exports = OpenROVController;
<commit_msg>Cleanup<commit_after>/*
 *
 * Description:
 * This file holds the controller logic.  It manages the connection to the Atmega328.
 *
 */
var path = require('path'), spawn = require('child_process').spawn, CONFIG = require('./config'), StatusReader = require('./StatusReader'), ArduinoPhysics = require('./ArduinoPhysics'), logger = require('./logger').create(CONFIG), EventEmitter = require('events').EventEmitter, Hardware = require('../' + CONFIG.Hardware);
var setup_serial = function () {
  var location = path.join(__dirname, '..', './linux');
  logger.log('Starting the script from ' + location + ' to setup UART1...');
  var setuart_process = spawn('sudo', [path.join(location, 'setuart.sh')]);
  setuart_process.on('error', function (err) {
    logger.log('Error while starting the UART1 setup scipt!\nThe error was: ' + err);
  });
};
var statusdata = {};
var settingsCollection = {
    smoothingIncriment: 0,
    deadZone_min: 0,
    deadZone_max: 0
  };

var rovsys = { capabilities: 0 };

var OpenROVController = function (eventLoop, client) {
  var controller = this;
  var serial;
  var globalEventLoop = eventLoop;
  this.physics = new ArduinoPhysics();
  this.hardware = new Hardware();
  this.cockpit = client;

  setInterval(function () {
    controller.emit('status', statusdata);
  }, 1000);

  this.hardware.on('serial-recieved', function (data) {
    globalEventLoop.emit('serial-recieved', data);
  });

  this.hardware.on('status', function (status) {
    for (var i in status) {
      statusdata[i] = status[i];
    }
    if ('ver' in status) {
      controller.ArduinoFirmwareVersion = status.ver;
    }
    if ('TSET' in status) {
      console.log(status.settings);
      var setparts = status.settings.split(',');
      settingsCollection.smoothingIncriment = setparts[0];
      settingsCollection.deadZone_min = setparts[1];
      settingsCollection.deadZone_max = setparts[2];
      controller.emit('Arduino-settings-reported', settingsCollection);
    }
    if ('CAPA' in status) {
      var s = rovsys;
      console.log('RovSys: ' + status.CAPA);
      s.capabilities = parseInt(status.CAPA);
      controller.Capabilities = s.capabilities;
      controller.emit('rovsys', s);
    }
    if ('cmd' in status) {
      if (status.com != 'ping(0)'){
        console.log('cmd: ' + status.cmd);
        controller.emit('command', status.cmd);
      }
    }
    if ('log' in status) {
      console.log('log: ' + status.log);
    }
    if ('boot' in status){
      this.Capabilities = 0;
      controller.updateSetting();
      controller.requestSettings();
      controller.requestCapabilities();
    }
  });
  setup_serial();
  this.hardware.connect();
  controller.ArduinoFirmwareVersion = 0;
  controller.Capabilities = 0;

  controller.notSafeToControl = function () {
    //Arduino is OK to accept commands. After the Capabilities was added, all future updates require
    //being backward safe compatible (meaning you cannot send a command that does something unexpected but
    //instead it should do nothing).
    if (controller.Capabilities !== 0)
      return false;
    //This feature added after the swap to ms on the Arduino
    console.log('Waiting for the capability response from Arduino before sending command.');
    console.log('Arduno Version: ' + controller.ArduinoFirmwareVersion);
    console.log('Capability bitmap: ' + controller.Capabilities);
    return true;
  };

  globalEventLoop.on('register-ArdunoFirmwareVersion', function (val) {
    controller.ArduinoFirmwareVersion = val;
  });
  globalEventLoop.on('register-ArduinoCapabilities', function (val) {
    controller.Capabilities = val;
  });

  globalEventLoop.on('SerialMonitor_toggle_rawSerial', function () {
    controller.hardware.toggleRawSerialData();
  });

  globalEventLoop.on('serial-stop', function () {
    logger.log('Closing serial connection for firmware upload');
    controller.hardware.close();
  });

  globalEventLoop.on('serial-start', function () {
    controller.hardware.connect();
    controller.updateSetting();
    logger.log('Opened serial connection after firmware upload');
  });

  controller.updateSetting();
  //Every few seconds we check to see if capabilities or settings changes on the arduino.
  //This handles the cases where we have garbled communication or a firmware update of the arduino.
  controller.requestSettings();
  controller.requestCapabilities();

  setInterval(function () {
    if (!controller.notSafeToControl()) return;
      controller.updateSetting();
      controller.requestSettings();
      controller.requestCapabilities();
  }, 10000);

  return controller;
};
OpenROVController.prototype = new EventEmitter();
OpenROVController.prototype.constructor = OpenROVController;

OpenROVController.prototype.send = function (cmd) {
  var controller = this;
  if (controller.notSafeToControl())
    return;

  var command = cmd + ';';
  console.log('Sending command to arduino: ' + command);

  controller.hardware.write(command);
};

OpenROVController.prototype.requestCapabilities = function () {
  console.log('Sending rcap to arduino');
  var command = 'rcap();';
  this.hardware.write(command);
};

OpenROVController.prototype.requestSettings = function () {
  var command = 'reportSetting();';
  this.hardware.write(command);
  command = 'rmtrmod();';
  this.hardware.write(command);
};

OpenROVController.prototype.updateSetting = function () {

  var command = 'updateSetting(' + CONFIG.preferences.get('smoothingIncriment') + ',' + CONFIG.preferences.get('deadzone_neg') + ',' + CONFIG.preferences.get('deadzone_pos') + ',' + CONFIG.preferences.get('water_type') + ';';
  this.hardware.write(command);
  //This is the multiplier used to make the motor act linear fashion.
  //for example: the props generate twice the thrust in the positive direction
  //than the negative direction.  To make it linear we have to multiply the
  //negative direction * 2.
  var port = CONFIG.preferences.get('thrust_modifier_port');
  var vertical = CONFIG.preferences.get('thrust_modifier_vertical');
  var starbord = CONFIG.preferences.get('thrust_modifier_starbord');
  var nport = CONFIG.preferences.get('thrust_modifier_nport');
  var nvertical = CONFIG.preferences.get('thrust_modifier_nvertical');
  var nstarbord = CONFIG.preferences.get('thrust_modifier_nstarbord');
  if (CONFIG.preferences.get('reverse_port_thruster')) {
    port = port * -1;
    nport = nport * -1;
  }
  if (CONFIG.preferences.get('reverse_lift_thruster')) {
    vertical = vertical * -1;
    nvertical = nvertical * -1;
  }
  if (CONFIG.preferences.get('reverse_starbord_thruster')) {
    starbord = starbord * -1;
    nstarbord = nstarbord * -1;
  }
  //API to Arduino to pass a percent in 2 decimal accuracy requires multipling by 100 before sending.
  command = 'mtrmod(' + port * 100 + ',' + vertical * 100 + ',' + starbord * 100 + ',' + nport * 100 + ',' + nvertical * 100 + ',' + nstarbord * 100 + ');';
  this.hardware.write(command);
};

OpenROVController.prototype.sendMotorTest = function (port, starbord, vertical) {
  var command = 'go(' + this.physics.mapRawMotor(port) + ',' +
    this.physics.mapRawMotor(vertical) + ',' +
    this.physics.mapRawMotor(starbord) + ',1)';
  //the 1 bypasses motor smoothing
  this.send(command);
};

OpenROVController.prototype.sendCommand = function (throttle, yaw, vertical) {
  var motorCommands = this.physics.mapMotors(throttle, yaw, vertical);
  var command = 'go(' + motorCommands.port + ','
    + motorCommands.vertical + ','
    + motorCommands.starbord + ')';
  this.send(command);
};

OpenROVController.prototype.stop = function (value) {
  var command = 'stop()';
  this.send(command);
};

OpenROVController.prototype.start = function (value) {
  var command = 'start()';
  this.send(command);
};

OpenROVController.prototype.registerPassthrough = function(config) {
  var self = this;
  if (config) {
    if (!config.messagePrefix) {
      throw new Error('You need to specify a messagePrefix that is used to emit and receive message.');
    }
    var messagePrefix = config.messagePrefix;
    if (config.fromROV) {
      if (Array.isArray(config.fromROV)) {
        config.fromROV.forEach(function(item) {
          self.on('status', function (data) {
            if (item in data) {
              self.cockpit.emit(messagePrefix+'.'+item, data[item]);
            }
          });
        });
      }
      else { throw new Error('config.fromROV needs to be an array.'); }
    }
    if (config.toROV) {
      if (Array.isArray(config.toROV)) {
        config.toROV.forEach(function(item) {
          self.cockpit.on(messagePrefix+'.'+item, function(data) {
            var arguments = Array.isArray(data) ? data.join() : data;
            var command = item + '(' + arguments + ')';
            self.send(command);
          });
        });
      }
      else { throw new Error('config.toROV needs to be an array.'); }
    }
  }
};

module.exports = OpenROVController;
<|endoftext|>


<commit_before>// #DROPZONE#
// This script implements the dropzone settings
'use strict';

/* global Dropzone */
(function ($) {
    $(function () {
        var dropzoneTemplateSelector = '.js-dropzone-template';
        var previewImageSelector = '.js-img-preview';
        var dropzoneSelector = '.js-dropzone';
        var messageSelector = '.js-dropzone-message';
        var lookupButtonSelector = '.js-related-lookup';
        var progressSelector = '.js-dropzone-progress';
        var previewImageWrapperSelector = '.js-img-wrapper';
        var filerClearerSelector = '.filerClearer';
        var dropzones = $(dropzoneSelector);
        var fileSelector = $('.js-file-selector');
        var fileIdInputSelector = '.vForeignKeyRawIdAdminField';
        var hiddenClass = 'hidden';

        if (dropzones.length && Dropzone && !window.filerDropzoneInitialized) {
            window.filerDropzoneInitialized = true;
            Dropzone.autoDiscover = false;
            dropzones.each(function () {
                var dropzone = $(this);
                var dropzoneUrl = dropzone.data('url');
                var inputId = dropzone.find(fileIdInputSelector);
                var isImage = inputId.is('[name="image"]');
                var lookupButton = dropzone.find(lookupButtonSelector);
                var message = dropzone.find(messageSelector);
                var clearButton = dropzone.find(filerClearerSelector);

                new Dropzone(this, {
                    url: dropzoneUrl,
                    paramName: 'file',
                    maxFiles: 1,
                    previewTemplate: $(dropzoneTemplateSelector).html(),
                    clickable: false,
                    addRemoveLinks: false,
                    init: function () {
                        this.on('removedfile', function () {
                            fileSelector.show();
                            this.removeAllFiles();
                        });
                    },
                    maxfilesexceeded: function (file) {
                        this.removeAllFiles();
                        this.addFile(file);
                    },
                    drop: function () {
                        clearButton.click();
                        fileSelector.hide();
                        lookupButton.addClass(hiddenClass);
                        message.addClass(hiddenClass);
                        dropzone.removeClass('dz-drag-hover');
                    },
                    success: function (file, response) {
                        $(progressSelector).addClass(hiddenClass);
                        if (file && file.status === 'success' && response) {
                            if (response.file_id) {
                                inputId.val(response.file_id);
                            }
                            if (response.thumbnail_180) {
                                if (isImage) {
                                    $(previewImageSelector).css({
                                        'background-image': 'url(' + response.thumbnail_180 + ')'
                                    });
                                    $(previewImageWrapperSelector).removeClass(hiddenClass);
                                }
                            }
                        }
                    },
                    reset: function () {
                        if (isImage) {
                            $(previewImageWrapperSelector).addClass(hiddenClass);
                            $(previewImageSelector).css({'background-image': 'none'});
                        }
                        inputId.val('');
                        lookupButton.removeClass(hiddenClass);
                        message.removeClass(hiddenClass);
                    }
                });
            });
        }
    });
})(jQuery);
<commit_msg>Drag and drop on Carousel Plugin fix<commit_after>// #DROPZONE#
// This script implements the dropzone settings
'use strict';

/* global Dropzone */
(function ($) {
    $(function () {
        var dropzoneTemplateSelector = '.js-dropzone-template';
        var previewImageSelector = '.js-img-preview';
        var dropzoneSelector = '.js-dropzone';
        var messageSelector = '.js-dropzone-message';
        var lookupButtonSelector = '.js-related-lookup';
        var progressSelector = '.js-dropzone-progress';
        var previewImageWrapperSelector = '.js-img-wrapper';
        var filerClearerSelector = '.filerClearer';
        var fileChooseSelector = '.js-file-selector';
        var dropzones = $(dropzoneSelector);
        var fileIdInputSelector = '.vForeignKeyRawIdAdminField';
        var hiddenClass = 'hidden';

        if (dropzones.length && Dropzone && !window.filerDropzoneInitialized) {
            window.filerDropzoneInitialized = true;
            Dropzone.autoDiscover = false;
            dropzones.each(function () {
                var dropzone = $(this);
                var dropzoneUrl = dropzone.data('url');
                var inputId = dropzone.find(fileIdInputSelector);
                var isImage = inputId.is('[name="image"]');
                var lookupButton = dropzone.find(lookupButtonSelector);
                var message = dropzone.find(messageSelector);
                var clearButton = dropzone.find(filerClearerSelector);
                var fileChoose = dropzone.find(fileChooseSelector);

                new Dropzone(this, {
                    url: dropzoneUrl,
                    paramName: 'file',
                    maxFiles: 1,
                    previewTemplate: $(dropzoneTemplateSelector).html(),
                    clickable: false,
                    addRemoveLinks: false,
                    init: function () {
                        this.on('removedfile', function () {
                            fileChoose.show();
                            this.removeAllFiles();
                        });
                    },
                    maxfilesexceeded: function (file) {
                        this.removeAllFiles();
                        this.addFile(file);
                    },
                    drop: function () {
                        clearButton.click();
                        fileChoose.hide();
                        lookupButton.addClass(hiddenClass);
                        message.addClass(hiddenClass);
                        dropzone.removeClass('dz-drag-hover');
                    },
                    success: function (file, response) {
                        dropzone.find(progressSelector).addClass(hiddenClass);
                        if (file && file.status === 'success' && response) {
                            if (response.file_id) {
                                inputId.val(response.file_id);
                            }
                            if (response.thumbnail_180) {
                                if (isImage) {
                                    $(previewImageSelector).css({
                                        'background-image': 'url(' + response.thumbnail_180 + ')'
                                    });
                                    $(previewImageWrapperSelector).removeClass(hiddenClass);
                                }
                            }
                        }
                    },
                    reset: function () {
                        if (isImage) {
                            $(previewImageWrapperSelector).addClass(hiddenClass);
                            $(previewImageSelector).css({'background-image': 'none'});
                        }
                        inputId.val('');
                        lookupButton.removeClass(hiddenClass);
                        message.removeClass(hiddenClass);
                    }
                });
            });
        }
    });
})(jQuery);
<|endoftext|>


<commit_before>/*global define*/

define(['jquery', 'underscore', 'backbone', 'templates', 'snapsvg', 'helpers/gauge-helper', 'marionette'], function($, _, Backbone, JST, snap, gaugeHelper) {
    'use strict';

    var OsdHistogramView = Backbone.Marionette.ItemView.extend({
        className: 'osd-histogram card gauge',
        template: JST['app/scripts/templates/osd-histogram.ejs'],
        modelEvents: {
            'change': 'modelChanged'
        },
        ui: {
            count: '.osd-histogram-count',
            spinner: '.fa-spinner'
        },
        initialize: function() {
            _.bindAll(this, 'modelChanged', 'animateBar', 'initCanvas', 'set');
            this.App = Backbone.Marionette.getOption(this, 'App');
            if (this.App) {
                this.listenTo(this.App.vent, 'status:update', this.set);
            }
            this.listenToOnce(this, 'render', this.initCanvas);
            this.model = new Backbone.Model({
                'ok': 0,
                'warn': 0,
                'critical': 0
            });
            gaugeHelper(this, 'status');
        },
        svg: {},
        set: function(model) {
            var attr = model.attributes.osd;
            this.model.set({
                ok: attr.ok.count,
                warn: attr.warn.count,
                critical: attr.critical.count,
            });
        },
        animateBar: function(svgEl, svgText, percentage, text, offset) {
            var y = 10 + 100 - percentage;
            var height = percentage;
            svgEl.animate({
                y: y,
                height: height
            }, 250);
            svgText.attr({
                text: text
            });
            var x = offset + (24 / 2 - svgText.node.getBBox().width / 2);
            svgText.attr({
                x: x
            });
        },
        percentage: function(count, total) {
            return Math.round(count / total * 100);
        },
        modelChanged: function(model) {
            var ok = model.get('ok');
            var warn = model.get('warn');
            var critical = model.get('critical');
            var count = 0;
            if (_.isNumber(ok)) {
                count += ok;
            }
            if (_.isNumber(warn)) {
                count += warn;
            }
            if (_.isNumber(critical)) {
                count += critical;
            }
            this.ui.count.text(count);
            if (_.isNumber(ok)) {
                this.animateBar(this.svg.ok, this.svg.okcount, this.percentage(ok, count), ok.toString(), 12);
            }
            if (_.isNumber(warn)) {
                this.animateBar(this.svg.warn, this.svg.warncount, this.percentage(warn, count), warn.toString(), 47);
            }
            if (_.isNumber(critical)) {
                this.animateBar(this.svg.critical, this.svg.criticalcount, this.percentage(critical, count), critical.toString(), 82);
            }
        },
        initCanvas: function() {
            this.p = snap(this.$('.osd-histogram-svg')[0]).attr({
            });
            this.p.node.setAttribute('viewBox', '0 0 130 130');
            this.p.path('M5,5L5,111L110,111').attr({
                'class': 'osd-lines'
            });
            this.svg.ok = this.p.rect(15, 110, 20, 0).attr({
                'class': 'osd-histogram-ok'
            });
            this.svg.warn = this.p.rect(50, 110, 20, 0).attr({
                'class': 'osd-histogram-warn'
            });
            this.svg.critical = this.p.rect(85, 110, 20, 0).attr({
                'class': 'osd-histogram-critical'
            });
            this.svg.okcount = this.p.text(12, 130, '0').attr({
                'class': 'osd-count-text'
            });
            this.svg.warncount = this.p.text(47, 130, '0').attr({
                'class': 'osd-count-text'
            });
            this.svg.criticalcount = this.p.text(82, 130, '0').attr({
                'class': 'osd-count-text'
            });
        }
    });

    return OsdHistogramView;
});
<commit_msg>OSD Widget Refactoring and fine tuning<commit_after>/*global define*/

define(['jquery', 'underscore', 'backbone', 'templates', 'snapsvg', 'helpers/gauge-helper', 'marionette'], function($, _, Backbone, JST, snap, gaugeHelper) {
    'use strict';

    var OsdHistogramView = Backbone.Marionette.ItemView.extend({
        className: 'osd-histogram card gauge',
        template: JST['app/scripts/templates/osd-histogram.ejs'],
        modelEvents: {
            'change': 'modelChanged'
        },
        ui: {
            count: '.osd-histogram-count',
            spinner: '.fa-spinner'
        },
        initialize: function() {
            _.bindAll(this, 'modelChanged', 'animateBar', 'initSVG', 'set');
            this.App = Backbone.Marionette.getOption(this, 'App');
            if (this.App) {
                this.listenTo(this.App.vent, 'status:update', this.set);
            }
            this.listenToOnce(this, 'render', this.initSVG);
            this.model = new Backbone.Model({
                'ok': 0,
                'warn': 0,
                'critical': 0
            });
            gaugeHelper(this, 'status');
        },
        svg: {},
        set: function(model) {
            var attr = model.attributes.osd;
            this.model.set({
                ok: attr.ok.count,
                warn: attr.warn.count,
                critical: attr.critical.count,
            });
        },
        animationMs: 1000,
        easing: mina.bounce,
        animateBar: function(svgBar, svgText, percentage, text, offset) {
            var y = 10 + 100 - percentage;
            var height = percentage;
            svgBar.animate({
                y: y,
                height: height
            }, this.animationMs, this.easing);
            svgText.attr({
                text: text
            });
            var x = offset + (24 / 2 - svgText.node.getBBox().width / 2);
            svgText.attr({
                x: x
            });
        },
        percentage: function(count, total) {
            return Math.round(count / total * 100);
        },
        modelChanged: function(model) {
            var ok = model.get('ok');
            var warn = model.get('warn');
            var critical = model.get('critical');
            var count = 0;
            if (_.isNumber(ok)) {
                count += ok;
            }
            if (_.isNumber(warn)) {
                count += warn;
            }
            if (_.isNumber(critical)) {
                count += critical;
            }
            this.ui.count.text(count);
            var svg = this.svg;
            var legendX = this.legendX;
            if (_.isNumber(ok)) {
                this.animateBar(svg.ok, svg.okcount, this.percentage(ok, count), ok.toString(), legendX[0]);
            }
            if (_.isNumber(warn)) {
                this.animateBar(svg.warn, svg.warncount, this.percentage(warn, count), warn.toString(), legendX[1]);
            }
            if (_.isNumber(critical)) {
                this.animateBar(svg.critical, svg.criticalcount, this.percentage(critical, count), critical.toString(), legendX[2]);
            }
            this.animationMs = 250;
            this.easing = mina.linear;
        },
        legendX: [ 10, 45, 80 ],
        barX: [ 13, 48, 83 ],
        initSVG: function() {
            var svg = this.svg;
            var p;
            this.p = snap(this.$('.osd-histogram-svg')[0]);
            p = this.p;
            var barBaseline = 110;
            var legendBaseline = barBaseline + 20;
            var barWidth = 20;
            var barHeight = 100;
            var barY = barBaseline - barHeight;
            p.node.setAttribute('viewBox', '0 0 130 130');
            p.path('M5,5L5,' + (barBaseline+1) + 'L110,' + (barBaseline+1)).attr({
                'class': 'osd-lines'
            });
            var legendX = this.legendX;
            var barX = this.barX;
            svg.ok = p.rect(barX[0], barY, barWidth, barHeight).attr({
                'class': 'osd-histogram-ok'
            });
            svg.warn = p.rect(barX[1], barY, barWidth, barHeight).attr({
                'class': 'osd-histogram-warn'
            });
            svg.critical = p.rect(barX[2], barY, barWidth, barHeight).attr({
                'class': 'osd-histogram-critical'
            });
            svg.okcount = p.text(legendX[0], legendBaseline, '0').attr({
                'class': 'osd-count-text'
            });
            svg.warncount = p.text(legendX[1], legendBaseline, '0').attr({
                'class': 'osd-count-text'
            });
            svg.criticalcount = p.text(legendX[2], legendBaseline, '0').attr({
                'class': 'osd-count-text'
            });
        }
    });

    return OsdHistogramView;
});
<|endoftext|>


<commit_before>'use strict';

const color = require('../config/color');
let demFeels = function () {};
demFeels.getEmotes = function () {
	return {};
};
try {
	demFeels = require('dem-feels');
} catch (e) {
	console.error(e);
}

exports.parseEmoticons = parseEmoticons;

// for travis build
if (typeof demFeels.extendEmotes === 'function') {
	// example extending emotes
	demFeels.extendEmotes({
	'#freewolf': 'http://i.imgur.com/ybxWXiG.png',
	'bomaye': 'http://i.imgur.com/cuDGGJW.gif',
	'dedchat': 'http://i.imgur.com/W39kJHu.jpg',
	'disarmher': 'http://i.imgur.com/y0gYGSx.gif',
	'feelsbd': 'http://i.imgur.com/YyEdmwX.png',
	'feelsbm': 'http://i.imgur.com/xwfJb2z.png',
	'feelsbn': 'http://i.imgur.com/wp51rIg.png',
	'feelscri':'http://i.imgur.com/JEMjW4f.jpg',
	'feelsdd': 'http://i.imgur.com/fXtdLtV.png',
	'feelsdoge': 'http://i.imgur.com/GklYWvi.png',
	'feelspac': 'http://i.imgur.com/Dc9DBUz.png',
	'feelsgd': 'http://i.imgur.com/Jf0n4BL.png',
	'feelsgn': 'http://i.imgur.com/juJQh0J.png',
	'feelshp': 'http://i.imgur.com/1W19BDG.png',
	'feelsmd': 'http://i.imgur.com/DJHMdSw.png',
	'feelskink': 'http://i.imgur.com/ubnzm6w.gif',
	'feelsnv': 'http://i.imgur.com/XF6kIdJ.png',
	'feelsok': 'http://i.imgur.com/gu3Osve.png',
	'feelspika': 'http://i.imgur.com/mBq3BAW.png',
	'feelspink': 'http://i.imgur.com/jqfB8Di.png',
	'feelspn': 'http://i.imgur.com/wSSM6Zk.png',
	'feelspr': 'http://i.imgur.com/3VtkKfJ.png',
	'feelsrg': 'http://i.imgur.com/DsRQCsI.png',
	'feelsrs': 'http://i.imgur.com/qGEot0R.png',
	'feelssc': 'http://i.imgur.com/cm6oTZ1.png',
	'feelstea': 'http://i.imgur.com/XQc8yZ2.gif',
	'Focus': 'http://i.imgur.com/dUN6xWl.gif',
	'funnylol': 'http://i.imgur.com/SlzCghq.png',
	'hmmface': 'http://i.imgur.com/Z5lOwfZ.png',
	'llamacool': 'http://i.imgur.com/X1x3728.gif',
	'llamafood': 'http://i.imgur.com/SUZkz5p.gif',
	'llamatea': 'http://i.imgur.com/nJnakEU.gif',
	'llamaywn': 'http://i.imgur.com/SVj8kBt.gif',
	'llamawave': 'http://i.imgur.com/KWAQbPu.gif',
	'noface': 'http://i.imgur.com/H744eRE.png',
	'oshet': 'http://i.imgur.com/yr5DjuZ.png',
	'Sanic': 'http://i.imgur.com/Y6etmna.png',
	'welldone': 'http://i.imgur.com/DfKT8GL.gif',
	'Work': 'http://i.imgur.com/C6veCvt.gif',
	'wtfman': 'http://i.imgur.com/kwR8Re9.png',
	'xaa': 'http://i.imgur.com/V728AvL.png',
	'yayface': 'http://i.imgur.com/anY1jf8.png',
	'yesface': 'http://i.imgur.com/k9YCF6K.png',
	'yousee': 'http://i.imgur.com/fjFRa6m.gif',
	});
}

const emotes = demFeels.getEmotes();

const emotesKeys = Object.keys(emotes).sort();

/**
* Parse emoticons in message.
*
* @param {String} message
* @param {Object} room
* @param {Object} user
* @param {Boolean} pm - returns a string if it is in private messages
* @returns {Boolean|String}
*/
function parseEmoticons(message, room, user, pm) {
	if (typeof message !== 'string' || (!pm && room.disableEmoticons)) return false;

	let match = false;
	let len = emotesKeys.length;

	while (len--) {
		if (message && message.indexOf(emotesKeys[len]) >= 0) {
			match = true;
			break;
		}
	}

	if (!match) return false;

	// escape HTML
	message = Tools.escapeHTML(message);

	// add emotes
	message = demFeels(message);

	// __italics__
	message = message.replace(/\_\_([^< ](?:[^<]*?[^< ])?)\_\_(?![^<]*?<\/a)/g, '$1');

	// **bold**
	message = message.replace(/\*\*([^< ](?:[^<]*?[^< ])?)\*\*/g, '$1');

	let group = user.getIdentity().charAt(0);
	if (room.auth) group = room.auth[user.userid] || group;

	let style = "background:none;border:0;padding:0 5px 0 0;font-family:Verdana,Helvetica,Arial,sans-serif;font-size:9pt;cursor:pointer";

	message = "
" + "" + group + "" + "<button name='parseCommand' value='/user " + user.name + "' style='" + style + "'>" + "" + user.name + ":" + "</button>" + message + "
";
	if (pm) return message;

	room.addRaw(message);

	return true;
}

/**
* Create a two column table listing emoticons.
*
* @return {String} emotes table
*/
function create_table() {
	let emotes_name = Object.keys(emotes);
	let emotes_list = [];
	let emotes_group_list = [];
	let len = emotes_name.length;

	for (let i = 0; i < len; i++) {
		emotes_list.push("" + "" + emotes_name[i] + "	");
	}

	for (let i = 0; i < len; i += 4) {
		let emoteOutput = [emotes_list[i], emotes_list[i + 1], emotes_list[i + 2], emotes_list[i + 3]];
		if (i < len) emotes_group_list.push("
" + emoteOutput.join('') + "
");
	}

	return (
		"
List of Emoticons" +
		"

" +
		emotes_group_list.join("") +
		"

"
	);
}

let emotes_table = create_table();

exports.commands = {
	blockemote: 'blockemoticons',
	blockemotes: 'blockemoticons',
	blockemoticon: 'blockemoticons',
	blockemoticons: function (target, room, user) {
		if (user.blockEmoticons === (target || true)) return this.sendReply("You are already blocking emoticons in private messages! To unblock, use /unblockemoticons");
		user.blockEmoticons = true;
		return this.sendReply("You are now blocking emoticons in private messages.");
	},
	blockemoticonshelp: ["/blockemoticons - Blocks emoticons in private messages. Unblock them with /unblockemoticons."],

	unblockemote: 'unblockemoticons',
	unblockemotes: 'unblockemoticons',
	unblockemoticon: 'unblockemoticons',
	unblockemoticons: function (target, room, user) {
		if (!user.blockEmoticons) return this.sendReply("You are not blocking emoticons in private messages! To block, use /blockemoticons");
		user.blockEmoticons = false;
		return this.sendReply("You are no longer blocking emoticons in private messages.");
	},
	unblockemoticonshelp: ["/unblockemoticons - Unblocks emoticons in private messages. Block them with /blockemoticons."],

	emotes: 'emoticons',
	emoticons: function (target, room, user) {
		if (!this.runBroadcast()) return;
		this.sendReply("|raw|" + emotes_table);
	},
	emoticonshelp: ["/emoticons - Get a list of emoticons."],

	toggleemote: 'toggleemoticons',
	toggleemotes: 'toggleemoticons',
	toggleemoticons: function (target, room, user) {
		if (!this.can('declare', null, room)) return false;
		room.disableEmoticons = !room.disableEmoticons;
		this.sendReply("Disallowing emoticons is set to " + room.disableEmoticons + " in this room.");
		if (room.disableEmoticons) {
			this.add("|raw|
Emoticons are disabled!
Emoticons will not work.
");
		} else {
			this.add("|raw|
Emoticons are enabled!
Emoticons will work now.
");
		}
	},
	toggleemoticonshelp: ["/toggleemoticons - Toggle emoticons on or off."],

	rande: 'randemote',
	randemote: function (target, room, user) {
		if (!this.runBroadcast()) return;
		let rng = Math.floor(Math.random() * emotesKeys.length);
		let randomEmote = emotesKeys[rng];
		this.sendReplyBox("");
	},
	randemotehelp: ["/randemote - Get a random emote."],
};
<commit_msg>resize emotes<commit_after>'use strict';

const color = require('../config/color');
let demFeels = function () {};
demFeels.getEmotes = function () {
	return {};
};
try {
	demFeels = require('dem-feels');
} catch (e) {
	console.error(e);
}

exports.parseEmoticons = parseEmoticons;

// for travis build
if (typeof demFeels.extendEmotes === 'function') {
	// example extending emotes
	demFeels.extendEmotes({
	'#freewolf': 'http://i.imgur.com/ybxWXiG.png',
	'bomaye': 'http://i.imgur.com/cuDGGJW.gif',
	'dedchat': 'http://i.imgur.com/W39kJHu.jpg',
	'disarmher': 'http://i.imgur.com/y0gYGSx.gif',
	'feelsbd': 'http://i.imgur.com/YyEdmwX.png',
	'feelsbm': 'http://i.imgur.com/xwfJb2z.png',
	'feelsbn': 'http://i.imgur.com/wp51rIg.png',
	'feelscri':'http://i.imgur.com/JEMjW4f.jpg',
	'feelsdd': 'http://i.imgur.com/fXtdLtV.png',
	'feelsdoge': 'http://i.imgur.com/GklYWvi.png',
	'feelspac': 'http://i.imgur.com/Dc9DBUz.png',
	'feelsgd': 'http://i.imgur.com/Jf0n4BL.png',
	'feelsgn': 'http://i.imgur.com/juJQh0J.png',
	'feelshp': 'http://i.imgur.com/1W19BDG.png',
	'feelsmd': 'http://i.imgur.com/DJHMdSw.png',
	'feelskink': 'http://i.imgur.com/ubnzm6w.gif',
	'feelsnv': 'http://i.imgur.com/XF6kIdJ.png',
	'feelsok': 'http://i.imgur.com/gu3Osve.png',
	'feelspika': 'http://i.imgur.com/mBq3BAW.png',
	'feelspink': 'http://i.imgur.com/jqfB8Di.png',
	'feelspn': 'http://i.imgur.com/wSSM6Zk.png',
	'feelspr': 'http://i.imgur.com/3VtkKfJ.png',
	'feelsrg': 'http://i.imgur.com/DsRQCsI.png',
	'feelsrs': 'http://i.imgur.com/qGEot0R.png',
	'feelssc': 'http://i.imgur.com/cm6oTZ1.png',
	'feelstea': 'http://i.imgur.com/XQc8yZ2.gif',
	'Focus': 'http://i.imgur.com/dUN6xWl.gif',
	'funnylol': 'http://i.imgur.com/SlzCghq.png',
	'hmmface': 'http://i.imgur.com/Z5lOwfZ.png',
	'llamacool': 'http://i.imgur.com/X1x3728.gif',
	'llamafood': 'http://i.imgur.com/SUZkz5p.gif',
	'llamatea': 'http://i.imgur.com/nJnakEU.gif',
	'llamaywn': 'http://i.imgur.com/SVj8kBt.gif',
	'llamawave': 'http://i.imgur.com/KWAQbPu.gif',
	'noface': 'http://i.imgur.com/H744eRE.png',
	'oshet': 'http://i.imgur.com/yr5DjuZ.png',
	'Sanic': 'http://i.imgur.com/Y6etmna.png',
	'welldone': 'http://i.imgur.com/DfKT8GL.gif',
	'Work': 'http://i.imgur.com/C6veCvt.gif',
	'wtfman': 'http://i.imgur.com/kwR8Re9.png',
	'xaa': 'http://i.imgur.com/V728AvL.png',
	'yayface': 'http://i.imgur.com/anY1jf8.png',
	'yesface': 'http://i.imgur.com/k9YCF6K.png',
	'yousee': 'http://i.imgur.com/fjFRa6m.gif',
	});
}

const emotes = demFeels.getEmotes();

const emotesKeys = Object.keys(emotes).sort();

/**
* Parse emoticons in message.
*
* @param {String} message
* @param {Object} room
* @param {Object} user
* @param {Boolean} pm - returns a string if it is in private messages
* @returns {Boolean|String}
*/
function parseEmoticons(message, room, user, pm) {
	if (typeof message !== 'string' || (!pm && room.disableEmoticons)) return false;

	let match = false;
	let len = emotesKeys.length;

	while (len--) {
		if (message && message.indexOf(emotesKeys[len]) >= 0) {
			match = true;
			break;
		}
	}

	if (!match) return false;

	// escape HTML
	message = Tools.escapeHTML(message);

	// add emotes
	message = demFeels(message);

	// __italics__
	message = message.replace(/\_\_([^< ](?:[^<]*?[^< ])?)\_\_(?![^<]*?<\/a)/g, '$1');

	// **bold**
	message = message.replace(/\*\*([^< ](?:[^<]*?[^< ])?)\*\*/g, '$1');

	let group = user.getIdentity().charAt(0);
	if (room.auth) group = room.auth[user.userid] || group;

	let style = "background:none;border:0;padding:0 5px 0 0;font-family:Verdana,Helvetica,Arial,sans-serif;font-size:9pt;cursor:pointer";

	message = "
" + "" + group + "" + "<button name='parseCommand' value='/user " + user.name + "' style='" + style + "'>" + "" + user.name + ":" + "</button>" + message + "
";
	if (pm) return message;

	room.addRaw(message);

	return true;
}

/**
* Create a two column table listing emoticons.
*
* @return {String} emotes table
*/
function create_table() {
	let emotes_name = Object.keys(emotes);
	let emotes_list = [];
	let emotes_group_list = [];
	let len = emotes_name.length;

	for (let i = 0; i < len; i++) {
		emotes_list.push("" + "" + emotes_name[i] + "	");
	}

	for (let i = 0; i < len; i += 4) {
		let emoteOutput = [emotes_list[i], emotes_list[i + 1], emotes_list[i + 2], emotes_list[i + 3]];
		if (i < len) emotes_group_list.push("
" + emoteOutput.join('') + "
");
	}

	return (
		"
List of Emoticons" +
		"

" +
		emotes_group_list.join("") +
		"

"
	);
}

let emotes_table = create_table();

exports.commands = {
	blockemote: 'blockemoticons',
	blockemotes: 'blockemoticons',
	blockemoticon: 'blockemoticons',
	blockemoticons: function (target, room, user) {
		if (user.blockEmoticons === (target || true)) return this.sendReply("You are already blocking emoticons in private messages! To unblock, use /unblockemoticons");
		user.blockEmoticons = true;
		return this.sendReply("You are now blocking emoticons in private messages.");
	},
	blockemoticonshelp: ["/blockemoticons - Blocks emoticons in private messages. Unblock them with /unblockemoticons."],

	unblockemote: 'unblockemoticons',
	unblockemotes: 'unblockemoticons',
	unblockemoticon: 'unblockemoticons',
	unblockemoticons: function (target, room, user) {
		if (!user.blockEmoticons) return this.sendReply("You are not blocking emoticons in private messages! To block, use /blockemoticons");
		user.blockEmoticons = false;
		return this.sendReply("You are no longer blocking emoticons in private messages.");
	},
	unblockemoticonshelp: ["/unblockemoticons - Unblocks emoticons in private messages. Block them with /blockemoticons."],

	emotes: 'emoticons',
	emoticons: function (target, room, user) {
		if (!this.runBroadcast()) return;
		this.sendReply("|raw|" + emotes_table);
	},
	emoticonshelp: ["/emoticons - Get a list of emoticons."],

	toggleemote: 'toggleemoticons',
	toggleemotes: 'toggleemoticons',
	toggleemoticons: function (target, room, user) {
		if (!this.can('declare', null, room)) return false;
		room.disableEmoticons = !room.disableEmoticons;
		this.sendReply("Disallowing emoticons is set to " + room.disableEmoticons + " in this room.");
		if (room.disableEmoticons) {
			this.add("|raw|
Emoticons are disabled!
Emoticons will not work.
");
		} else {
			this.add("|raw|
Emoticons are enabled!
Emoticons will work now.
");
		}
	},
	toggleemoticonshelp: ["/toggleemoticons - Toggle emoticons on or off."],

	rande: 'randemote',
	randemote: function (target, room, user) {
		if (!this.runBroadcast()) return;
		let rng = Math.floor(Math.random() * emotesKeys.length);
		let randomEmote = emotesKeys[rng];
		this.sendReplyBox("");
	},
	randemotehelp: ["/randemote - Get a random emote."],
};
<|endoftext|>


<commit_before>/* Emoticons Plugin
 * This is a chat-plugin for Emoticons
 * You will need a line in parser to actually
 * parse this so that it works. (See command-parser.js)
 * Credits: panpawn, jd
 */

var fs = require('fs');
var path = require('path');
var serialize = require('node-serialize');

if (typeof Gold === 'undefined') global.Gold = {};

Gold.emoticons = {
	chatEmotes: {}, //much object such wow :^)
	processEmoticons: function(text) {
		var patterns = [],
			metachars = /[[\]{}()*+?.\\|^$\-,&#\s]/g,
			self = this;
		for (var i in this.chatEmotes) {
			if (this.chatEmotes.hasOwnProperty(i)) {
				patterns.push('(' + i.replace(metachars, "\\$&") + ')');
			}
		}
		return text.replace(new RegExp(patterns.join('|'), 'g'), function(match) {
			return typeof self.chatEmotes[match] != 'undefined' ?
				'' :
				match;
		});
	},
	processChatData: function(user, room, connection, message) {
		var match = false;
		for (var i in this.chatEmotes) {
			if (message.indexOf(i) >= 0) {
				match = true;
			}
		}
		if (!room.emoteStatus) {
			kitty = message = this.processEmoticons(message);
			var message = Tools.escapeHTML(kitty);
			return (message);
			return;
		} else if (room.emoteStatus) {
			if (!match || message.charAt(0) === '!') return true;
			message = Tools.escapeHTML(message);
			message = this.processEmoticons(message);
			if (user.hiding) {
				room.addRaw(' <button class="astext" name="parseCommand" value="/user ' +
				user.name + '">' + '' + Tools.escapeHTML(user.name) + ':</button> ' + message + '
');
				room.update();
			}
			room.addRaw(user.getIdentity(room).substr(0,1) + '<button class="astext" name="parseCommand" value="/user ' +
				user.name + '">' + '' + Tools.escapeHTML(user.name) + ':</button> ' + message + '
');
			room.update();
			return false;
		}
	}
};

/* EZ-Emote Commands plugin
 * These are commands that make it easier for people to actually
 * add / remove emotes without having to manaully do so every time
 * By: panpawn (inspired by jd's ez-tc plugin)
 */

var emotes = {};

function loadEmotes() {
	try {
		emotes = serialize.unserialize(fs.readFileSync('config/emotes.json', 'utf8'));
		Object.merge(Gold.emoticons.chatEmotes, emotes);
	} catch (e) {}
}
setTimeout(function(){loadEmotes();},1000);

function saveEmotes() {
	try {
		fs.writeFileSync('config/emotes.json',serialize.serialize(emotes));
		Object.merge(Gold.emoticons.chatEmotes, emotes);
	} catch (e) {}
}

exports.commands = {
	emotes: 'ezemote',
	temotes: 'ezemote',
	temote: 'ezemote',
	emote: 'ezemote',
	ec: 'ezemote',
	ezemote: function (target, room, user) {
		if (!target) target = "help";
		var parts = target.split(',');
		for (var u in parts) parts[u] = parts[u].trim();

		try {
			switch (toId(parts[0])) {
				case 'add':
					if (!this.can('ban')) return this.sendReply("Access denied.");
					if (!(parts[2] || parts[3])) return this.sendReply("Usage: /ezemote add, [emote], [link]");
					var emoteName = parts[1];
					if (Gold.emoticons.chatEmotes[emoteName]) return this.sendReply("ERROR - the emote: " + emoteName + " already exists.");
					var link = parts.splice(2, parts.length).join(',');
					var fileTypes = [".gif",".png",".jpg"];
					if (fileTypes.indexOf(link.substr(-4)) < 0) return this.sendReply("ERROR: the emote you are trying to add must be a gif, png, or jpg.");
					emotes[emoteName] = Gold.emoticons.chatEmotes[emoteName] = link;
					saveEmotes();
					this.sendReply("The emote " + emoteName + " has been added.");
					this.logModCommand(user.name + " added the emote " + emoteName);
					Rooms.rooms.staff.add(Tools.escapeHTML(user.name) + " added the emote " + emoteName);
					room.update();
					break;
				case 'rem':
				case 'remove':
				case 'del':
				case 'delete':
					if (!this.can('ban')) return this.sendReply("Access denied.");
					if (!parts[1]) return this.sendReplyBox("/ezemote remove, [emote]");
					var emoteName = parts[1];
					if (!Gold.emoticons.chatEmotes[emoteName]) return this.sendReply("ERROR - the emote: " + emoteName + " does not exist.");
					delete Gold.emoticons.chatEmotes[emoteName];
					delete emotes[emoteName];
					saveEmotes();
					this.sendReply("The emote " + emoteName + " was removed.");
					this.logModCommand("The emote " + emoteName + " was removed by " + user.name);
					Rooms.rooms.staff.add("The emote " + emoteName + " was removed by " + Tools.escapeHTML(user.name));
					room.update();
					break;
				case 'list':
					if (!this.canBroadcast()) return;
					if (this.broadcasting) return this.sendReply("ERROR: this command is too spammy to broadcast.  Use / instead of ! to see it for yourself.");
					var output = "There's a total of " + Object.size(emotes) + " emotes added with this command:
";
					for (var e in emotes) {
						output += e + "
";
					}
					this.sendReplyBox(output);
					break;
				case 'view':
					if (!this.canBroadcast()) return;
					//if (this.broadcasting) return this.sendReply("ERROR: this command is too spammy to broadcast.  Use / instead of ! to see it for yourself.");
					var name = Object.keys(Gold.emoticons.chatEmotes);
					emoticons = [];
					var len = name.length;
					while (len--) {
						emoticons.push((Gold.emoticons.processEmoticons(name[(name.length - 1) - len]) + ' ' + name[(name.length - 1) - len]));
					}
					this.sendReplyBox("List of emoticons (" + Object.size(emotes) + "):

" + emoticons.join(' ').toString());
					break;
				case 'object':
					if (!this.canBroadcast()) return;
					if (this.broadcasting) return this.sendReply("ERROR: this command is too spammy to broadcast.  Use / instead of ! to see it for yourself.");
					this.sendReplyBox("Gold.emoticons.chatEmotes = " + fs.readFileSync('config/emotes.json','utf8'));
					break;
				case 'status':
					if (!this.canBroadcast()) return;
					if (!parts[1]) {
						switch (room.emoteStatus) {
							case true:
								this.sendReply("Chat emotes are currently enabled in this room.");
								break;
							case false:
								this.sendReply("Chat emotes are currently disabled in this room.");
								break;
						}
					} else {
						switch (toId(parts[1])) {
							case 'on':
							case 'enable':
								if (!this.can('declare', null, room)) return this.sendReply("Access denied.");
								if (room.emoteStatus) return this.sendReply("Um, emotes are already enabled in this room.");
								room.emoteStatus = true;
								room.chatRoomData.emoteStatus = room.emoteStatus;
								Rooms.global.writeChatRoomData();
								room.add(Tools.escapeHTML(user.name) + ' has enabled chat emotes in this room.');
								this.logModCommand(Tools.escapeHTML(user.name) + ' has enabled chat emotes in this room.');
								break;
							case 'off':
							case 'disable':
								if (!this.can('declare', null, room)) return this.sendReply("Access denied.");
								if (!room.emoteStatus) return this.sendReply("Um, emotes are already disabled in this room.");
								room.emoteStatus = false;
								room.chatRoomData.emoteStatus = room.emoteStatus;
								Rooms.global.writeChatRoomData();
								room.add(Tools.escapeHTML(user.name) + " has disabled chat emotes in this room.");
								this.logModCommand(Tools.escapeHTML(user.name) + " has disabled chat emotes in this room.");
								break;
							default:
								this.sendReply("Usage: /ezemote status, [on / off] - Enables or disables the current emote status.  Requires #, &, ~.");
						}
					}
					break;
				case 'help':
				default:
					if (!this.canBroadcast()) return;
					this.sendReplyBox(
						"
" +
							"EZ-Emote Commands:
" +
							"(By: panpawn)
" +
							"/ezemote add, [emote], [link] - Adds an emote. Requires @, &, ~.
" +
							"/ezemote remove, [emote] - Removes an emote. Requires @, &, ~.
" +
							"/ezemote status, [on / off] - Enables or disables the status of emotes. Requires #, &, ~.
" +
							"/ezemote status - Views the current status of emotes.
" +
							"/ezemote list - Shows the emotes that were added with this command in a list form.
" +
							"/ezemote view - Shows all of the current emotes with their respected image.
" +
							"/ezemote object - Shows the object of Gold.emoticons.chatEmotes. (Mostly for development usage)
" +
							"/ezemote help - Shows this help command.
" +
						"
"
					);
			}
		} catch (e) {
			try {
				Rooms.rooms.development.add(e.stack);
			} catch (e) {
				console.log("ERROR!  The EZ-Emote script has crashed!\n" + e.stack);
			}
		}
	}
};
<commit_msg>General emotes update<commit_after>/* Emoticons Plugin
 * This is a chat-plugin for Emoticons
 * You will need a line in parser to actually
 * parse this so that it works. (See command-parser.js)
 * Credits: panpawn, jd
 */

var fs = require('fs');
var path = require('path');
var serialize = require('node-serialize');

if (typeof Gold === 'undefined') global.Gold = {};

Gold.emoticons = {
	chatEmotes: {},
	processEmoticons: function(text) {
		var patterns = [],
		metachars = /[[\]{}()*+?.\\|^$\-,&#\s]/g,
		self = this;
		for (var i in this.chatEmotes) {
			if (this.chatEmotes.hasOwnProperty(i)) {
				patterns.push('(' + i.replace(metachars, "\\$&") + ')');
			}
		}
		return text.replace(new RegExp(patterns.join('|'), 'g'), function(match) {
			return typeof self.chatEmotes[match] != 'undefined' ?
				'' :
				match;
		});
	},
	processChatData: function(user, room, connection, message) {
		var match = false;
		for (var i in this.chatEmotes) {
			if (message.indexOf(i) >= 0) {
				match = true;
			}
		}
		if (!room.emoteStatus) {
			kitty = message = this.processEmoticons(message);
			var message = Tools.escapeHTML(kitty);
			return (message);
			return;
		} else if (room.emoteStatus) {
			if (!match || message.charAt(0) === '!') return true;
			message = Tools.escapeHTML(message);
			message = this.processEmoticons(message);
			if (user.hiding) {
				room.addRaw(' <button class="astext" name="parseCommand" value="/user ' +
				user.name + '">' + '' + Tools.escapeHTML(user.name) + ':</button> ' + message + '
');
				room.update();
			}
			room.addRaw(user.getIdentity(room).substr(0,1) + '<button class="astext" name="parseCommand" value="/user ' +
				user.name + '">' + '' + Tools.escapeHTML(user.name) + ':</button> ' + message + '
');
			room.update();
			return false;
		}
	}
};

//commands

var emotes = {};

function loadEmotes() {
	try {
		emotes = serialize.unserialize(fs.readFileSync('config/emotes.json', 'utf8'));
		Object.merge(Gold.emoticons.chatEmotes, emotes);
	} catch (e) {}
}
setTimeout(function(){loadEmotes();},1000);

function saveEmotes() {
	try {
		fs.writeFileSync('config/emotes.json',serialize.serialize(emotes));
		Object.merge(Gold.emoticons.chatEmotes, emotes);
	} catch (e) {}
}

exports.commands = {
	emotes: 'ezemote',
	temotes: 'ezemote',
	temote: 'ezemote',
	emote: 'ezemote',
	ec: 'ezemote',
	ezemote: function (target, room, user) {
		if (!target) target = "help";
		var parts = target.split(',');
		for (var u in parts) parts[u] = parts[u].trim();

		try {
			switch (toId(parts[0])) {
				case 'add':
					if (!this.can('ban')) return this.sendReply("Access denied.");
					if (!(parts[2] || parts[3])) return this.sendReply("Usage: /ezemote add, [emote], [link]");
					var emoteName = parts[1];
					if (Gold.emoticons.chatEmotes[emoteName]) return this.sendReply("ERROR - the emote: " + emoteName + " already exists.");
					var link = parts.splice(2, parts.length).join(',');
					var fileTypes = [".gif",".png",".jpg"];
					if (fileTypes.indexOf(link.substr(-4)) < 0) return this.sendReply("ERROR: the emote you are trying to add must be a gif, png, or jpg.");
					emotes[emoteName] = Gold.emoticons.chatEmotes[emoteName] = link;
					saveEmotes();
					this.sendReply("The emote " + emoteName + " has been added.");
					this.logModCommand(user.name + " added the emote " + emoteName);
					Rooms.rooms.staff.add(Tools.escapeHTML(user.name) + " added the emote " + emoteName);
					room.update();
					break;
				case 'rem':
				case 'remove':
				case 'del':
				case 'delete':
					if (!this.can('ban')) return this.sendReply("Access denied.");
					if (!parts[1]) return this.sendReplyBox("/ezemote remove, [emote]");
					var emoteName = parts[1];
					if (!Gold.emoticons.chatEmotes[emoteName]) return this.sendReply("ERROR - the emote: " + emoteName + " does not exist.");
					delete Gold.emoticons.chatEmotes[emoteName];
					delete emotes[emoteName];
					saveEmotes();
					this.sendReply("The emote " + emoteName + " was removed.");
					this.logModCommand("The emote " + emoteName + " was removed by " + user.name);
					Rooms.rooms.staff.add("The emote " + emoteName + " was removed by " + Tools.escapeHTML(user.name));
					room.update();
					break;
				case 'list':
					if (!this.canBroadcast()) return;
					if (this.broadcasting) return this.sendReply("ERROR: this command is too spammy to broadcast.  Use / instead of ! to see it for yourself.");
					var output = "There's a total of " + Object.size(emotes) + " emotes added with this command:
";
					for (var e in emotes) {
						output += e + "
";
					}
					this.sendReplyBox(output);
					break;
				case 'view':
					if (!this.canBroadcast()) return;
					//if (this.broadcasting) return this.sendReply("ERROR: this command is too spammy to broadcast.  Use / instead of ! to see it for yourself.");
					var name = Object.keys(Gold.emoticons.chatEmotes);
					emoticons = [];
					var len = name.length;
					while (len--) {
						emoticons.push((Gold.emoticons.processEmoticons(name[(name.length - 1) - len]) + ' ' + name[(name.length - 1) - len]));
					}
					this.sendReplyBox("List of emoticons (" + Object.size(emotes) + "):

" + emoticons.join(' ').toString());
					break;
				case 'object':
					if (!this.canBroadcast()) return;
					if (this.broadcasting) return this.sendReply("ERROR: this command is too spammy to broadcast.  Use / instead of ! to see it for yourself.");
					this.sendReplyBox("Gold.emoticons.chatEmotes = " + fs.readFileSync('config/emotes.json','utf8'));
					break;
				case 'status':
					if (!this.canBroadcast()) return;
					if (!parts[1]) {
						switch (room.emoteStatus) {
							case true:
								this.sendReply("Chat emotes are currently enabled in this room.");
								break;
							case false:
								this.sendReply("Chat emotes are currently disabled in this room.");
								break;
						}
					} else {
						switch (toId(parts[1])) {
							case 'on':
							case 'enable':
								if (!this.can('declare', null, room)) return this.sendReply("Access denied.");
								if (room.emoteStatus) return this.sendReply("Um, emotes are already enabled in this room.");
								room.emoteStatus = true;
								room.chatRoomData.emoteStatus = room.emoteStatus;
								Rooms.global.writeChatRoomData();
								room.add(Tools.escapeHTML(user.name) + ' has enabled chat emotes in this room.');
								this.logModCommand(Tools.escapeHTML(user.name) + ' has enabled chat emotes in this room.');
								break;
							case 'off':
							case 'disable':
								if (!this.can('declare', null, room)) return this.sendReply("Access denied.");
								if (!room.emoteStatus) return this.sendReply("Um, emotes are already disabled in this room.");
								room.emoteStatus = false;
								room.chatRoomData.emoteStatus = room.emoteStatus;
								Rooms.global.writeChatRoomData();
								room.add(Tools.escapeHTML(user.name) + " has disabled chat emotes in this room.");
								this.logModCommand(Tools.escapeHTML(user.name) + " has disabled chat emotes in this room.");
								break;
							default:
								this.sendReply("Usage: /ezemote status, [on / off] - Enables or disables the current emote status.  Requires #, &, ~.");
						}
					}
					break;
				case 'help':
				default:
					if (!this.canBroadcast()) return;
					this.sendReplyBox(
						"
" +
							"EZ-Emote Commands:
" +
							"(By: panpawn)
" +
							"/ezemote add, [emote], [link] - Adds an emote. Requires @, &, ~.
" +
							"/ezemote remove, [emote] - Removes an emote. Requires @, &, ~.
" +
							"/ezemote status, [on / off] - Enables or disables the status of emotes. Requires #, &, ~.
" +
							"/ezemote status - Views the current status of emotes.
" +
							"/ezemote list - Shows the emotes that were added with this command in a list form.
" +
							"/ezemote view - Shows all of the current emotes with their respected image.
" +
							"/ezemote object - Shows the object of Gold.emoticons.chatEmotes. (Mostly for development usage)
" +
							"/ezemote help - Shows this help command.
" +
						"
"
					);
			}
		} catch (e) {
			try {
				Rooms.rooms.development.add(e.stack);
			} catch (e) {
				console.log("ERROR!  The EZ-Emote script has crashed!\n" + e.stack);
			}
		}
	}
};
<|endoftext|>


<commit_before>/*************************************************
 * User Data Functions - by panpawn              *
 *                                               *
 *  This system includes features that store:    *
 *   - last seen data                            *
 *   - economy (bucks)                           *
 *   - tells (offline messaging)                 *
 *   - and more!                                 *
 *************************************************/
'use strict';

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

Gold.userData = Object.create(null);

function loadUserData() {
	fs.readFile('config/goldusers.json', 'utf8', function (err, file) {
		if (err) return;
		Gold.userData = JSON.parse(file);
	});
};
loadUserData();

try {
	Object.assign(Gold, {

		/******************************
		 * Initialize User Functions  *
		 ******************************/
		createUser: function (user) { // doesn't save unless it gets edited
			user = toId(user);
			if (Gold.userData[user] || user === 'constructor') return false;
			if (user.substr(0, 5) === 'guest') return false;

			Gold.userData[user] = { // esteemed user data
				ips: [],
				tells: Object.create(null),
				friends: [],
				badges: [],
				tellNum: 0,
				money: 0,
				lastSeen: 0,
				color: false,
				icon: false,
				vip: false,
				status: '',
				friendcode: '',
			} // we don't save blank user data objects until next save
		},
		saveData: function () {
				fs.writeFileSync('config/goldusers.json', JSON.stringify(Gold.userData));
		}.throttle(1 * 1000), // only save once/second - TOPS
		initiateUser: function (user, ip) {	// when the user connections, this runs
			user = toId(user);
			if (!Gold.userData[user]) Gold.createUser(user);

			this.addIp(user, ip);
			this.updateSeen(user); // (saves)
		},
		checkExisting: function (user) {
			user = toId(user);
			if (!Gold.userData[user]) Gold.createUser(user);
			return Gold.userData[user];
		},

		/*********************
		 * Economy Functions *
		 *********************/
		updateMoney: function (user, amount) {
			user = toId(user);
			if (isNaN(amount)) return false;

			let data = this.checkExisting(user);
			data.money = data.money + amount;
			this.saveData();
		},
		readMoney: function (user) {
			user = toId(user);
			let data = this.checkExisting(user);
			return data.money;
		},
		moneyCirculating: function () {
			let data = Object.keys(Gold.userData);
			// [total bucks, average bucks, number of users with at least 1 money]
			let results = [0, 0, 0];

			data.forEach(user => {
				if (Gold.userData[user].money > 0) {
					if (isNaN(Gold.userData[user].money)) return;
					results[0] += Math.round(Number(Gold.userData[user].money));
					results[2]++;
				}
			});
			results[1] = Math.round(results[0] / results[2]);

			return results;
		},
		richestUsers: function (number) { // basically the heavy lifting for the command
			number = number > Gold.moneyCirculating()[2] ? Gold.moneyCirculating()[2] : number;
			let data = Object.keys(Gold.userData);
			let userids = new Array(0);
			let tableStyle = 'background: linear-gradient(10deg, #FFF8B5, #eadf7c, #FFF8B5); color: black; border: 1px solid #635b00; padding: 2px; border-radius: 5px; text-align:center;';
			let tdStyle = 'border-radius: 5px; border: 1px solid #635b00; background: #fff8b5; color: black;';
			let returnText = `${number > 10 ? '<div class="infobox-limited">' : '<div>'}<b>The top ${number} richest users are:</b><table style="${tableStyle}" border="1" cellspacing ="0" cellpadding="3">`;
			returnText += `<tr><td style="${tdStyle}"><b>Rank</b></td><td style="${tdStyle}"><b>Name</b></td><td style="${tdStyle}"><b>Bucks</b></td></tr>`;

			function ResultsArray (id, money) {
				this.id = id;
				this.money = money;
			}

			data.forEach(user => {
				if (Gold.userData[user].money > 0) {
					userids.push(new ResultsArray(user, Gold.userData[user].money));
				}
			});

			userids.sort(function (a, b) {
				return b.money - a.money;
			});

			for (let i = 0; i < number; i++) {
				if (userids[i]) returnText += `<tr><td style="${tdStyle}">${i + 1}.</td><td style="${tdStyle}">${Gold.nameColor(userids[i].id, true)}</td><td style="${tdStyle}">${userids[i].money}</td></tr>`;
			}
			returnText += '

';

			return returnText;
		},

		/*******************
		 * Misc. Functions *
		 *******************/
		hasVip: function (user) {
			user = toId(user);
			let data = this.checkExisting(user);
			if (!data.badges) data.badges = [];
			let vip = data.badges.includes('vip');
			return vip;
		},
		modifyBadge: function (user, badgeid, action) {
			user = toId(user);
			badgeid = toId(badgeid);

			let data = this.checkExisting(user);
			if (!data.badges) data.badges = [];

			if (action === 'GIVE') {
				if (data.badges.includes(badgeid)) return false;
				data.badges.push(badgeid);
			} else if (action === 'TAKE') {
				if (!data.badges.includes(badgeid)) return false;
				data.badges.remove(badgeid);
			} else {
				return false;
			}
			this.saveData();
		},
		badgeList: function (displayall) {
			// This houses the badges of the server.  You can add/modify/remove badges
			// here the with the same format as you see.
			let badgeList = {
				'dev': {
					title: 'Developer',
					img: 'http://www.smogon.com/media/forums/images/badges/factory_foreman.png',
				}, 'admin': {
					title: 'Server Administrator',
					img: 'http://www.smogon.com/media/forums/images/badges/sop.png',
				}, 'fgs': {
					title: 'Former Gold Staff',
					img: 'http://www.smogon.com/media/forums/images/badges/forummod_alum.png',
				}, 'leader': {
					title: 'Server Leader',
					img: 'http://www.smogon.com/media/forums/images/badges/aop.png',
				}, 'mod': {
					title: 'Exceptional Staff Member',
					img: 'http://www.smogon.com/media/forums/images/badges/pyramid_king.png',
				}, 'rf': {
					title: 'Successful Room Founder',
					img: 'http://www.smogon.com/media/forums/images/badges/forumsmod.png',
				}, 'comcun': {
					title: 'Community Contributor',
					img: 'http://www.smogon.com/media/forums/images/badges/cc.png',
				}, 'art': {
					title: 'Artist',
					img: 'http://www.smogon.com/media/forums/images/badges/ladybug.png',
				}, 'vip': {
					title: 'VIP User',
					img: 'http://www.smogon.com/media/forums/images/badges/zeph.png',
				}, 'twinner': {
					title: 'Event Tournament Winner',
					img: 'http://www.smogon.com/media/forums/images/badges/spl.png',
				}, 'creator': {
					title: 'Server Creator',
					img: 'http://www.smogon.com/media/forums/images/badges/dragon.png',
				}
			};
			if (displayall) {
				let buff = [];
				Object.keys(badgeList).forEach(badge => {
					buff.push(`<img src="${badgeList[badge].img}" title="${badgeList[badge].title}">`);
				});
				return buff.join(" | ");
			}
			return badgeList;
		},
		displayBadges: function (user) {
			user = toId(user);
			let data = this.checkExisting(user), buff = [];
			if (!data.badges || data.badges.length < 0) return false;

			let badgeObj = this.badgeList();
			let badgeList = Object.keys(badgeObj);
			badgeList.forEach(badge => {
				if (data.badges.includes(badge)) buff.push(`<img src="${badgeObj[badge].img}" title="${badgeObj[badge].title}">`);
			});
			return buff.join(" ");
		},
		customColor: function (user, action, color) {
			user = toId(user);
			let data = this.checkExisting(user);
			if (!data.color) data.color = '';

			if (action === 'GIVE') {
				data.color = color;
			} else if (action === 'REMOVE') {
				data.color = false;
			} else {
				return false;
			}

			this.saveData();
		},
		customIcon: function (user, action, icon) {
			user = toId(user);
			let data = this.checkExisting(user);
			if (!data.icon) data.icon = '';

			if (action === 'GIVE') {
				data.icon = icon;
			} else if (action === 'REMOVE') {
				data.icon = false;
			} else {
				return false;
			}

			this.saveData();
		},
		addIp: function (user, ip) { // sub-function of initialize user
			user = toId(user);
			if (user.substr(0, 5) === 'guest') return false;

			let data = this.checkExisting(user);
			if (!data.ips) data.ips = [];

			if (!data.ips.includes(ip)) data.ips.push(ip);
		},
		updateSeen: function (user) {
			user = toId(user);
			if (user.substr(0, 5) === 'guest') return false;

			let data = Gold.userData[user];
			if (!data) this.createUser(user);

			data.lastSeen = Date.now();
			this.saveData();
		},
		updateFriends: function (user, friend, action) {
			user = toId(user), friend = toId(friend);
			let data = this.checkExisting(user);
			if (!data.friends) data.friends = [];

			if (action === 'ADD') {
				if (!data.friends.includes(friend))data.friends.push(friend);
			} else if (action === 'DELETE') {
				if (data.friends.includes(friend)) data.friends.remove(friend);
			} else {
				return false;
			}

			this.saveData();
		},
		createTell: function (user, reciever, message) { // heavy lifting for /tell
			reciever = toId(reciever);
			user = toId(user);
			message = Gold.emoticons.processEmoticons(Tools.escapeHTML(message)).replace(///g, '/');

			let data = this.checkExisting(reciever);
			if (!data.tells) data.tells = Object.create(null);
			let tells = data.tells;

			message = Gold.formatMessage(message); // Add PS formatting

			let date = `${moment().format('MMMM Do YYYY, h:mm A')} EST`;
			let tell = `<u>${date}</u><br />${Gold.nameColor(user, true)} said: ${message}`;

			Gold.userData[user].tellNum++;
			tells[`${user}#${Gold.userData[user].tellNum}`] = tell;
			this.saveData();
		},
		checkTells: function (user) {
			user = toId(user);
			let reply = [];
			if (Gold.userData[user]) {
				if (Object.keys(Gold.userData[user].tells).length > 0) {
					for (let i in Gold.userData[user].tells) {
						reply.push(`|raw|${Gold.userData[user].tells[i]}`);
						delete Gold.userData[user].tells[i];
					}
				}
			}
			if (reply.length > 0) this.saveData();
			if (reply.length === 0) return false;
			return reply;
		},
	});
} catch (e) {
	let staff = Rooms('staff');
	if (staff) staff.add(`|html|<div class="broadcast-red"><b>CUSTOM PS FUNCTIONALITY HAS CRASHED:</b><br />${e.stack}<br /><br /><b>Please report this to a developer... so panpawn.`).update();
}
<commit_msg>Let's try this again...<commit_after>/*************************************************
 * User Data Functions - by panpawn              *
 *                                               *
 *  This system includes features that store:    *
 *   - last seen data                            *
 *   - economy (bucks)                           *
 *   - tells (offline messaging)                 *
 *   - and more!                                 *
 *************************************************/
'use strict';

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

Gold.userData = Object.create(null);

function loadUserData() {
	fs.readFile('config/goldusers.json', 'utf8', function (err, file) {
		if (err) return;
		Gold.userData = JSON.parse(file);
	});
};
loadUserData();

try {
	Object.assign(Gold, {

		/******************************
		 * Initialize User Functions  *
		 ******************************/
		createUser: function (user) { // doesn't save unless it gets edited
			user = toId(user);
			if (Gold.userData[user] || user === 'constructor') return false;
			if (user.substr(0, 5) === 'guest') return false;

			Gold.userData[user] = { // esteemed user data
				ips: [],
				tells: Object.create(null),
				friends: [],
				badges: [],
				tellNum: 0,
				money: 0,
				lastSeen: 0,
				color: false,
				icon: false,
				vip: false,
				status: '',
				friendcode: '',
			} // we don't save blank user data objects until next save
		},
		saveData: function () {
				fs.writeFileSync('config/goldusers.json', JSON.stringify(Gold.userData));
		}.throttle(1 * 1000), // only save once/second - TOPS
		initiateUser: function (user, ip) {	// when the user connections, this runs
			user = toId(user);
			if (!Gold.userData[user]) Gold.createUser(user);

			this.addIp(user, ip);
			this.updateSeen(user); // (saves)
		},
		checkExisting: function (user) {
			user = toId(user);
			if (!Gold.userData[user]) Gold.createUser(user);
			return Gold.userData[user];
		},

		/*********************
		 * Economy Functions *
		 *********************/
		updateMoney: function (user, amount) {
			user = toId(user);
			if (isNaN(amount)) return false;
			amount = Number(amount);

			let data = this.checkExisting(user);
			data.money = Number(data.money + amount);
			this.saveData();
		},
		readMoney: function (user) {
			user = toId(user);
			let data = this.checkExisting(user);
			return data.money;
		},
		moneyCirculating: function () {
			let data = Object.keys(Gold.userData);
			// [total bucks, average bucks, number of users with at least 1 money]
			let results = [0, 0, 0];

			data.forEach(user => {
				if (Gold.userData[user].money > 0) {
					if (isNaN(Gold.userData[user].money)) return;
					results[0] += Math.round(Number(Gold.userData[user].money));
					results[2]++;
				}
			});
			results[1] = Math.round(results[0] / results[2]);

			return results;
		},
		richestUsers: function (number) { // basically the heavy lifting for the command
			number = number > Gold.moneyCirculating()[2] ? Gold.moneyCirculating()[2] : number;
			let data = Object.keys(Gold.userData);
			let userids = new Array(0);
			let tableStyle = 'background: linear-gradient(10deg, #FFF8B5, #eadf7c, #FFF8B5); color: black; border: 1px solid #635b00; padding: 2px; border-radius: 5px; text-align:center;';
			let tdStyle = 'border-radius: 5px; border: 1px solid #635b00; background: #fff8b5; color: black;';
			let returnText = `${number > 10 ? '<div class="infobox-limited">' : '<div>'}<b>The top ${number} richest users are:</b><table style="${tableStyle}" border="1" cellspacing ="0" cellpadding="3">`;
			returnText += `<tr><td style="${tdStyle}"><b>Rank</b></td><td style="${tdStyle}"><b>Name</b></td><td style="${tdStyle}"><b>Bucks</b></td></tr>`;

			function ResultsArray (id, money) {
				this.id = id;
				this.money = money;
			}

			data.forEach(user => {
				if (Gold.userData[user].money > 0) {
					userids.push(new ResultsArray(user, Gold.userData[user].money));
				}
			});

			userids.sort(function (a, b) {
				return b.money - a.money;
			});

			for (let i = 0; i < number; i++) {
				if (userids[i]) returnText += `<tr><td style="${tdStyle}">${i + 1}.</td><td style="${tdStyle}">${Gold.nameColor(userids[i].id, true)}</td><td style="${tdStyle}">${userids[i].money}</td></tr>`;
			}
			returnText += '

';

			return returnText;
		},

		/*******************
		 * Misc. Functions *
		 *******************/
		hasVip: function (user) {
			user = toId(user);
			let data = this.checkExisting(user);
			if (!data.badges) data.badges = [];
			let vip = data.badges.includes('vip');
			return vip;
		},
		modifyBadge: function (user, badgeid, action) {
			user = toId(user);
			badgeid = toId(badgeid);

			let data = this.checkExisting(user);
			if (!data.badges) data.badges = [];

			if (action === 'GIVE') {
				if (data.badges.includes(badgeid)) return false;
				data.badges.push(badgeid);
			} else if (action === 'TAKE') {
				if (!data.badges.includes(badgeid)) return false;
				data.badges.remove(badgeid);
			} else {
				return false;
			}
			this.saveData();
		},
		badgeList: function (displayall) {
			// This houses the badges of the server.  You can add/modify/remove badges
			// here the with the same format as you see.
			let badgeList = {
				'dev': {
					title: 'Developer',
					img: 'http://www.smogon.com/media/forums/images/badges/factory_foreman.png',
				}, 'admin': {
					title: 'Server Administrator',
					img: 'http://www.smogon.com/media/forums/images/badges/sop.png',
				}, 'fgs': {
					title: 'Former Gold Staff',
					img: 'http://www.smogon.com/media/forums/images/badges/forummod_alum.png',
				}, 'leader': {
					title: 'Server Leader',
					img: 'http://www.smogon.com/media/forums/images/badges/aop.png',
				}, 'mod': {
					title: 'Exceptional Staff Member',
					img: 'http://www.smogon.com/media/forums/images/badges/pyramid_king.png',
				}, 'rf': {
					title: 'Successful Room Founder',
					img: 'http://www.smogon.com/media/forums/images/badges/forumsmod.png',
				}, 'comcun': {
					title: 'Community Contributor',
					img: 'http://www.smogon.com/media/forums/images/badges/cc.png',
				}, 'art': {
					title: 'Artist',
					img: 'http://www.smogon.com/media/forums/images/badges/ladybug.png',
				}, 'vip': {
					title: 'VIP User',
					img: 'http://www.smogon.com/media/forums/images/badges/zeph.png',
				}, 'twinner': {
					title: 'Event Tournament Winner',
					img: 'http://www.smogon.com/media/forums/images/badges/spl.png',
				}, 'creator': {
					title: 'Server Creator',
					img: 'http://www.smogon.com/media/forums/images/badges/dragon.png',
				}
			};
			if (displayall) {
				let buff = [];
				Object.keys(badgeList).forEach(badge => {
					buff.push(`<img src="${badgeList[badge].img}" title="${badgeList[badge].title}">`);
				});
				return buff.join(" | ");
			}
			return badgeList;
		},
		displayBadges: function (user) {
			user = toId(user);
			let data = this.checkExisting(user), buff = [];
			if (!data.badges || data.badges.length < 0) return false;

			let badgeObj = this.badgeList();
			let badgeList = Object.keys(badgeObj);
			badgeList.forEach(badge => {
				if (data.badges.includes(badge)) buff.push(`<img src="${badgeObj[badge].img}" title="${badgeObj[badge].title}">`);
			});
			return buff.join(" ");
		},
		customColor: function (user, action, color) {
			user = toId(user);
			let data = this.checkExisting(user);
			if (!data.color) data.color = '';

			if (action === 'GIVE') {
				data.color = color;
			} else if (action === 'REMOVE') {
				data.color = false;
			} else {
				return false;
			}

			this.saveData();
		},
		customIcon: function (user, action, icon) {
			user = toId(user);
			let data = this.checkExisting(user);
			if (!data.icon) data.icon = '';

			if (action === 'GIVE') {
				data.icon = icon;
			} else if (action === 'REMOVE') {
				data.icon = false;
			} else {
				return false;
			}

			this.saveData();
		},
		addIp: function (user, ip) { // sub-function of initialize user
			user = toId(user);
			if (user.substr(0, 5) === 'guest') return false;

			let data = this.checkExisting(user);
			if (!data.ips) data.ips = [];

			if (!data.ips.includes(ip)) data.ips.push(ip);
		},
		updateSeen: function (user) {
			user = toId(user);
			if (user.substr(0, 5) === 'guest') return false;

			let data = Gold.userData[user];
			if (!data) this.createUser(user);

			data.lastSeen = Date.now();
			this.saveData();
		},
		updateFriends: function (user, friend, action) {
			user = toId(user), friend = toId(friend);
			let data = this.checkExisting(user);
			if (!data.friends) data.friends = [];

			if (action === 'ADD') {
				if (!data.friends.includes(friend))data.friends.push(friend);
			} else if (action === 'DELETE') {
				if (data.friends.includes(friend)) data.friends.remove(friend);
			} else {
				return false;
			}

			this.saveData();
		},
		createTell: function (user, reciever, message) { // heavy lifting for /tell
			reciever = toId(reciever);
			user = toId(user);
			message = Gold.emoticons.processEmoticons(Tools.escapeHTML(message)).replace(///g, '/');

			let data = this.checkExisting(reciever);
			if (!data.tells) data.tells = Object.create(null);
			let tells = data.tells;

			message = Gold.formatMessage(message); // Add PS formatting

			let date = `${moment().format('MMMM Do YYYY, h:mm A')} EST`;
			let tell = `<u>${date}</u><br />${Gold.nameColor(user, true)} said: ${message}`;

			Gold.userData[user].tellNum++;
			tells[`${user}#${Gold.userData[user].tellNum}`] = tell;
			this.saveData();
		},
		checkTells: function (user) {
			user = toId(user);
			let reply = [];
			if (Gold.userData[user]) {
				if (Object.keys(Gold.userData[user].tells).length > 0) {
					for (let i in Gold.userData[user].tells) {
						reply.push(`|raw|${Gold.userData[user].tells[i]}`);
						delete Gold.userData[user].tells[i];
					}
				}
			}
			if (reply.length > 0) this.saveData();
			if (reply.length === 0) return false;
			return reply;
		},
	});
} catch (e) {
	let staff = Rooms('staff');
	if (staff) staff.add(`|html|<div class="broadcast-red"><b>CUSTOM PS FUNCTIONALITY HAS CRASHED:</b><br />${e.stack}<br /><br /><b>Please report this to a developer... so panpawn.`).update();
}
<|endoftext|>