<commit_before>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.");
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    if (move !== null) {
        return move;
    }
    else {
        return getInput();
    }
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    if (move !== null) {
        return move;
    }
    else {
        return randomPlay();
    }
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    /* YOUR CODE HERE */
    if (playerMove === computerMove) {
        return "The result is a tie!";
    }
    else if(playerMove === "rock") {

        if(computerMove === "scissors") {
            winner = 'player';
        }
        else  {
            winner = 'computer';
        }
    }
    else if(playerMove === "paper"){

        if(computerMove === "rock") {
            winner = 'player';
        }
        else{
            winner = 'computer';
        }
    }
    else if(playerMove === "scissors"){

        if(computerMove === "paper") {
            winner = 'player';
        }
        else{
            winner = 'computer';
        }
    }
    return winner;
};

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
  var ties = 0;
    while ((playerWins < 5) && (computerWins < 5) && (ties < 10)) {
        console.log('looping');
        var playersAction = getPlayerMove(null);
        console.log('looping1');
        var computersAction = getComputerMove(null);
        console.log('looping2');
        var whoWon = getWinner(playersAction, computersAction);
        if  (whoWon == 'player') {
            playerWins++;
        }
        else if (whoWon == 'computer') {
            computerWins++;
        }
        else {
          ties++;
        }
        console.log('Player chose ' + playersAction + ' while Computer chose ' + computersAction);
        console.log('The score is currently ' + playerWins + ' to ' + computerWins + '\n');
    }
    console.log("Game Over!");
    return [playerWins, computerWins];

}
playToFive();
<commit_msg>Final RPS2<commit_after>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.");
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    if (move !== null) {
        return move;
    }
    else {
        return getInput();
    }
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    if (move !== null) {
        return move;
    }
    else {
        return randomPlay();
    }
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    /* YOUR CODE HERE */
    if (playerMove === computerMove) {
        return "The result is a tie!";
    }
    else if(playerMove === "rock") {

        if(computerMove === "scissors") {
            winner = 'player';
        }
        else  {
            winner = 'computer';
        }
    }
    else if(playerMove === "paper"){

        if(computerMove === "rock") {
            winner = 'player';
        }
        else{
            winner = 'computer';
        }
    }
    else if(playerMove === "scissors"){

        if(computerMove === "paper") {
            winner = 'player';
        }
        else{
            winner = 'computer';
        }
    }
    return winner;
};

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
  var ties = 0;
    while ((playerWins < 5) && (computerWins < 5) && (ties < 10)) {
        console.log('looping');
        var playersAction = getPlayerMove(null);
        var computersAction = getComputerMove(null);
        var whoWon = getWinner(playersAction, computersAction);
        if  (whoWon == 'player') {
            playerWins++;
        }
        else if (whoWon == 'computer') {
            computerWins++;
        }
        else {
          ties++;
        }
        console.log('Player chose ' + playersAction + ' while Computer chose ' + computersAction);
        console.log('The score is currently ' + playerWins + ' to ' + computerWins + '\n');
    }
    console.log("Game Over!");
    return [playerWins, computerWins];

}
playToFive();
<|endoftext|>


<commit_before>/**
 * jquery.toggleNator.js
 *
 * @author Tom Kopp
 * @license MIT
 * @version 1.1.1
 */
;(function ($) {

  var toggleNator = function (elems, options) {
      this.elems = elems
      this.options = options
    }
    , _groups = {}

  toggleNator.prototype = {
    defaults: {
      byGroup: true
      , group: 'all'
      , state: 'off'
      , triggerClass: 'toggleNator'
      , target: null
      , targetClass: 'toggleNatorTarget'
    }
    , init: function () {
      this.config = $.extend({}, this.defaults, this.options)
      this._prepareElements()
      this._apply()
      this._addEventListeners()
    }
    , toggleNator: function (k, elem) {
      // called on click event
      var that = this
        , $elem = $(elem)

      // change element's state to 'on'
      $elem.data('state', ($elem.data('state') === 'on' ? 'off': 'on'))
      if ($elem.data('byGroup')) {
        // get data-toggle group from clicked element and select all from same group
        $.each(_groups[$elem.data('group')], function (i, el) {
          // change state to 'off' on all other elements
          that._manageState(i, el, $elem)
          that._applyOne(i, el)
        })
      } else {
        that._applyOne(null, $elem)
      }
    }
    , _addEventListeners: function () {
      // set click event on all elements
      var that = this

      that._walkGroups(function (k, elem) {
        $(elem).on('click.toggleNator', function () {
          that.toggleNator(k, elem)
        })
      })
    }
    , _apply: function () {
      // toggle all targets based on element's state
      var that = this

      that._walkGroups(function (k, elem) {
        that._applyOne(k, elem)
      })
    }
    , _applyOne: function (k, elem) {
      // toggle targetClass based on element's state
      var $elem = $(elem)

      if ($elem.data('state') === 'on' && $elem.data('state') !== 'off') {
        $elem.addClass($elem.data('triggerClass'))
        if ($elem.data('targetElem') != null) {
          $elem.data('targetElem').addClass($elem.data('targetClass'))
        }
      } else {
        $elem.removeClass($elem.data('triggerClass'))
        if ($elem.data('targetElem') != null) {
          $elem.data('targetElem').data('targetElem').removeClass($elem.data('targetClass'))
        }
      }
    }
    , _prepareElements: function () {
      // set options, group and target for each element
      var options = this.config
      $.each(this.elems, function (k, elem) {
        var that = $(elem)
          , groupId
          , targetElem

        // merge general options with element's options
        that.data($.extend({}, options, that.data('toggleNator')))
        // get target object and save it in the element for later use
        if (that.data('target')) {
          that.data('targetElem', $('[data-toggleNatorTarget="'+ that.data('target') +'"]'))
        }

        if (that.data('byGroup')) {
          // if groups should be minded add by element's group
          groupId = that.data('group')
        } else {
          // if not separated by group, store it in default group
          groupId = options.group
        }

        if (groupId in _groups) {
          _groups[groupId] = _groups[groupId].add(that)
        } else {
          _groups[groupId] = that
        }
      })
    }
    , _manageState: function (k, elem, $src) {
      // change state on element
      var $elem = $(elem)
      if ($src.data('state') === 'on' && $src[0] !== $elem[0]) {
        $elem.data('state', 'off')
      }
    }
    , _walkGroups: function (callback) {
      // walk through _groups and their elements and apply callback function
      $.each(_groups, function (key, group) {
        $.each(group, function (k, elem) {
          callback(k, elem)
        })
      })
    }
  }

  $.fn.toggleNator = function (options) {
    new toggleNator(this, options).init()
    return this
  }

})(jQuery)
<commit_msg>update poor code to be more reliable<commit_after>/**
 * jquery.toggleNator.js
 *
 * @author Tom Kopp
 * @license MIT
 * @version 1.1.2
 */
;(function ($) {

  var toggleNator = function (elems, options) {
      this.elems = elems
      this.options = options
    }
    , _groups = {}

  toggleNator.prototype = {
    defaults: {
      byGroup: true
      , group: 'all'
      , state: 'off'
      , triggerClass: 'toggleNator'
      , target: null
      , targetClass: 'toggleNatorTarget'
    }
    , init: function () {
      this.config = $.extend({}, this.defaults, this.options)
      this._prepareElements()
      this._apply()
      this._addEventListeners()
    }
    , toggleNator: function (k, elem) {
      // called on click event
      var that = this
        , $elem = $(elem)

      // change element's state to 'on'
      $elem.data('state', ($elem.data('state') === 'on' ? 'off': 'on'))
      if ($elem.data('byGroup')) {
        // get data-toggle group from clicked element and select all from same group
        $.each(_groups[$elem.data('group')], function (i, el) {
          // change state to 'off' on all other elements
          that._manageState(i, el, $elem)
          that._applyOne(i, el)
        })
      } else {
        that._applyOne(null, $elem)
      }
    }
    , _addEventListeners: function () {
      // set click event on all elements
      var that = this

      that._walkGroups(function (k, elem) {
        $(elem).on('click.toggleNator', function () {
          that.toggleNator(k, elem)
        })
      })
    }
    , _apply: function () {
      // toggle all targets based on element's state
      var that = this

      that._walkGroups(function (k, elem) {
        that._applyOne(k, elem)
      })
    }
    , _applyOne: function (k, elem) {
      // toggle targetClass based on element's state
      var $elem = $(elem)

      if ($elem.data('state') === 'on' && $elem.data('state') !== 'off') {
        $elem.addClass($elem.data('triggerClass'))
        if ($elem.data('targetElem').length) {
          $elem.data('targetElem').addClass($elem.data('targetClass'))
        }
      } else {
        $elem.removeClass($elem.data('triggerClass'))
        if ($elem.data('targetElem').length) {
          $elem.data('targetElem').removeClass($elem.data('targetClass'))
        }
      }
    }
    , _prepareElements: function () {
      // set options, group and target for each element
      var options = this.config
      $.each(this.elems, function (k, elem) {
        var that = $(elem)
          , groupId
          , targetElem

        // merge general options with element's options
        that.data($.extend({}, options, that.data('toggleNator')))
        // get target object and save it in the element for later use
        if (that.data('target')) {
          that.data('targetElem', $('[data-toggleNatorTarget="'+ that.data('target') +'"]'))
        }

        if (that.data('byGroup')) {
          // if groups should be minded add by element's group
          groupId = that.data('group')
        } else {
          // if not separated by group, store it in default group
          groupId = options.group
        }

        if (groupId in _groups) {
          _groups[groupId] = _groups[groupId].add(that)
        } else {
          _groups[groupId] = that
        }
      })
    }
    , _manageState: function (k, elem, $src) {
      // change state on element
      var $elem = $(elem)
      if ($src.data('state') === 'on' && $src[0] !== $elem[0]) {
        $elem.data('state', 'off')
      }
    }
    , _walkGroups: function (callback) {
      // walk through _groups and their elements and apply callback function
      $.each(_groups, function (key, group) {
        $.each(group, function (k, elem) {
          callback(k, elem)
        })
      })
    }
  }

  $.fn.toggleNator = function (options) {
    new toggleNator(this, options).init()
    return this
  }

})(jQuery)
<|endoftext|>


<commit_before>//Import Modules
var roleBuilder = require('role.builder');

module.exports = {
    run: function(creep) {
            if (creep.memory.working == true && creep.carry.energy == 0) {
            creep.memory.working = false;
        }
        else if (creep.memory.working == false && creep.carry.energy == creep.carryCapacity) {
            creep.memory.working = true;
        }

        if (creep.memory.working == true) {
            var structure = creep.pos.findClosestByPath(FIND_STRUCTURES, {
                filter: (s) => s.hits < s.200000 && s.structureType == STRUCTURE_WALL
            });
            if (structure != undefined) {
                if (creep.repair(structure) == ERR_NOT_IN_RANGE) {
                    creep.moveTo(structure);
                }
            }
            else {
                roleBuilder.run(creep);
            }
        }
        // if creep needs to harvest energy from source
        else {
            var source = creep.pos.findClosestByPath(FIND_SOURCES);
            if (creep.harvest(source) == ERR_NOT_IN_RANGE) {
                creep.moveTo(source);
            }
        }
    }
};
<commit_msg>Only build walls to 200k Fixed<commit_after>//Import Modules
var roleBuilder = require('role.builder');

module.exports = {
    run: function(creep) {
            if (creep.memory.working == true && creep.carry.energy == 0) {
            creep.memory.working = false;
        }
        else if (creep.memory.working == false && creep.carry.energy == creep.carryCapacity) {
            creep.memory.working = true;
        }

        if (creep.memory.working == true) {
            var structure = creep.pos.findClosestByPath(FIND_STRUCTURES, {
                filter: (s) => s.hits < 200000 && s.structureType == STRUCTURE_WALL
            });
            if (structure != undefined) {
                if (creep.repair(structure) == ERR_NOT_IN_RANGE) {
                    creep.moveTo(structure);
                }
            }
            else {
                roleBuilder.run(creep);
            }
        }
        // if creep needs to harvest energy from source
        else {
            var source = creep.pos.findClosestByPath(FIND_SOURCES);
            if (creep.harvest(source) == ERR_NOT_IN_RANGE) {
                creep.moveTo(source);
            }
        }
    }
};
<|endoftext|>


<commit_before>const express = require('express')
const router = express.Router()
const { data } = require('../data/cards.json')
const { cards } = data

router.get('/:id', (req, res) => {
  const name = req.cookies.username
  const { id } = req.params
  const { side } = req.query
  const text = cards[id][side]
  const { hint } = cards[id]
  const templateData = { text }

  if (name) {
    if (side === 'question') {
      templateData.hint = hint
    }
    res.render('card', templateData)
  } else {
    res.redirect('/hello')
  }
})

module.exports = router
<commit_msg>comment for concept I just understood.<commit_after>const express = require('express')
const router = express.Router()
const { data } = require('../data/cards.json')
const { cards } = data

router.get('/:id', (req, res) => {
  const name = req.cookies.username
  const { id } = req.params
  const { side } = req.query
  const text = cards[id][side] // this combines the id number for the Q with the side (question or answer). depending on side will set value of text.
  const { hint } = cards[id]
  const templateData = { text }

  if (name) {
    if (side === 'question') {
      templateData.hint = hint
    }
    res.render('card', templateData)
  } else {
    res.redirect('/hello')
  }
})

module.exports = router
<|endoftext|>


<commit_before>/**
 * Bits and bobs. Largely for erroneous route handling.
 */

var REST = require( './../../lib/rest'),
    fs = require( 'fs' ),
    md = require( 'marked' );

/**
 * Generic home page
 *
 * @param req
 * @param res
 */
var home = function( req, res ) {

    fs.readFile( 'README.md', { encoding: 'utf8' }, function( err, data ) {

        if( err ) throw err;

        md.setOptions({
            gfm: true,
            tables: true,
            breaks: true,
            sanitize: true,
            smartLists: true,
            smartypants: true,
            highlight: function ( code ) {
                return require( 'highlight.js' ).highlightAuto( code ).value;
            }
        });

        var md_text = md( data );

        res.set('Content-Type', 'text/html');
        res.render( 'home.hbs', { layout: false, contents: md_text } );

    });

};

/**
 * A truly generic 400 error response
 *
 * @param req
 * @param res
 * @param {Number} code  HTTP status code, generally a 400
 * @param {String} status  Short status code, generally under 10 characters
 * @param {String} message  Lengthier description of the error
 * @param {Object} results  Optional container for any returned data
 */
var genericError = function( req, res, code, status, message, results ) {

    if( !code ) code = 400;

    REST.envelop.call( res, code, status, message, results );

};

/**
 * For bad requests to an endpoint that requires an ID (e.g. PUTs to /word)
 *
 * @param req
 * @param res
 */
var missingID = function( req, res ) {

    genericError( req, res, 400, "BADREQUEST", "Invalid request. Missing ID.", {} );

};

/**
 * For valid calls to missing resources
 *
 * @param req
 * @param res
 * @param {String} message  Lengthier description of the error
 * @param {Object} results  Optional container for any returned data
 */
var missing = function( req, res, message, results ) {

    if( !results ) results = {};

    genericError( req, res, 404, "NOTFOUND", message, results );

};

/**
 * Response to bad verb calls to good endpoints (i.e. trying to POST to a GET-only endpoint)
 *
 * @param req
 * @param res
 */
var badMethod = function( req, res ) {

    var method = req.route.method,
        endpoint = req.route.path,
        acceptable = res.get( 'Accepts' );

    genericError( req, res, 405, "BADMETHOD", "Method " + method.toUpperCase() + " not allowed on endpoint " + endpoint, { method_attempted: method, methods_accepted: acceptable } );

};

exports.genericError = genericError;
exports.missingID = missingID;
exports.missing = missing;
exports.badMethod = badMethod;
exports.home = home;
<commit_msg>Reducing dot lookups<commit_after>/**
 * Bits and bobs. Largely for erroneous route handling.
 */

var REST = require( './../../lib/rest'),
    fs = require( 'fs' ),
    md = require( 'marked' );

/**
 * Generic home page
 *
 * @param req
 * @param res
 */
var home = function( req, res ) {

    fs.readFile( 'README.md', { encoding: 'utf8' }, function( err, data ) {

        if( err ) throw err;

        md.setOptions({
            gfm: true,
            tables: true,
            breaks: true,
            sanitize: true,
            smartLists: true,
            smartypants: true,
            highlight: function ( code ) {
                return require( 'highlight.js' ).highlightAuto( code ).value;
            }
        });

        var md_text = md( data );

        res.set('Content-Type', 'text/html');
        res.render( 'home.hbs', { layout: false, contents: md_text } );

    });

};

/**
 * A truly generic 400 error response
 *
 * @param req
 * @param res
 * @param {Number} code  HTTP status code, generally a 400
 * @param {String} status  Short status code, generally under 10 characters
 * @param {String} message  Lengthier description of the error
 * @param {Object} results  Optional container for any returned data
 */
var genericError = function( req, res, code, status, message, results ) {

    if( !code ) code = 400;

    REST.envelop.call( res, code, status, message, results );

};

/**
 * For bad requests to an endpoint that requires an ID (e.g. PUTs to /word)
 *
 * @param req
 * @param res
 */
var missingID = function( req, res ) {

    genericError( req, res, 400, "BADREQUEST", "Invalid request. Missing ID.", {} );

};

/**
 * For valid calls to missing resources
 *
 * @param req
 * @param res
 * @param {String} message  Lengthier description of the error
 * @param {Object} results  Optional container for any returned data
 */
var missing = function( req, res, message, results ) {

    if( !results ) results = {};

    genericError( req, res, 404, "NOTFOUND", message, results );

};

/**
 * Response to bad verb calls to good endpoints (i.e. trying to POST to a GET-only endpoint)
 *
 * @param req
 * @param res
 */
var badMethod = function( req, res ) {

    var method = req.method,
        endpoint = req.path,
        acceptable = res.get( 'Accepts' );

    genericError( req, res, 405, "BADMETHOD", "Method " + method.toUpperCase() + " not allowed on endpoint " + endpoint, { method_attempted: method, methods_accepted: acceptable } );

};

exports.genericError = genericError;
exports.missingID = missingID;
exports.missing = missing;
exports.badMethod = badMethod;
exports.home = home;
<|endoftext|>


<commit_before>module.exports = function(RED)
{
	"use strict";

	function HueBridge(config)
	{
		var scope = this;
		var events = require('events');
		let huejay = require('huejay');

		// INTERVAL AND EVENT EMITTER
		this.nodeActive = true;
		this.lights = [];
		this.sensors = [];
		this.groups = [];
		this.rules = [];
		this.events = new events.EventEmitter();

		// CREATE NODE
		RED.nodes.createNode(scope, config);

		// DEFINE CLIENT
		let ipHostArray = (config.bridge).toString().trim().split(":");
		this.client = new huejay.Client({
			host: ipHostArray[0],
			port: (ipHostArray > 1) ? parseInt(ipHostArray[1]) : 80,
			username: config.key
		});

		// DELAY
		this.delay = function(ms)
		{
			return new Promise(resolve => setTimeout(resolve, ms));
		}

		// RECHECK DEVICES
		this.recheckAll = function()
		{
			scope.client.sensors.getAll().then(sensors => {
				let sensorUpdates = scope.getUpdates("sensor", sensors);
				scope.emitUpdates("sensor", sensorUpdates);

				return true;
			})
			scope.delay(500).then(() => { return "next"; })
			scope.client.lights.getAll().then(lights => {
				let lightUpdates = scope.getUpdates("light", lights);
				scope.emitUpdates("light", lightUpdates);

				return true;
			})
			scope.delay(500).then(() => { return "next"; })
			scope.client.groups.getAll().then(groups => {
				let groupUpdates = scope.getUpdates("group", groups);
				scope.emitUpdates("group", groupUpdates);

				return true;
			})
			scope.delay(500).then(() => { return "next"; })
			scope.client.rules.getAll().then(rules => {
				let ruleUpdates = scope.getUpdates("rule", rules);
				scope.emitUpdates("rule", ruleUpdates);

				return true;
			})
			.then(proceed => {
				// RECHECK
				if(scope.nodeActive == true && proceed == true) { setTimeout(function(){ scope.recheckAll(); }, config.interval); }
				return true;
			})
			.catch(error => {
				scope.debug(error.stack);

				if(scope.nodeActive == true)
				{
					setTimeout(function(){ scope.recheckAll(); }, 5000);
				}
			});
		}

		// RECHECK ONLY SENSORS
		this.recheckSensors = function()
		{
			scope.client.sensors.getAll().then(sensors => {
				let sensorUpdates = scope.getUpdates("sensor", sensors);
				scope.emitUpdates("sensor", sensorUpdates);

				return true;
			})
			.then(proceed => {
				// RECHECK
				if(scope.nodeActive == true && proceed == true) { setTimeout(function(){ scope.recheckSensors(); }, config.interval); }
				return true;
			})
			.catch(error => {
				scope.debug(error.stack);

				if(scope.nodeActive == true)
				{
					setTimeout(function(){ scope.recheckSensors(); }, 5000);
				}
			});
		}

		// START FIRST CHECK
		if(!config.disableupdates)
		{
			this.recheckAll();
		}
		else
		{
			this.recheckSensors();
		}

		// DETERMINE UPDATES
		this.getUpdates = function(mode, content)
		{
			var updates = [];
			for (var i = content.length - 1; i >= 0; i--)
			{
				let device = content[i];
				var updated = false;
				var uniqueStatus = "";

				if(mode == "light")
				{
					uniqueStatus = ((device.on) ? "1" : "0") + device.brightness + device.hue + device.saturation + device.colorTemp + device.reachable;

					if(device.id in this.lights)
					{
						if(this.lights[device.id] != uniqueStatus)
						{
							this.lights[device.id] = uniqueStatus;
							updated = true;
						}
					}
					else
					{
						this.lights[device.id] = uniqueStatus;
						updated = true;
					}
				}
				else if(mode == "sensor")
				{
					uniqueStatus = device.state.lastUpdated;
					if(device.id in this.sensors)
					{
						if(this.sensors[device.id] != uniqueStatus)
						{
							this.sensors[device.id] = uniqueStatus;
							updated = true;
						}
					}
					else
					{
						this.sensors[device.id] = uniqueStatus;
						updated = true;
					}
				}
				else if(mode == "group")
				{
					uniqueStatus = ((device.on) ? "1" : "0") + device.brightness + device.hue + device.saturation + device.colorTemp + ((device.anyOn) ? "1" : "0") + ((device.allOn) ? "1" : "0");
					if(device.id in this.groups)
					{
						if(this.groups[device.id] != uniqueStatus)
						{
							this.groups[device.id] = uniqueStatus;
							updated = true;
						}
					}
					else
					{
						this.groups[device.id] = uniqueStatus;
						updated = true;
					}
				}
				else if(mode == "rule")
				{
					let rule = device;
					uniqueStatus = rule.lastTriggered + rule.status;

					if(rule.id in this.rules)
					{
						if(this.rules[rule.id] != uniqueStatus)
						{
							this.rules[rule.id] = uniqueStatus;
							updated = true;
						}
					}
					else
					{
						this.rules[rule.id] = uniqueStatus;
						updated = true;
					}
				}

				// IS UPDATED?
				if(updated == true)
				{
					updates.push(device);
				}
			}

			// RETURN UPDATES
			return updates;
		}

		// EMIT UPDATES
		this.emitUpdates = function(device, updates)
		{
			for(let deviceUpdate of updates)
			{
				let eventName = device + deviceUpdate.id;
				scope.events.emit(eventName, deviceUpdate);
				scope.events.emit("globalDeviceUpdates", {type: device, payload: deviceUpdate});
			}
		}

		//
		// CLOSE NODE / REMOVE EVENT LISTENER
		this.on('close', function()
		{
			scope.nodeActive = false;
		});
	}

	RED.nodes.registerType("hue-bridge", HueBridge);

	//
	// DISCOVER HUE BRIDGES ON LOCAL NETWORK
	RED.httpAdmin.get('/hue/bridges', function(req, res, next)
	{
		let huejay = require('huejay');

		huejay.discover()
		.then(bridges => {
			res.end(JSON.stringify(bridges));
		})
		.catch(error => {
			res.send(500).send(error.message);
		});
	});

	//
	// GET BRIDGE NAME
	RED.httpAdmin.get('/hue/name', function(req, res, next)
	{
		if(!req.query.ip)
		{
			return res.status(500).send(RED._("hue-bridge-config.config.missing-ip"));
	    }
	    else
	    {
			var huejay = require('huejay');

			var bridgeIP = (req.query.ip).toString();
			var client = new huejay.Client({host: bridgeIP, username: 'default'});

			client.bridge.get()
			.then(bridge => {
				res.end(bridge.name);
			})
			.catch(error => {
				res.send(500).send(error.message);
			});
	    }
	});

	//
	// REGISTER A HUE BRIDGE
	RED.httpAdmin.get('/hue/register', function(req, rescope, next)
	{
		if(!req.query.ip)
		{
			return rescope.status(500).send(RED._("hue-bridge-config.config.missing-ip"));
		}
		else
		{
			var request = require('request');
			let bridgeIP = (req.query.ip).toString();

			request.post('http://'+bridgeIP+'/api', {body: JSON.stringify({"devicetype": "nodered_" + Math.floor((Math.random() * 100) + 1)}) }, function(err,httpResponse,body)
			{
				if(err)
				{
					rescope.end("error");
				}
				else
				{
					var bridge = JSON.parse(body);

					if(bridge[0].error)
					{
						rescope.end("error");
					}
					else
					{
						rescope.end(JSON.stringify(bridge));
					}
				}
			});
		}
	});

	//
	// DISCOVER SENSORS
	RED.httpAdmin.get('/hue/sensors', function(req, res, next)
	{
		let huejay = require('huejay');
		var bridge = (req.query.bridge).toString();
		var username = req.query.key;
		var type = req.query.type;

		let client = new huejay.Client({
			host: bridge,
			username: username
		});

		client.sensors.getAll()
		.then(sensors => {
			var allSensorDevices = [];

			for (let sensor of sensors)
			{
				if(sensor.type == type)
				{
					var oneSensor = {};
					oneSensor.id = sensor.id;
					oneSensor.name = sensor.name;
					oneSensor.model = sensor.model.name;
					oneSensor.model_id = sensor.modelid;

					allSensorDevices.push(oneSensor);
				}
			}

			res.end(JSON.stringify(allSensorDevices));
		})
		.catch(error => {
			res.send(500).send(error.stack);
		});
	});

	//
	// DISCOVER LIGHTS
	RED.httpAdmin.get('/hue/lights', function(req, res, next)
	{
		let huejay = require('huejay');
		var bridge = (req.query.bridge).toString();
		var username = req.query.key;

		let client = new huejay.Client({
			host: bridge,
			username: username
		});

		client.lights.getAll()
		.then(lights => {
			var allLights = [];

			for (let light of lights)
			{
				var oneLightBulb = {};
				oneLightBulb.id = light.id;
				oneLightBulb.name = light.name;

				allLights.push(oneLightBulb);
			}

			res.end(JSON.stringify(allLights));
		})
		.catch(error => {
			res.send(500).send(error.stack);
		});
	});

	//
	// DISCOVER GROUPS
	RED.httpAdmin.get('/hue/groups', function(req, res, next)
	{
		let huejay = require('huejay');
		var bridge = (req.query.bridge).toString();
		var username = req.query.key;

		let client = new huejay.Client({
			host: bridge,
			username: username
		});

		client.groups.getAll()
		.then(groups => {
			var allGroups = [];

			for (let group of groups)
			{
				var oneGroup = {};
				oneGroup.id = group.id;
				oneGroup.name = group.name;

				allGroups.push(oneGroup);
			}

			res.end(JSON.stringify(allGroups));
		})
		.catch(error => {
			res.send(500).send(error.stack);
		});
	});

	//
	// DISCOVER SCENES
	RED.httpAdmin.get('/hue/scenes', function(req, res, next)
	{
		let huejay = require('huejay');
		var bridge = (req.query.bridge).toString();
		var username = req.query.key;

		let client = new huejay.Client({
			host: bridge,
			username: username
		});

		client.scenes.getAll()
		.then(scenes => {
			var allScenes = [];

			for (let scene of scenes)
			{
				var oneScene = {};
				oneScene.id = scene.id;
				oneScene.name = scene.name;

				allScenes.push(oneScene);
			}

			res.end(JSON.stringify(allScenes));
		})
		.catch(error => {
			res.send(500).send(error.stack);
		});
	});

	//
	// DISCOVER RULES
	RED.httpAdmin.get('/hue/rules', function(req, res, next)
	{
		let huejay = require('huejay');
		var bridge = (req.query.bridge).toString();
		var username = req.query.key;

		let client = new huejay.Client({
			host: bridge,
			username: username
		});

		client.rules.getAll()
		.then(rules => {
			var allRules = [];

			for (let rule of rules)
			{
				var oneRule = {};
				oneRule.id = rule.id;
				oneRule.name = rule.name;

				allRules.push(oneRule);
			}

			res.end(JSON.stringify(allRules));
		})
		.catch(error => {
			res.send(500).send(error.stack);
		});
	});
};
<commit_msg>add model_id to sensor<commit_after>module.exports = function(RED)
{
	"use strict";

	function HueBridge(config)
	{
		var scope = this;
		var events = require('events');
		let huejay = require('huejay');

		// INTERVAL AND EVENT EMITTER
		this.nodeActive = true;
		this.lights = [];
		this.sensors = [];
		this.groups = [];
		this.rules = [];
		this.events = new events.EventEmitter();

		// CREATE NODE
		RED.nodes.createNode(scope, config);

		// DEFINE CLIENT
		let ipHostArray = (config.bridge).toString().trim().split(":");
		this.client = new huejay.Client({
			host: ipHostArray[0],
			port: (ipHostArray > 1) ? parseInt(ipHostArray[1]) : 80,
			username: config.key
		});

		// DELAY
		this.delay = function(ms)
		{
			return new Promise(resolve => setTimeout(resolve, ms));
		}

		// RECHECK DEVICES
		this.recheckAll = function()
		{
			scope.client.sensors.getAll().then(sensors => {
				let sensorUpdates = scope.getUpdates("sensor", sensors);
				scope.emitUpdates("sensor", sensorUpdates);

				return true;
			})
			scope.delay(500).then(() => { return "next"; })
			scope.client.lights.getAll().then(lights => {
				let lightUpdates = scope.getUpdates("light", lights);
				scope.emitUpdates("light", lightUpdates);

				return true;
			})
			scope.delay(500).then(() => { return "next"; })
			scope.client.groups.getAll().then(groups => {
				let groupUpdates = scope.getUpdates("group", groups);
				scope.emitUpdates("group", groupUpdates);

				return true;
			})
			scope.delay(500).then(() => { return "next"; })
			scope.client.rules.getAll().then(rules => {
				let ruleUpdates = scope.getUpdates("rule", rules);
				scope.emitUpdates("rule", ruleUpdates);

				return true;
			})
			.then(proceed => {
				// RECHECK
				if(scope.nodeActive == true && proceed == true) { setTimeout(function(){ scope.recheckAll(); }, config.interval); }
				return true;
			})
			.catch(error => {
				scope.debug(error.stack);

				if(scope.nodeActive == true)
				{
					setTimeout(function(){ scope.recheckAll(); }, 5000);
				}
			});
		}

		// RECHECK ONLY SENSORS
		this.recheckSensors = function()
		{
			scope.client.sensors.getAll().then(sensors => {
				let sensorUpdates = scope.getUpdates("sensor", sensors);
				scope.emitUpdates("sensor", sensorUpdates);

				return true;
			})
			.then(proceed => {
				// RECHECK
				if(scope.nodeActive == true && proceed == true) { setTimeout(function(){ scope.recheckSensors(); }, config.interval); }
				return true;
			})
			.catch(error => {
				scope.debug(error.stack);

				if(scope.nodeActive == true)
				{
					setTimeout(function(){ scope.recheckSensors(); }, 5000);
				}
			});
		}

		// START FIRST CHECK
		if(!config.disableupdates)
		{
			this.recheckAll();
		}
		else
		{
			this.recheckSensors();
		}

		// DETERMINE UPDATES
		this.getUpdates = function(mode, content)
		{
			var updates = [];
			for (var i = content.length - 1; i >= 0; i--)
			{
				let device = content[i];
				var updated = false;
				var uniqueStatus = "";

				if(mode == "light")
				{
					uniqueStatus = ((device.on) ? "1" : "0") + device.brightness + device.hue + device.saturation + device.colorTemp + device.reachable;

					if(device.id in this.lights)
					{
						if(this.lights[device.id] != uniqueStatus)
						{
							this.lights[device.id] = uniqueStatus;
							updated = true;
						}
					}
					else
					{
						this.lights[device.id] = uniqueStatus;
						updated = true;
					}
				}
				else if(mode == "sensor")
				{
					uniqueStatus = device.state.lastUpdated;
					if(device.id in this.sensors)
					{
						if(this.sensors[device.id] != uniqueStatus)
						{
							this.sensors[device.id] = uniqueStatus;
							updated = true;
						}
					}
					else
					{
						this.sensors[device.id] = uniqueStatus;
						updated = true;
					}
				}
				else if(mode == "group")
				{
					uniqueStatus = ((device.on) ? "1" : "0") + device.brightness + device.hue + device.saturation + device.colorTemp + ((device.anyOn) ? "1" : "0") + ((device.allOn) ? "1" : "0");
					if(device.id in this.groups)
					{
						if(this.groups[device.id] != uniqueStatus)
						{
							this.groups[device.id] = uniqueStatus;
							updated = true;
						}
					}
					else
					{
						this.groups[device.id] = uniqueStatus;
						updated = true;
					}
				}
				else if(mode == "rule")
				{
					let rule = device;
					uniqueStatus = rule.lastTriggered + rule.status;

					if(rule.id in this.rules)
					{
						if(this.rules[rule.id] != uniqueStatus)
						{
							this.rules[rule.id] = uniqueStatus;
							updated = true;
						}
					}
					else
					{
						this.rules[rule.id] = uniqueStatus;
						updated = true;
					}
				}

				// IS UPDATED?
				if(updated == true)
				{
					updates.push(device);
				}
			}

			// RETURN UPDATES
			return updates;
		}

		// EMIT UPDATES
		this.emitUpdates = function(device, updates)
		{
			for(let deviceUpdate of updates)
			{
				let eventName = device + deviceUpdate.id;
				scope.events.emit(eventName, deviceUpdate);
				scope.events.emit("globalDeviceUpdates", {type: device, payload: deviceUpdate});
			}
		}

		//
		// CLOSE NODE / REMOVE EVENT LISTENER
		this.on('close', function()
		{
			scope.nodeActive = false;
		});
	}

	RED.nodes.registerType("hue-bridge", HueBridge);

	//
	// DISCOVER HUE BRIDGES ON LOCAL NETWORK
	RED.httpAdmin.get('/hue/bridges', function(req, res, next)
	{
		let huejay = require('huejay');

		huejay.discover()
		.then(bridges => {
			res.end(JSON.stringify(bridges));
		})
		.catch(error => {
			res.send(500).send(error.message);
		});
	});

	//
	// GET BRIDGE NAME
	RED.httpAdmin.get('/hue/name', function(req, res, next)
	{
		if(!req.query.ip)
		{
			return res.status(500).send(RED._("hue-bridge-config.config.missing-ip"));
	    }
	    else
	    {
			var huejay = require('huejay');

			var bridgeIP = (req.query.ip).toString();
			var client = new huejay.Client({host: bridgeIP, username: 'default'});

			client.bridge.get()
			.then(bridge => {
				res.end(bridge.name);
			})
			.catch(error => {
				res.send(500).send(error.message);
			});
	    }
	});

	//
	// REGISTER A HUE BRIDGE
	RED.httpAdmin.get('/hue/register', function(req, rescope, next)
	{
		if(!req.query.ip)
		{
			return rescope.status(500).send(RED._("hue-bridge-config.config.missing-ip"));
		}
		else
		{
			var request = require('request');
			let bridgeIP = (req.query.ip).toString();

			request.post('http://'+bridgeIP+'/api', {body: JSON.stringify({"devicetype": "nodered_" + Math.floor((Math.random() * 100) + 1)}) }, function(err,httpResponse,body)
			{
				if(err)
				{
					rescope.end("error");
				}
				else
				{
					var bridge = JSON.parse(body);

					if(bridge[0].error)
					{
						rescope.end("error");
					}
					else
					{
						rescope.end(JSON.stringify(bridge));
					}
				}
			});
		}
	});

	//
	// DISCOVER SENSORS
	RED.httpAdmin.get('/hue/sensors', function(req, res, next)
	{
		let huejay = require('huejay');
		var bridge = (req.query.bridge).toString();
		var username = req.query.key;
		var type = req.query.type;

		let client = new huejay.Client({
			host: bridge,
			username: username
		});

		client.sensors.getAll()
		.then(sensors => {
			var allSensorDevices = [];

			for (let sensor of sensors)
			{
				if(sensor.type == type)
				{
					var oneSensor = {};
					oneSensor.id = sensor.id;
					oneSensor.name = sensor.name;
					oneSensor.model = sensor.model.name;
					oneSensor.model_id = sensor.modelid;
					oneSensor.json = sensor;

					allSensorDevices.push(oneSensor);
				}
			}

			res.end(JSON.stringify(allSensorDevices));
		})
		.catch(error => {
			res.send(500).send(error.stack);
		});
	});

	//
	// DISCOVER LIGHTS
	RED.httpAdmin.get('/hue/lights', function(req, res, next)
	{
		let huejay = require('huejay');
		var bridge = (req.query.bridge).toString();
		var username = req.query.key;

		let client = new huejay.Client({
			host: bridge,
			username: username
		});

		client.lights.getAll()
		.then(lights => {
			var allLights = [];

			for (let light of lights)
			{
				var oneLightBulb = {};
				oneLightBulb.id = light.id;
				oneLightBulb.name = light.name;

				allLights.push(oneLightBulb);
			}

			res.end(JSON.stringify(allLights));
		})
		.catch(error => {
			res.send(500).send(error.stack);
		});
	});

	//
	// DISCOVER GROUPS
	RED.httpAdmin.get('/hue/groups', function(req, res, next)
	{
		let huejay = require('huejay');
		var bridge = (req.query.bridge).toString();
		var username = req.query.key;

		let client = new huejay.Client({
			host: bridge,
			username: username
		});

		client.groups.getAll()
		.then(groups => {
			var allGroups = [];

			for (let group of groups)
			{
				var oneGroup = {};
				oneGroup.id = group.id;
				oneGroup.name = group.name;

				allGroups.push(oneGroup);
			}

			res.end(JSON.stringify(allGroups));
		})
		.catch(error => {
			res.send(500).send(error.stack);
		});
	});

	//
	// DISCOVER SCENES
	RED.httpAdmin.get('/hue/scenes', function(req, res, next)
	{
		let huejay = require('huejay');
		var bridge = (req.query.bridge).toString();
		var username = req.query.key;

		let client = new huejay.Client({
			host: bridge,
			username: username
		});

		client.scenes.getAll()
		.then(scenes => {
			var allScenes = [];

			for (let scene of scenes)
			{
				var oneScene = {};
				oneScene.id = scene.id;
				oneScene.name = scene.name;

				allScenes.push(oneScene);
			}

			res.end(JSON.stringify(allScenes));
		})
		.catch(error => {
			res.send(500).send(error.stack);
		});
	});

	//
	// DISCOVER RULES
	RED.httpAdmin.get('/hue/rules', function(req, res, next)
	{
		let huejay = require('huejay');
		var bridge = (req.query.bridge).toString();
		var username = req.query.key;

		let client = new huejay.Client({
			host: bridge,
			username: username
		});

		client.rules.getAll()
		.then(rules => {
			var allRules = [];

			for (let rule of rules)
			{
				var oneRule = {};
				oneRule.id = rule.id;
				oneRule.name = rule.name;

				allRules.push(oneRule);
			}

			res.end(JSON.stringify(allRules));
		})
		.catch(error => {
			res.send(500).send(error.stack);
		});
	});
};
<|endoftext|>


<commit_before>module.exports = {
    extends: 'eslint:recommended',
    env: {
        node: true,
        es6: true
    },
    parserOptions: {
        ecmaVersion: 6,
        sourceType: 'module'
    },
    rules: {
        // Best Practices
        'accessor-pairs': 2,
        'block-scoped-var': 2,
        'curly': 2,
        'default-case': 2,
        'dot-notation': 2,
        'dot-location': [2, 'property'],
        'eqeqeq': [2, 'allow-null'],
        'guard-for-in': 2,
        'no-alert': 2,
        'no-caller': 2,
        'no-div-regex': 2,
        'no-else-return': 2,
        'no-empty-function': 2,
        'no-empty-pattern': 2,
        'no-eval': 2,
        'no-extend-native': 2,
        'no-extra-bind': 2,
        'no-floating-decimal': 2,
        'no-implicit-coercion': 2,
        'no-implied-eval': 2,
        'no-iterator': 2,
        'no-labels': 2,
        'no-lone-blocks': 2,
        'no-loop-func': 2,
        'no-multi-spaces': 2,
        'no-native-reassign': 2,
        'no-new-func': 2,
        'no-new-wrappers': 2,
        'no-octal-escape': 2,
        'no-param-reassign': [2, { 'props': false }],
        'no-proto': 2,
        'no-return-assign': [2, 'always'],
        'no-script-url': 2,
        'no-self-compare': 2,
        'no-sequences': 2,
        'no-throw-literal': 2,
        'no-useless-call': 2,
        'no-useless-escape': 2,
        'no-void': 2,
        'no-with': 2,
        'radix': 2,
        'wrap-iife': [2, 'inside'],
        'no-unmodified-loop-condition': 2,
        'array-callback-return': 2,
        'yoda': 2,

        // Variables
        'no-label-var': 2,
        'no-shadow-restricted-names': 2,
        'no-undef-init': 2,
        'no-use-before-define': [2, 'nofunc'],

        // Node.js
        'callback-return': 2,
        'handle-callback-err': 1,
        'no-mixed-requires': [2, true],
        'no-new-require': 2,
        'no-path-concat': 2,
        'no-restricted-modules': [2, 'freelist', 'smalloc', 'sys'],

        // Stylistic Issues
        'array-bracket-spacing': [2, 'never'],
        'brace-style': [2, '1tbs'],
        'camelcase': 0,
        'comma-spacing': [2, { before: false, after: true }],
        'comma-style': [2, 'last'],
        'computed-property-spacing': [2, 'never'],
        'eol-last': 2,
        'indent': ['error', 4],
        'key-spacing': [2, { beforeColon: false, afterColon: true }],
        'linebreak-style': [2, 'unix'],
        'new-parens': 2,
        'no-array-constructor': 2,
        'no-lonely-if': 2,
        'no-multiple-empty-lines': [2, { max: 2 }],
        'no-nested-ternary': 2,
        'no-new-object': 2,
        'no-spaced-func': 2,
        'no-trailing-spaces': 2,
        'object-curly-spacing': [2, 'always'],
        'max-statements-per-line': [2, { max: 1 }],
        'one-var': [2, 'never'],
        'one-var-declaration-per-line': [2, 'always'],
        'operator-assignment': [2, 'always'],
        'operator-linebreak': [2, 'after'],
        'quotes': [2, 'single'],
        'space-before-blocks': [2, 'always'],
        'space-before-function-paren': [2, { anonymous: 'always', named: 'never' }],
        'space-in-parens': [2, 'never'],
        'space-infix-ops': 2,
        'space-unary-ops': 2,
        'keyword-spacing': 2,
        'no-whitespace-before-property': 2,
        'quote-props': [2, 'as-needed', { 'keywords': false, 'unnecessary': true, 'numbers': false }],

        // ECMAScript 6
        'arrow-parens': 2,
        'arrow-spacing': [2, { before: true, after: true }],
        'generator-star-spacing': [2, { 'before': false, 'after': true }],
        'no-confusing-arrow': 2,
        'no-duplicate-imports': 2,
        'no-var': 2,
        'no-useless-computed-key': 2,
        'no-useless-constructor': 2,
        'object-shorthand': 2,
        'prefer-const': 2,
        'prefer-spread': 2,
        'prefer-rest-params': 2,
        'prefer-template': 2,
        'template-curly-spacing': [2, 'never'],

        // Custom
        'no-underscore-dangle': 0,
        'no-console': 0,
        'semi': 0,
        'no-new': 0,

        // Complexity
        'max-depth': [2, 1],
        'max-params': [2, 3],
        'max-nested-callbacks': [2, 2],
        'max-statements': [2, 10],
        'complexity': [2, 6]
    }
};
<commit_msg>chore(auth): force no semicolons style<commit_after>module.exports = {
    extends: 'eslint:recommended',
    env: {
        node: true,
        es6: true
    },
    parserOptions: {
        ecmaVersion: 6,
        sourceType: 'module'
    },
    rules: {
        // Best Practices
        'accessor-pairs': 2,
        'block-scoped-var': 2,
        'curly': 2,
        'default-case': 2,
        'dot-notation': 2,
        'dot-location': [2, 'property'],
        'eqeqeq': [2, 'allow-null'],
        'guard-for-in': 2,
        'no-alert': 2,
        'no-caller': 2,
        'no-div-regex': 2,
        'no-else-return': 2,
        'no-empty-function': 2,
        'no-empty-pattern': 2,
        'no-eval': 2,
        'no-extend-native': 2,
        'no-extra-bind': 2,
        'no-floating-decimal': 2,
        'no-implicit-coercion': 2,
        'no-implied-eval': 2,
        'no-iterator': 2,
        'no-labels': 2,
        'no-lone-blocks': 2,
        'no-loop-func': 2,
        'no-multi-spaces': 2,
        'no-native-reassign': 2,
        'no-new-func': 2,
        'no-new-wrappers': 2,
        'no-octal-escape': 2,
        'no-param-reassign': [2, { 'props': false }],
        'no-proto': 2,
        'no-return-assign': [2, 'always'],
        'no-script-url': 2,
        'no-self-compare': 2,
        'no-sequences': 2,
        'no-throw-literal': 2,
        'no-useless-call': 2,
        'no-useless-escape': 2,
        'no-void': 2,
        'no-with': 2,
        'radix': 2,
        'wrap-iife': [2, 'inside'],
        'no-unmodified-loop-condition': 2,
        'array-callback-return': 2,
        'yoda': 2,

        // Variables
        'no-label-var': 2,
        'no-shadow-restricted-names': 2,
        'no-undef-init': 2,
        'no-use-before-define': [2, 'nofunc'],

        // Node.js
        'callback-return': 2,
        'handle-callback-err': 1,
        'no-mixed-requires': [2, true],
        'no-new-require': 2,
        'no-path-concat': 2,
        'no-restricted-modules': [2, 'freelist', 'smalloc', 'sys'],

        // Stylistic Issues
        'array-bracket-spacing': [2, 'never'],
        'brace-style': [2, '1tbs'],
        'camelcase': 0,
        'comma-spacing': [2, { before: false, after: true }],
        'comma-style': [2, 'last'],
        'computed-property-spacing': [2, 'never'],
        'eol-last': 2,
        'indent': ['error', 4],
        'key-spacing': [2, { beforeColon: false, afterColon: true }],
        'linebreak-style': [2, 'unix'],
        'new-parens': 2,
        'no-array-constructor': 2,
        'no-lonely-if': 2,
        'no-multiple-empty-lines': [2, { max: 2 }],
        'no-nested-ternary': 2,
        'no-new-object': 2,
        'no-spaced-func': 2,
        'no-trailing-spaces': 2,
        'object-curly-spacing': [2, 'always'],
        'max-statements-per-line': [2, { max: 1 }],
        'one-var': [2, 'never'],
        'one-var-declaration-per-line': [2, 'always'],
        'operator-assignment': [2, 'always'],
        'operator-linebreak': [2, 'after'],
        'quotes': [2, 'single'],
        'space-before-blocks': [2, 'always'],
        'space-before-function-paren': [2, { anonymous: 'always', named: 'never' }],
        'space-in-parens': [2, 'never'],
        'space-infix-ops': 2,
        'space-unary-ops': 2,
        'keyword-spacing': 2,
        'no-whitespace-before-property': 2,
        'quote-props': [2, 'as-needed', { 'keywords': false, 'unnecessary': true, 'numbers': false }],

        // ECMAScript 6
        'arrow-parens': 2,
        'arrow-spacing': [2, { before: true, after: true }],
        'generator-star-spacing': [2, { 'before': false, 'after': true }],
        'no-confusing-arrow': 2,
        'no-duplicate-imports': 2,
        'no-var': 2,
        'no-useless-computed-key': 2,
        'no-useless-constructor': 2,
        'object-shorthand': 2,
        'prefer-const': 2,
        'prefer-spread': 2,
        'prefer-rest-params': 2,
        'prefer-template': 2,
        'template-curly-spacing': [2, 'never'],

        // Custom
        'no-underscore-dangle': 0,
        'no-console': 0,
        'semi': [2, 'never'],
        'no-new': 0,

        // Complexity
        'max-depth': [2, 1],
        'max-params': [2, 3],
        'max-nested-callbacks': [2, 2],
        'max-statements': [2, 10],
        'complexity': [2, 6]
    }
};
<|endoftext|>


<commit_before>// Exports data as any supported format
// take in a format, file key, geojson, and callback
var fs = require('node-fs'),
  async = require('async');

module.exports = {
  ogrFormats: {
      kml: 'KML',
      zip: 'ESRI Shapefile',
      csv: 'CSV',
      gpkg: 'GPKG'
  },

  // exports large data via multi part file strategy
  exportLarge: function( format, id, key, type, options, done ){
    var self = this;

    options.limit = 10000;
    var pages,
      fileCount = 0;

    var dir = id +'_'+ (options.layer || 0),
      dbkey = type +':'+ id,
      table = dbkey +':'+ (options.layer || 0);

    // call ogr
    var callOGR = function(outFile, cmd, callback){
      config.worker.aspawn(cmd,
        function (err, stdout, stderr) {
          console.log('ogr2ogr done', err, stdout, stderr);
          if (err) {
            callback(err.message, null);
          } else {
            callback(null, outFile);
          }
      });
    };

    var vrt = '<OGRVRTDataSource>';

    var collect = function(file, json, callback){
      fileCount++;

      delete json.info;
      fs.writeFile(file, JSON.stringify(json), function(){
        vrt += '<OGRVRTLayer name="OGRGeoJSON"><SrcDataSource>'+file+'</SrcDataSource></OGRVRTLayer>';
        if (fileCount == pages){

          vrt += '</OGRVRTDataSource>';
          fs.writeFile(vrtFile, vrt, function(){
            // CALL OGR
            console.log('calling ogr2ogr - VRT to json', fs.existsSync(vrtFile) );
            var cmd = ['ogr2ogr', '-f', 'GeoJSON', '-append', jsonFile, vrtFile];
            callOGR(jsonFile, cmd, function(err, vrtOutFile){
              if (format == 'json' || format == 'geojson'){
                done(null, jsonFile.replace('geojson', 'json'));
              } else {
                //convert to format
                cmd = ['ogr2ogr', '-f', self.ogrFormats[format], newFile, vrtOutFile];
                callOGR(newFile, cmd, function(err, formatFile){
                  done(null, formatFile);
                });
              }
            });
          });
        }
        callback();
      });
    }

    var q = async.queue(function (task, cb) {
      var opts = {
        layer: options.layer,
        limit: options.limit,
        where: options.where,
        offset: task.offset,
        bypassProcessing: options.bypassProcessing
      };
      Cache.db.select(dbkey, opts, function(err, data){
        collect(task.file, data[0], cb);
      });
    }, 1);

    // make a dir for the files
    var path = [config.data_dir + 'files', dir].join('/');
    var base = path + '/' + key,
      vrtFile = base + '.vrt',
      jsonFile = base + '.json',
      newFile = base + '.' + format;

    // if we want json and it exists: return
    if ( fs.existsSync(jsonFile) && (format == 'json' || format == 'geojson') ){
      done(null, jsonFile);
    } else if (fs.existsSync(jsonFile)) {
      // if we already have the jsonfile and we want a diff format
      console.log('calling ogr');
      cmd = ['ogr2ogr', '-f', self.ogrFormats[format], newFile, jsonFile];
      callOGR(newFile, cmd, function(err, formatFile){
        done(null, formatFile);
      });
    } else {
      // we have nothing; generate new data
      fs.mkdir( base, '0777', true, function(){
        Cache.getCount(table, function(err, count){

          pages = Math.ceil(count / options.limit);

          for (var i = 0; i < pages; i++){
            var offset = i * (options.limit);
            q.push({ file: base+'/part.' + i + '.json', offset: offset }, function(){});
          }

        });
      });
    }

  },

  exportToFormat: function( format, dir, key, geojson, options, callback ){
    var self = this;

    // create the files for out output
    // we always create a json file, then use it to convert to a file
    var path = [config.data_dir + 'files', dir].join('/');
    var base = path + '/' + key,
      jsonFile = base + '.json';
      newFile = base + '.' + format;

    // executes OGR
    var _callOgr = function(inFile, outFile, callback){
      if (format == 'json' || format == 'geojson'){
        callback(null, outFile.replace('geojson', 'json'));
      } else if (self.ogrFormats[format]) {
        var cmd = ['ogr2ogr', '-f', self.ogrFormats[format], ( format == 'zip' ) ? outFile.replace('zip','shp') : outFile, inFile];
        if (format == 'csv') {
          if ( !geojson.features[0].geometry || geojson.features[0].geometry.type == 'Point'){
            cmd.push('-lco');
            cmd.push('GEOMETRY=AS_XY');
          }
        } else if (format == 'zip' || format == 'shp'){
          cmd.push('-lco');
          cmd.push('ENCODING=UTF-8');
        }
        if ( fs.existsSync( outFile ) ) {
          callback(null, outFile);
        } else {
          console.log('calling ogr2ogr');
          config.worker.aspawn(cmd,
            function (err, stdout, stderr) {
              console.log('ogr2ogr', err, stdout, stderr);
              if (err) {
                callback(err.message, null);
              } else {
                if ( format == 'zip' ){
                  // mkdir for base path (dir + key) to store shp
                  fs.mkdir( base, '0777', true, function(){
                    var shp = outFile.replace('zip','shp');
                    var dbf = outFile.replace('zip','dbf');
                    var shx = outFile.replace('zip','shx');
                    var prj = outFile.replace('zip','prj');
                    if ( options.name ){
                      // cp each file into dir with new name
                      fs.writeFileSync(base+'/' + options.name + '.shp', fs.readFileSync(shp));
                      fs.writeFileSync(base+'/' + options.name + '.dbf', fs.readFileSync(dbf));
                      fs.writeFileSync(base+'/' + options.name + '.shx', fs.readFileSync(shx));
                      fs.writeFileSync(base+'/' + options.name + '.prj', fs.readFileSync(prj));

                      // zip all and return the new zip
                      var newZip = base + '/' + options.name + '.zip';
                      config.worker.aspawn(['zip', '-rj', newZip, base+'/'], function(err, stdout, stderr){
                        callback(null, newZip);
                      });
                    } else {
                      config.worker.aspawn(['zip', '-j', outFile, shp, dbf, shx, prj], function(err, stdout, stderr){
                        callback(null, outFile);
                      });
                    }
                  });
                } else {
                  callback(null, outFile);
                }
              }
          });
        }
      } else {
        callback('Unknown format', null);
      }
    };

    // handles the response to callback
    var _send = function(err, file){
      if (err){
        callback( err, null );
      } else {
        // push the downloaded file up to s3
        if (peechee && peechee.type ){
          fs.readFile(file, function (err, data) {
            if ( format == 'zip' || format == 'gpkg' ){
              data = new Buffer(data, 'binary').toString('base64');
            }
            peechee.write(data, dir, key+'.'+format, function(err,res){
              if ( err ){
                callback('Problem saving file to s3: ' + err , null );
              } else {
                callback( null, file );
              }
            });
          });
        } else {
          callback(null, file);
        }
      }
    };

    fs.mkdir( path, '0777', true, function(){
      if ( !fs.existsSync( jsonFile ) ) {
        delete geojson.info;
        fs.writeFile( jsonFile, JSON.stringify( geojson ), function(){
          _callOgr( jsonFile, newFile, _send);
        });
      } else {
        _callOgr( jsonFile, newFile, _send) ;
      }
    });
  }
};
<commit_msg>status processing while files convert<commit_after>// Exports data as any supported format
// take in a format, file key, geojson, and callback
var fs = require('node-fs'),
  async = require('async');

module.exports = {
  ogrFormats: {
      kml: 'KML',
      zip: 'ESRI Shapefile',
      csv: 'CSV',
      gpkg: 'GPKG'
  },

  // exports large data via multi part file strategy
  exportLarge: function( format, id, key, type, options, done ){
    var self = this;

    options.limit = 10000;
    var pages,
      fileCount = 0;

    var dir = id +'_'+ (options.layer || 0),
      dbkey = type +':'+ id,
      table = dbkey +':'+ (options.layer || 0);

    var _update = function( info, cb ){
      Cache.updateInfo(table, info, function(err, success){
        cb();
      });
    };

    // call ogr in a separate process
    var callOGR = function(outFile, cmd, callback){
      config.worker.aspawn(cmd,function (err, stdout, stderr) {
        console.log('ogr2ogr done', err, stdout, stderr);
        callback(err, outFile);
      });
    };

    var vrt = '<OGRVRTDataSource>';

    var collect = function(file, json, callback){
      fileCount++;

      delete json.info;
      fs.writeFile(file, JSON.stringify(json), function(){
        vrt += '<OGRVRTLayer name="OGRGeoJSON"><SrcDataSource>'+file+'</SrcDataSource></OGRVRTLayer>';
        if (fileCount == pages){

          vrt += '</OGRVRTDataSource>';
          fs.writeFile(vrtFile, vrt, function(){
            // CALL OGR
            console.log('calling ogr2ogr - VRT to json', fs.existsSync(vrtFile) );
            var cmd = ['ogr2ogr', '-f', 'GeoJSON', '-append', jsonFile, vrtFile];
            callOGR(jsonFile, cmd, function(err, vrtOutFile){
              if (format == 'json' || format == 'geojson'){
                done(null, jsonFile.replace('geojson', 'json'));
              } else {
                //convert to format
                cmd = ['ogr2ogr', '-f', self.ogrFormats[format], newFile, vrtOutFile];
                callOGR(newFile, cmd, function(err, formatFile){
                  done(null, formatFile);
                });
              }
            });
          });
        }
        callback();
      });
    }

    var q = async.queue(function (task, cb) {
      var opts = {
        layer: options.layer,
        limit: options.limit,
        where: options.where,
        offset: task.offset,
        bypassProcessing: options.bypassProcessing
      };
      Cache.db.select(dbkey, opts, function(err, data){
        collect(task.file, data[0], cb);
      });
    }, 1);

    // make a dir for the files
    var path = [config.data_dir + 'files', dir].join('/');
    var base = path + '/' + key,
      vrtFile = base + '.vrt',
      jsonFile = base + '.json',
      newFile = base + '.' + format;

    // if we want json and it exists: return
    if ( fs.existsSync(jsonFile) && (format == 'json' || format == 'geojson') ){
      done(null, jsonFile);
    } else if (fs.existsSync(jsonFile)) {
      // if we already have the jsonfile and we want a diff format
      Cache.getInfo(table, function(err, info){
        info.status = 'processing';
        _update( info, function(err, res){
          done(null, info);

          console.log('calling ogr');
          cmd = ['ogr2ogr', '-f', self.ogrFormats[format], newFile, jsonFile];
          callOGR(newFile, cmd, function(err, formatFile){
             delete info.status;
             _update( info, function(e, res){});
          });
        });
      });
    } else {
      // we have nothing; generate new data
      fs.mkdir( base, '0777', true, function(){
        Cache.getCount(table, function(err, count){

          pages = Math.ceil(count / options.limit);

          for (var i = 0; i < pages; i++){
            var offset = i * (options.limit);
            q.push({ file: base+'/part.' + i + '.json', offset: offset }, function(){});
          }

        });
      });

    }

  },

  exportToFormat: function( format, dir, key, geojson, options, callback ){
    var self = this;

    // create the files for out output
    // we always create a json file, then use it to convert to a file
    var path = [config.data_dir + 'files', dir].join('/');
    var base = path + '/' + key,
      jsonFile = base + '.json';
      newFile = base + '.' + format;

    // executes OGR
    var _callOgr = function(inFile, outFile, callback){
      if (format == 'json' || format == 'geojson'){
        callback(null, outFile.replace('geojson', 'json'));
      } else if (self.ogrFormats[format]) {
        var cmd = ['ogr2ogr', '-f', self.ogrFormats[format], ( format == 'zip' ) ? outFile.replace('zip','shp') : outFile, inFile];
        if (format == 'csv') {
          if ( !geojson.features[0].geometry || geojson.features[0].geometry.type == 'Point'){
            cmd.push('-lco');
            cmd.push('GEOMETRY=AS_XY');
          }
        } else if (format == 'zip' || format == 'shp'){
          cmd.push('-lco');
          cmd.push('ENCODING=UTF-8');
        }
        if ( fs.existsSync( outFile ) ) {
          callback(null, outFile);
        } else {
          console.log('calling ogr2ogr');
          config.worker.aspawn(cmd,
            function (err, stdout, stderr) {
              console.log('ogr2ogr', err, stdout, stderr);
              if (err) {
                callback(err.message, null);
              } else {
                if ( format == 'zip' ){
                  // mkdir for base path (dir + key) to store shp
                  fs.mkdir( base, '0777', true, function(){
                    var shp = outFile.replace('zip','shp');
                    var dbf = outFile.replace('zip','dbf');
                    var shx = outFile.replace('zip','shx');
                    var prj = outFile.replace('zip','prj');
                    if ( options.name ){
                      // cp each file into dir with new name
                      fs.writeFileSync(base+'/' + options.name + '.shp', fs.readFileSync(shp));
                      fs.writeFileSync(base+'/' + options.name + '.dbf', fs.readFileSync(dbf));
                      fs.writeFileSync(base+'/' + options.name + '.shx', fs.readFileSync(shx));
                      fs.writeFileSync(base+'/' + options.name + '.prj', fs.readFileSync(prj));

                      // zip all and return the new zip
                      var newZip = base + '/' + options.name + '.zip';
                      config.worker.aspawn(['zip', '-rj', newZip, base+'/'], function(err, stdout, stderr){
                        callback(null, newZip);
                      });
                    } else {
                      config.worker.aspawn(['zip', '-j', outFile, shp, dbf, shx, prj], function(err, stdout, stderr){
                        callback(null, outFile);
                      });
                    }
                  });
                } else {
                  callback(null, outFile);
                }
              }
          });
        }
      } else {
        callback('Unknown format', null);
      }
    };

    // handles the response to callback
    var _send = function(err, file){
      if (err){
        callback( err, null );
      } else {
        // push the downloaded file up to s3
        if (peechee && peechee.type ){
          fs.readFile(file, function (err, data) {
            if ( format == 'zip' || format == 'gpkg' ){
              data = new Buffer(data, 'binary').toString('base64');
            }
            peechee.write(data, dir, key+'.'+format, function(err,res){
              if ( err ){
                callback('Problem saving file to s3: ' + err , null );
              } else {
                callback( null, file );
              }
            });
          });
        } else {
          callback(null, file);
        }
      }
    };

    fs.mkdir( path, '0777', true, function(){
      if ( !fs.existsSync( jsonFile ) ) {
        delete geojson.info;
        fs.writeFile( jsonFile, JSON.stringify( geojson ), function(){
          _callOgr( jsonFile, newFile, _send);
        });
      } else {
        _callOgr( jsonFile, newFile, _send) ;
      }
    });
  }
};
<|endoftext|>


<commit_before>var Storage = require('FuseJS/Storage');

var data = 'favorites';

/* ...
-----------------------------------------------------------------------------*/
var addFavorite
, deleteFavorite
, getFavorites;

/* Functions
-----------------------------------------------------------------------------*/
addFavorite = function(id) {
  var favorite = getFavorites();

  if (favorite === null) {
    favorite = {};
  }

  if (favorite[id]) {
    return;
  }

  favorite[id] = { name: 'woop' };
  Storage.writeSync(data, JSON.stringify(favorite));
}

deleteFavorite = function(id) {
  var favorite = getFavorites();

  if (favorite[id]) {
    delete favorite[id];
    Storage.writeSync(data, JSON.stringify(favorite));
  }
}

getFavorites = function() {
  var favorites = JSON.parse(Storage.readSync(data));
  if (favorites === null) {
    favorites = {};

    Storage.write(data, JSON.stringify(favorites));
  }

  return favorites;
}

/* Exports
-----------------------------------------------------------------------------*/
module.exports = {
  addFavorite: addFavorite,
  deleteFavorite: deleteFavorite,
  getFavorites: getFavorites
};
<commit_msg>Remove old code in addFavorite<commit_after>var Storage = require('FuseJS/Storage');

var data = 'favorites';

/* ...
-----------------------------------------------------------------------------*/
var addFavorite
, deleteFavorite
, getFavorites;

/* Functions
-----------------------------------------------------------------------------*/
addFavorite = function(id) {
  var favorite = getFavorites();

  if (favorite[id]) {
    return;
  }

  favorite[id] = { name: 'woop' };
  Storage.writeSync(data, JSON.stringify(favorite));
}

deleteFavorite = function(id) {
  var favorite = getFavorites();

  if (favorite[id]) {
    delete favorite[id];
    Storage.writeSync(data, JSON.stringify(favorite));
  }
}

getFavorites = function() {
  var favorites = JSON.parse(Storage.readSync(data));
  if (favorites === null) {
    favorites = {};

    Storage.write(data, JSON.stringify(favorites));
  }

  return favorites;
}

/* Exports
-----------------------------------------------------------------------------*/
module.exports = {
  addFavorite: addFavorite,
  deleteFavorite: deleteFavorite,
  getFavorites: getFavorites
};
<|endoftext|>


<commit_before>define(
    [
        'Chitin',
        '_'
    ],
    function (Chitin, _) {
        var WidgetAbstract = Chitin.Widget.extend({
            render: function (data) {
                var bus = this.bus,
                    prefAttrs = bus.prefs.attrs,
                    pair = prefAttrs.pair;

                data = _.extend(
                    data,
                    {
                        locale: bus.locale,
                        lang: {
                            'interface': prefAttrs.interface,
                            learn: pair ? pair.learn : '',
                            native: pair ? pair.native : ''
                        }
                    }
                );

                WidgetAbstract.__super__.render.call(this, data);
            }
        });

        return WidgetAbstract;
    }
);<commit_msg>support for touch events where appropriate<commit_after>define(
    [
        'Chitin',
        '_'
    ],
    function (Chitin, _) {
        var widgetPrototype = {
            render: function (data) {
                var bus = this.bus,
                    prefAttrs = bus.prefs.attrs,
                    pair = prefAttrs.pair,

                    commons = {
                        locale: bus.locale,
                        lang: {
                            'interface': prefAttrs.interface,
                            learn: pair ? pair.learn : '',
                            native: pair ? pair.native : ''
                        }
                    };

                data = _.extend(
                    data,
                    commons
                );

                WidgetAbstract.__super__.render.call(this, data);
            }
        };

        if ('ontouchend' in document) {
            widgetPrototype.delegateEvents = function (events) {
                if (!(events || (events = _.result(this, 'events')))) return;

                var touchEvents = {};
                _.each(events, function (value, key) {
                    var k = key;
                    if (key.substr(0, 6) == 'click ') {
                        k = key.replace(/^click /, 'touchend ');
                    }

                    touchEvents[k] = value
                });

                this._delegateEvents(touchEvents);
            }
        }

        /**
         * @class
         */
        var WidgetAbstract = Chitin.Widget.extend(widgetPrototype);

        return WidgetAbstract;
    }
);<|endoftext|>


<commit_before>function addCollection() {
    syncTree(function() {
        var newCollection = {
            text: $('#addCollectionName').val(),
            showBookmarkDescription: true,
            showBookmarkIcon: true,
            showBookmarksAsCards: false,
            bookmarkIconSize: 16
        };

        var selectedCollection = getSelectedCollection();

        if (typeof selectedCollection == 'undefined' || selectedCollection.id === "tree") {
            selectedCollection = newCollection;
            updateTree(selectedCollection);
        } else {
            if (typeof selectedCollection.nodes == 'undefined') {
                selectedCollection.nodes = [];
            }

            selectedCollection.nodes.push(newCollection);
            updateTree();
        }

        $('#addCollectionName').val("");
    });
}

function addBookmark() {
    syncTree(function(){
        var selectedCollection = getSelectedCollection();

        if (typeof selectedCollection.bookmarks == 'undefined') {
            selectedCollection.bookmarks = [];
        }

        var bookmark = {
            text: $('#addBookmarkName').val(),
            url: $('#addBookmarkUrl').val(),
            description: $('#addBookmarkDescription').val(),
            icon: "https://favicon.sboulema.nl/favicon?url=" + $('#addBookmarkUrl').val()
        };

        $.get(bookmark.icon + "&base64=true", function(data) {
            bookmark.iconData = data;
        });

        selectedCollection.bookmarks.push(bookmark);

        $('#addBookmarkName').val("");
        $('#addBookmarkUrl').val("");
        $('#addBookmarkDescription').val("");

        selectedCollection.tags = [selectedCollection.bookmarks.length];

        updateTree();
    });
}

function deleteBookmark() {
    var selectedCollection = getSelectedCollection();
    var bookmarkIndex = parseInt($("#editIndex").text());

    selectedCollection.bookmarks.splice(bookmarkIndex, 1);

    updateTree();
}

function deleteCollection() {
    var collection = getSelectedCollection();

    if (typeof collection.parentId != 'undefined') {
        var parent = tree.getDataById(collection.parentId);

        $.each(parent.nodes, function (index, node) {
            if (node.nodeId === collection.nodeId) {
                parent.nodes.splice(index, 1);
                updateTree();
                return false;
            }
        });
    } else {
        var index = getIndex(collection);
        var parent = getParent(collection)[0];

        if (parent.id === "tree") {
            var collections = getCollections();

            collections.splice(index, 1);

            updateTree(collections, true);
        } else {
            parent.nodes.slice(index, 1);

            updateTree();
        }
    }
}

function editBookmark(node, isCard) {
    var bookmark;
    var bookmarkIndex;

    // syncTree(function() {
        if (isCard) {
            bookmark = getSelectedBookmarkCard(node);
            bookmarkIndex = getIndexCard(node);
        } else {
            bookmark = getSelectedBookmark(node);
            bookmarkIndex = getIndex(node);
        }
        var selectedCollection = getSelectedCollection();

        $("#editName").val(bookmark.text);
        $("#editUrl").val(bookmark.url);
        $("#editIcon").val(bookmark.icon);
        $("#editIconAddon").attr("src", bookmark.icon);
        $("#editIndex").text(bookmarkIndex);
        $("#editDescription").val(bookmark.description);
        $("#editBookmarkCollection").val(selectedCollection.text);

        $('#editModal').modal('show');
    // });
}

function editCollection() {
    var selectedCollection = getSelectedCollection();

    syncTree(function() {
        $("#editCollectionName").val(selectedCollection.text);
        $("#editCollectionIcon").val(selectedCollection.icon);
        $("#editCollectionBackground").val(selectedCollection.background);
        $("#showBookmarkIconCheckbox").prop('checked', selectedCollection.showBookmarkIcon);
        $("#showBookmarkDescriptionCheckbox").prop('checked', selectedCollection.showBookmarkDescription);
        $("#bookmarkIconSizeSlider").val(selectedCollection.bookmarkIconSize);
        $("#showBookmarksAsCardsCheckbox").prop('checked', selectedCollection.showBookmarksAsCards);
        $("#editCollectionIconAddon").html("");

        $("#editIndex").text(getIndex(selectedCollection));
        $("#editCollectionParent").val(getParent(selectedCollection).text);

        $('#editCollectionModal').modal('show');
    });
}

function saveBookmark() {
    var selectedCollection = getSelectedCollection();
    var bookmarkIndex = parseInt($("#editIndex").text());

    selectedCollection.bookmarks[bookmarkIndex].text = $("#editName").val();
    selectedCollection.bookmarks[bookmarkIndex].url = $("#editUrl").val();
    selectedCollection.bookmarks[bookmarkIndex].icon = $("#editIcon").val();
    selectedCollection.bookmarks[bookmarkIndex].description = $("#editDescription").val();

    if ($("#editIcon").val().startsWith("https://favicon.sboulema.nl/favicon")) {
        $.get($("#editIcon").val() + "&base64=true", function(data) {
            selectedCollection.bookmarks[bookmarkIndex].iconData = data;
            updateTree();
        });
    }

    var moveToCollection = tree.getDataById($("#editMoveToCollection").text());

    if (typeof moveToCollection != 'undefined' &&
        typeof moveToCollection.nodeId != 'undefined' &&
        selectedCollection !== moveToCollection) {
        var bookmark = selectedCollection.bookmarks[bookmarkIndex];
        selectedCollection.bookmarks.splice(bookmarkIndex, 1);
        moveToCollection.bookmarks.push(bookmark);
        moveToCollection.tags = [moveToCollection.bookmarks.length];
        selectedCollection.tags = [selectedCollection.bookmarks.length];
    }

    updateTree();
}

function saveCollection() {
    var selectedCollection = getSelectedCollection();

    selectedCollection.text = $("#editCollectionName").val();
    selectedCollection.icon = $("#editCollectionIcon").val();
    selectedCollection.background = $("#editCollectionBackground").val();
    selectedCollection.showBookmarkIcon = $("#showBookmarkIconCheckbox").is(':checked');
    selectedCollection.showBookmarkDescription = $("#showBookmarkDescriptionCheckbox").is(':checked');
    selectedCollection.bookmarkIconSize = $("#bookmarkIconSizeSlider").val();
    selectedCollection.showBookmarksAsCards = $("#showBookmarksAsCardsCheckbox").is(':checked');

    // Check if we need to move the collection to a new parent
    var moveToCollection = tree.getDataByText($("#editMoveToCollection").text());
    var parentCollection = getParent(selectedCollection)[0];

    if (typeof moveToCollection != 'undefined' &&
        typeof moveToCollection.nodeId != 'undefined' &&
        moveToCollection !== parentCollection) {
        var copyCollection = $.extend(true, {}, selectedCollection);

        if (typeof moveToCollection.nodes == 'undefined') {
            moveToCollection.nodes = [];
        }

        moveToCollection.nodes.push(copyCollection);

        deleteCollection();
    }

    updateTree();
}

function getAllBookmarks() {
    var bookmarks = [];
    return search(getCollections(), "bookmarks", bookmarks);
}

search = function(hay, needle, accumulator) {
  var accumulator = accumulator || [];
  if (typeof hay == 'object') {
    for (var i in hay) {
        if (i === needle) {
            $.merge(accumulator, hay[i]);
        }
        search(hay[i], needle, accumulator) == true ? accumulator.push(hay) : 1;
    }
  }
  return new RegExp(needle).test(hay) || accumulator;
}

function showAllBookmarks() {
    $("#collectionName").attr("placeholder", "All bookmarks");

    $("#collectionIcon").html("");

    $("#accordion").empty();
    $('#bookmarks').empty();

    var collection = {
        bookmarks: getAllBookmarks(),
        showBookmarkIcon: true,
        showBookmarkDescription: true,
        bookmarkIconSize: 16
    };

    $("#bookmarks").html(showBookmarks(collection));
}

function showBookmarks(collection, showAsCards) {
    var bookmarksHtml = "";

    if (collection.showBookmarksAsCards) {
        $.each(collection.bookmarks, function (index, bookmark) {
            var item = "
";

            item += "";
            if (typeof bookmark.icon != 'undefined' && bookmark.icon !== "" && !bookmark.icon.startsWith("fa")) {
                item += "";
            } else {
                item += "";
            }
            item += "";

            item += "<button type='button' class='btn btn-primary btn-sm cardEditButton' onclick='editBookmark(this, true)'>" +
                "</button>";

            item += "
";

            bookmarksHtml += item;
        });

    } else {
        $.each(collection.bookmarks, function (index, bookmark) {

            var item = "
";
            item += "
";

            item += "
";

            if (collection.showBookmarkIcon) {
                if (typeof bookmark.icon != 'undefined' && bookmark.icon !== "" && !bookmark.icon.startsWith("fa")) {
                    item += "";
                    item += "" + bookmark.text + "";
                } else {
                    item += "";
                    item += "" + bookmark.text + "";
                }
            }

            if (collection.showBookmarkDescription && typeof bookmark.description != 'undefined' && bookmark.description != "") {
                item += " - " + bookmark.description + "";
            }

            item += "
";

            item += createBookmarkButtons(bookmark);

            item += "
";
            item += "
"

            bookmarksHtml += item;
        });
    }

    return bookmarksHtml;
}

function createBookmarkButtons(bookmark) {
    var buttons = $("
", {
        class: "col-auto btn-toolbar",
        role: "toolbar"
    });

    buttons.append(
        "
" +
        "<button type='button' class='btn btn-outline-secondary btn-sm' onclick='editBookmark(this)'>" +
        "</button>" +
        "
"
    );

    var copyButton = $(
        "
" +
        "<button type='button' class='btn btn-outline-secondary btn-sm btn-clipboard' data-clipboard-text='" +
        bookmark.url +  "'>" + "</button>" +
        "
"
    ).appendTo(buttons);

    if (navigator.share) {
        copyButton.addClass("mr-2");

        buttons.append(
            "
" +
            "<button type='button' class='btn btn-outline-secondary btn-sm' onclick='shareBookmark(this)'>" +
            "</button>" +
            "
"
        );
    }

    return buttons.html();
}

function shareBookmark(bookmark) {
    navigator.share({
        title: bookmark.text,
        text: bookmark.description,
        url: bookmark.url,
    })
      .then(() => console.log('Successful share'))
      .catch((error) => console.log('Error sharing', error));
}

function getCollectionBackground(collection) {
    if (typeof collection !== 'undefined' &&
        typeof collection.background !== 'undefined' &&
        collection.background !== "inherit") {
        return collection.background;
    }

    if (collection.id === "tree") {
        return "";
    }

    return getCollectionBackground(getParent(collection));
}

function getParent(collection) {
    var parent = tree.getDataById(collection.parentId);

    if (parent.length === 1) {
        return parent[0];
    }

    return parent;
}<commit_msg>Fix sharing bookmark?<commit_after>function addCollection() {
    syncTree(function() {
        var newCollection = {
            text: $('#addCollectionName').val(),
            showBookmarkDescription: true,
            showBookmarkIcon: true,
            showBookmarksAsCards: false,
            bookmarkIconSize: 16
        };

        var selectedCollection = getSelectedCollection();

        if (typeof selectedCollection == 'undefined' || selectedCollection.id === "tree") {
            selectedCollection = newCollection;
            updateTree(selectedCollection);
        } else {
            if (typeof selectedCollection.nodes == 'undefined') {
                selectedCollection.nodes = [];
            }

            selectedCollection.nodes.push(newCollection);
            updateTree();
        }

        $('#addCollectionName').val("");
    });
}

function addBookmark() {
    syncTree(function(){
        var selectedCollection = getSelectedCollection();

        if (typeof selectedCollection.bookmarks == 'undefined') {
            selectedCollection.bookmarks = [];
        }

        var bookmark = {
            text: $('#addBookmarkName').val(),
            url: $('#addBookmarkUrl').val(),
            description: $('#addBookmarkDescription').val(),
            icon: "https://favicon.sboulema.nl/favicon?url=" + $('#addBookmarkUrl').val()
        };

        $.get(bookmark.icon + "&base64=true", function(data) {
            bookmark.iconData = data;
        });

        selectedCollection.bookmarks.push(bookmark);

        $('#addBookmarkName').val("");
        $('#addBookmarkUrl').val("");
        $('#addBookmarkDescription').val("");

        selectedCollection.tags = [selectedCollection.bookmarks.length];

        updateTree();
    });
}

function deleteBookmark() {
    var selectedCollection = getSelectedCollection();
    var bookmarkIndex = parseInt($("#editIndex").text());

    selectedCollection.bookmarks.splice(bookmarkIndex, 1);

    updateTree();
}

function deleteCollection() {
    var collection = getSelectedCollection();

    if (typeof collection.parentId != 'undefined') {
        var parent = tree.getDataById(collection.parentId);

        $.each(parent.nodes, function (index, node) {
            if (node.nodeId === collection.nodeId) {
                parent.nodes.splice(index, 1);
                updateTree();
                return false;
            }
        });
    } else {
        var index = getIndex(collection);
        var parent = getParent(collection)[0];

        if (parent.id === "tree") {
            var collections = getCollections();

            collections.splice(index, 1);

            updateTree(collections, true);
        } else {
            parent.nodes.slice(index, 1);

            updateTree();
        }
    }
}

function editBookmark(node, isCard) {
    var bookmark;
    var bookmarkIndex;

    // syncTree(function() {
        if (isCard) {
            bookmark = getSelectedBookmarkCard(node);
            bookmarkIndex = getIndexCard(node);
        } else {
            bookmark = getSelectedBookmark(node);
            bookmarkIndex = getIndex(node);
        }
        var selectedCollection = getSelectedCollection();

        $("#editName").val(bookmark.text);
        $("#editUrl").val(bookmark.url);
        $("#editIcon").val(bookmark.icon);
        $("#editIconAddon").attr("src", bookmark.icon);
        $("#editIndex").text(bookmarkIndex);
        $("#editDescription").val(bookmark.description);
        $("#editBookmarkCollection").val(selectedCollection.text);

        $('#editModal').modal('show');
    // });
}

function editCollection() {
    var selectedCollection = getSelectedCollection();

    syncTree(function() {
        $("#editCollectionName").val(selectedCollection.text);
        $("#editCollectionIcon").val(selectedCollection.icon);
        $("#editCollectionBackground").val(selectedCollection.background);
        $("#showBookmarkIconCheckbox").prop('checked', selectedCollection.showBookmarkIcon);
        $("#showBookmarkDescriptionCheckbox").prop('checked', selectedCollection.showBookmarkDescription);
        $("#bookmarkIconSizeSlider").val(selectedCollection.bookmarkIconSize);
        $("#showBookmarksAsCardsCheckbox").prop('checked', selectedCollection.showBookmarksAsCards);
        $("#editCollectionIconAddon").html("");

        $("#editIndex").text(getIndex(selectedCollection));
        $("#editCollectionParent").val(getParent(selectedCollection).text);

        $('#editCollectionModal').modal('show');
    });
}

function saveBookmark() {
    var selectedCollection = getSelectedCollection();
    var bookmarkIndex = parseInt($("#editIndex").text());

    selectedCollection.bookmarks[bookmarkIndex].text = $("#editName").val();
    selectedCollection.bookmarks[bookmarkIndex].url = $("#editUrl").val();
    selectedCollection.bookmarks[bookmarkIndex].icon = $("#editIcon").val();
    selectedCollection.bookmarks[bookmarkIndex].description = $("#editDescription").val();

    if ($("#editIcon").val().startsWith("https://favicon.sboulema.nl/favicon")) {
        $.get($("#editIcon").val() + "&base64=true", function(data) {
            selectedCollection.bookmarks[bookmarkIndex].iconData = data;
            updateTree();
        });
    }

    var moveToCollection = tree.getDataById($("#editMoveToCollection").text());

    if (typeof moveToCollection != 'undefined' &&
        typeof moveToCollection.nodeId != 'undefined' &&
        selectedCollection !== moveToCollection) {
        var bookmark = selectedCollection.bookmarks[bookmarkIndex];
        selectedCollection.bookmarks.splice(bookmarkIndex, 1);
        moveToCollection.bookmarks.push(bookmark);
        moveToCollection.tags = [moveToCollection.bookmarks.length];
        selectedCollection.tags = [selectedCollection.bookmarks.length];
    }

    updateTree();
}

function saveCollection() {
    var selectedCollection = getSelectedCollection();

    selectedCollection.text = $("#editCollectionName").val();
    selectedCollection.icon = $("#editCollectionIcon").val();
    selectedCollection.background = $("#editCollectionBackground").val();
    selectedCollection.showBookmarkIcon = $("#showBookmarkIconCheckbox").is(':checked');
    selectedCollection.showBookmarkDescription = $("#showBookmarkDescriptionCheckbox").is(':checked');
    selectedCollection.bookmarkIconSize = $("#bookmarkIconSizeSlider").val();
    selectedCollection.showBookmarksAsCards = $("#showBookmarksAsCardsCheckbox").is(':checked');

    // Check if we need to move the collection to a new parent
    var moveToCollection = tree.getDataByText($("#editMoveToCollection").text());
    var parentCollection = getParent(selectedCollection)[0];

    if (typeof moveToCollection != 'undefined' &&
        typeof moveToCollection.nodeId != 'undefined' &&
        moveToCollection !== parentCollection) {
        var copyCollection = $.extend(true, {}, selectedCollection);

        if (typeof moveToCollection.nodes == 'undefined') {
            moveToCollection.nodes = [];
        }

        moveToCollection.nodes.push(copyCollection);

        deleteCollection();
    }

    updateTree();
}

function getAllBookmarks() {
    var bookmarks = [];
    return search(getCollections(), "bookmarks", bookmarks);
}

search = function(hay, needle, accumulator) {
  var accumulator = accumulator || [];
  if (typeof hay == 'object') {
    for (var i in hay) {
        if (i === needle) {
            $.merge(accumulator, hay[i]);
        }
        search(hay[i], needle, accumulator) == true ? accumulator.push(hay) : 1;
    }
  }
  return new RegExp(needle).test(hay) || accumulator;
}

function showAllBookmarks() {
    $("#collectionName").attr("placeholder", "All bookmarks");

    $("#collectionIcon").html("");

    $("#accordion").empty();
    $('#bookmarks').empty();

    var collection = {
        bookmarks: getAllBookmarks(),
        showBookmarkIcon: true,
        showBookmarkDescription: true,
        bookmarkIconSize: 16
    };

    $("#bookmarks").html(showBookmarks(collection));
}

function showBookmarks(collection, showAsCards) {
    var bookmarksHtml = "";

    if (collection.showBookmarksAsCards) {
        $.each(collection.bookmarks, function (index, bookmark) {
            var item = "
";

            item += "";
            if (typeof bookmark.icon != 'undefined' && bookmark.icon !== "" && !bookmark.icon.startsWith("fa")) {
                item += "";
            } else {
                item += "";
            }
            item += "";

            item += "<button type='button' class='btn btn-primary btn-sm cardEditButton' onclick='editBookmark(this, true)'>" +
                "</button>";

            item += "
";

            bookmarksHtml += item;
        });

    } else {
        $.each(collection.bookmarks, function (index, bookmark) {

            var item = "
";
            item += "
";

            item += "
";

            if (collection.showBookmarkIcon) {
                if (typeof bookmark.icon != 'undefined' && bookmark.icon !== "" && !bookmark.icon.startsWith("fa")) {
                    item += "";
                    item += "" + bookmark.text + "";
                } else {
                    item += "";
                    item += "" + bookmark.text + "";
                }
            }

            if (collection.showBookmarkDescription && typeof bookmark.description != 'undefined' && bookmark.description != "") {
                item += " - " + bookmark.description + "";
            }

            item += "
";

            item += createBookmarkButtons(bookmark);

            item += "
";
            item += "
"

            bookmarksHtml += item;
        });
    }

    return bookmarksHtml;
}

function createBookmarkButtons(bookmark) {
    var buttons = $("
", {
        class: "col-auto btn-toolbar",
        role: "toolbar"
    });

    buttons.append(
        "
" +
        "<button type='button' class='btn btn-outline-secondary btn-sm' onclick='editBookmark(this)'>" +
        "</button>" +
        "
"
    );

    var copyButton = $(
        "
" +
        "<button type='button' class='btn btn-outline-secondary btn-sm btn-clipboard' data-clipboard-text='" +
        bookmark.url +  "'>" + "</button>" +
        "
"
    ).appendTo(buttons);

    if (navigator.share) {
        copyButton.addClass("mr-2");

        buttons.append(
            "
" +
            "<button type='button' class='btn btn-outline-secondary btn-sm' onclick='shareBookmark(this)'>" +
            "</button>" +
            "
"
        );
    }

    return buttons.html();
}

function shareBookmark(node) {
    var bookmark = getSelectedBookmark(node);

    navigator.share({
        title: bookmark.text,
        text: bookmark.description,
        url: bookmark.url,
    })
      .then(() => console.log('Successful share'))
      .catch((error) => console.log('Error sharing', error));
}

function getCollectionBackground(collection) {
    if (typeof collection !== 'undefined' &&
        typeof collection.background !== 'undefined' &&
        collection.background !== "inherit") {
        return collection.background;
    }

    if (collection.id === "tree") {
        return "";
    }

    return getCollectionBackground(getParent(collection));
}

function getParent(collection) {
    var parent = tree.getDataById(collection.parentId);

    if (parent.length === 1) {
        return parent[0];
    }

    return parent;
}<|endoftext|>