<commit_before>var iconv = require('iconv-lite');
var net = require('net');
var util = require('./index');
var logger = require('./logger');
var config = require('../config');

if (!(config.reqCacheSize > 0) || config.reqCacheSize < 600) {
  config.reqCacheSize = 600;
}

if (!(config.frameCacheSize > 0) || config.frameCacheSize < 512) {
  config.frameCacheSize = 512;
}

var TIMEOUT = 60000;
var CLEAR_INTERVAL = 5000;
var CACHE_TIME = CLEAR_INTERVAL * 2;
var MAX_LENGTH = config.reqCacheSize;
var OVERFLOW_LENGTH = MAX_LENGTH * 3;
var MIN_LENGTH = MAX_LENGTH - 100;
var MAX_FRAMES_LENGTH = config.frameCacheSize;
var COUNT = 100;
var count = 0;
var ids = [];
var reqData = {};
var frames = [];
var proxy, binded, timeout, interval;

function disable() {
  proxy.removeListener('request', handleRequest);
  proxy.removeListener('frame', handleFrame);
  ids = [];
  reqData = {};
  frames = [];
  interval && clearInterval(interval);
  interval = null;
  binded = false;
}

function enable() {
  if (!binded) {
    binded = true;
    proxy.on('request', handleRequest);
    proxy.on('frame', handleFrame);
  }
  clearTimeout(timeout);
  timeout = setTimeout(disable, TIMEOUT);
  if (!interval) {
    interval = setInterval(clearCache, CLEAR_INTERVAL);
  }
}

/**
* 如果超过最大缓存数，清理如下请求数据：
* 1. 已经请求结束且结束时间超过10秒
* 2. 请求#1前面的未结束且未被ui读取过的请求
*/
function clearCache() {
  if (frames.length > MAX_FRAMES_LENGTH) {
    frames.splice(0, 100);
  }
  var len = ids.length;
  if (len <= MAX_LENGTH) {
    return;
  }

  var now = Date.now();
  var _ids = [];
  var overflow = len - OVERFLOW_LENGTH;
  if (overflow > 0) {
    overflow = overflow + MAX_LENGTH;
  }
  for (var i = 0; i < len; i++) {
    var id = ids[i];
    var curData = reqData[id];
    if (i > overflow &&
      (curData.endTime ? now - curData.endTime < CACHE_TIME : now - curData.startTime < TIMEOUT)) {
      _ids.push(id);
    } else {
      delete reqData[id];
      if (--len <= MIN_LENGTH) {
        ids = _ids.concat(ids.slice(i + 1));
        return;
      }
    }
  }
  ids = _ids;
}

function getIds(startTime, count, lastRowId) {
  startTime = startTime || lastRowId;
  if (!startTime) {
    return ids.slice(-count);
  }
  var index = 0;
  if (startTime !== '0') {
    index = ids.indexOf(startTime) + 1;
  }
  return ids.slice(index, index + count);
}

function getList(ids) {
  if (!Array.isArray(ids)) {
    return [];
  }
  return ids.map(function(id, i) {
    var curData = reqData[id];
    return curData;
  });
}

function handleRequest(req) {
  var curData = req.data;
  var id = curData.id = curData.id || (curData.startTime + '-' + ++count);
  reqData[id] = curData;
  ids.indexOf(id) === -1 && ids.push(id);
}

function decodeData(frame) {
  if (frame.text != null) {
    return frame;
  }
  if (frame.bin) {
    var result = [];
    frame.bin.forEach(function(b) {
      b = b.toString(16).toUpperCase();
      result.push(b.length > 1 ? b : '0' + b);
    });
    try {
      frame.text = iconv.decode(frame.bin, frame.charset || 'utf8');
    } catch (e) {
      frame.text = frame.bin + '';
    }
    frame.bin = result.join('');
  } else {
    frame.bin = frame.text = '';
  }

  return frame;
}
function handleFrame(data) {
  frames.push(data);
}

function getFrames(curReqId, lastFrameId) {
  if (!curReqId) {
    return;
  }
  var result = [];
  var count = 10;
  for (var i = frames.length - 1; i >= 0; i--) {
    var frame = frames[i];
    if (frame.reqId === curReqId && (lastFrameId ? frame.frameId > lastFrameId : count > 0)) {
      result.push(decodeData(frame));
      if (--count <= 0) {
        break;
      }
    }
  }
  return result.reverse();
}

module.exports = function init(_proxy) {
  proxy = _proxy;
  enable();
/**
* options: {
* 		startTime: timestamp || timestamp + '-' + count
* 		count: 获取新数据的数量
* 		ids: 请未结束的id列表
* }
*
* @param options
*/
  function formatFilter(filter, clientIp) {
    if (!filter.url && !filter.name && !filter.value && !filter.ip) {
      return;
    }
    var url = util.trimStr(filter.url).toLowerCase();
    var name = util.trimStr(filter.name).toLowerCase();
    var value = util.trimStr(filter.value).toLowerCase();
    var ip = util.trimStr(filter.ip);
    var list = [];
    if (ip === 'self') {
      ip = clientIp;
    } else if (ip && !net.isIP(ip)) {
      ip.split(',').forEach(function(item) {
        item = item.trim();
        if (item === 'self') {
          item = clientIp;
        }
        if (net.isIP(item) && list.indexOf(item) === -1) {
          list.push(item);
        }
      });
      ip = null;
    }
    var result;
    if (url) {
      result = {};
      result.url = url;
    }
    if (name && value) {
      result = result || {};
      result.name = name;
      result.value = value;
    }
    if (ip) {
      result = result || {};
      result.ip = ip;
    }
    if (list.length) {
      result = result || {};
      result.ipList = list.slice(0, 16);
    }
    return result;
  }
  function checkClientIp(item, filter) {
    var clientIp = item.req.ip;
    if (filter.ip && clientIp !== filter.ip) {
      return false;
    }
    var ipList = filter.ipList;
    if (!ipList) {
      return true;
    }
    var len = ipList.length;
    if (len < 3) {
      if (ipList[0] === clientIp) {
        return true;
      }
      if (ipList[1] && ipList[1] === clientIp) {
        return true;
      }
    } else {
      for (var i = 0; i < len; i++) {
        var ip = ipList[i];
        if (ip === clientIp) {
          return true;
        }
      }
    }
    return false;
  }
  function checkItem(item, filter) {
    if (!item) {
      return false;
    }
    if (!checkClientIp(item, filter)) {
      return false;
    }
    if (filter.url && item.url.toLowerCase().indexOf(filter.url) === -1) {
      return false;
    }
    if (!filter.name) {
      return true;
    }
    var value = item.req.headers[filter.name];
    if (!value || typeof value !== 'string') {
      if (!Array.isArray(value)) {
        return false;
      }
      value = value.join('\n');
    }
    value = value.toLowerCase();
    if (value.indexOf(filter.value) !== -1) {
      return true;
    }
    return value.indexOf(util.encodeURIComponent(filter.value).toLowerCase()) !== -1;
  }
  proxy.getLastDataId = function() {
    return ids[ids.length - 1];
  };
  proxy.getData = function(options, clientIp) {
    enable();
    options = options || {};
    var filter = formatFilter(options, clientIp);
    var data = {};
    var count = options.count;
    var startTime = options.startTime;
    var clearNetwork = count == 0 || startTime == -2;
    if (!clearNetwork) {
      count = count > 0 && count < COUNT ? +count : COUNT;
    }
    var newIds = (clearNetwork || startTime == -1) ? [] : getIds(startTime, count, options.lastRowId);
    var setData = function(item) {
      if (item) {
        if (config.secureFilter) {
          try {
            item = config.secureFilter(item, clientIp, filter) || item;
          } catch (e) {
            if (config.debugMode) {
              /* eslint-disable no-console */
              console.log(e);
            }
            logger.error(e);
          }
        }
        data[item.id] = item;
      }
    };
    if (newIds.length > 0) {
      if (filter) {
        var id = newIds[0];
        var index = ids.indexOf(newIds[0]);
        newIds = [];
        while(id && count > 0) {
          var item = reqData[id];
          if (checkItem(item, filter)) {
            setData(item);
            newIds.push(id);
            --count;
          }
          id = ids[++index];
        }
      } else if (!filter) {
        getList(newIds).forEach(setData);
      }
    }
    getList(options.ids).forEach(setData);
    var endId = ids[ids.length - 1];
    return {
      ids: options.ids || [],
      newIds: newIds,
      data: data,
      lastId: clearNetwork ? endId : newIds[newIds.length - 1],
      endId: endId,
      frames: getFrames(options.curReqId, options.lastFrameId)
    };
  };
};
<commit_msg>refactor: cache size<commit_after>var iconv = require('iconv-lite');
var net = require('net');
var util = require('./index');
var logger = require('./logger');
var config = require('../config');

if (!(config.reqCacheSize > 0) || config.reqCacheSize < 600) {
  config.reqCacheSize = 600;
}

if (!(config.frameCacheSize > 0) || config.frameCacheSize < 512) {
  config.frameCacheSize = 512;
}

var TIMEOUT = 36000;
var CLEAR_INTERVAL = 5000;
var CACHE_TIME = CLEAR_INTERVAL * 2;
var MAX_LENGTH = config.reqCacheSize;
var OVERFLOW_LENGTH = MAX_LENGTH * 3;
var MIN_LENGTH = MAX_LENGTH - 100;
var MAX_FRAMES_LENGTH = config.frameCacheSize;
var COUNT = 100;
var count = 0;
var ids = [];
var reqData = {};
var frames = [];
var proxy, binded, timeout, interval;

function disable() {
  proxy.removeListener('request', handleRequest);
  proxy.removeListener('frame', handleFrame);
  ids = [];
  reqData = {};
  frames = [];
  interval && clearInterval(interval);
  interval = null;
  binded = false;
}

function enable() {
  if (!binded) {
    binded = true;
    proxy.on('request', handleRequest);
    proxy.on('frame', handleFrame);
  }
  clearTimeout(timeout);
  timeout = setTimeout(disable, TIMEOUT);
  if (!interval) {
    interval = setInterval(clearCache, CLEAR_INTERVAL);
  }
}

/**
* 如果超过最大缓存数，清理如下请求数据：
* 1. 已经请求结束且结束时间超过10秒
* 2. 请求#1前面的未结束且未被ui读取过的请求
*/
function clearCache() {
  if (frames.length > MAX_FRAMES_LENGTH) {
    frames.splice(0, 100);
  }
  var len = ids.length;
  if (len <= MAX_LENGTH) {
    return;
  }

  var now = Date.now();
  var _ids = [];
  var overflow = len - OVERFLOW_LENGTH;
  if (overflow > 0) {
    overflow = overflow + MAX_LENGTH;
  }
  for (var i = 0; i < len; i++) {
    var id = ids[i];
    var curData = reqData[id];
    if (i > overflow &&
      (curData.endTime ? now - curData.endTime < CACHE_TIME : now - curData.startTime < TIMEOUT)) {
      _ids.push(id);
    } else {
      delete reqData[id];
      if (--len <= MIN_LENGTH) {
        ids = _ids.concat(ids.slice(i + 1));
        return;
      }
    }
  }
  ids = _ids;
}

function getIds(startTime, count, lastRowId) {
  startTime = startTime || lastRowId;
  if (!startTime) {
    return ids.slice(-count);
  }
  var index = 0;
  if (startTime !== '0') {
    index = ids.indexOf(startTime) + 1;
  }
  return ids.slice(index, index + count);
}

function getList(ids) {
  if (!Array.isArray(ids)) {
    return [];
  }
  return ids.map(function(id, i) {
    var curData = reqData[id];
    return curData;
  });
}

function handleRequest(req) {
  var curData = req.data;
  var id = curData.id = curData.id || (curData.startTime + '-' + ++count);
  reqData[id] = curData;
  ids.indexOf(id) === -1 && ids.push(id);
}

function decodeData(frame) {
  if (frame.text != null) {
    return frame;
  }
  if (frame.bin) {
    var result = [];
    frame.bin.forEach(function(b) {
      b = b.toString(16).toUpperCase();
      result.push(b.length > 1 ? b : '0' + b);
    });
    try {
      frame.text = iconv.decode(frame.bin, frame.charset || 'utf8');
    } catch (e) {
      frame.text = frame.bin + '';
    }
    frame.bin = result.join('');
  } else {
    frame.bin = frame.text = '';
  }

  return frame;
}
function handleFrame(data) {
  frames.push(data);
}

function getFrames(curReqId, lastFrameId) {
  if (!curReqId) {
    return;
  }
  var result = [];
  var count = 10;
  for (var i = frames.length - 1; i >= 0; i--) {
    var frame = frames[i];
    if (frame.reqId === curReqId && (lastFrameId ? frame.frameId > lastFrameId : count > 0)) {
      result.push(decodeData(frame));
      if (--count <= 0) {
        break;
      }
    }
  }
  return result.reverse();
}

module.exports = function init(_proxy) {
  proxy = _proxy;
  enable();
/**
* options: {
* 		startTime: timestamp || timestamp + '-' + count
* 		count: 获取新数据的数量
* 		ids: 请未结束的id列表
* }
*
* @param options
*/
  function formatFilter(filter, clientIp) {
    if (!filter.url && !filter.name && !filter.value && !filter.ip) {
      return;
    }
    var url = util.trimStr(filter.url).toLowerCase();
    var name = util.trimStr(filter.name).toLowerCase();
    var value = util.trimStr(filter.value).toLowerCase();
    var ip = util.trimStr(filter.ip);
    var list = [];
    if (ip === 'self') {
      ip = clientIp;
    } else if (ip && !net.isIP(ip)) {
      ip.split(',').forEach(function(item) {
        item = item.trim();
        if (item === 'self') {
          item = clientIp;
        }
        if (net.isIP(item) && list.indexOf(item) === -1) {
          list.push(item);
        }
      });
      ip = null;
    }
    var result;
    if (url) {
      result = {};
      result.url = url;
    }
    if (name && value) {
      result = result || {};
      result.name = name;
      result.value = value;
    }
    if (ip) {
      result = result || {};
      result.ip = ip;
    }
    if (list.length) {
      result = result || {};
      result.ipList = list.slice(0, 16);
    }
    return result;
  }
  function checkClientIp(item, filter) {
    var clientIp = item.req.ip;
    if (filter.ip && clientIp !== filter.ip) {
      return false;
    }
    var ipList = filter.ipList;
    if (!ipList) {
      return true;
    }
    var len = ipList.length;
    if (len < 3) {
      if (ipList[0] === clientIp) {
        return true;
      }
      if (ipList[1] && ipList[1] === clientIp) {
        return true;
      }
    } else {
      for (var i = 0; i < len; i++) {
        var ip = ipList[i];
        if (ip === clientIp) {
          return true;
        }
      }
    }
    return false;
  }
  function checkItem(item, filter) {
    if (!item) {
      return false;
    }
    if (!checkClientIp(item, filter)) {
      return false;
    }
    if (filter.url && item.url.toLowerCase().indexOf(filter.url) === -1) {
      return false;
    }
    if (!filter.name) {
      return true;
    }
    var value = item.req.headers[filter.name];
    if (!value || typeof value !== 'string') {
      if (!Array.isArray(value)) {
        return false;
      }
      value = value.join('\n');
    }
    value = value.toLowerCase();
    if (value.indexOf(filter.value) !== -1) {
      return true;
    }
    return value.indexOf(util.encodeURIComponent(filter.value).toLowerCase()) !== -1;
  }
  proxy.getLastDataId = function() {
    return ids[ids.length - 1];
  };
  proxy.getData = function(options, clientIp) {
    enable();
    options = options || {};
    var filter = formatFilter(options, clientIp);
    var data = {};
    var count = options.count;
    var startTime = options.startTime;
    var clearNetwork = count == 0 || startTime == -2;
    if (!clearNetwork) {
      count = count > 0 && count < COUNT ? +count : COUNT;
    }
    var newIds = (clearNetwork || startTime == -1) ? [] : getIds(startTime, count, options.lastRowId);
    var setData = function(item) {
      if (item) {
        if (config.secureFilter) {
          try {
            item = config.secureFilter(item, clientIp, filter) || item;
          } catch (e) {
            if (config.debugMode) {
              /* eslint-disable no-console */
              console.log(e);
            }
            logger.error(e);
          }
        }
        data[item.id] = item;
      }
    };
    if (newIds.length > 0) {
      if (filter) {
        var id = newIds[0];
        var index = ids.indexOf(newIds[0]);
        newIds = [];
        while(id && count > 0) {
          var item = reqData[id];
          if (checkItem(item, filter)) {
            setData(item);
            newIds.push(id);
            --count;
          }
          id = ids[++index];
        }
      } else if (!filter) {
        getList(newIds).forEach(setData);
      }
    }
    getList(options.ids).forEach(setData);
    var endId = ids[ids.length - 1];
    return {
      ids: options.ids || [],
      newIds: newIds,
      data: data,
      lastId: clearNetwork ? endId : newIds[newIds.length - 1],
      endId: endId,
      frames: getFrames(options.curReqId, options.lastFrameId)
    };
  };
};
<|endoftext|>


<commit_before>/*
 * Copyright 2013 The Polymer Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */

/*
 * Basic strategy: find the farthest apart points, use as diameter of circle
 * react to size change and rotation of the chord
 */

/**
 * @module PointerGestures
 * @submodule Events
 * @class pinch
 */
/**
 * Scale of the pinch zoom gesture
 * @property scale
 * @type Number
 */
/**
 * Center X position of pointers causing pinch
 * @property centerX
 * @type Number
 */
/**
 * Center Y position of pointers causing pinch
 * @property centerY
 * @type Number
 */

/**
 * @module PointerGestures
 * @submodule Events
 * @class rotate
 */
/**
 * Angle (in degrees) of rotation. Measured from starting positions of pointers.
 * @property angle
 * @type Number
 */
/**
 * Center X position of pointers causing rotation
 * @property centerX
 * @type Number
 */
/**
 * Center Y position of pointers causing rotation
 * @property centerY
 * @type Number
 */
(function(scope) {
  var dispatcher = scope.dispatcher;
  var pointermap = new scope.PointerMap();
  var RAD_TO_DEG = 180 / Math.PI;
  var pinch = {
    events: [
      'pointerdown',
      'pointermove',
      'pointerup',
      'pointercancel'
    ],
    reference: {},
    pointerdown: function(ev) {
      pointermap.set(ev.pointerId, ev);
      if (pointermap.pointers() == 2) {
        var points = this.calcChord();
        var angle = this.calcAngle(points);
        this.reference = {
          angle: angle,
          diameter: points.diameter,
          target: scope.findLCA(points.a.target, points.b.target)
        };
      }
    },
    pointerup: function(ev) {
      pointermap.delete(ev.pointerId);
    },
    pointermove: function(ev) {
      if (pointermap.has(ev.pointerId)) {
        pointermap.set(ev.pointerId, ev);
        if (pointermap.pointers() > 1) {
          this.calcPinchRotate();
        }
      }
    },
    pointercancel: function(ev) {
      this.pointerup(ev);
    },
    dispatchPinch: function(diameter, points) {
      var zoom = diameter / this.reference.diameter;
      var ev = dispatcher.makeEvent('pinch', {
        scale: zoom,
        centerX: points.center.x,
        centerY: points.center.y
      });
      dispatcher.dispatchEvent(ev, this.reference.target);
    },
    dispatchRotate: function(angle, points) {
      var diff = Math.round((angle - this.reference.angle) % 360);
      var ev = dispatcher.makeEvent('rotate', {
        angle: diff,
        centerX: points.center.x,
        centerY: points.center.y
      });
      dispatcher.dispatchEvent(ev, this.reference.target);
    },
    calcPinchRotate: function() {
      var points = this.calcChord();
      var diameter = points.diameter;
      var angle = this.calcAngle(points);
      if (diameter != this.reference.diameter) {
        this.dispatchPinch(diameter, points);
      }
      if (angle != this.reference.angle) {
        this.dispatchRotate(angle, points);
      }
    },
    calcChord: function() {
      var pointers = [];
      pointermap.forEach(function(p) {
        pointers.push(p);
      });
      var dist = 0;
      var points = {};
      var x, y, d;
      for (var i = 0; i < pointers.length; i++) {
        var a = pointers[i];
        for (var j = i + 1; j < pointers.length; j++) {
          var b = pointers[j];
          x = Math.abs(a.clientX - b.clientX);
          y = Math.abs(a.clientY - b.clientY);
          d = x + y;
          if (d > dist) {
            dist = d;
            points = {a: a, b: b};
          }
        }
      }
      x = Math.abs(points.a.clientX + points.b.clientX) / 2;
      y = Math.abs(points.a.clientY + points.b.clientY) / 2;
      points.center = { x: x, y: y };
      points.diameter = dist;
      return points;
    },
    calcAngle: function(points) {
      var x = points.a.clientX - points.b.clientX;
      var y = points.a.clientY - points.b.clientY;
      return (360 + Math.atan2(y, x) * RAD_TO_DEG) % 360;
    },
  };
  dispatcher.registerRecognizer('pinch', pinch);
})(window.PointerGestures);
<commit_msg>Always make *some* chord in pinch<commit_after>/*
 * Copyright 2013 The Polymer Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */

/*
 * Basic strategy: find the farthest apart points, use as diameter of circle
 * react to size change and rotation of the chord
 */

/**
 * @module PointerGestures
 * @submodule Events
 * @class pinch
 */
/**
 * Scale of the pinch zoom gesture
 * @property scale
 * @type Number
 */
/**
 * Center X position of pointers causing pinch
 * @property centerX
 * @type Number
 */
/**
 * Center Y position of pointers causing pinch
 * @property centerY
 * @type Number
 */

/**
 * @module PointerGestures
 * @submodule Events
 * @class rotate
 */
/**
 * Angle (in degrees) of rotation. Measured from starting positions of pointers.
 * @property angle
 * @type Number
 */
/**
 * Center X position of pointers causing rotation
 * @property centerX
 * @type Number
 */
/**
 * Center Y position of pointers causing rotation
 * @property centerY
 * @type Number
 */
(function(scope) {
  var dispatcher = scope.dispatcher;
  var pointermap = new scope.PointerMap();
  var RAD_TO_DEG = 180 / Math.PI;
  var pinch = {
    events: [
      'pointerdown',
      'pointermove',
      'pointerup',
      'pointercancel'
    ],
    reference: {},
    pointerdown: function(ev) {
      pointermap.set(ev.pointerId, ev);
      if (pointermap.pointers() == 2) {
        var points = this.calcChord();
        var angle = this.calcAngle(points);
        this.reference = {
          angle: angle,
          diameter: points.diameter,
          target: scope.findLCA(points.a.target, points.b.target)
        };
      }
    },
    pointerup: function(ev) {
      pointermap.delete(ev.pointerId);
    },
    pointermove: function(ev) {
      if (pointermap.has(ev.pointerId)) {
        pointermap.set(ev.pointerId, ev);
        if (pointermap.pointers() > 1) {
          this.calcPinchRotate();
        }
      }
    },
    pointercancel: function(ev) {
      this.pointerup(ev);
    },
    dispatchPinch: function(diameter, points) {
      var zoom = diameter / this.reference.diameter;
      var ev = dispatcher.makeEvent('pinch', {
        scale: zoom,
        centerX: points.center.x,
        centerY: points.center.y
      });
      dispatcher.dispatchEvent(ev, this.reference.target);
    },
    dispatchRotate: function(angle, points) {
      var diff = Math.round((angle - this.reference.angle) % 360);
      var ev = dispatcher.makeEvent('rotate', {
        angle: diff,
        centerX: points.center.x,
        centerY: points.center.y
      });
      dispatcher.dispatchEvent(ev, this.reference.target);
    },
    calcPinchRotate: function() {
      var points = this.calcChord();
      var diameter = points.diameter;
      var angle = this.calcAngle(points);
      if (diameter != this.reference.diameter) {
        this.dispatchPinch(diameter, points);
      }
      if (angle != this.reference.angle) {
        this.dispatchRotate(angle, points);
      }
    },
    calcChord: function() {
      var pointers = [];
      pointermap.forEach(function(p) {
        pointers.push(p);
      });
      var dist = 0;
      // start with at least two pointers
      var points = {a: pointers[0], b: pointers[1]};
      var x, y, d;
      for (var i = 0; i < pointers.length; i++) {
        var a = pointers[i];
        for (var j = i + 1; j < pointers.length; j++) {
          var b = pointers[j];
          x = Math.abs(a.clientX - b.clientX);
          y = Math.abs(a.clientY - b.clientY);
          d = x + y;
          if (d > dist) {
            dist = d;
            points = {a: a, b: b};
          }
        }
      }
      x = Math.abs(points.a.clientX + points.b.clientX) / 2;
      y = Math.abs(points.a.clientY + points.b.clientY) / 2;
      points.center = { x: x, y: y };
      points.diameter = dist;
      return points;
    },
    calcAngle: function(points) {
      var x = points.a.clientX - points.b.clientX;
      var y = points.a.clientY - points.b.clientY;
      return (360 + Math.atan2(y, x) * RAD_TO_DEG) % 360;
    },
  };
  dispatcher.registerRecognizer('pinch', pinch);
})(window.PointerGestures);
<|endoftext|>


<commit_before>const Promise = require(`bluebird`)
const path = require(`path`)
import invariant from 'invariant'

module.exports = async (api, args, defaultReturn) => {
  let gatsbyNode
  try {
    gatsbyNode = require(`${path.resolve(`.`)}/gatsby-node`)
  } catch (e) {
    console.log(`Couldn't open your gatsby-node.js file`)
    console.log(e)
  }
  if (gatsbyNode && gatsbyNode[api]) {
    const result = await gatsbyNode[api](args)
    if (!result) {
      throw new Error(`The API "${api}" in gatsby-node.js did not return a value`)
      process.exit()
    }
    return result
  }

  return defaultReturn
}
<commit_msg>Only show errors on loading gatsby-node if code errors not MODULE_NOT_FOUND<commit_after>const Promise = require(`bluebird`)
const path = require(`path`)
import invariant from 'invariant'
import _ from 'lodash'

module.exports = async (api, args, defaultReturn) => {
  let gatsbyNode
  try {
    gatsbyNode = require(`${path.resolve(`.`)}/gatsby-node`)
  } catch (e) {
    if (e.code !== `MODULE_NOT_FOUND` && !_.includes(e.Error, `gatsby-node`)) {
      console.log(`Couldn't open your gatsby-node.js file`)
      console.log(e)
    }
  }
  if (gatsbyNode && gatsbyNode[api]) {
    const result = await gatsbyNode[api](args)
    if (!result) {
      throw new Error(`The API "${api}" in gatsby-node.js did not return a value`)
      process.exit()
    }
    return result
  }

  return defaultReturn
}
<|endoftext|>


<commit_before>/**
 * Copyright [2013] [runrightfast.co]
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

(function() {
	'use strict';

	var Entity = require('runrightfast-commons').Entity;
	var util = require('util');
	var Joi = require('joi');
	var lodash = require('lodash');
	var Hoek = require('hoek');
	var assert = Hoek.assert;

	var validate = function validate(obj, schema) {
		var error = Joi.validate(obj, schema);
		if (error) {
			throw error;
		}
	};

	var validateProperty = function validateType(obj) {
		var schema = {
			name : Joi.types.String().regex(/\w+/).required(),
			description : Joi.types.String(),
			type : Joi.types.String().required(),
			constraints : Joi.types.Array()
		};
		validate(obj, schema);
		assert(lodash.isFunction(Joi.types[obj.type]), 'Unsupported type: ' + obj.type);
		if (obj.constraints) {
			var type = Joi.types[obj.type]();
			lodash.forEach(obj.constraints, function(c) {
				if (c.method === 'objectSchemaType') {
					// TODO
					throw new Error('NOT YET IMPLEMENTED');
				} else {
					type = type[c.method].apply(type, c.args);
				}
			});
		}
	};

	var validateType = function validateType(obj) {
		var schema = {
			name : Joi.types.String().regex(/\w+/).required(),
			description : Joi.types.String(),
			allowOtherKeys : Joi.types.Boolean(),
			properties : Joi.types.Object()
		};
		validate(obj, schema);
		if (obj.properties) {
			lodash.keys(obj.properties).forEach(function(key) {
				validateProperty(obj.properties[key]);
			});
		}
	};

	var validateObjectSchema = function validateObjectSchema(obj) {
		var schema = {
			namespace : Joi.types.String().regex(/ns:\/\/.+/).required(),
			version : Joi.types.String().regex(/\d+.\d+.\d+/).required(),
			description : Joi.types.String().required(),
			types : Joi.types.Object()
		};
		validate(obj, schema);
		if (obj.types) {
			lodash.keys(obj.types).forEach(function(key) {
				validateType(obj.types[key]);
			});
		}
	};

	var ObjectSchema = function ObjectSchema(options) {
		Entity.call(this, options);
		validateObjectSchema(options);
		this.namespace = options.namespace;
		this.version = options.version;
		this.description = options.description;
		this.types = options.types || {};
	};

	util.inherits(ObjectSchema, Entity);

	ObjectSchema.prototype.getTypeNames = function() {
		return lodash.keys(this.types);
	};

	ObjectSchema.prototype.getType = function(name) {
		assert(lodash.isString(name), 'name is required and must be a String');
		return this.types[name];
	};

	/**
	 *
	 * @param type
	 * @throws Error
	 *             if type with the same name already exists
	 */
	ObjectSchema.prototype.addType = function(type) {
		validateType(type);
		if (this.types[type.name]) {
			throw new Error('type already exists: ' + JSON.stringify(this.types[type.name]));
		}
		this.types[type.name] = type;
	};

	/**
	 * removes the specified type from the schema
	 *
	 * @param name
	 * @returns type that was removed or undefined if type did not exist
	 */
	ObjectSchema.prototype.removeType = function(name) {
		assert(lodash.isString(name), 'name is required and must be a String');
		var preExistingType = this.types[name];
		delete this.types[name];
		return preExistingType;
	};

	/**
	 * If a type with the same name already exists, then it will be replaced.
	 * Otherwise, it adds the new type.
	 *
	 * @param type
	 * @returns the pre-existing type or undefined
	 */
	ObjectSchema.prototype.setType = function(type) {
		validateType(type);
		var preExistingType = this.types[type.name];
		this.types[type.name] = type;
		return preExistingType;
	};

	var Type = function Type(options) {
		validateType(options);
		this.name = options.name;
		this.description = options.description || this.name;
		this.allowOtherKeys = !!options.allowOtherKeys;
		this.properties = options.properties || {};
	};

	Type.prototype.validate = function(obj) {

	};

	Type.prototype.getSchema = function(obj) {
		var schema = {};
		lodash.forEach(this.properties, function(prop) {
			var propertyType = Joi.types[prop.type];
			// schema[prop.name] = ;
		});
		return schema;
	};

	var Property = function Property(options) {
		validateProperty(options);
		this.name = options.name;
		this.description = options.description || this.name;
		this.type = options.type;
		// where each constraint is an object of the form
		// {method:'method',args:[]}
		this.constraints = options.constraints || [];
	};

	module.exports = {
		ObjectSchema : ObjectSchema,
		Type : Type,
		Property : Property
	};

}());
<commit_msg>reformatted<commit_after>/**
 * Copyright [2013] [runrightfast.co]
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

(function() {
	'use strict';

	var Entity = require('runrightfast-commons').Entity;
	var util = require('util');
	var Joi = require('joi');
	var lodash = require('lodash');
	var Hoek = require('hoek');
	var assert = Hoek.assert;

	var validate = function validate(obj, schema) {
		var error = Joi.validate(obj, schema);
		if (error) {
			throw error;
		}
	};

	var validateProperty = function validateType(obj) {
		var schema = {
			name : Joi.types.String().regex(/\w+/).required(),
			description : Joi.types.String(),
			type : Joi.types.String().required(),
			constraints : Joi.types.Array()
		};
		validate(obj, schema);
		assert(lodash.isFunction(Joi.types[obj.type]), 'Unsupported type: ' + obj.type);
		if (obj.constraints) {
			var type = Joi.types[obj.type]();
			lodash.forEach(obj.constraints, function(c) {
				if (c.method === 'objectSchemaType') {
					// TODO
					throw new Error('NOT YET IMPLEMENTED');

				} else {
					type = type[c.method].apply(type, c.args);
				}
			});
		}
	};

	var validateType = function validateType(obj) {
		var schema = {
			name : Joi.types.String().regex(/\w+/).required(),
			description : Joi.types.String(),
			allowOtherKeys : Joi.types.Boolean(),
			properties : Joi.types.Object()
		};
		validate(obj, schema);
		if (obj.properties) {
			lodash.keys(obj.properties).forEach(function(key) {
				validateProperty(obj.properties[key]);
			});
		}
	};

	var validateObjectSchema = function validateObjectSchema(obj) {
		var schema = {
			namespace : Joi.types.String().regex(/ns:\/\/.+/).required(),
			version : Joi.types.String().regex(/\d+.\d+.\d+/).required(),
			description : Joi.types.String().required(),
			types : Joi.types.Object()
		};
		validate(obj, schema);
		if (obj.types) {
			lodash.keys(obj.types).forEach(function(key) {
				validateType(obj.types[key]);
			});
		}
	};

	var ObjectSchema = function ObjectSchema(options) {
		Entity.call(this, options);
		validateObjectSchema(options);
		this.namespace = options.namespace;
		this.version = options.version;
		this.description = options.description;
		this.types = options.types || {};
	};

	util.inherits(ObjectSchema, Entity);

	ObjectSchema.prototype.getTypeNames = function() {
		return lodash.keys(this.types);
	};

	ObjectSchema.prototype.getType = function(name) {
		assert(lodash.isString(name), 'name is required and must be a String');
		return this.types[name];
	};

	/**
	 *
	 * @param type
	 * @throws Error
	 *             if type with the same name already exists
	 */
	ObjectSchema.prototype.addType = function(type) {
		validateType(type);
		if (this.types[type.name]) {
			throw new Error('type already exists: ' + JSON.stringify(this.types[type.name]));
		}
		this.types[type.name] = type;
	};

	/**
	 * removes the specified type from the schema
	 *
	 * @param name
	 * @returns type that was removed or undefined if type did not exist
	 */
	ObjectSchema.prototype.removeType = function(name) {
		assert(lodash.isString(name), 'name is required and must be a String');
		var preExistingType = this.types[name];
		delete this.types[name];
		return preExistingType;
	};

	/**
	 * If a type with the same name already exists, then it will be replaced.
	 * Otherwise, it adds the new type.
	 *
	 * @param type
	 * @returns the pre-existing type or undefined
	 */
	ObjectSchema.prototype.setType = function(type) {
		validateType(type);
		var preExistingType = this.types[type.name];
		this.types[type.name] = type;
		return preExistingType;
	};

	var Type = function Type(options) {
		validateType(options);
		this.name = options.name;
		this.description = options.description || this.name;
		this.allowOtherKeys = !!options.allowOtherKeys;
		this.properties = options.properties || {};
	};

	Type.prototype.validate = function(obj) {

	};

	Type.prototype.getSchema = function(obj) {
		var schema = {};
		lodash.forEach(this.properties, function(prop) {
			var propertyType = Joi.types[prop.type];
			// schema[prop.name] = ;
		});
		return schema;
	};

	var Property = function Property(options) {
		validateProperty(options);
		this.name = options.name;
		this.description = options.description || this.name;
		this.type = options.type;
		// where each constraint is an object of the form
		// {method:'method',args:[]}
		this.constraints = options.constraints || [];
	};

	module.exports = {
		ObjectSchema : ObjectSchema,
		Type : Type,
		Property : Property
	};

}());
<|endoftext|>


<commit_before>/*!
 * masterkey.js - master bip32 key object for bcoin
 * Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
 * https://github.com/bcoin-org/bcoin
 */

'use strict';

var util = require('../utils/util');
var Lock = require('../utils/lock');
var co = require('../utils/co');
var crypto = require('../crypto/crypto');
var assert = require('assert');
var BufferReader = require('../utils/reader');
var StaticWriter = require('../utils/staticwriter');
var encoding = require('../utils/encoding');
var HD = require('../hd/hd');

/*
 * Constants
 */

var BCOIN_SALT = new Buffer('bcoin', 'ascii');

/**
 * Master BIP32 key which can exist
 * in a timed out encrypted state.
 * @exports Master
 * @constructor
 * @param {Object} options
 */

function MasterKey(options) {
  if (!(this instanceof MasterKey))
    return new MasterKey(options);

  this.encrypted = false;
  this.iv = null;
  this.ciphertext = null;
  this.key = null;

  this.alg = MasterKey.alg.PBKDF2;
  this.N = 50000;
  this.r = 0;
  this.p = 0;

  this.aesKey = null;
  this.timer = null;
  this.until = 0;
  this._onTimeout = this.lock.bind(this);
  this.locker = new Lock(this);

  if (options)
    this.fromOptions(options);
}

/**
 * Key derivation algorithms.
 * @enum {Number}
 * @default
 */

MasterKey.alg = {
  PBKDF2: 0,
  SCRYPT: 1
};

/**
 * Key derivation algorithms by value.
 * @enum {String}
 * @default
 */

MasterKey.algByVal = {
  0: 'pbkdf2',
  1: 'scrypt'
};

/**
 * Inject properties from options object.
 * @private
 * @param {Object} options
 */

MasterKey.prototype.fromOptions = function fromOptions(options) {
  assert(options);

  if (options.encrypted != null) {
    assert(typeof options.encrypted === 'boolean');
    this.encrypted = options.encrypted;
  }

  if (options.iv) {
    assert(Buffer.isBuffer(options.iv));
    this.iv = options.iv;
  }

  if (options.ciphertext) {
    assert(Buffer.isBuffer(options.ciphertext));
    this.ciphertext = options.ciphertext;
  }

  if (options.key) {
    assert(HD.isHD(options.key));
    this.key = options.key;
  }

  if (options.alg != null) {
    if (typeof options.alg === 'string') {
      this.alg = MasterKey.alg[options.alg.toLowerCase()];
      assert(this.alg != null, 'Unknown algorithm.');
    } else {
      assert(typeof options.alg === 'number');
      assert(MasterKey.algByVal[options.alg]);
      this.alg = options.alg;
    }
  }

  if (options.rounds != null) {
    assert(util.isNumber(options.rounds));
    this.N = options.rounds;
  }

  if (options.N != null) {
    assert(util.isNumber(options.N));
    this.N = options.N;
  }

  if (options.r != null) {
    assert(util.isNumber(options.r));
    this.r = options.r;
  }

  if (options.p != null) {
    assert(util.isNumber(options.p));
    this.p = options.p;
  }

  assert(this.encrypted ? !this.key : this.key);

  return this;
};

/**
 * Instantiate master key from options.
 * @returns {MasterKey}
 */

MasterKey.fromOptions = function fromOptions(options) {
  return new MasterKey().fromOptions(options);
};

/**
 * Decrypt the key and set a timeout to destroy decrypted data.
 * @param {Buffer|String} passphrase - Zero this yourself.
 * @param {Number} [timeout=60000] timeout in ms.
 * @returns {Promise} - Returns {@link HDPrivateKey}.
 */

MasterKey.prototype.unlock = co(function* _unlock(passphrase, timeout) {
  var unlock = yield this.locker.lock();
  try {
    return yield this._unlock(passphrase, timeout);
  } finally {
    unlock();
  }
});

/**
 * Decrypt the key without a lock.
 * @private
 * @param {Buffer|String} passphrase - Zero this yourself.
 * @param {Number} [timeout=60000] timeout in ms.
 * @returns {Promise} - Returns {@link HDPrivateKey}.
 */

MasterKey.prototype._unlock = co(function* _unlock(passphrase, timeout) {
  var data, key;

  if (this.key) {
    if (this.encrypted) {
      assert(this.timer != null);
      this.start(timeout);
    }
    return this.key;
  }

  if (!passphrase)
    throw new Error('No passphrase.');

  assert(this.encrypted);

  key = yield this.derive(passphrase);
  data = crypto.decipher(this.ciphertext, key, this.iv);

  this.key = HD.fromExtended(data);

  this.start(timeout);

  this.aesKey = key;

  return this.key;
});

/**
 * Start the destroy timer.
 * @private
 * @param {Number} [timeout=60000] timeout in ms.
 */

MasterKey.prototype.start = function start(timeout) {
  if (!timeout)
    timeout = 60;

  this.stop();

  if (timeout === -1)
    return;

  this.until = util.now() + timeout;
  this.timer = setTimeout(this._onTimeout, timeout * 1000);
};

/**
 * Stop the destroy timer.
 * @private
 */

MasterKey.prototype.stop = function stop() {
  if (this.timer != null) {
    clearTimeout(this.timer);
    this.timer = null;
    this.until = 0;
  }
};

/**
 * Derive an aes key based on params.
 * @param {String|Buffer} passphrase
 * @returns {Promise}
 */

MasterKey.prototype.derive = function derive(passwd) {
  if (typeof passwd === 'string')
    passwd = new Buffer(passwd, 'utf8');

  switch (this.alg) {
    case MasterKey.alg.PBKDF2:
      return crypto.pbkdf2Async(passwd, BCOIN_SALT, this.N, 32, 'sha256');
    case MasterKey.alg.SCRYPT:
      return crypto.scryptAsync(passwd, BCOIN_SALT, this.N, this.r, this.p, 32);
    default:
      return Promise.reject(new Error('Unknown algorithm: ' + this.alg));
  }
};

/**
 * Encrypt data with in-memory aes key.
 * @param {Buffer} data
 * @param {Buffer} iv
 * @returns {Buffer}
 */

MasterKey.prototype.encipher = function encipher(data, iv) {
  if (!this.aesKey)
    return;

  if (typeof iv === 'string')
    iv = new Buffer(iv, 'hex');

  return crypto.encipher(data, this.aesKey, iv.slice(0, 16));
};

/**
 * Decrypt data with in-memory aes key.
 * @param {Buffer} data
 * @param {Buffer} iv
 * @returns {Buffer}
 */

MasterKey.prototype.decipher = function decipher(data, iv) {
  if (!this.aesKey)
    return;

  if (typeof iv === 'string')
    iv = new Buffer(iv, 'hex');

  return crypto.decipher(data, this.aesKey, iv.slice(0, 16));
};

/**
 * Destroy the key by zeroing the
 * privateKey and chainCode. Stop
 * the timer if there is one.
 * @returns {Promise}
 */

MasterKey.prototype.lock = co(function* _lock() {
  var unlock = yield this.locker.lock();
  try {
    return yield this._lock();
  } finally {
    unlock();
  }
});

/**
 * Destroy the key by zeroing the
 * privateKey and chainCode. Stop
 * the timer if there is one.
 */

MasterKey.prototype._lock = function lock() {
  if (!this.encrypted) {
    assert(this.timer == null);
    assert(this.key);
    return;
  }

  this.stop();

  if (this.key) {
    this.key.destroy(true);
    this.key = null;
  }

  if (this.aesKey) {
    crypto.cleanse(this.aesKey);
    this.aesKey = null;
  }
};

/**
 * Destroy the key permanently.
 */

MasterKey.prototype.destroy = co(function* destroy() {
  yield this.lock();
  this.locker.destroy();
});

/**
 * Decrypt the key permanently.
 * @param {Buffer|String} passphrase - Zero this yourself.
 * @returns {Promise}
 */

MasterKey.prototype.decrypt = co(function* decrypt(passphrase, aes) {
  var unlock = yield this.locker.lock();
  try {
    return yield this._decrypt(passphrase, aes);
  } finally {
    unlock();
  }
});

/**
 * Decrypt the key permanently without a lock.
 * @private
 * @param {Buffer|String} passphrase - Zero this yourself.
 * @returns {Promise}
 */

MasterKey.prototype._decrypt = co(function* decrypt(passphrase, aes) {
  var key, data;

  if (!this.encrypted)
    throw new Error('Master key is not encrypted.');

  if (!passphrase)
    throw new Error('No passphrase provided.');

  this._lock();

  key = yield this.derive(passphrase);
  data = crypto.decipher(this.ciphertext, key, this.iv);

  this.key = HD.fromExtended(data);
  this.encrypted = false;
  this.iv = null;
  this.ciphertext = null;

  if (!aes) {
    crypto.cleanse(key);
    return;
  }

  return key;
});

/**
 * Encrypt the key permanently.
 * @param {Buffer|String} passphrase - Zero this yourself.
 * @returns {Promise}
 */

MasterKey.prototype.encrypt = co(function* encrypt(passphrase, aes) {
  var unlock = yield this.locker.lock();
  try {
    return yield this._encrypt(passphrase, aes);
  } finally {
    unlock();
  }
});

/**
 * Encrypt the key permanently without a lock.
 * @private
 * @param {Buffer|String} passphrase - Zero this yourself.
 * @returns {Promise}
 */

MasterKey.prototype._encrypt = co(function* encrypt(passphrase, aes) {
  var key, data, iv;

  if (this.encrypted)
    throw new Error('Master key is already encrypted.');

  if (!passphrase)
    throw new Error('No passphrase provided.');

  data = this.key.toExtended();
  iv = crypto.randomBytes(16);

  this.stop();

  key = yield this.derive(passphrase);
  data = crypto.encipher(data, key, iv);

  this.key = null;
  this.encrypted = true;
  this.iv = iv;
  this.ciphertext = data;

  if (!aes) {
    crypto.cleanse(key);
    return;
  }

  return key;
});

/**
 * Calculate serialization size.
 * @returns {Number}
 */

MasterKey.prototype.getSize = function getSize() {
  var size = 0;

  if (this.encrypted) {
    size += 1;
    size += encoding.sizeVarBytes(this.iv);
    size += encoding.sizeVarBytes(this.ciphertext);
    size += 13;
    return size;
  }

  size += 1;
  size += encoding.sizeVarlen(this.key.getExtendedSize());

  return size;
};

/**
 * Serialize the key in the form of:
 * `[enc-flag][iv?][ciphertext?][extended-key?]`
 * @returns {Buffer}
 */

MasterKey.prototype.toRaw = function toRaw() {
  var size = this.getSize();
  var bw = new StaticWriter(size);

  if (this.encrypted) {
    bw.writeU8(1);
    bw.writeVarBytes(this.iv);
    bw.writeVarBytes(this.ciphertext);

    bw.writeU8(this.alg);
    bw.writeU32(this.N);
    bw.writeU32(this.r);
    bw.writeU32(this.p);

    return bw.render();
  }

  bw.writeU8(0);
  bw.writeVarBytes(this.key.toExtended());

  return bw.render();
};

/**
 * Inject properties from serialized data.
 * @private
 * @param {Buffer} raw
 */

MasterKey.prototype.fromRaw = function fromRaw(raw) {
  var br = new BufferReader(raw);

  this.encrypted = br.readU8() === 1;

  if (this.encrypted) {
    this.iv = br.readVarBytes();
    this.ciphertext = br.readVarBytes();

    this.alg = br.readU8();

    assert(MasterKey.algByVal[this.alg]);

    this.N = br.readU32();
    this.r = br.readU32();
    this.p = br.readU32();

    return this;
  }

  this.key = HD.fromExtended(br.readVarBytes());

  return this;
};

/**
 * Instantiate master key from serialized data.
 * @returns {MasterKey}
 */

MasterKey.fromRaw = function fromRaw(raw) {
  return new MasterKey().fromRaw(raw);
};

/**
 * Inject properties from an HDPrivateKey.
 * @private
 * @param {HDPrivateKey} key
 */

MasterKey.prototype.fromKey = function fromKey(key) {
  this.encrypted = false;
  this.iv = null;
  this.ciphertext = null;
  this.key = key;
  return this;
};

/**
 * Instantiate master key from an HDPrivateKey.
 * @param {HDPrivateKey} key
 * @returns {MasterKey}
 */

MasterKey.fromKey = function fromKey(key) {
  return new MasterKey().fromKey(key);
};

/**
 * Convert master key to a jsonifiable object.
 * @param {Boolean?} unsafe - Whether to include
 * the key data in the JSON.
 * @returns {Object}
 */

MasterKey.prototype.toJSON = function toJSON(unsafe) {
  if (this.encrypted) {
    return {
      encrypted: true,
      until: this.until,
      iv: this.iv.toString('hex'),
      ciphertext: unsafe ? this.ciphertext.toString('hex') : undefined,
      algorithm: MasterKey.algByVal[this.alg],
      N: this.N,
      r: this.r,
      p: this.p
    };
  }

  return {
    encrypted: false,
    key: unsafe ? this.key.toJSON() : undefined
  };
};

/**
 * Inspect the key.
 * @returns {Object}
 */

MasterKey.prototype.inspect = function inspect() {
  var json = this.toJSON(true);
  if (this.key)
    json.key = this.key.toJSON();
  return json;
};

/**
 * Test whether an object is a MasterKey.
 * @param {Object} obj
 * @returns {Boolean}
 */

MasterKey.isMasterKey = function isMasterKey(obj) {
  return obj
    && typeof obj.encrypted === 'boolean'
    && typeof obj.decrypt === 'function';
};

/*
 * Expose
 */

module.exports = MasterKey;
<commit_msg>masterkey: remove useless arg for lock.<commit_after>/*!
 * masterkey.js - master bip32 key object for bcoin
 * Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
 * https://github.com/bcoin-org/bcoin
 */

'use strict';

var util = require('../utils/util');
var Lock = require('../utils/lock');
var co = require('../utils/co');
var crypto = require('../crypto/crypto');
var assert = require('assert');
var BufferReader = require('../utils/reader');
var StaticWriter = require('../utils/staticwriter');
var encoding = require('../utils/encoding');
var HD = require('../hd/hd');

/*
 * Constants
 */

var BCOIN_SALT = new Buffer('bcoin', 'ascii');

/**
 * Master BIP32 key which can exist
 * in a timed out encrypted state.
 * @exports Master
 * @constructor
 * @param {Object} options
 */

function MasterKey(options) {
  if (!(this instanceof MasterKey))
    return new MasterKey(options);

  this.encrypted = false;
  this.iv = null;
  this.ciphertext = null;
  this.key = null;

  this.alg = MasterKey.alg.PBKDF2;
  this.N = 50000;
  this.r = 0;
  this.p = 0;

  this.aesKey = null;
  this.timer = null;
  this.until = 0;
  this._onTimeout = this.lock.bind(this);
  this.locker = new Lock();

  if (options)
    this.fromOptions(options);
}

/**
 * Key derivation algorithms.
 * @enum {Number}
 * @default
 */

MasterKey.alg = {
  PBKDF2: 0,
  SCRYPT: 1
};

/**
 * Key derivation algorithms by value.
 * @enum {String}
 * @default
 */

MasterKey.algByVal = {
  0: 'pbkdf2',
  1: 'scrypt'
};

/**
 * Inject properties from options object.
 * @private
 * @param {Object} options
 */

MasterKey.prototype.fromOptions = function fromOptions(options) {
  assert(options);

  if (options.encrypted != null) {
    assert(typeof options.encrypted === 'boolean');
    this.encrypted = options.encrypted;
  }

  if (options.iv) {
    assert(Buffer.isBuffer(options.iv));
    this.iv = options.iv;
  }

  if (options.ciphertext) {
    assert(Buffer.isBuffer(options.ciphertext));
    this.ciphertext = options.ciphertext;
  }

  if (options.key) {
    assert(HD.isHD(options.key));
    this.key = options.key;
  }

  if (options.alg != null) {
    if (typeof options.alg === 'string') {
      this.alg = MasterKey.alg[options.alg.toLowerCase()];
      assert(this.alg != null, 'Unknown algorithm.');
    } else {
      assert(typeof options.alg === 'number');
      assert(MasterKey.algByVal[options.alg]);
      this.alg = options.alg;
    }
  }

  if (options.rounds != null) {
    assert(util.isNumber(options.rounds));
    this.N = options.rounds;
  }

  if (options.N != null) {
    assert(util.isNumber(options.N));
    this.N = options.N;
  }

  if (options.r != null) {
    assert(util.isNumber(options.r));
    this.r = options.r;
  }

  if (options.p != null) {
    assert(util.isNumber(options.p));
    this.p = options.p;
  }

  assert(this.encrypted ? !this.key : this.key);

  return this;
};

/**
 * Instantiate master key from options.
 * @returns {MasterKey}
 */

MasterKey.fromOptions = function fromOptions(options) {
  return new MasterKey().fromOptions(options);
};

/**
 * Decrypt the key and set a timeout to destroy decrypted data.
 * @param {Buffer|String} passphrase - Zero this yourself.
 * @param {Number} [timeout=60000] timeout in ms.
 * @returns {Promise} - Returns {@link HDPrivateKey}.
 */

MasterKey.prototype.unlock = co(function* _unlock(passphrase, timeout) {
  var unlock = yield this.locker.lock();
  try {
    return yield this._unlock(passphrase, timeout);
  } finally {
    unlock();
  }
});

/**
 * Decrypt the key without a lock.
 * @private
 * @param {Buffer|String} passphrase - Zero this yourself.
 * @param {Number} [timeout=60000] timeout in ms.
 * @returns {Promise} - Returns {@link HDPrivateKey}.
 */

MasterKey.prototype._unlock = co(function* _unlock(passphrase, timeout) {
  var data, key;

  if (this.key) {
    if (this.encrypted) {
      assert(this.timer != null);
      this.start(timeout);
    }
    return this.key;
  }

  if (!passphrase)
    throw new Error('No passphrase.');

  assert(this.encrypted);

  key = yield this.derive(passphrase);
  data = crypto.decipher(this.ciphertext, key, this.iv);

  this.key = HD.fromExtended(data);

  this.start(timeout);

  this.aesKey = key;

  return this.key;
});

/**
 * Start the destroy timer.
 * @private
 * @param {Number} [timeout=60000] timeout in ms.
 */

MasterKey.prototype.start = function start(timeout) {
  if (!timeout)
    timeout = 60;

  this.stop();

  if (timeout === -1)
    return;

  this.until = util.now() + timeout;
  this.timer = setTimeout(this._onTimeout, timeout * 1000);
};

/**
 * Stop the destroy timer.
 * @private
 */

MasterKey.prototype.stop = function stop() {
  if (this.timer != null) {
    clearTimeout(this.timer);
    this.timer = null;
    this.until = 0;
  }
};

/**
 * Derive an aes key based on params.
 * @param {String|Buffer} passphrase
 * @returns {Promise}
 */

MasterKey.prototype.derive = function derive(passwd) {
  if (typeof passwd === 'string')
    passwd = new Buffer(passwd, 'utf8');

  switch (this.alg) {
    case MasterKey.alg.PBKDF2:
      return crypto.pbkdf2Async(passwd, BCOIN_SALT, this.N, 32, 'sha256');
    case MasterKey.alg.SCRYPT:
      return crypto.scryptAsync(passwd, BCOIN_SALT, this.N, this.r, this.p, 32);
    default:
      return Promise.reject(new Error('Unknown algorithm: ' + this.alg));
  }
};

/**
 * Encrypt data with in-memory aes key.
 * @param {Buffer} data
 * @param {Buffer} iv
 * @returns {Buffer}
 */

MasterKey.prototype.encipher = function encipher(data, iv) {
  if (!this.aesKey)
    return;

  if (typeof iv === 'string')
    iv = new Buffer(iv, 'hex');

  return crypto.encipher(data, this.aesKey, iv.slice(0, 16));
};

/**
 * Decrypt data with in-memory aes key.
 * @param {Buffer} data
 * @param {Buffer} iv
 * @returns {Buffer}
 */

MasterKey.prototype.decipher = function decipher(data, iv) {
  if (!this.aesKey)
    return;

  if (typeof iv === 'string')
    iv = new Buffer(iv, 'hex');

  return crypto.decipher(data, this.aesKey, iv.slice(0, 16));
};

/**
 * Destroy the key by zeroing the
 * privateKey and chainCode. Stop
 * the timer if there is one.
 * @returns {Promise}
 */

MasterKey.prototype.lock = co(function* _lock() {
  var unlock = yield this.locker.lock();
  try {
    return yield this._lock();
  } finally {
    unlock();
  }
});

/**
 * Destroy the key by zeroing the
 * privateKey and chainCode. Stop
 * the timer if there is one.
 */

MasterKey.prototype._lock = function lock() {
  if (!this.encrypted) {
    assert(this.timer == null);
    assert(this.key);
    return;
  }

  this.stop();

  if (this.key) {
    this.key.destroy(true);
    this.key = null;
  }

  if (this.aesKey) {
    crypto.cleanse(this.aesKey);
    this.aesKey = null;
  }
};

/**
 * Destroy the key permanently.
 */

MasterKey.prototype.destroy = co(function* destroy() {
  yield this.lock();
  this.locker.destroy();
});

/**
 * Decrypt the key permanently.
 * @param {Buffer|String} passphrase - Zero this yourself.
 * @returns {Promise}
 */

MasterKey.prototype.decrypt = co(function* decrypt(passphrase, aes) {
  var unlock = yield this.locker.lock();
  try {
    return yield this._decrypt(passphrase, aes);
  } finally {
    unlock();
  }
});

/**
 * Decrypt the key permanently without a lock.
 * @private
 * @param {Buffer|String} passphrase - Zero this yourself.
 * @returns {Promise}
 */

MasterKey.prototype._decrypt = co(function* decrypt(passphrase, aes) {
  var key, data;

  if (!this.encrypted)
    throw new Error('Master key is not encrypted.');

  if (!passphrase)
    throw new Error('No passphrase provided.');

  this._lock();

  key = yield this.derive(passphrase);
  data = crypto.decipher(this.ciphertext, key, this.iv);

  this.key = HD.fromExtended(data);
  this.encrypted = false;
  this.iv = null;
  this.ciphertext = null;

  if (!aes) {
    crypto.cleanse(key);
    return;
  }

  return key;
});

/**
 * Encrypt the key permanently.
 * @param {Buffer|String} passphrase - Zero this yourself.
 * @returns {Promise}
 */

MasterKey.prototype.encrypt = co(function* encrypt(passphrase, aes) {
  var unlock = yield this.locker.lock();
  try {
    return yield this._encrypt(passphrase, aes);
  } finally {
    unlock();
  }
});

/**
 * Encrypt the key permanently without a lock.
 * @private
 * @param {Buffer|String} passphrase - Zero this yourself.
 * @returns {Promise}
 */

MasterKey.prototype._encrypt = co(function* encrypt(passphrase, aes) {
  var key, data, iv;

  if (this.encrypted)
    throw new Error('Master key is already encrypted.');

  if (!passphrase)
    throw new Error('No passphrase provided.');

  data = this.key.toExtended();
  iv = crypto.randomBytes(16);

  this.stop();

  key = yield this.derive(passphrase);
  data = crypto.encipher(data, key, iv);

  this.key = null;
  this.encrypted = true;
  this.iv = iv;
  this.ciphertext = data;

  if (!aes) {
    crypto.cleanse(key);
    return;
  }

  return key;
});

/**
 * Calculate serialization size.
 * @returns {Number}
 */

MasterKey.prototype.getSize = function getSize() {
  var size = 0;

  if (this.encrypted) {
    size += 1;
    size += encoding.sizeVarBytes(this.iv);
    size += encoding.sizeVarBytes(this.ciphertext);
    size += 13;
    return size;
  }

  size += 1;
  size += encoding.sizeVarlen(this.key.getExtendedSize());

  return size;
};

/**
 * Serialize the key in the form of:
 * `[enc-flag][iv?][ciphertext?][extended-key?]`
 * @returns {Buffer}
 */

MasterKey.prototype.toRaw = function toRaw() {
  var size = this.getSize();
  var bw = new StaticWriter(size);

  if (this.encrypted) {
    bw.writeU8(1);
    bw.writeVarBytes(this.iv);
    bw.writeVarBytes(this.ciphertext);

    bw.writeU8(this.alg);
    bw.writeU32(this.N);
    bw.writeU32(this.r);
    bw.writeU32(this.p);

    return bw.render();
  }

  bw.writeU8(0);
  bw.writeVarBytes(this.key.toExtended());

  return bw.render();
};

/**
 * Inject properties from serialized data.
 * @private
 * @param {Buffer} raw
 */

MasterKey.prototype.fromRaw = function fromRaw(raw) {
  var br = new BufferReader(raw);

  this.encrypted = br.readU8() === 1;

  if (this.encrypted) {
    this.iv = br.readVarBytes();
    this.ciphertext = br.readVarBytes();

    this.alg = br.readU8();

    assert(MasterKey.algByVal[this.alg]);

    this.N = br.readU32();
    this.r = br.readU32();
    this.p = br.readU32();

    return this;
  }

  this.key = HD.fromExtended(br.readVarBytes());

  return this;
};

/**
 * Instantiate master key from serialized data.
 * @returns {MasterKey}
 */

MasterKey.fromRaw = function fromRaw(raw) {
  return new MasterKey().fromRaw(raw);
};

/**
 * Inject properties from an HDPrivateKey.
 * @private
 * @param {HDPrivateKey} key
 */

MasterKey.prototype.fromKey = function fromKey(key) {
  this.encrypted = false;
  this.iv = null;
  this.ciphertext = null;
  this.key = key;
  return this;
};

/**
 * Instantiate master key from an HDPrivateKey.
 * @param {HDPrivateKey} key
 * @returns {MasterKey}
 */

MasterKey.fromKey = function fromKey(key) {
  return new MasterKey().fromKey(key);
};

/**
 * Convert master key to a jsonifiable object.
 * @param {Boolean?} unsafe - Whether to include
 * the key data in the JSON.
 * @returns {Object}
 */

MasterKey.prototype.toJSON = function toJSON(unsafe) {
  if (this.encrypted) {
    return {
      encrypted: true,
      until: this.until,
      iv: this.iv.toString('hex'),
      ciphertext: unsafe ? this.ciphertext.toString('hex') : undefined,
      algorithm: MasterKey.algByVal[this.alg],
      N: this.N,
      r: this.r,
      p: this.p
    };
  }

  return {
    encrypted: false,
    key: unsafe ? this.key.toJSON() : undefined
  };
};

/**
 * Inspect the key.
 * @returns {Object}
 */

MasterKey.prototype.inspect = function inspect() {
  var json = this.toJSON(true);
  if (this.key)
    json.key = this.key.toJSON();
  return json;
};

/**
 * Test whether an object is a MasterKey.
 * @param {Object} obj
 * @returns {Boolean}
 */

MasterKey.isMasterKey = function isMasterKey(obj) {
  return obj
    && typeof obj.encrypted === 'boolean'
    && typeof obj.decrypt === 'function';
};

/*
 * Expose
 */

module.exports = MasterKey;
<|endoftext|>


<commit_before>var config = require('./lib/config')
  , express = require('express')
  , app = express()
  , server = app.listen(config.port)
  , io = require('socket.io').listen(server)
  , path = require('path')
  , fs=require('fs')
  , EventEmitter = require('events').EventEmitter
  , DashboardEngine = require('./lib/DashboardEngine-mock');

// Keep track of plugins js and css to load them in the view
var scripts = []
  , styles = []
  ;

app.configure( function() {
	app.use(express.static(__dirname + '/static/'));
	app.use(express.favicon());
	app.use(express.logger('dev'));
	app.use(app.router);

	app.set('port', config.port);
	app.set('views', __dirname + '/views');
	app.set('view engine', 'ejs', { pretty: true });
});

app.get('/', function (req, res) {
    res.render('index', {
        title: 'Express'
        ,scripts: scripts
        ,styles: styles
    });
});

var cockpit = {
	status : 'Unknown',
}

// no debug messages
io.configure(function(){ io.set('log level', 1); });

var dashboardEngine = new DashboardEngine();

var deps = {
    server: server
  , app: app
  , io: io
  , dashboardEngine: dashboardEngine
  , socket : undefined
};

// Load the plugins
var dir = path.join(__dirname, 'plugins');
function getFilter(ext) {
    return function(filename) {
        return filename.match(new RegExp('\\.' + ext + '$', 'i'));
    };
}

fs.readdir(
	dir,
	function (err, files) {
	    if (err) {
	        throw err;
	    }
	    files.filter(
	    	function (file) { return fs.statSync(path.join(dir,file)).isDirectory(); }
	    	)
	    .forEach(
	    	function (plugin) {
	    		console.log("Loading " + plugin + " plugin.");
	    		// Load the backend code
	    		var pluginPath = path.join(dir, plugin);
	    		require(pluginPath)(plugin, deps);

      			// Add the public assets to a static route
      			assets = path.join(dir, plugin, 'public');
				if (fs.existsSync(assets)) {
					app.use("/plugin/" + plugin, express.static(assets));
				}

				// Add the js to the view
				if (fs.existsSync(js = path.join(assets, 'js'))) {
					fs.readdirSync(js)
						.filter(getFilter('js'))
						.forEach(
							function(script) {
								scripts.push("/plugin/" + plugin + "/js/" + script);
							});
				}

				// Add the css to the view
				if (fs.existsSync(css = path.join(assets, 'css'))) {
					fs.readdirSync(css)
						.filter(getFilter('css'))
						.forEach(
							function(style) {
								styles.push("/plugin/" + plugin + "/css/" + style);
							});
				}
    });
});

io.sockets.on('connection', function (socket) {

	// redirecting messages to socket-ios
	dashboardEngine.on('message', function(message){
		socket.emit(message.key, message.value);
	});

	deps.socket = socket;

});

console.log('Started listening on port: ' + config.port);
<commit_msg>Fix moving to real engine, not mock<commit_after>var config = require('./lib/config')
  , express = require('express')
  , app = express()
  , server = app.listen(config.port)
  , io = require('socket.io').listen(server)
  , path = require('path')
  , fs=require('fs')
  , EventEmitter = require('events').EventEmitter
  , DashboardEngine = require('./lib/DashboardEngine');

// Keep track of plugins js and css to load them in the view
var scripts = []
  , styles = []
  ;

app.configure( function() {
	app.use(express.static(__dirname + '/static/'));
	app.use(express.favicon());
	app.use(express.logger('dev'));
	app.use(app.router);

	app.set('port', config.port);
	app.set('views', __dirname + '/views');
	app.set('view engine', 'ejs', { pretty: true });
});

app.get('/', function (req, res) {
    res.render('index', {
        title: 'Express'
        ,scripts: scripts
        ,styles: styles
    });
});

var cockpit = {
	status : 'Unknown',
}

// no debug messages
io.configure(function(){ io.set('log level', 1); });

var dashboardEngine = new DashboardEngine();

var deps = {
    server: server
  , app: app
  , io: io
  , dashboardEngine: dashboardEngine
  , socket : undefined
};

// Load the plugins
var dir = path.join(__dirname, 'plugins');
function getFilter(ext) {
    return function(filename) {
        return filename.match(new RegExp('\\.' + ext + '$', 'i'));
    };
}

fs.readdir(
	dir,
	function (err, files) {
	    if (err) {
	        throw err;
	    }
	    files.filter(
	    	function (file) { return fs.statSync(path.join(dir,file)).isDirectory(); }
	    	)
	    .forEach(
	    	function (plugin) {
	    		console.log("Loading " + plugin + " plugin.");
	    		// Load the backend code
	    		var pluginPath = path.join(dir, plugin);
	    		require(pluginPath)(plugin, deps);

      			// Add the public assets to a static route
      			assets = path.join(dir, plugin, 'public');
				if (fs.existsSync(assets)) {
					app.use("/plugin/" + plugin, express.static(assets));
				}

				// Add the js to the view
				if (fs.existsSync(js = path.join(assets, 'js'))) {
					fs.readdirSync(js)
						.filter(getFilter('js'))
						.forEach(
							function(script) {
								scripts.push("/plugin/" + plugin + "/js/" + script);
							});
				}

				// Add the css to the view
				if (fs.existsSync(css = path.join(assets, 'css'))) {
					fs.readdirSync(css)
						.filter(getFilter('css'))
						.forEach(
							function(style) {
								styles.push("/plugin/" + plugin + "/css/" + style);
							});
				}
    });
});

io.sockets.on('connection', function (socket) {

	// redirecting messages to socket-ios
	dashboardEngine.on('message', function(message){
		socket.emit(message.key, message.value);
	});

	deps.socket = socket;

});

console.log('Started listening on port: ' + config.port);
<|endoftext|>


<commit_before>'use strict';

var nodes = require('../node');
var Node = require('../node/node');
var async = require('async');
var debug = require('../util/debug')('factory');

var typeNodeMap = nodes.reduce(function(typeNodeMap, node) {
    typeNodeMap[node.TYPE] = node;
    return typeNodeMap;
}, {});

function Factory(user, databaseService) {
    this.user = user;
    this.databaseService = databaseService;
    this.typeNodeMap = typeNodeMap;
}

module.exports = Factory;

/**
 * Create DAG for analysis definition
 *
 * @param {Object} definition As specified in camshaft-reference.
 * @param {Function} callback function(err, rootNode)
 */
Factory.prototype.create = function (definition, callback) {
    this._create(definition, 0, callback);
};

/**
 * This should create and validate nodes before calling callback back.
 * That includes includes creating intermediate tables for async analysis operations.
 *
 * DAG node creation
 * 1. Extract param names for child nodes
 * 2. Create nodes, for each:
 *  2.1. Go to 1.
 *  2.2. Retrieve column names
 *  2.3. Register operations to be queued in batch sql api
 *
 * @param {Object} definition
 * @param {Number|Function} depth
 * @param {Function} callback
 */
Factory.prototype._create = function (definition, depth, callback) {
    debug('create', definition);
    var errorWrapped = createErrorWrapper(definition);

    if (!this._supportsType(definition.type)) {
        return callback(errorWrapped(new Error('Unknown analysis type: "' + definition.type + '"')));
    }

    var self = this;

    definition.params.id = definition.id;

    var NodeClass = self.getNodeClass(definition.type);

    var childNodesNames = Node.getChildNodesNames(NodeClass);
    var childNodesDefinitions = childNodesNames.reduce(function(childNodesDefinitions, childNodeName) {
        if (definition.params.hasOwnProperty(childNodeName)) {
            childNodesDefinitions.push(definition.params[childNodeName]);
        }
        return childNodesDefinitions;
    }, []);

    depth += 1;
    function create(definition, callback) {
        self._create(definition, depth, callback);
    }

    async.mapSeries(childNodesDefinitions, create, function(err, results) {
        if (err) {
            return callback(errorWrapped(err));
        }

        childNodesNames.forEach(function(childNodesName, index) {
            definition.params[childNodesName] = results[index];
        });

        var node;
        try {
            node = new NodeClass(self.user, definition.params);
        } catch (err) {
            return callback(errorWrapped(err));
        }

        var skipUpdate = depth === 1;
        self.databaseService.getMetadataFromAffectedTables(node, skipUpdate,
        function(err, data) {
            if (err) {
                return callback(errorWrapped(err));
            }
            node.setUpdatedAt(data.last_update);
            var affectedTables = data.affected_tables.map(function(table){
                return table.schema + '.' + table.table;
            });
            node.addAffectedTables(affectedTables);

            self.databaseService.createCacheTable(node, function(err) {
                if (err) {
                    return callback(errorWrapped(err));
                }
                self.databaseService.getColumns(node, function(err, columns) {
                    if (err) {
                        return callback(errorWrapped(err));
                    }
                    node.setColumns(columns);
                    var errors = [];
                    var isValid = node.isValid(errors);
                    if (!isValid) {
                        var errorMessage = 'Validation failed: ' + errors.map(function(e) {
                            return e.message;
                        }).join('; ') + '.';
                        return callback(errorWrapped(new Error(errorMessage)));
                    }
                    return callback(null, node);
                });
            });
        });
    });
};

function createErrorWrapper (definition) {
    return function (err) {
        err.node_id = definition.id;
        return err;
    };
}

Factory.prototype._supportsType = function(nodeType) {
    return this.typeNodeMap.hasOwnProperty(nodeType);
};

Factory.prototype.getNodeClass = function(nodeType) {
    return this.typeNodeMap[nodeType];
};
<commit_msg>Improve naming<commit_after>'use strict';

var nodes = require('../node');
var Node = require('../node/node');
var async = require('async');
var debug = require('../util/debug')('factory');

var typeNodeMap = nodes.reduce(function(typeNodeMap, node) {
    typeNodeMap[node.TYPE] = node;
    return typeNodeMap;
}, {});

function Factory(user, databaseService) {
    this.user = user;
    this.databaseService = databaseService;
    this.typeNodeMap = typeNodeMap;
}

module.exports = Factory;

/**
 * Create DAG for analysis definition
 *
 * @param {Object} definition As specified in camshaft-reference.
 * @param {Function} callback function(err, rootNode)
 */
Factory.prototype.create = function (definition, callback) {
    this._create(definition, 0, callback);
};

/**
 * This should create and validate nodes before calling callback back.
 * That includes includes creating intermediate tables for async analysis operations.
 *
 * DAG node creation
 * 1. Extract param names for child nodes
 * 2. Create nodes, for each:
 *  2.1. Go to 1.
 *  2.2. Retrieve column names
 *  2.3. Register operations to be queued in batch sql api
 *
 * @param {Object} definition
 * @param {Number|Function} depth
 * @param {Function} callback
 */
Factory.prototype._create = function (definition, depth, callback) {
    debug('create', definition);
    var wrapError = createErrorWrapper(definition);

    if (!this._supportsType(definition.type)) {
        return callback(wrapError(new Error('Unknown analysis type: "' + definition.type + '"')));
    }

    var self = this;

    definition.params.id = definition.id;

    var NodeClass = self.getNodeClass(definition.type);

    var childNodesNames = Node.getChildNodesNames(NodeClass);
    var childNodesDefinitions = childNodesNames.reduce(function(childNodesDefinitions, childNodeName) {
        if (definition.params.hasOwnProperty(childNodeName)) {
            childNodesDefinitions.push(definition.params[childNodeName]);
        }
        return childNodesDefinitions;
    }, []);

    depth += 1;
    function create(definition, callback) {
        self._create(definition, depth, callback);
    }

    async.mapSeries(childNodesDefinitions, create, function(err, results) {
        if (err) {
            return callback(wrapError(err));
        }

        childNodesNames.forEach(function(childNodesName, index) {
            definition.params[childNodesName] = results[index];
        });

        var node;
        try {
            node = new NodeClass(self.user, definition.params);
        } catch (err) {
            return callback(wrapError(err));
        }

        var skipUpdate = depth === 1;
        self.databaseService.getMetadataFromAffectedTables(node, skipUpdate,
        function(err, data) {
            if (err) {
                return callback(wrapError(err));
            }
            node.setUpdatedAt(data.last_update);
            var affectedTables = data.affected_tables.map(function(table){
                return table.schema + '.' + table.table;
            });
            node.addAffectedTables(affectedTables);

            self.databaseService.createCacheTable(node, function(err) {
                if (err) {
                    return callback(wrapError(err));
                }
                self.databaseService.getColumns(node, function(err, columns) {
                    if (err) {
                        return callback(wrapError(err));
                    }
                    node.setColumns(columns);
                    var errors = [];
                    var isValid = node.isValid(errors);
                    if (!isValid) {
                        var errorMessage = 'Validation failed: ' + errors.map(function(e) {
                            return e.message;
                        }).join('; ') + '.';
                        return callback(wrapError(new Error(errorMessage)));
                    }
                    return callback(null, node);
                });
            });
        });
    });
};

function createErrorWrapper (definition) {
    return function (err) {
        err.node_id = definition.id;
        return err;
    };
}

Factory.prototype._supportsType = function(nodeType) {
    return this.typeNodeMap.hasOwnProperty(nodeType);
};

Factory.prototype.getNodeClass = function(nodeType) {
    return this.typeNodeMap[nodeType];
};
<|endoftext|>


<commit_before>describe("About Mutability", function() {

  it("should expect object properties to be public and mutable", function () {
    var aPerson = {firstname: "John", lastname: "Smith" };
    aPerson.firstname = "Alan";

    expect(aPerson.firstname).toBe('Alan');
  });

  it("should understand that constructed properties are public and mutable", function () {
    function Person(firstname, lastname)
    {
      this.firstname = firstname;
      this.lastname = lastname;
    }
    var aPerson = new Person ("John", "Smith");
    aPerson.firstname = "Alan";

    expect(aPerson.firstname).toBe('Alan');
  });

  it("should expect prototype properties to be public and mutable", function () {
    function Person(firstname, lastname)
    {
      this.firstname = firstname;
      this.lastname = lastname;
    }
    Person.prototype.getFullName = function () {
      return this.firstname + " " + this.lastname;
    };

    var aPerson = new Person ("John", "Smith");
    expect(aPerson.getFullName()).toBe('John Smith');

    aPerson.getFullName = function () {
      return this.lastname + ", " + this.firstname;
    };

    expect(aPerson.getFullName()).toBe('Smith, John');
  });

  it("should know that variables inside a constructor and constructor args are private", function () {
    function Person(firstname, lastname)
    {
      var fullName = firstname + " " + lastname;

      this.getFirstName = function () { return firstname; };
      this.getLastName = function () { return lastname; };
      this.getFullName = function () { return fullName; };
    }
    var aPerson = new Person ("John", "Smith");

    aPerson.firstname = "Penny";
    aPerson.lastname = "Andrews";
    aPerson.fullName = "Penny Andrews";

    expect(aPerson.getFirstName()).toBe(FILL_ME_IN);
    expect(aPerson.getLastName()).toBe(FILL_ME_IN);
    expect(aPerson.getFullName()).toBe(FILL_ME_IN);

    aPerson.getFullName = function () {
      return aPerson.lastname + ", " + aPerson.firstname;
    };

    expect(aPerson.getFullName()).toBe(FILL_ME_IN);
  });

});
<commit_msg>completed 'should know that vars inside a constr and constr args are private'<commit_after>describe("About Mutability", function() {

  it("should expect object properties to be public and mutable", function () {
    var aPerson = {firstname: "John", lastname: "Smith" };
    aPerson.firstname = "Alan";

    expect(aPerson.firstname).toBe('Alan');
  });

  it("should understand that constructed properties are public and mutable", function () {
    function Person(firstname, lastname)
    {
      this.firstname = firstname;
      this.lastname = lastname;
    }
    var aPerson = new Person ("John", "Smith");
    aPerson.firstname = "Alan";

    expect(aPerson.firstname).toBe('Alan');
  });

  it("should expect prototype properties to be public and mutable", function () {
    function Person(firstname, lastname)
    {
      this.firstname = firstname;
      this.lastname = lastname;
    }
    Person.prototype.getFullName = function () {
      return this.firstname + " " + this.lastname;
    };

    var aPerson = new Person ("John", "Smith");
    expect(aPerson.getFullName()).toBe('John Smith');

    aPerson.getFullName = function () {
      return this.lastname + ", " + this.firstname;
    };

    expect(aPerson.getFullName()).toBe('Smith, John');
  });

  it("should know that variables inside a constructor and constructor args are private", function () {
    function Person(firstname, lastname)
    {
      var fullName = firstname + " " + lastname;

      this.getFirstName = function () { return firstname; };
      this.getLastName = function () { return lastname; };
      this.getFullName = function () { return fullName; };
    }
    var aPerson = new Person ("John", "Smith");

    aPerson.firstname = "Penny";
    aPerson.lastname = "Andrews";
    aPerson.fullName = "Penny Andrews";

    expect(aPerson.getFirstName()).toBe('John');
    expect(aPerson.getLastName()).toBe('Smith');
    expect(aPerson.getFullName()).toBe('John Smith');

    aPerson.getFullName = function () {
      return aPerson.lastname + ", " + aPerson.firstname;
    };

    expect(aPerson.getFullName()).toBe('Andrews, Penny');
  });

});
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Колхоз. Кликер
// @namespace    https://odkl.kolhoz.mobi/
// @version      2.0
// @description  Высаживает, поливает, удобряет, кормит животный, продаёт растения и собирает карты
// @author       GoodVin
// @match        *://*.kolhoz.mobi/*
// @match        *://kolhoz.mobi/*
// @require      https://code.jquery.com/jquery-3.2.1.slim.min.js
// @require      https://github.com/wisegoodvin/mobclickers/raw/master/shared_functions.js
// @downloadURL  https://github.com/wisegoodvin/mobclickers/raw/master/kolhmobi_clicker.user.js
// @updateURL    https://github.com/wisegoodvin/mobclickers/raw/master/kolhmobi_clicker.user.js
// @grant        unsafeWindow
// @grant        GM_setValue
// @grant        GM_getValue
// @icon         http://kolhoz.mobi/favicon.ico
// ==/UserScript==
unsafeWindow.$ = jQuery;
//console.log(navigator);
var today = ("00" + (new Date()).getYear()).slice(-2) + ("00" + ((new Date()).getMonth() + 1)).slice(-2) + ("00" + (new Date()).getDate()).slice(-2);
var time = parseInt(today + ("00" + (new Date()).getHours()).slice(-2) + ("00" + (new Date()).getMinutes()).slice(-2), 10);

$(function(){
	// сначала добавляем кнопки
	$('[ скрипт: в'+(options.scriptenabled ? '' : 'ы')+'кл ]').appendTo("body");
	if(!options.scriptenabled) return false;
	$('[ тип продаж: '+(options.sellertype ? 'умн' : 'прост')+' ]').appendTo("body");
	$('[ автозагоны: в'+(options.feeder ? '' : 'ы')+'кл ]').appendTo("body");
	$('[ обмен рубинов: в'+(options.rubys ? '' : 'ы')+'кл ]').appendTo("body");
	$('[ сбор карт: в'+(options.rubys ? '' : 'ы')+'кл ]').appendTo("body");

	// кончилось бабло
	if($("a:text(продать товар из амбара)").length) {
		console.log("Не хватает денег на покупку семян/удобрений!");
		if(!options.sellertype) return $("a:text(продать товар из амбара)").cl();
		else {
			if(options.feeder) {
				setvar('feeddate', '');
				return go('/mypetfarm');
			} else {
				setvar('feeddate', '');
				setvar('selldate', '');
				return go('/warehouse');
			}
		}
	}

    if($("a:text(вскопать)").length) return $("a:text(вскопать)").log("КОПАЙ!").cl();
	if($("a:text(всё)").length) return $("a:text(всё)").log("Действия по ссылке ВСЁ").cl();

	// действия на главном экране
	$(".block .ptm > ul > li a").each(function(){
		// вскапывание
		if(hastxt(this, "вскопать")) return cl(this, 250, 300);
	});
    if(clicktimer) return false;

	// простые продажи
    if(!options.sellertype) {
        // вход в амбар (шанс зайти туда - 10%)
        if(1 == rand(1, 10)) return go('/warehouse');
        // действия в амбаре
        if('/warehouse' == self.location.pathname) {
            console.log('Продажа из амбара');
            if($(".block a:text(продать)").length) return $(".block a:text(продать)").cl(this);
            if($(".block:text(амбар пуст)").length) return go('/');
        }
        if(clicktimer) return false;
    }
	// умные продажи
	else {
		if(empty(options.selldate) || today != options.selldate) {
			if(options.feeddate == today || !options.feeder) {
				if('/warehouse' == self.location.pathname) {
					if($(".block a:text(продать)").length) return $(".block a:text(продать)").cl(this);
					if($(".block:text(амбар пуст)").length) {
						setvar('selldate', today);
						return go('/');
					}
				} else return go('/warehouse');
			} else if('/mypetfarm' != self.location.pathname) return go('/mypetfarm');
		} else if('/warehouse' == self.location.pathname) return go('/myfarm');
	}

	// кормёжка
	if(options.feeder && (empty(options.feeddate) || options.feeddate != today)) {
		if('/mypetfarm' == self.location.pathname) {
			if($(".feedbackPanelERROR:text(не хватает)").length) {
				setvar('feeddate', today);
				console.log("Кончились продукты");
				return go('/myfarm');
			}
			else if($("a[href*='harvest']:text(продать)").length) return $("a[href*='harvest']:text(продать)").log("Продаём звериную хрень").cl();
			else if($("a[href*='food']:text(покормить)").length) return $("a[href*='food']:text(покормить)").log("Надо выбрать корм для скотинки").cl();
			else if($("a[href*='lastFood']:text(покормить)").length) return $("a[href*='lastFood']:text(покормить)").log("Кормим скотинку").cl();
			else if($("a[href*='fruits']:text(кормить)").length) return $("a[href*='fruits']:text(кормить)").log("Выбираем первую попавшуюся жрачку").cl();
			else {
				setvar('feeddate', today);
				return go('/myfarm');
			}
		} else return go('/mypetfarm');
	}

	// обмен рубинов
	if(options.rubys && (empty(options.rubysdate) || 720 <= time - options.rubysdate)) {
		if('/converter' == self.location.pathname) {
			if($("a[href*='convertAllRubyLink']").length) return $("a[href*='convertAllRubyLink']").log("Конвертируем все доступные рубины").cl();
			else {
				setvar('rubysdate', time);
				return go('/myfarm');
			}
		} else return go('/converter');
	}

	// сбор карт
	if(options.cardcollector && (empty(options.cardtime) || time - options.cardtime >= 181)) {
		if('/queue' == self.location.pathname) {
			if($("a.btny[href*='open']").length) $("a.btny[href*='open']").log("Открываем доступный сундук").cl();
			else {
				setvar('cardtime', time);
				return go('/myfarm');
			}
		}
		else if('/reward' == self.location.pathname && $("a:text(продолжить)").length) $("a:text(продолжить)").log("Забираем карты").cl();
		else return go('/queue');
	}

    // запуск таймера
    var txt = $(".ptm > ul > li").text().toLowerCase().replace(/\n/g,' ').replace(/\r/g,'').replace(/\s{1,}/g,' ').trim();
    if(!empty(txt)) {
        const timeregex = /(\d+\s+(?:д|ч|м|с)[а-яё\s]+)?\d+\s(?:ч|м|с)/g;
        var mintime = null;
        var idx = 0;
        while((res = timeregex.exec(txt)) !== null) {
            if (res.index === timeregex.lastIndex) timeregex.lastIndex++;
            if(empty(res[0])) continue;
            var t = str2secs(res[0]);
            if(empty(mintime) || t < mintime) mintime = t;
        }
        mintime += 5;
        console.log('Никаких действие не сделано - запущен таймер на '+mintime+' сек. до ближайшего действия.');
        return go("/", mintime * 1000);
    }

	// ошибка
	if(/Error/i.test(self.location.href) || /actionsBlock/i.test(self.location.href)) {
		console.log("Мы на странице с ошибкой - запущен таймер на переход к основному окну");
		return go('/', rand(3000,5000));
	}
});
<commit_msg>добавил ранчо<commit_after>// ==UserScript==
// @name         Колхоз. Кликер
// @namespace    https://odkl.kolhoz.mobi/
// @version      2.1
// @description  Высаживает, поливает, удобряет, кормит животный, продаёт растения, окучивает ранчоб открывает сундуки и собирает карты
// @author       GoodVin
// @match        *://*.kolhoz.mobi/*
// @match        *://kolhoz.mobi/*
// @require      https://code.jquery.com/jquery-3.2.1.slim.min.js
// @require      https://github.com/wisegoodvin/mobclickers/raw/master/shared_functions.js
// @downloadURL  https://github.com/wisegoodvin/mobclickers/raw/master/kolhmobi_clicker.user.js
// @updateURL    https://github.com/wisegoodvin/mobclickers/raw/master/kolhmobi_clicker.user.js
// @grant        unsafeWindow
// @grant        GM_setValue
// @grant        GM_getValue
// @icon         http://kolhoz.mobi/favicon.ico
// ==/UserScript==
unsafeWindow.$ = jQuery;
//console.log(navigator);
var today = ("00" + (new Date()).getYear()).slice(-2) + ("00" + ((new Date()).getMonth() + 1)).slice(-2) + ("00" + (new Date()).getDate()).slice(-2);
var time = parseInt(today + ("00" + (new Date()).getHours()).slice(-2) + ("00" + (new Date()).getMinutes()).slice(-2), 10);

$(function(){
	// сначала добавляем кнопки
	$('[ скрипт: в'+(options.scriptenabled ? '' : 'ы')+'кл ]').appendTo("body");
	if(!options.scriptenabled) return false;
	$('[ тип продаж: '+(options.sellertype ? 'умн' : 'прост')+' ]').appendTo("body");
	$('[ автозагоны: в'+(options.feeder ? '' : 'ы')+'кл ]').appendTo("body");
	$('[ обмен рубинов: в'+(options.rubys ? '' : 'ы')+'кл ]').appendTo("body");
	$('[ сбор карт: в'+(options.cardcollector ? '' : 'ы')+'кл ]').appendTo("body");
	$('[ ранчо: в'+(options.rancho ? '' : 'ы')+'кл ]').appendTo("body");

	// кончилось бабло
	if($("a:text(продать товар из амбара)").length) {
		console.log("Не хватает денег на покупку семян/удобрений!");
		if(!options.sellertype) return $("a:text(продать товар из амбара)").cl();
		else {
			if(options.feeder) {
				setvar('feeddate', '');
				return go('/mypetfarm');
			} else {
				setvar('feeddate', '');
				setvar('selldate', '');
				return go('/warehouse');
			}
		}
	}

    if($("a:text(вскопать)").length) return $("a:text(вскопать)").log("КОПАЙ!").cl();
	if($("a:text(всё)").length) return $("a:text(всё)").log("Действия по ссылке ВСЁ").cl();

	// действия на главном экране
	$(".block .ptm > ul > li a").each(function(){
		// вскапывание
		if(hastxt(this, "вскопать")) return cl(this, 250, 300);
	});
    if(clicktimer) return false;

	// простые продажи
    if(!options.sellertype) {
        // вход в амбар (шанс зайти туда - 10%)
        if(1 == rand(1, 10)) return go('/warehouse');
        // действия в амбаре
        if('/warehouse' == self.location.pathname) {
            console.log('Продажа из амбара');
            if($(".block a:text(продать)").length) return $(".block a:text(продать)").cl(this);
            if($(".block:text(амбар пуст)").length) return go('/');
        }
        if(clicktimer) return false;
    }
	// умные продажи
	else {
		if(empty(options.selldate) || today != options.selldate) {
			if(options.feeddate == today || !options.feeder) {
				if('/warehouse' == self.location.pathname) {
					if($(".block a:text(продать)").length) return $(".block a:text(продать)").cl(this);
					if($(".block:text(амбар пуст)").length) {
						setvar('selldate', today);
						return go('/');
					}
				} else return go('/warehouse');
			} else if('/mypetfarm' != self.location.pathname) return go('/mypetfarm');
		} else if('/warehouse' == self.location.pathname) return go('/myfarm');
	}

	// кормёжка
	if(options.feeder && (empty(options.feeddate) || options.feeddate != today)) {
		if('/mypetfarm' == self.location.pathname) {
			if($(".feedbackPanelERROR:text(не хватает)").length) {
				setvar('feeddate', today);
				console.log("Кончились продукты");
				return go('/myfarm');
			}
			else if($("a[href*='harvest']:text(продать)").length) return $("a[href*='harvest']:text(продать)").log("Продаём звериную хрень").cl();
			else if($("a[href*='food']:text(покормить)").length) return $("a[href*='food']:text(покормить)").log("Надо выбрать корм для скотинки").cl();
			else if($("a[href*='lastFood']:text(покормить)").length) return $("a[href*='lastFood']:text(покормить)").log("Кормим скотинку").cl();
			else if($("a[href*='fruits']:text(кормить)").length) return $("a[href*='fruits']:text(кормить)").log("Выбираем первую попавшуюся жрачку").cl();
			else {
				setvar('feeddate', today);
				return go('/myfarm');
			}
		} else return go('/mypetfarm');
	}

	// обмен рубинов
	if(options.rubys && (empty(options.rubysdate) || 720 <= time - options.rubysdate)) {
		if('/converter' == self.location.pathname) {
			if($("a[href*='convertAllRubyLink']").length) return $("a[href*='convertAllRubyLink']").log("Конвертируем все доступные рубины").cl();
			else {
				setvar('rubysdate', time);
				return go('/myfarm');
			}
		} else return go('/converter');
	}

	// сбор карт
	if(options.cardcollector && (empty(options.cardtime) || time - options.cardtime >= 181)) {
		if('/queue' == self.location.pathname) {
			if($("a.btny[href*='open']").length) $("a.btny[href*='open']").log("Открываем доступный сундук").cl();
			else {
				setvar('cardtime', time);
				return go('/myfarm');
			}
		}
		else if('/reward' == self.location.pathname && $("a:text(продолжить)").length) $("a:text(продолжить)").log("Забираем карты").cl();
		else return go('/queue');
	}

	// ранчо
	if(options.rancho && $("a[href*='rancho']").parent().find("span.title").length && /^\/my/i.test(self.location.pathname)) return go('/rancho');
	if('/rancho' == self.location.pathname) {
		console.log('Ранчо');
		if($("a:text(собрать)").length) return $("a:text(собрать)").log("Собираем уражай").cl();
		if($("a:text(выбрать)").length) return $("a:text(выбрать)").log("Выбираем растение").cl();
		if($("a:text(посадить)").length) return $("a:text(посадить)").log("Сажаем растение").cl();
		return go('/');
	}
	if(/AmericanSelectSeedPage/i.test(self.location.href)) {
		console.log('Ранчо - выбор растения');
		var all = $("img[src*='afarm']").toArray(), dis = $("img[style*='opacity']").toArray(), allow = [];
		for(var i=0, l=all.length; i<l; i++) if(dis.indexOf(all[i]) < 0) allow.push(all[i]);
		if(allow.length) return $(allow[allow.length - 1]).closest("a").cl();
		else return go('/');
	}

    // запуск таймера
    var txt = $(".ptm > ul > li").text().toLowerCase().replace(/\n/g,' ').replace(/\r/g,'').replace(/\s{1,}/g,' ').trim();
    if(!empty(txt)) {
        const timeregex = /(\d+\s+(?:д|ч|м|с)[а-яё\s]+)?\d+\s(?:ч|м|с)/g;
        var mintime = null;
        var idx = 0;
        while((res = timeregex.exec(txt)) !== null) {
            if (res.index === timeregex.lastIndex) timeregex.lastIndex++;
            if(empty(res[0])) continue;
            var t = str2secs(res[0]);
            if(empty(mintime) || t < mintime) mintime = t;
        }
		if(options.rancho && mintime > 60) mintime = 60;
        else mintime += 5;
        console.log('Никаких действие не сделано - запущен таймер на '+mintime+' сек. до ближайшего действия.');
        return go("/", mintime * 1000);
    }

	// ошибка
	if(/Error/i.test(self.location.href) || /actionsBlock/i.test(self.location.href)) {
		console.log("Мы на странице с ошибкой - запущен таймер на переход к основному окну");
		return go('/', rand(3000,5000));
	}
});
<|endoftext|>