<commit_before>"use strict"

import Context, {FileContext} from "./context"
import ShadowTree from "./shadowtree"
import PHPStrictError from "./phpstricterror"

var fs = require("fs")

class Lint {
    static get PHPStrictError() {
        return PHPStrictError
    }
    static get ShadowTree() {
        return ShadowTree
    }
    constructor(tree, filename = null, namespace = []) {
        Object.assign(
            this,
            {
                filename: filename,
                namespace: namespace,
                tree: tree,
            }
        );
    }
    check() {
        return ShadowTree.Node.typed(this.tree).check(
            new Context(
                new FileContext(this.filename)
            )
        )
    }
    static check(tree, filename = null) {
        var l = new Lint(tree, filename)
        try {
            return l.check()
        } catch(e) {
            if(e instanceof PHPStrictError) {
                console.log(e.message)
                if(filename) {
                    var lines = fs.readFileSync(filename, "utf8").split(/\n/)
                    if(e.loc.start.line >= 5) {
                        console.log(lines.slice(e.loc.start.line - 5, e.loc.start.line).join("\n"))
                    } else {
                        console.log(lines.slice(0, e.loc.start.line).join("\n"))
                    }
                    if(e.loc.start.line == e.loc.end.line) {
                        console.log(
                            " ".repeat(e.loc.start.column) + "^" +
                            "~".repeat(e.loc.end.column - e.loc.start.column - 1)
                        )
                    } else {
                        console.log(
                            " ".repeat(e.loc.start.column) + "^"
                        )
                    }
                }
                return null
            } else {
                throw e
            }
        }
    }
};

module.exports = Lint;
<commit_msg>Show more lines by default<commit_after>"use strict"

import Context, {FileContext} from "./context"
import ShadowTree from "./shadowtree"
import PHPStrictError from "./phpstricterror"

var fs = require("fs")

const ShowContextLines = 10

class Lint {
    static get PHPStrictError() {
        return PHPStrictError
    }
    static get ShadowTree() {
        return ShadowTree
    }
    constructor(tree, filename = null, namespace = []) {
        Object.assign(
            this,
            {
                filename: filename,
                namespace: namespace,
                tree: tree,
            }
        );
    }
    check() {
        return ShadowTree.Node.typed(this.tree).check(
            new Context(
                new FileContext(this.filename)
            )
        )
    }
    static check(tree, filename = null) {
        var l = new Lint(tree, filename)
        try {
            return l.check()
        } catch(e) {
            if(e instanceof PHPStrictError) {
                console.log(e.message)
                if(filename) {
                    var lines = fs.readFileSync(filename, "utf8").split(/\n/)
                    if(e.loc.start.line >= ShowContextLines) {
                        console.log(lines.slice(e.loc.start.line - ShowContextLines, e.loc.start.line).join("\n"))
                    } else {
                        console.log(lines.slice(0, e.loc.start.line).join("\n"))
                    }
                    if(e.loc.start.line == e.loc.end.line) {
                        console.log(
                            " ".repeat(e.loc.start.column) + "^" +
                            "~".repeat(e.loc.end.column - e.loc.start.column - 1)
                        )
                    } else {
                        console.log(
                            " ".repeat(e.loc.start.column) + "^"
                        )
                    }
                }
                return null
            } else {
                throw e
            }
        }
    }
};

module.exports = Lint;
<|endoftext|>


<commit_before>/** @module module:instantsearch */
/**
 * @external SearchParameters
 * @see https://community.algolia.com/algoliasearch-helper-js/reference.html#searchparameters
 */
// required for browsers not supporting Object.freeze (helper requirement)
import '../shams/Object.freeze.js';

// required for IE <= 10 since move to babel6
import '../shims/Object.getPrototypeOf.js';

import toFactory from 'to-factory';
import algoliasearchHelper from 'algoliasearch-helper';

import InstantSearch from './InstantSearch.js';
import version from './version.js';

import * as connectors from '../connectors/index.js';
import * as widgets from '../widgets/index.js';

/**
 * @typedef {Object} UrlSyncOptions
 * @property {Object} [mapping] Object used to define replacement query
 * parameter to use in place of another. Keys are current query parameters
 * and value the new value, e.g. `{ q: 'query' }`.
 * @property {number} [threshold] Idle time in ms after which a new
 * state is created in the browser history. The default value is 700. The url is always updated at each keystroke
 * but we only create a "previous search state" (activated when click on back button) every 700ms of idle time.
 * @property {string[]} [trackedParameters] Parameters that will
 * be synchronized in the URL. Default value is `['query', 'attribute:*',
 * 'index', 'page', 'hitsPerPage']`. `attribute:*` means all the faceting attributes will be tracked. You
 * can track only some of them by using [..., 'attribute:color', 'attribute:categories']. All other possible
 * values are all the [attributes of the Helper SearchParameters](https://community.algolia.com/algoliasearch-helper-js/reference.html#searchparameters).
 *
 * There's a special `is_v` parameter that will get added everytime, it tracks the version of instantsearch.js
 * linked to the url.
 * @property {boolean} [useHash] If set to true, the url will be
 * hash based. Otherwise, it'll use the query parameters using the modern
 * history API.
 * @property {function} [getHistoryState] Pass this function to override the
 * default history API state we set to `null`. For example this could be used to force passing
 * {turbolinks: true} to the history API every time we update it.
 */

/**
 * @typedef {Object} InstantSearchOptions
 * @property {string} appId The Algolia application ID
 * @property {string} apiKey The Algolia search-only API key
 * @property {string} indexName The name of the main index
 * @property {string} [numberLocale] The locale used to display numbers. This will be passed
 * to [`Number.prototype.toLocaleString()`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString)
 * @property {function} [searchFunction] A hook that will be called each time a search needs to be done, with the
 * helper as a parameter. It's your responsibility to call helper.search(). This option allows you to avoid doing
 * searches at page load for example.
 * @property  {function} [createAlgoliaClient] Allows you to provide your own algolia client instead of
 * the one instantiated internally by instantsearch.js. Useful in situations where you need
 * to setup complex mechanism on the client or if you need to share it easily.
 * Usage:
 * ```javascript
 * instantsearch({
 *   // other parameters
 *   createAlgoliaClient: function(algoliasearch, appId, apiKey) {
 *     return anyCustomClient;
 *   }
 * });
 * ```
 * We forward `algoliasearch` which is the original algoliasearch module imported inside instantsearch.js
 * @property {object} [searchParameters] Additional parameters to pass to
 * the Algolia API.
 * [Full documentation](https://community.algolia.com/algoliasearch-helper-js/reference.html#searchparameters)
 * @property {boolean|UrlSyncOptions} [urlSync] Url synchronization configuration.
 * Setting to `true` will synchronize the needed search parameters with the browser url.
 */

/**
 * InstantSearch is the main component of InstantSearch.js. This object
 * manages the widget and let you add new ones.
 *
 * Three parameters are required to get you started with instantsearch.js:
 *  - `appId`: your algolia application id
 *  - `apiKey`: the search key associated with your application
 *  - `indexName`: the main index that you will use for your new search UI
 *
 * Those parameters can be found in your [Algolia dashboard](https://www.algolia.com/api-keys).
 * If you want to get up and running quickly with InstantSearch.js, have a
 * look at the [getting started](getting-started.html).
 *
 * @function instantsearch
 * @param {InstantSearchOptions} $0 The options
 * @return {InstantSearch} the instantsearch instance
 */
const instantsearch = Object.assign(toFactory(InstantSearch), {
  createQueryString: algoliasearchHelper.url.getQueryStringFromState,
  connectors,
  widgets,
  version,
});

export default instantsearch;
<commit_msg>fix(misc): IE11 support without using transpiler<commit_after>/** @module module:instantsearch */
/**
 * @external SearchParameters
 * @see https://community.algolia.com/algoliasearch-helper-js/reference.html#searchparameters
 */
// required for browsers not supporting Object.freeze (helper requirement)
import '../shams/Object.freeze.js';

// required for IE <= 10 since move to babel6
import '../shims/Object.getPrototypeOf.js';

import toFactory from 'to-factory';
import algoliasearchHelper from 'algoliasearch-helper';

import InstantSearch from './InstantSearch.js';
import version from './version.js';

import * as connectors from '../connectors/index.js';
import * as widgets from '../widgets/index.js';

/**
 * @typedef {Object} UrlSyncOptions
 * @property {Object} [mapping] Object used to define replacement query
 * parameter to use in place of another. Keys are current query parameters
 * and value the new value, e.g. `{ q: 'query' }`.
 * @property {number} [threshold] Idle time in ms after which a new
 * state is created in the browser history. The default value is 700. The url is always updated at each keystroke
 * but we only create a "previous search state" (activated when click on back button) every 700ms of idle time.
 * @property {string[]} [trackedParameters] Parameters that will
 * be synchronized in the URL. Default value is `['query', 'attribute:*',
 * 'index', 'page', 'hitsPerPage']`. `attribute:*` means all the faceting attributes will be tracked. You
 * can track only some of them by using [..., 'attribute:color', 'attribute:categories']. All other possible
 * values are all the [attributes of the Helper SearchParameters](https://community.algolia.com/algoliasearch-helper-js/reference.html#searchparameters).
 *
 * There's a special `is_v` parameter that will get added everytime, it tracks the version of instantsearch.js
 * linked to the url.
 * @property {boolean} [useHash] If set to true, the url will be
 * hash based. Otherwise, it'll use the query parameters using the modern
 * history API.
 * @property {function} [getHistoryState] Pass this function to override the
 * default history API state we set to `null`. For example this could be used to force passing
 * {turbolinks: true} to the history API every time we update it.
 */

/**
 * @typedef {Object} InstantSearchOptions
 * @property {string} appId The Algolia application ID
 * @property {string} apiKey The Algolia search-only API key
 * @property {string} indexName The name of the main index
 * @property {string} [numberLocale] The locale used to display numbers. This will be passed
 * to [`Number.prototype.toLocaleString()`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString)
 * @property {function} [searchFunction] A hook that will be called each time a search needs to be done, with the
 * helper as a parameter. It's your responsibility to call helper.search(). This option allows you to avoid doing
 * searches at page load for example.
 * @property  {function} [createAlgoliaClient] Allows you to provide your own algolia client instead of
 * the one instantiated internally by instantsearch.js. Useful in situations where you need
 * to setup complex mechanism on the client or if you need to share it easily.
 * Usage:
 * ```javascript
 * instantsearch({
 *   // other parameters
 *   createAlgoliaClient: function(algoliasearch, appId, apiKey) {
 *     return anyCustomClient;
 *   }
 * });
 * ```
 * We forward `algoliasearch` which is the original algoliasearch module imported inside instantsearch.js
 * @property {object} [searchParameters] Additional parameters to pass to
 * the Algolia API.
 * [Full documentation](https://community.algolia.com/algoliasearch-helper-js/reference.html#searchparameters)
 * @property {boolean|UrlSyncOptions} [urlSync] Url synchronization configuration.
 * Setting to `true` will synchronize the needed search parameters with the browser url.
 */

/**
 * InstantSearch is the main component of InstantSearch.js. This object
 * manages the widget and let you add new ones.
 *
 * Three parameters are required to get you started with instantsearch.js:
 *  - `appId`: your algolia application id
 *  - `apiKey`: the search key associated with your application
 *  - `indexName`: the main index that you will use for your new search UI
 *
 * Those parameters can be found in your [Algolia dashboard](https://www.algolia.com/api-keys).
 * If you want to get up and running quickly with InstantSearch.js, have a
 * look at the [getting started](getting-started.html).
 *
 * @function instantsearch
 * @param {InstantSearchOptions} $0 The options
 * @return {InstantSearch} the instantsearch instance
 */
const instantsearch = toFactory(InstantSearch);

instantsearch.createQueryString = algoliasearchHelper.url.getQueryStringFromState;
instantsearch.connectors = connectors;
instantsearch.widgets = widgets;
instantsearch.version = version;

export default instantsearch;
<|endoftext|>


<commit_before>//many items left from tutorial
//http://www.anupshinde.com/posts/how-to-create-nodejs-npm-package/
"use strict"
//var fs = require('fs');
//var schema = require('validate');
//var _ = require('underscore');
//var S = require('string');
var utils = require('./utils');
var getEntry = utils.getEntry;
var getRecord = utils.getRecord;

exports.getRecord = getRecord;
<commit_msg>Remove old comments<commit_after>"use strict"
var utils = require('./utils');
var getEntry = utils.getEntry;
var getRecord = utils.getRecord;

exports.getRecord = getRecord;
<|endoftext|>


<commit_before>
export default {

	extension (data) {
		var position = data.lastIndexOf('.');
		return position > 0 ? data.slice(position + 1) : '';
	},

	join () {
		return Array.prototype.join
			.call(arguments, '/')
			.replace(/\/{2,}/g, '/')
			.replace(/^(https?:\/)/, '$1/');
	},

	base (href) {
		var base = window.document.querySelector('base');

		if (href) {
			if (base) {
				base.href = href;
			} else {
				base = window.document.createElement('base');
				base.href = href;
				window.document.head.insertBefore(base, window.document.head.firstElementChild);
			}
		}

		return base ? base.href : window.location.origin + window.location.pathname;
	},

	resolve (path, base) {
		var result = [];

		path = path.replace(window.location.origin, '');

		if (path.indexOf('http://') === 0 || path.indexOf('https://') === 0 || path.indexOf('//') === 0) {
			return path;
		}

		if (path.charAt(0) !== '/') {
			base = base || this.base();
			path = base + '/' + path;
			path = path.replace(window.location.origin, '');
		}

		path = path.replace(/\/{2,}/, '/');
		path = path.replace(/^\//, '');
		path = path.replace(/\/$/, '');

		var paths = path.split('/');

		for (var i = 0, l = paths.length; i < l; i++) {
			if (paths[i] === '.' || paths[i] === '') {
				continue;
			} else if (paths[i] === '..') {
				if (i > 0) {
					result.splice(i - 1, 1);
				}
			} else {
				result.push(paths[i]);
			}
		}

		return '/' + result.join('/');
	}

}
<commit_msg>added formatting<commit_after>
export default {

	extension (data) {
		var position = data.lastIndexOf('.');
		return position > 0 ? data.slice(position + 1) : '';
	},

	join () {
		return Array.prototype.join
			.call(arguments, '/')
			.replace(/\/{2,}/g, '/')
			.replace(/^(https?:\/)/, '$1/');
	},

	base (href) {
		var base = window.document.querySelector('base');

		if (href) {

			if (base) {
				base.href = href;
			} else {
				base = window.document.createElement('base');
				base.href = href;
				window.document.head.insertBefore(base, window.document.head.firstElementChild);
			}

		}

		return base ? base.href : window.location.origin + window.location.pathname;
	},

	resolve (path, base) {
		var result = [];

		path = path.replace(window.location.origin, '');

		if (path.indexOf('http://') === 0 || path.indexOf('https://') === 0 || path.indexOf('//') === 0) {
			return path;
		}

		if (path.charAt(0) !== '/') {
			base = base || this.base();
			path = base + '/' + path;
			path = path.replace(window.location.origin, '');
		}

		path = path.replace(/\/{2,}/, '/');
		path = path.replace(/^\//, '');
		path = path.replace(/\/$/, '');

		var paths = path.split('/');

		for (var i = 0, l = paths.length; i < l; i++) {

			if (paths[i] === '.' || paths[i] === '') {
				continue;
			} else if (paths[i] === '..') {

				if (i > 0) {
					result.splice(i - 1, 1);
				}

			} else {
				result.push(paths[i]);
			}

		}

		return '/' + result.join('/');
	}

}
<|endoftext|>


<commit_before>import constant from "./constant";
import jiggle from "./jiggle";
import {quadtree} from "d3-quadtree";
import {x, y} from "./simulation";

export default function() {
  var nodes,
      node,
      alpha,
      strength = constant(-30),
      strengths,
      distanceMin2 = 1,
      distanceMax2 = Infinity,
      theta2 = 0.81;

  function force(_) {
    var i, n = nodes.length, tree = quadtree(nodes, x, y).visitAfter(accumulate);
    for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply);
  }

  function initialize() {
    if (!nodes) return;
    var i, n = nodes.length, node;
    strengths = new Array(n);
    for (i = 0; i < n; ++i) node = nodes[i], strengths[node.index] = +strength(node, i, nodes);
  }

  function accumulate(quad) {
    var strength = 0, q, c, x, y, i;

    // For internal nodes, accumulate forces from child quadrants.
    if (quad.length) {
      for (x = y = i = 0; i < 4; ++i) {
        if ((q = quad[i]) && (c = q.value)) {
          strength += c, x += c * q.x, y += c * q.y;
        }
      }
      quad.x = x / strength;
      quad.y = y / strength;
    }

    // For leaf nodes, accumulate forces from coincident quadrants.
    else {
      q = quad;
      q.x = q.data.x;
      q.y = q.data.y;
      do strength += strengths[q.data.index];
      while (q = q.next);
    }

    quad.value = strength;
  }

  function apply(quad, x1, _, x2) {
    if (!quad.value) return true;

    var x = quad.x - node.x,
        y = quad.y - node.y,
        w = x2 - x1,
        l = x * x + y * y;

    // Apply the Barnes-Hut approximation if possible.
    // Limit forces for very close nodes; randomize direction if coincident.
    if (w * w / theta2 < l) {
      if (l < distanceMax2) {
        if (x === 0) x = jiggle(), l += x * x;
        if (y === 0) y = jiggle(), l += y * y;
        if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
        node.vx += x * quad.value * alpha / l;
        node.vy += y * quad.value * alpha / l;
      }
      return true;
    }

    // Otherwise, process points directly.
    else if (quad.length || l >= distanceMax2) return;

    // Limit forces for very close nodes; randomize direction if coincident.
    if (quad.data !== node || quad.next) {
      if (x === 0) x = jiggle(), l += x * x;
      if (y === 0) y = jiggle(), l += y * y;
      if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
    }

    do if (quad.data !== node) {
      w = strengths[quad.data.index] * alpha / l;
      node.vx += x * w;
      node.vy += y * w;
    } while (quad = quad.next);
  }

  force.initialize = function(_) {
    nodes = _;
    initialize();
  };

  force.strength = function(_) {
    return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength;
  };

  force.distanceMin = function(_) {
    return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2);
  };

  force.distanceMax = function(_) {
    return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2);
  };

  force.theta = function(_) {
    return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2);
  };

  return force;
}
<commit_msg>Correct weighted average in barnes-hut coordinates<commit_after>import constant from "./constant";
import jiggle from "./jiggle";
import {quadtree} from "d3-quadtree";
import {x, y} from "./simulation";

export default function() {
  var nodes,
      node,
      alpha,
      strength = constant(-30),
      strengths,
      distanceMin2 = 1,
      distanceMax2 = Infinity,
      theta2 = 0.81;

  function force(_) {
    var i, n = nodes.length, tree = quadtree(nodes, x, y).visitAfter(accumulate);
    for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply);
  }

  function initialize() {
    if (!nodes) return;
    var i, n = nodes.length, node;
    strengths = new Array(n);
    for (i = 0; i < n; ++i) node = nodes[i], strengths[node.index] = +strength(node, i, nodes);
  }

  function accumulate(quad) {
    var strength = 0, q, c, sumC = 0, x, y, i;

    // For internal nodes, accumulate forces from child quadrants.
    if (quad.length) {
      for (x = y = i = 0; i < 4; ++i) {
        if ((q = quad[i]) && (c = Math.abs(q.value))) {
          strength += q.value, sumC += c, x += c * q.x, y += c * q.y;
        }
      }
      quad.x = x / sumC;
      quad.y = y / sumC;
    }

    // For leaf nodes, accumulate forces from coincident quadrants.
    else {
      q = quad;
      q.x = q.data.x;
      q.y = q.data.y;
      do strength += strengths[q.data.index];
      while (q = q.next);
    }

    quad.value = strength;
  }

  function apply(quad, x1, _, x2) {
    if (!quad.value) return true;

    var x = quad.x - node.x,
        y = quad.y - node.y,
        w = x2 - x1,
        l = x * x + y * y;

    // Apply the Barnes-Hut approximation if possible.
    // Limit forces for very close nodes; randomize direction if coincident.
    if (w * w / theta2 < l) {
      if (l < distanceMax2) {
        if (x === 0) x = jiggle(), l += x * x;
        if (y === 0) y = jiggle(), l += y * y;
        if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
        node.vx += x * quad.value * alpha / l;
        node.vy += y * quad.value * alpha / l;
      }
      return true;
    }

    // Otherwise, process points directly.
    else if (quad.length || l >= distanceMax2) return;

    // Limit forces for very close nodes; randomize direction if coincident.
    if (quad.data !== node || quad.next) {
      if (x === 0) x = jiggle(), l += x * x;
      if (y === 0) y = jiggle(), l += y * y;
      if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
    }

    do if (quad.data !== node) {
      w = strengths[quad.data.index] * alpha / l;
      node.vx += x * w;
      node.vy += y * w;
    } while (quad = quad.next);
  }

  force.initialize = function(_) {
    nodes = _;
    initialize();
  };

  force.strength = function(_) {
    return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength;
  };

  force.distanceMin = function(_) {
    return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2);
  };

  force.distanceMax = function(_) {
    return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2);
  };

  force.theta = function(_) {
    return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2);
  };

  return force;
}
<|endoftext|>


<commit_before>(function() {

//  ---------------------------------------------------------------------------------------------------------------  //
//  no.Model
//  ---------------------------------------------------------------------------------------------------------------  //

//  Базовый класс для моделей. Конструктор пустой, чтобы легче было наследоваться.
//  Вся инициализация делается в _init(), который вызывает фабрикой no.Model.create().
//
no.Model = function() {};

//  ---------------------------------------------------------------------------------------------------------------  //

//  Добавляем методы из no.Events: on(), off(), trigger().
no.extend(no.Model.prototype, no.Events);

//  ---------------------------------------------------------------------------------------------------------------  //

var _ctors = {};
var _infos = {};

var _cache = {};

var _keySuffix = 0;

//  ---------------------------------------------------------------------------------------------------------------  //

/**
 * Статус модели "Ошибка".
 * Данные загрузились с ошибкой.
 * @constant
 * @type {String}
 */
no.Model.prototype.STATUS_ERROR = 'error';

/**
 * Статус модели "Нет данных".
 * Данные еще не загружались.
 * @constant
 * @type {String}
 */
no.Model.prototype.STATUS_NONE = 'none';

/**
 * Статус модели "Все хорошо".
 * Данные загрузились успешно.
 * @constant
 * @type {String}
 */
no.Model.prototype.STATUS_OK = 'ok';

/**
 * Статус модели "Не валиден".
 * Данные есть, но кто-то пометил их невалидными.
 * @constant
 * @type {String}
 */
no.Model.prototype.STATUS_INVALID = 'invalid';

no.Model.prototype._init = function(id, params, data) {
    this.id = id;
    this.params = params;

    this._reset();
    this.setData(data);

    var info = this.info = _infos[id];

    this.key = no.Model.key(id, params, info);

    this.timestamp = 0;
};

no.Model.prototype._reset = function(status) {
    this.data = null;
    this.error = null;

    this.status = status || this.STATUS_NONE;
    this.retries = 0;
    this.requests = 0;

    this.timestamp = 0;
};

//  ---------------------------------------------------------------------------------------------------------------  //

//  Определяем новую модель.
//
//      //  Простая модель, без параметров.
//      no.Model.define('profile');
//
//      no.Model.define('album', {
//          params: {
//              //  Любое значение, кроме null расценивается как дефолтное значение этого параметра.
//              //  На самом деле, конечно, не любое -- смысл имеют только Number и String.
//              'author-login': null,
//              'album-id': null,
//
//              //  Этим двум параметрам заданы дефолтные значения.
//              'page': 0,
//              'pageSize': 20
//          }
//      });
//
no.Model.define = function(id, info, ctor) {
    info = info || {};
    if (info.methods) {
        //  Нужно унаследоваться от no.Model и добавить в прототип info.models.
        ctor = no.inherits(function() {}, no.Model, info.methods);
    } else {
        ctor = ctor || no.Model;
    }

    var params = info.params || (( info.params = {} ));

    info.pNames = no.object.keys(params);

    //  Для do-моделей отдельные правила кэширования и построения ключей.
    info.isDo = /^do-/.test(id);

    _infos[id] = info;
    _ctors[id] = ctor;

    //  Создаем пустой кэш для всех моделей с данным id.
    _cache[id] = {};
};

//  Фабрика для моделей. Создает инстанс нужного класса и инициализирует его.
no.Model.create = function(id, params, data)  {
    var model = no.Model.get(id, params);

    if (!model) {
        var ctor = _ctors[id];
        model = new ctor();
        model._init(id, params, data);

        no.Model.store(model);
    } else if (data) {
        //  Модель уже существует, а мы пытаемся создать такую же, но с непустой data.
        //  FIXME: Все же непонятно, что нужно делать.
        //  Может быть, нужно передавать { silent: true }?
        model.setData(data);
        /// throw Error('Model already exists');
    }

    return model;
};

//  ---------------------------------------------------------------------------------------------------------------  //

no.Model.info = function(id) {
    return _infos[id];
};

//  ---------------------------------------------------------------------------------------------------------------  //

no.Model.key = function(id, params, info) {
    info || ( info = _infos[id] );

    //  Для do-моделей ключ строим особым образом.
    if (info.isDo) {
        return 'do-' + _keySuffix++;
    }

    var defaults = info.params;
    var pNames = info.pNames;

    var key = 'model=' + id;

    for (var i = 0, l = pNames.length; i < l; i++) {
        var pName = pNames[i];

        var pValue = params[pName];
        //  Нельзя просто написать params[pName] || defaults[pName] --
        //  т.к. params[pName] может быть 0 или ''.
        pValue = (pValue === undefined) ? defaults[pName] : pValue;

        if (pValue != null) {
            key += '&' + pName + '=' + pValue;
        }
    }

    return key;
};

//  ---------------------------------------------------------------------------------------------------------------  //

//  Инвалидируем все модели с заданным id,
//  удовлетворяющие фильтру filter (функция, принимающая
//  параметром модель и возвращающая boolean).
no.Model.invalidate = function(id, filter) {
    var models = _cache[id];

    for (var key in models) {
        var model = models[key];
        if ( filter(model) ) {
            model.invalidate();
        }
    }
};

no.Model.prototype.invalidate = function() {
    this._reset(this.STATUS_INVALID);
};

no.Model.prototype.isValid = function() {
    return (this.status === this.STATUS_OK);
};

//  ---------------------------------------------------------------------------------------------------------------  //

//  Возвращает данные, находящиеся по пути path.
//
//      var foo = model.get('foo'); // model.data.foo.
//      var bar = model.get('foo.bar'); // model.data.foo.bar (если foo существует).
//
no.Model.prototype.get = function(path) {
    var data = this.data;
    if (data) {
        return no.path(path, data);
    }
};

//  Сохраняет value по пути path.
//
//  Возможные флаги, которые могут быть в options:
//
//      {
//          silent: true        //  Не генерить событие о том, что модель изменилась,
//      }
//
no.Model.prototype.set = function(path, value, options) {
    var data = this.data;
    if (!data) { return; }

    //  Сохраняем новое значение и одновременно получаем старое значение.
    var oldValue = no.path(path, data, value);

    if ( !( (options && options.silent) || no.object.isEqual(value, oldValue) ) ) {
        //  FIXME: Может быть отправлять старое/новое значение?
        this.trigger('changed.' + path);
    }
};

//  ---------------------------------------------------------------------------------------------------------------  //

no.Model.prototype.getData = function() {
    return this.data;
};

//  Заменяет данные модели на data.
//
//  При этом по-дефолту на модели генерится событие 'changed'.
//  Это поведение можно поменять, передав объект options:
//
//      {
//          silent: true        //  Не генерить событие о том, что модель изменилась,
//      }
//
no.Model.prototype.setData = function(data, options) {
    if (data) {
        var old = this.data;
        this.data = this.preprocessData(data);
        this.error = null;
        this.status = this.STATUS_OK;

        //  Не проверяем здесь, действительно ли data отличается от oldData --
        //  setData должен вызываться только когда обновленная модель целиком перезапрошена.
        //  Можно считать, что она в этом случае всегда меняется.
        if ( old != null && !(options && options.silent) ) {
            this.trigger('changed');
        }

        this.touch();
    }

};

no.Model.prototype.getError = function() {
    return this.error;
};

no.Model.prototype.setError = function(error) {
    this.data = null;
    this.error = error;
    this.status = this.STATUS_ERROR;
};

no.Model.prototype.preprocessData = function(data) {
    return data;
};

//  ---------------------------------------------------------------------------------------------------------------  //

//  FIXME: Этот код сильно пересекается с вычислением ключа.
//  Нельзя ли избавиться от копипаста?
no.Model.prototype.getRequestParams = function() {
    var params = this.params;

    var defaults = this.info.params;
    var reqParams = {};

    for (var pName in defaults) {
        var pValue = params[pName];

        pValue = (pValue === undefined) ? defaults[pName] : pValue;
        if (pValue != null) {
            reqParams[pName] = pValue;
        }
    }

    return reqParams;
};

//  ---------------------------------------------------------------------------------------------------------------  //

//  Работа с кэшем.

/**
 * Возвращает модель из кеша.
 * @param {String} id Название модели.
 * @param {String|Object} key Ключ(string) или параметры(object) модели.
 * @return {no.Model}
 */
no.Model.get = function(id, key) {
    key = (typeof key === 'string') ? key : no.Model.key(id, key);

    return _cache[id][key];
};

//  Сохраняем модель в кэше.
no.Model.store = function(model) {
    if ( model.isDo() ) {
        return;
    }

    var id = model.id;
    var key = model.key;

    var cached = _cache[id][key];
    if (!cached) {
        _cache[id][key] = model;
    } else {
        //  NOTE: Почему тут нельзя просто заменить старую модель на новую.
        //  Потому, что в этом случае все, кто был подписан на события от старой модели
        //  не смогут переподписаться на новую модель.
        cached.data = model.data;
    }
};

//  Проверяем, есть ли модель в кэше и валидна ли она.
no.Model.isValid = function(id, key) {
    var model = no.Model.get(id, key);
    if (!model) { return; } // undefined означает, что кэша нет вообще, а false -- что он инвалидный.

    return model.isValid();
};

//  ---------------------------------------------------------------------------------------------------------------  //

//  Возвращает, можно ли перезапрашивать эту модель, если предыдущий запрос не удался.
no.Model.prototype.canRetry = function(error) {
    //  do-модели нельзя перезапрашивать.
    return ( !this.isDo() && this.retries < 3 );
};

//  ---------------------------------------------------------------------------------------------------------------  //

no.Model.prototype.extractData = function(result) {
    if (result) {
        return result.result;
    }
};

no.Model.prototype.extractError = function(result) {
    if (result) {
        return result.error;
    }
};

//  ---------------------------------------------------------------------------------------------------------------  //

no.Model.prototype.isDo = function() {
    return this.info.isDo;
};

//  ---------------------------------------------------------------------------------------------------------------  //

no.Model.prototype.touch = function() {
    this.timestamp = +new Date();
};

//  ---------------------------------------------------------------------------------------------------------------  //

/**
 * Подготавливает модель к запросу.
 * @param {Number} requestID ID запроса.
 * @return {no.Model}
 */
no.Model.prototype.prepareRequest = function(requestID) {
    this.requestID = requestID;
    this.retries++;
    this.promise = new no.Promise();

    return this;
};

})();

<commit_msg>no.object.keys -> Object.keys<commit_after>(function() {

//  ---------------------------------------------------------------------------------------------------------------  //
//  no.Model
//  ---------------------------------------------------------------------------------------------------------------  //

//  Базовый класс для моделей. Конструктор пустой, чтобы легче было наследоваться.
//  Вся инициализация делается в _init(), который вызывает фабрикой no.Model.create().
//
no.Model = function() {};

//  ---------------------------------------------------------------------------------------------------------------  //

//  Добавляем методы из no.Events: on(), off(), trigger().
no.extend(no.Model.prototype, no.Events);

//  ---------------------------------------------------------------------------------------------------------------  //

var _ctors = {};
var _infos = {};

var _cache = {};

var _keySuffix = 0;

//  ---------------------------------------------------------------------------------------------------------------  //

/**
 * Статус модели "Ошибка".
 * Данные загрузились с ошибкой.
 * @constant
 * @type {String}
 */
no.Model.prototype.STATUS_ERROR = 'error';

/**
 * Статус модели "Нет данных".
 * Данные еще не загружались.
 * @constant
 * @type {String}
 */
no.Model.prototype.STATUS_NONE = 'none';

/**
 * Статус модели "Все хорошо".
 * Данные загрузились успешно.
 * @constant
 * @type {String}
 */
no.Model.prototype.STATUS_OK = 'ok';

/**
 * Статус модели "Не валиден".
 * Данные есть, но кто-то пометил их невалидными.
 * @constant
 * @type {String}
 */
no.Model.prototype.STATUS_INVALID = 'invalid';

no.Model.prototype._init = function(id, params, data) {
    this.id = id;
    this.params = params;

    this._reset();
    this.setData(data);

    var info = this.info = _infos[id];

    this.key = no.Model.key(id, params, info);

    this.timestamp = 0;
};

no.Model.prototype._reset = function(status) {
    this.data = null;
    this.error = null;

    this.status = status || this.STATUS_NONE;
    this.retries = 0;
    this.requests = 0;

    this.timestamp = 0;
};

//  ---------------------------------------------------------------------------------------------------------------  //

//  Определяем новую модель.
//
//      //  Простая модель, без параметров.
//      no.Model.define('profile');
//
//      no.Model.define('album', {
//          params: {
//              //  Любое значение, кроме null расценивается как дефолтное значение этого параметра.
//              //  На самом деле, конечно, не любое -- смысл имеют только Number и String.
//              'author-login': null,
//              'album-id': null,
//
//              //  Этим двум параметрам заданы дефолтные значения.
//              'page': 0,
//              'pageSize': 20
//          }
//      });
//
no.Model.define = function(id, info, ctor) {
    info = info || {};
    if (info.methods) {
        //  Нужно унаследоваться от no.Model и добавить в прототип info.models.
        ctor = no.inherits(function() {}, no.Model, info.methods);
    } else {
        ctor = ctor || no.Model;
    }

    var params = info.params || (( info.params = {} ));

    info.pNames = Object.keys(params);

    //  Для do-моделей отдельные правила кэширования и построения ключей.
    info.isDo = /^do-/.test(id);

    _infos[id] = info;
    _ctors[id] = ctor;

    //  Создаем пустой кэш для всех моделей с данным id.
    _cache[id] = {};
};

//  Фабрика для моделей. Создает инстанс нужного класса и инициализирует его.
no.Model.create = function(id, params, data)  {
    var model = no.Model.get(id, params);

    if (!model) {
        var ctor = _ctors[id];
        model = new ctor();
        model._init(id, params, data);

        no.Model.store(model);
    } else if (data) {
        //  Модель уже существует, а мы пытаемся создать такую же, но с непустой data.
        //  FIXME: Все же непонятно, что нужно делать.
        //  Может быть, нужно передавать { silent: true }?
        model.setData(data);
        /// throw Error('Model already exists');
    }

    return model;
};

//  ---------------------------------------------------------------------------------------------------------------  //

no.Model.info = function(id) {
    return _infos[id];
};

//  ---------------------------------------------------------------------------------------------------------------  //

no.Model.key = function(id, params, info) {
    info || ( info = _infos[id] );

    //  Для do-моделей ключ строим особым образом.
    if (info.isDo) {
        return 'do-' + _keySuffix++;
    }

    var defaults = info.params;
    var pNames = info.pNames;

    var key = 'model=' + id;

    for (var i = 0, l = pNames.length; i < l; i++) {
        var pName = pNames[i];

        var pValue = params[pName];
        //  Нельзя просто написать params[pName] || defaults[pName] --
        //  т.к. params[pName] может быть 0 или ''.
        pValue = (pValue === undefined) ? defaults[pName] : pValue;

        if (pValue != null) {
            key += '&' + pName + '=' + pValue;
        }
    }

    return key;
};

//  ---------------------------------------------------------------------------------------------------------------  //

//  Инвалидируем все модели с заданным id,
//  удовлетворяющие фильтру filter (функция, принимающая
//  параметром модель и возвращающая boolean).
no.Model.invalidate = function(id, filter) {
    var models = _cache[id];

    for (var key in models) {
        var model = models[key];
        if ( filter(model) ) {
            model.invalidate();
        }
    }
};

no.Model.prototype.invalidate = function() {
    this._reset(this.STATUS_INVALID);
};

no.Model.prototype.isValid = function() {
    return (this.status === this.STATUS_OK);
};

//  ---------------------------------------------------------------------------------------------------------------  //

//  Возвращает данные, находящиеся по пути path.
//
//      var foo = model.get('foo'); // model.data.foo.
//      var bar = model.get('foo.bar'); // model.data.foo.bar (если foo существует).
//
no.Model.prototype.get = function(path) {
    var data = this.data;
    if (data) {
        return no.path(path, data);
    }
};

//  Сохраняет value по пути path.
//
//  Возможные флаги, которые могут быть в options:
//
//      {
//          silent: true        //  Не генерить событие о том, что модель изменилась,
//      }
//
no.Model.prototype.set = function(path, value, options) {
    var data = this.data;
    if (!data) { return; }

    //  Сохраняем новое значение и одновременно получаем старое значение.
    var oldValue = no.path(path, data, value);

    if ( !( (options && options.silent) || no.object.isEqual(value, oldValue) ) ) {
        //  FIXME: Может быть отправлять старое/новое значение?
        this.trigger('changed.' + path);
    }
};

//  ---------------------------------------------------------------------------------------------------------------  //

no.Model.prototype.getData = function() {
    return this.data;
};

//  Заменяет данные модели на data.
//
//  При этом по-дефолту на модели генерится событие 'changed'.
//  Это поведение можно поменять, передав объект options:
//
//      {
//          silent: true        //  Не генерить событие о том, что модель изменилась,
//      }
//
no.Model.prototype.setData = function(data, options) {
    if (data) {
        var old = this.data;
        this.data = this.preprocessData(data);
        this.error = null;
        this.status = this.STATUS_OK;

        //  Не проверяем здесь, действительно ли data отличается от oldData --
        //  setData должен вызываться только когда обновленная модель целиком перезапрошена.
        //  Можно считать, что она в этом случае всегда меняется.
        if ( old != null && !(options && options.silent) ) {
            this.trigger('changed');
        }

        this.touch();
    }

};

no.Model.prototype.getError = function() {
    return this.error;
};

no.Model.prototype.setError = function(error) {
    this.data = null;
    this.error = error;
    this.status = this.STATUS_ERROR;
};

no.Model.prototype.preprocessData = function(data) {
    return data;
};

//  ---------------------------------------------------------------------------------------------------------------  //

//  FIXME: Этот код сильно пересекается с вычислением ключа.
//  Нельзя ли избавиться от копипаста?
no.Model.prototype.getRequestParams = function() {
    var params = this.params;

    var defaults = this.info.params;
    var reqParams = {};

    for (var pName in defaults) {
        var pValue = params[pName];

        pValue = (pValue === undefined) ? defaults[pName] : pValue;
        if (pValue != null) {
            reqParams[pName] = pValue;
        }
    }

    return reqParams;
};

//  ---------------------------------------------------------------------------------------------------------------  //

//  Работа с кэшем.

/**
 * Возвращает модель из кеша.
 * @param {String} id Название модели.
 * @param {String|Object} key Ключ(string) или параметры(object) модели.
 * @return {no.Model}
 */
no.Model.get = function(id, key) {
    key = (typeof key === 'string') ? key : no.Model.key(id, key);

    return _cache[id][key];
};

//  Сохраняем модель в кэше.
no.Model.store = function(model) {
    if ( model.isDo() ) {
        return;
    }

    var id = model.id;
    var key = model.key;

    var cached = _cache[id][key];
    if (!cached) {
        _cache[id][key] = model;
    } else {
        //  NOTE: Почему тут нельзя просто заменить старую модель на новую.
        //  Потому, что в этом случае все, кто был подписан на события от старой модели
        //  не смогут переподписаться на новую модель.
        cached.data = model.data;
    }
};

//  Проверяем, есть ли модель в кэше и валидна ли она.
no.Model.isValid = function(id, key) {
    var model = no.Model.get(id, key);
    if (!model) { return; } // undefined означает, что кэша нет вообще, а false -- что он инвалидный.

    return model.isValid();
};

//  ---------------------------------------------------------------------------------------------------------------  //

//  Возвращает, можно ли перезапрашивать эту модель, если предыдущий запрос не удался.
no.Model.prototype.canRetry = function(error) {
    //  do-модели нельзя перезапрашивать.
    return ( !this.isDo() && this.retries < 3 );
};

//  ---------------------------------------------------------------------------------------------------------------  //

no.Model.prototype.extractData = function(result) {
    if (result) {
        return result.result;
    }
};

no.Model.prototype.extractError = function(result) {
    if (result) {
        return result.error;
    }
};

//  ---------------------------------------------------------------------------------------------------------------  //

no.Model.prototype.isDo = function() {
    return this.info.isDo;
};

//  ---------------------------------------------------------------------------------------------------------------  //

no.Model.prototype.touch = function() {
    this.timestamp = +new Date();
};

//  ---------------------------------------------------------------------------------------------------------------  //

/**
 * Подготавливает модель к запросу.
 * @param {Number} requestID ID запроса.
 * @return {no.Model}
 */
no.Model.prototype.prepareRequest = function(requestID) {
    this.requestID = requestID;
    this.retries++;
    this.promise = new no.Promise();

    return this;
};

})();

<|endoftext|>


<commit_before>'use strict';

const OracleDB = require('oracledb');
const Promise = require('bluebird');

exports.getConnection = function (options) {
    return new Promise(function (resolve, reject) {
        OracleDB.getConnection(options, function (err, conn) {
            if (err) return reject(err);
            resolve(new Connection(conn));
        });
    });
};

class Connection {
    constructor(conn) {
        this._conn = conn;
    }

    execute(query) {
        return new Promise((resolve, reject) => {
            this._conn.execute(query, {}, {
                outFormat: OracleDB.OBJECT,
                resultSet: true
            }, function (err, result) {
                if (err) return reject(err);
                resolve(new ResultSet(result.resultSet));
            });
        });
    }

    release() {
        return new Promise((resolve, reject) => {
            this._conn.release(function (err) {
                if (err) return reject(err);
                resolve();
            });
        });
    }
}

class ResultSet {
    constructor(resultSet) {
        this._resultSet = resultSet;
    }

    close() {
        return new Promise((resolve, reject) => {
            this._resultSet.close(function (err) {
                if (err) return reject(err);
                resolve();
            });
        });
    }

    getRow() {
        return new Promise((resolve, reject) => {
            this._resultSet.getRow(function (err, row) {
                if (err) return reject(err);
                resolve(row);
            });
        });
    }

    getRows(rows) {
        return new Promise((resolve, reject) => {
            this._resultSet.getRows(rows, function (err, rows) {
                if (err) return reject(err);
                resolve(rows);
            });
        });
    }
}
<commit_msg>Update oracledb.js<commit_after>'use strict';

const OracleDB = require('oracledb');
const Promise = require('bluebird');

global.oracledb = module.exports;

exports.getConnection = function (options) {
    return new Promise(function (resolve, reject) {
        OracleDB.getConnection(options, function (err, conn) {
            if (err) return reject(err);
            resolve(new Connection(conn));
        });
    });
};

class Connection {
    constructor(conn) {
        this._conn = conn;
    }

    execute(query) {
        return new Promise((resolve, reject) => {
            this._conn.execute(query, {}, {
                outFormat: OracleDB.OBJECT,
                resultSet: true
            }, function (err, result) {
                if (err) return reject(err);
                resolve(new ResultSet(result.resultSet));
            });
        });
    }

    release() {
        return new Promise((resolve, reject) => {
            this._conn.release(function (err) {
                if (err) return reject(err);
                resolve();
            });
        });
    }
}

class ResultSet {
    constructor(resultSet) {
        this._resultSet = resultSet;
    }

    close() {
        return new Promise((resolve, reject) => {
            this._resultSet.close(function (err) {
                if (err) return reject(err);
                resolve();
            });
        });
    }

    getRow() {
        return new Promise((resolve, reject) => {
            this._resultSet.getRow(function (err, row) {
                if (err) return reject(err);
                resolve(row);
            });
        });
    }

    getRows(rows) {
        return new Promise((resolve, reject) => {
            this._resultSet.getRows(rows, function (err, rows) {
                if (err) return reject(err);
                resolve(rows);
            });
        });
    }
}
<|endoftext|>


<commit_before>define([
  'globals',
  'helpers',
  'plumbing'
], function(globals, helpers, plumbing) {
  /**
   * @ngdoc overview
   * @name pedigree
   * @description
   * Get someone's ancestry or descendancy
   *
   * {@link https://familysearch.org/developers/docs/api/resources#pedigree FamilySearch API Docs}
   */
  var maybe = helpers.maybe; // shorthand

  var exports = {};

  /**
   * Generate ancestry or descendancy convenience functions
   *
   * @param numberLabel ascendancyNumber or descendancyNumber
   * @returns {{getPersons: Function, exists: Function, getPerson: Function}}
   */
  function pedigreeConvenienceFunctionGenerator(numberLabel) {
    return {
      getPersons:    function()    { return this.persons; },
      exists:        function(num) { return !!maybe(helpers.find(this.persons, matchPersonNum(numberLabel, num))).id; },
      getPerson:     function(num) { return helpers.find(this.persons, matchPersonNum(numberLabel, num)); }
    };
  }

  function matchPersonNum(numberLabel, num) {
    return function(p) {
      /*jshint eqeqeq:false */
      return p.display[numberLabel] == num; // == so users can pass in either numbers or strings for ascendancy numbers
    };
  }

  /**
   * @ngdoc function
   * @name pedigree.functions:getAncestry
   * @function
   *
   * @description
   * Get the ancestors of a specified person and optionally a specified spouse with the following convenience functions
   *
   * - `getPersons()` - return an array of {@link person.types:constructor.Person Persons}
   * - `getPerson(ascendancyNumber)` - return a {@link person.types:constructor.Person Person}
   * - `exists(ascendancyNumber)` - return true if a person with ascendancy number exists
   * - `getDescendant(descendancyNumber)` - return a {@link person.types:constructor.Person Person} if the descendants parameter is true
   * - `existsDescendant(ascendancyNumber)` - return true if a person with descendancy number exists if the descendants parameter is true
   *
   * ### Notes
   *
   * * Each Person object has an additional `$getAscendancyNumber()` function that returns the person's ascendancy number,
   * and if the descendants parameter is true, a $getDescendancyNumber() function that returns the person's descendancy number
   * * Some information on the Person objects is available only if `params` includes `personDetails`
   * * If `params` includes `marriageDetails`, then `person.display` includes `marriageDate` and `marriagePlace`.
   *
   * {@link https://familysearch.org/developers/docs/api/tree/Ancestry_resource FamilySearch API Docs}
   *
   * {@link http://jsfiddle.net/DallanQ/gt726/ editable example}
   *
   * @param {string} pid id of the person
   * @param {Object=} params includes `generations` to retrieve (max 8),
   * `spouse` id to get ancestry of person and spouse,
   * `personDetails` set to true to retrieve full person objects for each ancestor,
   * `descendants` set to true to retrieve one generation of descendants
   * @param {Object=} opts options to pass to the http function specified during init
   * @return {Object} promise for the ancestry
   */
  exports.getAncestry = function(pid, params, opts) {
    return helpers.chainHttpPromises(
      plumbing.getUrl('ancestry-query'),
      function(url) {
        return plumbing.get(url, helpers.extend({'person': pid}, params), {}, opts,
          helpers.compose(
            helpers.objectExtender(pedigreeConvenienceFunctionGenerator('ascendancyNumber')),
            !!params.descendants ? helpers.objectExtender({
              getDescendant:    function(num) { return helpers.find(this.persons, matchPersonNum('descendancyNumber', num)); },
              existsDescendant: function(num) { return !!maybe(helpers.find(this.persons, matchPersonNum('descendancyNumber', num))).id; }
            }) : null,
            globals.personMapper(),
            helpers.objectExtender({$getAscendancyNumber: function() { return this.display.ascendancyNumber; }}, function(response) {
              return maybe(response).persons;
            }),
            !!params.descendants ? helpers.objectExtender({$getDescendancyNumber: function() { return this.display.descendancyNumber; }}, function(response) {
              return maybe(response).persons;
            }) : null
          ));
      });
  };

  /**
   * @ngdoc function
   * @name pedigree.functions:getDescendancy
   * @function
   *
   * @description
   * Get the descendants of a specified person and optionally a specified spouse with the following convenience functions
   * (similar convenience functions as getAncestry)
   *
   * - `getPersons()` - return an array of {@link person.types:constructor.Person Persons}
   * - `getPerson(descendancyNumber)` - return a {@link person.types:constructor.Person Person}
   * - `exists(descendancyNumber)` - return true if a person with ascendancy number exists
   *
   * ### Notes
   *
   * * Each Person object has an additional `$getDescendancyNumber()` function that returns the person's descendancy number.
   * * Some information on the Person objects is available only if `params` includes `personDetails`
   * * If `params` includes `marriageDetails`, then `person.display` includes `marriageDate` and `marriagePlace`.
   *
   * {@link https://familysearch.org/developers/docs/api/tree/Descendancy_resource FamilySearch API Docs}
   *
   * {@link http://jsfiddle.net/DallanQ/eBNGk/ editable example}
   *
   * @param {string} pid id of the person
   * @param {Object=} params includes
   * `generations` to retrieve max 2,
   * `spouse` id to get descendency of person and spouse,
   * `marriageDetails` set to true to provide marriage details, and
   * `personDetails` set to true to provide person details.
   * @param {Object=} opts options to pass to the http function specified during init
   * @return {Object} promise for the descendancy
   */
  exports.getDescendancy = function(pid, params, opts) {
    return helpers.chainHttpPromises(
      plumbing.getUrl('descendancy-query'),
      function(url) {
        return plumbing.get(url, helpers.extend({'person': pid}, params), {}, opts,
          helpers.compose(
            helpers.objectExtender(pedigreeConvenienceFunctionGenerator('descendancyNumber')),
            globals.personMapper(),
            helpers.objectExtender({$getDescendancyNumber: function() { return this.display.descendancyNumber; }}, function(response) {
              return maybe(response).persons;
            })
          ));
      });
  };

  return exports;
});<commit_msg>make unit tests pass<commit_after>define([
  'globals',
  'helpers',
  'plumbing'
], function(globals, helpers, plumbing) {
  /**
   * @ngdoc overview
   * @name pedigree
   * @description
   * Get someone's ancestry or descendancy
   *
   * {@link https://familysearch.org/developers/docs/api/resources#pedigree FamilySearch API Docs}
   */
  var maybe = helpers.maybe; // shorthand

  var exports = {};

  /**
   * Generate ancestry or descendancy convenience functions
   *
   * @param numberLabel ascendancyNumber or descendancyNumber
   * @returns {{getPersons: Function, exists: Function, getPerson: Function}}
   */
  function pedigreeConvenienceFunctionGenerator(numberLabel) {
    return {
      getPersons:    function()    { return this.persons; },
      exists:        function(num) { return !!maybe(helpers.find(this.persons, matchPersonNum(numberLabel, num))).id; },
      getPerson:     function(num) { return helpers.find(this.persons, matchPersonNum(numberLabel, num)); }
    };
  }

  function matchPersonNum(numberLabel, num) {
    return function(p) {
      /*jshint eqeqeq:false */
      return p.display[numberLabel] == num; // == so users can pass in either numbers or strings for ascendancy numbers
    };
  }

  /**
   * @ngdoc function
   * @name pedigree.functions:getAncestry
   * @function
   *
   * @description
   * Get the ancestors of a specified person and optionally a specified spouse with the following convenience functions
   *
   * - `getPersons()` - return an array of {@link person.types:constructor.Person Persons}
   * - `getPerson(ascendancyNumber)` - return a {@link person.types:constructor.Person Person}
   * - `exists(ascendancyNumber)` - return true if a person with ascendancy number exists
   * - `getDescendant(descendancyNumber)` - return a {@link person.types:constructor.Person Person} if the descendants parameter is true
   * - `existsDescendant(ascendancyNumber)` - return true if a person with descendancy number exists if the descendants parameter is true
   *
   * ### Notes
   *
   * * Each Person object has an additional `$getAscendancyNumber()` function that returns the person's ascendancy number,
   * and if the descendants parameter is true, a $getDescendancyNumber() function that returns the person's descendancy number
   * * Some information on the Person objects is available only if `params` includes `personDetails`
   * * If `params` includes `marriageDetails`, then `person.display` includes `marriageDate` and `marriagePlace`.
   *
   * {@link https://familysearch.org/developers/docs/api/tree/Ancestry_resource FamilySearch API Docs}
   *
   * {@link http://jsfiddle.net/DallanQ/gt726/ editable example}
   *
   * @param {string} pid id of the person
   * @param {Object=} params includes `generations` to retrieve (max 8),
   * `spouse` id to get ancestry of person and spouse,
   * `personDetails` set to true to retrieve full person objects for each ancestor,
   * `descendants` set to true to retrieve one generation of descendants
   * @param {Object=} opts options to pass to the http function specified during init
   * @return {Object} promise for the ancestry
   */
  exports.getAncestry = function(pid, params, opts) {
    return helpers.chainHttpPromises(
      plumbing.getUrl('ancestry-query'),
      function(url) {
        return plumbing.get(url, helpers.extend({'person': pid}, params), {}, opts,
          helpers.compose(
            helpers.objectExtender(pedigreeConvenienceFunctionGenerator('ascendancyNumber')),
            !!params && !!params.descendants ? helpers.objectExtender({
              getDescendant:    function(num) { return helpers.find(this.persons, matchPersonNum('descendancyNumber', num)); },
              existsDescendant: function(num) { return !!maybe(helpers.find(this.persons, matchPersonNum('descendancyNumber', num))).id; }
            }) : null,
            globals.personMapper(),
            helpers.objectExtender({$getAscendancyNumber: function() { return this.display.ascendancyNumber; }}, function(response) {
              return maybe(response).persons;
            }),
            !!params && !!params.descendants ? helpers.objectExtender({$getDescendancyNumber: function() { return this.display.descendancyNumber; }}, function(response) {
              return maybe(response).persons;
            }) : null
          ));
      });
  };

  /**
   * @ngdoc function
   * @name pedigree.functions:getDescendancy
   * @function
   *
   * @description
   * Get the descendants of a specified person and optionally a specified spouse with the following convenience functions
   * (similar convenience functions as getAncestry)
   *
   * - `getPersons()` - return an array of {@link person.types:constructor.Person Persons}
   * - `getPerson(descendancyNumber)` - return a {@link person.types:constructor.Person Person}
   * - `exists(descendancyNumber)` - return true if a person with ascendancy number exists
   *
   * ### Notes
   *
   * * Each Person object has an additional `$getDescendancyNumber()` function that returns the person's descendancy number.
   * * Some information on the Person objects is available only if `params` includes `personDetails`
   * * If `params` includes `marriageDetails`, then `person.display` includes `marriageDate` and `marriagePlace`.
   *
   * {@link https://familysearch.org/developers/docs/api/tree/Descendancy_resource FamilySearch API Docs}
   *
   * {@link http://jsfiddle.net/DallanQ/eBNGk/ editable example}
   *
   * @param {string} pid id of the person
   * @param {Object=} params includes
   * `generations` to retrieve max 2,
   * `spouse` id to get descendency of person and spouse,
   * `marriageDetails` set to true to provide marriage details, and
   * `personDetails` set to true to provide person details.
   * @param {Object=} opts options to pass to the http function specified during init
   * @return {Object} promise for the descendancy
   */
  exports.getDescendancy = function(pid, params, opts) {
    return helpers.chainHttpPromises(
      plumbing.getUrl('descendancy-query'),
      function(url) {
        return plumbing.get(url, helpers.extend({'person': pid}, params), {}, opts,
          helpers.compose(
            helpers.objectExtender(pedigreeConvenienceFunctionGenerator('descendancyNumber')),
            globals.personMapper(),
            helpers.objectExtender({$getDescendancyNumber: function() { return this.display.descendancyNumber; }}, function(response) {
              return maybe(response).persons;
            })
          ));
      });
  };

  return exports;
});<|endoftext|>


<commit_before>// @flow
//
import eventDispatcher from './utils/dispatch-event';
import { cancelEvent, getTouches, detectDoubleTap, calcScale } from './utils/handle-event';
import scaleElement from './utils/handle-element';
import { isWithin, calcNewScale, addOffset, getInitialScale, getScaleFactor, getZoomFactor, getTouchCenter } from './utils/handle-pinch';
import { drag, sanitizeOffset } from './utils/handle-drag';
import defaults from './defaults';

const first = (items: Array<Object>) => items[0];

const pinchIt = (targets: string | Object, options: Object = {}) => {
  // private variable cache
  let element = null;

  let scaling;
  let lastScale = 1;
  let startTouches;

  let zoomFactor = 1;

  let offset = { x: 0, y: 0 };
  let lastZoomCenter = false;
  let lastDragPosition = false;

  // Base configuration for the pinch instance
  const opts = {...defaults, ...options};
  const { on, dispatch } = eventDispatcher();

 /**
  *  dispatchPinchEvent - Shorthand method for creating events
  *
  *  @param { String } phase
  *  @param { String } type
  *  @param { Object } details
  *  @return { Void }
  **/
  const dispatchPinchEvent = (eventName: string, phase: string, data: Object = {}): void => {
    dispatch(eventName, Object.assign(data, {
      phase
    }));
  };

  const resetGlobals = (/* opts */): void => {
    scaling = undefined;
    lastScale = 1;
    startTouches = null;
    zoomFactor = 1;
    lastZoomCenter = false;

    lastDragPosition = false;
    offset = { x: 0, y: 0 };
  };

  // event handling
  /**
   * Set scaling if we are using more then one finger
   * and captures our first punch point
   *
   * private
   * @param { Object } e the event from our eventlistener
   */
  const onTouchstart = (e: TouchEvent) => {
    dispatchPinchEvent('touchstart', 'before', e);

    scaling = (e.touches.length === 2);
    startTouches = Array.from(e.touches);
    lastScale = 1;

    if (detectDoubleTap(e)) {
      const image = e.currentTarget.querySelector('img');
      scaleElement(e.target, image, 1, { x: 0, y: 0 }, opts.snapBackSpeed, opts.ease);
      resetGlobals();
    }

    dispatchPinchEvent('touchstart', 'after', e);
  };

  const onTouchmove = (e: TouchEvent) => {
    dispatchPinchEvent('touchmove', 'before', e);

    if ((!scaling || !startTouches) && zoomFactor > 1) {
      cancelEvent(e);

      const touch = first(getTouches(e.currentTarget, Array.from(e.touches)));
      const dragOffset = drag(touch, lastDragPosition, offset, zoomFactor);

      offset = sanitizeOffset(e.target, dragOffset, zoomFactor);
      lastDragPosition = touch;
    } else if (scaling && startTouches) {
      cancelEvent(e);

      // a relative scale factor is used
      const touchCenter = getTouchCenter(getTouches(e.currentTarget, Array.from(e.touches)));
      const newScale = calcScale(e.currentTarget, startTouches, Array.from(e.touches));
      const scaleValue = calcNewScale(newScale, lastScale);

      const scale = getScaleFactor(scaleValue, zoomFactor, opts);
      zoomFactor = getZoomFactor(scaleValue, zoomFactor, opts);

      offset = addOffset(offset, {
        x: (scale - 1) * (touchCenter.x + offset.x),
        y: (scale - 1) * (touchCenter.y + offset.y)
      });

      lastScale = newScale;
      offset = drag(touchCenter, lastZoomCenter, offset, zoomFactor);
      lastZoomCenter = touchCenter;
    }

    const image = e.currentTarget.querySelector('img');
    scaleElement(e.target, image, zoomFactor, offset, 0, opts.ease);

    dispatchPinchEvent('touchmove', 'after', e);
  };

  const onTouchend = (e: TouchEvent) => {
    dispatchPinchEvent('touchend', 'before', e);

    lastDragPosition = false;
    lastZoomCenter = false;
    lastScale = 1;
    if (zoomFactor) {
      if (!isWithin(zoomFactor, opts)) {
        const image = e.currentTarget.querySelector('img');
        const isLessThan = (getInitialScale(e.target, image) * zoomFactor < opts.minScale);
        zoomFactor = isLessThan ? opts.minScale : opts.maxScale;
        offset = sanitizeOffset(e.target, offset, zoomFactor);
        scaleElement(e.target, image, zoomFactor, offset, opts.snapBackSpeed, opts.ease);
      }
    }

    dispatchPinchEvent('touchend', 'after', e);
  };

  const attachEvents = (el: HTMLElement) => {
    el.addEventListener('touchstart', onTouchstart);
    el.addEventListener('touchmove', onTouchmove);
    el.addEventListener('touchend', onTouchend);
  };

  const detachhEvents = (el: Object) => {
    el.removeEventListener('touchstart', onTouchstart);
    el.removeEventListener('touchmove', onTouchmove);
    el.removeEventListener('touchend', onTouchend);
  };

  /**
   * public
   * reset function:
   * @param { Number } duration
   * @param { String } easing
   * @return { Void }
   */
  const reset = (): void => {
    if (!element) return;
    const { snapBackSpeed, easing } = opts;
    scaleElement(element, 1, { x: 0, y: 0 }, snapBackSpeed, easing);
    resetGlobals();
  };

  /**
   * public
   * destroy function: called to gracefully destroy the lory instance
   * @return { Void }
   */
  const destroy = (): void => {
    dispatchPinchEvent('destroy', 'before', {});
    if (!element) return;
    reset();
    // remove event listeners
    detachhEvents(element);
    element = null;
    resetGlobals();
    dispatchPinchEvent('destroy', 'after', {});
  };

  /**
   * setup - Init function
   *
   * @param { String, Object }
   * @return { Void }
   **/
  const setup = (target: string | Object): void => {
    if (element) destroy();
    dispatchPinchEvent('init', 'before', {});
    // resolve target
    // pinchit allows for both a node or a string to be passed
    switch (typeof target) {
      case 'object':
        element = target;
        break;
      case 'string':
        element = document.querySelector(target);
        break;
      default:
        element = null;
        console.warn('missing target, either pass an node or a string');
    }

    if (element) {
      console.log(element);
      attachEvents(element);
    }

    dispatchPinchEvent('init', 'after', {});
  };

  // trigger initial setup
  setup(targets);

  return {
    setup,
    reset,
    destroy,
    element,
    on,
  };
};

export default pinchIt;
<commit_msg>updated reset to target inner iamge<commit_after>// @flow
//
import eventDispatcher from './utils/dispatch-event';
import { cancelEvent, getTouches, detectDoubleTap, calcScale } from './utils/handle-event';
import scaleElement from './utils/handle-element';
import { isWithin, calcNewScale, addOffset, getInitialScale, getScaleFactor, getZoomFactor, getTouchCenter } from './utils/handle-pinch';
import { drag, sanitizeOffset } from './utils/handle-drag';
import defaults from './defaults';

const first = (items: Array<Object>) => items[0];

const pinchIt = (targets: string | Object, options: Object = {}) => {
  // private variable cache
  let element = null;

  let scaling;
  let lastScale = 1;
  let startTouches;

  let zoomFactor = 1;

  let offset = { x: 0, y: 0 };
  let lastZoomCenter = false;
  let lastDragPosition = false;

  // Base configuration for the pinch instance
  const opts = {...defaults, ...options};
  const { on, dispatch } = eventDispatcher();

 /**
  *  dispatchPinchEvent - Shorthand method for creating events
  *
  *  @param { String } phase
  *  @param { String } type
  *  @param { Object } details
  *  @return { Void }
  **/
  const dispatchPinchEvent = (eventName: string, phase: string, data: Object = {}): void => {
    dispatch(eventName, Object.assign(data, {
      phase
    }));
  };

  const resetGlobals = (/* opts */): void => {
    scaling = undefined;
    lastScale = 1;
    startTouches = null;
    zoomFactor = 1;
    lastZoomCenter = false;

    lastDragPosition = false;
    offset = { x: 0, y: 0 };
  };

  // event handling
  /**
   * Set scaling if we are using more then one finger
   * and captures our first punch point
   *
   * private
   * @param { Object } e the event from our eventlistener
   */
  const onTouchstart = (e: TouchEvent) => {
    dispatchPinchEvent('touchstart', 'before', e);

    scaling = (e.touches.length === 2);
    startTouches = Array.from(e.touches);
    lastScale = 1;

    if (detectDoubleTap(e)) {
      const image = e.currentTarget.querySelector('img');
      scaleElement(e.target, image, 1, { x: 0, y: 0 }, opts.snapBackSpeed, opts.ease);
      resetGlobals();
    }

    dispatchPinchEvent('touchstart', 'after', e);
  };

  const onTouchmove = (e: TouchEvent) => {
    dispatchPinchEvent('touchmove', 'before', e);

    if ((!scaling || !startTouches) && zoomFactor > 1) {
      cancelEvent(e);

      const touch = first(getTouches(e.currentTarget, Array.from(e.touches)));
      const dragOffset = drag(touch, lastDragPosition, offset, zoomFactor);

      offset = sanitizeOffset(e.target, dragOffset, zoomFactor);
      lastDragPosition = touch;
    } else if (scaling && startTouches) {
      cancelEvent(e);

      // a relative scale factor is used
      const touchCenter = getTouchCenter(getTouches(e.currentTarget, Array.from(e.touches)));
      const newScale = calcScale(e.currentTarget, startTouches, Array.from(e.touches));
      const scaleValue = calcNewScale(newScale, lastScale);

      const scale = getScaleFactor(scaleValue, zoomFactor, opts);
      zoomFactor = getZoomFactor(scaleValue, zoomFactor, opts);

      offset = addOffset(offset, {
        x: (scale - 1) * (touchCenter.x + offset.x),
        y: (scale - 1) * (touchCenter.y + offset.y)
      });

      lastScale = newScale;
      offset = drag(touchCenter, lastZoomCenter, offset, zoomFactor);
      lastZoomCenter = touchCenter;
    }

    const image = e.currentTarget.querySelector('img');
    scaleElement(e.target, image, zoomFactor, offset, 0, opts.ease);

    dispatchPinchEvent('touchmove', 'after', e);
  };

  const onTouchend = (e: TouchEvent) => {
    dispatchPinchEvent('touchend', 'before', e);

    lastDragPosition = false;
    lastZoomCenter = false;
    lastScale = 1;
    if (zoomFactor) {
      if (!isWithin(zoomFactor, opts)) {
        const image = e.currentTarget.querySelector('img');
        const isLessThan = (getInitialScale(e.target, image) * zoomFactor < opts.minScale);
        zoomFactor = isLessThan ? opts.minScale : opts.maxScale;
        offset = sanitizeOffset(e.target, offset, zoomFactor);
        scaleElement(e.target, image, zoomFactor, offset, opts.snapBackSpeed, opts.ease);
      }
    }

    dispatchPinchEvent('touchend', 'after', e);
  };

  const attachEvents = (el: HTMLElement) => {
    el.addEventListener('touchstart', onTouchstart);
    el.addEventListener('touchmove', onTouchmove);
    el.addEventListener('touchend', onTouchend);
  };

  const detachhEvents = (el: Object) => {
    el.removeEventListener('touchstart', onTouchstart);
    el.removeEventListener('touchmove', onTouchmove);
    el.removeEventListener('touchend', onTouchend);
  };

  /**
   * public
   * reset function:
   * @param { Number } duration
   * @param { String } easing
   * @return { Void }
   */
  const reset = (): void => {
    if (!element) return;
    const { snapBackSpeed, easing } = opts;
    console.log('reset?');
    const image = element.querySelector('img');
    console.log(image);
    scaleElement(element, image, 1, { x: 0, y: 0 }, snapBackSpeed, easing);
    resetGlobals();
  };

  /**
   * public
   * destroy function: called to gracefully destroy the lory instance
   * @return { Void }
   */
  const destroy = (): void => {
    dispatchPinchEvent('destroy', 'before', {});
    if (!element) return;
    reset();
    // remove event listeners
    detachhEvents(element);
    element = null;
    resetGlobals();
    dispatchPinchEvent('destroy', 'after', {});
  };

  /**
   * setup - Init function
   *
   * @param { String, Object }
   * @return { Void }
   **/
  const setup = (target: string | Object): void => {
    if (element) destroy();
    dispatchPinchEvent('init', 'before', {});
    // resolve target
    // pinchit allows for both a node or a string to be passed
    switch (typeof target) {
      case 'object':
        element = target;
        break;
      case 'string':
        element = document.querySelector(target);
        break;
      default:
        element = null;
        console.warn('missing target, either pass an node or a string');
    }

    if (element) {
      console.log(element);
      attachEvents(element);
    }

    dispatchPinchEvent('init', 'after', {});
  };

  // trigger initial setup
  setup(targets);

  return {
    setup,
    reset,
    destroy,
    element,
    on,
  };
};

export default pinchIt;
<|endoftext|>


<commit_before>(function (root, factory) {

    'use strict';

    if (typeof define === 'function' && define.amd) {
        // AMD environment
        define('notify', [], function () {
            return factory(root, document);
        });
    } else {
        // Browser environment
        root.Notify = factory(root, document);
    }

}(this, function (w, d) {

    'use strict';

    function Notify(title, options) {

        this.title = typeof title === 'string' ? title : null;

        this.options = {
            icon: '',
            body: '',
            tag: '',
            notifyShow: null,
            notifyClose: null,
            notifyClick: null,
            notifyError: null,
            permissionGranted: null,
            permissionDenied: null
        };

        this.permission = null;

        if (!this.isSupported()) {
            return;
        }

        if (!this.title) {
            throw new Error('Notify(): first arg (title) must be a string.');
        }

        //User defined options for notification content
        if (typeof options === 'object') {

            for (var i in options) {
                if (options.hasOwnProperty(i)) {
                    this.options[i] = options[i];
                }
            }

            //callback when notification is displayed
            if (typeof this.options.notifyShow === 'function') {
                this.onShowCallback = this.options.notifyShow;
            }

            //callback when notification is closed
            if (typeof this.options.notifyClose === 'function') {
                this.onCloseCallback = this.options.notifyClose;
            }

            //callback when notification is clicked
            if (typeof this.options.notifyClick === 'function') {
                this.onClickCallback = this.options.notifyClick;
            }

            //callback when notification throws error
            if (typeof this.options.notifyError === 'function') {
                this.onErrorCallback = this.options.notifyError;
            }

            //callback user grants permission for notification
            if (typeof this.options.permissionGranted === 'function') {
                this.onPermissionGrantedCallback = this.options.permissionGranted;
            }

            //callback user denies permission for notification
            if (typeof this.options.permissionDenied === 'function') {
                this.onPermissionDeniedCallback = this.options.permissionDenied;
            }
        }
    }

    // return true if the browser supports HTML5 Notification
    Notify.isSupported = function () {
        if ('Notification' in w) {
            return true;
        }
        return false;
    };

    // returns true if the permission is not granted
    Notify.needsPermission = function () {
        if (Notify.isSupported() && Notification.permission === 'granted') {
            return false;
        }
        return true;
    };

    // asks the user for permission to display notifications.  Then calls the callback functions is supplied.
    Notify.requestPermission = function (onPermissionGrantedCallback, onPermissionDeniedCallback) {
        if (Notify.isSupported()) {
            w.Notification.requestPermission(function (perm) {
                switch (perm) {
                    case 'granted':
                        if (typeof onPermissionGrantedCallback === 'function') {
                            onPermissionGrantedCallback();
                        }
                        break;
                    case 'denied':
                        if (typeof onPermissionDeniedCallback === 'function') {
                            onPermissionDeniedCallback();
                        }
                        break;
                }
            });
        }
    };

    Notify.prototype.needsPermission = function () {
        if ('Notification' in w && Notification.permission === 'granted') {
            return false;
        }
        return true;
    };

    Notify.prototype.requestPermission = function () {
        var that = this;
        w.Notification.requestPermission(function (perm) {
            that.permission = perm;
            switch (that.permission) {
            case 'granted':
                that.onPermissionGranted();
                break;
            case 'denied':
                that.onPermissionDenied();
                break;
            }
        });
    };

    Notify.prototype.show = function () {

        if (!this.isSupported()) {
            return;
        }

        this.myNotify = new Notification(this.title, {
            'body': this.options.body,
            'tag' : this.options.tag,
            'icon' : this.options.icon
        });

        this.myNotify.addEventListener('show', this, false);
        this.myNotify.addEventListener('error', this, false);
        this.myNotify.addEventListener('close', this, false);
        this.myNotify.addEventListener('click', this, false);
    };

    Notify.prototype.onShowNotification = function (e) {
        if (this.onShowCallback) {
            this.onShowCallback(e);
        }
    };

    Notify.prototype.onCloseNotification = function () {
        if (this.onCloseCallback) {
            this.onCloseCallback();
        }
        this.destroy();
    };

    Notify.prototype.onClickNotification = function () {
        if (this.onClickCallback) {
            this.onClickCallback();
        }
    };

    Notify.prototype.onErrorNotification = function () {
        if (this.onErrorCallback) {
            this.onErrorCallback();
        }
        this.destroy();
    };

    Notify.prototype.onPermissionGranted = function () {
        if (this.onPermissionGrantedCallback) {
            this.onPermissionGrantedCallback();
        }
    };

    Notify.prototype.onPermissionDenied = function () {
        if (this.onPermissionDeniedCallback) {
            this.onPermissionDeniedCallback();
        }
    };

    Notify.prototype.destroy = function () {
        this.myNotify.removeEventListener('show', this, false);
        this.myNotify.removeEventListener('error', this, false);
        this.myNotify.removeEventListener('close', this, false);
        this.myNotify.removeEventListener('click', this, false);
    };

    Notify.prototype.isSupported = function () {
        if ('Notification' in w) {
            return true;
        }
        return false;
    };

    Notify.prototype.handleEvent = function (e) {
        switch (e.type) {
        case 'show':
            this.onShowNotification(e);
            break;
        case 'close':
            this.onCloseNotification(e);
            break;
        case 'click':
            this.onClickNotification(e);
            break;
        case 'error':
            this.onErrorNotification(e);
            break;
        }
    };

    return Notify;

}));
<commit_msg>Remove instance version of isSupported(), needsPermission(), requestPermission(). Note: This is a breaking change!<commit_after>(function (root, factory) {

    'use strict';

    if (typeof define === 'function' && define.amd) {
        // AMD environment
        define('notify', [], function () {
            return factory(root, document);
        });
    } else {
        // Browser environment
        root.Notify = factory(root, document);
    }

}(this, function (w, d) {

    'use strict';

    function Notify(title, options) {

        this.title = typeof title === 'string' ? title : null;

        this.options = {
            icon: '',
            body: '',
            tag: '',
            notifyShow: null,
            notifyClose: null,
            notifyClick: null,
            notifyError: null,
            permissionGranted: null,
            permissionDenied: null
        };

        this.permission = null;

        if (!Notify.isSupported()) {
            return;
        }

        if (!this.title) {
            throw new Error('Notify(): first arg (title) must be a string.');
        }

        //User defined options for notification content
        if (typeof options === 'object') {

            for (var i in options) {
                if (options.hasOwnProperty(i)) {
                    this.options[i] = options[i];
                }
            }

            //callback when notification is displayed
            if (typeof this.options.notifyShow === 'function') {
                this.onShowCallback = this.options.notifyShow;
            }

            //callback when notification is closed
            if (typeof this.options.notifyClose === 'function') {
                this.onCloseCallback = this.options.notifyClose;
            }

            //callback when notification is clicked
            if (typeof this.options.notifyClick === 'function') {
                this.onClickCallback = this.options.notifyClick;
            }

            //callback when notification throws error
            if (typeof this.options.notifyError === 'function') {
                this.onErrorCallback = this.options.notifyError;
            }

            //callback user grants permission for notification
            if (typeof this.options.permissionGranted === 'function') {
                this.onPermissionGrantedCallback = this.options.permissionGranted;
            }

            //callback user denies permission for notification
            if (typeof this.options.permissionDenied === 'function') {
                this.onPermissionDeniedCallback = this.options.permissionDenied;
            }
        }
    }

    // return true if the browser supports HTML5 Notification
    Notify.isSupported = function () {
        if ('Notification' in w) {
            return true;
        }
        return false;
    };

    // returns true if the permission is not granted
    Notify.needsPermission = function () {
        if (Notify.isSupported() && Notification.permission === 'granted') {
            return false;
        }
        return true;
    };

    // asks the user for permission to display notifications.  Then calls the callback functions is supplied.
    Notify.requestPermission = function (onPermissionGrantedCallback, onPermissionDeniedCallback) {
        if (Notify.isSupported()) {
            w.Notification.requestPermission(function (perm) {
                switch (perm) {
                    case 'granted':
                        if (typeof onPermissionGrantedCallback === 'function') {
                            onPermissionGrantedCallback();
                        }
                        break;
                    case 'denied':
                        if (typeof onPermissionDeniedCallback === 'function') {
                            onPermissionDeniedCallback();
                        }
                        break;
                }
            });
        }
    };

    Notify.prototype.show = function () {

        if (!Notify.isSupported()) {
            return;
        }

        this.myNotify = new Notification(this.title, {
            'body': this.options.body,
            'tag' : this.options.tag,
            'icon' : this.options.icon
        });

        this.myNotify.addEventListener('show', this, false);
        this.myNotify.addEventListener('error', this, false);
        this.myNotify.addEventListener('close', this, false);
        this.myNotify.addEventListener('click', this, false);
    };

    Notify.prototype.onShowNotification = function (e) {
        if (this.onShowCallback) {
            this.onShowCallback(e);
        }
    };

    Notify.prototype.onCloseNotification = function () {
        if (this.onCloseCallback) {
            this.onCloseCallback();
        }
        this.destroy();
    };

    Notify.prototype.onClickNotification = function () {
        if (this.onClickCallback) {
            this.onClickCallback();
        }
    };

    Notify.prototype.onErrorNotification = function () {
        if (this.onErrorCallback) {
            this.onErrorCallback();
        }
        this.destroy();
    };

    Notify.prototype.onPermissionGranted = function () {
        if (this.onPermissionGrantedCallback) {
            this.onPermissionGrantedCallback();
        }
    };

    Notify.prototype.onPermissionDenied = function () {
        if (this.onPermissionDeniedCallback) {
            this.onPermissionDeniedCallback();
        }
    };

    Notify.prototype.destroy = function () {
        this.myNotify.removeEventListener('show', this, false);
        this.myNotify.removeEventListener('error', this, false);
        this.myNotify.removeEventListener('close', this, false);
        this.myNotify.removeEventListener('click', this, false);
    };

    Notify.prototype.handleEvent = function (e) {
        switch (e.type) {
        case 'show':
            this.onShowNotification(e);
            break;
        case 'close':
            this.onCloseNotification(e);
            break;
        case 'click':
            this.onClickNotification(e);
            break;
        case 'error':
            this.onErrorNotification(e);
            break;
        }
    };

    return Notify;

}));
<|endoftext|>


<commit_before>'use strict';

exports.commands = {
	test: function (target, room, user) {
		if (!this.can('forcewin')) return false;
		this.parse('/afk');
		this.parse('/back');
		this.parse('/wallet');
		this.parse('/atm ' + user.name);
		this.parse('/atm asdlkasdjalkdas');
		this.parse(`/givemoney ${user.name}, 5`);
		this.parse(`/takemoney ${user.name}, 5`);
		this.parse('/resetmoney bob118');
		this.parse('/transfermoney bob118, 10.0');
		this.parse('/transfermoney bob118, hoe');
		this.parse('/transfermoney bob118, -10');
		this.parse('/transfermoney bob118, 0.1');
		this.parse('/transfermoney bob118, 1.1');
		this.parse('/transfermoney bob118293829328392839829382938298329, 1.1');
		this.parse('/transfermoney bob118, 2');
		this.parse('/takebucks bob118, 2');
		this.parse(`/givemoney ${user.name}, 2`);
		this.parse('/shop');
		this.parse(`/givemoney ${user.name}, 5`);
		this.parse('/buy symbol');
		this.parse('/customsymbol @');
		this.parse('/customsymbol ^');
		this.parse('/resetsymbol');
		this.parse('/moneylog');
		this.parse('/moneyladder');
		this.parse(`/givemoney ${user.name}, 5`);
		this.parse('/dicegame 5');
		this.parse('/endgame');
		this.parse(`/takemoney ${user.name}, 5`);
		this.parse('/bucks');
	},
};<commit_msg>Command-Tests: Fix /test crash with new shop and dice code<commit_after>'use strict';

exports.commands = {
	test: function (target, room, user) {
		if (!this.can('forcewin')) return false;
		this.parse('/afk');
		this.parse('/back');
		this.parse('/wallet');
		this.parse('/atm ' + user.name);
		this.parse('/atm asdlkasdjalkdas');
		this.parse(`/givemoney ${user.name}, 5`);
		this.parse(`/takemoney ${user.name}, 5`);
		this.parse('/resetmoney bob118');
		this.parse('/transfermoney bob118, 10.0');
		this.parse('/transfermoney bob118, hoe');
		this.parse('/transfermoney bob118, -10');
		this.parse('/transfermoney bob118, 0.1');
		this.parse('/transfermoney bob118, 1.1');
		this.parse('/transfermoney bob118293829328392839829382938298329, 1.1');
		this.parse('/transfermoney bob118, 2');
		this.parse('/takebucks bob118, 2');
		this.parse(`/givemoney ${user.name}, 2`);
		this.parse('/shop');
		this.parse(`/givemoney ${user.name}, 5`);
		this.parse('/shop buy customsymbol');
		this.parse('/customsymbol @');
		this.parse('/customsymbol ^');
		this.parse('/resetsymbol');
		this.parse('/moneylog');
		this.parse('/moneyladder');
		this.parse(`/givemoney ${user.name}, 5`);
		this.parse('/dicegame 5');
		this.parse('/endddice');
		this.parse(`/takemoney ${user.name}, 5`);
		this.parse('/bucks');
	},
};
<|endoftext|>


<commit_before>/*
	Porthole: Activate an element when it is in the viewport.
	Give an element a data-scroll-activate attribute and it'll get a "inviewport" class when in the viewport, as well as an "inviewport" event triggered on it.
	Elements that also have a data-scroll-deactivate attribute will lose the class when they leave the viewport, and they'll get a "outviewport" event
*/
(function($){

	var queue = [];
	var listening;
	var deActivateSelector = "[data-scroll-deactivate]";
	var toleranceSelector = "data-scroll-activetolerance";
	var activeClass = "inviewport";
	var viewportSize;
	var options = {
		removeClass: false, //remove class when out of viewport? default false
		activeTolerance: 0 // adjust the active window that is considered to be "in the viewport". Positive values make the window larger (good for prefetching images). Negative Values make it smaller (good for cueing animations)
	};

	// polyfill raf if needed
	var raf = (function(){
		return  window.requestAnimationFrame       ||
			window.webkitRequestAnimationFrame ||
			window.mozRequestAnimationFrame    ||
			function( callback ){
				window.setTimeout(callback, 1000 / 60);
			};
	})();

	var getViewportSize = function(){
		if( !viewportSize ){
			var test = document.createElement( "div" );
			test.style.cssText = "position: fixed;top: 0;left: 0;bottom: 0;right: 0;";
			document.documentElement.insertBefore( test, document.documentElement.firstChild );
			viewportSize = { width: test.offsetWidth, height: test.offsetHeight };
			document.documentElement.removeChild( test );
		}
		return viewportSize;
	};

	$( window ).bind( "resize", function(){
		viewportSize = null;
	});

	var checkActivateElems = function(){
		var viewportHeight = getViewportSize().height;
		$( queue ).each(function(){
			var isActive = $( this ).is( "." + activeClass );
			var thisTop = this.getBoundingClientRect().top;
			var thisBottom = thisTop + this.offsetHeight;
			var tolerance = 0;
			var toleranceAttr = $( this ).attr( toleranceSelector );
			if( toleranceAttr ){
				var tolVal = parseFloat( toleranceAttr );
				if( !isNaN( tolVal ) ){
					tolerance = tolVal;
				}
			}
			var thisOptions = $.extend( options, {
				removeClass: $( this ).is( deActivateSelector ) || false,
				activeTolerance: tolerance
			});

			if( thisOptions.activeTolerance !== 0 ){
				thisTop += thisOptions.activeTolerance;
			}

			if( thisTop  >= 0 && thisTop <= viewportHeight ||
				thisTop <= 0 && thisBottom >= viewportHeight ||
				thisBottom >= 0 && thisBottom  <= viewportHeight ){
				if( !isActive ){
					$( this )
						.addClass( activeClass )
						.trigger( "inviewport" );
				}
			}
			else if( isActive && thisOptions.removeClass === true ){
				$( this )
					.removeClass( activeClass )
					.trigger( "outviewport" );
			}
		});
	};

	var listen = function(){
		raf( checkActivateElems );
		listening = true;
		$( window ).bind( "scroll resize porthole", function(){
			raf( checkActivateElems );
		} );
	};

	$.fn.porthole = function(){
		return this.each(function(){
			queue.push( this );
			if( !listening ){
				listen();
			}
		});
	};

}(jQuery));
<commit_msg>offer a pseudo-element opt-out for declaring an element hidden if it'd otherwise fail the detection of whether it's in the viewport<commit_after>/*
	Porthole: Activate an element when it is in the viewport.
	Give an element a data-scroll-activate attribute and it'll get a "inviewport" class when in the viewport, as well as an "inviewport" event triggered on it.
	Elements that also have a data-scroll-deactivate attribute will lose the class when they leave the viewport, and they'll get a "outviewport" event
*/
(function($){

	var queue = [];
	var listening;
	var deActivateSelector = "[data-scroll-deactivate]";
	var toleranceSelector = "data-scroll-activetolerance";
	var activeClass = "inviewport";
	var viewportSize;
	var options = {
		removeClass: false, //remove class when out of viewport? default false
		activeTolerance: 0 // adjust the active window that is considered to be "in the viewport". Positive values make the window larger (good for prefetching images). Negative Values make it smaller (good for cueing animations)
	};

	// polyfill raf if needed
	var raf = (function(){
		return  window.requestAnimationFrame       ||
			window.webkitRequestAnimationFrame ||
			window.mozRequestAnimationFrame    ||
			function( callback ){
				window.setTimeout(callback, 1000 / 60);
			};
	})();

	var getViewportSize = function(){
		if( !viewportSize ){
			var test = document.createElement( "div" );
			test.style.cssText = "position: fixed;top: 0;left: 0;bottom: 0;right: 0;";
			document.documentElement.insertBefore( test, document.documentElement.firstChild );
			viewportSize = { width: test.offsetWidth, height: test.offsetHeight };
			document.documentElement.removeChild( test );
		}
		return viewportSize;
	};

	$( window ).bind( "resize", function(){
		viewportSize = null;
	});

	var checkActivateElems = function(){
		var viewportHeight = getViewportSize().height;
		$( queue ).each(function(){
			var beforeContent = window.getComputedStyle( this, ":before" ).content;
			var isActive = $( this ).is( "." + activeClass );
			var thisTop = this.getBoundingClientRect().top;
			var thisBottom = thisTop + this.offsetHeight;
			var tolerance = 0;
			var toleranceAttr = $( this ).attr( toleranceSelector );
			if( toleranceAttr ){
				var tolVal = parseFloat( toleranceAttr );
				if( !isNaN( tolVal ) ){
					tolerance = tolVal;
				}
			}
			var thisOptions = $.extend( options, {
				removeClass: $( this ).is( deActivateSelector ) || false,
				activeTolerance: tolerance
			});

			if( thisOptions.activeTolerance !== 0 ){
				thisTop += thisOptions.activeTolerance;
			}
			if( beforeContent !== "hidden" &&
			( thisTop  >= 0 && thisTop <= viewportHeight ||
				thisTop <= 0 && thisBottom >= viewportHeight ||
				thisBottom >= 0 && thisBottom  <= viewportHeight )
			 ){
				if( !isActive ){
					$( this )
						.addClass( activeClass )
						.trigger( "inviewport" );
				}
			}
			else if( isActive && thisOptions.removeClass === true ){
				$( this )
					.removeClass( activeClass )
					.trigger( "outviewport" );
			}
		});
	};

	var listen = function(){
		raf( checkActivateElems );
		listening = true;
		$( window ).bind( "scroll resize porthole", function(){
			raf( checkActivateElems );
		} );
	};

	$.fn.porthole = function(){
		return this.each(function(){
			queue.push( this );
			if( !listening ){
				listen();
			}
		});
	};

}(jQuery));
<|endoftext|>