<commit_before>'use strict';

module.exports = function (babel) {
	var t = babel.types;

	return {
		inherits: require("babel-plugin-syntax-jsx"),
		name: "redom-jsx-transform",
		visitor: {
			JSXElement: function JSXElement(path, file) {
				var thisAttr = [];
				var restAttr = [];
				var list;
				var node = path.node;
				path.node.openingElement.attributes.forEach((attr) => {
					if(attr.name.name === 'list'){
                      	list = attr;
                    }

					(attr.name.name === 'this' ? thisAttr : restAttr).push(attr);
				});
				if (path.node.openingElement.name.name.match(/^[A-Z]/)) {
					var attribObj = restAttr.length ? buildOpeningElementAttributes(restAttr, file) : t.objectExpression([]);
					var children = t.react.buildChildren(path.node).map((node) => {
						if (t.isLiteral(node)) {
							return t.callExpression(t.identifier('text'), [node])
						}
						return node;
					});

					node = t.newExpression(path.node.openingElement.name, [attribObj].concat(children));
				}

				if (thisAttr.length) {
					var attr = thisAttr[thisAttr.length - 1];
					var thisMember = t.isJSXExpressionContainer(attr.value) ? attr.value.expression : attr.value;
					var assignToThis = t.assignmentExpression('=', t.memberExpression(t.thisExpression(), thisMember, true), node);
					path.node.openingElement.attributes = restAttr;
					node = t.isJSXElement(path.parent) ? t.jSXExpressionContainer(assignToThis) : assignToThis;
				}

				if(list){
					var listMember = t.isJSXExpressionContainer(list.value) ? list.value.expression : list.value;
					node = t.callExpression(t.identifier('list'), [node, listMember])
				}

				if (node !== path.node) {
					path.replaceWith(node);
				}

			}
		}
	};

	function convertAttributeValue(node) {
		if (t.isJSXExpressionContainer(node)) {
			return node.expression;
		} else {
			return node;
		}
	}

	function convertAttribute(node) {
		let value = convertAttributeValue(node.value || t.booleanLiteral(true));

		if (t.isStringLiteral(value) && !t.isJSXExpressionContainer(node.value)) {
			value.value = value.value.replace(/\n\s+/g, " ");
		}

		if (t.isValidIdentifier(node.name.name)) {
			node.name.type = "Identifier";
		} else {
			node.name = t.stringLiteral(node.name.name);
		}

		return t.inherits(t.objectProperty(node.name, value), node);
	}

	function buildOpeningElementAttributes(attribs, file) {
		let _props = [];
		let objs = [];

		let useBuiltIns = file.opts.useBuiltIns || false;
		if (typeof useBuiltIns !== "boolean") {
			throw new Error("transform-react-jsx currently only accepts a boolean option for useBuiltIns (defaults to false)");
		}

		function pushProps() {
			if (!_props.length) return;

			objs.push(t.objectExpression(_props));
			_props = [];
		}

		while (attribs.length) {
			let prop = attribs.shift();
			if (t.isJSXSpreadAttribute(prop)) {
				pushProps();
				objs.push(prop.argument);
			} else {
				_props.push(convertAttribute(prop));
			}
		}

		pushProps();

		if (objs.length === 1) {
			// only one object
			attribs = objs[0];
		} else {
			// looks like we have multiple objects
			if (!t.isObjectExpression(objs[0])) {
				objs.unshift(t.objectExpression([]));
			}

			const helper = useBuiltIns ?
				t.memberExpression(t.identifier("Object"), t.identifier("assign")) :
				file.addHelper("extends");

			// spread it
			attribs = t.callExpression(helper, objs);
		}

		return attribs;
	}

};
<commit_msg>fix 'Maximum call...' error when using list without component<commit_after>'use strict';

module.exports = function (babel) {
	var t = babel.types;

	return {
		inherits: require("babel-plugin-syntax-jsx"),
		name: "redom-jsx-transform",
		visitor: {
			JSXElement: function JSXElement(path, file) {
				var thisAttr = [];
              	var listAttr = [];
				var restAttr = [];
              	var list;
				var node = path.node;
				path.node.openingElement.attributes.forEach((attr) => {
                  	if(attr.name.name === 'list'){
                      	listAttr.push(attr);
                    }else if(attr.name.name === 'this'){
                    	thisAttr.push(attr);
                    }else{
                      	restAttr.push(attr)
                    }
                }
				);
				if (path.node.openingElement.name.name.match(/^[A-Z]/)) {
					var attribObj = restAttr.length ? buildOpeningElementAttributes(restAttr, file) : t.objectExpression([]);
					var children = t.react.buildChildren(path.node).map((node) => {
						if (t.isLiteral(node)) {
							return t.callExpression(t.identifier('text'), [node])
						}
						return node;
					});

					node = t.newExpression(path.node.openingElement.name, [attribObj].concat(children));
				}

				if (thisAttr.length) {
					var attr = thisAttr[thisAttr.length - 1];
					var thisMember = t.isJSXExpressionContainer(attr.value) ? attr.value.expression : attr.value;
					var assignToThis = t.assignmentExpression('=', t.memberExpression(t.thisExpression(), thisMember, true), node);
					path.node.openingElement.attributes = restAttr;
					node = t.isJSXElement(path.parent) ? t.jSXExpressionContainer(assignToThis) : assignToThis;
				}

              	if(listAttr.length){
                  list = listAttr[listAttr.length - 1];
                  var listMember = t.isJSXExpressionContainer(list.value) ? list.value.expression : list.value;
                  path.node.openingElement.attributes = restAttr;
                  node = t.callExpression(t.identifier('list'), [node, listMember]);
                }

				if (node !== path.node) {
					path.replaceWith(node);
				}

			}
		}
	};

	function convertAttributeValue(node) {
		if (t.isJSXExpressionContainer(node)) {
			return node.expression;
		} else {
			return node;
		}
	}

	function convertAttribute(node) {
		let value = convertAttributeValue(node.value || t.booleanLiteral(true));

		if (t.isStringLiteral(value) && !t.isJSXExpressionContainer(node.value)) {
			value.value = value.value.replace(/\n\s+/g, " ");
		}

		if (t.isValidIdentifier(node.name.name)) {
			node.name.type = "Identifier";
		} else {
			node.name = t.stringLiteral(node.name.name);
		}

		return t.inherits(t.objectProperty(node.name, value), node);
	}

	function buildOpeningElementAttributes(attribs, file) {
		let _props = [];
		let objs = [];

		let useBuiltIns = file.opts.useBuiltIns || false;
		if (typeof useBuiltIns !== "boolean") {
			throw new Error("transform-react-jsx currently only accepts a boolean option for useBuiltIns (defaults to false)");
		}

		function pushProps() {
			if (!_props.length) return;

			objs.push(t.objectExpression(_props));
			_props = [];
		}

		while (attribs.length) {
			let prop = attribs.shift();
			if (t.isJSXSpreadAttribute(prop)) {
				pushProps();
				objs.push(prop.argument);
			} else {
				_props.push(convertAttribute(prop));
			}
		}

		pushProps();

		if (objs.length === 1) {
			// only one object
			attribs = objs[0];
		} else {
			// looks like we have multiple objects
			if (!t.isObjectExpression(objs[0])) {
				objs.unshift(t.objectExpression([]));
			}

			const helper = useBuiltIns ?
				t.memberExpression(t.identifier("Object"), t.identifier("assign")) :
				file.addHelper("extends");

			// spread it
			attribs = t.callExpression(helper, objs);
		}

		return attribs;
	}

};
<|endoftext|>


<commit_before>const selectDialog = require("./select")
const selectButton = require("./selectButton")

module.exports = ({ items, label }) =>
  selectButton(
    ctx => () => label(ctx.value()),
    selectDialog({
      title: "Choisir un élément",
      value: Array.isArray(items) ? () => () => items : items,
      itemLabel: ctx => () => label(ctx.value),
    })
  )
<commit_msg>more customizable itemPicker<commit_after>const isFunction = require("lodash/isFunction")
const selectDialog = require("./select")
const selectButton = require("./selectButton")

module.exports = ({ items, label, title }) =>
  selectButton(
    ctx => () => label(isFunction(ctx.value) ? ctx.value() : ctx.value, ctx),
    selectDialog({
      title: title || "Choisir un élément",
      value: Array.isArray(items) ? () => () => items : items,
      itemLabel: ctx => () => label(ctx.value, ctx),
    })
  )
<|endoftext|>


<commit_before>import React from 'react';
const Mustache = require('mustache');

export default class ReactMustache extends React.Component {

  compileTemplate(template, data){
    // lazy template compiling
    return Mustache.render(template,data);
  }

  render() {
    const { template, data, Component, ...props } = this.props
    if (!template) return false

    const __html = this.compileTemplate(template, data);

    return (
      <Component dangerouslySetInnerHTML={{__html}} {...props}/>
    )
  }
}

ReactMustache.defaultProps = {
  data: {},
  Component: 'div'
}
<commit_msg> Export default moved to the bottom<commit_after>import React from 'react';
const Mustache = require('mustache');

class ReactMustache extends React.Component {

  compileTemplate(template, data){
    // lazy template compiling
    return Mustache.render(template,data);
  }

  render() {
    const { template, data, Component, ...props } = this.props
    if (!template) return false

    const __html = this.compileTemplate(template, data);

    return (
      <Component dangerouslySetInnerHTML={{__html}} {...props}/>
    )
  }
}

ReactMustache.defaultProps = {
  data: {},
  Component: 'div'
}

export default ReactMustache;
<|endoftext|>


<commit_before>/**
 * Small library for calculation of basic financial factors.
 * @module finance-factors/src
 * @license MIT
 * @author diegofigs
 */

/**
 * Returns a Future Worth Factor assuming a single payment.
 * @param {Number} i 100-based interest rate e.g. 15% = 15
 * @param {Number} n number of periods
 * @return {Number}
 */
export function singleFW (i, n) {
  let futureWorthFactor = Math.pow((1 + (i / 100)), n)
  return futureWorthFactor
}

/**
 * Returns a Present Worth Factor assuming a single payment
 * in the future.
 * @param {Number} i 100-based interest rate e.g. 15% = 15
 * @param {Number} n number of periods
 * @return {Number}
 */
export function singlePW (i, n) {
  let presentWorthFactor = 1 / singleFW(i, n)
  return presentWorthFactor
}

/**
 * Returns an Annual Worth Factor assuming a single payment.
 * @param {Number} i 100-based interest rate e.g. 15% = 15
 * @param {Number} n number of periods
 * @return {Number}
 */
export function uniformAWfromP (i, n) {
  let futureWorthFactor = this.singleFW(i, n)
  let annualWorthFactor = (futureWorthFactor * (i / 100) / (futureWorthFactor - 1))
  return annualWorthFactor
}

/**
 * Returns an Annual Worth Factor assuming a single payment
 * in the future.
 * @param {Number} i 100-based interest rate e.g. 15% = 15
 * @param {Number} n number of periods
 * @return {Number}
 */
export function uniformAWfromF (i, n) {
  let futureWorthFactor = this.singleFW(i, n)
  let annualWorthFactor = ((i / 100) / (futureWorthFactor - 1))
  return annualWorthFactor
}

/**
 * Returns a Future Worth Factor assuming an uniform annual
 * payment across 'n' number of periods.
 * @param {Number} i 100-based interest rate e.g. 15% = 15
 * @param {Number} n number of periods
 * @return {Number}
 */
export function uniformFWfromA (i, n) {
  return 1 / uniformAWfromF(i, n)
}

/**
 * Returns a Present Worth Factor assuming an uniform annual
 * payment across 'n' number of periods.
 * @param {Number} i 100-based interest rate e.g. 15% = 15
 * @param {Number} n number of periods
 * @return {Number}
 */
export function uniformPWfromA (i, n) {
  return 1 / uniformAWfromP(i, n)
}
<commit_msg>add examples for single methods, fix author tag<commit_after>/**
 * Small library for calculation of basic financial factors.
 * @module finance-factors
 * @author diegofigs <diego.fv94@gmail.com>
 * @license MIT
 */

/**
 * Returns a Future Worth Factor assuming a single payment.
 * @param {Number} i 100-based interest rate e.g. 15% = 15
 * @param {Number} n number of periods
 * @return {Number}
 * @example let futureWorth = singleFW(5, 1);
 * console.log(futureWorth); // Returns 1.05
 */
export function singleFW (i, n) {
  let futureWorthFactor = Math.pow((1 + (i / 100)), n)
  return futureWorthFactor
}

/**
 * Returns a Present Worth Factor assuming a single payment
 * in the future.
 * @param {Number} i 100-based interest rate e.g. 15% = 15
 * @param {Number} n number of periods
 * @return {Number}
 * @example let presentWorth = singlePW(5, 1);
 * console.log(presentWorth); // Returns 0.9523809523809523
 */
export function singlePW (i, n) {
  let presentWorthFactor = 1 / singleFW(i, n)
  return presentWorthFactor
}

/**
 * Returns an Annual Worth Factor assuming a single payment.
 * @param {Number} i 100-based interest rate e.g. 15% = 15
 * @param {Number} n number of periods
 * @return {Number}
 */
export function uniformAWfromP (i, n) {
  let futureWorthFactor = this.singleFW(i, n)
  let annualWorthFactor = (futureWorthFactor * (i / 100) / (futureWorthFactor - 1))
  return annualWorthFactor
}

/**
 * Returns an Annual Worth Factor assuming a single payment
 * in the future.
 * @param {Number} i 100-based interest rate e.g. 15% = 15
 * @param {Number} n number of periods
 * @return {Number}
 */
export function uniformAWfromF (i, n) {
  let futureWorthFactor = this.singleFW(i, n)
  let annualWorthFactor = ((i / 100) / (futureWorthFactor - 1))
  return annualWorthFactor
}

/**
 * Returns a Future Worth Factor assuming an uniform annual
 * payment across 'n' number of periods.
 * @param {Number} i 100-based interest rate e.g. 15% = 15
 * @param {Number} n number of periods
 * @return {Number}
 */
export function uniformFWfromA (i, n) {
  return 1 / uniformAWfromF(i, n)
}

/**
 * Returns a Present Worth Factor assuming an uniform annual
 * payment across 'n' number of periods.
 * @param {Number} i 100-based interest rate e.g. 15% = 15
 * @param {Number} n number of periods
 * @return {Number}
 */
export function uniformPWfromA (i, n) {
  return 1 / uniformAWfromP(i, n)
}
<|endoftext|>


<commit_before>'use strict';

import _Action 						from './actions/Action';
import _ActionDispatcher 	from './actions/ActionDispatcher';
import _FormAction 				from './actions/FormAction';
import _KeyboardAction 		from './actions/KeyboardAction';
import _MouseAction 			from './actions/MouseAction';
import _TouchAction 			from './actions/TouchAction';

import _Atom 							from './components/Atom';
import _Molecule 					from './components/Molecule';
import _Organism 					from './components/Organism';
import _ComponentObject 	from './components/ComponentObject';

import _Utils 						from './utils/Utils';

export let Action 					= _Action;
export let ActionDispatcher = _ActionDispatcher;
export let FormAction 			= _FormAction;
export let KeyboardAction 	= _KeyboardAction;
export let MouseAction 			= _MouseAction;
export let TouchAction 			= _TouchAction;

export let ComponentObject 	= _ComponentObject;
export let Atom 						= _Atom;
export let Molecule 				= _Molecule;
export let Organism 				= _Organism;

export let Utils 						= _Utils;
<commit_msg>style(index): remove spaces<commit_after>'use strict';

import _Action 						from './actions/Action';
import _ActionDispatcher 	from './actions/ActionDispatcher';
import _FormAction 				from './actions/FormAction';
import _KeyboardAction 		from './actions/KeyboardAction';
import _MouseAction 			from './actions/MouseAction';
import _TouchAction 			from './actions/TouchAction';
import _Atom 							from './components/Atom';
import _Molecule 					from './components/Molecule';
import _Organism 					from './components/Organism';
import _ComponentObject 	from './components/ComponentObject';
import _Utils 						from './utils/Utils';

export let Action 					= _Action;
export let ActionDispatcher = _ActionDispatcher;
export let FormAction 			= _FormAction;
export let KeyboardAction 	= _KeyboardAction;
export let MouseAction 			= _MouseAction;
export let TouchAction 			= _TouchAction;
export let ComponentObject 	= _ComponentObject;
export let Atom 						= _Atom;
export let Molecule 				= _Molecule;
export let Organism 				= _Organism;
export let Utils 						= _Utils;
<|endoftext|>


<commit_before>requirejs.config({
    paths: {
        'text': '../Scripts/text',
        'durandal': '../Scripts/durandal',
        'plugins': '../Scripts/durandal/plugins',
        'transitions': '../Scripts/durandal/transitions'
    }
});

define('jquery', function () { return jQuery; });
define('knockout', ko);

define(['durandal/system', 'durandal/app', 'durandal/viewLocator', 'services/mockServices'],  function (system, app, viewLocator, mockServices) {
    //>>excludeStart("build", true);
    system.debug(true);
    //>>excludeEnd("build");

    app.title = 'Read Every Word';

    app.configurePlugins({
        router: true,
        dialog: false,
        observable: true
    });

    mockServices.mock();
    configureValidation();

    app.start().then(function() {
        //Replace 'viewmodels' in the moduleId with 'views' to locate the view.
        //Look for partial views in a 'views' folder in the root.
        viewLocator.useConvention();

        //Show the app by setting the root view model for our application with a transition.
        app.setRoot('viewmodels/shell', 'entrance');
    });

    function configureValidation() {
        $.validator.addMethod("validpassword", function (value, element) {
            return this.optional(element) ||
                /^.*(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*[\d])(?=.*[\W_]).*$/.test(value);
        }, "The password must contain a minimum of one lower case character," +
           " one upper case character, one digit and one special character..");

        $.validator.setDefaults({
            highlight: function (element) {
                $(element).closest('.form-group').addClass('has-error');
            },
            unhighlight: function (element) {
                $(element).closest('.form-group').removeClass('has-error');
            },
            errorClass: 'control-label has-error'
        });
    }
});<commit_msg>Checking if internet is available<commit_after>requirejs.config({
    paths: {
        'text': '../Scripts/text',
        'durandal': '../Scripts/durandal',
        'plugins': '../Scripts/durandal/plugins',
        'transitions': '../Scripts/durandal/transitions'
    }
});

define('jquery', function () { return jQuery; });
define('knockout', ko);

define(['durandal/system', 'durandal/app', 'durandal/viewLocator', 'services/mockServices'],  function (system, app, viewLocator, mockServices) {
    //>>excludeStart("build", true);
    system.debug(true);
    //>>excludeEnd("build");

    app.title = 'Read Every Word';

    app.configurePlugins({
        router: true,
        dialog: false,
        observable: true
    });

    configureAjax();
    mockServices.mock();
    configureValidation();

    app.start().then(function() {
        //Replace 'viewmodels' in the moduleId with 'views' to locate the view.
        //Look for partial views in a 'views' folder in the root.
        viewLocator.useConvention();

        //Show the app by setting the root view model for our application with a transition.
        app.setRoot('viewmodels/shell', 'entrance');
    });

    function configureValidation() {
        $.validator.addMethod("validpassword", function (value, element) {
            return this.optional(element) ||
                /^.*(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*[\d])(?=.*[\W_]).*$/.test(value);
        }, "The password must contain a minimum of one lower case character," +
           " one upper case character, one digit and one special character..");

        $.validator.setDefaults({
            highlight: function (element) {
                $(element).closest('.form-group').addClass('has-error');
            },
            unhighlight: function (element) {
                $(element).closest('.form-group').removeClass('has-error');
            },
            errorClass: 'control-label has-error'
        });
    }

    function configureAjax() {
        $(document).ajaxSend(function (event, xhr, settings) {
            if (!navigator.onLine) {
                toastr.warn("Cannot connect to the internet.");
                xhr.abort();
            }
        });
    }
});<|endoftext|>


<commit_before>/* Validate that the package.json follows the expected form */

// This is really the first test. If the tests fail here
// then there is likely a JSON formatting error in the file.
var pluginsList = require('../static/plugins_list.json');

var chai = require('chai'),
    expect = chai.expect;

describe('the json document', function() {
  it('should have a plugins object', function() {
    expect(pluginsList).to.have.property('plugins').that.is.an('object');
  });

  describe('the top-level plugins object', function() {
    let plugins = pluginsList.plugins;

    it('should not be empty', function() {
      expect(plugins).to.not.be.empty;
    });

    describe('each plugin should validate', function() {
      for (let plugin_name in plugins) {
        let plugin_data = plugins[plugin_name];
        it(plugin_name + ' should have a valid payload', function() {
          // validate plugin
          expect(plugin_data).to.be.an('object');
        });
      }
    });

  });

  it('should have a mime_types array', function() {
    expect(pluginsList).to.have.property('mime_types').that.is.an('array');
  });

  describe('the top-level mime_types array', function() {
    let mimes = pluginsList.mime_types;

    it('should not be empty', function() {
      expect(mimes).to.not.be.empty;
    });

    describe('each mime_type entry should validate', function() {
      for (let mime of mimes) {
        it(mime + ' should be a valid mime_type', function() {
          expect(mime).to.be.ok; // todo: actually validate
        });
      }
    });

  });
});

/*

{
  plugins: {
    :plugin_name : {
      display_name: "",
      description: "",
      versions: {
        :os || all: {
          latest: [
            {
             "status":"latest",
             "version":"0.0.0",
             "detected_version":"0.0.0",
             "detection_type":"original",
              "os_name":"*",
              "platform":{
                "app_id":"*",
                "app_release":"*",
                "app_version":"*",
                "locale":"*"
              }
            }
          ],
          vulnerable: [ ... ]
        }
      },
      mimes: [ :mime_types ],
      url: "",
      regex: [ :reges_str ]
    }
  },
  mime_types: []
}
*/
<commit_msg>add extensive validation tests<commit_after>/* Validate that the package.json follows the expected form */

// This is really the first test. If the tests fail here
// then there is likely a JSON formatting error in the file.
var pluginsList = require('../static/plugins_list.json');

var chai = require('chai'),
    expect = chai.expect;

describe('in the json document', function() {
  // this hoists up so we can access it later in validation
  var mimes = []

  /* we start with mime_types because we need it to exist to validate plugins */
  it('a mime_types array must exist', function() {
    expect(pluginsList).to.have.property('mime_types').that.is.an('array');
  });

  describe('the top-level mime_types array', function() {
    mimes = pluginsList.mime_types;

    it('must not be empty', function() {
      expect(mimes).to.not.be.empty;
    });

    describe('must contain valid mime_types:', function() {
      for (let mime of mimes) {
        it(mime + ' should be a valid mime_type', function() {
          /* mime types in this context predate and may not conform to the
          whatwg mimesniff spec. It is unclear how to validate them. */
          expect(mime).to.include("/");
        });
      }
    });

  });

  it('a plugins object must exist', function() {
    expect(pluginsList).to.have.property('plugins').that.is.an('object');
  });

  describe('the top-level plugins object', function() {
    let plugins = pluginsList.plugins;

    it('must not be empty', function() {
      expect(plugins).to.not.be.empty;
    });

    describe('must contain valid plugins:', function() {
      for (let plugin_name in plugins) {
        let plugin_data = plugins[plugin_name];
        describe(plugin_name, function() {
          it('must be an object', function() {
            expect(plugin_data).to.be.an('object');
          });
          it('must have a display name', function() {
            expect(plugin_data.display_name).to.be.a('string');
          });
          it('must have a description', function() {
            expect(plugin_data.description).to.be.a('string');
          });
          it('must have some version(s)', function() {
            expect(plugin_data.versions).to.be.an('object');
          });
          for (let version_name in plugin_data.versions) {
            describe('version ' + version_name + ":", function() {
              let versions = plugin_data.versions[version_name];
              it('must be a known version', function() {
                expect(version_name).to.be.oneOf(["win", "mac", "lin", "all"]);
              });
              it('must have a latest version', function() {
                expect(versions.latest).to.be.an('array');
              });
              for (let v in versions.latest) {
                let version = versions.latest[v];
                describe('version ' + version.version + ":", function() {
                  it('must have a valid status', function() {
                    expect(version.status).to.be.oneOf(
                      ['latest', 'vulnerable']);
                  });
                  if (version.status === "vulnerable") {
                    it('must describe the vulnerability', function() {
                      expect(version.vulnerability_url).to.be.a('string');
                    });
                  }
                  it('must define an affected version', function() {
                    expect(version.version).to.be.a('string');
                    version_array = version.version.split('.');
                    expect(version_array).to.have.length.below(5);
                    for (let version_number in version_array) {
                      let n = Number(version_array[version_number]);
                      expect(n).to.be.a('Number');
                    }
                  });
                  it('must define a detection_type', function() {
                    expect(version.detection_type).to.be.a('string');
                  });
                  // most of the time version.os_name will agree with the parent
                  // os name, but not always so we don't assert that
                  // it('must agree with parent elements about os_name',);
                  it('must define a platform', function() {
                    expect(version).to.have.a.property('platform');
                    let p = version.platform;
                    expect(p).to.be.a('object');
                    expect(p.app_id).to.equal('*');
                    expect(p.app_release).to.equal('*');
                    // C DC for two versions of adobe
                    expect(p.app_version).to.oneOf(['*', 'Continuous DC'])
                    expect(p.locale).to.equal('*')
                  });
                });
              }
              for (let v in versions.vulnerable) {
                let version = versions.vulnerable[v];
                describe('version ' + version.version + ":", function() {
                  it('must have a valid status', function() {
                    expect(version.status).to.equal('vulnerable');
                  });
                  if (version.status === "vulnerable") {
                    it('must describe the vulnerability', function() {
                      expect(version.vulnerability_url).to.be.a('string');
                    });
                  }
                  it('must define an affected version', function() {
                    expect(version.version).to.be.a('string');
                    version_array = version.version.split('.');
                    expect(version_array).to.have.length.below(5);
                    for (let version_number in version_array) {
                      let n = Number(version_array[version_number]);
                      expect(n).to.be.a('Number');
                    }
                  });
                  it('must define a detection_type', function() {
                    expect(version.detection_type).to.be.a('string');
                  });
                  // most of the time version.os_name will agree with the parent
                  // os name, but not always so we don't assert that
                  // it('must agree with parent elements about os_name',);
                  it('must define a platform', function() {
                    expect(version).to.have.a.property('platform');
                    let p = version.platform;
                    expect(p).to.be.a('object');
                    expect(p.app_id).to.equal('*');
                    expect(p.app_release).to.oneOf(
                      ['*', 'Extended Release Version']);
                    // C DC for two versions of adobe
                    expect(p.app_version).to.oneOf(['*', 'Continuous DC'])
                    expect(p.locale).to.equal('*')
                  });
                });
              }
            });
          }
          it('must check for known mime types', function() {
            let plugin_mimes = plugin_data.mimes;
            expect(plugin_mimes).to.be.an('array');
            for (let mime in plugin_mimes) {
              // ensure they are in the top level mimes array
              expect(plugin_mimes[mime]).to.be.oneOf(mimes);
            }
          });
          it('must provide a url', function() {
            expect(plugin_data.url).to.be.a('string');
          });
          it('must provide a regex', function() {
            // todo: validate each regex
            expect(plugin_data.regex).to.be.an('array');
            for (let r in plugin_data.regex) {
              expect(plugin_data.regex[r]).to.be.a('string')
            }
          });
        });
      }
    });

  });
});
<|endoftext|>


<commit_before>import {
  moduleForModel,
  test
} from 'ember-qunit';

moduleForModel('statement', {
  // Specify the other units that are required for this test.
  needs: ['step']
});

test('it exists', function(assert) {
  var model = this.subject();
  // var store = this.store();
  assert.ok(!!model);
});
<commit_msg>Fixes hanging unit tests. Specify step is a model.<commit_after>import {
  moduleForModel,
  test
} from 'ember-qunit';

moduleForModel('statement', {
  // Specify the other units that are required for this test.
  needs: ['model:step']
});

test('it exists', function(assert) {
  var model = this.subject();
  // var store = this.store();
  assert.ok(!!model);
});
<|endoftext|>


<commit_before>/**

  favicon.js

**/

var fs = require("fs"),
    favicon = require("serve-favicon"),
    Utils = require("./utils");

module.exports = function() {

  var file = Utils.makePathAbsolute(global.config.favicon || "/favicon.ico");

  // Ensure that file exists before adding middleware
  try {
    fs.lstatSync(file);
  } catch (err) {
    return null;
  };

  return favicon(file);

};<commit_msg>favicon: removed (now included in common.js)<commit_after><|endoftext|>


<commit_before>/**
 * @requires lex.js, parse.js, scope.js, interpret.js
 */
var llang = {
    evaluate : function (formula, evaluation) {
        var tokens = lex(formula);
        var tree = parse(tokens);
        var initializator = getInitializator(getVariables(tokens));
        return interpret(tree, initializator.apply(initializator, evaluation));
    },
    _ : {
        lex : lex,
        parse : parse,
        getInitializator : getInitializator,
        getVariables : getVariables,
        interpret : interpret
    }
};

if (typeof window != 'undefined') {
    window.llang = llang;
}

else {
    module.exports = llang;
}
<commit_msg>Add evaluateAll support<commit_after>/**
 * @requires lex.js, parse.js, scope.js, interpret.js
 */
var llang = {
    _evaluate : function (formula, evaluation, tokens, vars) {
        var tree = parse(tokens);
        var initializator = getInitializator(vars);
        return interpret(tree, initializator.apply(initializator, evaluation));
    },
    evaluate : function (formula, evaluation) {
        var tokens = lex(formula);
        return this._evaluate(formula, evaluation, tokens, getVariables(tokens));
    },
    evaluateAll : function (formula) {
        var tokens = lex(formula);
        var vars = getVariables(tokens);
        var n = vars.length;
        var result = [];
        var combinations = generateCombinations(n);

        for (var i = 0, count = Math.pow(2, n); i < count; i++) {
            result.push(this._evaluate(formula, combinations[i], tokens, vars));
        }

        return result;
    },
    _ : {
        lex : lex,
        parse : parse,
        getInitializator : getInitializator,
        getVariables : getVariables,
        interpret : interpret
    }
};

if (typeof window != 'undefined') {
    window.llang = llang;
}

else {
    module.exports = llang;
}
<|endoftext|>


<commit_before>
<commit_msg>Update logic.js<commit_after>(function(ext) {
    // Cleanup function when the extension is unloaded
    ext._shutdown = function() {};

    // Status reporting code
    // Use this to report missing hardware, plugin or unsupported browser
    ext._getStatus = function() {
        return {status: 2, msg: 'Ready'};
    };

    ext.power = function(base, exponent) {
        return Math.pow(base, exponent);
    };

    // Block and block menu descriptions
    var descriptor = {
        blocks: [
            ['r', '%n to the power of %n', 'power', 2, 3],
        ]
    };

    // Register the extension
    ScratchExtensions.register('Mod - Math', descriptor, ext);
})({});

<|endoftext|>


<commit_before>import router from './router'
import store from './store'
import vue from 'vue'
import NProgress from 'nprogress' // Progress 进度条
import 'nprogress/nprogress.css'// Progress 进度条样式

// permissiom judge
function hasPermission(roles, permissionRoles) {
  if (roles.indexOf('admin') >= 0) return true // admin权限 直接通过
  if (!permissionRoles) return true
  return roles.some(role => permissionRoles.indexOf(role) >= 0)
}

// register global progress.
const whiteList = ['/login', '/authredirect']// 不重定向白名单
router.beforeEach((to, from, next) => {
  NProgress.start() // 开启Progress
  if (store.getters.token) { // 判断是否有token
    if (to.path === '/login') {
      next({ path: '/' })
    } else {
      if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
        store.dispatch('GetInfo').then(res => { // 拉取user_info
          const roles = res.data.role

          store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
            router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
            next({ ...to }) // hack方法 确保addRoutes已完成
          })

        }).catch(() => {
          store.dispatch('FedLogOut').then(() => {
            next({ path: '/login' })
          })
        })
      } else {
        // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
        store.dispatch('getNowRoutes', to);

        if (hasPermission(store.getters.roles, to.meta.role)) {
          next()//

          console.log("has userinfo")
        } else {
          next({ path: '/', query: { noGoBack: true }})
        }
        // 可删 ↑
      }
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单，直接进入
      next()
    } else {
      next('/login') // 否则全部重定向到登录页
      NProgress.done() // 在hash模式下 改变手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 ps：history模式下无问题，可删除该行！
    }
  }
})

router.afterEach(() => {
  NProgress.done() // 结束Progress
})
<commit_msg>fixed bugs<commit_after>import router from './router'
import store from './store'
import vue from 'vue'
import NProgress from 'nprogress' // Progress 进度条
import 'nprogress/nprogress.css'// Progress 进度条样式

// permissiom judge
function hasPermission(roles, permissionRoles) {
  if (roles.indexOf('admin') >= 0) return true // admin权限 直接通过
  if (!permissionRoles) return true
  return roles.some(role => permissionRoles.indexOf(role) >= 0)
}

// register global progress.
const whiteList = ['/login', '/authredirect']// 不重定向白名单
router.beforeEach((to, from, next) => {
  NProgress.start() // 开启Progress
  if (store.getters.token) { // 判断是否有token
    if (to.path === '/login') {
      next({ path: '/' })
    } else {
      if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
        store.dispatch('GetInfo').then(res => { // 拉取user_info
          const roles = res.data.role

          store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
            router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
            next({ ...to }) // hack方法 确保addRoutes已完成
          })

        }).catch(() => {
          store.dispatch('FedLogOut').then(() => {
            next({ path: '/login' })
          })
        })
      } else {
        // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
        store.dispatch('getNowRoutes', to);

        if (hasPermission(store.getters.roles, to.meta.role)) {
          next()//

          console.log("has userinfo")
        } else {
          next({ path: '/', query: { noGoBack: true }})
        }
        // 可删 ↑
      }
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单，直接进入
      next()
    } else {
      next('/login') // 否则全部重定向到登录页
      NProgress.done() // 在hash模式下 改变手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 ps：history模式下无问题，可删除该行！
    }
  }
})

router.afterEach(() => {
  NProgress.done() // 结束Progress
})
<|endoftext|>


<commit_before>/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
/*global global*/
/**
 * @author Christian Johansen (christian@cjohansen.no) and contributors
 * @license BSD
 *
 * Copyright (c) 2010-2014 Christian Johansen
 */
"use strict";

// node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()
// browsers, a number.
// see https://github.com/cjohansen/Sinon.JS/pull/436
var timeoutResult = setTimeout(function() {}, 0);
var addTimerReturnsObject = typeof timeoutResult === "object";
clearTimeout(timeoutResult);

var NativeDate = Date;
var id = 1;

/**
 * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into
 * number of milliseconds. This is used to support human-readable strings passed
 * to clock.tick()
 */
function parseTime(str) {
    if (!str) {
        return 0;
    }

    var strings = str.split(":");
    var l = strings.length, i = l;
    var ms = 0, parsed;

    if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
        throw new Error("tick only understands numbers and 'h:m:s'");
    }

    while (i--) {
        parsed = parseInt(strings[i], 10);

        if (parsed >= 60) {
            throw new Error("Invalid time " + str);
        }

        ms += parsed * Math.pow(60, (l - i - 1));
    }

    return ms * 1000;
}

/**
 * Used to grok the `now` parameter to createClock.
 */
function getEpoch(epoch) {
    if (!epoch) { return 0; }
    if (typeof epoch.getTime === "function") { return epoch.getTime(); }
    if (typeof epoch === "number") { return epoch; }
    throw new TypeError("now should be milliseconds since UNIX epoch");
}

function inRange(from, to, timer) {
    return timer && timer.callAt >= from && timer.callAt <= to;
}

function mirrorDateProperties(target, source) {
    if (source.now) {
        target.now = function now() {
            return target.clock.now;
        };
    } else {
        delete target.now;
    }

    if (source.toSource) {
        target.toSource = function toSource() {
            return source.toSource();
        };
    } else {
        delete target.toSource;
    }

    target.toString = function toString() {
        return source.toString();
    };

    target.prototype = source.prototype;
    target.parse = source.parse;
    target.UTC = source.UTC;
    target.prototype.toUTCString = source.prototype.toUTCString;

    for (var prop in source) {
        if (source.hasOwnProperty(prop)) {
            target[prop] = source[prop];
        }
    }

    return target;
}

function createDate() {
    function ClockDate(year, month, date, hour, minute, second, ms) {
        // Defensive and verbose to avoid potential harm in passing
        // explicit undefined when user does not pass argument
        switch (arguments.length) {
        case 0:
            return new NativeDate(ClockDate.clock.now);
        case 1:
            return new NativeDate(year);
        case 2:
            return new NativeDate(year, month);
        case 3:
            return new NativeDate(year, month, date);
        case 4:
            return new NativeDate(year, month, date, hour);
        case 5:
            return new NativeDate(year, month, date, hour, minute);
        case 6:
            return new NativeDate(year, month, date, hour, minute, second);
        default:
            return new NativeDate(year, month, date, hour, minute, second, ms);
        }
    }

    return mirrorDateProperties(ClockDate, NativeDate);
}

function addTimer(clock, args, opt) {
    if (args.length === 0) {
        throw new Error("Function requires at least 1 parameter");
    }

    if (typeof args[0] === "undefined") {
        throw new Error("Callback must be provided to timer calls");
    }

    var toId = id++;
    var delay = args[1] || 0;

    if (!clock.timeouts) {
        clock.timeouts = {};
    }

    clock.timeouts[toId] = {
        id: toId,
        func: args[0],
        callAt: clock.now + delay,
        invokeArgs: Array.prototype.slice.call(args, 2)
    };

    if (opt && opt.recurring) {
        clock.timeouts[toId].interval = delay;
    }

    if (addTimerReturnsObject) {
        return {
            id: toId,
            ref: function() {},
            unref: function() {}
        };
    }
    else {
        return toId;
    }
}

function firstTimerInRange(clock, from, to) {
    var timer, smallest = null, originalTimer;

    for (var id in clock.timeouts) {
        if (!inRange(from, to, clock.timeouts[id])) {
            continue;
        }

        if (smallest === null || clock.timeouts[id].callAt < smallest) {
            originalTimer = clock.timeouts[id];
            smallest = clock.timeouts[id].callAt;

            timer = {
                func: clock.timeouts[id].func,
                callAt: clock.timeouts[id].callAt,
                interval: clock.timeouts[id].interval,
                id: clock.timeouts[id].id,
                invokeArgs: clock.timeouts[id].invokeArgs
            };
        }
    }

    return timer || null;
}

function callTimer(clock, timer) {
    if (typeof timer.interval == "number") {
        clock.timeouts[timer.id].callAt += timer.interval;
    } else {
        delete clock.timeouts[timer.id];
    }

    try {
        if (typeof timer.func == "function") {
            timer.func.apply(null, timer.invokeArgs);
        } else {
            eval(timer.func);
        }
    } catch (e) {
        var exception = e;
    }

    if (!clock.timeouts[timer.id]) {
        if (exception) {
            throw exception;
        }
        return;
    }

    if (exception) {
        throw exception;
    }
}

function uninstall(clock, target) {
    var method;

    for (var i = 0, l = clock.methods.length; i < l; i++) {
        method = clock.methods[i];

        if (target[method].hadOwnProperty) {
            target[method] = clock["_" + method];
        } else {
            try {
                delete target[method];
            } catch (e) {}
        }
    }

    // Prevent multiple executions which will completely remove these props
    clock.methods = [];
}

function hijackMethod(target, method, clock) {
    clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(target, method);
    clock["_" + method] = target[method];

    if (method == "Date") {
        var date = mirrorDateProperties(clock[method], target[method]);
        target[method] = date;
    } else {
        target[method] = function () {
            return clock[method].apply(clock, arguments);
        };

        for (var prop in clock[method]) {
            if (clock[method].hasOwnProperty(prop)) {
                target[method][prop] = clock[method][prop];
            }
        }
    }

    target[method].clock = clock;
}

var timers = {
    setTimeout: setTimeout,
    clearTimeout: clearTimeout,
    setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
    clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
    setInterval: setInterval,
    clearInterval: clearInterval,
    Date: Date
};

var keys = Object.keys || function (obj) {
    var ks = [];
    for (var key in obj) {
        ks.push(key);
    }
    return ks;
};

module.exports.timers = timers;

var createClock = module.exports.createClock = function (now) {
    var clock = {
        now: getEpoch(now),
        timeouts: {},
        Date: createDate()
    };

    clock.Date.clock = clock;

    clock.setTimeout = function setTimeout(callback, timeout) {
        return addTimer(clock, arguments);
    };

    clock.clearTimeout = function clearTimeout(timerId) {
        if (!timerId) {
            // null appears to be allowed in most browsers, and appears to be
            // relied upon by some libraries, like Bootstrap carousel
            return;
        }
        if (!clock.timeouts) {
            clock.timeouts = [];
        }
        // in Node, timerId is an object with .ref()/.unref(), and
        // its .id field is the actual timer id.
        if (typeof timerId === "object") {
            timerId = timerId.id
        }
        if (timerId in clock.timeouts) {
            delete clock.timeouts[timerId];
        }
    };

    clock.setInterval = function setInterval(callback, timeout) {
        return addTimer(clock, arguments, { recurring: true });
    };

    clock.clearInterval = function clearInterval(timerId) {
        clock.clearTimeout(timerId);
    };

    clock.setImmediate = function setImmediate(callback) {
        var passThruArgs = Array.prototype.slice.call(arguments, 1);
        return addTimer(clock, [callback, 0].concat(passThruArgs));
    };

    clock.clearImmediate = function clearImmediate(timerId) {
        clock.clearTimeout(timerId);
    };

    clock.tick = function tick(ms) {
        ms = typeof ms == "number" ? ms : parseTime(ms);
        var tickFrom = clock.now, tickTo = clock.now + ms, previous = clock.now;
        var timer = firstTimerInRange(clock, tickFrom, tickTo);

        var firstException;
        while (timer && tickFrom <= tickTo) {
            if (clock.timeouts[timer.id]) {
                tickFrom = clock.now = timer.callAt;
                try {
                    callTimer(clock, timer);
                } catch (e) {
                    firstException = firstException || e;
                }
            }

            timer = firstTimerInRange(clock, previous, tickTo);
            previous = tickFrom;
        }

        clock.now = tickTo;

        if (firstException) {
            throw firstException;
        }

        return clock.now;
    };

    clock.reset = function reset() {
        clock.timeouts = {};
    };

    return clock;
};

module.exports.install = function install(target, now, toFake) {
    if (typeof target === "number") {
        toFake = now;
        now = target;
        target = null;
    }

    if (!target) {
        target = global;
    }

    var clock = createClock(now);

    clock.uninstall = function () {
        uninstall(clock, target);
    };

    clock.methods = toFake || [];

    if (clock.methods.length === 0) {
        clock.methods = keys(timers);
    }

    for (var i = 0, l = clock.methods.length; i < l; i++) {
        hijackMethod(target, clock.methods[i], clock);
    }

    return clock;
};
<commit_msg>Remove redundant module prefix<commit_after>/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
/*global global*/
/**
 * @author Christian Johansen (christian@cjohansen.no) and contributors
 * @license BSD
 *
 * Copyright (c) 2010-2014 Christian Johansen
 */
"use strict";

// node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()
// browsers, a number.
// see https://github.com/cjohansen/Sinon.JS/pull/436
var timeoutResult = setTimeout(function() {}, 0);
var addTimerReturnsObject = typeof timeoutResult === "object";
clearTimeout(timeoutResult);

var NativeDate = Date;
var id = 1;

/**
 * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into
 * number of milliseconds. This is used to support human-readable strings passed
 * to clock.tick()
 */
function parseTime(str) {
    if (!str) {
        return 0;
    }

    var strings = str.split(":");
    var l = strings.length, i = l;
    var ms = 0, parsed;

    if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
        throw new Error("tick only understands numbers and 'h:m:s'");
    }

    while (i--) {
        parsed = parseInt(strings[i], 10);

        if (parsed >= 60) {
            throw new Error("Invalid time " + str);
        }

        ms += parsed * Math.pow(60, (l - i - 1));
    }

    return ms * 1000;
}

/**
 * Used to grok the `now` parameter to createClock.
 */
function getEpoch(epoch) {
    if (!epoch) { return 0; }
    if (typeof epoch.getTime === "function") { return epoch.getTime(); }
    if (typeof epoch === "number") { return epoch; }
    throw new TypeError("now should be milliseconds since UNIX epoch");
}

function inRange(from, to, timer) {
    return timer && timer.callAt >= from && timer.callAt <= to;
}

function mirrorDateProperties(target, source) {
    if (source.now) {
        target.now = function now() {
            return target.clock.now;
        };
    } else {
        delete target.now;
    }

    if (source.toSource) {
        target.toSource = function toSource() {
            return source.toSource();
        };
    } else {
        delete target.toSource;
    }

    target.toString = function toString() {
        return source.toString();
    };

    target.prototype = source.prototype;
    target.parse = source.parse;
    target.UTC = source.UTC;
    target.prototype.toUTCString = source.prototype.toUTCString;

    for (var prop in source) {
        if (source.hasOwnProperty(prop)) {
            target[prop] = source[prop];
        }
    }

    return target;
}

function createDate() {
    function ClockDate(year, month, date, hour, minute, second, ms) {
        // Defensive and verbose to avoid potential harm in passing
        // explicit undefined when user does not pass argument
        switch (arguments.length) {
        case 0:
            return new NativeDate(ClockDate.clock.now);
        case 1:
            return new NativeDate(year);
        case 2:
            return new NativeDate(year, month);
        case 3:
            return new NativeDate(year, month, date);
        case 4:
            return new NativeDate(year, month, date, hour);
        case 5:
            return new NativeDate(year, month, date, hour, minute);
        case 6:
            return new NativeDate(year, month, date, hour, minute, second);
        default:
            return new NativeDate(year, month, date, hour, minute, second, ms);
        }
    }

    return mirrorDateProperties(ClockDate, NativeDate);
}

function addTimer(clock, args, opt) {
    if (args.length === 0) {
        throw new Error("Function requires at least 1 parameter");
    }

    if (typeof args[0] === "undefined") {
        throw new Error("Callback must be provided to timer calls");
    }

    var toId = id++;
    var delay = args[1] || 0;

    if (!clock.timeouts) {
        clock.timeouts = {};
    }

    clock.timeouts[toId] = {
        id: toId,
        func: args[0],
        callAt: clock.now + delay,
        invokeArgs: Array.prototype.slice.call(args, 2)
    };

    if (opt && opt.recurring) {
        clock.timeouts[toId].interval = delay;
    }

    if (addTimerReturnsObject) {
        return {
            id: toId,
            ref: function() {},
            unref: function() {}
        };
    }
    else {
        return toId;
    }
}

function firstTimerInRange(clock, from, to) {
    var timer, smallest = null, originalTimer;

    for (var id in clock.timeouts) {
        if (!inRange(from, to, clock.timeouts[id])) {
            continue;
        }

        if (smallest === null || clock.timeouts[id].callAt < smallest) {
            originalTimer = clock.timeouts[id];
            smallest = clock.timeouts[id].callAt;

            timer = {
                func: clock.timeouts[id].func,
                callAt: clock.timeouts[id].callAt,
                interval: clock.timeouts[id].interval,
                id: clock.timeouts[id].id,
                invokeArgs: clock.timeouts[id].invokeArgs
            };
        }
    }

    return timer || null;
}

function callTimer(clock, timer) {
    if (typeof timer.interval == "number") {
        clock.timeouts[timer.id].callAt += timer.interval;
    } else {
        delete clock.timeouts[timer.id];
    }

    try {
        if (typeof timer.func == "function") {
            timer.func.apply(null, timer.invokeArgs);
        } else {
            eval(timer.func);
        }
    } catch (e) {
        var exception = e;
    }

    if (!clock.timeouts[timer.id]) {
        if (exception) {
            throw exception;
        }
        return;
    }

    if (exception) {
        throw exception;
    }
}

function uninstall(clock, target) {
    var method;

    for (var i = 0, l = clock.methods.length; i < l; i++) {
        method = clock.methods[i];

        if (target[method].hadOwnProperty) {
            target[method] = clock["_" + method];
        } else {
            try {
                delete target[method];
            } catch (e) {}
        }
    }

    // Prevent multiple executions which will completely remove these props
    clock.methods = [];
}

function hijackMethod(target, method, clock) {
    clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(target, method);
    clock["_" + method] = target[method];

    if (method == "Date") {
        var date = mirrorDateProperties(clock[method], target[method]);
        target[method] = date;
    } else {
        target[method] = function () {
            return clock[method].apply(clock, arguments);
        };

        for (var prop in clock[method]) {
            if (clock[method].hasOwnProperty(prop)) {
                target[method][prop] = clock[method][prop];
            }
        }
    }

    target[method].clock = clock;
}

var timers = {
    setTimeout: setTimeout,
    clearTimeout: clearTimeout,
    setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
    clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
    setInterval: setInterval,
    clearInterval: clearInterval,
    Date: Date
};

var keys = Object.keys || function (obj) {
    var ks = [];
    for (var key in obj) {
        ks.push(key);
    }
    return ks;
};

exports.timers = timers;

var createClock = exports.createClock = function (now) {
    var clock = {
        now: getEpoch(now),
        timeouts: {},
        Date: createDate()
    };

    clock.Date.clock = clock;

    clock.setTimeout = function setTimeout(callback, timeout) {
        return addTimer(clock, arguments);
    };

    clock.clearTimeout = function clearTimeout(timerId) {
        if (!timerId) {
            // null appears to be allowed in most browsers, and appears to be
            // relied upon by some libraries, like Bootstrap carousel
            return;
        }
        if (!clock.timeouts) {
            clock.timeouts = [];
        }
        // in Node, timerId is an object with .ref()/.unref(), and
        // its .id field is the actual timer id.
        if (typeof timerId === "object") {
            timerId = timerId.id
        }
        if (timerId in clock.timeouts) {
            delete clock.timeouts[timerId];
        }
    };

    clock.setInterval = function setInterval(callback, timeout) {
        return addTimer(clock, arguments, { recurring: true });
    };

    clock.clearInterval = function clearInterval(timerId) {
        clock.clearTimeout(timerId);
    };

    clock.setImmediate = function setImmediate(callback) {
        var passThruArgs = Array.prototype.slice.call(arguments, 1);
        return addTimer(clock, [callback, 0].concat(passThruArgs));
    };

    clock.clearImmediate = function clearImmediate(timerId) {
        clock.clearTimeout(timerId);
    };

    clock.tick = function tick(ms) {
        ms = typeof ms == "number" ? ms : parseTime(ms);
        var tickFrom = clock.now, tickTo = clock.now + ms, previous = clock.now;
        var timer = firstTimerInRange(clock, tickFrom, tickTo);

        var firstException;
        while (timer && tickFrom <= tickTo) {
            if (clock.timeouts[timer.id]) {
                tickFrom = clock.now = timer.callAt;
                try {
                    callTimer(clock, timer);
                } catch (e) {
                    firstException = firstException || e;
                }
            }

            timer = firstTimerInRange(clock, previous, tickTo);
            previous = tickFrom;
        }

        clock.now = tickTo;

        if (firstException) {
            throw firstException;
        }

        return clock.now;
    };

    clock.reset = function reset() {
        clock.timeouts = {};
    };

    return clock;
};

exports.install = function install(target, now, toFake) {
    if (typeof target === "number") {
        toFake = now;
        now = target;
        target = null;
    }

    if (!target) {
        target = global;
    }

    var clock = createClock(now);

    clock.uninstall = function () {
        uninstall(clock, target);
    };

    clock.methods = toFake || [];

    if (clock.methods.length === 0) {
        clock.methods = keys(timers);
    }

    for (var i = 0, l = clock.methods.length; i < l; i++) {
        hijackMethod(target, clock.methods[i], clock);
    }

    return clock;
};
<|endoftext|>


<commit_before>var keys = require('./keys');

var invKeys = {};
for (var keyName in keys) {
  invKeys[keys[keyName]] = keyName;
}

var Input = function(app, container) {
  this._container = container;
  this._keys = {};

  this.canControlKeys = true;

  this.mouse = {
    isDown: false,
    isLeftDown: false,
    isMiddleDown: false,
    isRightDown: false,
    x: null,
    y: null
  };

  this._addEvents(app);
};

Input.prototype.resetKeys = function() {
  this._keys = {};
};

Input.prototype.isKeyDown = function(key) {
  if (key == null) { return false; }

  if (this.canControlKeys) {
    var code = typeof key === 'number' ? key : keys[key.toLowerCase()];
    return this._keys[code];
  }
};

Input.prototype._addEvents = function(app) {
  var self = this;

  var mouseEvent = {
    x: null,
    y: null,
    button: null,
    isTouch: false,
    event: null,
    stateStopEvent: function() {
      app.states._preventEvent = true;
    }
  };

  var keyboardEvent = {
    key: null,
    name: null,
    event: null,
    stateStopEvent: function() {
      app.states._preventEvent = true;
    }
  };

  self._container.addEventListener('mousemove', function(e) {
    var x = e.offsetX === undefined ? e.layerX - self._container.offsetLeft : e.offsetX;
    var y = e.offsetY === undefined ? e.layerY - self._container.offsetTop : e.offsetY;

    self.mouse.x = x;
    self.mouse.y = y;
    self.mouse.isActive = true;

    mouseEvent.x = x;
    mouseEvent.y = y;
    mouseEvent.button = null;
    mouseEvent.event = e;
    mouseEvent.isTouch = false;

    app.states.mousemove(mouseEvent);
  });

  self._container.addEventListener('mouseup', function(e) {
    e.preventDefault();

    var x = e.offsetX === undefined ? e.layerX - self._container.offsetLeft : e.offsetX;
    var y = e.offsetY === undefined ? e.layerY - self._container.offsetTop : e.offsetY;

    switch (e.button) {
      case 0:
        self.mouse.isLeftDown = false;
      break;
      case 1:
        self.mouse.isMiddleDown = false;
        break;
      case 2:
        self.mouse.isRightDown = false;
        break;
    }

    self.mouse.isDown = self.mouse.isLeftDown || self.mouse.isRightDown || self.mouse.isMiddleDown;

    mouseEvent.x = x;
    mouseEvent.y = y;
    mouseEvent.button = e.button;
    mouseEvent.event = e;
    mouseEvent.isTouch = false;

    app.states.mouseup(mouseEvent);
  }, false);

  self._container.addEventListener('mouseleave', function() {
    self.mouse.isActive = false;

    self.mouse.isDown = false;
    self.mouse.isLeftDown = false;
    self.mouse.isRightDown = false;
    self.mouse.isMiddleDown = false;
  });

  self._container.addEventListener('mouseenter', function() {
    self.mouse.isActive = true;
  });

  self._container.addEventListener('mousedown', function(e) {
    e.preventDefault();

    var x = e.offsetX === undefined ? e.layerX - self._container.offsetLeft : e.offsetX;
    var y = e.offsetY === undefined ? e.layerY - self._container.offsetTop : e.offsetY;

    self.mouse.x = x;
    self.mouse.y = y;
    self.mouse.isDown = true;
    self.mouse.isActive = true;

    switch (e.button) {
      case 0:
        self.mouse.isLeftDown = true;
      break;
      case 1:
        self.mouse.isMiddleDown = true;
        break;
      case 2:
        self.mouse.isRightDown = true;
        break;
    }

    mouseEvent.x = x;
    mouseEvent.y = y;
    mouseEvent.button = e.button;
    mouseEvent.event = e;
    mouseEvent.isTouch = false;

    app.states.mousedown(mouseEvent);
  }, false);

  self._container.addEventListener('touchstart', function(e) {
    e.preventDefault();

    for (var i=0; i<e.touches.length; i++) {
      var touch = e.touches[i];

      var x = touch.pageX - self._container.offsetLeft;
      var y = touch.pageY - self._container.offsetTop;

      self.mouse.x = x;
      self.mouse.y = y;
      self.mouse.isDown = true;
      self.mouse.isLeftDown = true;
      self.mouse.isActive = true;

      mouseEvent.x = x;
      mouseEvent.y = y;
      mouseEvent.button = 1;
      mouseEvent.event = e;
      mouseEvent.isTouch = true;

      app.states.mousedown(mouseEvent);
    }
  });

  self._container.addEventListener('touchmove', function(e) {
    e.preventDefault();

    for (var i=0; i<e.touches.length; i++) {
      var touch = e.touches[i];

      var x = touch.pageX - self._container.offsetLeft;
      var y = touch.pageY - self._container.offsetTop;

      self.mouse.x = x;
      self.mouse.y = y;
      self.mouse.isDown = true;
      self.mouse.isLeftDown = true;
      self.mouse.isActive = true;

      mouseEvent.x = x;
      mouseEvent.y = y;
      mouseEvent.event = e;
      mouseEvent.isTouch = true;

      app.states.mousemove(mouseEvent);
    }
  });

  self._container.addEventListener('touchend', function(e) {
    e.preventDefault();

    var touch = e.changedTouches[0];

    var x = touch.pageX - self._container.offsetLeft;
    var y = touch.pageY - self._container.offsetTop;

    self.mouse.x = x;
    self.mouse.y = y;
    self.mouse.isActive = false;
    self.mouse.isDown = false;
    self.mouse.isLeftDown = false;
    self.mouse.isRightDown = false;
    self.mouse.isMiddleDown = false;

    mouseEvent.x = x;
    mouseEvent.y = y;
    mouseEvent.event = e;
    mouseEvent.isTouch = true;

    app.states.mouseup(mouseEvent);
  });

  self._container.addEventListener('contextmenu', function(e) {
    e.preventDefault();
  });

  document.addEventListener('keydown', function(e) {
    self._keys[e.keyCode] = true;

    keyboardEvent.key = e.which;
    keyboardEvent.name = invKeys[e.which];
    keyboardEvent.event = e;

    app.states.keydown(keyboardEvent);
  });

  document.addEventListener('keyup', function(e) {
    self._keys[e.keyCode] = false;

    keyboardEvent.key = e.which;
    keyboardEvent.name = invKeys[e.which];
    keyboardEvent.event = e;

    app.states.keyup(keyboardEvent);
  });
};

module.exports = Input;
<commit_msg>add new delta x/y to mouse<commit_after>var keys = require('./keys');

var invKeys = {};
for (var keyName in keys) {
  invKeys[keys[keyName]] = keyName;
}

var Input = function(app, container) {
  this._container = container;
  this._keys = {};

  this.canControlKeys = true;

  this.mouse = {
    isDown: false,
    isLeftDown: false,
    isMiddleDown: false,
    isRightDown: false,
    x: null,
    y: null,
    dx: 0,
    dy: 0
  };

  this._addEvents(app);
};

Input.prototype.resetKeys = function() {
  this._keys = {};
};

Input.prototype.isKeyDown = function(key) {
  if (key == null) { return false; }

  if (this.canControlKeys) {
    var code = typeof key === 'number' ? key : keys[key.toLowerCase()];
    return this._keys[code];
  }
};

Input.prototype._addEvents = function(app) {
  var self = this;

  var mouseEvent = {
    x: null,
    y: null,
    button: null,
    isTouch: false,
    event: null,
    stateStopEvent: function() {
      app.states._preventEvent = true;
    }
  };

  var keyboardEvent = {
    key: null,
    name: null,
    event: null,
    stateStopEvent: function() {
      app.states._preventEvent = true;
    }
  };

  self._container.addEventListener('mousemove', function(e) {
    var x = e.offsetX === undefined ? e.layerX - self._container.offsetLeft : e.offsetX;
    var y = e.offsetY === undefined ? e.layerY - self._container.offsetTop : e.offsetY;

    if (self.mouse.x != null && self.mouse.x != null) {
      self.mouse.dx = x - self.mouse.x;
      self.mouse.dy = y - self.mouse.y;
    }

    self.mouse.x = x;
    self.mouse.y = y;
    self.mouse.isActive = true;

    mouseEvent.x = x;
    mouseEvent.y = y;
    mouseEvent.button = null;
    mouseEvent.event = e;
    mouseEvent.isTouch = false;

    app.states.mousemove(mouseEvent);
  });

  self._container.addEventListener('mouseup', function(e) {
    e.preventDefault();

    var x = e.offsetX === undefined ? e.layerX - self._container.offsetLeft : e.offsetX;
    var y = e.offsetY === undefined ? e.layerY - self._container.offsetTop : e.offsetY;

    switch (e.button) {
      case 0:
        self.mouse.isLeftDown = false;
      break;
      case 1:
        self.mouse.isMiddleDown = false;
        break;
      case 2:
        self.mouse.isRightDown = false;
        break;
    }

    self.mouse.isDown = self.mouse.isLeftDown || self.mouse.isRightDown || self.mouse.isMiddleDown;

    mouseEvent.x = x;
    mouseEvent.y = y;
    mouseEvent.button = e.button;
    mouseEvent.event = e;
    mouseEvent.isTouch = false;

    app.states.mouseup(mouseEvent);
  }, false);

  self._container.addEventListener('mouseleave', function() {
    self.mouse.isActive = false;

    self.mouse.isDown = false;
    self.mouse.isLeftDown = false;
    self.mouse.isRightDown = false;
    self.mouse.isMiddleDown = false;
  });

  self._container.addEventListener('mouseenter', function() {
    self.mouse.isActive = true;
  });

  self._container.addEventListener('mousedown', function(e) {
    e.preventDefault();

    var x = e.offsetX === undefined ? e.layerX - self._container.offsetLeft : e.offsetX;
    var y = e.offsetY === undefined ? e.layerY - self._container.offsetTop : e.offsetY;

    self.mouse.x = x;
    self.mouse.y = y;
    self.mouse.isDown = true;
    self.mouse.isActive = true;

    switch (e.button) {
      case 0:
        self.mouse.isLeftDown = true;
      break;
      case 1:
        self.mouse.isMiddleDown = true;
        break;
      case 2:
        self.mouse.isRightDown = true;
        break;
    }

    mouseEvent.x = x;
    mouseEvent.y = y;
    mouseEvent.button = e.button;
    mouseEvent.event = e;
    mouseEvent.isTouch = false;

    app.states.mousedown(mouseEvent);
  }, false);

  self._container.addEventListener('touchstart', function(e) {
    e.preventDefault();

    for (var i=0; i<e.touches.length; i++) {
      var touch = e.touches[i];

      var x = touch.pageX - self._container.offsetLeft;
      var y = touch.pageY - self._container.offsetTop;

      self.mouse.x = x;
      self.mouse.y = y;
      self.mouse.isDown = true;
      self.mouse.isLeftDown = true;
      self.mouse.isActive = true;

      mouseEvent.x = x;
      mouseEvent.y = y;
      mouseEvent.button = 1;
      mouseEvent.event = e;
      mouseEvent.isTouch = true;

      app.states.mousedown(mouseEvent);
    }
  });

  self._container.addEventListener('touchmove', function(e) {
    e.preventDefault();

    for (var i=0; i<e.touches.length; i++) {
      var touch = e.touches[i];

      var x = touch.pageX - self._container.offsetLeft;
      var y = touch.pageY - self._container.offsetTop;

      self.mouse.x = x;
      self.mouse.y = y;
      self.mouse.isDown = true;
      self.mouse.isLeftDown = true;
      self.mouse.isActive = true;

      mouseEvent.x = x;
      mouseEvent.y = y;
      mouseEvent.event = e;
      mouseEvent.isTouch = true;

      app.states.mousemove(mouseEvent);
    }
  });

  self._container.addEventListener('touchend', function(e) {
    e.preventDefault();

    var touch = e.changedTouches[0];

    var x = touch.pageX - self._container.offsetLeft;
    var y = touch.pageY - self._container.offsetTop;

    self.mouse.x = x;
    self.mouse.y = y;
    self.mouse.isActive = false;
    self.mouse.isDown = false;
    self.mouse.isLeftDown = false;
    self.mouse.isRightDown = false;
    self.mouse.isMiddleDown = false;

    mouseEvent.x = x;
    mouseEvent.y = y;
    mouseEvent.event = e;
    mouseEvent.isTouch = true;

    app.states.mouseup(mouseEvent);
  });

  self._container.addEventListener('contextmenu', function(e) {
    e.preventDefault();
  });

  document.addEventListener('keydown', function(e) {
    self._keys[e.keyCode] = true;

    keyboardEvent.key = e.which;
    keyboardEvent.name = invKeys[e.which];
    keyboardEvent.event = e;

    app.states.keydown(keyboardEvent);
  });

  document.addEventListener('keyup', function(e) {
    self._keys[e.keyCode] = false;

    keyboardEvent.key = e.which;
    keyboardEvent.name = invKeys[e.which];
    keyboardEvent.event = e;

    app.states.keyup(keyboardEvent);
  });
};

module.exports = Input;
<|endoftext|>


<commit_before>import config from 'config'
import { createSelector } from 'reselect'
import errorToUserFriendly from '@zap/utils/userFriendlyErrors'
import { decodePayReq, getNodeAlias } from '@zap/utils/crypto'
import { convert } from '@zap/utils/btc'
import delay from '@zap/utils/delay'
import { grpcService } from 'workers'
import { fetchBalance } from './balance'
import { fetchChannels } from './channels'
import { networkSelectors } from './network'
import { showError } from './notification'

// ------------------------------------
// Initial State
// ------------------------------------

const initialState = {
  paymentLoading: false,
  payment: null,
  payments: [],
  paymentsSending: [],
}

// ------------------------------------
// Constants
// ------------------------------------

export const SET_PAYMENT = 'SET_PAYMENT'
export const GET_PAYMENTS = 'GET_PAYMENTS'
export const RECEIVE_PAYMENTS = 'RECEIVE_PAYMENTS'
export const SEND_PAYMENT = 'SEND_PAYMENT'
export const PAYMENT_SUCCESSFUL = 'PAYMENT_SUCCESSFUL'
export const PAYMENT_FAILED = 'PAYMENT_FAILED'
export const DECREASE_PAYMENT_RETRIES = 'DECREASE_PAYMENT_RETRIES'

// ------------------------------------
// Helpers
// ------------------------------------

/**
 * decoratePayment - Decorate payment object with custom/computed properties.
 *
 * @param  {object} payment Payment
 * @param  {Array} nodes Nodes
 * @returns {object} Decorated payment
 */
const decoratePayment = (payment, nodes = []) => {
  // Add basic type information.
  const decoration = {
    type: 'payment',
  }

  // Older versions of lnd provided the sat amount in `value`.
  // This is now deprecated in favor of `value_sat` and `value_msat`.
  // Patch data returned from older clients to match the current format for consistency.
  const { value } = payment
  if (value && (!payment.value_sat || !payment.value_msat)) {
    Object.assign(decoration, {
      value_sat: value,
      value_msat: convert('sats', 'msats', value),
    })
  }

  // First try to get the pubkey from payment.path
  let pubkey = payment.path && payment.path[payment.path.length - 1]

  // If we don't have a pubkey, try to get it from the payment request.
  if (!pubkey && payment.payment_request) {
    const paymentRequest = decodePayReq(payment.payment_request)
    pubkey = paymentRequest.payeeNodeKey
  }

  // Try to add some info about the destination of the payment.
  if (pubkey) {
    Object.assign(decoration, {
      dest_node_pubkey: pubkey,
      dest_node_alias: getNodeAlias(pubkey, nodes),
    })
  }

  return {
    ...payment,
    ...decoration,
  }
}

/**
 * getLastSendingEntry - Find the latest temporary paymentsSending entry for the payment.
 *
 * @param  {object} state Redux state
 * @param  {string} paymentRequest Payment request
 * @returns {object} sendingPayments entry
 */
const getLastSendingEntry = (state, paymentRequest) =>
  [...state.payment.paymentsSending]
    .sort((a, b) => b.creation_date - a.creation_date)
    .find(p => p.paymentRequest === paymentRequest)

/**
 * handleDecreaseRetries - Decreases number of retries left for the given @paymentRequest.
 *
 * @param  {object} state Redux state
 * @param  {{ paymentRequest }} paymentRequest Payment request
 * @returns {object} Updated state
 */
const handleDecreaseRetries = (state, { paymentRequest }) => {
  const paymentsSending = state.paymentsSending.map(payment => {
    if (payment.paymentRequest === paymentRequest) {
      return { ...payment, remainingRetries: payment.remainingRetries - 1 }
    }
    return payment
  })

  return {
    ...state,
    paymentsSending,
  }
}

// ------------------------------------
// Actions
// ------------------------------------

/**
 * setPayment - Set the current in progress payment.
 *
 * @param  {object} payment Payment
 * @returns {object} Action
 */
export function setPayment(payment) {
  return {
    type: SET_PAYMENT,
    payment,
  }
}

/**
 * getPayments - Initiate fetching all payments.
 *
 * @returns {object} Action
 */
export function getPayments() {
  return {
    type: GET_PAYMENTS,
  }
}

/**
 * sendPayment - After initiating a lightning payment, store details of it in paymentSending array.
 *
 * @param {object} data Payment data
 * @returns {Function} Thunk
 */
export const sendPayment = data => dispatch => {
  const invoice = decodePayReq(data.paymentRequest)
  const paymentHashTag = invoice.tags ? invoice.tags.find(t => t.tagName === 'payment_hash') : null

  if (!paymentHashTag || !paymentHashTag.data) {
    dispatch(showError('Unable to send payment: Invalid invoice (no payment hash)'))
    return
  }

  const payment = {
    ...data,
    status: 'sending',
    isSending: true,
    creation_date: Math.round(new Date() / 1000),
    payment_hash: paymentHashTag.data,
  }

  dispatch({
    type: SEND_PAYMENT,
    payment,
  })
}

/**
 * fetchPayments - Fetch details of all lightning payments.
 *
 * @returns {Function} Thunk
 */
export const fetchPayments = () => async dispatch => {
  dispatch(getPayments())
  const grpc = await grpcService
  const payments = await grpc.services.Lightning.listPayments()
  dispatch(receivePayments(payments))
}

/**
 * receivePayments - Fetch payments success callback.
 *
 * @param {{payments}} List of payments.
 * @returns {Function} Thunk
 */
export const receivePayments = ({ payments }) => dispatch => {
  dispatch({ type: RECEIVE_PAYMENTS, payments })
}

/**
 * decPaymentRetry - Decrement payment request retry count.
 *
 * @param {object} paymentRequest Lightning payment request.
 * @returns {Function} Thunk
 */
const decPaymentRetry = paymentRequest => ({
  type: DECREASE_PAYMENT_RETRIES,
  paymentRequest,
})

/**
 * payInvoice - Pay a lightniung invoice.
 * Controller code that wraps the send action and schedules automatic retries in the case of a failure.
 *
 * @param {object} options Options
 * @param {string} options.payReq Payment request
 * @param {number} options.amt Payment amount (in sats)
 * @param {number} options.feeLimit The max fee to apply
 * @param {boolean} options.isRetry Boolean indicating whether this is a retry attempt
 * @param {number} options.retries Number of remaining retries
 * @returns {Function} Thunk
 */
export const payInvoice = ({
  payReq,
  amt,
  feeLimit,
  isRetry = false,
  retries = 0,
}) => async dispatch => {
  // if it's a retry - only decrease number of retries left
  if (isRetry) {
    dispatch(decPaymentRetry(payReq))
  }
  // Otherwise, add to sendingPayments in the state.
  else {
    dispatch(
      sendPayment({
        paymentRequest: payReq,
        feeLimit,
        value: amt,
        remainingRetries: retries,
        maxRetries: retries,
      })
    )
  }

  // Submit the payment to LND.
  try {
    const grpc = await grpcService
    const data = await grpc.services.Lightning.sendPayment({
      payment_request: payReq,
      amt,
      fee_limit: { fixed: feeLimit },
    })
    dispatch(paymentSuccessful(data))
  } catch (e) {
    dispatch(
      paymentFailed({
        error: e.message,
        payment_request: e.payload.payment_request,
      })
    )
  }
}

/**
 * paymentSuccessful - Success handler for payInvoice.
 *
 * @param {{payment_request}} payment_request Payment request
 * @returns {Function} Thunk
 */
export const paymentSuccessful = ({ payment_request }) => async (dispatch, getState) => {
  const state = getState()
  const paymentSending = getLastSendingEntry(state, payment_request)
  // If we found a related entery in paymentsSending, gracefully remove it and handle as success case.
  if (paymentSending) {
    const { creation_date, paymentRequest } = paymentSending

    // Ensure payment stays in sending state for at least 2 seconds.
    await delay(2000 - (Date.now() - creation_date * 1000))

    // Mark the payment as successful.
    dispatch({ type: PAYMENT_SUCCESSFUL, paymentRequest })

    // Wait for another second.
    await delay(1500)
  }

  // Refetch payments.
  dispatch(fetchPayments())

  // Fetch new balance.
  dispatch(fetchBalance())

  // Fetch updated channels.
  dispatch(fetchChannels())
}

/**
 * paymentFailed - Error handler for payInvoice.
 *
 * @param {object} details Details
 * @param {string} details.payment_request Payment request
 * @param {string} details.error Error message
 * @returns {Function} Thunk
 */
export const paymentFailed = ({ payment_request, error }) => async (dispatch, getState) => {
  const state = getState()
  const paymentSending = getLastSendingEntry(state, payment_request)
  // errors that trigger retry mechanism
  const RETRIABLE_ERRORS = [
    'unable to find a path to destination', // ErrNoPathFound
    'target not found', // ErrTargetNotInNetwork
  ]

  // If we found a related entery in paymentsSending, gracefully remove it and handle as error case.
  if (paymentSending) {
    const { creation_date, paymentRequest, remainingRetries, maxRetries } = paymentSending
    // if we have retries left and error is eligible for retry - rebroadcast payment
    if (remainingRetries && RETRIABLE_ERRORS.includes(error)) {
      const data = {
        ...paymentSending,
        payReq: paymentRequest,
        isRetry: true,
      }
      const retryIndex = maxRetries - remainingRetries + 1
      // add increasing delay
      await delay(config.invoices.baseRetryDelay * retryIndex * retryIndex)
      dispatch(payInvoice(data))
    } else {
      // Ensure payment stays in sending state for at least 2 seconds.
      await delay(2000 - (Date.now() - creation_date * 1000))

      // Mark the payment as failed.
      dispatch({ type: PAYMENT_FAILED, paymentRequest, error: errorToUserFriendly(error) })
    }
  }
}

// ------------------------------------
// Action Handlers
// ------------------------------------

const ACTION_HANDLERS = {
  [GET_PAYMENTS]: state => ({ ...state, paymentLoading: true }),
  [RECEIVE_PAYMENTS]: (state, { payments }) => ({
    ...state,
    paymentLoading: false,
    payments,
    paymentsSending: state.paymentsSending.filter(
      item => !payments.find(p => p.payment_hash === item.payment_hash)
    ),
  }),
  [SET_PAYMENT]: (state, { payment }) => ({ ...state, payment }),
  [SEND_PAYMENT]: (state, { payment }) => ({
    ...state,
    paymentsSending: [...state.paymentsSending, payment],
  }),
  [DECREASE_PAYMENT_RETRIES]: handleDecreaseRetries,
  [PAYMENT_SUCCESSFUL]: (state, { paymentRequest }) => {
    return {
      ...state,
      paymentsSending: state.paymentsSending.map(item => {
        if (item.paymentRequest !== paymentRequest) {
          return item
        }
        return {
          ...item,
          status: 'successful',
        }
      }),
    }
  },
  [PAYMENT_FAILED]: (state, { paymentRequest, error }) => {
    return {
      ...state,
      paymentsSending: state.paymentsSending.map(item => {
        if (item.paymentRequest !== paymentRequest) {
          return item
        }
        return {
          ...item,
          status: 'failed',
          error,
        }
      }),
    }
  },
}

// ------------------------------------
// Selectors
// ------------------------------------

const paymentSelectors = {}
const modalPaymentSelector = state => state.payment.payment
const paymentsSelector = state => state.payment.payments
const paymentsSendingSelector = state => state.payment.paymentsSending
const nodesSelector = state => networkSelectors.nodes(state)

paymentSelectors.payments = createSelector(
  paymentsSelector,
  nodesSelector,
  (payments, nodes) => payments.map(payment => decoratePayment(payment, nodes))
)

paymentSelectors.paymentsSending = createSelector(
  paymentsSendingSelector,
  nodesSelector,
  (paymentsSending, nodes) => paymentsSending.map(payment => decoratePayment(payment, nodes))
)

paymentSelectors.paymentModalOpen = createSelector(
  modalPaymentSelector,
  payment => !!payment
)

export { paymentSelectors }

// ------------------------------------
// Reducer
// ------------------------------------

/**
 * paymentReducer - Payment reducer.
 *
 * @param  {object} state = initialState Initial state
 * @param  {object} action Action
 * @returns {object} Next state
 */
export default function paymentReducer(state = initialState, action) {
  const handler = ACTION_HANDLERS[action.type]

  return handler ? handler(state, action) : state
}
<commit_msg>refactor: use immer in payment reducer<commit_after>import config from 'config'
import { createSelector } from 'reselect'
import errorToUserFriendly from '@zap/utils/userFriendlyErrors'
import { decodePayReq, getNodeAlias } from '@zap/utils/crypto'
import { convert } from '@zap/utils/btc'
import delay from '@zap/utils/delay'
import { grpcService } from 'workers'
import createReducer from './utils/createReducer'
import { fetchBalance } from './balance'
import { fetchChannels } from './channels'
import { networkSelectors } from './network'
import { showError } from './notification'

// ------------------------------------
// Initial State
// ------------------------------------

const initialState = {
  paymentLoading: false,
  payment: null,
  payments: [],
  paymentsSending: [],
}

// ------------------------------------
// Constants
// ------------------------------------

export const SET_PAYMENT = 'SET_PAYMENT'
export const GET_PAYMENTS = 'GET_PAYMENTS'
export const RECEIVE_PAYMENTS = 'RECEIVE_PAYMENTS'
export const SEND_PAYMENT = 'SEND_PAYMENT'
export const PAYMENT_SUCCESSFUL = 'PAYMENT_SUCCESSFUL'
export const PAYMENT_FAILED = 'PAYMENT_FAILED'
export const DECREASE_PAYMENT_RETRIES = 'DECREASE_PAYMENT_RETRIES'

// ------------------------------------
// Helpers
// ------------------------------------

/**
 * decoratePayment - Decorate payment object with custom/computed properties.
 *
 * @param  {object} payment Payment
 * @param  {Array} nodes Nodes
 * @returns {object} Decorated payment
 */
const decoratePayment = (payment, nodes = []) => {
  // Add basic type information.
  const decoration = {
    type: 'payment',
  }

  // Older versions of lnd provided the sat amount in `value`.
  // This is now deprecated in favor of `value_sat` and `value_msat`.
  // Patch data returned from older clients to match the current format for consistency.
  const { value } = payment
  if (value && (!payment.value_sat || !payment.value_msat)) {
    Object.assign(decoration, {
      value_sat: value,
      value_msat: convert('sats', 'msats', value),
    })
  }

  // First try to get the pubkey from payment.path
  let pubkey = payment.path && payment.path[payment.path.length - 1]

  // If we don't have a pubkey, try to get it from the payment request.
  if (!pubkey && payment.payment_request) {
    const paymentRequest = decodePayReq(payment.payment_request)
    pubkey = paymentRequest.payeeNodeKey
  }

  // Try to add some info about the destination of the payment.
  if (pubkey) {
    Object.assign(decoration, {
      dest_node_pubkey: pubkey,
      dest_node_alias: getNodeAlias(pubkey, nodes),
    })
  }

  return {
    ...payment,
    ...decoration,
  }
}

/**
 * getLastSendingEntry - Find the latest temporary paymentsSending entry for the payment.
 *
 * @param  {object} state Redux state
 * @param  {string} paymentRequest Payment request
 * @returns {object} sendingPayments entry
 */
const getLastSendingEntry = (state, paymentRequest) =>
  [...state.payment.paymentsSending]
    .sort((a, b) => b.creation_date - a.creation_date)
    .find(p => p.paymentRequest === paymentRequest)

// ------------------------------------
// Actions
// ------------------------------------

/**
 * setPayment - Set the current in progress payment.
 *
 * @param  {object} payment Payment
 * @returns {object} Action
 */
export function setPayment(payment) {
  return {
    type: SET_PAYMENT,
    payment,
  }
}

/**
 * getPayments - Initiate fetching all payments.
 *
 * @returns {object} Action
 */
export function getPayments() {
  return {
    type: GET_PAYMENTS,
  }
}

/**
 * sendPayment - After initiating a lightning payment, store details of it in paymentSending array.
 *
 * @param {object} data Payment data
 * @returns {Function} Thunk
 */
export const sendPayment = data => dispatch => {
  const invoice = decodePayReq(data.paymentRequest)
  const paymentHashTag = invoice.tags ? invoice.tags.find(t => t.tagName === 'payment_hash') : null

  if (!paymentHashTag || !paymentHashTag.data) {
    dispatch(showError('Unable to send payment: Invalid invoice (no payment hash)'))
    return
  }

  const payment = {
    ...data,
    status: 'sending',
    isSending: true,
    creation_date: Math.round(new Date() / 1000),
    payment_hash: paymentHashTag.data,
  }

  dispatch({
    type: SEND_PAYMENT,
    payment,
  })
}

/**
 * fetchPayments - Fetch details of all lightning payments.
 *
 * @returns {Function} Thunk
 */
export const fetchPayments = () => async dispatch => {
  dispatch(getPayments())
  const grpc = await grpcService
  const payments = await grpc.services.Lightning.listPayments()
  dispatch(receivePayments(payments))
}

/**
 * receivePayments - Fetch payments success callback.
 *
 * @param {{payments}} List of payments.
 * @returns {Function} Thunk
 */
export const receivePayments = ({ payments }) => dispatch => {
  dispatch({ type: RECEIVE_PAYMENTS, payments })
}

/**
 * decPaymentRetry - Decrement payment request retry count.
 *
 * @param {object} paymentRequest Lightning payment request.
 * @returns {Function} Thunk
 */
const decPaymentRetry = paymentRequest => ({
  type: DECREASE_PAYMENT_RETRIES,
  paymentRequest,
})

/**
 * payInvoice - Pay a lightniung invoice.
 * Controller code that wraps the send action and schedules automatic retries in the case of a failure.
 *
 * @param {object} options Options
 * @param {string} options.payReq Payment request
 * @param {number} options.amt Payment amount (in sats)
 * @param {number} options.feeLimit The max fee to apply
 * @param {boolean} options.isRetry Boolean indicating whether this is a retry attempt
 * @param {number} options.retries Number of remaining retries
 * @returns {Function} Thunk
 */
export const payInvoice = ({
  payReq,
  amt,
  feeLimit,
  isRetry = false,
  retries = 0,
}) => async dispatch => {
  // if it's a retry - only decrease number of retries left
  if (isRetry) {
    dispatch(decPaymentRetry(payReq))
  }
  // Otherwise, add to sendingPayments in the state.
  else {
    dispatch(
      sendPayment({
        paymentRequest: payReq,
        feeLimit,
        value: amt,
        remainingRetries: retries,
        maxRetries: retries,
      })
    )
  }

  // Submit the payment to LND.
  try {
    const grpc = await grpcService
    const data = await grpc.services.Lightning.sendPayment({
      payment_request: payReq,
      amt,
      fee_limit: { fixed: feeLimit },
    })
    dispatch(paymentSuccessful(data))
  } catch (e) {
    dispatch(
      paymentFailed({
        error: e.message,
        payment_request: e.payload.payment_request,
      })
    )
  }
}

/**
 * paymentSuccessful - Success handler for payInvoice.
 *
 * @param {{payment_request}} payment_request Payment request
 * @returns {Function} Thunk
 */
export const paymentSuccessful = ({ payment_request }) => async (dispatch, getState) => {
  const state = getState()
  const paymentSending = getLastSendingEntry(state, payment_request)
  // If we found a related entery in paymentsSending, gracefully remove it and handle as success case.
  if (paymentSending) {
    const { creation_date, paymentRequest } = paymentSending

    // Ensure payment stays in sending state for at least 2 seconds.
    await delay(2000 - (Date.now() - creation_date * 1000))

    // Mark the payment as successful.
    dispatch({ type: PAYMENT_SUCCESSFUL, paymentRequest })

    // Wait for another second.
    await delay(1500)
  }

  // Refetch payments.
  dispatch(fetchPayments())

  // Fetch new balance.
  dispatch(fetchBalance())

  // Fetch updated channels.
  dispatch(fetchChannels())
}

/**
 * paymentFailed - Error handler for payInvoice.
 *
 * @param {object} details Details
 * @param {string} details.payment_request Payment request
 * @param {string} details.error Error message
 * @returns {Function} Thunk
 */
export const paymentFailed = ({ payment_request, error }) => async (dispatch, getState) => {
  const state = getState()
  const paymentSending = getLastSendingEntry(state, payment_request)
  // errors that trigger retry mechanism
  const RETRIABLE_ERRORS = [
    'unable to find a path to destination', // ErrNoPathFound
    'target not found', // ErrTargetNotInNetwork
  ]

  // If we found a related entery in paymentsSending, gracefully remove it and handle as error case.
  if (paymentSending) {
    const { creation_date, paymentRequest, remainingRetries, maxRetries } = paymentSending
    // if we have retries left and error is eligible for retry - rebroadcast payment
    if (remainingRetries && RETRIABLE_ERRORS.includes(error)) {
      const data = {
        ...paymentSending,
        payReq: paymentRequest,
        isRetry: true,
      }
      const retryIndex = maxRetries - remainingRetries + 1
      // add increasing delay
      await delay(config.invoices.baseRetryDelay * retryIndex * retryIndex)
      dispatch(payInvoice(data))
    } else {
      // Ensure payment stays in sending state for at least 2 seconds.
      await delay(2000 - (Date.now() - creation_date * 1000))

      // Mark the payment as failed.
      dispatch({ type: PAYMENT_FAILED, paymentRequest, error: errorToUserFriendly(error) })
    }
  }
}

// ------------------------------------
// Action Handlers
// ------------------------------------

const ACTION_HANDLERS = {
  [GET_PAYMENTS]: state => {
    state.paymentLoading = true
  },
  [RECEIVE_PAYMENTS]: (state, { payments }) => {
    state.paymentLoading = false
    state.payments = payments
    state.paymentsSending = state.paymentsSending.filter(
      item => !payments.find(p => p.payment_hash === item.payment_hash)
    )
  },
  [SET_PAYMENT]: (state, { payment }) => {
    state.payment = payment
  },
  [SEND_PAYMENT]: (state, { payment }) => {
    state.paymentsSending.push(payment)
  },

  [DECREASE_PAYMENT_RETRIES]: (state, { paymentRequest }) => {
    const { paymentsSending } = state
    const item = paymentsSending.find(item => item.paymentRequest === paymentRequest)
    if (item) {
      item.remainingRetries -= 1
    }
  },
  [PAYMENT_SUCCESSFUL]: (state, { paymentRequest }) => {
    const { paymentsSending } = state
    const item = paymentsSending.find(item => item.paymentRequest === paymentRequest)
    if (item) {
      item.status = 'successful'
    }
  },
  [PAYMENT_FAILED]: (state, { paymentRequest, error }) => {
    const { paymentsSending } = state
    const item = paymentsSending.find(item => item.paymentRequest === paymentRequest)
    if (item) {
      item.status = 'failed'
      item.error = error
    }
  },
}

// ------------------------------------
// Selectors
// ------------------------------------

const paymentSelectors = {}
const modalPaymentSelector = state => state.payment.payment
const paymentsSelector = state => state.payment.payments
const paymentsSendingSelector = state => state.payment.paymentsSending
const nodesSelector = state => networkSelectors.nodes(state)

paymentSelectors.payments = createSelector(
  paymentsSelector,
  nodesSelector,
  (payments, nodes) => payments.map(payment => decoratePayment(payment, nodes))
)

paymentSelectors.paymentsSending = createSelector(
  paymentsSendingSelector,
  nodesSelector,
  (paymentsSending, nodes) => paymentsSending.map(payment => decoratePayment(payment, nodes))
)

paymentSelectors.paymentModalOpen = createSelector(
  modalPaymentSelector,
  payment => !!payment
)

export { paymentSelectors }

export default createReducer(initialState, ACTION_HANDLERS)
<|endoftext|>


<commit_before>/*!
 * jQuery JavaScript Library v@VERSION
 * http://jquery.com/
 *
 * Includes Sizzle.js
 * http://sizzlejs.com/
 *
 * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: @DATE
 */
(function( window, undefined ) {

// Can't do this because several apps including ASP.NET trace
// the stack via arguments.caller.callee and Firefox dies if
// you try to trace through "use strict" call chains. (#13335)
// Support: Firefox 18+
//"use strict";
<commit_msg>2013!<commit_after>/*!
 * jQuery JavaScript Library v@VERSION
 * http://jquery.com/
 *
 * Includes Sizzle.js
 * http://sizzlejs.com/
 *
 * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: @DATE
 */
(function( window, undefined ) {

// Can't do this because several apps including ASP.NET trace
// the stack via arguments.caller.callee and Firefox dies if
// you try to trace through "use strict" call chains. (#13335)
// Support: Firefox 18+
//"use strict";
<|endoftext|>