<commit_before>import reduceRight from "lodash/collection/reduceRight";
import * as messages from "../../../messages";
import flatten from "lodash/array/flatten";
import * as util from  "../../../util";
import map from "lodash/collection/map";
import * as t from "../../../types";

export var metadata = {
  group: "builtin-trailing"
};

export function CallExpression(node) {
  var callee = this.get("callee");
  if (!callee.isIdentifier()) return;

  var binding = this.scope.getBinding(callee.node.name);
  if (!binding) return;

  if (!binding.path.isFunction()) return;
  if (binding.identifier !== binding.path.node.id) return;

  binding.path.setData("shouldTryTCO", true);
}

export var Func/*tion*/ = {
  exit(node, parent, scope, file) {
    if (node.generator || node.async) return;
    if (!this.getData("shouldTryTCO")) return;

    var tailCall = new TailCallTransformer(this, scope, file);
    tailCall.run();
  }
};

function returnBlock(expr) {
  return t.blockStatement([t.returnStatement(expr)]);
}

var visitor = {
  BlockStatement(node, parent) {
    if (t.isTryStatement(parent)) {
      if (node === parent.block) {
        this.skip();
      } else if (parent.finalizer && node !== parent.finalizer) {
        this.skip();
      }
    }
  },

  ReturnStatement(node, parent, scope, state) {
    return state.subTransform(node.argument);
  },

  Function() {
    this.skip();
  },

  VariableDeclaration(node, parent, scope, state) {
    state.vars.push(node);
  },

  ThisExpression(node, parent, scope, state) {
    if (!state.isShadowed) {
      state.needsThis = true;
      state.thisPaths.push(this);
    }
  },

  ReferencedIdentifier(node, parent, scope, state) {
    if (node.name === "arguments" && (!state.isShadowed || node._shadowedFunctionLiteral)) {
      state.needsArguments = true;
      state.argumentsPaths.push(this);
    }
  }
};

class TailCallTransformer {
  constructor(path, scope, file) {
    this.hasTailRecursion = false;

    this.needsArguments = false;
    this.argumentsPaths = [];
    this.setsArguments  = false;

    this.needsThis = false;
    this.thisPaths = [];

    this.isShadowed = path.isArrowFunctionExpression() || path.is("shadow");
    this.ownerId    = path.node.id;
    this.vars       = [];

    this.scope = scope;
    this.path  = path;
    this.file  = file;
    this.node  = path.node;
  }

  getArgumentsId() {
    return this.argumentsId = this.argumentsId || this.scope.generateUidIdentifier("arguments");
  }

  getThisId() {
    return this.thisId = this.thisId || this.scope.generateUidIdentifier("this");
  }

  getLeftId() {
    return this.leftId = this.leftId || this.scope.generateUidIdentifier("left");
  }

  getFunctionId() {
    return this.functionId = this.functionId || this.scope.generateUidIdentifier("function");
  }

  getAgainId() {
    return this.againId = this.againId || this.scope.generateUidIdentifier("again");
  }

  getParams() {
    var params = this.params;

    if (!params) {
      params = this.node.params;
      this.paramDecls = [];

      for (var i = 0; i < params.length; i++) {
        var param = params[i];
        if (!param._isDefaultPlaceholder) {
          this.paramDecls.push(t.variableDeclarator(
            param,
            params[i] = this.scope.generateUidIdentifier("x")
          ));
        }
      }
    }

    return this.params = params;
  }

  hasDeopt() {
    // check if the ownerId has been reassigned, if it has then it's not safe to
    // perform optimisations
    var ownerIdInfo = this.scope.getBinding(this.ownerId.name);
    return ownerIdInfo && !ownerIdInfo.constant;
  }

  run() {
    var node  = this.node;

    // only tail recursion can be optimized as for now, so we can skip anonymous
    // functions entirely
    var ownerId = this.ownerId;
    if (!ownerId) return;

    // traverse the function and look for tail recursion
    this.path.traverse(visitor, this);

    // has no tail call recursion
    if (!this.hasTailRecursion) return;

    // the function binding isn't constant so we can't be sure that it's the same function :(
    if (this.hasDeopt()) {
      this.file.log.deopt(node, messages.get("tailCallReassignmentDeopt"));
      return;
    }

    //

    var body = t.ensureBlock(node).body;

    for (var i = 0; i < body.length; i++) {
      var bodyNode = body[i];
      if (!t.isFunctionDeclaration(bodyNode)) continue;

      bodyNode = body[i] = t.variableDeclaration("var", [
        t.variableDeclarator(bodyNode.id, t.toExpression(bodyNode))
      ]);
      bodyNode._blockHoist = 2;
    }

    if (this.vars.length > 0) {
      var declarations = flatten(map(this.vars, function (decl) {
        return decl.declarations;
      }));

      var assignment = reduceRight(declarations, function (expr, decl) {
        return t.assignmentExpression("=", decl.id, expr);
      }, t.identifier("undefined"));

      var statement = t.expressionStatement(assignment);
      statement._blockHoist = Infinity;
      body.unshift(statement);
    }

    var paramDecls = this.paramDecls;
    if (paramDecls.length > 0) {
      var paramDecl = t.variableDeclaration("var", paramDecls);
      paramDecl._blockHoist = Infinity;
      body.unshift(paramDecl);
    }

    body.unshift(t.expressionStatement(
      t.assignmentExpression("=", this.getAgainId(), t.literal(false)))
    );

    node.body = util.template("tail-call-body", {
      FUNCTION_ID: this.getFunctionId(),
      AGAIN_ID:    this.getAgainId(),
      BLOCK:       node.body
    });

    var topVars = [];

    if (this.needsThis) {
      for (var path of (this.thisPaths: Array)) {
        path.replaceWith(this.getThisId());
      }

      topVars.push(t.variableDeclarator(this.getThisId(), t.thisExpression()));
    }

    if (this.needsArguments || this.setsArguments) {
      for (let path of (this.argumentsPaths: Array)) {
        path.replaceWith(this.argumentsId);
      }

      var decl = t.variableDeclarator(this.argumentsId);
      if (this.argumentsId) {
        decl.init = t.identifier("arguments");
        decl.init._shadowedFunctionLiteral = true;
      }
      topVars.push(decl);
    }

    var leftId = this.leftId;
    if (leftId) {
      topVars.push(t.variableDeclarator(leftId));
    }

    if (topVars.length > 0) {
      node.body.body.unshift(t.variableDeclaration("var", topVars));
    }
  }

  subTransform(node) {
    if (!node) return;

    var handler = this[`subTransform${node.type}`];
    if (handler) return handler.call(this, node);
  }

  subTransformConditionalExpression(node) {
    var callConsequent = this.subTransform(node.consequent);
    var callAlternate = this.subTransform(node.alternate);
    if (!callConsequent && !callAlternate) {
      return;
    }

    // if ternary operator had tail recursion in value, convert to optimized if-statement
    node.type = "IfStatement";
    node.consequent = callConsequent ? t.toBlock(callConsequent) : returnBlock(node.consequent);

    if (callAlternate) {
      node.alternate = t.isIfStatement(callAlternate) ? callAlternate : t.toBlock(callAlternate);
    } else {
      node.alternate = returnBlock(node.alternate);
    }

    return [node];
  }

  subTransformLogicalExpression(node) {
    // only call in right-value of can be optimized
    var callRight = this.subTransform(node.right);
    if (!callRight) return;

    // cache left value as it might have side-effects
    var leftId = this.getLeftId();
    var testExpr = t.assignmentExpression(
      "=",
      leftId,
      node.left
    );

    if (node.operator === "&&") {
      testExpr = t.unaryExpression("!", testExpr);
    }

    return [t.ifStatement(testExpr, returnBlock(leftId))].concat(callRight);
  }

  subTransformSequenceExpression(node) {
    var seq = node.expressions;

    // only last element can be optimized
    var lastCall = this.subTransform(seq[seq.length - 1]);
    if (!lastCall) {
      return;
    }

    // remove converted expression from sequence
    // and convert to regular expression if needed
    if (--seq.length === 1) {
      node = seq[0];
    }

    return [t.expressionStatement(node)].concat(lastCall);
  }

  subTransformCallExpression(node) {
    var callee = node.callee;
    var thisBinding, args;

    if (t.isMemberExpression(callee, { computed: false }) && t.isIdentifier(callee.property)) {
      switch (callee.property.name) {
        case "call":
          args = t.arrayExpression(node.arguments.slice(1));
          break;

        case "apply":
          args = node.arguments[1] || t.identifier("undefined");
          this.needsArguments = true;
          break;

        default:
          return;
      }

      thisBinding = node.arguments[0];
      callee = callee.object;
    }

    // only tail recursion can be optimized as for now
    if (!t.isIdentifier(callee) || !this.scope.bindingIdentifierEquals(callee.name, this.ownerId)) {
      return;
    }

    this.hasTailRecursion = true;

    if (this.hasDeopt()) return;

    var body = [];

    if (this.needsThis && !t.isThisExpression(thisBinding)) {
      body.push(t.expressionStatement(t.assignmentExpression(
        "=",
        this.getThisId(),
        thisBinding || t.identifier("undefined")
      )));
    }

    if (!args) {
      args = t.arrayExpression(node.arguments);
    }

    if (t.isArrayExpression(args) && args.elements.length > this.node.params.length) {
      this.needsArguments = true;
    }

    var argumentsId = this.getArgumentsId();
    var params      = this.getParams();

    if (this.needsArguments) {
      body.push(t.expressionStatement(t.assignmentExpression(
        "=",
        argumentsId,
        args
      )));
    }

    if (t.isArrayExpression(args)) {
      var elems = args.elements;
      for (let i = 0; i < elems.length && i < params.length; i++) {
        let param = params[i];
        let elem = elems[i] || (elems[i] = t.identifier("undefined"));
        if (!param._isDefaultPlaceholder) {
          elems[i] = t.assignmentExpression("=", param, elem);
        }
      }

      if (!this.needsArguments) {
        for (let elem of (elems: Array)) {
          body.push(t.expressionStatement(elem));
        }
      }
    } else {
      this.setsArguments = true;
      for (let i = 0; i < params.length; i++) {
        let param = params[i];
        if (!param._isDefaultPlaceholder) {
          body.push(t.expressionStatement(t.assignmentExpression(
            "=",
            param,
            t.memberExpression(argumentsId, t.literal(i), true)
          )));
        }
      }
    }

    body.push(t.expressionStatement(
      t.assignmentExpression("=", this.getAgainId(), t.literal(true))
    ));

    body.push(t.continueStatement(this.getFunctionId()));

    return body;
  }
}
<commit_msg>remove TCOable check<commit_after>import reduceRight from "lodash/collection/reduceRight";
import * as messages from "../../../messages";
import flatten from "lodash/array/flatten";
import * as util from  "../../../util";
import map from "lodash/collection/map";
import * as t from "../../../types";

export var metadata = {
  group: "builtin-trailing"
};

export function Func/*tion*/(node, parent, scope, file) {
  if (node.generator || node.async) return;
  var tailCall = new TailCallTransformer(this, scope, file);
  tailCall.run();
}

function returnBlock(expr) {
  return t.blockStatement([t.returnStatement(expr)]);
}

var visitor = {
  BlockStatement(node, parent) {
    if (t.isTryStatement(parent)) {
      if (node === parent.block) {
        this.skip();
      } else if (parent.finalizer && node !== parent.finalizer) {
        this.skip();
      }
    }
  },

  ReturnStatement(node, parent, scope, state) {
    return state.subTransform(node.argument);
  },

  Function() {
    this.skip();
  },

  VariableDeclaration(node, parent, scope, state) {
    state.vars.push(node);
  },

  ThisExpression(node, parent, scope, state) {
    if (!state.isShadowed) {
      state.needsThis = true;
      state.thisPaths.push(this);
    }
  },

  ReferencedIdentifier(node, parent, scope, state) {
    if (node.name === "arguments" && (!state.isShadowed || node._shadowedFunctionLiteral)) {
      state.needsArguments = true;
      state.argumentsPaths.push(this);
    }
  }
};

class TailCallTransformer {
  constructor(path, scope, file) {
    this.hasTailRecursion = false;

    this.needsArguments = false;
    this.argumentsPaths = [];
    this.setsArguments  = false;

    this.needsThis = false;
    this.thisPaths = [];

    this.isShadowed = path.isArrowFunctionExpression() || path.is("shadow");
    this.ownerId    = path.node.id;
    this.vars       = [];

    this.scope = scope;
    this.path  = path;
    this.file  = file;
    this.node  = path.node;
  }

  getArgumentsId() {
    return this.argumentsId = this.argumentsId || this.scope.generateUidIdentifier("arguments");
  }

  getThisId() {
    return this.thisId = this.thisId || this.scope.generateUidIdentifier("this");
  }

  getLeftId() {
    return this.leftId = this.leftId || this.scope.generateUidIdentifier("left");
  }

  getFunctionId() {
    return this.functionId = this.functionId || this.scope.generateUidIdentifier("function");
  }

  getAgainId() {
    return this.againId = this.againId || this.scope.generateUidIdentifier("again");
  }

  getParams() {
    var params = this.params;

    if (!params) {
      params = this.node.params;
      this.paramDecls = [];

      for (var i = 0; i < params.length; i++) {
        var param = params[i];
        if (!param._isDefaultPlaceholder) {
          this.paramDecls.push(t.variableDeclarator(
            param,
            params[i] = this.scope.generateUidIdentifier("x")
          ));
        }
      }
    }

    return this.params = params;
  }

  hasDeopt() {
    // check if the ownerId has been reassigned, if it has then it's not safe to
    // perform optimisations
    var ownerIdInfo = this.scope.getBinding(this.ownerId.name);
    return ownerIdInfo && !ownerIdInfo.constant;
  }

  run() {
    var node  = this.node;

    // only tail recursion can be optimized as for now, so we can skip anonymous
    // functions entirely
    var ownerId = this.ownerId;
    if (!ownerId) return;

    // traverse the function and look for tail recursion
    this.path.traverse(visitor, this);

    // has no tail call recursion
    if (!this.hasTailRecursion) return;

    // the function binding isn't constant so we can't be sure that it's the same function :(
    if (this.hasDeopt()) {
      this.file.log.deopt(node, messages.get("tailCallReassignmentDeopt"));
      return;
    }

    //

    var body = t.ensureBlock(node).body;

    for (var i = 0; i < body.length; i++) {
      var bodyNode = body[i];
      if (!t.isFunctionDeclaration(bodyNode)) continue;

      bodyNode = body[i] = t.variableDeclaration("var", [
        t.variableDeclarator(bodyNode.id, t.toExpression(bodyNode))
      ]);
      bodyNode._blockHoist = 2;
    }

    if (this.vars.length > 0) {
      var declarations = flatten(map(this.vars, function (decl) {
        return decl.declarations;
      }));

      var assignment = reduceRight(declarations, function (expr, decl) {
        return t.assignmentExpression("=", decl.id, expr);
      }, t.identifier("undefined"));

      var statement = t.expressionStatement(assignment);
      statement._blockHoist = Infinity;
      body.unshift(statement);
    }

    var paramDecls = this.paramDecls;
    if (paramDecls.length > 0) {
      var paramDecl = t.variableDeclaration("var", paramDecls);
      paramDecl._blockHoist = Infinity;
      body.unshift(paramDecl);
    }

    body.unshift(t.expressionStatement(
      t.assignmentExpression("=", this.getAgainId(), t.literal(false)))
    );

    node.body = util.template("tail-call-body", {
      FUNCTION_ID: this.getFunctionId(),
      AGAIN_ID:    this.getAgainId(),
      BLOCK:       node.body
    });

    var topVars = [];

    if (this.needsThis) {
      for (var path of (this.thisPaths: Array)) {
        path.replaceWith(this.getThisId());
      }

      topVars.push(t.variableDeclarator(this.getThisId(), t.thisExpression()));
    }

    if (this.needsArguments || this.setsArguments) {
      for (let path of (this.argumentsPaths: Array)) {
        path.replaceWith(this.argumentsId);
      }

      var decl = t.variableDeclarator(this.argumentsId);
      if (this.argumentsId) {
        decl.init = t.identifier("arguments");
        decl.init._shadowedFunctionLiteral = true;
      }
      topVars.push(decl);
    }

    var leftId = this.leftId;
    if (leftId) {
      topVars.push(t.variableDeclarator(leftId));
    }

    if (topVars.length > 0) {
      node.body.body.unshift(t.variableDeclaration("var", topVars));
    }
  }

  subTransform(node) {
    if (!node) return;

    var handler = this[`subTransform${node.type}`];
    if (handler) return handler.call(this, node);
  }

  subTransformConditionalExpression(node) {
    var callConsequent = this.subTransform(node.consequent);
    var callAlternate = this.subTransform(node.alternate);
    if (!callConsequent && !callAlternate) {
      return;
    }

    // if ternary operator had tail recursion in value, convert to optimized if-statement
    node.type = "IfStatement";
    node.consequent = callConsequent ? t.toBlock(callConsequent) : returnBlock(node.consequent);

    if (callAlternate) {
      node.alternate = t.isIfStatement(callAlternate) ? callAlternate : t.toBlock(callAlternate);
    } else {
      node.alternate = returnBlock(node.alternate);
    }

    return [node];
  }

  subTransformLogicalExpression(node) {
    // only call in right-value of can be optimized
    var callRight = this.subTransform(node.right);
    if (!callRight) return;

    // cache left value as it might have side-effects
    var leftId = this.getLeftId();
    var testExpr = t.assignmentExpression(
      "=",
      leftId,
      node.left
    );

    if (node.operator === "&&") {
      testExpr = t.unaryExpression("!", testExpr);
    }

    return [t.ifStatement(testExpr, returnBlock(leftId))].concat(callRight);
  }

  subTransformSequenceExpression(node) {
    var seq = node.expressions;

    // only last element can be optimized
    var lastCall = this.subTransform(seq[seq.length - 1]);
    if (!lastCall) {
      return;
    }

    // remove converted expression from sequence
    // and convert to regular expression if needed
    if (--seq.length === 1) {
      node = seq[0];
    }

    return [t.expressionStatement(node)].concat(lastCall);
  }

  subTransformCallExpression(node) {
    var callee = node.callee;
    var thisBinding, args;

    if (t.isMemberExpression(callee, { computed: false }) && t.isIdentifier(callee.property)) {
      switch (callee.property.name) {
        case "call":
          args = t.arrayExpression(node.arguments.slice(1));
          break;

        case "apply":
          args = node.arguments[1] || t.identifier("undefined");
          this.needsArguments = true;
          break;

        default:
          return;
      }

      thisBinding = node.arguments[0];
      callee = callee.object;
    }

    // only tail recursion can be optimized as for now
    if (!t.isIdentifier(callee) || !this.scope.bindingIdentifierEquals(callee.name, this.ownerId)) {
      return;
    }

    this.hasTailRecursion = true;

    if (this.hasDeopt()) return;

    var body = [];

    if (this.needsThis && !t.isThisExpression(thisBinding)) {
      body.push(t.expressionStatement(t.assignmentExpression(
        "=",
        this.getThisId(),
        thisBinding || t.identifier("undefined")
      )));
    }

    if (!args) {
      args = t.arrayExpression(node.arguments);
    }

    if (t.isArrayExpression(args) && args.elements.length > this.node.params.length) {
      this.needsArguments = true;
    }

    var argumentsId = this.getArgumentsId();
    var params      = this.getParams();

    if (this.needsArguments) {
      body.push(t.expressionStatement(t.assignmentExpression(
        "=",
        argumentsId,
        args
      )));
    }

    if (t.isArrayExpression(args)) {
      var elems = args.elements;
      for (let i = 0; i < elems.length && i < params.length; i++) {
        let param = params[i];
        let elem = elems[i] || (elems[i] = t.identifier("undefined"));
        if (!param._isDefaultPlaceholder) {
          elems[i] = t.assignmentExpression("=", param, elem);
        }
      }

      if (!this.needsArguments) {
        for (let elem of (elems: Array)) {
          body.push(t.expressionStatement(elem));
        }
      }
    } else {
      this.setsArguments = true;
      for (let i = 0; i < params.length; i++) {
        let param = params[i];
        if (!param._isDefaultPlaceholder) {
          body.push(t.expressionStatement(t.assignmentExpression(
            "=",
            param,
            t.memberExpression(argumentsId, t.literal(i), true)
          )));
        }
      }
    }

    body.push(t.expressionStatement(
      t.assignmentExpression("=", this.getAgainId(), t.literal(true))
    ));

    body.push(t.continueStatement(this.getFunctionId()));

    return body;
  }
}
<|endoftext|>


<commit_before>'use strict';

import perfNow from 'performance-now';

const DEFAULT_SWIPE_VELOCITY = 0.6;
const DIRECTION_THRESHOLD = 10;
const CHECK_DIRECTION_COUNT = 2;

var eventOptions = false;
try {
  var options = Object.defineProperty({}, "passive", {
    get: () => {
      eventOptions = {
        passive: false,
        capture: true
      };
    }
  });
  window.addEventListener("test", null, options);
} catch(err) {}

export default class GestureHelper {
  constructor(el, options) {
    this.el = el;
    this.options = Object.assign({}, {
      threshold: DIRECTION_THRESHOLD,
      swipeVelocity: DEFAULT_SWIPE_VELOCITY,
      onPanStart: () => {},
      onPan: () => {},
      onPanEnd: () => {}
    }, options);
    this.panning = false;
    this.startDirection = null;
    this.directionCount = 0;
    this.setup();
  }

  isPanning() {
    return this.panning;
  }

  setup() {

    // MOUSE
    let mouseMoveHandler = e => this.handleMove({
      e: e, x: e.clientX, y: e.clientY
    });
    this.el.addEventListener('mousedown', e => {
      this.handleStart({ x: e.clientX, y: e.clientY });
      this.el.addEventListener('mousemove', mouseMoveHandler, eventOptions);
    }, eventOptions);
    this.el.addEventListener('mouseup', e => {
      this.handleEnd();
      console.log('kill listeners!!');
      this.el.removeEventListener('mousemove', mouseMoveHandler, eventOptions);
    }, eventOptions);

    // TOUCH
    let touchMoveHandler = e => this.handleMove({
      e: e,
      x: e.touches[0].clientX, y: e.touches[0].clientY
    });
    let touchEndHandler = e => {
      this.handleEnd();
      this.el.removeEventListener('touchmove', touchMoveHandler, eventOptions);
    };
    this.el.addEventListener('touchstart', e => {
      this.handleStart({
        x: e.touches[0].clientX, y: e.touches[0].clientY
      });
      this.el.addEventListener('touchmove', touchMoveHandler, eventOptions);
    }, false);
    this.el.addEventListener('touchend', touchEndHandler, eventOptions);
    this.el.addEventListener('touchcancel', touchEndHandler, eventOptions);
  }

  handleStart({x=0,y=0}) {

    // Ensure all settings are reset:
    this.startX = x;
    this.startY = y;
    this.startDirection = null;
    this.directionCount = 1;
    this.panning = false;
    this.startTime = perfNow();
    this.maxVelocity = this.currVelocity = 0;
  }

  getStartDirection({x=0,y=0}) {
    if (this.directionCount < CHECK_DIRECTION_COUNT) {
      this.directionCount++;
      return null;
    } else {
      return Math.abs(x) > Math.abs(y) ? 'horizontal' : 'vertical';
    }
  }

  handleMove({e={},x=0,y=0}) {
    let deltaX = x - this.startX;
    let deltaY = y - this.startY;

    if (this.startDirection === null) {
      this.startDirection = this.getStartDirection({x:deltaX,y:deltaY});
    } else if (this.startDirection === 'horizontal'
      && !this.panning
      && Math.abs(deltaX) > this.options.threshold) {

      this.panning = true;
      this.options.onPanStart({});
    }

    if (this.panning) {
      if (eventOptions && eventOptions.passive === false) {
        e.preventDefault();
      }
      this.options.onPan({deltaX});

      // velocity = total distance moved / the time taken
      this.currVelocity = deltaX / (perfNow() - this.startTime);
      this.maxVelocity = Math.max(this.maxVelocity, Math.abs(this.currVelocity));
    }
  }

  handleEnd(x) {
    if (!this.panning) {
      return;
    }
    this.options.onPanEnd({
      isSwipe: this.maxVelocity > this.options.swipeVelocity,
      swipeDirection: (this.currVelocity > 0) ? 'left' : 'right'
    });

    this.panning = false;
  }
}
<commit_msg>get rid of most globals<commit_after>'use strict';

import perfNow from 'performance-now';

var eventOptions = false;
try {
  var options = Object.defineProperty({}, "passive", {
    get: () => {
      eventOptions = {
        passive: false,
        capture: true
      };
    }
  });
  window.addEventListener("test", null, options);
} catch(err) {}

export default class GestureHelper {
  constructor(el, options) {
    this.el = el;
    this.options = Object.assign({}, {
      threshold: 5,
      swipeVelocity: 0.6,
      onPanStart: () => {},
      onPan: () => {},
      onPanEnd: () => {}
    }, options);
    this.panning = false;
    this.startDirection = null;
    this.directionCount = 0;
    this.setup();
  }

  isPanning() {
    return this.panning;
  }

  setup() {

    // MOUSE
    let mouseMoveHandler = e => this.handleMove({
      e: e, x: e.clientX, y: e.clientY
    });
    this.el.addEventListener('mousedown', e => {
      this.handleStart({ x: e.clientX, y: e.clientY });
      this.el.addEventListener('mousemove', mouseMoveHandler, eventOptions);
    }, eventOptions);
    this.el.addEventListener('mouseup', e => {
      this.handleEnd();
      console.log('kill listeners!!');
      this.el.removeEventListener('mousemove', mouseMoveHandler, eventOptions);
    }, eventOptions);

    // TOUCH
    let touchMoveHandler = e => this.handleMove({
      e: e,
      x: e.touches[0].clientX, y: e.touches[0].clientY
    });
    let touchEndHandler = e => {
      this.handleEnd();
      this.el.removeEventListener('touchmove', touchMoveHandler, eventOptions);
    };
    this.el.addEventListener('touchstart', e => {
      this.handleStart({
        x: e.touches[0].clientX, y: e.touches[0].clientY
      });
      this.el.addEventListener('touchmove', touchMoveHandler, eventOptions);
    }, false);
    this.el.addEventListener('touchend', touchEndHandler, eventOptions);
    this.el.addEventListener('touchcancel', touchEndHandler, eventOptions);
  }

  handleStart({x=0,y=0}) {

    // Ensure all settings are reset:
    this.startX = x;
    this.startY = y;
    this.startDirection = null;
    this.directionCount = 1;
    this.panning = false;
    this.startTime = perfNow();
    this.maxVelocity = this.currVelocity = 0;
  }

  getStartDirection({x=0,y=0}) {
    if (this.directionCount < 2) {
      this.directionCount++;
      return null;
    } else {
      return Math.abs(x) > Math.abs(y) ? 'horizontal' : 'vertical';
    }
  }

  handleMove({e={},x=0,y=0}) {
    let deltaX = x - this.startX;
    let deltaY = y - this.startY;

    if (this.startDirection === null) {
      this.startDirection = this.getStartDirection({x:deltaX,y:deltaY});
    } else if (this.startDirection === 'horizontal'
      && !this.panning
      && Math.abs(deltaX) > this.options.threshold) {

      this.panning = true;
      this.options.onPanStart({});
    }

    if (this.panning) {
      if (eventOptions && eventOptions.passive === false) {
        e.preventDefault();
      }
      this.options.onPan({deltaX});

      // velocity = total distance moved / the time taken
      this.currVelocity = deltaX / (perfNow() - this.startTime);
      this.maxVelocity = Math.max(this.maxVelocity, Math.abs(this.currVelocity));
    }
  }

  handleEnd(x) {
    if (!this.panning) {
      return;
    }
    this.options.onPanEnd({
      isSwipe: this.maxVelocity > this.options.swipeVelocity,
      swipeDirection: (this.currVelocity > 0) ? 'left' : 'right'
    });

    this.panning = false;
  }
}
<|endoftext|>


<commit_before>var stringify = require('json-stable-stringify');
var getRaw = require('./get-raw-config');
var loaders = {};
var rawcache = {};

module.exports = getRawCached;

function getRawCached(options) {
  var rawkey = `${options.account}/${options.accountKey}/${options.accountTable}/${options.namespace}`;
  if (rawcache[rawkey]) return Promise.resolve(rawcache[rawkey]);
  if (loaders[rawkey]) return loaders[rawkey];

  return getRaw(options)
    .then((rawdata)=>{
      rawcache[rawkey] = rawdata;
      delete loaders[rawkey];

      //remove cached raw data after 4 minutes
      //don't prevent app exit via this timer
      setTimeout(function(){
        delete rawcache[key];
      }, 240000).unref();

      return rawdata;
    })
    .catch((err)=>{
      delete loaders[rawkey];
      return Promise.reject(err); //raise error
    });
}
<commit_msg>fix typo<commit_after>var stringify = require('json-stable-stringify');
var getRaw = require('./get-raw-config');
var loaders = {};
var rawcache = {};

module.exports = getRawCached;

function getRawCached(options) {
  var rawkey = `${options.account}/${options.accountKey}/${options.accountTable}/${options.namespace}`;
  if (rawcache[rawkey]) return Promise.resolve(rawcache[rawkey]);
  if (loaders[rawkey]) return loaders[rawkey];

  return getRaw(options)
    .then((rawdata)=>{
      rawcache[rawkey] = rawdata;
      delete loaders[rawkey];

      //remove cached raw data after 4 minutes
      //don't prevent app exit via this timer
      setTimeout(function(){
        delete rawcache[rawkey];
      }, 240000).unref();

      return rawdata;
    })
    .catch((err)=>{
      delete loaders[rawkey];
      return Promise.reject(err); //raise error
    });
}
<|endoftext|>


<commit_before>var url = require('url'),
	util = require('util'),
	amqp = require('amqp'),
	redis = require('redis'),
	assert = require('assert'),
	events = require('events')
	uuid = require('node-uuid');

var createMessage = require('./protocol').createMessage;

debug = process.env.NODE_CELERY_DEBUG === '1' ? util.debug : function() {};

function Configuration(options) {
	var self = this;

	for (var o in options) {
		if (options.hasOwnProperty(o)) {
			self[o.replace(/^CELERY_/, '')] = options[o];
		}
	}

	self.BROKER_URL = self.BROKER_URL || 'amqp://';
	self.DEFAULT_QUEUE = self.DEFAULT_QUEUE || 'celery';
	self.DEFAULT_EXCHANGE = self.DEFAULT_EXCHANGE || '';
	self.DEFAULT_EXCHANGE_TYPE = self.DEFAULT_EXCHANGE_TYPE || 'direct';
	self.DEFAULT_ROUTING_KEY = self.DEFAULT_ROUTING_KEY || 'celery';
	self.RESULT_EXCHANGE = self.RESULT_EXCHANGE || 'celeryresults';
	self.TASK_RESULT_EXPIRES = self.TASK_RESULT_EXPIRES || 86400000; // 1 day
	self.ROUTES = self.ROUTES || {};

	if (self.RESULT_BACKEND && self.RESULT_BACKEND.toLowerCase() === 'amqp') {
		self.backend_type = 'amqp';
	} else if (self.RESULT_BACKEND && url.parse(self.RESULT_BACKEND)
		.protocol === 'redis:') {
		self.backend_type = 'redis';
	}
}

function Client(conf, callback) {
	var self = this;

	self.conf = new Configuration(conf);

	self.ready = false;
	self.broker_connected = false;
	self.backend_connected = false;

	self.broker = amqp.createConnection({
		url: self.conf.BROKER_URL
	}, {
		defaultExchangeName: self.conf.DEFAULT_EXCHANGE
	}, callback);

	if (self.conf.backend_type === 'amqp') {
		self.backend = self.broker;
		self.backend_connected = true;
	} else if (self.conf.backend_type === 'redis') {
		var purl = url.parse(self.conf.RESULT_BACKEND);
		self.backend = redis.createClient(purl.port, purl.hostname);

		var on_ready = function() {
			self.backend_connected = true;
			if (self.broker_connected) {
				self.ready = true;
				debug('Emiting connect event...');
				self.emit('connect');
			}
		};

		self.backend.on('connect', function() {
			debug('Backend connected...');
			if (purl.auth) {
				self.backend.auth(purl.auth.split(':')[1], on_ready);
			} else {
				on_ready();
			}
		});

		self.backend.on('error', function(err) {
			self.emit('error', err);
		});
	} else {
		self.backend_connected = true;
	}

	self.broker.on('ready', function() {
		debug('Broker connected...');
		self.broker_connected = true;
		if (self.backend_connected) {
			self.ready = true;
			self.emit('connect');
		}
	});

	self.broker.on('error', function(err) {
		self.emit('error', err);
	});

	self.broker.on('end', function() {
		self.emit('end');
	});
}

util.inherits(Client, events.EventEmitter);

Client.prototype.createTask = function(name, options) {
	return new Task(this, name, options);
};

Client.prototype.end = function() {
	this.broker.end();
	if (this.broker !== this.backend) {
		this.backend.end();
	}
};

Client.prototype.call = function(name /*[args], [kwargs], [options], [callback]*/ ) {
	var args, kwargs, options, callback;
	for (var i = arguments.length - 1; i > 0; i--) {
		if (typeof arguments[i] === 'function') {
			callback = arguments[i];
		} else if (Object.prototype.toString.call(arguments[i]) === '[object Array]') {
			args = arguments[i];
		} else if (typeof arguments[i] === 'object') {
			if (options) {
				kwargs = arguments[i];
			} else {
				options = arguments[i];
			}
		}
	}

	var task = this.createTask(name),
		result = task.call(args, kwargs, options);

	if (callback) {
		result.on('ready', callback);
	}
	return result;
};

function Task(client, name, options) {
	var self = this;

	self.client = client;
	self.name = name;
	self.options = options || {};

	var route = self.client.conf.ROUTES[name],
		queue = route && route.queue;

	self.publish = function(args, kwargs, options, callback) {
		var id = uuid.v4();
		self.client.broker.publish(
		self.options.queue || queue || self.client.conf.DEFAULT_QUEUE,
		createMessage(self.name, args, kwargs, options, id), {
			'contentType': 'application/json'
		},
		callback);
		return new Result(id, self.client);
	};
}

Task.prototype.call = function(args, kwargs, options, callback) {
	var self = this;

	args = args || [];
	kwargs = kwargs || {};
	options = options || self.options || {};

	assert(self.client.ready);
	return self.publish(args, kwargs, options, callback);
};

function Result(taskid, client) {
	var self = this;

	events.EventEmitter.call(self);
	self.taskid = taskid;
	self.client = client;
	self.result = null;

	if (self.client.conf.backend_type === 'amqp') {
		debug('Subscribing to result queue...');
		self.client.backend.queue(
		self.taskid.replace(/-/g, ''), {
			"arguments": {
				'x-expires': self.client.conf.TASK_RESULT_EXPIRES
			}
		},

		function(q) {
			q.bind(self.client.conf.RESULT_EXCHANGE, '#');
			q.subscribe(function(message) {
				self.result = message;
				//q.unbind('#');
				debug('Emiting ready event...');
				self.emit('ready', message);
				self.emit(message.status.toLowerCase(), message);
			});
		});
	}
}

util.inherits(Result, events.EventEmitter);

Result.prototype.get = function(callback) {
	var self = this;
	if (callback && self.result === null) {
		self.client.backend.get('celery-task-meta-' + self.taskid, function(err, reply) {
			self.result = JSON.parse(reply);
			callback(self.result);
		});
	} else {
		return self.result;
	}
};

exports.createClient = function(config, callback) {
	return new Client(config, callback);
};
<commit_msg>Allow for database selection for redis backend.<commit_after>var url = require('url'),
	util = require('util'),
	amqp = require('amqp'),
	redis = require('redis'),
	assert = require('assert'),
	events = require('events')
	uuid = require('node-uuid');

var createMessage = require('./protocol').createMessage;

debug = process.env.NODE_CELERY_DEBUG === '1' ? util.debug : function() {};

function Configuration(options) {
	var self = this;

	for (var o in options) {
		if (options.hasOwnProperty(o)) {
			self[o.replace(/^CELERY_/, '')] = options[o];
		}
	}

	self.BROKER_URL = self.BROKER_URL || 'amqp://';
	self.DEFAULT_QUEUE = self.DEFAULT_QUEUE || 'celery';
	self.DEFAULT_EXCHANGE = self.DEFAULT_EXCHANGE || '';
	self.DEFAULT_EXCHANGE_TYPE = self.DEFAULT_EXCHANGE_TYPE || 'direct';
	self.DEFAULT_ROUTING_KEY = self.DEFAULT_ROUTING_KEY || 'celery';
	self.RESULT_EXCHANGE = self.RESULT_EXCHANGE || 'celeryresults';
	self.TASK_RESULT_EXPIRES = self.TASK_RESULT_EXPIRES || 86400000; // 1 day
	self.ROUTES = self.ROUTES || {};

	if (self.RESULT_BACKEND && self.RESULT_BACKEND.toLowerCase() === 'amqp') {
		self.backend_type = 'amqp';
	} else if (self.RESULT_BACKEND && url.parse(self.RESULT_BACKEND)
		.protocol === 'redis:') {
		self.backend_type = 'redis';
	}
}

function Client(conf, callback) {
	var self = this;

	self.conf = new Configuration(conf);

	self.ready = false;
	self.broker_connected = false;
	self.backend_connected = false;

	self.broker = amqp.createConnection({
		url: self.conf.BROKER_URL
	}, {
		defaultExchangeName: self.conf.DEFAULT_EXCHANGE
	}, callback);

	if (self.conf.backend_type === 'amqp') {
		self.backend = self.broker;
		self.backend_connected = true;
	} else if (self.conf.backend_type === 'redis') {
		var purl = url.parse(self.conf.RESULT_BACKEND),
			database = purl.pathname.slice(1);
		self.backend = redis.createClient(purl.port, purl.hostname);
		if (database) {
			self.backend.select(database);
		}

		var on_ready = function() {
			self.backend_connected = true;
			if (self.broker_connected) {
				self.ready = true;
				debug('Emiting connect event...');
				self.emit('connect');
			}
		};

		self.backend.on('connect', function() {
			debug('Backend connected...');
			if (purl.auth) {
				self.backend.auth(purl.auth.split(':')[1], on_ready);
			} else {
				on_ready();
			}
		});

		self.backend.on('error', function(err) {
			self.emit('error', err);
		});
	} else {
		self.backend_connected = true;
	}

	self.broker.on('ready', function() {
		debug('Broker connected...');
		self.broker_connected = true;
		if (self.backend_connected) {
			self.ready = true;
			self.emit('connect');
		}
	});

	self.broker.on('error', function(err) {
		self.emit('error', err);
	});

	self.broker.on('end', function() {
		self.emit('end');
	});
}

util.inherits(Client, events.EventEmitter);

Client.prototype.createTask = function(name, options) {
	return new Task(this, name, options);
};

Client.prototype.end = function() {
	this.broker.end();
	if (this.broker !== this.backend) {
		this.backend.end();
	}
};

Client.prototype.call = function(name /*[args], [kwargs], [options], [callback]*/ ) {
	var args, kwargs, options, callback;
	for (var i = arguments.length - 1; i > 0; i--) {
		if (typeof arguments[i] === 'function') {
			callback = arguments[i];
		} else if (Object.prototype.toString.call(arguments[i]) === '[object Array]') {
			args = arguments[i];
		} else if (typeof arguments[i] === 'object') {
			if (options) {
				kwargs = arguments[i];
			} else {
				options = arguments[i];
			}
		}
	}

	var task = this.createTask(name),
		result = task.call(args, kwargs, options);

	if (callback) {
		result.on('ready', callback);
	}
	return result;
};

function Task(client, name, options) {
	var self = this;

	self.client = client;
	self.name = name;
	self.options = options || {};

	var route = self.client.conf.ROUTES[name],
		queue = route && route.queue;

	self.publish = function(args, kwargs, options, callback) {
		var id = uuid.v4();
		self.client.broker.publish(
		self.options.queue || queue || self.client.conf.DEFAULT_QUEUE,
		createMessage(self.name, args, kwargs, options, id), {
			'contentType': 'application/json'
		},
		callback);
		return new Result(id, self.client);
	};
}

Task.prototype.call = function(args, kwargs, options, callback) {
	var self = this;

	args = args || [];
	kwargs = kwargs || {};
	options = options || self.options || {};

	assert(self.client.ready);
	return self.publish(args, kwargs, options, callback);
};

function Result(taskid, client) {
	var self = this;

	events.EventEmitter.call(self);
	self.taskid = taskid;
	self.client = client;
	self.result = null;

	if (self.client.conf.backend_type === 'amqp') {
		debug('Subscribing to result queue...');
		self.client.backend.queue(
		self.taskid.replace(/-/g, ''), {
			"arguments": {
				'x-expires': self.client.conf.TASK_RESULT_EXPIRES
			}
		},

		function(q) {
			q.bind(self.client.conf.RESULT_EXCHANGE, '#');
			q.subscribe(function(message) {
				self.result = message;
				//q.unbind('#');
				debug('Emiting ready event...');
				self.emit('ready', message);
				self.emit(message.status.toLowerCase(), message);
			});
		});
	}
}

util.inherits(Result, events.EventEmitter);

Result.prototype.get = function(callback) {
	var self = this;
	if (callback && self.result === null) {
		self.client.backend.get('celery-task-meta-' + self.taskid, function(err, reply) {
			self.result = JSON.parse(reply);
			callback(self.result);
		});
	} else {
		return self.result;
	}
};

exports.createClient = function(config, callback) {
	return new Client(config, callback);
};
<|endoftext|>


<commit_before>/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

/**
 * @class 2x2 Matrix
 * @name mat2
 */
var mat2 = {};

/**
 * Creates a new identity mat2
 *
 * @returns {mat2} a new 2x2 matrix
 */
mat2.create = function() {
    var out = new GLMAT_ARRAY_TYPE(4);
    out[0] = 1;
    out[1] = 0;
    out[2] = 0;
    out[3] = 1;
    return out;
};

/**
 * Creates a new mat2 initialized with values from an existing matrix
 *
 * @param {mat2} a matrix to clone
 * @returns {mat2} a new 2x2 matrix
 */
mat2.clone = function(a) {
    var out = new GLMAT_ARRAY_TYPE(4);
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    return out;
};

/**
 * Copy the values from one mat2 to another
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the source matrix
 * @returns {mat2} out
 */
mat2.copy = function(out, a) {
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    return out;
};

/**
 * Set a mat2 to the identity matrix
 *
 * @param {mat2} out the receiving matrix
 * @returns {mat2} out
 */
mat2.identity = function(out) {
    out[0] = 1;
    out[1] = 0;
    out[2] = 0;
    out[3] = 1;
    return out;
};

/**
 * Transpose the values of a mat2
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the source matrix
 * @returns {mat2} out
 */
mat2.transpose = function(out, a) {
    // If we are transposing ourselves we can skip a few steps but have to cache some values
    if (out === a) {
        var a1 = a[1];
        out[1] = a[2];
        out[2] = a1;
    } else {
        out[0] = a[0];
        out[1] = a[2];
        out[2] = a[1];
        out[3] = a[3];
    }

    return out;
};

/**
 * Inverts a mat2
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the source matrix
 * @returns {mat2} out
 */
mat2.invert = function(out, a) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],

        // Calculate the determinant
        det = a0 * a3 - a2 * a1;

    if (!det) {
        return null;
    }
    det = 1.0 / det;

    out[0] =  a3 * det;
    out[1] = -a1 * det;
    out[2] = -a2 * det;
    out[3] =  a0 * det;

    return out;
};

/**
 * Calculates the adjugate of a mat2
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the source matrix
 * @returns {mat2} out
 */
mat2.adjoint = function(out, a) {
    // Caching this value is nessecary if out == a
    var a0 = a[0];
    out[0] =  a[3];
    out[1] = -a[1];
    out[2] = -a[2];
    out[3] =  a0;

    return out;
};

/**
 * Calculates the determinant of a mat2
 *
 * @param {mat2} a the source matrix
 * @returns {Number} determinant of a
 */
mat2.determinant = function (a) {
    return a[0] * a[3] - a[2] * a[1];
};

/**
 * Multiplies two mat2's
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the first operand
 * @param {mat2} b the second operand
 * @returns {mat2} out
 */
mat2.multiply = function (out, a, b) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
    var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
    out[0] = a0 * b0 + a2 * b1;
    out[1] = a1 * b0 + a3 * b1;
    out[2] = a0 * b2 + a2 * b3;
    out[3] = a1 * b2 + a3 * b3;
    return out;
};

/**
 * Alias for {@link mat2.multiply}
 * @function
 */
mat2.mul = mat2.multiply;

/**
 * Rotates a mat2 by the given angle
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the matrix to rotate
 * @param {Number} rad the angle to rotate the matrix by
 * @returns {mat2} out
 */
mat2.rotate = function (out, a, rad) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
        s = Math.sin(rad),
        c = Math.cos(rad);
    out[0] = a0 *  c + a2 * s;
    out[1] = a1 *  c + a3 * s;
    out[2] = a0 * -s + a2 * c;
    out[3] = a1 * -s + a3 * c;
    return out;
};

/**
 * Scales the mat2 by the dimensions in the given vec2
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the matrix to rotate
 * @param {vec2} v the vec2 to scale the matrix by
 * @returns {mat2} out
 **/
mat2.scale = function(out, a, v) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
        v0 = v[0], v1 = v[1];
    out[0] = a0 * v0;
    out[1] = a1 * v0;
    out[2] = a2 * v1;
    out[3] = a3 * v1;
    return out;
};

/**
 * Creates a matrix from a given angle
 * This is equivalent to (but much faster than):
 *
 *     mat2.identity(dest);
 *     mat2.rotate(dest, dest, rad);
 *
 * @param {mat2} out mat2 receiving operation result
 * @param {Number} rad the angle to rotate the matrix by
 * @returns {mat2} out
 */
mat2.fromRotation = function(out, rad) {
    var s = Math.sin(rad),
        c = Math.cos(rad);
    out[0] = c;
    out[1] = s;
    out[2] = -s;
    out[3] = c;
    return out;
}

/**
 * Creates a matrix from a vector scaling
 * This is equivalent to (but much faster than):
 *
 *     mat2.identity(dest);
 *     mat2.scale(dest, dest, vec);
 *
 * @param {mat2} out mat2 receiving operation result
 * @param {vec2} v Scaling vector
 * @returns {mat2} out
 */
mat2.setScale = function(out, v) {
    out[0] = v[0];
    out[1] = 0;
    out[2] = 0;
    out[3] = v[1];
    return out;
}

/**
 * Returns a string representation of a mat2
 *
 * @param {mat2} mat matrix to represent as a string
 * @returns {String} string representation of the matrix
 */
mat2.str = function (a) {
    return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
};

/**
 * Returns Frobenius norm of a mat2
 *
 * @param {mat2} a the matrix to calculate Frobenius norm of
 * @returns {Number} Frobenius norm
 */
mat2.frob = function (a) {
    return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2)))
};

/**
 * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
 * @param {mat2} L the lower triangular matrix
 * @param {mat2} D the diagonal matrix
 * @param {mat2} U the upper triangular matrix
 * @param {mat2} a the input matrix to factorize
 */

mat2.LDU = function (L, D, U, a) {
    L[2] = a[2]/a[0];
    U[0] = a[0];
    U[1] = a[1];
    U[3] = a[3] - L[2] * U[1];
    return [L, D, U];
};

if(typeof(exports) !== 'undefined') {
    exports.mat2 = mat2;
}
<commit_msg>corrected typo: setScale is now fromScaling in mat2<commit_after>/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

/**
 * @class 2x2 Matrix
 * @name mat2
 */
var mat2 = {};

/**
 * Creates a new identity mat2
 *
 * @returns {mat2} a new 2x2 matrix
 */
mat2.create = function() {
    var out = new GLMAT_ARRAY_TYPE(4);
    out[0] = 1;
    out[1] = 0;
    out[2] = 0;
    out[3] = 1;
    return out;
};

/**
 * Creates a new mat2 initialized with values from an existing matrix
 *
 * @param {mat2} a matrix to clone
 * @returns {mat2} a new 2x2 matrix
 */
mat2.clone = function(a) {
    var out = new GLMAT_ARRAY_TYPE(4);
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    return out;
};

/**
 * Copy the values from one mat2 to another
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the source matrix
 * @returns {mat2} out
 */
mat2.copy = function(out, a) {
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    return out;
};

/**
 * Set a mat2 to the identity matrix
 *
 * @param {mat2} out the receiving matrix
 * @returns {mat2} out
 */
mat2.identity = function(out) {
    out[0] = 1;
    out[1] = 0;
    out[2] = 0;
    out[3] = 1;
    return out;
};

/**
 * Transpose the values of a mat2
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the source matrix
 * @returns {mat2} out
 */
mat2.transpose = function(out, a) {
    // If we are transposing ourselves we can skip a few steps but have to cache some values
    if (out === a) {
        var a1 = a[1];
        out[1] = a[2];
        out[2] = a1;
    } else {
        out[0] = a[0];
        out[1] = a[2];
        out[2] = a[1];
        out[3] = a[3];
    }

    return out;
};

/**
 * Inverts a mat2
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the source matrix
 * @returns {mat2} out
 */
mat2.invert = function(out, a) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],

        // Calculate the determinant
        det = a0 * a3 - a2 * a1;

    if (!det) {
        return null;
    }
    det = 1.0 / det;

    out[0] =  a3 * det;
    out[1] = -a1 * det;
    out[2] = -a2 * det;
    out[3] =  a0 * det;

    return out;
};

/**
 * Calculates the adjugate of a mat2
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the source matrix
 * @returns {mat2} out
 */
mat2.adjoint = function(out, a) {
    // Caching this value is nessecary if out == a
    var a0 = a[0];
    out[0] =  a[3];
    out[1] = -a[1];
    out[2] = -a[2];
    out[3] =  a0;

    return out;
};

/**
 * Calculates the determinant of a mat2
 *
 * @param {mat2} a the source matrix
 * @returns {Number} determinant of a
 */
mat2.determinant = function (a) {
    return a[0] * a[3] - a[2] * a[1];
};

/**
 * Multiplies two mat2's
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the first operand
 * @param {mat2} b the second operand
 * @returns {mat2} out
 */
mat2.multiply = function (out, a, b) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
    var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
    out[0] = a0 * b0 + a2 * b1;
    out[1] = a1 * b0 + a3 * b1;
    out[2] = a0 * b2 + a2 * b3;
    out[3] = a1 * b2 + a3 * b3;
    return out;
};

/**
 * Alias for {@link mat2.multiply}
 * @function
 */
mat2.mul = mat2.multiply;

/**
 * Rotates a mat2 by the given angle
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the matrix to rotate
 * @param {Number} rad the angle to rotate the matrix by
 * @returns {mat2} out
 */
mat2.rotate = function (out, a, rad) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
        s = Math.sin(rad),
        c = Math.cos(rad);
    out[0] = a0 *  c + a2 * s;
    out[1] = a1 *  c + a3 * s;
    out[2] = a0 * -s + a2 * c;
    out[3] = a1 * -s + a3 * c;
    return out;
};

/**
 * Scales the mat2 by the dimensions in the given vec2
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the matrix to rotate
 * @param {vec2} v the vec2 to scale the matrix by
 * @returns {mat2} out
 **/
mat2.scale = function(out, a, v) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
        v0 = v[0], v1 = v[1];
    out[0] = a0 * v0;
    out[1] = a1 * v0;
    out[2] = a2 * v1;
    out[3] = a3 * v1;
    return out;
};

/**
 * Creates a matrix from a given angle
 * This is equivalent to (but much faster than):
 *
 *     mat2.identity(dest);
 *     mat2.rotate(dest, dest, rad);
 *
 * @param {mat2} out mat2 receiving operation result
 * @param {Number} rad the angle to rotate the matrix by
 * @returns {mat2} out
 */
mat2.fromRotation = function(out, rad) {
    var s = Math.sin(rad),
        c = Math.cos(rad);
    out[0] = c;
    out[1] = s;
    out[2] = -s;
    out[3] = c;
    return out;
}

/**
 * Creates a matrix from a vector scaling
 * This is equivalent to (but much faster than):
 *
 *     mat2.identity(dest);
 *     mat2.scale(dest, dest, vec);
 *
 * @param {mat2} out mat2 receiving operation result
 * @param {vec2} v Scaling vector
 * @returns {mat2} out
 */
mat2.fromScaling = function(out, v) {
    out[0] = v[0];
    out[1] = 0;
    out[2] = 0;
    out[3] = v[1];
    return out;
}

/**
 * Returns a string representation of a mat2
 *
 * @param {mat2} mat matrix to represent as a string
 * @returns {String} string representation of the matrix
 */
mat2.str = function (a) {
    return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
};

/**
 * Returns Frobenius norm of a mat2
 *
 * @param {mat2} a the matrix to calculate Frobenius norm of
 * @returns {Number} Frobenius norm
 */
mat2.frob = function (a) {
    return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2)))
};

/**
 * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
 * @param {mat2} L the lower triangular matrix
 * @param {mat2} D the diagonal matrix
 * @param {mat2} U the upper triangular matrix
 * @param {mat2} a the input matrix to factorize
 */

mat2.LDU = function (L, D, U, a) {
    L[2] = a[2]/a[0];
    U[0] = a[0];
    U[1] = a[1];
    U[3] = a[3] - L[2] * U[1];
    return [L, D, U];
};

if(typeof(exports) !== 'undefined') {
    exports.mat2 = mat2;
}<|endoftext|>


<commit_before>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
var path = require("path");
var Module = require("./Module");
var SourceMapSource = require("webpack-sources").SourceMapSource;
var OriginalSource = require("webpack-sources").OriginalSource;
var RawSource = require("webpack-sources").RawSource;
var ReplaceSource = require("webpack-sources").ReplaceSource;
var CachedSource = require("webpack-sources").CachedSource;
var LineToLineMappedSource = require("webpack-sources").LineToLineMappedSource;
var ModuleParseError = require("./ModuleParseError");
var TemplateArgumentDependency = require("./dependencies/TemplateArgumentDependency");
var AsyncDependenciesBlock = require("./AsyncDependenciesBlock");

var ModuleBuildError = require("./ModuleBuildError");
var ModuleError = require("./ModuleError");
var ModuleWarning = require("./ModuleWarning");

var runLoaders = require("loader-runner").runLoaders;
var getContext = require("loader-runner").getContext;

function asString(buf) {
	if(Buffer.isBuffer(buf)) {
		return buf.toString("utf-8");
	}
	return buf;
}

function NormalModule(request, userRequest, rawRequest, loaders, resource, parser) {
	Module.call(this);
	this.request = request;
	this.userRequest = userRequest;
	this.rawRequest = rawRequest;
	this.parser = parser;
	this.resource = resource;
	this.context = getContext(resource);
	this.loaders = loaders;
	this.fileDependencies = [];
	this.contextDependencies = [];
	this.warnings = [];
	this.errors = [];
	this.error = null;
	this._source = null;
	this.meta = {};
	this.assets = {};
	this.built = false;
	this._cachedSource = null;
}
module.exports = NormalModule;

NormalModule.prototype = Object.create(Module.prototype);

NormalModule.prototype.identifier = function() {
	return this.request;
};

NormalModule.prototype.readableIdentifier = function(requestShortener) {
	return requestShortener.shorten(this.userRequest);
};

function contextify(options, request) {
	return request.split("!").map(function(r) {
		var rp = path.relative(options.context, r);
		if(path.sep === "\\")
			rp = rp.replace(/\\/g, "/");
		if(rp.indexOf("../") !== 0)
			rp = "./" + rp;
		return rp;
	}).join("!");
}

NormalModule.prototype.libIdent = function(options) {
	return contextify(options, this.userRequest);
};

NormalModule.prototype.doBuild = function doBuild(options, compilation, resolver, fs, callback) {
	this.cacheable = false;
	var module = this;
	var loaderContext = {
		version: 2,
		emitWarning: function(warning) {
			module.warnings.push(new ModuleWarning(module, warning));
		},
		emitError: function(error) {
			module.errors.push(new ModuleError(module, error));
		},
		exec: function(code, filename) {
			var Module = require("module");
			var m = new Module(filename, module);
			m.paths = Module._nodeModulePaths(module.context);
			m.filename = filename;
			m._compile(code, filename);
			return m.exports;
		},
		resolve: function(context, request, callback) {
			resolver.resolve({}, context, request, callback);
		},
		resolveSync: function(context, request) {
			return resolver.resolveSync({}, context, request);
		},
		options: options
	};
	loaderContext.webpack = true;
	loaderContext.sourceMap = !!this.useSourceMap;
	loaderContext.emitFile = function(name, content, sourceMap) {
		if(typeof sourceMap === "string") {
			this.assets[name] = new OriginalSource(content, sourceMap);
		} else if(sourceMap) {
			this.assets[name] = new SourceMapSource(content, name, sourceMap);
		} else {
			this.assets[name] = new RawSource(content);
		}
	}.bind(this);
	loaderContext._module = this;
	loaderContext._compilation = compilation;
	loaderContext._compiler = compilation.compiler;
	loaderContext.fs = fs;
	compilation.applyPlugins("normal-module-loader", loaderContext, this);
	if(options.loader)
		for(var key in options.loader)
			loaderContext[key] = options.loader[key];

	runLoaders({
		resource: this.resource,
		loaders: this.loaders,
		context: loaderContext,
		readResource: fs.readFile.bind(fs)
	}, function(err, result) {
		if(result) {
			module.cacheable = result.cacheable;
			module.fileDependencies = result.fileDependencies;
			module.contextDependencies = result.contextDependencies;
		}
		if(err) {
			module.error = err;
			return callback(new ModuleBuildError(module, err));
		}

		var resourceBuffer = result.resourceBuffer;
		var source = result.result[0];
		var sourceMap = result.result[1];

		if(!Buffer.isBuffer(source) && typeof source !== "string") {
			module.error = new Error("Final loader didn't return a Buffer or String");
			return callback(new ModuleBuildError(module, module.error));
		}
		source = asString(source);
		if(module.identifier && module.lineToLine && resourceBuffer) {
			module._source = new LineToLineMappedSource(source, module.identifier(),
				asString(resourceBuffer));
		} else if(module.identifier && module.useSourceMap && sourceMap) {
			module._source = new SourceMapSource(source, module.identifier(), sourceMap);
		} else if(module.identifier) {
			module._source = new OriginalSource(source, module.identifier());
		} else {
			module._source = new RawSource(source);
		}
		return callback();
	});
};

NormalModule.prototype.disconnect = function disconnect() {
	this.built = false;
	Module.prototype.disconnect.call(this);
};

NormalModule.prototype.build = function build(options, compilation, resolver, fs, callback) {
	this.buildTimestamp = new Date().getTime();
	this.built = true;
	return this.doBuild(options, compilation, resolver, fs, function(err) {
		if(err) return callback(err);
		this.dependencies.length = 0;
		this.variables.length = 0;
		this.blocks.length = 0;
		this._cachedSource = null;
		if(options.module && options.module.noParse) {
			if(Array.isArray(options.module.noParse)) {
				if(options.module.noParse.some(function(regExp) {
						return typeof regExp === "string" ?
							this.request.indexOf(regExp) === 0 :
							regExp.test(this.request);
					}, this)) return callback();
			} else if(typeof options.module.noParse === "string" ?
				this.request.indexOf(options.module.noParse) === 0 :
				options.module.noParse.test(this.request)) {
				return callback();
			}
		}
		try {
			this.parser.parse(this._source.source(), {
				current: this,
				module: this,
				compilation: compilation,
				options: options
			});
		} catch(e) {
			var source = this._source.source();
			this._source = null;
			return callback(new ModuleParseError(this, source, e));
		}
		return callback();
	}.bind(this));
};

NormalModule.prototype.source = function(dependencyTemplates, outputOptions, requestShortener) {
	var hash = require("crypto").createHash("md5");
	this.updateHash(hash);
	hash = hash.digest("hex");
	if(this._cachedSource && this._cachedSource.hash === hash) {
		return this._cachedSource.source;
	}
	var _source = this._source;
	if(!_source) return new RawSource("throw new Error('No source available');");
	var source = new ReplaceSource(_source);
	this._cachedSource = {
		source: source,
		hash: hash
	};
	var topLevelBlock = this;

	function doDep(dep) {
		var template = dependencyTemplates.get(dep.constructor);
		if(!template) throw new Error("No template for dependency: " + dep.constructor.name);
		template.apply(dep, source, outputOptions, requestShortener, dependencyTemplates);
	}

	function doVariable(availableVars, vars, variable) {
		var name = variable.name;
		var expr = variable.expressionSource(dependencyTemplates, outputOptions, requestShortener);
		if(availableVars.some(function(v) {
				return v.name === name && v.expression.source() === expr.source();
			})) return;
		vars.push({
			name: name,
			expression: expr
		});
	}

	function doBlock(availableVars, block) {
		block.dependencies.forEach(doDep);
		var vars = [];
		if(block.variables.length > 0) {
			block.variables.forEach(doVariable.bind(null, availableVars, vars));
			var varNames = [];
			var varExpressions = [];
			var varStartCode = "";
			var varEndCode = "";

			function emitFunction() {
				if(varNames.length === 0) return;

				varStartCode += "/* WEBPACK VAR INJECTION */(function(" + varNames.join(", ") + ") {";
				// exports === this in the topLevelBlock, but exports do compress better...
				varEndCode = (topLevelBlock === block ? "}.call(exports, " : "}.call(this, ") +
					varExpressions.map(function(e) {
						return e.source();
					}).join(", ") + "))" + varEndCode;

				varNames.length = 0;
				varExpressions.length = 0;
			}
			vars.forEach(function(v) {
				if(varNames.indexOf(v.name) >= 0) emitFunction();
				varNames.push(v.name);
				varExpressions.push(v.expression);
			});
			emitFunction();
			var start = block.range ? block.range[0] : -10;
			var end = block.range ? block.range[1] : _source.size();
			if(varStartCode) source.insert(start + 0.5, varStartCode);
			if(varEndCode) source.insert(end + 0.5, "\n/* WEBPACK VAR INJECTION */" + varEndCode);
		}
		block.blocks.forEach(doBlock.bind(null, availableVars.concat(vars)));
	}
	doBlock([], this);
	return new CachedSource(source);
};

NormalModule.prototype.needRebuild = function needRebuild(fileTimestamps, contextTimestamps) {
	var timestamp = 0;
	this.fileDependencies.forEach(function(file) {
		var ts = fileTimestamps[file];
		if(!ts) timestamp = Infinity;
		if(ts > timestamp) timestamp = ts;
	});
	this.contextDependencies.forEach(function(context) {
		var ts = contextTimestamps[context];
		if(!ts) timestamp = Infinity;
		if(ts > timestamp) timestamp = ts;
	});
	return timestamp >= this.buildTimestamp;
};

NormalModule.prototype.size = function() {
	return this._source ? this._source.size() : -1;
};

NormalModule.prototype.updateHash = function(hash) {
	if(this._source) {
		hash.update("source");
		this._source.updateHash(hash);
	} else
		hash.update("null");
	hash.update("meta");
	hash.update(JSON.stringify(this.meta));
	Module.prototype.updateHash.call(this, hash);
};

NormalModule.prototype.getSourceHash = function() {
	if(!this._source) return "";
	var hash = require("crypto").createHash("md5");
	hash.update(this._source.source());
	return hash.digest("hex");
};

NormalModule.prototype.getAllModuleDependencies = function() {
	var list = [];

	function doDep(dep) {
		if(dep.module && list.indexOf(dep.module) < 0)
			list.push(dep.module);
	}

	function doVariable(variable) {
		variable.dependencies.forEach(doDep);
	}

	function doBlock(block) {
		block.variables.forEach(doVariable);
		block.dependencies.forEach(doDep);
		block.blocks.forEach(doBlock);
	}
	doBlock(this);
	return list;
};

NormalModule.prototype.createTemplate = function(keepModules, roots) {
	roots.sort(function(a, b) {
		var ia = a.identifier();
		var ib = b.identifier();
		if(ia < ib) return -1;
		if(ib < ia) return 1;
		return 0;
	});
	var template = new NormalModule("", "", "", [], "", null);
	template._source = this._source;
	template.built = this.built;
	template.templateModules = keepModules;
	template._templateOrigin = this;
	template.readableIdentifier = function() {
		return "template of " + this._templateOrigin.id + " referencing " + keepModules.map(function(m) {
			return m.id;
		}).join(", ");
	};
	template.identifier = function() {
		var array = roots.map(function(m) {
			return m.identifier();
		});
		array.sort();
		return array.join("|");
	};
	var args = template.arguments = [];

	function doDeps(deps) {
		return deps.map(function(dep) {
			if(dep.module && keepModules.indexOf(dep.module) < 0) {
				var argName = "__webpack_module_template_argument_" + args.length + "__";
				args.push(argName);
				return new TemplateArgumentDependency(argName, dep);
			} else {
				return dep;
			}
		});
	}

	function doBlock(block, newBlock) {
		block.variables.forEach(function(variable) {
			var newDependencies = doDeps(variable.dependencies);
			newBlock.addVariable(variable.name, variable.expression, newDependencies);
		});
		newBlock.dependencies = doDeps(block.dependencies);
		block.blocks.forEach(function(childBlock) {
			var newChildBlock = new AsyncDependenciesBlock(childBlock.name, childBlock.module, childBlock.loc);
			newBlock.addBlock(newChildBlock);
			doBlock(childBlock, newChildBlock);
		});
	}
	doBlock(this, template);
	return template;
};

NormalModule.prototype.getTemplateArguments = function(keepModules) {
	var list = [];

	function doDep(dep) {
		if(dep.module && keepModules.indexOf(dep.module) < 0)
			list.push(dep.module);
	}

	function doVariable(variable) {
		variable.dependencies.forEach(doDep);
	}

	function doBlock(block) {
		block.variables.forEach(doVariable);
		block.dependencies.forEach(doDep);
		block.blocks.forEach(doBlock);
	}
	doBlock(this);
	return list;
};
<commit_msg>fixed a edge case with var injection<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
var path = require("path");
var Module = require("./Module");
var SourceMapSource = require("webpack-sources").SourceMapSource;
var OriginalSource = require("webpack-sources").OriginalSource;
var RawSource = require("webpack-sources").RawSource;
var ReplaceSource = require("webpack-sources").ReplaceSource;
var CachedSource = require("webpack-sources").CachedSource;
var LineToLineMappedSource = require("webpack-sources").LineToLineMappedSource;
var ModuleParseError = require("./ModuleParseError");
var TemplateArgumentDependency = require("./dependencies/TemplateArgumentDependency");
var AsyncDependenciesBlock = require("./AsyncDependenciesBlock");

var ModuleBuildError = require("./ModuleBuildError");
var ModuleError = require("./ModuleError");
var ModuleWarning = require("./ModuleWarning");

var runLoaders = require("loader-runner").runLoaders;
var getContext = require("loader-runner").getContext;

function asString(buf) {
	if(Buffer.isBuffer(buf)) {
		return buf.toString("utf-8");
	}
	return buf;
}

function NormalModule(request, userRequest, rawRequest, loaders, resource, parser) {
	Module.call(this);
	this.request = request;
	this.userRequest = userRequest;
	this.rawRequest = rawRequest;
	this.parser = parser;
	this.resource = resource;
	this.context = getContext(resource);
	this.loaders = loaders;
	this.fileDependencies = [];
	this.contextDependencies = [];
	this.warnings = [];
	this.errors = [];
	this.error = null;
	this._source = null;
	this.meta = {};
	this.assets = {};
	this.built = false;
	this._cachedSource = null;
}
module.exports = NormalModule;

NormalModule.prototype = Object.create(Module.prototype);

NormalModule.prototype.identifier = function() {
	return this.request;
};

NormalModule.prototype.readableIdentifier = function(requestShortener) {
	return requestShortener.shorten(this.userRequest);
};

function contextify(options, request) {
	return request.split("!").map(function(r) {
		var rp = path.relative(options.context, r);
		if(path.sep === "\\")
			rp = rp.replace(/\\/g, "/");
		if(rp.indexOf("../") !== 0)
			rp = "./" + rp;
		return rp;
	}).join("!");
}

NormalModule.prototype.libIdent = function(options) {
	return contextify(options, this.userRequest);
};

NormalModule.prototype.doBuild = function doBuild(options, compilation, resolver, fs, callback) {
	this.cacheable = false;
	var module = this;
	var loaderContext = {
		version: 2,
		emitWarning: function(warning) {
			module.warnings.push(new ModuleWarning(module, warning));
		},
		emitError: function(error) {
			module.errors.push(new ModuleError(module, error));
		},
		exec: function(code, filename) {
			var Module = require("module");
			var m = new Module(filename, module);
			m.paths = Module._nodeModulePaths(module.context);
			m.filename = filename;
			m._compile(code, filename);
			return m.exports;
		},
		resolve: function(context, request, callback) {
			resolver.resolve({}, context, request, callback);
		},
		resolveSync: function(context, request) {
			return resolver.resolveSync({}, context, request);
		},
		options: options
	};
	loaderContext.webpack = true;
	loaderContext.sourceMap = !!this.useSourceMap;
	loaderContext.emitFile = function(name, content, sourceMap) {
		if(typeof sourceMap === "string") {
			this.assets[name] = new OriginalSource(content, sourceMap);
		} else if(sourceMap) {
			this.assets[name] = new SourceMapSource(content, name, sourceMap);
		} else {
			this.assets[name] = new RawSource(content);
		}
	}.bind(this);
	loaderContext._module = this;
	loaderContext._compilation = compilation;
	loaderContext._compiler = compilation.compiler;
	loaderContext.fs = fs;
	compilation.applyPlugins("normal-module-loader", loaderContext, this);
	if(options.loader)
		for(var key in options.loader)
			loaderContext[key] = options.loader[key];

	runLoaders({
		resource: this.resource,
		loaders: this.loaders,
		context: loaderContext,
		readResource: fs.readFile.bind(fs)
	}, function(err, result) {
		if(result) {
			module.cacheable = result.cacheable;
			module.fileDependencies = result.fileDependencies;
			module.contextDependencies = result.contextDependencies;
		}
		if(err) {
			module.error = err;
			return callback(new ModuleBuildError(module, err));
		}

		var resourceBuffer = result.resourceBuffer;
		var source = result.result[0];
		var sourceMap = result.result[1];

		if(!Buffer.isBuffer(source) && typeof source !== "string") {
			module.error = new Error("Final loader didn't return a Buffer or String");
			return callback(new ModuleBuildError(module, module.error));
		}
		source = asString(source);
		if(module.identifier && module.lineToLine && resourceBuffer) {
			module._source = new LineToLineMappedSource(source, module.identifier(),
				asString(resourceBuffer));
		} else if(module.identifier && module.useSourceMap && sourceMap) {
			module._source = new SourceMapSource(source, module.identifier(), sourceMap);
		} else if(module.identifier) {
			module._source = new OriginalSource(source, module.identifier());
		} else {
			module._source = new RawSource(source);
		}
		return callback();
	});
};

NormalModule.prototype.disconnect = function disconnect() {
	this.built = false;
	Module.prototype.disconnect.call(this);
};

NormalModule.prototype.build = function build(options, compilation, resolver, fs, callback) {
	this.buildTimestamp = new Date().getTime();
	this.built = true;
	return this.doBuild(options, compilation, resolver, fs, function(err) {
		if(err) return callback(err);
		this.dependencies.length = 0;
		this.variables.length = 0;
		this.blocks.length = 0;
		this._cachedSource = null;
		if(options.module && options.module.noParse) {
			if(Array.isArray(options.module.noParse)) {
				if(options.module.noParse.some(function(regExp) {
						return typeof regExp === "string" ?
							this.request.indexOf(regExp) === 0 :
							regExp.test(this.request);
					}, this)) return callback();
			} else if(typeof options.module.noParse === "string" ?
				this.request.indexOf(options.module.noParse) === 0 :
				options.module.noParse.test(this.request)) {
				return callback();
			}
		}
		try {
			this.parser.parse(this._source.source(), {
				current: this,
				module: this,
				compilation: compilation,
				options: options
			});
		} catch(e) {
			var source = this._source.source();
			this._source = null;
			return callback(new ModuleParseError(this, source, e));
		}
		return callback();
	}.bind(this));
};

NormalModule.prototype.source = function(dependencyTemplates, outputOptions, requestShortener) {
	var hash = require("crypto").createHash("md5");
	this.updateHash(hash);
	hash = hash.digest("hex");
	if(this._cachedSource && this._cachedSource.hash === hash) {
		return this._cachedSource.source;
	}
	var _source = this._source;
	if(!_source) return new RawSource("throw new Error('No source available');");
	var source = new ReplaceSource(_source);
	this._cachedSource = {
		source: source,
		hash: hash
	};
	var topLevelBlock = this;

	function doDep(dep) {
		var template = dependencyTemplates.get(dep.constructor);
		if(!template) throw new Error("No template for dependency: " + dep.constructor.name);
		template.apply(dep, source, outputOptions, requestShortener, dependencyTemplates);
	}

	function doVariable(availableVars, vars, variable) {
		var name = variable.name;
		var expr = variable.expressionSource(dependencyTemplates, outputOptions, requestShortener);
		if(availableVars.some(function(v) {
				return v.name === name && v.expression.source() === expr.source();
			})) return;
		vars.push({
			name: name,
			expression: expr
		});
	}

	function doBlock(availableVars, block) {
		block.dependencies.forEach(doDep);
		var vars = [];
		if(block.variables.length > 0) {
			block.variables.forEach(doVariable.bind(null, availableVars, vars));
			var varNames = [];
			var varExpressions = [];
			var varStartCode = "";
			var varEndCode = "";

			function emitFunction() {
				if(varNames.length === 0) return;

				varStartCode += "/* WEBPACK VAR INJECTION */(function(" + varNames.join(", ") + ") {";
				// exports === this in the topLevelBlock, but exports do compress better...
				varEndCode = (topLevelBlock === block ? "}.call(exports, " : "}.call(this, ") +
					varExpressions.map(function(e) {
						return e.source();
					}).join(", ") + "))" + varEndCode;

				varNames.length = 0;
				varExpressions.length = 0;
			}
			vars.forEach(function(v) {
				if(varNames.indexOf(v.name) >= 0) emitFunction();
				varNames.push(v.name);
				varExpressions.push(v.expression);
			});
			emitFunction();
			var start = block.range ? block.range[0] : -10;
			var end = block.range ? block.range[1] : (_source.size() + 1);
			if(varStartCode) source.insert(start + 0.5, varStartCode);
			if(varEndCode) source.insert(end + 0.5, "\n/* WEBPACK VAR INJECTION */" + varEndCode);
		}
		block.blocks.forEach(doBlock.bind(null, availableVars.concat(vars)));
	}
	doBlock([], this);
	return new CachedSource(source);
};

NormalModule.prototype.needRebuild = function needRebuild(fileTimestamps, contextTimestamps) {
	var timestamp = 0;
	this.fileDependencies.forEach(function(file) {
		var ts = fileTimestamps[file];
		if(!ts) timestamp = Infinity;
		if(ts > timestamp) timestamp = ts;
	});
	this.contextDependencies.forEach(function(context) {
		var ts = contextTimestamps[context];
		if(!ts) timestamp = Infinity;
		if(ts > timestamp) timestamp = ts;
	});
	return timestamp >= this.buildTimestamp;
};

NormalModule.prototype.size = function() {
	return this._source ? this._source.size() : -1;
};

NormalModule.prototype.updateHash = function(hash) {
	if(this._source) {
		hash.update("source");
		this._source.updateHash(hash);
	} else
		hash.update("null");
	hash.update("meta");
	hash.update(JSON.stringify(this.meta));
	Module.prototype.updateHash.call(this, hash);
};

NormalModule.prototype.getSourceHash = function() {
	if(!this._source) return "";
	var hash = require("crypto").createHash("md5");
	hash.update(this._source.source());
	return hash.digest("hex");
};

NormalModule.prototype.getAllModuleDependencies = function() {
	var list = [];

	function doDep(dep) {
		if(dep.module && list.indexOf(dep.module) < 0)
			list.push(dep.module);
	}

	function doVariable(variable) {
		variable.dependencies.forEach(doDep);
	}

	function doBlock(block) {
		block.variables.forEach(doVariable);
		block.dependencies.forEach(doDep);
		block.blocks.forEach(doBlock);
	}
	doBlock(this);
	return list;
};

NormalModule.prototype.createTemplate = function(keepModules, roots) {
	roots.sort(function(a, b) {
		var ia = a.identifier();
		var ib = b.identifier();
		if(ia < ib) return -1;
		if(ib < ia) return 1;
		return 0;
	});
	var template = new NormalModule("", "", "", [], "", null);
	template._source = this._source;
	template.built = this.built;
	template.templateModules = keepModules;
	template._templateOrigin = this;
	template.readableIdentifier = function() {
		return "template of " + this._templateOrigin.id + " referencing " + keepModules.map(function(m) {
			return m.id;
		}).join(", ");
	};
	template.identifier = function() {
		var array = roots.map(function(m) {
			return m.identifier();
		});
		array.sort();
		return array.join("|");
	};
	var args = template.arguments = [];

	function doDeps(deps) {
		return deps.map(function(dep) {
			if(dep.module && keepModules.indexOf(dep.module) < 0) {
				var argName = "__webpack_module_template_argument_" + args.length + "__";
				args.push(argName);
				return new TemplateArgumentDependency(argName, dep);
			} else {
				return dep;
			}
		});
	}

	function doBlock(block, newBlock) {
		block.variables.forEach(function(variable) {
			var newDependencies = doDeps(variable.dependencies);
			newBlock.addVariable(variable.name, variable.expression, newDependencies);
		});
		newBlock.dependencies = doDeps(block.dependencies);
		block.blocks.forEach(function(childBlock) {
			var newChildBlock = new AsyncDependenciesBlock(childBlock.name, childBlock.module, childBlock.loc);
			newBlock.addBlock(newChildBlock);
			doBlock(childBlock, newChildBlock);
		});
	}
	doBlock(this, template);
	return template;
};

NormalModule.prototype.getTemplateArguments = function(keepModules) {
	var list = [];

	function doDep(dep) {
		if(dep.module && keepModules.indexOf(dep.module) < 0)
			list.push(dep.module);
	}

	function doVariable(variable) {
		variable.dependencies.forEach(doDep);
	}

	function doBlock(block) {
		block.variables.forEach(doVariable);
		block.dependencies.forEach(doDep);
		block.blocks.forEach(doBlock);
	}
	doBlock(this);
	return list;
};
<|endoftext|>


<commit_before>import { getAllTestsInClass } from '../helpers/viewHelpers.js';

var objToArray = function(obj) {
  return Object.keys(obj).map(function(key) {
    return obj[key];
  });
};

exports.processData = function(classId) {
  return getAllTestsInClass(classId).then(function(allTestsFromClass) {
    var allTestData = {};
    // console.log('allTestsFromClass: ', allTestsFromClass);

    for (var key in allTestsFromClass.data[0].answerKeys) {
      allTestData[key] = {id: allTestsFromClass.data[0].answerKeys[key].keyId,
                          name: allTestsFromClass.data[0].answerKeys[key].keyName,  // This will be name in the future.
                          correctAnswers: objToArray(JSON.parse(allTestsFromClass.data[0].answerKeys[key].answers)),
                          studentTestResults: [],
                          studentTestScores: []
                         };
    };

    allTestsFromClass.data[0].students.forEach(function(student) {
      var studentId = student.StudentId;
      var studentName = student.StudentName;

      student.tests.forEach(function(item) {
        var test = {};
        // test.testId = item.id;
        test.student = {id: studentId, name: studentName};
        test.studentScore = Math.round(item.result * 100);
        test.studentAnswers = objToArray(JSON.parse(item.studentAnswers));
        test.imageUrl = item.URL;
        test.answerKeyId = item.answerKeyId;

        for (var key in allTestData) {
          if (Number(allTestData[key].id) === Number(test.answerKeyId)) {
            allTestData[key].studentTestResults.push(test);
            allTestData[key].studentTestScores.push(test.studentScore);
          }
        }
      });
    });
    // console.log('Final allTestData object after processing: ', allTestData);
    return allTestData;
  });
};

exports.prepStudentAnswersForTest = function(allTestData) {
  console.log('Im Inside prepStudentAnswersForTest and allTestData is: ', allTestData);
  return allTestData[0].studentTestResults.map(function(item) {
    return item.studentAnswers;
  });
}

// exports.getCorrectAnswerForTestQuestion = function(allTestData, testId, questionOfInterest) {
//   //        indexOfTestInfo
//   console.log('1: ', gaussData[testId - 1]);
//   console.log('2: ', gaussData[testId - 1].correctAnswers);
//   console.log('3: ', gaussData[testId - 1].correctAnswers[questionOfInterest - 1]);
//   return allTestData[testId - 1].correctAnswers[questionOfInterest - 1][0];
// }

exports.responseFrequency = function(studentAnswersForTest, questionOfInterest) {
  // console.log('studentAnswersForTest: ', studentAnswersForTest);

  var totalFrequencyCount = [];
  for (var i = 0; i < studentAnswersForTest[0].length; i++) {
    var singleFrequencyCount = [
      {name: 'A', value: 0},
      {name: 'B', value: 0},
      {name: 'C', value: 0},
      {name: 'D', value: 0},
      {name: 'E', value: 0}
    ];
    totalFrequencyCount[i] = singleFrequencyCount;
  }

  studentAnswersForTest.forEach(function(answerSet) {
    answerSet.forEach(function(answer, index) {
      if (answer[0] === 'a') {         // Maybe use .contains here instead for questions with more than one answer?
        totalFrequencyCount[index][0].value++;
      } else if (answer[0] === 'b') {  // Maybe use .contains here instead for questions with more than one answer?
        totalFrequencyCount[index][1].value++;
      } else if (answer[0] === 'c') {  // Maybe use .contains here instead for questions with more than one answer?
        totalFrequencyCount[index][2].value++;
      } else if (answer[0] === 'd') {  // Maybe use .contains here instead for questions with more than one answer?
        totalFrequencyCount[index][3].value++;
      } else if (answer[0] === 'e') {  // Maybe use .contains here instead for questions with more than one answer?
        totalFrequencyCount[index][4].value++;
      }
    });
  });
    // console.log('------', totalFrequencyCount);
  return totalFrequencyCount[questionOfInterest - 1];
}

// // --------------------------------------------------------------------------------
// // Formulas for Statistical Variables:
// // --------------------------------------------------------------------------------

// Sum
exports.sum = (arrayOfGrades) => d3.sum(arrayOfGrades, 'Accessor Function Here!');

// Mean
exports.mean = (arrayOfGrades) => d3.mean(arrayOfGrades, 'Accessor Function Here!');

// Median
exports.median = (arrayOfGrades) => d3.median(arrayOfGrades, 'Accessor Function Here!');

// Standard Deviation
exports.stdDev = (arrayOfGrades) => d3.deviation(arrayOfGrades, 'Acessore Function Here!');

// Variance
exports.variance = (arrayOfGrades) => d3.variance(arrayOfGrades, 'Acessore Function Here!');

// Quantiles, where p is a number in the range [0, 1].
exports.quantile = (arrayOfGrades) => d3.quantile(arrayOfGrades, p, 'Acessore Function Here!');
// Example: p = 0.25 is the first quantile, Q1.
//          p = 0.75 is the third quantile, Q3.

// Test Item Difficulty
exports.singleItemDifficulty = function(allTestData, testId, responseFrequency, studentAnswersForEntireTest, questionOfInterest) {
  // Assume item is worth 1 point.
  var fullScoreForItem = 1;
  // var fullScoreForItem = (1 / studentAnswersForEntireTest[0].length) * 100;
  console.log('Question of Interest: ', questionOfInterest);
  var correctChoice = allTestData[testId - 1].correctAnswers[questionOfInterest - 1][0];
  console.log('Correct Choice: ', correctChoice);

  var numIncorrect = responseFrequency.reduce(function(acc, curr) {
    if (curr.name.toLowerCase() !== correctChoice) {
      acc += curr.value;
    }
    return acc;
  }, 0);
  // console.log('Number Incorrect: ', numIncorrect);

  // Replace studentAnswersForEntireTest with responseFrequency!!!!
  var averageScoreForItem = (studentAnswersForEntireTest.length - numIncorrect) / studentAnswersForEntireTest.length;
  // console.log('averageScoreForItem: ', averageScoreForItem);
  var itemDifficulty = averageScoreForItem / fullScoreForItem;
  console.log('itemDifficulty #', questionOfInterest, ': ', itemDifficulty);

  return itemDifficulty;
}

const testDifficulty = function(allTestData, testId, studentAnswersForEntireTest) {
      var fullScoreForItem = 1;
      var sumSingleItems = 0;
      var totalPointsForTest = 28;
      console.log('studentAnswersForEntireTest: ', studentAnswersForEntireTest);

      for (var i = 1; i < studentAnswersForEntireTest[0].length; i++) {
        var respFreq2 = responseFrequency(studentAnswersForEntireTest, i);
        sumSingleItems += singleItemDifficulty(allTestData, testId, respFreq2, studentAnswersForEntireTest, i) * fullScoreForItem;
      }

      var totalDifficulty = (1 / totalPointsForTest) * sumSingleItems;

      return totalDifficulty;
    }

// Reliability Coeffecient (Chronbach's Alpha)
exports.alpha = (k, arrayOfArraysOfStudentAnswers, arrayOfGrades) => {'sttuffff'};
// alpha = (k / (k - 1)) * (1 - (sum( sigma2(arrayOfGradesForSignleTestItem))) / sigma2(arrayOfExamGrades) )

<commit_msg>(cleanup) Minor cleanup (WIP)<commit_after>import { getAllTestsInClass } from '../helpers/viewHelpers.js';

var objToArray = function(obj) {
  return Object.keys(obj).map(function(key) {
    return obj[key];
  });
};

exports.processData = function(classId) {
  return getAllTestsInClass(classId).then(function(allTestsFromClass) {
    var allTestData = {};
    // console.log('allTestsFromClass: ', allTestsFromClass);

    for (var key in allTestsFromClass.data[0].answerKeys) {
      allTestData[key] = {id: allTestsFromClass.data[0].answerKeys[key].keyId,
                          name: allTestsFromClass.data[0].answerKeys[key].keyName,  // This will be name in the future.
                          correctAnswers: objToArray(JSON.parse(allTestsFromClass.data[0].answerKeys[key].answers)),
                          studentTestResults: [],
                          studentTestScores: []
                         };
    };

    allTestsFromClass.data[0].students.forEach(function(student) {
      var studentId = student.StudentId;
      var studentName = student.StudentName;

      student.tests.forEach(function(item) {
        var test = {};
        // test.testId = item.id;
        test.student = {id: studentId, name: studentName};
        test.studentScore = Math.round(item.result * 100);
        test.studentAnswers = objToArray(JSON.parse(item.studentAnswers));
        test.imageUrl = item.URL;
        test.answerKeyId = item.answerKeyId;

        for (var key in allTestData) {
          if (Number(allTestData[key].id) === Number(test.answerKeyId)) {
            allTestData[key].studentTestResults.push(test);
            allTestData[key].studentTestScores.push(test.studentScore);
          }
        }
      });
    });
    // console.log('Final allTestData object after processing: ', allTestData);
    return allTestData;
  });
};

exports.prepStudentAnswersForTest = function(allTestData) {
  console.log('Im Inside prepStudentAnswersForTest and allTestData is: ', allTestData);
  return allTestData[0].studentTestResults.map(function(item) {
    return item.studentAnswers;
  });
}

// exports.getCorrectAnswerForTestQuestion = function(allTestData, testId, questionOfInterest) {
//   //        indexOfTestInfo
//   console.log('1: ', gaussData[testId - 1]);
//   console.log('2: ', gaussData[testId - 1].correctAnswers);
//   console.log('3: ', gaussData[testId - 1].correctAnswers[questionOfInterest - 1]);
//   return allTestData[testId - 1].correctAnswers[questionOfInterest - 1][0];
// }

exports.responseFrequency = function(studentAnswersForTest, questionOfInterest) {
  // console.log('studentAnswersForTest: ', studentAnswersForTest);

  var totalFrequencyCount = [];
  for (var i = 0; i < studentAnswersForTest[0].length; i++) {
    var singleFrequencyCount = [
      {name: 'A', value: 0},
      {name: 'B', value: 0},
      {name: 'C', value: 0},
      {name: 'D', value: 0},
      {name: 'E', value: 0}
    ];
    totalFrequencyCount[i] = singleFrequencyCount;
  }

  studentAnswersForTest.forEach(function(answerSet) {
    answerSet.forEach(function(answer, index) {
      if (answer[0] === 'a') {         // Maybe use .contains here instead for questions with more than one answer?
        totalFrequencyCount[index][0].value++;
      } else if (answer[0] === 'b') {  // Maybe use .contains here instead for questions with more than one answer?
        totalFrequencyCount[index][1].value++;
      } else if (answer[0] === 'c') {  // Maybe use .contains here instead for questions with more than one answer?
        totalFrequencyCount[index][2].value++;
      } else if (answer[0] === 'd') {  // Maybe use .contains here instead for questions with more than one answer?
        totalFrequencyCount[index][3].value++;
      } else if (answer[0] === 'e') {  // Maybe use .contains here instead for questions with more than one answer?
        totalFrequencyCount[index][4].value++;
      }
    });
  });
    // console.log('------', totalFrequencyCount);
  return totalFrequencyCount[questionOfInterest - 1];
}

// // --------------------------------------------------------------------------------
// // Formulas for Statistical Variables:
// // --------------------------------------------------------------------------------

// Sum
exports.sum = (arrayOfGrades) => d3.sum(arrayOfGrades, 'Accessor Function Here!');

// Mean
exports.mean = (arrayOfGrades) => d3.mean(arrayOfGrades, 'Accessor Function Here!');

// Median
exports.median = (arrayOfGrades) => d3.median(arrayOfGrades, 'Accessor Function Here!');

// Standard Deviation
exports.stdDev = (arrayOfGrades) => d3.deviation(arrayOfGrades, 'Acessore Function Here!');

// Variance
exports.variance = (arrayOfGrades) => d3.variance(arrayOfGrades, 'Acessore Function Here!');

// Quantiles, where p is a number in the range [0, 1].
exports.quantile = (arrayOfGrades) => d3.quantile(arrayOfGrades, p, 'Acessore Function Here!');
// Example: p = 0.25 is the first quantile, Q1.
//          p = 0.75 is the third quantile, Q3.

// Test Item Difficulty
exports.singleItemDifficulty = function(allTestData, testId, responseFrequency, studentAnswersForEntireTest, questionOfInterest) {
  // Assume item is worth 1 point.
  var fullScoreForItem = 1;
  // var fullScoreForItem = (1 / studentAnswersForEntireTest[0].length) * 100;
  console.log('Question of Interest: ', questionOfInterest);
  var correctChoice = allTestData[testId - 1].correctAnswers[questionOfInterest - 1][0];
  console.log('Correct Choice: ', correctChoice);

  var numIncorrect = responseFrequency.reduce(function(acc, curr) {
    if (curr.name.toLowerCase() !== correctChoice) {
      acc += curr.value;
    }
    return acc;
  }, 0);
  // console.log('Number Incorrect: ', numIncorrect);

  // Replace studentAnswersForEntireTest with responseFrequency!!!!
  var averageScoreForItem = (studentAnswersForEntireTest.length - numIncorrect) / studentAnswersForEntireTest.length;
  // console.log('averageScoreForItem: ', averageScoreForItem);
  var itemDifficulty = averageScoreForItem / fullScoreForItem;
  console.log('itemDifficulty #', questionOfInterest, ': ', itemDifficulty);

  return itemDifficulty;
}

const testDifficulty = function(allTestData, testId, studentAnswersForEntireTest) {
  var fullScoreForItem = 1;
  var sumSingleItems = 0;
  var totalPointsForTest = 28;
  console.log('studentAnswersForEntireTest: ', studentAnswersForEntireTest);

  for (var i = 1; i < studentAnswersForEntireTest[0].length; i++) {
    var respFreq2 = responseFrequency(studentAnswersForEntireTest, i);
    sumSingleItems += singleItemDifficulty(allTestData, testId, respFreq2, studentAnswersForEntireTest, i) * fullScoreForItem;
  }

  var totalDifficulty = (1 / totalPointsForTest) * sumSingleItems;

  return totalDifficulty;
}

// Reliability Coeffecient (Chronbach's Alpha)
exports.alpha = (k, arrayOfArraysOfStudentAnswers, arrayOfGrades) => {'sttuffff'};
// alpha = (k / (k - 1)) * (1 - (sum( sigma2(arrayOfGradesForSignleTestItem))) / sigma2(arrayOfExamGrades) )

<|endoftext|>