<commit_before>'use strict';

const repl = require('repl');
const io = require('socket.io');

let randInt = (min, max) => Math.floor(Math.random() * (max - min)) + min;
let randChoose = choices => choices[randInt(0, choices.length)];
class Player {
  constructor(server, id) {
    let config = server.config;
    this.id = id;
    this.clan = null;
    this.server = server;
    this.untilSend = 1;

    this.name = 'unknown';
    this.skin = 0;
    this.size = config.playerScale;

    this.aimAngle = 0;
    this.movement = null;
    this.kill();
  }
  updateMovement(delta) {
    let config = this.server.config;
    let tx = 0;
    let ty = 0;
    if (this.movement != null) {
      tx = Math.cos(this.movement);
      ty = Math.sin(this.movement);
    }
    this.vx *= Math.pow(config.playerDecel, delta);
    this.vy *= Math.pow(config.playerDecel, delta);
    this.vx += tx * config.playerSpeed * delta * this.size / 2;
    this.vy += ty * config.playerSpeed * delta * this.size / 2;
    this.x += this.vx;
    this.y += this.vy;
  }
  update(delta) {
    if (this.alive) {
      this.updateMovement(delta);
      this.untilSend--;
      if (!this.untilSend) {
        this.untilSend = this.server.config.clientSendRate;
        this.sendPosition();
      }
    }
  }
  sendPosition() {
    let socket = this.socket;
    socket.emit('a');
    socket.emit('3', [
      this.id,
      this.x,
      this.y, -2.26,-1,0,0,null,0,0,0,0]);
  }
  link(socket) {
    this.socket = socket;
    socket.once('error', err => {
      console.log(err);
      this.destroy();
    });

    var emit = (...arg) => {
      try {
        socket.broadcast.emit(...arg)
        socket.emit(...arg)
      } catch (e) {
        sockets.forEach(a => a.emit(...arg))
      }
    }

    socket.on('2', angle => this.aimAngle = angle);
    socket.on('3', angle => this.movement = angle);

    socket.on("14",function(data){
        emit("p",x,y)
    });

    socket.once('disconnect', () => this.destroy());
    socket.emit('id', {
      teams: this.server.clans
    });
    socket.on('1', data => {
      this.name = data.name.length > 15 || !data.name ? 'unknown' : data.name;
      this.skin = data.skin;
      this.spawn();
    });
  }
  destroy() {
    this.kill();
    this.server.remove(this.id);
    this.socket.disconnect();
  }
  kill() {
    this.alive = false;
    this.x = 0;
    this.y = 0;no
    this.slowDown();
  }
  slowDown() {
    this.vx = 0;
    this.vy = 0;
  }
  spawn() {
    let config = this.server.config;
    let socket = this.socket;
    this.alive = true;
    let { x, y } = this.server.allocatePosition(this.size);
    this.x = x;
    this.y = y;
    this.slowDown();
    socket.emit('1', this.id);
    socket.emit('2', [socket.id,this.id,this.name,this.x,this.y,0,100,100,this.size,this.skin],true);
  }
  hitResource(type) {

  }
}
class Resource {
  constructor(server, x, y, size, type) {
    let config = server.config;
    this.x = x;
    this.y = y;
    this.type = config.resourceTypes.indexOf(type);
    this.size = size;
  }
  reward(by) {
    by.hitResource(this.type);
  }
}
class Server {
  constructor(config) {
    this.config = config;
    this.players = Array(config.maxPlayers).fill(null);
    this.lastRun = Date.now();
    this.clans = [];
    this.objects = [];
    setInterval(() => this.update(), config.serverUpdateRate);
    this.generateWorld();
  }
  remove(sid) {
    this.players[sid] = null;
  }
  update() {
    let now = Date.now();
    let delta = now - this.lastRun;
    this.lastRun = now;
    for (let i of this.players) {
      if (i != null) {
        i.update(delta);
      }
    }
  }
  generateWorld() {
    let config = this.config;
    let areaCount = config.areaCount;
    let mapScale = config.mapScale;
    let areaSize = mapScale / areaCount;
    let all = [];
    for (let afx = 0, atx = 1; afx < areaCount; afx++, atx++) {
      for (let afy = 0, aty = 1; afy < areaCount; afy++, aty++) {
        for (let i = 0; i < config.treesPerArea; i++) {
          let x = randInt(areaSize * afx, areaSize * atx);
          let y = randInt(areaSize * afy, areaSize * aty);
          all.push(new Resource(this, x, y, randChoose(config.treeScales), 'wood'));
        }
        for (let i = 0; i < config.bushesPerArea; i++) {
          let x = randInt(areaSize * afx, areaSize * atx);
          let y = randInt(areaSize * afy, areaSize * aty);
          all.push(new Resource(this, x, y, randChoose(config.bushScales), 'food'));
        }
      }
    }
    for (let i = 0; i < config.totalRocks; i++) {
      let x = randInt(0, mapScale);
      let y = randInt(0, mapScale);
      all.push(new Resource(this, x, y, randChoose(config.rockScales), 'stone'));
    }
    for (let i = 0; i < config.goldOres; i++) {
      let x = randInt(0, mapScale);
      let y = randInt(0, mapScale);
      all.push(new Resource(this, x, y, 0, 'points'));
    }
    this.objects = all;
  }
  allocatePosition(size) {
    let scale = this.config.mapScale;
    let x = 0;
    let y = 0;
    while (true) {
      x = randInt(0, scale);
      y = randInt(0, scale);
      if (true) { // check if there's nothing overlapping
        break;
      }
    }
    return { x, y };
  }
  handle(socket) {
    for (let i = 0; i < this.players.length; i++) {
      if (this.players[i] == null) {
        let player = new Player(this, i);
        player.link(socket);
        this.players[i] = player;
        break;
      }
    }
  }
}

let app = new Server({
  mapScale: 14400,
  maxPlayers: 50,
  clientSendRate: 5,
  serverUpdateRate: 9,
  playerDecel: 0.993,
  playerSpeed: 0.0016,
  playerScale: 35,
  areaCount: 7,
  treesPerArea: 9,
  bushesPerArea: 3,
  totalRocks: 32,
  goldOres: 7,
  resourceTypes: ['wood', 'food', 'stone', 'points'],
  treeScales: [140, 145, 150, 155],
  bushScales: [80, 85, 95],
  rockScales: [80, 85, 90],
});

for (let i = 5000; i <= 5010; i++) {
  io(i).on('connection', socket => app.handle(socket));
}
/*
let teams = [];
let sockets = [];
  io(i).on('connection', function (socket) {
    let emit = (...arg) => {
      try {
        socket.broadcast.emit(...arg);
        socket.emit(...arg);
      } catch (e) {
        sockets.forEach(a => a.emit(...arg));
      }
    };
    sockets.push(socket);
    socket.on('1', function (data) {
      let id = 27;
      let name = data.name.length > 15 ? 'unknown' : data.name;
      socket.emit('id', {
        "teams": teams
      });
      socket.emit('1', id);
      socket.emit('mm', 0);
      socket.emit('3', []);
      let x = randInt(0, config.mapScale);
      let y = randInt(0, config.mapScale);
      let userteam = null;
      let last = 0;
      socket.emit("2", ["a3Pm5dMzeKOjc5gvAJEF", id, name, x, 7200, 0, 100, 100, 35, data.skin], true);
      socket.emit("5", [27, data.name, 9001]); //[5,"RIP",31988,45,"KADEJO503",23404,34,"winter wolf",4821,28,"Godenot",4500,33,"Arena Closer",3000,32,"LightTheif",2940,6,"CarlosKoS-_-16",2800,4,"GD desconhecido",2635,35,"jack black GD",2357,19,"AMIGO BOM",1623])
      socket.emit("6", [
        29, 3115.1, 13592.9, 0, 109.2, 1, null, -1,
        353, 4103, 13436, 0, 80, 2, null, -1,
        339, 2498, 14155, 0, 90, 2, null, -1
      ]);
      socket.emit("8", 2.6, 28);
      socket.on("ch", data => {
        emit("ch", id, data);
      });
      socket.on("8", data => {
        console.log('CLAN CREATE REQUEST:', data);
        teams.push([{
          "sid": data,
          "owner": id
        }]);
        let userteam = data;
        emit("st", data, true);
      });
      socket.on("3", function (data) {
        if (data == null) {
          vx = vy = 0;
          return;
        } else if (x < 0 || x > config.mapScale || y < 0 || y > config.mapScale) {
          x = 7200;
          y = 7200;
        }
        if (y >= 6840 && y <= 7560) {
          x += 0.44;
        }
        let speed = y > 2400 ? 60 * 0.8 : 60;
        vx = Math.cos(data) * speed;
        vy = Math.sin(data) * speed;
        x += vx;
        y += vy;
        socket.emit('a');
        socket.emit("3", [id, x, y, -2.26, -1, 0, 0, null, 0, 0, 0, 0]);
      });
      socket.on("14", function (data) {
        console.log('ping!!!', arguments);
      });
    });
  });
}
*/
repl.start({
  eval: (a, _c, _f, cb) => {
    try {
      cb(null, eval(a)); // jshint ignore: line
    } catch (e) {
      cb(e);
    }
  }
});
<commit_msg>Arrow function for ping<commit_after>'use strict';

const repl = require('repl');
const io = require('socket.io');

let randInt = (min, max) => Math.floor(Math.random() * (max - min)) + min;
let randChoose = choices => choices[randInt(0, choices.length)];
class Player {
  constructor(server, id) {
    let config = server.config;
    this.id = id;
    this.clan = null;
    this.server = server;
    this.untilSend = 1;

    this.name = 'unknown';
    this.skin = 0;
    this.size = config.playerScale;

    this.aimAngle = 0;
    this.movement = null;
    this.kill();
  }
  updateMovement(delta) {
    let config = this.server.config;
    let tx = 0;
    let ty = 0;
    if (this.movement != null) {
      tx = Math.cos(this.movement);
      ty = Math.sin(this.movement);
    }
    this.vx *= Math.pow(config.playerDecel, delta);
    this.vy *= Math.pow(config.playerDecel, delta);
    this.vx += tx * config.playerSpeed * delta * this.size / 2;
    this.vy += ty * config.playerSpeed * delta * this.size / 2;
    this.x += this.vx;
    this.y += this.vy;
  }
  update(delta) {
    if (this.alive) {
      this.updateMovement(delta);
      this.untilSend--;
      if (!this.untilSend) {
        this.untilSend = this.server.config.clientSendRate;
        this.sendPosition();
      }
    }
  }
  sendPosition() {
    let socket = this.socket;
    socket.emit('a');
    socket.emit('3', [
      this.id,
      this.x,
      this.y, -2.26,-1,0,0,null,0,0,0,0]);
  }
  link(socket) {
    this.socket = socket;
    socket.once('error', err => {
      console.log(err);
      this.destroy();
    });

    var emit = (...arg) => {
      try {
        socket.broadcast.emit(...arg)
        socket.emit(...arg)
      } catch (e) {
        sockets.forEach(a => a.emit(...arg))
      }
    }

    socket.on('2', angle => this.aimAngle = angle);
    socket.on('3', angle => this.movement = angle);

    socket.on("14", data => emit("p",x,y));

    socket.once('disconnect', () => this.destroy());
    socket.emit('id', {
      teams: this.server.clans
    });
    socket.on('1', data => {
      this.name = data.name.length > 15 || !data.name ? 'unknown' : data.name;
      this.skin = data.skin;
      this.spawn();
    });
  }
  destroy() {
    this.kill();
    this.server.remove(this.id);
    this.socket.disconnect();
  }
  kill() {
    this.alive = false;
    this.x = 0;
    this.y = 0;no
    this.slowDown();
  }
  slowDown() {
    this.vx = 0;
    this.vy = 0;
  }
  spawn() {
    let config = this.server.config;
    let socket = this.socket;
    this.alive = true;
    let { x, y } = this.server.allocatePosition(this.size);
    this.x = x;
    this.y = y;
    this.slowDown();
    socket.emit('1', this.id);
    socket.emit('2', [socket.id,this.id,this.name,this.x,this.y,0,100,100,this.size,this.skin],true);
  }
  hitResource(type) {

  }
}
class Resource {
  constructor(server, x, y, size, type) {
    let config = server.config;
    this.x = x;
    this.y = y;
    this.type = config.resourceTypes.indexOf(type);
    this.size = size;
  }
  reward(by) {
    by.hitResource(this.type);
  }
}
class Server {
  constructor(config) {
    this.config = config;
    this.players = Array(config.maxPlayers).fill(null);
    this.lastRun = Date.now();
    this.clans = [];
    this.objects = [];
    setInterval(() => this.update(), config.serverUpdateRate);
    this.generateWorld();
  }
  remove(sid) {
    this.players[sid] = null;
  }
  update() {
    let now = Date.now();
    let delta = now - this.lastRun;
    this.lastRun = now;
    for (let i of this.players) {
      if (i != null) {
        i.update(delta);
      }
    }
  }
  generateWorld() {
    let config = this.config;
    let areaCount = config.areaCount;
    let mapScale = config.mapScale;
    let areaSize = mapScale / areaCount;
    let all = [];
    for (let afx = 0, atx = 1; afx < areaCount; afx++, atx++) {
      for (let afy = 0, aty = 1; afy < areaCount; afy++, aty++) {
        for (let i = 0; i < config.treesPerArea; i++) {
          let x = randInt(areaSize * afx, areaSize * atx);
          let y = randInt(areaSize * afy, areaSize * aty);
          all.push(new Resource(this, x, y, randChoose(config.treeScales), 'wood'));
        }
        for (let i = 0; i < config.bushesPerArea; i++) {
          let x = randInt(areaSize * afx, areaSize * atx);
          let y = randInt(areaSize * afy, areaSize * aty);
          all.push(new Resource(this, x, y, randChoose(config.bushScales), 'food'));
        }
      }
    }
    for (let i = 0; i < config.totalRocks; i++) {
      let x = randInt(0, mapScale);
      let y = randInt(0, mapScale);
      all.push(new Resource(this, x, y, randChoose(config.rockScales), 'stone'));
    }
    for (let i = 0; i < config.goldOres; i++) {
      let x = randInt(0, mapScale);
      let y = randInt(0, mapScale);
      all.push(new Resource(this, x, y, 0, 'points'));
    }
    this.objects = all;
  }
  allocatePosition(size) {
    let scale = this.config.mapScale;
    let x = 0;
    let y = 0;
    while (true) {
      x = randInt(0, scale);
      y = randInt(0, scale);
      if (true) { // check if there's nothing overlapping
        break;
      }
    }
    return { x, y };
  }
  handle(socket) {
    for (let i = 0; i < this.players.length; i++) {
      if (this.players[i] == null) {
        let player = new Player(this, i);
        player.link(socket);
        this.players[i] = player;
        break;
      }
    }
  }
}

let app = new Server({
  mapScale: 14400,
  maxPlayers: 50,
  clientSendRate: 5,
  serverUpdateRate: 9,
  playerDecel: 0.993,
  playerSpeed: 0.0016,
  playerScale: 35,
  areaCount: 7,
  treesPerArea: 9,
  bushesPerArea: 3,
  totalRocks: 32,
  goldOres: 7,
  resourceTypes: ['wood', 'food', 'stone', 'points'],
  treeScales: [140, 145, 150, 155],
  bushScales: [80, 85, 95],
  rockScales: [80, 85, 90],
});

for (let i = 5000; i <= 5010; i++) {
  io(i).on('connection', socket => app.handle(socket));
}
/*
let teams = [];
let sockets = [];
  io(i).on('connection', function (socket) {
    let emit = (...arg) => {
      try {
        socket.broadcast.emit(...arg);
        socket.emit(...arg);
      } catch (e) {
        sockets.forEach(a => a.emit(...arg));
      }
    };
    sockets.push(socket);
    socket.on('1', function (data) {
      let id = 27;
      let name = data.name.length > 15 ? 'unknown' : data.name;
      socket.emit('id', {
        "teams": teams
      });
      socket.emit('1', id);
      socket.emit('mm', 0);
      socket.emit('3', []);
      let x = randInt(0, config.mapScale);
      let y = randInt(0, config.mapScale);
      let userteam = null;
      let last = 0;
      socket.emit("2", ["a3Pm5dMzeKOjc5gvAJEF", id, name, x, 7200, 0, 100, 100, 35, data.skin], true);
      socket.emit("5", [27, data.name, 9001]); //[5,"RIP",31988,45,"KADEJO503",23404,34,"winter wolf",4821,28,"Godenot",4500,33,"Arena Closer",3000,32,"LightTheif",2940,6,"CarlosKoS-_-16",2800,4,"GD desconhecido",2635,35,"jack black GD",2357,19,"AMIGO BOM",1623])
      socket.emit("6", [
        29, 3115.1, 13592.9, 0, 109.2, 1, null, -1,
        353, 4103, 13436, 0, 80, 2, null, -1,
        339, 2498, 14155, 0, 90, 2, null, -1
      ]);
      socket.emit("8", 2.6, 28);
      socket.on("ch", data => {
        emit("ch", id, data);
      });
      socket.on("8", data => {
        console.log('CLAN CREATE REQUEST:', data);
        teams.push([{
          "sid": data,
          "owner": id
        }]);
        let userteam = data;
        emit("st", data, true);
      });
      socket.on("3", function (data) {
        if (data == null) {
          vx = vy = 0;
          return;
        } else if (x < 0 || x > config.mapScale || y < 0 || y > config.mapScale) {
          x = 7200;
          y = 7200;
        }
        if (y >= 6840 && y <= 7560) {
          x += 0.44;
        }
        let speed = y > 2400 ? 60 * 0.8 : 60;
        vx = Math.cos(data) * speed;
        vy = Math.sin(data) * speed;
        x += vx;
        y += vy;
        socket.emit('a');
        socket.emit("3", [id, x, y, -2.26, -1, 0, 0, null, 0, 0, 0, 0]);
      });
      socket.on("14", function (data) {
        console.log('ping!!!', arguments);
      });
    });
  });
}
*/
repl.start({
  eval: (a, _c, _f, cb) => {
    try {
      cb(null, eval(a)); // jshint ignore: line
    } catch (e) {
      cb(e);
    }
  }
});
<|endoftext|>


<commit_before>/* eslint-env node */

'use strict';

const fs = require('fs');
const path = require('path');
const dotenv = require('dotenv');
const parseArgs = require('minimist');

module.exports = {
  name: 'ember-cli-dotenv',

  /**
   * NOTE: dotenv needs to be invoked before the app config is materialized
   * so that the process.env's are set appropriately.  Previously this was done
   * within the `config` hook.  As of 2.15.x, that is too late in the process
   * and needed to be moved into `init`.
   */
  init() {
    this._super.init && this._super.init.apply(this, arguments);

    let root = this.project.root;
    let configFactory = path.join(root, 'config', 'dotenv.js');
    let options = {
      path: path.join(root, '.env'),
      clientAllowedKeys: [],
      failOnMissingKey: false,
    };

    if (fs.existsSync(configFactory)) {
      Object.assign(options, require(configFactory)(this._resolveEnvironment()));
    }

    let loadedConfig = dotenv.config({ path: options.path });
    if (loadedConfig.error && options.failOnMissingKey) {
      throw new Error('[ember-cli-dotenv]: Error while loading ' + options.path + '.');
    } else if (loadedConfig.error) {
      // Nothing to load
      return;
    }

    let allowedKeys = options.clientAllowedKeys || [];

    if (options.failOnMissingKey) {
      allowedKeys.map(key => {
        if (!loadedConfig.parsed[key]) {
          throw new Error('[ember-cli-dotenv]: Required environment variable \'' + key + '\' is missing.');
        }
      });
    }

    this._config = allowedKeys.reduce((accumulator, key) => {
      accumulator[key] = loadedConfig.parsed[key];

      return accumulator;
    }, {});
  },

  _resolveEnvironment() {
    if (process.env.EMBER_ENV) {
      return process.env.EMBER_ENV;
    }

    let args = parseArgs(process.argv);
    let env = args.e || args.env || args.environment;

    // Is it "ember b -prod" command?
    if (!env && process.argv.indexOf('-prod') > -1) {
      env = 'production'
    }

    // Is it "ember test" or "ember t" command without explicit env specified?
    if (!env && (process.argv.indexOf('test') > -1 || process.argv.indexOf('t') > -1)) {
      env = 'test'
    }

    return env || 'development';
  },

  config() {
    return this._config;
  }
};
<commit_msg>#44 Display warnings when failOnMissingKey disabled<commit_after>/* eslint-env node */

'use strict';

const fs = require('fs');
const path = require('path');
const dotenv = require('dotenv');
const parseArgs = require('minimist');

module.exports = {
  name: 'ember-cli-dotenv',

  /**
   * NOTE: dotenv needs to be invoked before the app config is materialized
   * so that the process.env's are set appropriately.  Previously this was done
   * within the `config` hook.  As of 2.15.x, that is too late in the process
   * and needed to be moved into `init`.
   */
  init() {
    this._super.init && this._super.init.apply(this, arguments);

    let root = this.project.root;
    let configFactory = path.join(root, 'config', 'dotenv.js');
    let options = {
      path: path.join(root, '.env'),
      clientAllowedKeys: [],
      failOnMissingKey: false,
    };

    if (fs.existsSync(configFactory)) {
      Object.assign(options, require(configFactory)(this._resolveEnvironment()));
    }

    let loadedConfig = dotenv.config({ path: options.path });

    // It might happen that environment config is missing or corrupted
    if (loadedConfig.error) {
      let loadingErrMsg = `[ember-cli-dotenv]: ${loadedConfig.error.message}`;
      if (options.failOnMissingKey) {
        throw new Error(loadingErrMsg);
      } else {
        console.warn(loadingErrMsg);
        return;
      }
    }

    let allowedKeys = options.clientAllowedKeys || [];

    allowedKeys.map(key => {
      if (loadedConfig.parsed[key] === undefined) {
        let errMsg = '[ember-cli-dotenv]: Required environment variable \'' + key + '\' is missing.';
        if (options.failOnMissingKey) {
          throw new Error(errMsg);
        } else {
          console.warn(errMsg);
        }
      }
    });

    this._config = allowedKeys.reduce((accumulator, key) => {
      accumulator[key] = loadedConfig.parsed[key];

      return accumulator;
    }, {});
  },

  _resolveEnvironment() {
    if (process.env.EMBER_ENV) {
      return process.env.EMBER_ENV;
    }

    let args = parseArgs(process.argv);
    let env = args.e || args.env || args.environment;

    // Is it "ember b -prod" command?
    if (!env && process.argv.indexOf('-prod') > -1) {
      env = 'production'
    }

    // Is it "ember test" or "ember t" command without explicit env specified?
    if (!env && (process.argv.indexOf('test') > -1 || process.argv.indexOf('t') > -1)) {
      env = 'test'
    }

    return env || 'development';
  },

  config() {
    return this._config;
  }
};
<|endoftext|>


<commit_before>#!/usr/bin/env node

const fs = require('fs');
const path = require('path');
const Mqtt = require('mqtt');
const chalk = require('chalk');
const qrcode = require('qrcode-terminal');
const express = require('express');
const bodyParser = require('body-parser');
const basicAuth = require('express-basic-auth');

const app = express();

const log = require('yalm');
const HAP = require('hap-nodejs');
const pkgHap = require('./node_modules/hap-nodejs/package.json');
const pkg = require('./package.json');
const config = require('./config.js');

log.setLevel(config.verbosity);

log(pkg.name + ' ' + pkg.version + ' starting');

const mqttStatus = {}; // Holds the payloads of the last-received message, keys are the topics.
const mqttCallbacks = {}; // Holds arrays of subscription callbacks, keys are the topics.
let mqttConnected;

let bridgeListening;
const topics = [];

log.info('mqtt trying to connect', config.url);
const mqtt = Mqtt.connect(config.url, {
    will: {topic: config.name + '/connected', payload: '0', retain: true},
    rejectUnauthorized: !config.insecure
});

mqtt.on('connect', () => {
    mqttConnected = true;
    log.info('mqtt connected ' + config.url);
    /* istanbul ignore if */
    if (!bridgeListening) {
        mqttPub(config.name + '/connected', '1', {retain: true});
    }
});

/* istanbul ignore next */
mqtt.on('reconnect', () => {
    log.info('mqtt reconnect');
});

/* istanbul ignore next */
mqtt.on('offline', () => {
    log.info('mqtt offline');
});

/* istanbul ignore next */
mqtt.on('close', () => {
    if (mqttConnected) {
        mqttConnected = false;
        log.info('mqtt closed ' + config.url);
    }
});

/* istanbul ignore next */
mqtt.on('error', err => {
    log.error('mqtt error ' + err);
});

function typeGuess(payload) {
    let state;
    // Nasty type guessing.
    // TODO clarify Do we really want/need to cast the strings "true" and "false" to bool? https://github.com/hobbyquaker/homekit2mqtt/issues/66
    if (payload === 'true') {
        state = true;
    } else if (payload === 'false') {
        state = false;
    } else if (isNaN(payload)) {
        state = payload;
    } else {
        state = parseFloat(payload);
    }
    return state;
}

// MQTT subscribe function that provides a callback on incoming messages.
// Not meant to be used with wildcards!
function mqttSub(topic, /* string, optional, default "val" */ attr, callback) {
    topic = String(topic);
    if (topic === '') {
        log.error('trying to subscribe empty topic');
        return;
    }
    if (typeof attr === 'function') {
        callback = attr;
        attr = 'val';
    } else if (typeof attr === 'undefined' || attr === '') {
        attr = 'val';
    } else {
        attr = String(attr);
    }
    /* istanbul ignore else */
    if (typeof callback === 'function') {
        /* istanbul ignore if */
        if (mqttCallbacks[topic]) {
            mqttCallbacks[topic].push({attr, callback});
        } else {
            mqttCallbacks[topic] = [{attr, callback}];
            log.debug('mqtt subscribe', topic);
            mqtt.subscribe(topic);
        }
    } else {
        log.debug('mqtt subscribe', topic);
        mqtt.subscribe(topic);
    }
}

// MQTT publish function, checks for valid topic and converts payload to string in a meaningful manner.
function mqttPub(topic, payload, options) {
    /* istanbul ignore if */
    if (!topic || (typeof topic !== 'string')) {
        log.error('mqttPub invalid topic', topic);
    } else {
        /* istanbul ignore if */
        if (typeof payload === 'object') {
            payload = JSON.stringify(payload);
        } else if (typeof payload === 'undefined') {
            payload = '';
        } else if (typeof payload !== 'string') {
            payload = String(payload);
        }
        log.debug('> mqtt', topic, payload);
        mqtt.publish(topic, payload, options, err => {
            /* istanbul ignore next */
            if (err) {
                log.error('mqtt publish error ' + err);
            }
        });
    }
}

log.info('using hap-nodejs version', pkgHap.version);

const {uuid, Bridge, Accessory, Service, Characteristic} = HAP;

/* istanbul ignore next */
if (config.storagedir) {
    log.info('using directory ' + config.storagedir + ' for persistent storage');
}
// If storagedir is not set it uses HAP-Nodejs default
// (usually /usr/local/lib/node_modules/homekit2mqtt/node_modules/node-persist/persist)
HAP.init(config.storagedir || undefined);

// Create Bridge which will host all Accessories
const bridge = new Bridge(config.bridgename, uuid.generate(config.bridgename));

// Listen for Bridge identification event
/* istanbul ignore next */
bridge.on('identify', (paired, callback) => {
    log('< hap bridge identify', paired ? '(paired)' : '(unpaired)');
    callback();
});

// Handler for Accessory identification events
/* istanbul ignore next */
function identify(settings, paired, callback) {
    log.debug('< hap identify', settings.name, paired ? '(paired)' : '(unpaired)');
    if (settings.topicIdentify) {
        log.debug('> mqtt', settings.topicIdentify, settings.payloadIdentify);
        mqttPub(settings.topicIdentify, settings.payloadIdentify);
    }
    callback();
}

function newAccessory(settings) {
    log.debug('creating new accessory', '"' + settings.name + '"', '"' + settings.id + '"', uuid.generate(settings.id));
    const acc = new Accessory(settings.name, uuid.generate(settings.id));
    if (settings.manufacturer || settings.model || settings.serial) {
        acc.getService(Service.AccessoryInformation)
            .setCharacteristic(Characteristic.Manufacturer, settings.manufacturer || '-')
            .setCharacteristic(Characteristic.Model, settings.model || '-')
            .setCharacteristic(Characteristic.SerialNumber, settings.serial || '-');
    }
    if (!settings.payload) {
        settings.payload = {};
    }
    if (!settings.config) {
        settings.config = {};
    }
    /* istanbul ignore next */
    acc.on('identify', (paired, callback) => {
        identify(settings, paired, callback);
    });
    return acc;
}

const addService = {};

function loadService(service) {
    const file = 'services/' + service + '.js';
    log.debug('loading', file);
    addService[service] = require(path.join(__dirname, file))({mqttPub, mqttSub, mqttStatus, log, Service, Characteristic});
}

let mapping;
let accCount;

/* Convert old config file schema to keep compatiblity */
function convertMapping() {
    let isConverted;
    Object.keys(mapping).forEach(id => {
        const accConfig = mapping[id];

        if (!accConfig.services) {
            accConfig.services = [];
            isConverted = true;
        }

        if (accConfig.topic && accConfig.topic.identify) {
            accConfig.topicIdentify = accConfig.topic.identify;
            delete accConfig.topic.identify;
            isConverted = true;
        }
        if (accConfig.payload && accConfig.payload.identify) {
            accConfig.payloadIdentify = accConfig.payload.identify;
            delete accConfig.payload.identify;
            isConverted = true;
        }

        if (accConfig.service) {
            accConfig.services.unshift({
                name: accConfig.name,
                service: accConfig.service,
                topic: accConfig.topic || {},
                payload: accConfig.payload || {},
                config: accConfig.config || {},
                props: accConfig.props || {}
            });
            delete accConfig.service;
            delete accConfig.topic;
            delete accConfig.payload;
            delete accConfig.config;
            delete accConfig.props;
            isConverted = true;
        }
    });
    if (isConverted) {
        log.info('mapping file converted');
        saveMapping();
    }
}

function createBridge() {
    mqtt.on('message', (topic, payload) => {
        payload = payload.toString();
        let state;
        if (payload.indexOf('{') === -1 || config.disableJsonParse) {
            state = typeGuess(payload);
        } else {
            try {
                // We got an Object - let's hope it follows mqtt-smarthome architecture and has an attribute "val"
                // see https://github.com/mqtt-smarthome/mqtt-smarthome/blob/master/Architecture.md
                // TODO make attribute configurable to support non-mqtt-smarthome json payloads https://github.com/hobbyquaker/homekit2mqtt/issues/67
                // the attibute configuration has to be part of the service settings
                state = JSON.parse(payload).val;
                if (typeof state === 'undefined') {
                    // :-( attribute does not exist
                    throw new TypeError('attribute val undefined');
                }
            } catch (err) {
                state = typeGuess(payload);
            }
        }

        log.debug('< mqtt', topic, state, payload);
        // TODO take care when mqttStatus is used on hap get, these have to handle the attribute themselfes https://github.com/hobbyquaker/homekit2mqtt/issues/67
        mqttStatus[topic] = state;
        /* istanbul ignore else */
        if (mqttCallbacks[topic]) {
            mqttCallbacks[topic].forEach(obj => {
                const {attr, callback} = obj; // eslint-disable-line no-unused-vars
                if (typeof callback === 'function') {
                    // TODO make attribute configurable to support non-mqtt-smarthome json payloads https://github.com/hobbyquaker/homekit2mqtt/issues/67
                    callback(state);
                }
            });
        }
        // Topics array Used for autocomplete in web ui)
        if (topics.indexOf(topic) === -1 && topic !== config.name + '/connected') {
            topics.push(topic);
        }
    });

    // Load and create all accessories
    log.info('loading HomeKit to MQTT mapping file ' + config.mapfile);
    mapping = require(config.mapfile);
    convertMapping();
    accCount = 0;
    Object.keys(mapping).forEach(id => {
        const accConfig = mapping[id];
        accConfig.id = id;
        const acc = newAccessory(accConfig);

        accConfig.services.forEach((s, i) => {
            if (!addService[s.service]) {
                loadService(s.service);
            }
            log.debug('adding service', s.service, 'to accessory', accConfig.name);
            addService[s.service](acc, s, String(i));
        });

        log.debug('addBridgedAccessory ' + accConfig.name);
        bridge.addBridgedAccessory(acc);
        accCount++;
    });
    log.info('hap created', accCount, 'Accessories');

    bridge.publish({
        username: config.username,
        port: config.port,
        pincode: config.c,
        category: Accessory.Categories.OTHER
    });
    log('hap publishing bridge "' + config.bridgename + '" username=' + config.username, 'port=' + config.port,
        'pincode=' + config.c, 'setupURI=' + bridge.setupURI());

    bridge._server.on('listening', () => {
        bridgeListening = true;
        mqttPub(config.name + '/connected', '2', {retain: true});
        log('hap Bridge listening on port', config.port);

        console.log('\nScan this code with your HomeKit app on your iOS device to pair with homekit2mqtt:');
        qrcode.generate(bridge.setupURI());
        console.log('Or enter this code with your HomeKit app on your iOS device to pair with homekit2mqtt:');
        console.log(chalk.black.bgWhite('                       '));
        console.log(chalk.black.bgWhite('    ┌────────────┐     '));
        console.log(chalk.black.bgWhite('    │ ' + config.pincode + ' │     '));
        console.log(chalk.black.bgWhite('    └────────────┘     '));
        console.log(chalk.black.bgWhite('                       '));
        console.log('');
    });

    bridge._server.on('pair', username => {
        log('hap paired', username);
    });

    /* istanbul ignore next */
    bridge._server.on('unpair', username => {
        log('hap unpaired', username);
    });

    /* istanbul ignore next */
    bridge._server.on('verify', () => {
        log('hap verify');
    });
}

function saveMapping() {
    fs.writeFileSync(config.mapfile, JSON.stringify(mapping, null, '  '));
    log.info('saved config to', config.mapfile);
}

let isStarted = false;

function start() {
    if (isStarted) {
        log.error('already started');
        return;
    }
    isStarted = true;
    log.debug('mqtt unsubscribe #');
    mqtt.unsubscribe('#');
    createBridge();
}

if (config.disableWeb) {
    createBridge();
} else {
    // Get all retained messages (used for autocomplete in web ui)
    log.debug('mqtt subscribe #');
    mqtt.subscribe('#');
    let retainTimeout = setTimeout(start, 1000);
    mqtt.on('message', (topic, payload, msg) => {
        if (isStarted) {
            return;
        }
        if (msg.retain) {
            clearTimeout(retainTimeout);
            retainTimeout = setTimeout(start, 1000);
        }
        if (topics.indexOf(topic) === -1 && topic !== config.name + '/connected') {
            topics.push(topic);
        }
    });

    app.listen(config.webPort, () => {
        log.info('http server listening on port', config.webPort);
    });

    app.use(basicAuth({
        users: {homekit: config.pincode},
        challenge: true,
        realm: 'homekit2mqtt ui'
    }));

    app.get('/', (req, res) => {
        res.redirect(301, '/ui');
    });
    app.use('/ui', express.static(path.join(__dirname, '/ui')));
    app.use('/node_modules', express.static(path.join(__dirname, '/node_modules')));
    app.use('/services.json', express.static(path.join(__dirname, '/services.json')));

    app.get('/topics', (req, res) => {
        log.info('http > topics');
        res.send(JSON.stringify(topics));
    });

    app.get('/config', (req, res) => {
        log.info('http > config');
        res.send(JSON.stringify(mapping));
    });

    app.post('/config', bodyParser.json(), (req, res) => {
        log.info('http < config');
        mapping = req.body;
        saveMapping();
        res.send('ok');
    });

    app.get('/quit', (req, res) => {
        log.info('http < quit');
        res.send('ok');
        setTimeout(() => {
            process.exit(0);
        }, 250);
    });
}
<commit_msg>load file of module without own path logic<commit_after>#!/usr/bin/env node

const fs = require('fs');
const path = require('path');
const Mqtt = require('mqtt');
const chalk = require('chalk');
const qrcode = require('qrcode-terminal');
const express = require('express');
const bodyParser = require('body-parser');
const basicAuth = require('express-basic-auth');

const app = express();

const log = require('yalm');
const HAP = require('hap-nodejs');
const pkgHap = require('hap-nodejs/package.json');
const pkg = require('./package.json');
const config = require('./config.js');

log.setLevel(config.verbosity);

log(pkg.name + ' ' + pkg.version + ' starting');

const mqttStatus = {}; // Holds the payloads of the last-received message, keys are the topics.
const mqttCallbacks = {}; // Holds arrays of subscription callbacks, keys are the topics.
let mqttConnected;

let bridgeListening;
const topics = [];

log.info('mqtt trying to connect', config.url);
const mqtt = Mqtt.connect(config.url, {
    will: {topic: config.name + '/connected', payload: '0', retain: true},
    rejectUnauthorized: !config.insecure
});

mqtt.on('connect', () => {
    mqttConnected = true;
    log.info('mqtt connected ' + config.url);
    /* istanbul ignore if */
    if (!bridgeListening) {
        mqttPub(config.name + '/connected', '1', {retain: true});
    }
});

/* istanbul ignore next */
mqtt.on('reconnect', () => {
    log.info('mqtt reconnect');
});

/* istanbul ignore next */
mqtt.on('offline', () => {
    log.info('mqtt offline');
});

/* istanbul ignore next */
mqtt.on('close', () => {
    if (mqttConnected) {
        mqttConnected = false;
        log.info('mqtt closed ' + config.url);
    }
});

/* istanbul ignore next */
mqtt.on('error', err => {
    log.error('mqtt error ' + err);
});

function typeGuess(payload) {
    let state;
    // Nasty type guessing.
    // TODO clarify Do we really want/need to cast the strings "true" and "false" to bool? https://github.com/hobbyquaker/homekit2mqtt/issues/66
    if (payload === 'true') {
        state = true;
    } else if (payload === 'false') {
        state = false;
    } else if (isNaN(payload)) {
        state = payload;
    } else {
        state = parseFloat(payload);
    }
    return state;
}

// MQTT subscribe function that provides a callback on incoming messages.
// Not meant to be used with wildcards!
function mqttSub(topic, /* string, optional, default "val" */ attr, callback) {
    topic = String(topic);
    if (topic === '') {
        log.error('trying to subscribe empty topic');
        return;
    }
    if (typeof attr === 'function') {
        callback = attr;
        attr = 'val';
    } else if (typeof attr === 'undefined' || attr === '') {
        attr = 'val';
    } else {
        attr = String(attr);
    }
    /* istanbul ignore else */
    if (typeof callback === 'function') {
        /* istanbul ignore if */
        if (mqttCallbacks[topic]) {
            mqttCallbacks[topic].push({attr, callback});
        } else {
            mqttCallbacks[topic] = [{attr, callback}];
            log.debug('mqtt subscribe', topic);
            mqtt.subscribe(topic);
        }
    } else {
        log.debug('mqtt subscribe', topic);
        mqtt.subscribe(topic);
    }
}

// MQTT publish function, checks for valid topic and converts payload to string in a meaningful manner.
function mqttPub(topic, payload, options) {
    /* istanbul ignore if */
    if (!topic || (typeof topic !== 'string')) {
        log.error('mqttPub invalid topic', topic);
    } else {
        /* istanbul ignore if */
        if (typeof payload === 'object') {
            payload = JSON.stringify(payload);
        } else if (typeof payload === 'undefined') {
            payload = '';
        } else if (typeof payload !== 'string') {
            payload = String(payload);
        }
        log.debug('> mqtt', topic, payload);
        mqtt.publish(topic, payload, options, err => {
            /* istanbul ignore next */
            if (err) {
                log.error('mqtt publish error ' + err);
            }
        });
    }
}

log.info('using hap-nodejs version', pkgHap.version);

const {uuid, Bridge, Accessory, Service, Characteristic} = HAP;

/* istanbul ignore next */
if (config.storagedir) {
    log.info('using directory ' + config.storagedir + ' for persistent storage');
}
// If storagedir is not set it uses HAP-Nodejs default
// (usually /usr/local/lib/node_modules/homekit2mqtt/node_modules/node-persist/persist)
HAP.init(config.storagedir || undefined);

// Create Bridge which will host all Accessories
const bridge = new Bridge(config.bridgename, uuid.generate(config.bridgename));

// Listen for Bridge identification event
/* istanbul ignore next */
bridge.on('identify', (paired, callback) => {
    log('< hap bridge identify', paired ? '(paired)' : '(unpaired)');
    callback();
});

// Handler for Accessory identification events
/* istanbul ignore next */
function identify(settings, paired, callback) {
    log.debug('< hap identify', settings.name, paired ? '(paired)' : '(unpaired)');
    if (settings.topicIdentify) {
        log.debug('> mqtt', settings.topicIdentify, settings.payloadIdentify);
        mqttPub(settings.topicIdentify, settings.payloadIdentify);
    }
    callback();
}

function newAccessory(settings) {
    log.debug('creating new accessory', '"' + settings.name + '"', '"' + settings.id + '"', uuid.generate(settings.id));
    const acc = new Accessory(settings.name, uuid.generate(settings.id));
    if (settings.manufacturer || settings.model || settings.serial) {
        acc.getService(Service.AccessoryInformation)
            .setCharacteristic(Characteristic.Manufacturer, settings.manufacturer || '-')
            .setCharacteristic(Characteristic.Model, settings.model || '-')
            .setCharacteristic(Characteristic.SerialNumber, settings.serial || '-');
    }
    if (!settings.payload) {
        settings.payload = {};
    }
    if (!settings.config) {
        settings.config = {};
    }
    /* istanbul ignore next */
    acc.on('identify', (paired, callback) => {
        identify(settings, paired, callback);
    });
    return acc;
}

const addService = {};

function loadService(service) {
    const file = 'services/' + service + '.js';
    log.debug('loading', file);
    addService[service] = require(path.join(__dirname, file))({mqttPub, mqttSub, mqttStatus, log, Service, Characteristic});
}

let mapping;
let accCount;

/* Convert old config file schema to keep compatiblity */
function convertMapping() {
    let isConverted;
    Object.keys(mapping).forEach(id => {
        const accConfig = mapping[id];

        if (!accConfig.services) {
            accConfig.services = [];
            isConverted = true;
        }

        if (accConfig.topic && accConfig.topic.identify) {
            accConfig.topicIdentify = accConfig.topic.identify;
            delete accConfig.topic.identify;
            isConverted = true;
        }
        if (accConfig.payload && accConfig.payload.identify) {
            accConfig.payloadIdentify = accConfig.payload.identify;
            delete accConfig.payload.identify;
            isConverted = true;
        }

        if (accConfig.service) {
            accConfig.services.unshift({
                name: accConfig.name,
                service: accConfig.service,
                topic: accConfig.topic || {},
                payload: accConfig.payload || {},
                config: accConfig.config || {},
                props: accConfig.props || {}
            });
            delete accConfig.service;
            delete accConfig.topic;
            delete accConfig.payload;
            delete accConfig.config;
            delete accConfig.props;
            isConverted = true;
        }
    });
    if (isConverted) {
        log.info('mapping file converted');
        saveMapping();
    }
}

function createBridge() {
    mqtt.on('message', (topic, payload) => {
        payload = payload.toString();
        let state;
        if (payload.indexOf('{') === -1 || config.disableJsonParse) {
            state = typeGuess(payload);
        } else {
            try {
                // We got an Object - let's hope it follows mqtt-smarthome architecture and has an attribute "val"
                // see https://github.com/mqtt-smarthome/mqtt-smarthome/blob/master/Architecture.md
                // TODO make attribute configurable to support non-mqtt-smarthome json payloads https://github.com/hobbyquaker/homekit2mqtt/issues/67
                // the attibute configuration has to be part of the service settings
                state = JSON.parse(payload).val;
                if (typeof state === 'undefined') {
                    // :-( attribute does not exist
                    throw new TypeError('attribute val undefined');
                }
            } catch (err) {
                state = typeGuess(payload);
            }
        }

        log.debug('< mqtt', topic, state, payload);
        // TODO take care when mqttStatus is used on hap get, these have to handle the attribute themselfes https://github.com/hobbyquaker/homekit2mqtt/issues/67
        mqttStatus[topic] = state;
        /* istanbul ignore else */
        if (mqttCallbacks[topic]) {
            mqttCallbacks[topic].forEach(obj => {
                const {attr, callback} = obj; // eslint-disable-line no-unused-vars
                if (typeof callback === 'function') {
                    // TODO make attribute configurable to support non-mqtt-smarthome json payloads https://github.com/hobbyquaker/homekit2mqtt/issues/67
                    callback(state);
                }
            });
        }
        // Topics array Used for autocomplete in web ui)
        if (topics.indexOf(topic) === -1 && topic !== config.name + '/connected') {
            topics.push(topic);
        }
    });

    // Load and create all accessories
    log.info('loading HomeKit to MQTT mapping file ' + config.mapfile);
    mapping = require(config.mapfile);
    convertMapping();
    accCount = 0;
    Object.keys(mapping).forEach(id => {
        const accConfig = mapping[id];
        accConfig.id = id;
        const acc = newAccessory(accConfig);

        accConfig.services.forEach((s, i) => {
            if (!addService[s.service]) {
                loadService(s.service);
            }
            log.debug('adding service', s.service, 'to accessory', accConfig.name);
            addService[s.service](acc, s, String(i));
        });

        log.debug('addBridgedAccessory ' + accConfig.name);
        bridge.addBridgedAccessory(acc);
        accCount++;
    });
    log.info('hap created', accCount, 'Accessories');

    bridge.publish({
        username: config.username,
        port: config.port,
        pincode: config.c,
        category: Accessory.Categories.OTHER
    });
    log('hap publishing bridge "' + config.bridgename + '" username=' + config.username, 'port=' + config.port,
        'pincode=' + config.c, 'setupURI=' + bridge.setupURI());

    bridge._server.on('listening', () => {
        bridgeListening = true;
        mqttPub(config.name + '/connected', '2', {retain: true});
        log('hap Bridge listening on port', config.port);

        console.log('\nScan this code with your HomeKit app on your iOS device to pair with homekit2mqtt:');
        qrcode.generate(bridge.setupURI());
        console.log('Or enter this code with your HomeKit app on your iOS device to pair with homekit2mqtt:');
        console.log(chalk.black.bgWhite('                       '));
        console.log(chalk.black.bgWhite('    ┌────────────┐     '));
        console.log(chalk.black.bgWhite('    │ ' + config.pincode + ' │     '));
        console.log(chalk.black.bgWhite('    └────────────┘     '));
        console.log(chalk.black.bgWhite('                       '));
        console.log('');
    });

    bridge._server.on('pair', username => {
        log('hap paired', username);
    });

    /* istanbul ignore next */
    bridge._server.on('unpair', username => {
        log('hap unpaired', username);
    });

    /* istanbul ignore next */
    bridge._server.on('verify', () => {
        log('hap verify');
    });
}

function saveMapping() {
    fs.writeFileSync(config.mapfile, JSON.stringify(mapping, null, '  '));
    log.info('saved config to', config.mapfile);
}

let isStarted = false;

function start() {
    if (isStarted) {
        log.error('already started');
        return;
    }
    isStarted = true;
    log.debug('mqtt unsubscribe #');
    mqtt.unsubscribe('#');
    createBridge();
}

if (config.disableWeb) {
    createBridge();
} else {
    // Get all retained messages (used for autocomplete in web ui)
    log.debug('mqtt subscribe #');
    mqtt.subscribe('#');
    let retainTimeout = setTimeout(start, 1000);
    mqtt.on('message', (topic, payload, msg) => {
        if (isStarted) {
            return;
        }
        if (msg.retain) {
            clearTimeout(retainTimeout);
            retainTimeout = setTimeout(start, 1000);
        }
        if (topics.indexOf(topic) === -1 && topic !== config.name + '/connected') {
            topics.push(topic);
        }
    });

    app.listen(config.webPort, () => {
        log.info('http server listening on port', config.webPort);
    });

    app.use(basicAuth({
        users: {homekit: config.pincode},
        challenge: true,
        realm: 'homekit2mqtt ui'
    }));

    app.get('/', (req, res) => {
        res.redirect(301, '/ui');
    });
    app.use('/ui', express.static(path.join(__dirname, '/ui')));
    app.use('/node_modules', express.static(path.join(__dirname, '/node_modules')));
    app.use('/services.json', express.static(path.join(__dirname, '/services.json')));

    app.get('/topics', (req, res) => {
        log.info('http > topics');
        res.send(JSON.stringify(topics));
    });

    app.get('/config', (req, res) => {
        log.info('http > config');
        res.send(JSON.stringify(mapping));
    });

    app.post('/config', bodyParser.json(), (req, res) => {
        log.info('http < config');
        mapping = req.body;
        saveMapping();
        res.send('ok');
    });

    app.get('/quit', (req, res) => {
        log.info('http < quit');
        res.send('ok');
        setTimeout(() => {
            process.exit(0);
        }, 250);
    });
}
<|endoftext|>


<commit_before>#! /usr/bin/env node

'use strict'

const client = require('./client')
const fs = require('fs')
const pkg = require('./package.json')
const program = require('commander')
const startJackal = require('./lib')

const generateCallback = client.generateCallback
const run = client.run
const send = client.send
const getStats = client.getStats

program
  .version(pkg.version)

program
  .command('start [configPath]')
  .description('Start the Jackal microservice using the specified config file')
  .action(function (configPath) {
    let config

    if (configPath) {
      const buffer = fs.readFileSync(configPath)
      config = JSON.parse(buffer.toString())
    } else {
      config = {
        logger: { environment: 'production' },
        statsD: { host: 'localhost', port: 8125, prefix: 'jackal' }
      }
    }

    startJackal(config)
  })

program
  .command('send <contractsPath> <jackalUrl>')
  .description('Send the consumer\'s contracts in the specified file to the Jackal service at the specified URL')
  .action(function (contractsPath, jackalUrl) {
    send(contractsPath, jackalUrl, generateCallback(201))
  })

program
  .command('run <jackalUrl>')
  .description('Runs the provider\'s contracts stored in the database of the Jackal service at the specified URL')
  .action(function (jackalUrl) {
    run(jackalUrl, generateCallback(200))
  })

program
  .command('stats <jackalUrl>')
  .description('Gets usage stats from the running Jackal service at the specified URL')
  .action(function (jackalUrl) {
    getStats(jackalUrl)
  })

program
  .parse(process.argv)
<commit_msg>Commenting out stats command in project root file until functionality can be completed<commit_after>#! /usr/bin/env node

'use strict'

const client = require('./client')
const fs = require('fs')
const pkg = require('./package.json')
const program = require('commander')
const startJackal = require('./lib')

const generateCallback = client.generateCallback
const run = client.run
const send = client.send
const getStats = client.getStats

program
  .version(pkg.version)

program
  .command('start [configPath]')
  .description('Start the Jackal microservice using the specified config file')
  .action(function (configPath) {
    let config

    if (configPath) {
      const buffer = fs.readFileSync(configPath)
      config = JSON.parse(buffer.toString())
    } else {
      config = {
        logger: { environment: 'production' },
        statsD: { host: 'localhost', port: 8125, prefix: 'jackal' }
      }
    }

    startJackal(config)
  })

program
  .command('send <contractsPath> <jackalUrl>')
  .description('Send the consumer\'s contracts in the specified file to the Jackal service at the specified URL')
  .action(function (contractsPath, jackalUrl) {
    send(contractsPath, jackalUrl, generateCallback(201))
  })

program
  .command('run <jackalUrl>')
  .description('Runs the provider\'s contracts stored in the database of the Jackal service at the specified URL')
  .action(function (jackalUrl) {
    run(jackalUrl, generateCallback(200))
  })

// program
//   .command('stats <jackalUrl>')
//   .description('Gets usage stats from the running Jackal service at the specified URL')
//   .action(function (jackalUrl) {
//     getStats(jackalUrl)
//   })

program
  .parse(process.argv)
<|endoftext|>


<commit_before>'use strict';

Object.defineProperty(exports, "__esModule", {
    value: true
});

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _CoreStore = require('focus-core/store/CoreStore');

var _CoreStore2 = _interopRequireDefault(_CoreStore);

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

var _storeLine = require('./components/store-line');

var _storeLine2 = _interopRequireDefault(_storeLine);

var _config = require('./components/config');

var _config2 = _interopRequireDefault(_config);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

exports.default = _react2.default.createClass({
    displayName: 'customDevTools',

    getInitialState: function getInitialState() {
        return {
            isExpanded: false,
            storeArray: [],
            showContact: false,
            filterTextValue: '',
            searchBarExpanded: false,
            cssDisplay: 'none',
            displayOptions: false
        };
    },
    componentDidMount: function componentDidMount() {
        window.addEventListener('keydown', this.handleKeyDown);
    },
    componentWillUnmount: function componentWillUnmount() {
        window.removeEventListener('keydown', this.handleKeyDown);
    },
    handleKeyDown: function handleKeyDown(e) {
        // Ignore regular keys when focused on a field
        // and no modifiers are active.
        if (!e.ctrlKey && !e.metaKey && !e.altKey && (e.target.tagName === 'INPUT' || e.target.tagName === 'SELECT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable)) {
            return;
        }
        var charCode = e.keyCode || e.which;
        var char = String.fromCharCode(charCode);
        if (charCode === 77 && e.ctrlKey) {
            this.toggleVisibility();
        }
    },
    toggleVisibility: function toggleVisibility() {
        this.setState({
            cssDisplay: this.state.cssDisplay === 'inline' ? 'none' : 'inline'
        });
    },
    processAllStores: function processAllStores() {
        var allStores = _CoreStore2.default.prototype._instances;
        var metierStoreArray = [];
        var otherArray = [];
        for (var i = 0; i < allStores.length; i++) {
            switch (Object.getPrototypeOf(allStores[i]).constructor.name) {
                case 'CoreStore':
                case 'ListStore':
                    metierStoreArray.push(allStores[i]);
                    break;
                default:
                    otherArray.push(allStores[i]);
                    break;
            }
        }
        this.processMetierStoreArray(metierStoreArray);
    },
    processMetierStoreArray: function processMetierStoreArray(metierStoreArray) {
        var storeArray = [];
        for (var i = 0; i < metierStoreArray.length; i++) {
            switch (Object.getPrototypeOf(metierStoreArray[i]).constructor.name) {
                case 'CoreStore':
                    for (var property in metierStoreArray[i].definition) {
                        if (metierStoreArray[i].definition.hasOwnProperty(property)) {
                            var getMethodName = 'get' + property[0].toUpperCase() + property.slice(1);
                            if (metierStoreArray[i][getMethodName]() !== undefined) {
                                var storeObject = {};
                                storeObject.name = metierStoreArray[i].definition[property];
                                storeObject.value = metierStoreArray[i][getMethodName]();
                                storeObject.type = 'CoreStore';
                                if (metierStoreArray[i].status.get(storeObject.name)) {
                                    storeObject.status = metierStoreArray[i].status.get(storeObject.name).name;
                                }
                                storeArray.push(storeObject);
                            }
                        }
                    }
                    break;
                case 'ListStore':
                    if (metierStoreArray[i].getDataList() !== undefined) {
                        var listStoreObject = {};
                        listStoreObject.value = {};
                        listStoreObject.value.criteria = metierStoreArray[i].getCriteria();
                        listStoreObject.value.data = metierStoreArray[i].getDataList();
                        listStoreObject.name = metierStoreArray[i].config.identifier;
                        listStoreObject.type = 'ListStore';
                        storeArray.push(listStoreObject);
                    }
                    break;
                default:
                    break;
            }
        }
        storeArray = _.sortBy(storeArray, function (o) {
            return o.name;
        });
        if (this.state.filterTextValue.length > 0) {
            var filteredStoreArray = _.filter(storeArray, function (o) {
                return o.name.toUpperCase().includes(x.target.value.toUpperCase());
            });
            this.setState({
                storeArray: storeArray,
                filteredStoreArray: filteredStoreArray
            });
        } else {
            this.setState({
                storeArray: storeArray,
                filteredStoreArray: storeArray
            });
        }
    },
    getClassName: function getClassName() {
        return this.state.isExpanded ? 'customDevTools-expanded' : 'customDevTools';
    },
    handleCollapse: function handleCollapse() {
        this.setState({
            isExpanded: !this.state.isExpanded
        });
    },
    getIconClassName: function getIconClassName() {
        return this.state.isExpanded ? 'customDevTools-button-expand' : 'customDevTools-button-collapse';
    },
    displayCoreStoreList: function displayCoreStoreList() {
        return _.map(this.state.filteredStoreArray, function (store) {
            return _react2.default.createElement(_storeLine2.default, { store: store });
        });
    },
    handleFilterChange: function handleFilterChange(x) {
        var filteredStoreArray = _.filter(this.state.storeArray, function (o) {
            return o.name.toUpperCase().includes(x.target.value.toUpperCase());
        });
        this.setState({
            filterTextValue: x.target.value,
            filteredStoreArray: filteredStoreArray
        });
    },
    toggleSearchBar: function toggleSearchBar() {
        if (this.state.searchBarExpanded) {
            this.setState({
                searchBarExpanded: !this.state.searchBarExpanded,
                filterTextValue: ''
            }, this.processAllStores);
        } else {
            this.setState({
                searchBarExpanded: true
            });
        }
    },
    toggleOptions: function toggleOptions() {
        this.setState({
            displayOptions: !this.state.displayOptions
        });
    },

    // getConfig(){
    //     return this.refs['mdap-config'].getOptionsValues();
    // },

    render: function render() {
        return _react2.default.createElement(
            'div',
            { className: this.getClassName(), style: { display: this.state.cssDisplay } },
            this.state.isExpanded && _react2.default.createElement('br', null),
            this.state.isExpanded && _react2.default.createElement('div', { onClick: this.processAllStores, className: 'reloadDouble' }),
            _react2.default.createElement(
                'div',
                { className: 'submit cursor-pointer mb20 button-minimize-container' },
                this.state.isExpanded && _react2.default.createElement(
                    'div',
                    null,
                    _react2.default.createElement('div', { onClick: this.toggleOptions, className: 'icon-gear' }),
                    _react2.default.createElement('div', { onClick: this.toggleSearchBar, className: 'searchButton' })
                ),
                _react2.default.createElement(
                    'div',
                    { className: 'collapse-button-container', onClick: this.handleCollapse },
                    _react2.default.createElement('div', { className: this.getIconClassName() })
                )
            ),
            !this.state.isExpanded && _react2.default.createElement(
                'div',
                { className: 'devToolTitle' },
                _react2.default.createElement(
                    'b',
                    null,
                    'CustomDevTools'
                )
            ),
            this.state.searchBarExpanded && _react2.default.createElement(
                'form',
                { className: 'searchInputContainer', onSubmit: function onSubmit(e) {
                        e.preventDefault();
                    } },
                _react2.default.createElement('input', { className: 'searchInput', type: 'text', value: this.state.filterTextValue, name: 'storeNameFilter', onChange: this.handleFilterChange, placeholder: 'store...', autoComplete: 'off' })
            ),
            _react2.default.createElement(
                'div',
                { className: 'customDevToolsContent' },
                this.state.displayOptions ? _react2.default.createElement(_config2.default, { ref: 'mdap-config' }) : this.displayCoreStoreList()
            )
        );
    }
});
module.exports = exports['default'];<commit_msg>Opt hidden<commit_after>'use strict';

Object.defineProperty(exports, "__esModule", {
    value: true
});

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _CoreStore = require('focus-core/store/CoreStore');

var _CoreStore2 = _interopRequireDefault(_CoreStore);

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

var _storeLine = require('./components/store-line');

var _storeLine2 = _interopRequireDefault(_storeLine);

var _config = require('./components/config');

var _config2 = _interopRequireDefault(_config);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

exports.default = _react2.default.createClass({
    displayName: 'customDevTools',

    getInitialState: function getInitialState() {
        return {
            isExpanded: false,
            storeArray: [],
            showContact: false,
            filterTextValue: '',
            searchBarExpanded: false,
            cssDisplay: 'none',
            displayOptions: false
        };
    },
    componentDidMount: function componentDidMount() {
        window.addEventListener('keydown', this.handleKeyDown);
    },
    componentWillUnmount: function componentWillUnmount() {
        window.removeEventListener('keydown', this.handleKeyDown);
    },
    handleKeyDown: function handleKeyDown(e) {
        // Ignore regular keys when focused on a field
        // and no modifiers are active.
        if (!e.ctrlKey && !e.metaKey && !e.altKey && (e.target.tagName === 'INPUT' || e.target.tagName === 'SELECT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable)) {
            return;
        }
        var charCode = e.keyCode || e.which;
        var char = String.fromCharCode(charCode);
        if (charCode === 77 && e.ctrlKey) {
            this.toggleVisibility();
        }
    },
    toggleVisibility: function toggleVisibility() {
        this.setState({
            cssDisplay: this.state.cssDisplay === 'inline' ? 'none' : 'inline'
        });
    },
    processAllStores: function processAllStores() {
        var allStores = _CoreStore2.default.prototype._instances;
        var metierStoreArray = [];
        var otherArray = [];
        for (var i = 0; i < allStores.length; i++) {
            switch (Object.getPrototypeOf(allStores[i]).constructor.name) {
                case 'CoreStore':
                case 'ListStore':
                    metierStoreArray.push(allStores[i]);
                    break;
                default:
                    otherArray.push(allStores[i]);
                    break;
            }
        }
        this.processMetierStoreArray(metierStoreArray);
    },
    processMetierStoreArray: function processMetierStoreArray(metierStoreArray) {
        var storeArray = [];
        for (var i = 0; i < metierStoreArray.length; i++) {
            switch (Object.getPrototypeOf(metierStoreArray[i]).constructor.name) {
                case 'CoreStore':
                    for (var property in metierStoreArray[i].definition) {
                        if (metierStoreArray[i].definition.hasOwnProperty(property)) {
                            var getMethodName = 'get' + property[0].toUpperCase() + property.slice(1);
                            if (metierStoreArray[i][getMethodName]() !== undefined) {
                                var storeObject = {};
                                storeObject.name = metierStoreArray[i].definition[property];
                                storeObject.value = metierStoreArray[i][getMethodName]();
                                storeObject.type = 'CoreStore';
                                if (metierStoreArray[i].status.get(storeObject.name)) {
                                    storeObject.status = metierStoreArray[i].status.get(storeObject.name).name;
                                }
                                storeArray.push(storeObject);
                            }
                        }
                    }
                    break;
                case 'ListStore':
                    if (metierStoreArray[i].getDataList() !== undefined) {
                        var listStoreObject = {};
                        listStoreObject.value = {};
                        listStoreObject.value.criteria = metierStoreArray[i].getCriteria();
                        listStoreObject.value.data = metierStoreArray[i].getDataList();
                        listStoreObject.name = metierStoreArray[i].config.identifier;
                        listStoreObject.type = 'ListStore';
                        storeArray.push(listStoreObject);
                    }
                    break;
                default:
                    break;
            }
        }
        storeArray = _.sortBy(storeArray, function (o) {
            return o.name;
        });
        if (this.state.filterTextValue.length > 0) {
            var filteredStoreArray = _.filter(storeArray, function (o) {
                return o.name.toUpperCase().includes(x.target.value.toUpperCase());
            });
            this.setState({
                storeArray: storeArray,
                filteredStoreArray: filteredStoreArray
            });
        } else {
            this.setState({
                storeArray: storeArray,
                filteredStoreArray: storeArray
            });
        }
    },
    getClassName: function getClassName() {
        return this.state.isExpanded ? 'customDevTools-expanded' : 'customDevTools';
    },
    handleCollapse: function handleCollapse() {
        this.setState({
            isExpanded: !this.state.isExpanded
        });
    },
    getIconClassName: function getIconClassName() {
        return this.state.isExpanded ? 'customDevTools-button-expand' : 'customDevTools-button-collapse';
    },
    displayCoreStoreList: function displayCoreStoreList() {
        return _.map(this.state.filteredStoreArray, function (store) {
            return _react2.default.createElement(_storeLine2.default, { store: store });
        });
    },
    handleFilterChange: function handleFilterChange(x) {
        var filteredStoreArray = _.filter(this.state.storeArray, function (o) {
            return o.name.toUpperCase().includes(x.target.value.toUpperCase());
        });
        this.setState({
            filterTextValue: x.target.value,
            filteredStoreArray: filteredStoreArray
        });
    },
    toggleSearchBar: function toggleSearchBar() {
        if (this.state.searchBarExpanded) {
            this.setState({
                searchBarExpanded: !this.state.searchBarExpanded,
                filterTextValue: ''
            }, this.processAllStores);
        } else {
            this.setState({
                searchBarExpanded: true
            });
        }
    },
    toggleOptions: function toggleOptions() {
        console.log('Wip');
        // this.setState({
        //     displayOptions: !this.state.displayOptions
        // })
    },

    // getConfig(){
    //     return this.refs['mdap-config'].getOptionsValues();
    // },

    render: function render() {
        return _react2.default.createElement(
            'div',
            { className: this.getClassName(), style: { display: this.state.cssDisplay } },
            this.state.isExpanded && _react2.default.createElement('br', null),
            this.state.isExpanded && _react2.default.createElement('div', { onClick: this.processAllStores, className: 'reloadDouble' }),
            _react2.default.createElement(
                'div',
                { className: 'submit cursor-pointer mb20 button-minimize-container' },
                this.state.isExpanded && _react2.default.createElement(
                    'div',
                    null,
                    _react2.default.createElement('div', { onClick: this.toggleOptions, className: 'icon-gear' }),
                    _react2.default.createElement('div', { onClick: this.toggleSearchBar, className: 'searchButton' })
                ),
                _react2.default.createElement(
                    'div',
                    { className: 'collapse-button-container', onClick: this.handleCollapse },
                    _react2.default.createElement('div', { className: this.getIconClassName() })
                )
            ),
            !this.state.isExpanded && _react2.default.createElement(
                'div',
                { className: 'devToolTitle' },
                _react2.default.createElement(
                    'b',
                    null,
                    'CustomDevTools'
                )
            ),
            this.state.searchBarExpanded && _react2.default.createElement(
                'form',
                { className: 'searchInputContainer', onSubmit: function onSubmit(e) {
                        e.preventDefault();
                    } },
                _react2.default.createElement('input', { className: 'searchInput', type: 'text', value: this.state.filterTextValue, name: 'storeNameFilter', onChange: this.handleFilterChange, placeholder: 'store...', autoComplete: 'off' })
            ),
            _react2.default.createElement(
                'div',
                { className: 'customDevToolsContent' },
                this.state.displayOptions ? _react2.default.createElement(_config2.default, { ref: 'mdap-config' }) : this.displayCoreStoreList()
            )
        );
    }
});
module.exports = exports['default'];<|endoftext|>


<commit_before>/**
 * Created by apizzimenti on 1/1/17.
 */

var paramExist = require("./../tools/Globals").paramExist,
    Error = require("./../tools/Error").Error,
    realTime = require("./../tools/Globals").realTime,
    hotCold = require("./../tools/Globals").hotCold,
    tc = require("./../tools/Globals").tableContent,

    chalk = require("chalk"),
    Table = require("cli-table2");

function Output (location, weather, args) {

    var e = new Error("");

    if (paramExist(location, "object")) {
        this.location = location;
    } else {
        e.message = "The location parameter does not exist.";
        e.throw();
        return;
    }

    if (paramExist(weather, "object")) {
        this.weather = weather;
    } else {
        e.message = "The weather parameter does not exist.";
        e.throw();
        return;
    }

    if (paramExist(args, "object")) {
        this.args = args;
    } else {
        e.message = "The args parameter does not exist.";
        e.throw();
        return;
    }

    this.currently = this.weather.currently;
    this.daily = this.weather.daily.data.slice(1, this.weather.daily.data.length - 3);
}

Output.prototype.header = function () {

    var city = this.location.city,
        state = this.location.region_name;

    console.log(chalk.underline("\nCurrent conditions for " + city + ", " + state + ":"));
};

Output.prototype.current = function () {

    var c = this.currently,
        summary = c.summary.toLowerCase(),
        feels = hotCold(Math.round(c.apparentTemperature), this.args.c || this.args.celsius),
        temp = hotCold(Math.round(c.temperature), this.args.c || this.args.celsius),
        wind = Math.round(c.windSpeed),
        wind_unit = this.args.celsius || this.args.c ? " mps " : " mph ";

    console.log(temp + "° • feels like " + feels + "° • " + wind + wind_unit + "wind • " + summary + "\n");
};

Output.prototype.icons = function () {

    var _this = this;

    this.icons = [];

    this.daily.forEach(function (day) {

        var icon = day.icon;

        switch (icon) {
            case "clear-day":case "clear-night":
                _this.icons.push("☀ clear");
                break;

            case "rain":
                _this.icons.push("☂ rain");
                break;

            case "snow":
                _this.icons.push("❄ snow");
                break;

            case "sleet":
                _this.icons.push("☂❄ sleet");
                break;

            case "wind":
                _this.icons.push("➳ wind");
                break;

            case "fog":
                _this.icons.push("☁ fog");
                break;

            case "partly-cloudy-day":case "partly-cloudy-night":
                _this.icons.push("☁☀ partly cloudy");
                break;

            default:
                _this.icons.push("☁ clouds");
                break;
        }
    });

    for (var i = 0; i < this.icons.length; i++) {
        this.icons[i] = tc(this.icons[i]);
    }
};

Output.prototype.data = function () {

    var _this = this,
        temps = "";

    this.days = [];
    this.temps = [];
    this.precip = [];
    this.sunrise = [];
    this.sunset = [];

    this.daily.forEach(function (day) {

        _this.days.push(tc(new Date(day.time * 1000).toDateString()));

        temps = chalk.bold(hotCold(Math.round(day.temperatureMax), _this.args.c || _this.args.celsius)) + "° " + chalk.dim(hotCold(Math.round(day.temperatureMin), _this.args.c || _this.args.celsius)) + "°";
        _this.temps.push(tc(temps));

        _this.precip.push(tc(Math.round(day.precipProbability * 100, 2) + "% chance precip"));
        _this.sunrise.push(tc(chalk.yellow("☀") + " " + realTime(day.sunriseTime)));
        _this.sunset.push(tc(chalk.blue("☾") + " " + realTime(day.sunsetTime)));
    });
};

Output.prototype.print = function () {

    this.header();
    this.current();

    this.icons();
    this.data();

    var _this = this,
        table = new Table(
            {
                colWidths: [20, 20, 20, 20],
                head: this.days,
                chars: {
                    'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''
                },
                style: {
                    head: ["bold"],
                    align: ["center"]
                }
            }
        );

    table.push(
        _this.temps,
        _this.icons,
        _this.precip,
        _this.sunrise,
        _this.sunset
    );

    console.log(table.toString());
};

module.exports = {
    Output: Output
};
<commit_msg>redo args<commit_after>/**
 * Created by apizzimenti on 1/1/17.
 */

var paramExist = require("./../tools/Globals").paramExist,
    Error = require("./../tools/Error").Error,
    realTime = require("./../tools/Globals").realTime,
    hotCold = require("./../tools/Globals").hotCold,
    tc = require("./../tools/Globals").tableContent,

    chalk = require("chalk"),
    Table = require("cli-table2");

function Output (location, weather, args) {

    var e = new Error("");

    if (paramExist(location, "object")) {
        this.location = location;
    } else {
        e.message = "The location parameter does not exist.";
        e.throw();
        return;
    }

    if (paramExist(weather, "object")) {
        this.weather = weather;
    } else {
        e.message = "The weather parameter does not exist.";
        e.throw();
        return;
    }

    if (paramExist(args, "object")) {
        this.args = args;
    } else {
        e.message = "The args parameter does not exist.";
        e.throw();
        return;
    }

    this.currently = this.weather.currently;
    this.daily = this.weather.daily.data.slice(1, this.weather.daily.data.length - 3);
}

Output.prototype.header = function () {

    var city = this.location.city,
        state = this.location.region_name;

    console.log(chalk.underline("\nCurrent conditions for " + city + ", " + state + ":"));
};

Output.prototype.current = function () {

    var c = this.currently,
        summary = c.summary.toLowerCase(),
        feels = hotCold(Math.round(c.apparentTemperature), this.args.get("celsius")),
        temp = hotCold(Math.round(c.temperature), this.args.get("celsius")),
        wind = Math.round(c.windSpeed),
        wind_unit = this.args.celsius || this.args.c ? " mps " : " mph ";

    console.log(temp + "° • feels like " + feels + "° • " + wind + wind_unit + "wind • " + summary + "\n");
};

Output.prototype.icons = function () {

    var _this = this;

    this.icons = [];

    this.daily.forEach(function (day) {

        var icon = day.icon;

        switch (icon) {
            case "clear-day":case "clear-night":
                _this.icons.push("☀ clear");
                break;

            case "rain":
                _this.icons.push("☂ rain");
                break;

            case "snow":
                _this.icons.push("❄ snow");
                break;

            case "sleet":
                _this.icons.push("☂❄ sleet");
                break;

            case "wind":
                _this.icons.push("➳ wind");
                break;

            case "fog":
                _this.icons.push("☁ fog");
                break;

            case "partly-cloudy-day":case "partly-cloudy-night":
                _this.icons.push("☁☀ partly cloudy");
                break;

            default:
                _this.icons.push("☁ clouds");
                break;
        }
    });

    for (var i = 0; i < this.icons.length; i++) {
        this.icons[i] = tc(this.icons[i]);
    }
};

Output.prototype.data = function () {

    var _this = this,
        temps = "";

    this.days = [];
    this.temps = [];
    this.precip = [];
    this.sunrise = [];
    this.sunset = [];

    this.daily.forEach(function (day) {

        _this.days.push(tc(new Date(day.time * 1000).toDateString()));

        temps = chalk.bold(hotCold(Math.round(day.temperatureMax), _this.args.get("celsius"))) + "° " + chalk.dim(hotCold(Math.round(day.temperatureMin), _this.args.get("celsius"))) + "°";
        _this.temps.push(tc(temps));

        _this.precip.push(tc(Math.round(day.precipProbability * 100, 2) + "% chance precip"));
        _this.sunrise.push(tc(chalk.yellow("☀") + " " + realTime(day.sunriseTime)));
        _this.sunset.push(tc(chalk.blue("☾") + " " + realTime(day.sunsetTime)));
    });
};

Output.prototype.print = function () {

    this.header();
    this.current();

    this.icons();
    this.data();

    var _this = this,
        table = new Table(
            {
                colWidths: [20, 20, 20, 20],
                head: this.days,
                chars: {
                    'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''
                },
                style: {
                    head: ["bold"],
                    align: ["center"]
                }
            }
        );

    table.push(
        _this.temps,
        _this.icons,
        _this.precip,
        _this.sunrise,
        _this.sunset
    );

    console.log(table.toString());
};

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


<commit_before>/*!
 * pretty-remarkable <https://github.com/jonschlinkert/pretty-remarkable>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */

'use strict';

/**
 * Local dependencies
 */

var rules = require('./lib/rules');

/**
 * Register as a plugin by passing `prettify` to remarkable's
 * `.use()` method.
 *
 * ```js
 * var md = new Remarkable();
 * md.use(prettify);
 * var result = md.render(str);
 * ```
 *
 * @param {Object} `options`
 * @return {String}
 */

function prettify(md) {
  md.renderer.renderInline = function(tokens, options, env) {
    var _rules = rules;
    var len = tokens.length, i = 0;
    var str = '';

    while (len--) {
      str += _rules[tokens[i].type](tokens, i++, options, env, this);
    }
    return str;
  };

  md.renderer.render = function(tokens, options, env) {
    var _rules = rules;
    var len = tokens.length, i = -1;
    var str = '';

    while (++i < len) {
      if (tokens[i].type === 'inline') {
        str += this.renderInline(tokens[i].children, options, env);
      } else {
        str += _rules[tokens[i].type](tokens, i, options, env, this);
      }
    }
    str = str.split(/(?:\r\n|\n){2,}/).join('\n\n');
    str = str.trim() + (options.newline ? '\n' : '');
    return str;
  };
}

/**
 * expose `prettify`
 */

module.exports = prettify;
<commit_msg>make newline condensing optional<commit_after>/*!
 * pretty-remarkable <https://github.com/jonschlinkert/pretty-remarkable>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT License.
 */

'use strict';

/**
 * Local dependencies
 */

var rules = require('./lib/rules');

/**
 * Register as a plugin by passing `prettify` to remarkable's
 * `.use()` method.
 *
 * ```js
 * var md = new Remarkable();
 * md.use(prettify);
 * var result = md.render(str);
 * ```
 *
 * @param {Object} `options`
 * @return {String}
 */

function prettify(md) {
  md.renderer.renderInline = function(tokens, options, env) {
    var _rules = rules;
    var len = tokens.length, i = 0;
    var str = '';

    while (len--) {
      str += _rules[tokens[i].type](tokens, i++, options, env, this);
    }
    return str;
  };

  md.renderer.render = function(tokens, options, env) {
    var _rules = rules;
    var len = tokens.length, i = -1;
    var str = '';

    while (++i < len) {
      if (tokens[i].type === 'inline') {
        str += this.renderInline(tokens[i].children, options, env);
      } else {
        str += _rules[tokens[i].type](tokens, i, options, env, this);
      }
    }

    if (options.condense !== false) {
      str = str.split(/(?:\r\n|\n){2,}/).join('\n\n');
    }
    str = str.trim() + (options.newline ? '\n' : '');
    return str;
  };
}

/**
 * expose `prettify`
 */

module.exports = prettify;
<|endoftext|>


<commit_before>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

var service=require('cordova/plugin/webos/service'),
    cordova = require('cordova');

module.exports = {
    id: "webos",
    initialize: function() {
        if (window.PalmSystem) {
            window.PalmSystem.stageReady();
        }

        var Mojo = window.Mojo || {};

        // wait for deviceready before listening and firing document events
        document.addEventListener("deviceready", function () {

            // LunaSysMgr calls this when the windows is maximized or opened.
            window.Mojo.stageActivated = function() {
                console.log("stageActivated");
                cordova.fireDocumentEvent("resume");
            };
            // LunaSysMgr calls this when the windows is minimized or closed.
            window.Mojo.stageDeactivated = function() {
                console.log("stageDeactivated");
                cordova.fireDocumentEvent("pause");
            };
            // LunaSysMgr calls this when a KeepAlive app's window is hidden
            window.Mojo.hide = function() {
                console.log("hide");
            };
            // LunaSysMgr calls this when a KeepAlive app's window is shown
            window.Mojo.show = function() {
                console.log("show");
            };

            // LunaSysMgr calls this whenever an app is "launched;"
            window.Mojo.relaunch = function() {
                // need to return true to tell sysmgr the relaunch succeeded.
                // otherwise, it'll try to focus the app, which will focus the first
                // opened window of an app with multiple windows.

                var lp=JSON.parse(PalmSystem.launchParams) || {};

                if (lp['palm-command'] && lp['palm-command'] == 'open-app-menu') {
                    console.log("event:ToggleAppMenu");
                    cordova.fireDocumentEvent("menubutton");
                }

                console.log("relaunch");
                return true;
            };

            // start to listen for network connection changes
            service.Request('palm://com.palm.connectionmanager', {
                method: 'getstatus',
                parameters: { subscribe: true },
                onSuccess: function (result) {
                    console.log("subscribe:result:"+JSON.stringify(result));

                    if (!result.isInternetConnectionAvailable) {
                        if (navigator.onLine) {
                            console.log("Firing event:offline");
                            cordova.fireDocumentEvent("offline");
                        }
                    } else {
                        console.log("Firing event:online");
                        cordova.fireDocumentEvent("online");
                    }
                },
                onFailure: function(e) {
                    console.error("subscribe:error");
                }
            });

        });
    },
    clobbers: {
        requestFileSystem:{
            path: 'cordova/plugin/webos/requestfilesystem'
        },
        FileReader: {
            path: "cordova/plugin/webos/filereader"
        }
    },
    merges: {
        navigator: {
            children: {
                service: {
                    path: "cordova/plugin/webos/service"
                },
                application: {
                    path: "cordova/plugin/webos/application"
                },
                window: {
                    path: "cordova/plugin/webos/window"
                },
                notification: {
                    path: "cordova/plugin/webos/notification"
                },
                orientation: {
                    path: "cordova/plugin/webos/orientation"
                },
                keyboard: {
                    path: "cordova/plugin/webos/keyboard"
                }
            }
        }
    }
};
<commit_msg>Added support for the back-gesture (mapped to backbutton)<commit_after>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

var service=require('cordova/plugin/webos/service'),
    cordova = require('cordova');

module.exports = {
    id: "webos",
    initialize: function() {
        if (window.PalmSystem) {
            window.PalmSystem.stageReady();
        }

        var Mojo = window.Mojo || {};

        // wait for deviceready before listening and firing document events
        document.addEventListener("deviceready", function () {

            // LunaSysMgr calls this when the windows is maximized or opened.
            window.Mojo.stageActivated = function() {
                console.log("stageActivated");
                cordova.fireDocumentEvent("resume");
            };
            // LunaSysMgr calls this when the windows is minimized or closed.
            window.Mojo.stageDeactivated = function() {
                console.log("stageDeactivated");
                cordova.fireDocumentEvent("pause");
            };
            // LunaSysMgr calls this when a KeepAlive app's window is hidden
            window.Mojo.hide = function() {
                console.log("hide");
            };
            // LunaSysMgr calls this when a KeepAlive app's window is shown
            window.Mojo.show = function() {
                console.log("show");
            };

            // LunaSysMgr calls this whenever an app is "launched;"
            window.Mojo.relaunch = function() {
                // need to return true to tell sysmgr the relaunch succeeded.
                // otherwise, it'll try to focus the app, which will focus the first
                // opened window of an app with multiple windows.

                var lp=JSON.parse(PalmSystem.launchParams) || {};

                if (lp['palm-command'] && lp['palm-command'] == 'open-app-menu') {
                    console.log("event:ToggleAppMenu");
                    cordova.fireDocumentEvent("menubutton");
                }

                console.log("relaunch");
                return true;
            };

            // start listening for keyup events to catch the back-gesture
            document.addEventListener('keyup', function(ev) {
              if (ev.keyIdentifier == "U+1200001" || ev.keyIdentifier == "U+001B" || ev.keyIdentifier =="Back") {
                console.log("Firing event:backbutton");
                cordova.fireDocumentEvent("backbutton");
                ev.preventDefault();
                return true;
              }
            }, false);

            // start to listen for network connection changes
            service.Request('palm://com.palm.connectionmanager', {
                method: 'getstatus',
                parameters: { subscribe: true },
                onSuccess: function (result) {
                    console.log("subscribe:result:"+JSON.stringify(result));

                    if (!result.isInternetConnectionAvailable) {
                        if (navigator.onLine) {
                            console.log("Firing event:offline");
                            cordova.fireDocumentEvent("offline");
                        }
                    } else {
                        console.log("Firing event:online");
                        cordova.fireDocumentEvent("online");
                    }
                },
                onFailure: function(e) {
                    console.error("subscribe:error");
                }
            });

        });
    },
    clobbers: {
        requestFileSystem:{
            path: 'cordova/plugin/webos/requestfilesystem'
        },
        FileReader: {
            path: "cordova/plugin/webos/filereader"
        }
    },
    merges: {
        navigator: {
            children: {
                service: {
                    path: "cordova/plugin/webos/service"
                },
                application: {
                    path: "cordova/plugin/webos/application"
                },
                window: {
                    path: "cordova/plugin/webos/window"
                },
                notification: {
                    path: "cordova/plugin/webos/notification"
                },
                orientation: {
                    path: "cordova/plugin/webos/orientation"
                },
                keyboard: {
                    path: "cordova/plugin/webos/keyboard"
                }
            }
        }
    }
};
<|endoftext|>