<commit_before>import mongoose from 'mongoose'
import Node from '../model/node'
import rank from './rank'

import {
  HTTP_OK,
  HTTP_CREATED,
  HTTP_NOT_FOUND,
  HTTP_BAD_REQUEST,
  HTTP_INTERNAL_SERVER_ERROR,
} from '../../../shared/config'

/* eslint no-underscore-dangle: ["error", { "allow": ["_id"] }] */

mongoose.set('debug', true)

exports.findAll = (req, res/* , next*/) => {
  Node.find({}, (err, nodes) => {
    if (err) {
      return res.status(HTTP_NOT_FOUND).send(err)
    }
    req.nodes = nodes
    return res.status(HTTP_OK).json(nodes)
    // next()
  })
}

exports.findById = (req, res, next) => {
  if (req.params.id) {
    Node.findOne({ _id: req.params.id }, (err, node) => {
      if (err) {
        return res.status(HTTP_NOT_FOUND).send(err)
      }
      req.node = node
      // res.status(HTTP_OK).json(node)
      return next()
    })
  } else {
    res.status(HTTP_BAD_REQUEST).send('No node id')
  }
}

exports.add = (req, res) => {
  // if (req.body.node.mId !== ('' || null)) {
  //   req.body.node._id = req.body.node.mId
  // }
  const newNode = new Node(req.body.node)
  newNode.mRank = rank.calcRank(newNode.mId)
  newNode.mTimeStampRankFromServer = new Date()
  try {
    newNode.save((err) => {
      if (err) {
        return res.send(err)
      }
      req.node = newNode
      return res.status(HTTP_CREATED).json({ message: 'Node added!' })
    })
  } catch (ex) {
    res.status(HTTP_INTERNAL_SERVER_ERROR).send(ex)
  }
}

exports.update = (req, res, next) => {
  if (req.params.id) {
    console.log(`Type of node: ${typeof req.body.node}`)
    console.log(`node before parse:\n${req.body.node}`)
    if (typeof req.body.node === 'string' || req.body.node instanceof String) {
      req.body.node = JSON.parse(req.body.node)
    }
    console.log(`node after parse:\n${req.body.node}`)
    // if (req.body.node.mId !== ('' || null)) {
    // if (req.body.node.mId !== ('' || null)) {
    //   req.body.node._id = req.body.node.mId
    // }
    // }
    // console.log(`req.body: ${req.body}`)
    // const newNode = new Node(req.body.node)
    // newNode.mRank = rank.calcRank(newNode._id)
    // newNode.mTimeStampRankFromServer = new Date()
    // delete newNode._id
    req.body.node.mRank = rank.calcRank(req.params.id)
    req.body.node.mTimeStampRankFromServer = new Date()
    Node.findOneAndUpdate({ mId: req.params.id }, req.body.node, { new: true, upsert: true },
    (err, node) => {
      if (err) {
        if (err.code === 11000) {
          // Another upsert occurred during the upsert, try again. You could omit the
          // upsert option here if you don't ever delete docs while this is running.
          // Monitor.update({ _id: minute }, { $inc: update }, { upsert: true },
          Node.findOneAndUpdate({ mId: req.params.id }, req.body.node, { new: true, upsert: true },
          (error, updatednode) => {
            if (error) {
              console.trace(err)
              return res.status(HTTP_INTERNAL_SERVER_ERROR).send(err)
            }
            req.node = updatednode
            return next()
          })
        }
      }
      req.node = node
      return next()
    })
  } else {
    res.status(HTTP_BAD_REQUEST).send('No node id')
  }
}

exports.delete = (req, res) => {
  if (req.params.id) {
    Node.remove({
      mId: req.params.id,
    }, (err) => {
      if (err) {
        return res.send(err)
      }
      req.node = null
      return res.status(HTTP_OK).json({ message: `Node ${req.params.id} successfully deleted` })
    })
  } else {
    res.status(HTTP_BAD_REQUEST).send('No node id')
  }
}

exports.graph = (req, res, next) => {
  if (!req.node) { return res.status(HTTP_BAD_REQUEST).json('Must specify node') }
  // Suppose we have a collection of courses, where a document might look like
  // `{ _id: 0, name: 'Calculus', prerequisite: 'Trigonometry'}` and
  // `{ _id: 0, name: 'Trigonometry', prerequisite: 'Algebra' }`
  Node.aggregate({ $match: { mId: req.node.id } }).graphLookup({
    from: 'relations',
    startWith: '$mId',
    connectFromField: 'relations',
    connectToField: 'node',
    as: 'relations',
    maxDepth: req.node.mRank,
    depthField: 'nodeDegree' },
    (err, result) => {
      if (err) {
        console.error(err)
        return res.status(HTTP_NOT_FOUND).json('Node graph not found')
      }
      console.log(`Graph: ${result}`)
      req.graph = result
      return next()
    }).exec()
  console.log(`Graph: ${req.graph}`)
  return res.status(HTTP_INTERNAL_SERVER_ERROR).json('Couldnt perform aggregation')
}
<commit_msg>Sync Node<commit_after>import mongoose from 'mongoose'
import Node from '../model/node'
import rank from './rank'

import {
  HTTP_OK,
  HTTP_CREATED,
  HTTP_NOT_FOUND,
  HTTP_BAD_REQUEST,
  HTTP_INTERNAL_SERVER_ERROR,
} from '../../../shared/config'

/* eslint no-underscore-dangle: ["error", { "allow": ["_id"] }] */

mongoose.set('debug', true)

exports.findAll = (req, res/* , next*/) => {
  Node.find({}, (err, nodes) => {
    if (err) {
      return res.status(HTTP_NOT_FOUND).send(err)
    }
    req.nodes = nodes
    return res.status(HTTP_OK).json(nodes)
    // next()
  })
}

exports.findById = (req, res, next) => {
  if (req.params.id) {
    Node.findOne({ _id: req.params.id }, (err, node) => {
      if (err) {
        return res.status(HTTP_NOT_FOUND).send(err)
      }
      req.node = node
      // res.status(HTTP_OK).json(node)
      return next()
    })
  } else {
    res.status(HTTP_BAD_REQUEST).send('No node id')
  }
}

exports.add = (req, res) => {
  // if (req.body.node.mId !== ('' || null)) {
  //   req.body.node._id = req.body.node.mId
  // }
  const newNode = new Node(req.body.node)
  newNode.mRank = rank.calcRank(newNode.mId)
  newNode.mTimeStampRankFromServer = new Date()
  try {
    newNode.save((err) => {
      if (err) {
        return res.send(err)
      }
      req.node = newNode
      return res.status(HTTP_CREATED).json({ message: 'Node added!' })
    })
  } catch (ex) {
    res.status(HTTP_INTERNAL_SERVER_ERROR).send(ex)
  }
}

exports.update = (req, res, next) => {
  if (req.params.id) {
    if (typeof req.body.node === 'string' || req.body.node instanceof String) {
      req.body.node = JSON.parse(req.body.node)
    }
    req.body.node.mRank = rank.calcRank(req.params.id)
    req.body.node.mTimeStampRankFromServer = new Date()
    Node.findOneAndUpdate({ mId: req.params.id }, req.body.node, { new: true, upsert: true },
    (err, node) => {
      if (err) {
        if (err.code === 11000) {
          // Another upsert occurred during the upsert, try again. You could omit the
          // upsert option here if you don't ever delete docs while this is running.
          Node.findOneAndUpdate({ mId: req.params.id }, req.body.node, { new: true, upsert: true },
          (error, updatednode) => {
            if (error) {
              console.trace(err)
              return next(error)
            }
            req.node = updatednode
            return next()
          })
        }
      }
      req.node = node
      return next()
    })
  } else {
    res.status(HTTP_BAD_REQUEST).send('No node id')
  }
}

exports.delete = (req, res) => {
  if (req.params.id) {
    Node.remove({
      mId: req.params.id,
    }, (err) => {
      if (err) {
        return res.send(err)
      }
      req.node = null
      return res.status(HTTP_OK).json({ message: `Node ${req.params.id} successfully deleted` })
    })
  } else {
    res.status(HTTP_BAD_REQUEST).send('No node id')
  }
}

exports.graph = (req, res, next) => {
  if (!req.node) { return res.status(HTTP_BAD_REQUEST).json('Must specify node') }
  // Suppose we have a collection of courses, where a document might look like
  // `{ _id: 0, name: 'Calculus', prerequisite: 'Trigonometry'}` and
  // `{ _id: 0, name: 'Trigonometry', prerequisite: 'Algebra' }`
  Node.aggregate({ $match: { mId: req.node.id } }).graphLookup({
    from: 'relations',
    startWith: '$mId',
    connectFromField: 'relations',
    connectToField: 'node',
    as: 'relations',
    maxDepth: req.node.mRank,
    depthField: 'nodeDegree' },
    (err, result) => {
      if (err) {
        console.error(err)
        return res.status(HTTP_NOT_FOUND).json('Node graph not found')
      }
      console.log(`Graph: ${result}`)
      req.graph = result
      return next()
    }).exec()
  console.log(`Graph: ${req.graph}`)
  return res.status(HTTP_INTERNAL_SERVER_ERROR).json('Couldnt perform aggregation')
}
<|endoftext|>


<commit_before>Ball.Preloader = function(game) {};
Ball.Preloader.prototype = {
	preload: function() {
		this.preloadBg = this.add.sprite((Ball._WIDTH-297)*0.5, (Ball._HEIGHT-145)*0.5, 'preloaderBg');
		this.preloadBar = this.add.sprite((Ball._WIDTH-158)*0.5, (Ball._HEIGHT-50)*0.5, 'preloaderBar');
		this.load.setPreloadSprite(this.preloadBar);

		this.load.image('ball', 'img/tapon.png');

		this.load.image('title', 'img/title.png');

		this.load.image('screen-bg', 'img/fondo.png');
		this.load.image('screen-mainmenu', 'img/screen-mainmenu.png');
		this.load.image('screen-howtoplay', 'img/screen-howtoplay.png');
		this.load.image('border-horizontal', 'img/border-horizontal.png');
		this.load.image('border-vertical', 'img/border-vertical.png');

		this.load.spritesheet('button-start', 'img/button-start.png', 146, 51);

	},
	create: function() {
		if ('addEventListener' in document) {
		    document.addEventListener('deviceready', function() {
        	Ball._DISPOSITIVO=true;
        	this.game.state.start('MainMenu');
    		}, false);

	}

	}
};<commit_msg>Estructura completada y funcionando.<commit_after>Ball.Preloader = function(game) {};
Ball.Preloader.prototype = {
	preload: function() {
		this.preloadBg = this.add.sprite((Ball._WIDTH-297)*0.5, (Ball._HEIGHT-145)*0.5, 'preloaderBg');
		this.preloadBar = this.add.sprite((Ball._WIDTH-158)*0.5, (Ball._HEIGHT-50)*0.5, 'preloaderBar');
		this.load.setPreloadSprite(this.preloadBar);

		this.load.image('ball', 'img/tapon.png');

		this.load.image('title', 'img/title.png');

		this.load.image('screen-bg', 'img/fondo.png');
		this.load.image('screen-mainmenu', 'img/screen-mainmenu.png');
		this.load.image('screen-howtoplay', 'img/screen-howtoplay.png');
		this.load.image('border-horizontal', 'img/border-horizontal.png');
		this.load.image('border-vertical', 'img/border-vertical.png');

		this.load.spritesheet('button-start', 'img/button-start.png', 146, 51);

	},
	create: function() {
		this.game.state.start('MainMenu');

	}
};

if ('addEventListener' in document) {
		    document.addEventListener('deviceready', function() {
        	Ball._DISPOSITIVO=true;
        	alert("en preload");
			}, false);

	}<|endoftext|>


<commit_before>window.TestServ = function(name) {
  var _this = this;

  if (!!name) {
    inject([name, function(service) {
      _this = service;
    }]);
    return _this;
  }
};

window.TestServ.prototype = {
  addPromise: function(name) {
    var _this = this;
    _this[name] = function() {};
    spyOn(_this, name).and.returnValue({
      then: function(success, fail) {
        _this[name].success = success;
        _this[name].fail = fail;
      }
    });
    return this;
  },

  addMethod: function(name, returnedValue) {
    if (typeof returnedValue === "function" ) {
      this[name] = returnedValue;
      spyOn(this, name).and.callThrough();
    } else {
      this[name] = angular.noop;
      spyOn(this, name).and.returnValue(returnedValue !== undefined ? returnedValue : this);
    }
    return this;
  },

  addProperty: function(name, returnedValue) {
    this[name] = returnedValue;
    return this;
  }
};

window.TestElement = function() {
  var _this = this;
  inject(function($rootScope, $compile, $timeout, $controller, $templateCache, $filter) {
    _this._$scope = $rootScope.$new();
    _this.$originalScope = $rootScope.$new();
    _this.$compile = $compile;
    _this.$timeout = $timeout;
    _this.$controller = $controller;
    _this.$templateCache = $templateCache;
    _this.$filter = $filter;
  });
  this.name = '';
};

window.TestElement.prototype = {
  createCtrl: function(name, services) {
    if (!services) {
      services = {};
    }
    if (!services.$scope) {
      services.$scope = this._$scope;
    }
    this._ctrl = this.$controller(name, services);
    return this._ctrl;
  },

  addTemplate: function(path, ctrlAs) {
    var template;
    template = this.$templateCache.get(path);
    this._el = angular.element(template);

    if (!!ctrlAs) {
      this._$scope[ctrlAs] = this._ctrl;
    }

    this.$compile(this._el)(this._$scope);
    this._$scope.$digest();

    try {
      this.$timeout.verifyNoPendingTasks();
    } catch (e) {
      this.$timeout.flush();
    }

    return this._el;
  },

  createDirective: function(name, html, scope) {
    this.name = name;
    var elem = angular.element(html);
    this._$scope = angular.extend(this.$originalScope, scope);
    this._el = this.$compile(elem)(this._$scope);
    this._$scope.$digest();

    try {
      this.$timeout.verifyNoPendingTasks();
    } catch (e) {
      this.$timeout.flush();
    }
    return this._el;
  },

  createComponent: function(name, html, scope) {
    this.createDirective(name, html, scope);
    return this._el;
  },

  createFilter: function(name) {
    return this.$filter(name);
  },

  get scope() {
    return this._ctrl ?
      this._$scope : Object.keys(this.dom.children()).length ?
        this.dom.children().scope() : this.dom.scope();
  },

  get ctrl() {
    return this._ctrl ? this._ctrl : angular.element(this._el).controller(this.name);
  },

  get dom() {
    return angular.element(this._el);
  },

  find: function (selector) {
    return angular.element(this.dom[0].querySelector(selector));
  },

  findAll: function (selector) {
    var htmlObject = this.dom[0].querySelectorAll(selector);
    var returnedArray = [];
    for (var property in htmlObject) {
      if (htmlObject.hasOwnProperty(property) && typeof htmlObject[property] !== 'number') {
        returnedArray.push(angular.element(htmlObject[property]));
      }
    }
    return returnedArray;
  },

  destroy: function() {
    this._$scope.$destroy();
    this._el = null;
    this._ctrl = null;
  },

  clickOn: function(selector) {
    if (this.dom[0].querySelector(selector)) {
      this.dom[0].querySelector(selector).click();
    } else {
      this.dom[0].click();
    }
    this._$scope.$digest();
    return this._getFlushedThenable();
  },

  inputOn: function(selector, value, which) {
    if (!which) {
      if (this.dom[0].querySelector(selector)) {
        angular.element(this.dom[0].querySelector(selector)).val(value).triggerHandler('input');
      } else if (this.dom[0].tagName == 'INPUT') {
        this._el.val(value).triggerHandler('input');
      }
    } else {
      if (this.dom[0].querySelectorAll(selector)[which]) {
        angular.element(this.dom[0].querySelectorAll(selector)[which]).val(value).triggerHandler('input');
      } else if (this.dom[0].tagName == 'INPUT') {
        this._el.val(value).triggerHandler('input');
      }
    }
    this._$scope.$digest();
    return this._getFlushedThenable();
  },

  _getFlushedThenable: function() {
    try {
      this.$timeout.verifyNoPendingTasks();
    } catch (e) {
      this.$timeout.flush();
    }
    return {
      then: function(fn) {
        fn();
      }
    };
  }
};

window.TestDummy = {
  get filter() {
    return function(input) {
      return input;
    };
  },

  get directive() {
    return [{ restrict: 'AE' }];
  }
};

window.TestFactory = {
  define: function(name, attributes) {
    if (!this.models) {
      this.models = {};
    }
    this.models[name] = attributes;
  },

  create: function(name, attributes) {
    var
      model = angular.copy(this.models[name]),
      property;
    if (model) {
      if (typeof model === 'function') {
        model = model();
      } else {
        if (attributes) {
          for (property in attributes) {
            if (attributes.hasOwnProperty(property)) {
              model[property] = attributes[property];
            }
          }
        }

        for (property in model) {
          if (model.hasOwnProperty(property) && typeof model[property] === 'function') {
            model[property] = model[property]();
          }
        }
      }
    }
    return model;
  },

  createList: function(name, number, attributes) {
    var
      model = angular.copy(this.models[name]),
      list = [],
      i = 0,
      property;

    if (model) {
      if (attributes) {
        for (property in attributes) {
          if (attributes.hasOwnProperty(property)) {
            model[property] = attributes[property];
          }
        }
      }
    }

    for (property in model) {
      if (model.hasOwnProperty(property) && typeof model !== 'function' && typeof model[property] === 'function') {
        model[property].clear();
      }
    }

    for (i; i < number; i++) {
      if (typeof model === 'function') {
        list.push(angular.copy(model()));
      } else {
        list.push(angular.copy(model));
      }
    }

    list = list.map(function(item) {
      for (var property in item) {
        if (item.hasOwnProperty(property) && typeof item[property] === 'function') {
          item[property] = item[property]();
        }
      }
      return item;
    });

    return list;
  },

  defineSequence: function(name, argOne, argTwo) {
    var callback, iterator;
    if (!this.seq) {
      this.seq = {};
    }
    if (typeof argOne == 'function') {
      callback = argOne;
      iterator = argTwo ? argTwo : 1;
    } else {
      iterator = argOne ? argOne : 1;
      callback = function(value) {
        return value;
      };
    }

    this.seq[name] = {
      value: 0,
      callback: callback,
      iterator: iterator
    };
  },

  sequence: function(name) {
    var _this = this;
    if (!!this.seq[name]) {
      var returnedObject = function() {
        _this.seq[name].value += _this.seq[name].iterator;
        return _this.seq[name].callback(_this.seq[name].value);
      };

      returnedObject.clear = function() {
        _this.seq[name].value = 0;
      };

      return returnedObject;
    }
  }
};

window.TestModule = function(name) {
  this.module = angular.module(name);
  this.deps = this.module.value(name).requires;
};

window.TestModule.prototype = {
  hasModule: function(name) {
    return this.deps.indexOf(name) >= 0;
  }
};
<commit_msg>add module.exports<commit_after>window.TestServ = function(name) {
  var _this = this;

  if (!!name) {
    inject([name, function(service) {
      _this = service;
    }]);
    return _this;
  }
};

window.TestServ.prototype = {
  addPromise: function(name) {
    var _this = this;
    _this[name] = function() {};
    spyOn(_this, name).and.returnValue({
      then: function(success, fail) {
        _this[name].success = success;
        _this[name].fail = fail;
      }
    });
    return this;
  },

  addMethod: function(name, returnedValue) {
    if (typeof returnedValue === "function" ) {
      this[name] = returnedValue;
      spyOn(this, name).and.callThrough();
    } else {
      this[name] = angular.noop;
      spyOn(this, name).and.returnValue(returnedValue !== undefined ? returnedValue : this);
    }
    return this;
  },

  addProperty: function(name, returnedValue) {
    this[name] = returnedValue;
    return this;
  }
};

window.TestElement = function() {
  var _this = this;
  inject(function($rootScope, $compile, $timeout, $controller, $templateCache, $filter) {
    _this._$scope = $rootScope.$new();
    _this.$originalScope = $rootScope.$new();
    _this.$compile = $compile;
    _this.$timeout = $timeout;
    _this.$controller = $controller;
    _this.$templateCache = $templateCache;
    _this.$filter = $filter;
  });
  this.name = '';
};

window.TestElement.prototype = {
  createCtrl: function(name, services) {
    if (!services) {
      services = {};
    }
    if (!services.$scope) {
      services.$scope = this._$scope;
    }
    this._ctrl = this.$controller(name, services);
    return this._ctrl;
  },

  addTemplate: function(path, ctrlAs) {
    var template;
    template = this.$templateCache.get(path);
    this._el = angular.element(template);

    if (!!ctrlAs) {
      this._$scope[ctrlAs] = this._ctrl;
    }

    this.$compile(this._el)(this._$scope);
    this._$scope.$digest();

    try {
      this.$timeout.verifyNoPendingTasks();
    } catch (e) {
      this.$timeout.flush();
    }

    return this._el;
  },

  createDirective: function(name, html, scope) {
    this.name = name;
    var elem = angular.element(html);
    this._$scope = angular.extend(this.$originalScope, scope);
    this._el = this.$compile(elem)(this._$scope);
    this._$scope.$digest();

    try {
      this.$timeout.verifyNoPendingTasks();
    } catch (e) {
      this.$timeout.flush();
    }
    return this._el;
  },

  createComponent: function(name, html, scope) {
    this.createDirective(name, html, scope);
    return this._el;
  },

  createFilter: function(name) {
    return this.$filter(name);
  },

  get scope() {
    return this._ctrl ?
      this._$scope : Object.keys(this.dom.children()).length ?
        this.dom.children().scope() : this.dom.scope();
  },

  get ctrl() {
    return this._ctrl ? this._ctrl : angular.element(this._el).controller(this.name);
  },

  get dom() {
    return angular.element(this._el);
  },

  find: function (selector) {
    return angular.element(this.dom[0].querySelector(selector));
  },

  findAll: function (selector) {
    var htmlObject = this.dom[0].querySelectorAll(selector);
    var returnedArray = [];
    for (var property in htmlObject) {
      if (htmlObject.hasOwnProperty(property) && typeof htmlObject[property] !== 'number') {
        returnedArray.push(angular.element(htmlObject[property]));
      }
    }
    return returnedArray;
  },

  destroy: function() {
    this._$scope.$destroy();
    this._el = null;
    this._ctrl = null;
  },

  clickOn: function(selector) {
    if (this.dom[0].querySelector(selector)) {
      this.dom[0].querySelector(selector).click();
    } else {
      this.dom[0].click();
    }
    this._$scope.$digest();
    return this._getFlushedThenable();
  },

  inputOn: function(selector, value, which) {
    if (!which) {
      if (this.dom[0].querySelector(selector)) {
        angular.element(this.dom[0].querySelector(selector)).val(value).triggerHandler('input');
      } else if (this.dom[0].tagName == 'INPUT') {
        this._el.val(value).triggerHandler('input');
      }
    } else {
      if (this.dom[0].querySelectorAll(selector)[which]) {
        angular.element(this.dom[0].querySelectorAll(selector)[which]).val(value).triggerHandler('input');
      } else if (this.dom[0].tagName == 'INPUT') {
        this._el.val(value).triggerHandler('input');
      }
    }
    this._$scope.$digest();
    return this._getFlushedThenable();
  },

  _getFlushedThenable: function() {
    try {
      this.$timeout.verifyNoPendingTasks();
    } catch (e) {
      this.$timeout.flush();
    }
    return {
      then: function(fn) {
        fn();
      }
    };
  }
};

window.TestDummy = {
  get filter() {
    return function(input) {
      return input;
    };
  },

  get directive() {
    return [{ restrict: 'AE' }];
  }
};

window.TestFactory = {
  define: function(name, attributes) {
    if (!this.models) {
      this.models = {};
    }
    this.models[name] = attributes;
  },

  create: function(name, attributes) {
    var
      model = angular.copy(this.models[name]),
      property;
    if (model) {
      if (typeof model === 'function') {
        model = model();
      } else {
        if (attributes) {
          for (property in attributes) {
            if (attributes.hasOwnProperty(property)) {
              model[property] = attributes[property];
            }
          }
        }

        for (property in model) {
          if (model.hasOwnProperty(property) && typeof model[property] === 'function') {
            model[property] = model[property]();
          }
        }
      }
    }
    return model;
  },

  createList: function(name, number, attributes) {
    var
      model = angular.copy(this.models[name]),
      list = [],
      i = 0,
      property;

    if (model) {
      if (attributes) {
        for (property in attributes) {
          if (attributes.hasOwnProperty(property)) {
            model[property] = attributes[property];
          }
        }
      }
    }

    for (property in model) {
      if (model.hasOwnProperty(property) && typeof model !== 'function' && typeof model[property] === 'function') {
        model[property].clear();
      }
    }

    for (i; i < number; i++) {
      if (typeof model === 'function') {
        list.push(angular.copy(model()));
      } else {
        list.push(angular.copy(model));
      }
    }

    list = list.map(function(item) {
      for (var property in item) {
        if (item.hasOwnProperty(property) && typeof item[property] === 'function') {
          item[property] = item[property]();
        }
      }
      return item;
    });

    return list;
  },

  defineSequence: function(name, argOne, argTwo) {
    var callback, iterator;
    if (!this.seq) {
      this.seq = {};
    }
    if (typeof argOne == 'function') {
      callback = argOne;
      iterator = argTwo ? argTwo : 1;
    } else {
      iterator = argOne ? argOne : 1;
      callback = function(value) {
        return value;
      };
    }

    this.seq[name] = {
      value: 0,
      callback: callback,
      iterator: iterator
    };
  },

  sequence: function(name) {
    var _this = this;
    if (!!this.seq[name]) {
      var returnedObject = function() {
        _this.seq[name].value += _this.seq[name].iterator;
        return _this.seq[name].callback(_this.seq[name].value);
      };

      returnedObject.clear = function() {
        _this.seq[name].value = 0;
      };

      return returnedObject;
    }
  }
};

window.TestModule = function(name) {
  this.module = angular.module(name);
  this.deps = this.module.value(name).requires;
};

window.TestModule.prototype = {
  hasModule: function(name) {
    return this.deps.indexOf(name) >= 0;
  }
};

module.exports = {
  TestServ: window.TestServ,
  TestElement: window.TestElement,
  TestDummy: window.TestDummy,
  TestFactory: window.TestFactory,
  TestModule: window.TestModule
};
<|endoftext|>


<commit_before>'use strict';

require('./support/index');

const Promise = require('bluebird');
const sinon   = require('sinon');

const Context  = require('./../lib/Context');
const Reporter = require('./../lib/Reporter');

describe('Context', () => {

    let context,
        CustomReporter, customReporterConstructorSpy, customReporterReportSpy,
        CustomReporterContext, customReporterContext;

    beforeEach(() => {
        context                        = new Context;
        customReporterConstructorSpy   = sinon.spy();
        customReporterReportSpy        = sinon.spy();
        CustomReporter                 = class {
            constructor() {
                customReporterConstructorSpy(...arguments);
            }

            report() {
                customReporterReportSpy(...arguments);
            }

            clone() {
                return new this.constructor();
            }
        };
        CustomReporterContext          = class extends Context {
        };
        CustomReporterContext.Reporter = CustomReporter;
        customReporterContext          = new CustomReporterContext;
    });

    describe('makeReporter', () => {

        it('should make an instance of Reporter', () => {

            context.makeReporter().should.be.an.instanceOf(Reporter);
        });

        it('should allow the use of a custom Reporter class', () => {

            customReporterContext.makeReporter().should.be.an.instanceOf(CustomReporter);
        });

        it('should invoke the Reporter constructor with itself as the argument', () => {

            customReporterContext.makeReporter();
            customReporterConstructorSpy.should.have.been.calledWith(customReporterContext);
        });
    });

    describe('getUptime', () => {

        it('should return the number of milliseconds that have passed since the instantiation of the context', () => {

            context = new Context;

            return Promise.delay(20).then(() => {

                context.getUptime().should.be.within(18, 30); // Yeah this is kinda tricky
            });
        });
    });

    describe('report', () => {

        it('should invoke the report method on the reporter and extend the data with the internal scope', () => {

            context = new CustomReporterContext({}, {someScopeVar: 'beepboop'});
            context.report('info', {someDataVar: 'beepbop'});
            customReporterReportSpy.should.have.been.calledWithMatch('info', {
                someScopeVar: 'beepboop',
                someDataVar:  'beepbop'
            });
        });
    });

    describe('createSubContext', () => {

        it('should create a new context of the same type based on the internal scope, extended with the given scope', () => {

            let options       = {verbosity: 3};
            let internalScope = {base: 'foo'};
            let customContext = new CustomReporterContext(options, internalScope);

            let subContext = customContext.createSubContext({ext: 'bar'});
            internalScope.should.deep.equal({base: 'foo'}); //First, check if the initial scope was not modified (no side-effects)
            subContext.should.be.an.instanceOf(CustomReporterContext);
            subContext.options.should.deep.equal(options);
            subContext.scope.should.deep.equal({ext: 'bar', base: 'foo'});
        });
    });

    describe('withScope', () => {

        it('should run some function with a subContext that includes the given scope', () => {

            new Context({}, {base: 'foo'}).withScope({ext: 'bar'}, context => context.scope.base + context.scope.ext)
                .should.equal('foobar');
        });
    });
});<commit_msg>made “uptime” test less strict<commit_after>'use strict';

require('./support/index');

const Promise = require('bluebird');
const sinon   = require('sinon');

const Context  = require('./../lib/Context');
const Reporter = require('./../lib/Reporter');

describe('Context', () => {

    let context,
        CustomReporter, customReporterConstructorSpy, customReporterReportSpy,
        CustomReporterContext, customReporterContext;

    beforeEach(() => {
        context                        = new Context;
        customReporterConstructorSpy   = sinon.spy();
        customReporterReportSpy        = sinon.spy();
        CustomReporter                 = class {
            constructor() {
                customReporterConstructorSpy(...arguments);
            }

            report() {
                customReporterReportSpy(...arguments);
            }

            clone() {
                return new this.constructor();
            }
        };
        CustomReporterContext          = class extends Context {
        };
        CustomReporterContext.Reporter = CustomReporter;
        customReporterContext          = new CustomReporterContext;
    });

    describe('makeReporter', () => {

        it('should make an instance of Reporter', () => {

            context.makeReporter().should.be.an.instanceOf(Reporter);
        });

        it('should allow the use of a custom Reporter class', () => {

            customReporterContext.makeReporter().should.be.an.instanceOf(CustomReporter);
        });

        it('should invoke the Reporter constructor with itself as the argument', () => {

            customReporterContext.makeReporter();
            customReporterConstructorSpy.should.have.been.calledWith(customReporterContext);
        });
    });

    describe('getUptime', () => {

        it('should return the number of milliseconds that have passed since the instantiation of the context', () => {

            context = new Context;

            return Promise.delay(20).then(() => {

                context.getUptime().should.be.within(18, 50); // Yeah this is kinda tricky
            });
        });
    });

    describe('report', () => {

        it('should invoke the report method on the reporter and extend the data with the internal scope', () => {

            context = new CustomReporterContext({}, {someScopeVar: 'beepboop'});
            context.report('info', {someDataVar: 'beepbop'});
            customReporterReportSpy.should.have.been.calledWithMatch('info', {
                someScopeVar: 'beepboop',
                someDataVar:  'beepbop'
            });
        });
    });

    describe('createSubContext', () => {

        it('should create a new context of the same type based on the internal scope, extended with the given scope', () => {

            let options       = {verbosity: 3};
            let internalScope = {base: 'foo'};
            let customContext = new CustomReporterContext(options, internalScope);

            let subContext = customContext.createSubContext({ext: 'bar'});
            internalScope.should.deep.equal({base: 'foo'}); //First, check if the initial scope was not modified (no side-effects)
            subContext.should.be.an.instanceOf(CustomReporterContext);
            subContext.options.should.deep.equal(options);
            subContext.scope.should.deep.equal({ext: 'bar', base: 'foo'});
        });
    });

    describe('withScope', () => {

        it('should run some function with a subContext that includes the given scope', () => {

            new Context({}, {base: 'foo'}).withScope({ext: 'bar'}, context => context.scope.base + context.scope.ext)
                .should.equal('foobar');
        });
    });
});<|endoftext|>


<commit_before>import assert from 'assert'
import jsdocx from '../dist/jsdocx'

describe('#Element', () => {
  describe('#src', () => {
    it('should exist after creation', () => {
      let m = new jsdocx.Element()
      assert.equal(m.hasOwnProperty('src'), true)
      assert.equal(typeof m.src, 'object')
    })
    it('should contain given content tree', () => {
      let tree = {
        a: 'Foo',
        b: 'Bar'
      }
      let m = new jsdocx.Element(tree)
      assert.equal(m.hasOwnProperty('src'), true)
      assert.equal(m.src, tree)
    })
  })
  describe('#contents', () => {
    it('should exist after creation', () => {
      let p = new jsdocx.Element()
      assert.equal(p.hasOwnProperty('contents'), true)
      assert.equal(p.contents instanceof Array, true)
      assert.equal(p.contents.length, 0)
    })
  })
  describe('#contentHook', () => {
    it('should exist after creation', () => {
      let p = new jsdocx.Element()
      assert.equal(p.hasOwnProperty('contentHook'), true)
      assert.equal(typeof p.contentHook, 'object')
    })
    it('should be "null" if not specified', () => {
      let p = new jsdocx.Element()
      assert.equal(p.contentHook, null)
    })
    it('should be equal to given value', () => {
      let p = new jsdocx.Element({ foo: 'bar' }, '.foo')
      assert.equal(p.contentHook, '.foo')
    })
    it('should throw a TypeError if invalid', () => {
      assert.throws(() => {
        new jsdocx.Element({}, 'a')
      }, TypeError)
    })
  })
  describe('#toJson', () => {
    it('should transfrom "src" in valid JSON syntax', () => {
      let src = {
        'a': 'Foo',
        b: 'Bar'
      }
      let m = new jsdocx.Element(src)
      assert.deepEqual(m.toJson(), {
        'a': 'Foo',
        'b': 'Bar'
      })
    })
    it('should ignore content if hook is null', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: {}
      })
      let m = new jsdocx.Element({
        d: 1
      })
      p.contents.push(m)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': {}
      })
    })
    it('should insert content at given hook', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: {}
      }, '.c')
      let m = new jsdocx.Element({
        d: 1
      })
      p.contents.push(m)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': {
          'd': 1
        }
      })
    })
    it('should append content at given hook when is an array', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: []
      }, '.c')
      let m = new jsdocx.Element({
        d: 1
      })
      p.contents.push(m)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': [{
          'd': 1
        }]
      })
    })
    it('should append content at given complex hook', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: {
          d: {
            e: {
            }
          }
        }
      }, '.c.d.e')
      let m = new jsdocx.Element({
        f: 1
      })
      p.contents.push(m)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': {
          'd': {
            'e': {
              'f': 1
            }
          }
        }
      })
    })
    it('should append content at given complex hook when is an array', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: {
          d: {
            e: []
          }
        }
      }, '.c.d.e')
      let m = new jsdocx.Element({
        f: 1
      })
      p.contents.push(m)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': {
          'd': {
            'e': [{
              'f': 1
            }]
          }
        }
      })
    })
    it('should insert more contents at given hook', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: {
          d: {
            e: {
            }
          }
        }
      }, '.c.d.e')
      let m1 = new jsdocx.Element({
        f: 1
      })
      let m2 = new jsdocx.Element({
        'g': 2
      })
      p.contents.push(m1)
      p.contents.push(m2)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': {
          'd': {
            'e': {
              'f': 1,
              'g': 2
            }
          }
        }
      })
    })
    it('should insert more contents at given hook when is an array', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: {
          d: {
            e: []
          }
        }
      }, '.c.d.e')
      let m1 = new jsdocx.Element({
        f: 1
      })
      let m2 = new jsdocx.Element({
        'g': 2
      })
      p.contents.push(m1)
      p.contents.push(m2)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': {
          'd': {
            'e': [{
              'f': 1
            }, {
              'g': 2
            }]
          }
        }
      })
    })
    it('should insert contents at given hook when string keys are used', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: {
          'd.e': {
            'f': []
          }
        }
      }, '.c["d.e"].f')
      let m1 = new jsdocx.Element({
        g: 1
      })
      let m2 = new jsdocx.Element({
        h: 2
      })
      p.contents.push(m1)
      p.contents.push(m2)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': {
          'd.e': {
            'f': [{
              'g': 1
            }, {
              'h': 2
            }]
          }
        }
      })
    })
  })
  describe('#toJson', () => {
    it('should return a JSON repr of content tree', () => {
      let m = new jsdocx.Element({
        a: 'Foo',
        b: 'Bar',
        'c': [],
        d: 1
      })
      assert.deepEqual(m.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': [],
        'd': 1
      })
    })
  })
  describe('#toXml', () => {
    it('should return a XML repr of content tree', () => {
      let m = new jsdocx.Element({
        a: {
          '@foo': 'bar',
          '#': 'Foo'
        },
        b: 'Bar',
        'c': {},
        d: 1
      })
      assert.equal(m.toXml(), 'FooBar<c></c><d>1</d>')
    })
    it('should return a XML repr of full content tree (with children)', () => {
      let p = new jsdocx.Element({
        a: {
          '@foo': 'bar',
          '#': 'Foo'
        },
        b: 'Bar',
        'c': {},
        d: 1
      }, '.c')
      let m = new jsdocx.Element({
        e: 2
      })
      p.contents.push(m)
      assert.equal(p.toXml(), 'FooBar<c><e>2</e></c><d>1</d>')
    })
  })
})
<commit_msg>Polish tests<commit_after>import assert from 'assert'
import jsdocx from '../dist/jsdocx'

describe('#Element', () => {
  describe('#src', () => {
    it('should exist after creation', () => {
      let e = new jsdocx.Element()
      assert.equal(e.hasOwnProperty('src'), true)
      assert.equal(typeof e.src, 'object')
    })
    it('should contain given content tree', () => {
      let tree = {
        a: 'Foo',
        b: 'Bar'
      }
      let e = new jsdocx.Element(tree)
      assert.equal(e.hasOwnProperty('src'), true)
      assert.equal(e.src, tree)
    })
  })
  describe('#contents', () => {
    it('should exist after creation', () => {
      let e = new jsdocx.Element()
      assert.equal(e.hasOwnProperty('contents'), true)
      assert.equal(e.contents instanceof Array, true)
      assert.equal(e.contents.length, 0)
    })
  })
  describe('#contentHook', () => {
    it('should exist after creation', () => {
      let e = new jsdocx.Element()
      assert.equal(e.hasOwnProperty('contentHook'), true)
      assert.equal(typeof e.contentHook, 'object')
    })
    it('should be "null" if not specified', () => {
      let e = new jsdocx.Element()
      assert.equal(e.contentHook, null)
    })
    it('should be equal to given value', () => {
      let e = new jsdocx.Element({ foo: 'bar' }, '.foo')
      assert.equal(e.contentHook, '.foo')
    })
    it('should throw a TypeError if invalid', () => {
      assert.throws(() => {
        new jsdocx.Element({}, 'a')
      }, TypeError)
    })
  })
  describe('#toJson', () => {
    it('should transfrom "src" in valid JSON syntax', () => {
      let src = {
        'a': 'Foo',
        b: 'Bar'
      }
      let e = new jsdocx.Element(src)
      assert.deepEqual(e.toJson(), {
        'a': 'Foo',
        'b': 'Bar'
      })
    })
    it('should ignore content if hook is null', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: {}
      })
      let e = new jsdocx.Element({
        d: 1
      })
      p.contents.push(e)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': {}
      })
    })
    it('should insert content at given hook', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: {}
      }, '.c')
      let e = new jsdocx.Element({
        d: 1
      })
      p.contents.push(e)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': {
          'd': 1
        }
      })
    })
    it('should append content at given hook when is an array', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: []
      }, '.c')
      let e = new jsdocx.Element({
        d: 1
      })
      p.contents.push(e)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': [{
          'd': 1
        }]
      })
    })
    it('should append content at given complex hook', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: {
          d: {
            e: {
            }
          }
        }
      }, '.c.d.e')
      let e = new jsdocx.Element({
        f: 1
      })
      p.contents.push(e)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': {
          'd': {
            'e': {
              'f': 1
            }
          }
        }
      })
    })
    it('should append content at given complex hook when is an array', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: {
          d: {
            e: []
          }
        }
      }, '.c.d.e')
      let e = new jsdocx.Element({
        f: 1
      })
      p.contents.push(e)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': {
          'd': {
            'e': [{
              'f': 1
            }]
          }
        }
      })
    })
    it('should insert more contents at given hook', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: {
          d: {
            e: {
            }
          }
        }
      }, '.c.d.e')
      let e1 = new jsdocx.Element({
        f: 1
      })
      let e2 = new jsdocx.Element({
        'g': 2
      })
      p.contents.push(e1)
      p.contents.push(e2)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': {
          'd': {
            'e': {
              'f': 1,
              'g': 2
            }
          }
        }
      })
    })
    it('should insert more contents at given hook when is an array', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: {
          d: {
            e: []
          }
        }
      }, '.c.d.e')
      let e1 = new jsdocx.Element({
        f: 1
      })
      let e2 = new jsdocx.Element({
        'g': 2
      })
      p.contents.push(e1)
      p.contents.push(e2)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': {
          'd': {
            'e': [{
              'f': 1
            }, {
              'g': 2
            }]
          }
        }
      })
    })
    it('should insert contents at given hook when string keys are used', () => {
      let p = new jsdocx.Element({
        'a': 'Foo',
        b: 'Bar',
        c: {
          'd.e': {
            'f': []
          }
        }
      }, '.c["d.e"].f')
      let e1 = new jsdocx.Element({
        g: 1
      })
      let e2 = new jsdocx.Element({
        h: 2
      })
      p.contents.push(e1)
      p.contents.push(e2)
      assert.deepEqual(p.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': {
          'd.e': {
            'f': [{
              'g': 1
            }, {
              'h': 2
            }]
          }
        }
      })
    })
    it('should return a JSON repr of content tree', () => {
      let e = new jsdocx.Element({
        a: 'Foo',
        b: 'Bar',
        'c': [],
        d: 1
      })
      assert.deepEqual(e.toJson(), {
        'a': 'Foo',
        'b': 'Bar',
        'c': [],
        'd': 1
      })
    })
  })
  describe('#toXml', () => {
    it('should return a XML repr of content tree', () => {
      let e = new jsdocx.Element({
        a: {
          '@foo': 'bar',
          '#': 'Foo'
        },
        b: 'Bar',
        'c': {},
        d: 1
      })
      assert.equal(e.toXml(), 'FooBar<c></c><d>1</d>')
    })
    it('should return a XML repr of full content tree (with children)', () => {
      let p = new jsdocx.Element({
        a: {
          '@foo': 'bar',
          '#': 'Foo'
        },
        b: 'Bar',
        'c': {},
        d: 1
      }, '.c')
      let e = new jsdocx.Element({
        e: 2
      })
      p.contents.push(e)
      assert.equal(p.toXml(), 'FooBar<c><e>2</e></c><d>1</d>')
    })
  })
})
<|endoftext|>


<commit_before>'use strict';

angular.module('wlsApp', [
  	'wlsApp.services',
	'ui.router',
	'ui.bootstrap',
	'ui.bootstrap.tpls'
])
.config(['$stateProvider', '$urlRouterProvider',
		  	function($stateProvider, $urlRouterProvider) {
	$urlRouterProvider
	.otherwise('/index');

	$stateProvider
		.state('index', {
			url: "/index",
			views: {
				"state" : { templateUrl: "partials/main_state.html",}
			}
		})
		.state('list', {
			url: "/list",
			views: {
				"state" : { templateUrl: "partials/stocklist.html",}
			}
		})
		.state('stock', {
			url: "/stock",
			views: {
				"state" : { templateUrl: "partials/stock.html", }
			}
		})
		.state('add', {
			url: "/add",
			views: {
				"state" : { templateUrl: "partials/add_stock.html", }
			}
		})
		.state('edit', {
			url: "/edit",
			views: {
				"state" : { templateUrl: "partials/edit_stock.html", }
			}
		})
}])
.controller('MainCtrl', ['$scope', '$window', '$state', 'apiService', function($scope, $window, $state, apiService) {
	$scope.currentStock;
	$scope.editStockID;

	//----------------- STOCK LIST ----------------------
  	apiService.fetchStocks()
  	.then(function(data) {
  		$scope.stocks = data;
	    console.log('stocks', $scope.stocks);
  	}), function(error) {
  		console.log('fetch stocks error', error);
  	};

	//----------------- SHOW STOCK  ----------------------
    $scope.showCurrentStock = function(_id) {
	    apiService.fetchCurrentStock(_id)
	    .then(function(data) {
	    	$scope.currentStock = data;
    		$state.go('stock');
	    }), function(error) {
  		console.log('show stock error', error);
	    };
  	};

	//----------------- ADD STOCK  ----------------------
  	$scope.insertStock = function(stock) {
    	apiService.insertStock(stock)
    	.then(function(data) {
    		apiService.fetchStocks()
    		.then(function(data) {
  				$scope.stocks = data;
  			}), function(error) {
  				console.log('fetch stocks error', error);
  			};
    		$state.go('list');
    	}), function(error) {
  			console.log('insert stock error', error);
    	};
    };

	//----------------- DELETE STOCK  ----------------------
  	var handleDeleteStockSuccess = function(data, status) {
  		console.log('STATUS', status);
  		$scope.stocks = apiService.fetchStocks()
          .success(handleStockListSuccess);
    	$state.go('list');
  	};

  	$scope.deleteStock = function(_id) {
    	apiService.deleteStock(_id)
    	.then(function(data) {
    		apiService.fetchStocks()
    		.then(function(data) {
  				$scope.stocks = data;
  			}), function(error) {
  				console.log('fetch stocks error', error);
  			};
    		$state.go('list');
    	}), function(error) {
  			console.log('delete stock error', error);
    	};
  	};
    //----------------- EDIT STOCK  ----------------------
	$scope.editStock = function(_id, stock) {
    	apiService.editStock(_id, stock)
    	.then(function(data) {
    		apiService.fetchStocks()
    		.then(function(data) {
  				$scope.stocks = data;
  			}), function(error) {
  				console.log('fetch stocks error', error);
  			};
    		$state.go('list');
    	}), function(error) {
  			console.log('edit stock error', error);
    	};
  	};

	//----------------- SUBMIT FORM ----------------------
	$scope.submitInsertForm = function(isValid) {
		if(isValid) {
			$scope.insertStock($scope.currentStock);
		}
	};

	//----------------- EDIT FORM ----------------------
	$scope.submitEditForm = function(isValid) {
		if(isValid) {
			$scope.editStock($scope.editStockID, $scope.currentStock);
		}
	};

	$scope.copyStock = function(stock) {
		$scope.currentStock = stock;
	};

	$scope.copyEditStock = function(id, stock) {
		$scope.editStockID = id;
		$scope.currentStock = stock;
	};

}]); <commit_msg>Remove old delete callback<commit_after>'use strict';

angular.module('wlsApp', [
  	'wlsApp.services',
	'ui.router',
	'ui.bootstrap',
	'ui.bootstrap.tpls'
])
.config(['$stateProvider', '$urlRouterProvider',
		  	function($stateProvider, $urlRouterProvider) {
	$urlRouterProvider
	.otherwise('/index');

	$stateProvider
		.state('index', {
			url: "/index",
			views: {
				"state" : { templateUrl: "partials/main_state.html",}
			}
		})
		.state('list', {
			url: "/list",
			views: {
				"state" : { templateUrl: "partials/stocklist.html",}
			}
		})
		.state('stock', {
			url: "/stock",
			views: {
				"state" : { templateUrl: "partials/stock.html", }
			}
		})
		.state('add', {
			url: "/add",
			views: {
				"state" : { templateUrl: "partials/add_stock.html", }
			}
		})
		.state('edit', {
			url: "/edit",
			views: {
				"state" : { templateUrl: "partials/edit_stock.html", }
			}
		})
}])
.controller('MainCtrl', ['$scope', '$window', '$state', 'apiService', function($scope, $window, $state, apiService) {
	$scope.currentStock;
	$scope.editStockID;

	//----------------- STOCK LIST ----------------------
  	apiService.fetchStocks()
  	.then(function(data) {
  		$scope.stocks = data;
	    console.log('stocks', $scope.stocks);
  	}), function(error) {
  		console.log('fetch stocks error', error);
  	};

	//----------------- SHOW STOCK  ----------------------
    $scope.showCurrentStock = function(_id) {
	    apiService.fetchCurrentStock(_id)
	    .then(function(data) {
	    	$scope.currentStock = data;
    		$state.go('stock');
	    }), function(error) {
  		console.log('show stock error', error);
	    };
  	};

	//----------------- ADD STOCK  ----------------------
  	$scope.insertStock = function(stock) {
    	apiService.insertStock(stock)
    	.then(function(data) {
    		apiService.fetchStocks()
    		.then(function(data) {
  				$scope.stocks = data;
  			}), function(error) {
  				console.log('fetch stocks error', error);
  			};
    		$state.go('list');
    	}), function(error) {
  			console.log('insert stock error', error);
    	};
    };

	//----------------- DELETE STOCK  ----------------------
  	$scope.deleteStock = function(_id) {
    	apiService.deleteStock(_id)
    	.then(function(data) {
    		apiService.fetchStocks()
    		.then(function(data) {
  				$scope.stocks = data;
  			}), function(error) {
  				console.log('fetch stocks error', error);
  			};
    		$state.go('list');
    	}), function(error) {
  			console.log('delete stock error', error);
    	};
  	};
    //----------------- EDIT STOCK  ----------------------
	$scope.editStock = function(_id, stock) {
    	apiService.editStock(_id, stock)
    	.then(function(data) {
    		apiService.fetchStocks()
    		.then(function(data) {
  				$scope.stocks = data;
  			}), function(error) {
  				console.log('fetch stocks error', error);
  			};
    		$state.go('list');
    	}), function(error) {
  			console.log('edit stock error', error);
    	};
  	};

	//----------------- SUBMIT FORM ----------------------
	$scope.submitInsertForm = function(isValid) {
		if(isValid) {
			$scope.insertStock($scope.currentStock);
		}
	};

	//----------------- EDIT FORM ----------------------
	$scope.submitEditForm = function(isValid) {
		if(isValid) {
			$scope.editStock($scope.editStockID, $scope.currentStock);
		}
	};

	$scope.copyStock = function(stock) {
		$scope.currentStock = stock;
	};

	$scope.copyEditStock = function(id, stock) {
		$scope.editStockID = id;
		$scope.currentStock = stock;
	};

}]); <|endoftext|>


<commit_before>'use strict'

/**
 * Test dependencies
 * @ignore
 */
const cwd = process.cwd()
const path = require('path')
const fs = require('fs')
const chai = require('chai')
const chaiAsPromised = require('chai-as-promised')
const sinon = require('sinon')
const sinonChai = require('sinon-chai')

/**
 * Assertions
 * @ignore
 */
chai.use(chaiAsPromised)
chai.should()
chai.use(sinonChai)
const expect = chai.expect

/**
 * Code Under Test
 * @ignore
 */
const { JWK } = require('../src')
const { DataError, OperationError } = require('../src/errors')

/**
 * Test Data
 * @ignore
 */
const { ECPrivateJWK, ECPublicJWK, A256GCMJWK } = require('./keys')

const ECPublicJWKString = fs.readFileSync(path.join(cwd, 'test', 'file_import', 'fileImportJWKTestData.json'), 'utf8')
const InvalidJWKString = fs.readFileSync(path.join(cwd, 'test', 'file_import', 'fileImportJWKTestData.json'), 'utf8')

const ECPublicJWKNoAlg = Object.assign({}, ECPublicJWK)
delete ECPublicJWKNoAlg.alg

const ECPublicJWKNoKid = Object.assign({}, ECPublicJWK)
delete ECPublicJWKNoKid.kid

const plainTextData = 'data'
const encryptedData = {"iv":"RH9i_J861XN7qvgHYZ86ag","ciphertext":"qkrkiw","tag":"kqfdLgy8qopnzeKmC5JwQA"}
const signedData = 'MEQCIAIqNr8-7Pozi1D-cigvEKbkP5SpKezzEEDSqM9McIV1AiBd4gioW8njOpr29Ymrvjp46q7hA7lSOjAJpdi5TjHWsg'

/**
 * Tests
 * @ignore
 */
describe('JWK', () => {

  describe('constructor', () => {

    it('should throw if no data is passed', () => {
      expect(() => new JWK()).to.throw('Invalid JWK')
    })

    it('should parse string input', () => {
      let jwk = new JWK(ECPublicJWKString)
      jwk.should.be.an.instanceOf(JWK)
    })

    it('should throw if it fails to parse string input', () => {
      expect(() => new JWK('invalid')).to.throw('Invalid JWK JSON String')
    })

    it('should throw if conflicting alg options are passed in', () => {
      expect(() => new JWK(ECPublicJWK, { alg: 'KS256' })).to.throw('Conflicting algorithm option')
    })

    it('should not throw if alg passed in twice but not conflicting', () => {
      expect(() => new JWK(ECPublicJWK, { alg: 'ES256' })).to.not.throw
    })

    it('should get alg from options if not on data', () => {
      let jwk = new JWK(ECPublicJWKNoAlg, { alg: 'ES256' })
      jwk.alg.should.equal('ES256')
    })

    it('should throw if alg is not present on data or options', () => {
      expect(new JWK(ECPublicJWKNoAlg, { alg: 'ES256' })).to.throw
    })

    it('should throw if conflicting kid options are passed in', () => {
      expect(() => new JWK(ECPublicJWK, { kid: '1' })).to.throw('Conflicting key identifier option')
    })

    it('should not throw if kid passed in twice but not conflicting', () => {
      expect(() => new JWK(ECPublicJWK, { kid: '2' })).to.not.throw
    })

    it('should get kid from options if not on data', () => {
      let jwk = new JWK(ECPublicJWK, { alg: 'ES256', kid: '2' })
      jwk.kid.should.equal('2')
    })

    it('should throw if kid is not present on data or options', () => {
      expect(() => new JWK(ECPublicJWKNoKid, {})).to.throw('Valid JWA key identifier required for JWK')
    })

    it('should copy non-standard key metadata', () => {
      let json = Object.assign({}, ECPublicJWK, { meta: 'abc' })
      let jwk = new JWK(json)
      jwk.meta.should.equal('abc')
    })
  })

  describe('importKey', () => {

  })

  describe('fromCryptoKey', () => {

  })

  describe('sign', () => {
    let jwk

    before(() => {
      return JWK.importKey(ECPrivateJWK).then(key => jwk = key)
    })

    it('should return a promise', () => {
      return jwk.sign(plainTextData).should.be.fulfilled
    })

    it('should resolve a string', () => {
      return jwk.sign(plainTextData).should.eventually.be.a('string')
    })
  })

  describe('verify', () => {
    let jwk

    before(() => {
      return JWK.importKey(ECPublicJWK).then(key => jwk = key)
    })

    it('should return a promise', () => {
      return jwk.verify(plainTextData, signedData).should.be.fulfilled
    })

    it('should resolve a boolean', () => {
      return jwk.verify(plainTextData, signedData).should.eventually.be.true
    })

    it('should fail to verify the signature with incorrect data', () => {
      return jwk.verify(plainTextData + 'a', signedData).should.eventually.be.false
    })
  })

  describe('encrypt', () => {
    let jwk

    before(() => {
      return JWK.importKey(A256GCMJWK).then(key => jwk = key)
    })

    it('should return a promise', () => {
      return jwk.encrypt(plainTextData, Buffer.from('')).should.be.fulfilled
    })

    it('should resolve encrypted data', () => {
      return jwk.encrypt(plainTextData, Buffer.from('')).then(data => {
        data.should.haveOwnProperty('ciphertext')
        data.should.haveOwnProperty('iv')
        data.should.haveOwnProperty('tag')
      })
    })
  })

  describe('decrypt', () => {
    let jwk

    before(() => {
      return JWK.importKey(A256GCMJWK).then(key => jwk = key)
    })

    it('should return a promise', () => {
      let { ciphertext, iv, tag } = encryptedData
      return jwk.decrypt(ciphertext, iv, tag, Buffer.from('')).should.be.fulfilled
    })

    it('should resolve plain text data', () => {
      let { ciphertext, iv, tag } = encryptedData
      return jwk.decrypt(ciphertext, iv, tag, Buffer.from('')).should.eventually.equal(plainTextData)
    })
  })
})
<commit_msg>test(JWK): updated error messages<commit_after>'use strict'

/**
 * Test dependencies
 * @ignore
 */
const cwd = process.cwd()
const path = require('path')
const fs = require('fs')
const chai = require('chai')
const chaiAsPromised = require('chai-as-promised')
const sinon = require('sinon')
const sinonChai = require('sinon-chai')

/**
 * Assertions
 * @ignore
 */
chai.use(chaiAsPromised)
chai.should()
chai.use(sinonChai)
const expect = chai.expect

/**
 * Code Under Test
 * @ignore
 */
const { JWK } = require('../src')
const { DataError, OperationError } = require('../src/errors')

/**
 * Test Data
 * @ignore
 */
const { ECPrivateJWK, ECPublicJWK, A256GCMJWK } = require('./keys')

const ECPublicJWKString = fs.readFileSync(path.join(cwd, 'test', 'file_import', 'fileImportJWKTestData.json'), 'utf8')
const InvalidJWKString = fs.readFileSync(path.join(cwd, 'test', 'file_import', 'fileImportJWKTestData.json'), 'utf8')

const ECPublicJWKNoAlg = Object.assign({}, ECPublicJWK)
delete ECPublicJWKNoAlg.alg

const ECPublicJWKNoKid = Object.assign({}, ECPublicJWK)
delete ECPublicJWKNoKid.kid

const plainTextData = 'data'
const encryptedData = {"iv":"RH9i_J861XN7qvgHYZ86ag","ciphertext":"qkrkiw","tag":"kqfdLgy8qopnzeKmC5JwQA"}
const signedData = 'MEQCIAIqNr8-7Pozi1D-cigvEKbkP5SpKezzEEDSqM9McIV1AiBd4gioW8njOpr29Ymrvjp46q7hA7lSOjAJpdi5TjHWsg'

/**
 * Tests
 * @ignore
 */
describe('JWK', () => {

  describe('constructor', () => {

    it('should throw if no data is passed', () => {
      expect(() => new JWK()).to.throw('Invalid JWK')
    })

    it('should parse string input', () => {
      let jwk = new JWK(ECPublicJWKString)
      jwk.should.be.an.instanceOf(JWK)
    })

    it('should throw if it fails to parse string input', () => {
      expect(() => new JWK('invalid')).to.throw('Invalid JWK JSON String')
    })

    it('should throw if conflicting alg options are passed in', () => {
      expect(() => new JWK(ECPublicJWK, { alg: 'KS256' })).to.throw('Conflicting \'alg\' option')
    })

    it('should not throw if alg passed in twice but not conflicting', () => {
      expect(() => new JWK(ECPublicJWK, { alg: 'ES256' })).to.not.throw
    })

    it('should get alg from options if not on data', () => {
      let jwk = new JWK(ECPublicJWKNoAlg, { alg: 'ES256' })
      jwk.alg.should.equal('ES256')
    })

    it('should throw if alg is not present on data or options', () => {
      expect(() => new JWK(ECPublicJWKNoAlg, {})).to.throw('Valid \'alg\' required for JWK')
    })

    it('should throw if conflicting kid options are passed in', () => {
      expect(() => new JWK(ECPublicJWK, { kid: '1' })).to.throw('Conflicting \'kid\' option')
    })

    it('should not throw if kid passed in twice but not conflicting', () => {
      expect(() => new JWK(ECPublicJWK, { kid: '2' })).to.not.throw
    })

    it('should get kid from options if not on data', () => {
      let jwk = new JWK(ECPublicJWK, { alg: 'ES256', kid: '2' })
      jwk.kid.should.equal('2')
    })

    it('should throw if kid is not present on data or options', () => {
      expect(() => new JWK(ECPublicJWKNoKid, {})).to.throw('Valid \'kid\' required for JWK')
    })

    it('should copy non-standard key metadata', () => {
      let json = Object.assign({}, ECPublicJWK, { meta: 'abc' })
      let jwk = new JWK(json)
      jwk.meta.should.equal('abc')
    })
  })

  describe('importKey', () => {

  })

  describe('fromCryptoKey', () => {

  })

  describe('sign', () => {
    let jwk

    before(() => {
      return JWK.importKey(ECPrivateJWK).then(key => jwk = key)
    })

    it('should return a promise', () => {
      return jwk.sign(plainTextData).should.be.fulfilled
    })

    it('should resolve a string', () => {
      return jwk.sign(plainTextData).should.eventually.be.a('string')
    })
  })

  describe('verify', () => {
    let jwk

    before(() => {
      return JWK.importKey(ECPublicJWK).then(key => jwk = key)
    })

    it('should return a promise', () => {
      return jwk.verify(plainTextData, signedData).should.be.fulfilled
    })

    it('should resolve a boolean', () => {
      return jwk.verify(plainTextData, signedData).should.eventually.be.true
    })

    it('should fail to verify the signature with incorrect data', () => {
      return jwk.verify(plainTextData + 'a', signedData).should.eventually.be.false
    })
  })

  describe('encrypt', () => {
    let jwk

    before(() => {
      return JWK.importKey(A256GCMJWK).then(key => jwk = key)
    })

    it('should return a promise', () => {
      return jwk.encrypt(plainTextData, Buffer.from('')).should.be.fulfilled
    })

    it('should resolve encrypted data', () => {
      return jwk.encrypt(plainTextData, Buffer.from('')).then(data => {
        data.should.haveOwnProperty('ciphertext')
        data.should.haveOwnProperty('iv')
        data.should.haveOwnProperty('tag')
      })
    })
  })

  describe('decrypt', () => {
    let jwk

    before(() => {
      return JWK.importKey(A256GCMJWK).then(key => jwk = key)
    })

    it('should return a promise', () => {
      let { ciphertext, iv, tag } = encryptedData
      return jwk.decrypt(ciphertext, iv, tag, Buffer.from('')).should.be.fulfilled
    })

    it('should resolve plain text data', () => {
      let { ciphertext, iv, tag } = encryptedData
      return jwk.decrypt(ciphertext, iv, tag, Buffer.from('')).should.eventually.equal(plainTextData)
    })
  })
})
<|endoftext|>


<commit_before>// @flow
/*jshint esversion: 6 */
/*jslint node: true */
"use strict";

const {ipcRenderer} = require("electron");
const {List} = require("immutable");
const {DateTime} = require("luxon");
const Qrcode = require("qrcode");

function logIpc(msgType) {
    ipcRenderer.on(msgType, (...args) => {
        console.log(`IPC Message: ${msgType}, Args:`);
        for (let i = 0; i < args.length; i++)
            console.log(args[i]);
    });
}

// sed -r -n "/\.send/{s/.*send\("([^"]+)".*/logIpc("\1");/p}" main.js|sort -u
logIpc("call-get-wallets");
logIpc("check-login-response");
logIpc("generate-wallet-response");
logIpc("get-settings-response");
logIpc("get-transaction-update");
logIpc("get-wallet-by-name-response");
//logIpc("get-wallets-response");
logIpc("refresh-wallet-response");
logIpc("rename-wallet-response");
logIpc("render-qr-code");
logIpc("save-settings-response");
logIpc("send-finish");
logIpc("show-notification-response");
logIpc("update-wallet-balance");
logIpc("verify-login-response");
logIpc("write-login-response");
logIpc("zz-get-wallets");

let addrListNode = document.getElementById("addrList");
const txListNode = document.getElementById("txList");
const totalBalanceNode = document.getElementById("totalBalance");
const depositTabButton = document.getElementById("depositTabButton");
const depositToAddrInput = document.getElementById("depositToAddr");
const depositAmountInput = document.getElementById("depositAmount");
const depositMsg = document.getElementById("depositMsg");
const depositQrcodeImage = document.getElementById("depositQrcodeImg");
const withdrawTabButton = document.getElementById("withdrawTabButton");
const withdrawAvailBalanceNode = document.getElementById("withdrawAvailBalance");
const withdrawFromAddrInput = document.getElementById("withdrawFromAddr");
const withdrawToAddrInput = document.getElementById("withdrawToAddr");
const withdrawAmountInput = document.getElementById("withdrawAmount");
const withdrawFeeInput = document.getElementById("withdrawFee");
const withdrawMsg = document.getElementById("withdrawMsg");
const withdrawButton = document.getElementById("withdrawButton");
const withdrawStatusTitleNode = document.getElementById("withdrawStatusTitle");
const withdrawStatusBodyNode = document.getElementById("withdrawStatusBody");

const refreshTimeout = 150;
let refreshTimer;
let showZeroBalances = false;
let depositQrcodeTimer;
const myAddrs = new Set();

// ---------------------------------------------------------------------------------------------------------------------
// IPC
ipcRenderer.on("get-wallets-response", (event, msgStr) => {
    const msg = JSON.parse(msgStr);
    checkResponse(msg);
    clearChildNodes(addrListNode);
    clearChildNodes(txListNode);
    // TODO: sort like txs
    addAddresses(msg.wallets);
    addTransactions(msg.transactions);
    setTotalBalance(msg.total);
    scheduleRefresh();
});

ipcRenderer.on("update-wallet-balance", (event, msgStr) => {
    const msg = JSON.parse(msgStr);
    checkResponse(msg);
    setAddressBalance(msg.wallet, msg.balance);
    setTotalBalance(msg.total);
});

ipcRenderer.on("get-transaction-update", (event, msgStr) => {
    const txObj = JSON.parse(msgStr);
    txObj.amount = parseFloat(txObj.amount);
    addTransactions([txObj], true);
});

ipcRenderer.on("refresh-wallet-response", (event, msgStr) => {
    const msg = JSON.parse(msgStr);
    checkResponse(msg);
    scheduleRefresh();
});

ipcRenderer.on("send-finish", (event, result, msg) =>
    updateWithdrawalStatus(result, msg));

window.addEventListener("load", initWallet);

// FUNCTIONS
function checkResponse(resp) {
    if (resp.response !== "OK") {
        console.error(resp);
        throw new Error("Failed response");
    }
}

// Expects a balance node with one balanceAmount child node
function setBalanceText(balanceNode, balance) {
    const balanceAmountNode = balanceNode.firstElementChild;
    balanceAmountNode.textContent = formatBalance(balance);
    if (balance > 0)
        balanceNode.classList.add("addrBalancePositive");
    else
        balanceNode.classList.remove("addrBalancePositive");
}

function createAddrItem(addrObj) {
    const addrItem = cloneTemplate("addrItemTemplate");

    addrItem.dataset.addr = addrObj.addr;
    addrItem.dataset.name = addrObj.name || '';

    if (addrObj.name) {
        addrItem.getElementsByClassName("addrName")[0].textContent = addrObj.name;
    }

    const addrTextNode = addrItem.getElementsByClassName("addrText")[0];
    addrTextNode.addEventListener("click", () => openZenExplorer("address/" + addrObj.addr));
    addrTextNode.textContent = addrObj.addr;

    addrItem.getElementsByClassName("addrDepositButton")[0].addEventListener("click", () => {
        depositToAddrInput.value = addrObj.addr;
        updateDepositQrcode();
        depositTabButton.click();
    });
    addrItem.getElementsByClassName("addrWithdrawButton")[0].addEventListener("click", () => {
        withdrawFromAddrInput.value = addrObj.addr;
        validateWithdrawForm();
        withdrawTabButton.click();
    });

    setAddrItemBalance(addrItem, addrObj.lastbalance);
    return addrItem;
}

function setAddrItemBalance(addrItem, balance) {
    addrItem.dataset.balance = balance;
    hideElement(addrItem, balance === 0 && !showZeroBalances);
    const balanceNode = addrItem.getElementsByClassName("addrBalance")[0];
    setBalanceText(balanceNode, balance);
    const withdrawButton = addrItem.getElementsByClassName("addrWithdrawButton")[0];
    withdrawButton.disabled = balance === 0;
}

function shortTxId(txId) {
    const edgeLen = 8;
    return txId.substring(0, edgeLen) + "…" + txId.substring(txId.length - edgeLen);
}

function createTxItem(txObj, newTx = false) {
    const node = txObj.block >= 0 ? cloneTemplate("txItemTemplate") : cloneTemplate("txMempoolItemTemplate");

    node.dataset.txid = txObj.txid;
    node.dataset.blockheight = txObj.block;

    if (txObj.block >= 0) {
        node.querySelector(".txDate").textContent = DateTime.fromMillis(txObj.time * 1000).toLocaleString(DateTime.DATETIME_MED);
        node.querySelector(".txBlock").textContent = txObj.block;
    }

    const txIdNode = node.getElementsByClassName("txId")[0];
    txIdNode.addEventListener("click", () => openZenExplorer("tx/" + txObj.txid));
    txIdNode.textContent = shortTxId(txObj.txid);

    let balanceStr, balanceClass;
    if (txObj.amount >= 0) {
        balanceStr = "+" + formatBalance(txObj.amount);
        balanceClass = "txBalancePositive";
    } else {
        balanceStr = "-" + formatBalance(-txObj.amount);
        balanceClass = "txBalanceNegative";
    }
    node.querySelector(".txBalance").classList.add(balanceClass);
    node.querySelector(".txBalanceAmount").textContent = balanceStr;

    const txAddrsNode = node.getElementsByClassName("txAddrs")[0];
    txObj.vins.split(",").sort().filter(addr => myAddrs.has(addr)).forEach(vin => {
        const txVinNode = document.createElement("span");
        txVinNode.classList.add("txVin");
        txVinNode.textContent = vin;
        txAddrsNode.append(txVinNode);
    });
    txObj.vouts.split(",").sort().filter(addr => myAddrs.has(addr)).forEach(vout => {
        const txVoutNode = document.createElement("span");
        txVoutNode.classList.add("txVout");
        txVoutNode.textContent = vout;
        txAddrsNode.append(txVoutNode);
    });

    if (newTx) {
        node.classList.add("txItemNew");
    }

    return node;
}

function addAddresses(addrs) {
    addrs.forEach(addrObj => {
        myAddrs.add(addrObj.addr);
        const addrItem = createAddrItem(addrObj);
        hideElement(addrItem, addrObj.lastbalance === 0 && !showZeroBalances);
        addrListNode.appendChild(addrItem);
    });
    sortAddrItems();
}

function sortAddrItems() {
    const sortedAddrItems = [...addrListNode.childNodes].sort((a, b) => {
        const balA = parseFloat(a.dataset.balance);
        const balB = parseFloat(b.dataset.balance);
        if (balA === balB) {
            const nameA = a.dataset.name || '';
            const nameB = b.dataset.name || '';
            return nameA.localeCompare(nameB);
        }
        return balB - balA;
    });
    const newAddrListNode = addrListNode.cloneNode(false);
    newAddrListNode.append(...sortedAddrItems);
    addrListNode.parentNode.replaceChild(newAddrListNode, addrListNode);
    addrListNode = newAddrListNode;
}

function setAddressBalance(addr, balance) {
    const addrItem = addrListNode.querySelector(`[data-addr='${addr}']`);
    setAddrItemBalance(addrItem, balance);
    sortAddrItems();
}

function addTransactions(txs, newTx = false) {
    txs.sort((a, b) => {
        if ((a.block - b.block) === 0) {
            return 0;
        } else if (a.block < 0) {
            return 1;
        } else if (b.block < 0) {
            return -1;
        }
        return a.block - b.block;
    });

    for (const txObj of txs) {
        const oldTxItem = txListNode.querySelector(`[data-txid='${txObj.txid}']`);
        if (oldTxItem) {
            if (oldTxItem.dataset.blockheight !== "-1") {
                console.error("Attempting to replace transaction in block");
            } else if (txObj.block >= 0) {
                txListNode.replaceChild(createTxItem(txObj, newTx), oldTxItem);
            }
        } else {
            txListNode.prepend(createTxItem(txObj, newTx));
        }
    }
}

function setTotalBalance(balance) {
    setBalanceText(totalBalanceNode, balance);
}

function toggleZeroBalanceAddrs() {
    showZeroBalances = !showZeroBalances;
    [...addrListNode.querySelectorAll("[data-balance='0']")]
        .forEach(node => hideElement(node, !showZeroBalances));
}

function scheduleRefresh() {
    if (refreshTimer)
        clearTimeout(refreshTimer);
    refreshTimer = setTimeout(() => refresh(), refreshTimeout * 1000);
}

function refresh() {
    ipcRenderer.send("refresh-wallet");
    scheduleRefresh();
}

function initDepositView() {
    const qrcodeTypeDelay = 500; // ms
    depositToAddrInput.addEventListener("input", () => updateDepositQrcode(qrcodeTypeDelay));
    depositAmountInput.addEventListener("input", () => updateDepositQrcode(qrcodeTypeDelay));
}

function updateDepositQrcode(qrcodeDelay = 0) {
    const qrcodeOpts = {
        errorCorrectionLevel: "H",
        scale: 5,
        color: {dark: "#000000ff", light: "#fefefeff"}
    };

    const toAddr = depositToAddrInput.value;
    const amount = parseFloat(depositAmountInput.value || 0);

    if (!toAddr) {
        depositMsg.textContent = "WARNING: To address is empty";
    } else if (!addrListNode.querySelector(`[data-addr='${toAddr}']`)) {
        depositMsg.textContent = "WARNING: To address does not belong to this wallet";
    } else if (!amount) {
        depositMsg.textContent = "WARNING: Amount is not positive";
    } else {
        depositMsg.textContent = "\xA0"; //
    }
    if (depositQrcodeTimer) {
        clearTimeout(depositQrcodeTimer);
    }
    depositQrcodeTimer = setTimeout(() => {
        const json = {symbol: "zen", tAddr: toAddr, amount: amount};
        Qrcode.toDataURL(JSON.stringify(json), qrcodeOpts, (err, url) => {
            if (err)
                console.log(err);
            else
                depositQrcodeImage.src = url;
            depositQrcodeTimer = null;
        });
    }, qrcodeDelay);
}

function initWithdrawView() {
    withdrawFromAddrInput.addEventListener("input", validateWithdrawForm);
    withdrawToAddrInput.addEventListener("input", validateWithdrawForm);
    withdrawAmountInput.addEventListener("input", validateWithdrawForm);
    withdrawFeeInput.addEventListener("input", validateWithdrawForm);
    withdrawButton.addEventListener("click", () => {
        if (confirm("Do you really want to send this transaction?")) {
            ipcRenderer.send("send",
                withdrawFromAddrInput.value,
                withdrawToAddrInput.value,
                withdrawFeeInput.value,
                withdrawAmountInput.value);
        }
    });
    validateWithdrawForm();
}

function validateWithdrawForm() {
    const fromAddr = withdrawFromAddrInput.value;
    const toAddr = withdrawToAddrInput.value;
    const amount = parseFloat(withdrawAmountInput.value || 0);
    const fee = parseFloat(withdrawFeeInput.value || 0);

    withdrawButton.disabled = true;
    withdrawAvailBalance.textContent = 0;

    if (!fromAddr) {
        withdrawMsg.textContent = "ERROR: The From address is empty";
        return;
    }

    const fromAddrItem = addrListNode.querySelector(`[data-addr='${fromAddr}']`);
    if (!fromAddrItem) {
        withdrawMsg.textContent = "ERROR: The From address does not belong to this wallet";
        return;
    }

    const fromBalance = parseFloat(fromAddrItem.dataset.balance);
    withdrawAvailBalance.textContent = fromBalance;

    if (!toAddr) {
        withdrawMsg.textContent = "ERROR: The To address is empty";
        return;
    }
    if (!amount) {
        withdrawMsg.textContent = "ERROR: The amount is not positive";
        return;
    }
    if (amount + fee > fromBalance) {
        withdrawMsg.textContent = "ERROR: Insufficient funds on the From address";
        return;
    }

    withdrawMsg.textContent = "\xA0"; //
    withdrawButton.disabled = false;
}

function updateWithdrawalStatus(result, msg) {
    if (result === "error") {
        withdrawStatusTitleNode.classList.add("withdrawStatusBad");
        withdrawStatusTitleNode.textContent = "Error:"
    } else if (result === "ok") {
        withdrawStatusTitleNode.classList.remove("withdrawStatusBad");
        withdrawStatusTitleNode.textContent = "Transaction has been successfully sent";
    }
    withdrawStatusBodyNode.innerHTML = msg;
}

function initWallet() {
    fixLinks();
    initDepositView();
    initWithdrawView();
    document.getElementById("actionShowZeroBalances").addEventListener("click", toggleZeroBalanceAddrs);
    document.getElementById("refreshButton").addEventListener("click", refresh);
    ipcRenderer.send("get-wallets");
}
<commit_msg>Increase refresh interval to 5 mins<commit_after>// @flow
/*jshint esversion: 6 */
/*jslint node: true */
"use strict";

const {ipcRenderer} = require("electron");
const {List} = require("immutable");
const {DateTime} = require("luxon");
const Qrcode = require("qrcode");

function logIpc(msgType) {
    ipcRenderer.on(msgType, (...args) => {
        console.log(`IPC Message: ${msgType}, Args:`);
        for (let i = 0; i < args.length; i++)
            console.log(args[i]);
    });
}

// sed -r -n "/\.send/{s/.*send\("([^"]+)".*/logIpc("\1");/p}" main.js|sort -u
logIpc("call-get-wallets");
logIpc("check-login-response");
logIpc("generate-wallet-response");
logIpc("get-settings-response");
logIpc("get-transaction-update");
logIpc("get-wallet-by-name-response");
//logIpc("get-wallets-response");
logIpc("refresh-wallet-response");
logIpc("rename-wallet-response");
logIpc("render-qr-code");
logIpc("save-settings-response");
logIpc("send-finish");
logIpc("show-notification-response");
logIpc("update-wallet-balance");
logIpc("verify-login-response");
logIpc("write-login-response");
logIpc("zz-get-wallets");

let addrListNode = document.getElementById("addrList");
const txListNode = document.getElementById("txList");
const totalBalanceNode = document.getElementById("totalBalance");
const depositTabButton = document.getElementById("depositTabButton");
const depositToAddrInput = document.getElementById("depositToAddr");
const depositAmountInput = document.getElementById("depositAmount");
const depositMsg = document.getElementById("depositMsg");
const depositQrcodeImage = document.getElementById("depositQrcodeImg");
const withdrawTabButton = document.getElementById("withdrawTabButton");
const withdrawAvailBalanceNode = document.getElementById("withdrawAvailBalance");
const withdrawFromAddrInput = document.getElementById("withdrawFromAddr");
const withdrawToAddrInput = document.getElementById("withdrawToAddr");
const withdrawAmountInput = document.getElementById("withdrawAmount");
const withdrawFeeInput = document.getElementById("withdrawFee");
const withdrawMsg = document.getElementById("withdrawMsg");
const withdrawButton = document.getElementById("withdrawButton");
const withdrawStatusTitleNode = document.getElementById("withdrawStatusTitle");
const withdrawStatusBodyNode = document.getElementById("withdrawStatusBody");

const refreshTimeout = 300;
let refreshTimer;
let showZeroBalances = false;
let depositQrcodeTimer;
const myAddrs = new Set();

// ---------------------------------------------------------------------------------------------------------------------
// IPC
ipcRenderer.on("get-wallets-response", (event, msgStr) => {
    const msg = JSON.parse(msgStr);
    checkResponse(msg);
    clearChildNodes(addrListNode);
    clearChildNodes(txListNode);
    // TODO: sort like txs
    addAddresses(msg.wallets);
    addTransactions(msg.transactions);
    setTotalBalance(msg.total);
    scheduleRefresh();
});

ipcRenderer.on("update-wallet-balance", (event, msgStr) => {
    const msg = JSON.parse(msgStr);
    checkResponse(msg);
    setAddressBalance(msg.wallet, msg.balance);
    setTotalBalance(msg.total);
});

ipcRenderer.on("get-transaction-update", (event, msgStr) => {
    const txObj = JSON.parse(msgStr);
    txObj.amount = parseFloat(txObj.amount);
    addTransactions([txObj], true);
});

ipcRenderer.on("refresh-wallet-response", (event, msgStr) => {
    const msg = JSON.parse(msgStr);
    checkResponse(msg);
    scheduleRefresh();
});

ipcRenderer.on("send-finish", (event, result, msg) =>
    updateWithdrawalStatus(result, msg));

window.addEventListener("load", initWallet);

// FUNCTIONS
function checkResponse(resp) {
    if (resp.response !== "OK") {
        console.error(resp);
        throw new Error("Failed response");
    }
}

// Expects a balance node with one balanceAmount child node
function setBalanceText(balanceNode, balance) {
    const balanceAmountNode = balanceNode.firstElementChild;
    balanceAmountNode.textContent = formatBalance(balance);
    if (balance > 0)
        balanceNode.classList.add("addrBalancePositive");
    else
        balanceNode.classList.remove("addrBalancePositive");
}

function createAddrItem(addrObj) {
    const addrItem = cloneTemplate("addrItemTemplate");

    addrItem.dataset.addr = addrObj.addr;
    addrItem.dataset.name = addrObj.name || '';

    if (addrObj.name) {
        addrItem.getElementsByClassName("addrName")[0].textContent = addrObj.name;
    }

    const addrTextNode = addrItem.getElementsByClassName("addrText")[0];
    addrTextNode.addEventListener("click", () => openZenExplorer("address/" + addrObj.addr));
    addrTextNode.textContent = addrObj.addr;

    addrItem.getElementsByClassName("addrDepositButton")[0].addEventListener("click", () => {
        depositToAddrInput.value = addrObj.addr;
        updateDepositQrcode();
        depositTabButton.click();
    });
    addrItem.getElementsByClassName("addrWithdrawButton")[0].addEventListener("click", () => {
        withdrawFromAddrInput.value = addrObj.addr;
        validateWithdrawForm();
        withdrawTabButton.click();
    });

    setAddrItemBalance(addrItem, addrObj.lastbalance);
    return addrItem;
}

function setAddrItemBalance(addrItem, balance) {
    addrItem.dataset.balance = balance;
    hideElement(addrItem, balance === 0 && !showZeroBalances);
    const balanceNode = addrItem.getElementsByClassName("addrBalance")[0];
    setBalanceText(balanceNode, balance);
    const withdrawButton = addrItem.getElementsByClassName("addrWithdrawButton")[0];
    withdrawButton.disabled = balance === 0;
}

function shortTxId(txId) {
    const edgeLen = 8;
    return txId.substring(0, edgeLen) + "…" + txId.substring(txId.length - edgeLen);
}

function createTxItem(txObj, newTx = false) {
    const node = txObj.block >= 0 ? cloneTemplate("txItemTemplate") : cloneTemplate("txMempoolItemTemplate");

    node.dataset.txid = txObj.txid;
    node.dataset.blockheight = txObj.block;

    if (txObj.block >= 0) {
        node.querySelector(".txDate").textContent = DateTime.fromMillis(txObj.time * 1000).toLocaleString(DateTime.DATETIME_MED);
        node.querySelector(".txBlock").textContent = txObj.block;
    }

    const txIdNode = node.getElementsByClassName("txId")[0];
    txIdNode.addEventListener("click", () => openZenExplorer("tx/" + txObj.txid));
    txIdNode.textContent = shortTxId(txObj.txid);

    let balanceStr, balanceClass;
    if (txObj.amount >= 0) {
        balanceStr = "+" + formatBalance(txObj.amount);
        balanceClass = "txBalancePositive";
    } else {
        balanceStr = "-" + formatBalance(-txObj.amount);
        balanceClass = "txBalanceNegative";
    }
    node.querySelector(".txBalance").classList.add(balanceClass);
    node.querySelector(".txBalanceAmount").textContent = balanceStr;

    const txAddrsNode = node.getElementsByClassName("txAddrs")[0];
    txObj.vins.split(",").sort().filter(addr => myAddrs.has(addr)).forEach(vin => {
        const txVinNode = document.createElement("span");
        txVinNode.classList.add("txVin");
        txVinNode.textContent = vin;
        txAddrsNode.append(txVinNode);
    });
    txObj.vouts.split(",").sort().filter(addr => myAddrs.has(addr)).forEach(vout => {
        const txVoutNode = document.createElement("span");
        txVoutNode.classList.add("txVout");
        txVoutNode.textContent = vout;
        txAddrsNode.append(txVoutNode);
    });

    if (newTx) {
        node.classList.add("txItemNew");
    }

    return node;
}

function addAddresses(addrs) {
    addrs.forEach(addrObj => {
        myAddrs.add(addrObj.addr);
        const addrItem = createAddrItem(addrObj);
        hideElement(addrItem, addrObj.lastbalance === 0 && !showZeroBalances);
        addrListNode.appendChild(addrItem);
    });
    sortAddrItems();
}

function sortAddrItems() {
    const sortedAddrItems = [...addrListNode.childNodes].sort((a, b) => {
        const balA = parseFloat(a.dataset.balance);
        const balB = parseFloat(b.dataset.balance);
        if (balA === balB) {
            const nameA = a.dataset.name || '';
            const nameB = b.dataset.name || '';
            return nameA.localeCompare(nameB);
        }
        return balB - balA;
    });
    const newAddrListNode = addrListNode.cloneNode(false);
    newAddrListNode.append(...sortedAddrItems);
    addrListNode.parentNode.replaceChild(newAddrListNode, addrListNode);
    addrListNode = newAddrListNode;
}

function setAddressBalance(addr, balance) {
    const addrItem = addrListNode.querySelector(`[data-addr='${addr}']`);
    setAddrItemBalance(addrItem, balance);
    sortAddrItems();
}

function addTransactions(txs, newTx = false) {
    txs.sort((a, b) => {
        if ((a.block - b.block) === 0) {
            return 0;
        } else if (a.block < 0) {
            return 1;
        } else if (b.block < 0) {
            return -1;
        }
        return a.block - b.block;
    });

    for (const txObj of txs) {
        const oldTxItem = txListNode.querySelector(`[data-txid='${txObj.txid}']`);
        if (oldTxItem) {
            if (oldTxItem.dataset.blockheight !== "-1") {
                console.error("Attempting to replace transaction in block");
            } else if (txObj.block >= 0) {
                txListNode.replaceChild(createTxItem(txObj, newTx), oldTxItem);
            }
        } else {
            txListNode.prepend(createTxItem(txObj, newTx));
        }
    }
}

function setTotalBalance(balance) {
    setBalanceText(totalBalanceNode, balance);
}

function toggleZeroBalanceAddrs() {
    showZeroBalances = !showZeroBalances;
    [...addrListNode.querySelectorAll("[data-balance='0']")]
        .forEach(node => hideElement(node, !showZeroBalances));
}

function scheduleRefresh() {
    if (refreshTimer)
        clearTimeout(refreshTimer);
    refreshTimer = setTimeout(() => refresh(), refreshTimeout * 1000);
}

function refresh() {
    ipcRenderer.send("refresh-wallet");
    scheduleRefresh();
}

function initDepositView() {
    const qrcodeTypeDelay = 500; // ms
    depositToAddrInput.addEventListener("input", () => updateDepositQrcode(qrcodeTypeDelay));
    depositAmountInput.addEventListener("input", () => updateDepositQrcode(qrcodeTypeDelay));
}

function updateDepositQrcode(qrcodeDelay = 0) {
    const qrcodeOpts = {
        errorCorrectionLevel: "H",
        scale: 5,
        color: {dark: "#000000ff", light: "#fefefeff"}
    };

    const toAddr = depositToAddrInput.value;
    const amount = parseFloat(depositAmountInput.value || 0);

    if (!toAddr) {
        depositMsg.textContent = "WARNING: To address is empty";
    } else if (!addrListNode.querySelector(`[data-addr='${toAddr}']`)) {
        depositMsg.textContent = "WARNING: To address does not belong to this wallet";
    } else if (!amount) {
        depositMsg.textContent = "WARNING: Amount is not positive";
    } else {
        depositMsg.textContent = "\xA0"; //
    }
    if (depositQrcodeTimer) {
        clearTimeout(depositQrcodeTimer);
    }
    depositQrcodeTimer = setTimeout(() => {
        const json = {symbol: "zen", tAddr: toAddr, amount: amount};
        Qrcode.toDataURL(JSON.stringify(json), qrcodeOpts, (err, url) => {
            if (err)
                console.log(err);
            else
                depositQrcodeImage.src = url;
            depositQrcodeTimer = null;
        });
    }, qrcodeDelay);
}

function initWithdrawView() {
    withdrawFromAddrInput.addEventListener("input", validateWithdrawForm);
    withdrawToAddrInput.addEventListener("input", validateWithdrawForm);
    withdrawAmountInput.addEventListener("input", validateWithdrawForm);
    withdrawFeeInput.addEventListener("input", validateWithdrawForm);
    withdrawButton.addEventListener("click", () => {
        if (confirm("Do you really want to send this transaction?")) {
            ipcRenderer.send("send",
                withdrawFromAddrInput.value,
                withdrawToAddrInput.value,
                withdrawFeeInput.value,
                withdrawAmountInput.value);
        }
    });
    validateWithdrawForm();
}

function validateWithdrawForm() {
    const fromAddr = withdrawFromAddrInput.value;
    const toAddr = withdrawToAddrInput.value;
    const amount = parseFloat(withdrawAmountInput.value || 0);
    const fee = parseFloat(withdrawFeeInput.value || 0);

    withdrawButton.disabled = true;
    withdrawAvailBalance.textContent = 0;

    if (!fromAddr) {
        withdrawMsg.textContent = "ERROR: The From address is empty";
        return;
    }

    const fromAddrItem = addrListNode.querySelector(`[data-addr='${fromAddr}']`);
    if (!fromAddrItem) {
        withdrawMsg.textContent = "ERROR: The From address does not belong to this wallet";
        return;
    }

    const fromBalance = parseFloat(fromAddrItem.dataset.balance);
    withdrawAvailBalance.textContent = fromBalance;

    if (!toAddr) {
        withdrawMsg.textContent = "ERROR: The To address is empty";
        return;
    }
    if (!amount) {
        withdrawMsg.textContent = "ERROR: The amount is not positive";
        return;
    }
    if (amount + fee > fromBalance) {
        withdrawMsg.textContent = "ERROR: Insufficient funds on the From address";
        return;
    }

    withdrawMsg.textContent = "\xA0"; //
    withdrawButton.disabled = false;
}

function updateWithdrawalStatus(result, msg) {
    if (result === "error") {
        withdrawStatusTitleNode.classList.add("withdrawStatusBad");
        withdrawStatusTitleNode.textContent = "Error:"
    } else if (result === "ok") {
        withdrawStatusTitleNode.classList.remove("withdrawStatusBad");
        withdrawStatusTitleNode.textContent = "Transaction has been successfully sent";
    }
    withdrawStatusBodyNode.innerHTML = msg;
}

function initWallet() {
    fixLinks();
    initDepositView();
    initWithdrawView();
    document.getElementById("actionShowZeroBalances").addEventListener("click", toggleZeroBalanceAddrs);
    document.getElementById("refreshButton").addEventListener("click", refresh);
    ipcRenderer.send("get-wallets");
}
<|endoftext|>