<commit_before>/**
*
*  Grab space with your hands
*
*/

THREE.LeapTwoFistControls = (function () {

  var X_AXIS = new THREE.Vector3(1, 0, 0);
  var Y_AXIS = new THREE.Vector3(0, 1, 0);
  var Z_AXIS = new THREE.Vector3(0, 0, 1);

  var LeapTwoFistControls = function (object, controller) {
    this.object = object;
    this.controller = controller;
    this.anchorHands = [];
    this.vector = new THREE.Vector3();
    this.matrix = new THREE.Matrix4();
    this.quaternion = new THREE.Quaternion();
    this.rotationMomentum = new THREE.Quaternion();
    this.translationMomentum = new THREE.Vector3();
    this.rotationMomentum = this.object.quaternion.clone();
    this.negate = true;
  }

  LeapTwoFistControls.prototype.update = function() {
    var self = this;
    var frame = this.controller.frame();

    // do we have a frame
    if (!frame || !frame.valid) {
      return;
    }

    var filteredHands;
    var anchorHands = this.anchorHands;
    var persistentHands = [];
    // match hands to anchors
    // remove hands that have disappeared
    // add hands that have appeared

    filteredHands = frame.hands.filter(function (h) {
      return self.isFist(h);
      // return true;
    });
    filteredHands.forEach(function (hand, hIdx) {
      var matched = false;
      anchorHands.some(function (anchorHand, ahIdx) {
        if (anchorHand.id == hand.id) {
          persistentHands[ahIdx] = hand;
          matched = true
        }
        return matched;
      });
    });

    var aHands = [];
    persistentHands.forEach(function (hand, i) {
      aHands.push(anchorHands[i]);
    });

    if (persistentHands.length) {

      var translation = this.getTranslation(aHands, persistentHands);
      var scale = this.getScale(aHands, persistentHands);
      var rotation = this.getRotation(aHands, persistentHands);

      // console.log("trans:", translation);
      // console.log("scale:", scale);
      // console.log("rotation:", rotation);

      // scale
      // this.object.fov /= scale[3];
      // this.object.updateProjectionMatrix();

      // rotation
      // this.quaternion.setFromAxisAngle(X_AXIS, -rotation[0]);
      // this.rotationMomentum.multiply(this.quaternion);
      this.quaternion.setFromAxisAngle(Y_AXIS, rotation[1]);
      this.rotationMomentum.multiply(this.quaternion);
      this.quaternion.setFromAxisAngle(Z_AXIS, -rotation[2]);
      this.rotationMomentum.multiply(this.quaternion);

      // translation

      this.vector.fromArray(translation);
      if (this.negate) {
        this.vector.negate();
      }
      this.vector.applyQuaternion(this.object.quaternion);
      this.translationMomentum.add(this.vector);
    }

    // set reference for next frame
    this.anchorHands = filteredHands;

    // translation
    this.object.position.add(this.translationMomentum);

    // rotation
    this.object.quaternion.slerp(this.rotationMomentum, 0.15);
    this.object.quaternion.normalize();

    // decay momentum
    this.translationMomentum.multiplyScalar(0.95);
  }

  LeapTwoFistControls.prototype.isFist = function (hands) {
    return hands.fingers.length == 0;
  }

  LeapTwoFistControls.prototype.getCenter = function(hands) {
    var l = hands.length;
    if (l == 0) {
      return [0, 0, 0];
    } else if (l == 1) {
      return hands[0].palmPosition;
    }

    var x = y = z = 0;
    hands.forEach(function (hand, i) {
      x += hand.palmPosition[0];
      y += hand.palmPosition[1];
      z += hand.palmPosition[2];
    });
    return [x/l, y/l, z/l];
  }

  LeapTwoFistControls.prototype.getTranslation = function(anchorHands, hands) {
    var centerAnchor = this.getCenter(anchorHands);
    var centerCurrent = this.getCenter(hands);
    return [
      centerCurrent[0] - centerAnchor[0],
      centerCurrent[1] - centerAnchor[1],
      centerCurrent[2] - centerAnchor[2]
    ];
  }

  LeapTwoFistControls.prototype.getScale = function(anchorHands, hands) {
    if (hands.length < 2 || anchorHands.length < 2) {
      return [1, 1, 1, 1];
    }

    var centerAnchor = this.getCenter(anchorHands);
    var centerCurrent = this.getCenter(hands);
    var aveRadiusAnchor = aveDistance(centerAnchor, anchorHands);
    var aveRadiusCurrent = aveDistance(centerCurrent, hands);

    // scale of current over previous
    return [
      aveRadiusCurrent[0] / aveRadiusAnchor[0],
      aveRadiusCurrent[1] / aveRadiusAnchor[1],
      aveRadiusCurrent[2] / aveRadiusAnchor[2],
      length(aveRadiusCurrent) / length(aveRadiusAnchor)
    ];
  }

  LeapTwoFistControls.prototype.getRotation = function(anchorHands, hands) {
    if (hands.length < 2 || anchorHands.length < 2) {
      return [0, 0, 0];
    }

    var anchorAngles = getAngles(anchorHands);
    var angles = getAngles(hands);

    return [
      angles[0] - anchorAngles[0],
      angles[1] - anchorAngles[1],
      angles[2] - anchorAngles[2]
    ];
  }

  function getAngles(hands) {
    var pos1 = hands[0].palmPosition;
    var pos2 = hands[1].palmPosition;

    var dx = pos2[0] - pos1[0];
    var dy = pos2[1] - pos1[1];
    var dz = pos2[2] - pos1[2];

    return [Math.atan2(dz, dy), Math.atan2(dz, dx), Math.atan2(dy, dx)];
  }

  function aveDistance(center, hands) {
    var aveDistance = [0, 0, 0];
    hands.forEach(function (hand) {
      var p = hand.palmPosition;
      aveDistance[0] += Math.abs(p[0] - center[0]);
      aveDistance[1] += Math.abs(p[1] - center[1]);
      aveDistance[2] += Math.abs(p[2] - center[2]);
    });
    aveDistance[0] /= hands.length;
    aveDistance[1] /= hands.length;
    aveDistance[2] /= hands.length;
    return aveDistance;
  }

  function length(arr) {
    var sum = 0;
    arr.forEach(function (v) {
      sum += v * v;
    });
    return Math.sqrt(sum);
  }

  function dist(arr1, arr2) {
    var sum = 0;
    arr1.forEach(function (v, i) {
      var d = v - arr2[i];
      sum += d * d;
    });
    return Math.sqrt(sum);
  }

  return LeapTwoFistControls;
}());
<commit_msg>clean up rotation, require minimum distance from axis<commit_after>/**
*
*  Grab space with your hands
*
*/

THREE.LeapTwoFistControls = (function () {

  var MIN_ROT_MAG_SQ = 0.5;
  var X_AXIS = new THREE.Vector3(1, 0, 0);
  var Y_AXIS = new THREE.Vector3(0, 1, 0);
  var Z_AXIS = new THREE.Vector3(0, 0, 1);

  var LeapTwoFistControls = function (object, controller) {
    this.object = object;
    this.controller = controller;
    this.anchorHands = [];
    this.vector = new THREE.Vector3();
    this.matrix = new THREE.Matrix4();
    this.quaternion = new THREE.Quaternion();
    this.rotationMomentum = new THREE.Quaternion();
    this.translationMomentum = new THREE.Vector3();
    this.rotationMomentum = this.object.quaternion.clone();
    this.negate = true;
  }

  LeapTwoFistControls.prototype.update = function() {
    var self = this;
    var frame = this.controller.frame();

    // do we have a frame
    if (!frame || !frame.valid) {
      return;
    }

    // match hands to anchors
    // remove hands that have disappeared
    // add hands that have appeared
    var anchorHands = this.anchorHands;
    var filteredHands = frame.hands.filter(function (h) {
      return h.valid && self.isFist(h);
    });

    var aHands = [];
    var persistentHands = [];

    filteredHands.forEach(function (hand, hIdx) {
      var matched = false;
      anchorHands.some(function (anchorHand, ahIdx) {
        if (anchorHand.id == hand.id) {
          persistentHands.push(hand);
          aHands.push(anchorHand);
          matched = true
        }
        return matched;
      });
    });

    if (persistentHands.length) {

      var translation = this.getTranslation(aHands, persistentHands);
      var scale = this.getScale(aHands, persistentHands);
      var rotation = this.getRotation(aHands, persistentHands);

      // console.log("trans:", translation);
      // console.log("scale:", scale);
      // console.log("rotation:", rotation);

      // scale
      // this.object.fov /= scale[3];
      // this.object.updateProjectionMatrix();

      // rotation
      // this.quaternion.setFromAxisAngle(X_AXIS, -rotation[0]);
      // this.rotationMomentum.multiply(this.quaternion);
      this.quaternion.setFromAxisAngle(Y_AXIS, rotation[1]);
      this.rotationMomentum.multiply(this.quaternion);
      this.quaternion.setFromAxisAngle(Z_AXIS, -rotation[2]);
      this.rotationMomentum.multiply(this.quaternion);

      // translation

      this.vector.fromArray(translation);
      if (this.negate) {
        this.vector.negate();
      }
      this.vector.applyQuaternion(this.object.quaternion);
      this.translationMomentum.add(this.vector);
    }

    // set reference for next frame
    this.anchorHands = filteredHands;

    // translation
    this.object.position.add(this.translationMomentum);
    this.translationMomentum.multiplyScalar(0.9);

    // rotation
    this.object.quaternion.slerp(this.rotationMomentum, 0.15);
    this.object.quaternion.normalize();
  }

  LeapTwoFistControls.prototype.isFist = function (hands) {
    return hands.fingers.length == 0;
  }

  LeapTwoFistControls.prototype.getCenter = function(hands) {
    var l = hands.length;
    if (l == 0) {
      return [0, 0, 0];
    } else if (l == 1) {
      return hands[0].palmPosition;
    }

    var x = y = z = 0;
    hands.forEach(function (hand, i) {
      x += hand.palmPosition[0];
      y += hand.palmPosition[1];
      z += hand.palmPosition[2];
    });
    return [x/l, y/l, z/l];
  }

  LeapTwoFistControls.prototype.getTranslation = function(anchorHands, hands) {
    if (anchorHands.length != hands.length) {
      return [0, 0, 0];
    }
    var centerAnchor = this.getCenter(anchorHands);
    var centerCurrent = this.getCenter(hands);
    return [
      centerCurrent[0] - centerAnchor[0],
      centerCurrent[1] - centerAnchor[1],
      centerCurrent[2] - centerAnchor[2]
    ];
  }

  LeapTwoFistControls.prototype.getScale = function(anchorHands, hands) {
    if (hands.length < 2 || anchorHands.length < 2) {
      return [1, 1, 1, 1];
    }

    var centerAnchor = this.getCenter(anchorHands);
    var centerCurrent = this.getCenter(hands);
    var aveRadiusAnchor = aveDistance(centerAnchor, anchorHands);
    var aveRadiusCurrent = aveDistance(centerCurrent, hands);

    // scale of current over previous
    return [
      aveRadiusCurrent[0] / aveRadiusAnchor[0],
      aveRadiusCurrent[1] / aveRadiusAnchor[1],
      aveRadiusCurrent[2] / aveRadiusAnchor[2],
      length(aveRadiusCurrent) / length(aveRadiusAnchor)
    ];
  }

  LeapTwoFistControls.prototype.getRotation = function(anchorHands, hands) {
    if (hands.length < 2 || anchorHands.length < 2) {
      return [0, 0, 0];
    }

    var anchorAngles = getAngles(anchorHands);
    var angles = getAngles(hands);

    return [
      angles[0] - anchorAngles[0],
      angles[1] - anchorAngles[1],
      angles[2] - anchorAngles[2]
    ];
  }

  function getAngles(hands) {
    var pos1 = hands[0].palmPosition;
    var pos2 = hands[1].palmPosition;

    var dx = pos2[0] - pos1[0];
    var dy = pos2[1] - pos1[1];
    var dz = pos2[2] - pos1[2];
    var mag = dx * dx + dy * dy + dz * dz;

    var ax = (dz * dz + dy * dy) / mag > MIN_ROT_MAG_SQ ? Math.atan2(dz, dy) : 0;
    var ay = (dz * dz + dx * dx) / mag > MIN_ROT_MAG_SQ ? Math.atan2(dz, dx) : 0;
    var az = (dy * dy + dx * dx) / mag > MIN_ROT_MAG_SQ ? Math.atan2(dy, dx) : 0;

    return [ax, ay, az];
  }

  function aveDistance(center, hands) {
    var aveDistance = [0, 0, 0];
    hands.forEach(function (hand) {
      var p = hand.palmPosition;
      aveDistance[0] += Math.abs(p[0] - center[0]);
      aveDistance[1] += Math.abs(p[1] - center[1]);
      aveDistance[2] += Math.abs(p[2] - center[2]);
    });
    aveDistance[0] /= hands.length;
    aveDistance[1] /= hands.length;
    aveDistance[2] /= hands.length;
    return aveDistance;
  }

  function length(arr) {
    var sum = 0;
    arr.forEach(function (v) {
      sum += v * v;
    });
    return Math.sqrt(sum);
  }

  function dist(arr1, arr2) {
    var sum = 0;
    arr1.forEach(function (v, i) {
      var d = v - arr2[i];
      sum += d * d;
    });
    return Math.sqrt(sum);
  }

  return LeapTwoFistControls;
}());
<|endoftext|>


<commit_before>/* Autogenerated with Kurento Idl */

/*
 * (C) Copyright 2013-2015 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the GNU Lesser General Public License (LGPL)
 * version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

var inherits = require('inherits');

var kurentoClient = require('kurento-client');

var checkType      = kurentoClient.checkType;
var ChecktypeError = checkType.ChecktypeError;

var Transaction = kurentoClient.TransactionsManager.Transaction;

var Filter = kurentoClient.register.abstracts.Filter;

function noop(error, result) {
  if (error) console.trace(error);

  return result
};

/**
 * Create a {@link module:platedetector.PlateDetectorFilter PlateDetectorFilter}
 *
 * @classdesc
 *  PlateDetectorFilter interface. This type of {@link
 *  module:core/abstracts.Endpoint Endpoint} detects
 *  vehicle plates in a video feed.
 *
 * @extends module:core/abstracts.Filter
 *
 * @constructor module:platedetector.PlateDetectorFilter
 *
 * @fires {@link module:platedetector#event:PlateDetected PlateDetected}
 */
function PlateDetectorFilter(){
  PlateDetectorFilter.super_.call(this);
};
inherits(PlateDetectorFilter, Filter);

//
// Public methods
//

/**
 * Configures the average width of the license plates in the image represented
 * as an image percentage.
 *
 * @alias module:platedetector.PlateDetectorFilter.setPlateWidthPercentage
 *
 * @param {external:Number} plateWidthPercentage
 *  average width of the license plates represented as an image percentage
 *  [0..1].
 *
 * @param {module:platedetector.PlateDetectorFilter~setPlateWidthPercentageCallback} [callback]
 *
 * @return {external:Promise}
 */
PlateDetectorFilter.prototype.setPlateWidthPercentage = function(plateWidthPercentage, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  checkType('float', 'plateWidthPercentage', plateWidthPercentage, {required: true});

  var params = {
    plateWidthPercentage: plateWidthPercentage
  };

  callback = (callback || noop).bind(this)

  return this._invoke(transaction, 'setPlateWidthPercentage', params, callback);
};
/**
 * @callback module:platedetector.PlateDetectorFilter~setPlateWidthPercentageCallback
 * @param {external:Error} error
 */

/**
 * @alias module:platedetector.PlateDetectorFilter.constructorParams
 *
 * @property {module:core.MediaPipeline} mediaPipeline
 *  the parent {@link module:core.MediaPipeline MediaPipeline} of this {@link
 *  module:platedetector.PlateDetectorFilter PlateDetectorFilter}
 */
PlateDetectorFilter.constructorParams = {
  mediaPipeline: {
    type: 'MediaPipeline',
    required: true
  }
};

/**
 * @alias module:platedetector.PlateDetectorFilter.events
 *
 * @extends module:core/abstracts.Filter.events
 */
PlateDetectorFilter.events = Filter.events.concat(['PlateDetected']);

/**
 * Checker for {@link platedetector.PlateDetectorFilter}
 *
 * @memberof module:platedetector
 *
 * @param {external:String} key
 * @param {module:platedetector.PlateDetectorFilter} value
 */
function checkPlateDetectorFilter(key, value)
{
  if(!(value instanceof PlateDetectorFilter))
    throw ChecktypeError(key, PlateDetectorFilter, value);
};

module.exports = PlateDetectorFilter;

PlateDetectorFilter.check = checkPlateDetectorFilter;
<commit_msg>Generated code from kms-platedetector 60cbbd660a3d212d6fab0ae149a7b47871ab9917<commit_after>/* Autogenerated with Kurento Idl */

/*
 * (C) Copyright 2013-2015 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the GNU Lesser General Public License (LGPL)
 * version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

var inherits = require('inherits');

var kurentoClient = require('kurento-client');

var disguise = kurentoClient.disguise;

var checkType      = kurentoClient.checkType;
var ChecktypeError = checkType.ChecktypeError;

var Transaction = kurentoClient.TransactionsManager.Transaction;

var Filter = kurentoClient.register.abstracts.Filter;

function noop(error, result) {
  if (error) console.trace(error);

  return result
};

/**
 * Create a {@link module:platedetector.PlateDetectorFilter PlateDetectorFilter}
 *
 * @classdesc
 *  PlateDetectorFilter interface. This type of {@link
 *  module:core/abstracts.Endpoint Endpoint} detects
 *  vehicle plates in a video feed.
 *
 * @extends module:core/abstracts.Filter
 *
 * @constructor module:platedetector.PlateDetectorFilter
 *
 * @fires {@link module:platedetector#event:PlateDetected PlateDetected}
 */
function PlateDetectorFilter(){
  PlateDetectorFilter.super_.call(this);
};
inherits(PlateDetectorFilter, Filter);

//
// Public methods
//

/**
 * Configures the average width of the license plates in the image represented
 * as an image percentage.
 *
 * @alias module:platedetector.PlateDetectorFilter.setPlateWidthPercentage
 *
 * @param {external:Number} plateWidthPercentage
 *  average width of the license plates represented as an image percentage
 *  [0..1].
 *
 * @param {module:platedetector.PlateDetectorFilter~setPlateWidthPercentageCallback} [callback]
 *
 * @return {external:Promise}
 */
PlateDetectorFilter.prototype.setPlateWidthPercentage = function(plateWidthPercentage, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  checkType('float', 'plateWidthPercentage', plateWidthPercentage, {required: true});

  var params = {
    plateWidthPercentage: plateWidthPercentage
  };

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'setPlateWidthPercentage', params, callback), this)
};
/**
 * @callback module:platedetector.PlateDetectorFilter~setPlateWidthPercentageCallback
 * @param {external:Error} error
 */

/**
 * @alias module:platedetector.PlateDetectorFilter.constructorParams
 *
 * @property {module:core.MediaPipeline} mediaPipeline
 *  the parent {@link module:core.MediaPipeline MediaPipeline} of this {@link
 *  module:platedetector.PlateDetectorFilter PlateDetectorFilter}
 */
PlateDetectorFilter.constructorParams = {
  mediaPipeline: {
    type: 'MediaPipeline',
    required: true
  }
};

/**
 * @alias module:platedetector.PlateDetectorFilter.events
 *
 * @extends module:core/abstracts.Filter.events
 */
PlateDetectorFilter.events = Filter.events.concat(['PlateDetected']);

/**
 * Checker for {@link platedetector.PlateDetectorFilter}
 *
 * @memberof module:platedetector
 *
 * @param {external:String} key
 * @param {module:platedetector.PlateDetectorFilter} value
 */
function checkPlateDetectorFilter(key, value)
{
  if(!(value instanceof PlateDetectorFilter))
    throw ChecktypeError(key, PlateDetectorFilter, value);
};

module.exports = PlateDetectorFilter;

PlateDetectorFilter.check = checkPlateDetectorFilter;
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var jwt = require('jsonwebtoken');
var shiroTrie = require('shiro-trie');

var consts = require('./../constants');

var log_green = '\x1B[32m';
var log_red = '\x1b[31m';
var log_reset = '\x1B[0m';
var LOG_AUTH    = log_green + 'AUTH:    ' + log_reset;
var LOG_GRANTED = log_green + 'GRANTED: ' + log_reset;
var LOG_DENIED  = log_red   + 'DENIED:  ' + log_reset;

function mkopts (opts) {
  var options = opts && !_.isEmpty(opts) ? opts : { };
  if (!options.redirectDeniedURL) {
    options.redirectDeniedURL = null;
  }
  return options;
}

function getRemoteIP (req) {
  return req.headers['x-forwarded-for'] || req.connection.remoteAddress
}

function init (env, ctx) {
  var authorization = { };
  var storage = authorization.storage = require('./storage')(env, ctx);
  var defaultRoles = (env.settings.authDefaultRoles || '').split(/[, :]/);

  function extractToken (req) {
    var token;
    var authorization = req.header('Authorization');

    if (authorization) {
      var parts = authorization.split(' ');
      if (parts.length === 2 && parts[0] === 'Bearer') {
        token = parts[1];
      }
    }

    if (!token && req.auth_token) {
      token = req.auth_token;
    }

    if (!token) {
      token = authorizeAccessToken(req);
    }

    if (token) {
      req.auth_token = token;
    }

    return token;
  }

  function authorizeAccessToken (req) {

    var accessToken = req.query.token;

    if (!accessToken && req.body) {
      if (_.isArray(req.body) && req.body.length > 0 && req.body[0].token) {
        accessToken = req.body[0].token;
        delete req.body[0].token;
      } else if (req.body.token) {
        accessToken = req.body.token;
        delete req.body.token;
      }
    }

    var authToken = null;

    if (accessToken) {
      // make an auth token on the fly, based on an access token
      var authed = authorization.authorize(accessToken);
      if (authed && authed.token) {
        authToken = authed.token;
      }
    }

    return authToken;
  }

  function adminSecretFromRequest (req) {
    var secret = req.query && req.query.secret ? req.query.secret : req.header('api-secret');

    if (!secret && req.api_secret) {
      //see if we already got the secret from the body, since it gets deleted
      secret = req.api_secret;
    } else if (!secret && req.body) {
      // try to get the secret from the body, but don't leave it there
      if (_.isArray(req.body) && req.body.length > 0 && req.body[0].secret) {
        secret = req.body[0].secret;
        delete req.body[0].secret;
      } else if (req.body.secret) {
        secret = req.body.secret;
        delete req.body.secret;
      }
    }

    if (secret) {
      // store the secret hash on the request since the req may get processed again
      req.api_secret = secret;
    }

    return secret;
  }

 function authorizeAdminSecretWithRequest (req) {
    return authorizeAdminSecret(adminSecretFromRequest(req));
  }

  function authorizeAdminSecret (secret) {
    return (env.api_secret && env.api_secret.length > 12) ? (secret === env.api_secret) : false;
  }

  authorization.seenPermissions = [ ];

  authorization.expandedPermissions = function expandedPermissions ( ) {
    var permissions = shiroTrie.new();
    permissions.add(authorization.seenPermissions);
    return permissions;
  };

  authorization.resolveWithRequest = function resolveWithRequest (req, callback) {
    authorization.resolve({
      api_secret: adminSecretFromRequest(req)
      , token: extractToken(req)
    }, callback);
  };

  authorization.checkMultiple = function checkMultiple(permission, shiros) {
    var found = _.find(shiros, function checkEach (shiro) {
      return shiro && shiro.check(permission);
    });
    return _.isObject(found);
  };

  authorization.resolve = function resolve (data, callback) {

    if (authorizeAdminSecret(data.api_secret)) {
      var admin = shiroTrie.new();
      admin.add(['*']);
      return callback(null, { shiros: [ admin ] });
    }

    var defaultShiros = storage.rolesToShiros(defaultRoles);

    if (data.token) {
      jwt.verify(data.token, env.api_secret, function result(err, verified) {
        if (err) {
          return callback(err, { shiros: [ ] });
        } else {
          var resolved = storage.resolveSubjectAndPermissions(verified.accessToken);
          var shiros = resolved.shiros.concat(defaultShiros);
          return callback(null, { shiros: shiros, subject: resolved.subject });
        }
      });
    } else {
      return callback(null, { shiros: defaultShiros });
    }

  };

  authorization.isPermitted = function isPermitted (permission, opts) {

    opts = mkopts(opts);
    authorization.seenPermissions = _.chain(authorization.seenPermissions)
      .push(permission)
      .sort()
      .uniq()
      .value();

    function check(req, res, next) {

      var remoteIP = getRemoteIP(req);

      if (authorizeAdminSecretWithRequest(req)) {
        console.log(LOG_GRANTED, remoteIP, 'api-secret', permission);
        next( );
        return;
      }

      var token = extractToken(req);
      var defaultShiros = storage.rolesToShiros(defaultRoles);

      if (token) {
        jwt.verify(token, env.api_secret, function result(err, verified) {
          if (err) {
            console.info('Error verifying Authorized Token', err);
            res.status(consts.HTTP_UNAUTHORIZED).send('Unauthorized - Invalid/Missing');
          } else {
            var resolved = storage.resolveSubjectAndPermissions(verified.accessToken);
            if (authorization.checkMultiple(permission, resolved.shiros)) {
              console.log(LOG_GRANTED, remoteIP, verified.accessToken , permission);
              next();
            } else if (authorization.checkMultiple(permission, defaultShiros)) {
              console.log(LOG_GRANTED, remoteIP, verified.accessToken, permission, 'default');
              next( );
            } else {
              console.log(LOG_DENIED, remoteIP, verified.accessToken, permission);
              res.sendJSONStatus(res, consts.HTTP_UNAUTHORIZED, 'Unauthorized', 'Invalid/Missing');
            }
          }
        });
      } else {
        if (authorization.checkMultiple(permission, defaultShiros)) {
          console.log(LOG_GRANTED, remoteIP, 'no-token', permission, 'default');
          return next( );
        }
        console.log(LOG_DENIED, remoteIP, 'no-token', permission);
        res.sendJSONStatus(res, consts.HTTP_UNAUTHORIZED, 'Unauthorized', 'Invalid/Missing');
      }

    }

    return check;
  };

  authorization.authorize = function authorize (accessToken) {
    var subject = storage.findSubject(accessToken);

    var authorized = null;

    if (subject) {
      var token = jwt.sign( { accessToken: subject.accessToken }, env.api_secret, { expiresIn: '1h' } );

      //decode so we can tell the client the issued and expired times
      var decoded = jwt.decode(token);

      var roles = _.uniq(subject.roles.concat(defaultRoles));

      authorized = {
        token: token
        , sub: subject.name
        // not sending roles to client to prevent us from treating them as magic
        // instead group permissions by role so the we can create correct shiros on the client
        , permissionGroups: _.map(roles, storage.roleToPermissions)
        , iat: decoded.iat
        , exp: decoded.exp
      };
    }

    return authorized;
  };

  authorization.endpoints = require('./endpoints')(env, authorization);

  return authorization;
}

module.exports = init;
<commit_msg>codacy<commit_after>'use strict';

var _ = require('lodash');
var jwt = require('jsonwebtoken');
var shiroTrie = require('shiro-trie');

var consts = require('./../constants');

var log_green = '\x1B[32m';
var log_red = '\x1b[31m';
var log_reset = '\x1B[0m';
var LOG_GRANTED = log_green + 'GRANTED: ' + log_reset;
var LOG_DENIED  = log_red   + 'DENIED:  ' + log_reset;

function mkopts (opts) {
  var options = opts && !_.isEmpty(opts) ? opts : { };
  if (!options.redirectDeniedURL) {
    options.redirectDeniedURL = null;
  }
  return options;
}

function getRemoteIP (req) {
  return req.headers['x-forwarded-for'] || req.connection.remoteAddress;
}

function init (env, ctx) {
  var authorization = { };
  var storage = authorization.storage = require('./storage')(env, ctx);
  var defaultRoles = (env.settings.authDefaultRoles || '').split(/[, :]/);

  function extractToken (req) {
    var token;
    var authorization = req.header('Authorization');

    if (authorization) {
      var parts = authorization.split(' ');
      if (parts.length === 2 && parts[0] === 'Bearer') {
        token = parts[1];
      }
    }

    if (!token && req.auth_token) {
      token = req.auth_token;
    }

    if (!token) {
      token = authorizeAccessToken(req);
    }

    if (token) {
      req.auth_token = token;
    }

    return token;
  }

  function authorizeAccessToken (req) {

    var accessToken = req.query.token;

    if (!accessToken && req.body) {
      if (_.isArray(req.body) && req.body.length > 0 && req.body[0].token) {
        accessToken = req.body[0].token;
        delete req.body[0].token;
      } else if (req.body.token) {
        accessToken = req.body.token;
        delete req.body.token;
      }
    }

    var authToken = null;

    if (accessToken) {
      // make an auth token on the fly, based on an access token
      var authed = authorization.authorize(accessToken);
      if (authed && authed.token) {
        authToken = authed.token;
      }
    }

    return authToken;
  }

  function adminSecretFromRequest (req) {
    var secret = req.query && req.query.secret ? req.query.secret : req.header('api-secret');

    if (!secret && req.api_secret) {
      //see if we already got the secret from the body, since it gets deleted
      secret = req.api_secret;
    } else if (!secret && req.body) {
      // try to get the secret from the body, but don't leave it there
      if (_.isArray(req.body) && req.body.length > 0 && req.body[0].secret) {
        secret = req.body[0].secret;
        delete req.body[0].secret;
      } else if (req.body.secret) {
        secret = req.body.secret;
        delete req.body.secret;
      }
    }

    if (secret) {
      // store the secret hash on the request since the req may get processed again
      req.api_secret = secret;
    }

    return secret;
  }

 function authorizeAdminSecretWithRequest (req) {
    return authorizeAdminSecret(adminSecretFromRequest(req));
  }

  function authorizeAdminSecret (secret) {
    return (env.api_secret && env.api_secret.length > 12) ? (secret === env.api_secret) : false;
  }

  authorization.seenPermissions = [ ];

  authorization.expandedPermissions = function expandedPermissions ( ) {
    var permissions = shiroTrie.new();
    permissions.add(authorization.seenPermissions);
    return permissions;
  };

  authorization.resolveWithRequest = function resolveWithRequest (req, callback) {
    authorization.resolve({
      api_secret: adminSecretFromRequest(req)
      , token: extractToken(req)
    }, callback);
  };

  authorization.checkMultiple = function checkMultiple(permission, shiros) {
    var found = _.find(shiros, function checkEach (shiro) {
      return shiro && shiro.check(permission);
    });
    return _.isObject(found);
  };

  authorization.resolve = function resolve (data, callback) {

    if (authorizeAdminSecret(data.api_secret)) {
      var admin = shiroTrie.new();
      admin.add(['*']);
      return callback(null, { shiros: [ admin ] });
    }

    var defaultShiros = storage.rolesToShiros(defaultRoles);

    if (data.token) {
      jwt.verify(data.token, env.api_secret, function result(err, verified) {
        if (err) {
          return callback(err, { shiros: [ ] });
        } else {
          var resolved = storage.resolveSubjectAndPermissions(verified.accessToken);
          var shiros = resolved.shiros.concat(defaultShiros);
          return callback(null, { shiros: shiros, subject: resolved.subject });
        }
      });
    } else {
      return callback(null, { shiros: defaultShiros });
    }

  };

  authorization.isPermitted = function isPermitted (permission, opts) {

    opts = mkopts(opts);
    authorization.seenPermissions = _.chain(authorization.seenPermissions)
      .push(permission)
      .sort()
      .uniq()
      .value();

    function check(req, res, next) {

      var remoteIP = getRemoteIP(req);

      if (authorizeAdminSecretWithRequest(req)) {
        console.log(LOG_GRANTED, remoteIP, 'api-secret', permission);
        next( );
        return;
      }

      var token = extractToken(req);
      var defaultShiros = storage.rolesToShiros(defaultRoles);

      if (token) {
        jwt.verify(token, env.api_secret, function result(err, verified) {
          if (err) {
            console.info('Error verifying Authorized Token', err);
            res.status(consts.HTTP_UNAUTHORIZED).send('Unauthorized - Invalid/Missing');
          } else {
            var resolved = storage.resolveSubjectAndPermissions(verified.accessToken);
            if (authorization.checkMultiple(permission, resolved.shiros)) {
              console.log(LOG_GRANTED, remoteIP, verified.accessToken , permission);
              next();
            } else if (authorization.checkMultiple(permission, defaultShiros)) {
              console.log(LOG_GRANTED, remoteIP, verified.accessToken, permission, 'default');
              next( );
            } else {
              console.log(LOG_DENIED, remoteIP, verified.accessToken, permission);
              res.sendJSONStatus(res, consts.HTTP_UNAUTHORIZED, 'Unauthorized', 'Invalid/Missing');
            }
          }
        });
      } else {
        if (authorization.checkMultiple(permission, defaultShiros)) {
          console.log(LOG_GRANTED, remoteIP, 'no-token', permission, 'default');
          return next( );
        }
        console.log(LOG_DENIED, remoteIP, 'no-token', permission);
        res.sendJSONStatus(res, consts.HTTP_UNAUTHORIZED, 'Unauthorized', 'Invalid/Missing');
      }

    }

    return check;
  };

  authorization.authorize = function authorize (accessToken) {
    var subject = storage.findSubject(accessToken);

    var authorized = null;

    if (subject) {
      var token = jwt.sign( { accessToken: subject.accessToken }, env.api_secret, { expiresIn: '1h' } );

      //decode so we can tell the client the issued and expired times
      var decoded = jwt.decode(token);

      var roles = _.uniq(subject.roles.concat(defaultRoles));

      authorized = {
        token: token
        , sub: subject.name
        // not sending roles to client to prevent us from treating them as magic
        // instead group permissions by role so the we can create correct shiros on the client
        , permissionGroups: _.map(roles, storage.roleToPermissions)
        , iat: decoded.iat
        , exp: decoded.exp
      };
    }

    return authorized;
  };

  authorization.endpoints = require('./endpoints')(env, authorization);

  return authorization;
}

module.exports = init;
<|endoftext|>


<commit_before>var tz = require('timezone');
var calcMealCOB = require('oref0/lib/determine-basal/cob-autosens');
var basal = require('oref0/lib/profile/basal');
var get_iob = require('oref0/lib/iob');
var isf = require('../profile/isf');

function diaCarbs(opts, time) {
    var treatments = opts.treatments;
    var profile_data = opts.profile;
    if (typeof(opts.glucose) !== 'undefined') {
        var glucose_data = opts.glucose;
    }
    if (typeof(opts.prepped_glucose) !== 'undefined') {
        var prepped_glucose_data = opts.prepped_glucose;
    }
    var boluses = 0;
    var carbDelay = 20 * 60 * 1000;
    var maxCarbs = 0;
    var mealCarbTime = time.getTime();
    if (!treatments) return {};

    //console.error(glucose_data);
    var iob_inputs = {
        profile: profile_data
    ,   history: opts.pumphistory
    };
    var COB_inputs = {
        glucose_data: glucose_data
    ,   iob_inputs: iob_inputs
    ,   basalprofile: opts.basalprofile
    ,   mealTime: mealCarbTime
    };
    var mealCOB = 0;
    var csf_glucose_data = [];
    var isf_glucose_data = [];
    var basal_glucose_data = [];

    var bucketed_data = [];
    bucketed_data[0] = glucose_data[0];
    j=0;
    for (var i=1; i < glucose_data.length; ++i) {
        var bgTime;
        var lastbgTime;
        if (glucose_data[i].display_time) {
            bgTime = new Date(glucose_data[i].display_time.replace('T', ' '));
        } else if (glucose_data[i].dateString) {
            bgTime = new Date(glucose_data[i].dateString);
        } else { console.error("Could not determine BG time"); }
        if (glucose_data[i-1].display_time) {
            lastbgTime = new Date(glucose_data[i-1].display_time.replace('T', ' '));
        } else if (glucose_data[i-1].dateString) {
            lastbgTime = new Date(glucose_data[i-1].dateString);
        } else { console.error("Could not determine last BG time"); }
        if (glucose_data[i].glucose < 39 || glucose_data[i-1].glucose < 39) {
            continue;
        }
        var elapsed_minutes = (bgTime - lastbgTime)/(60*1000);
        if(Math.abs(elapsed_minutes) > 2) {
            j++;
            bucketed_data[j]=glucose_data[i];
            bucketed_data[j].date = bgTime.getTime();
        } else {
            bucketed_data[j].glucose = (bucketed_data[j].glucose + glucose_data[i].glucose)/2;
        }
    }
    //console.error(bucketed_data);
    //console.error(bucketed_data[bucketed_data.length-1]);
    absorbing = 0;
    for (var i=bucketed_data.length-4; i > 0; --i) {
        var glucose_datum = bucketed_data[i];
        //console.error(glucose_datum);
        var bgDate = new Date(glucose_datum.date);
        var bgTime = bgDate.getTime();
        // TODO: if there is already a record with bgTime in the prepped_glucose_data, use that
        COB_inputs.bgTime = bgDate;
        mealCOB = 0;
        var carbs = 0;
        treatments.forEach(function(treatment) {
            var dia_ago = bgTime - 1.5*profile_data.dia*60*60*1000;
            var treatmentDate = new Date(tz(treatment.timestamp));
            var treatmentTime = treatmentDate.getTime();
            if (treatmentTime > dia_ago && treatmentTime <= bgTime) {
                if (treatment.carbs >= 1) {
                    //console.error(treatment.carbs, maxCarbs, treatmentDate);
                    carbs += parseFloat(treatment.carbs);
                    COB_inputs.mealTime = treatmentTime;
                    var myCarbsAbsorbed = calcMealCOB(COB_inputs).carbsAbsorbed;
                    //console.error("myCarbsAbsorbed: ",myCarbsAbsorbed);
                    var myMealCOB = Math.max(0, carbs - myCarbsAbsorbed);
                    //console.error("myMealCOB: ",myMealCOB);
                    mealCOB = Math.max(mealCOB, myMealCOB);
                }
                if (treatment.bolus >= 0.1) {
                    boluses += parseFloat(treatment.bolus);
                }
            }
        });

        var bg;
        var avgDelta;
        var delta;
        if (typeof(bucketed_data[i].glucose) != 'undefined') {
            bg = bucketed_data[i].glucose;
            if ( bg < 40 || bucketed_data[i+3].glucose < 40) {
                process.stderr.write("!");
                continue;
            }
            avgDelta = (bg - bucketed_data[i+3].glucose)/3;
            delta = (bg - bucketed_data[i+1].glucose);
        } else { console.error("Could not find glucose data"); }

        avgDelta = avgDelta.toFixed(2);
        glucose_datum.avgDelta = avgDelta;

        var sens = isf.isfLookup(iob_inputs.profile.isfProfile,bgDate);
        iob_inputs.clock=bgDate.toISOString();
        currentBasal = basal.basalLookup(opts.basalprofile, bgDate);
        iob_inputs.profile.current_basal = currentBasal;
        basalBgi = Math.round(( currentBasal * sens / 60 * 5 )*100)/100; // U/hr * mg/dL/U * 1 hr / 60 minutes * 5 = mg/dL/5m
        //console.log(JSON.stringify(iob_inputs.profile));
        var iob = get_iob(iob_inputs)[0];
        //console.error(JSON.stringify(iob));

        var bgi = Math.round(( -iob.activity * sens * 5 )*100)/100;
        glucose_datum.bgi = bgi;
        deviation = avgDelta-bgi;
        deviation = deviation.toFixed(2);
        glucose_datum.deviation = deviation;
        // If mealCOB is zero but all deviations since hitting COB=0 are positive, assign those data points to csf_glucose_data
        // Once deviations go negative for at least one data point after COB=0, we can use the rest of the data to tune ISF or basals
        if (mealCOB > 0 || absorbing) {
            if (deviation > 0) {
                absorbing = 1;
            } else {
                absorbing = 0;
            }
            type="csf";
            csf_glucose_data.push(glucose_datum);
        } else {
            // Go through the remaining time periods and divide them into periods where scheduled basal insulin activity dominates. This would be determined by calculating the BG impact of scheduled basal insulin (for example 1U/hr * 48 mg/dL/U ISF = 48 mg/dL/hr = 5 mg/dL/5m), and comparing that to BGI from bolus and net basal insulin activity.
            // When BGI is positive (insulin activity is negative) or BG is rising, we want to use that data to tune basals
            // When BGI is smaller than about 1/4 of basalBGI, we want to use that data to tune basals
            // When BGI is negative and more than about 1/4 of basalBGI, we can use that data to tune ISF
            //if (basalBgi > -4 * bgi || avgDelta > 0) {
            if (basalBgi > -4 * bgi) {
                type="basal";
                basal_glucose_data.push(glucose_datum);
            } else {
                type="isf";
                isf_glucose_data.push(glucose_datum);
            }
        }
        console.error(absorbing.toString(),"MealCOB:",mealCOB.toFixed(1),"basal BGI:",basalBgi.toFixed(1),"BGI:",bgi.toFixed(1),"at",bgDate, "Dev:",deviation,"avgDelta:",avgDelta,type);
    }

    return {
        csf_glucose_data: csf_glucose_data,
        isf_glucose_data: isf_glucose_data,
        basal_glucose_data: basal_glucose_data
    };
}

exports = module.exports = diaCarbs;

<commit_msg>add mealCarbs and mealAbsorption start/end<commit_after>var tz = require('timezone');
var calcMealCOB = require('oref0/lib/determine-basal/cob-autosens');
var basal = require('oref0/lib/profile/basal');
var get_iob = require('oref0/lib/iob');
var isf = require('../profile/isf');

function diaCarbs(opts, time) {
    var treatments = opts.treatments;
    var profile_data = opts.profile;
    if (typeof(opts.glucose) !== 'undefined') {
        var glucose_data = opts.glucose;
    }
    if (typeof(opts.prepped_glucose) !== 'undefined') {
        var prepped_glucose_data = opts.prepped_glucose;
    }
    var boluses = 0;
    var carbDelay = 20 * 60 * 1000;
    var maxCarbs = 0;
    var mealCarbTime = time.getTime();
    if (!treatments) return {};

    //console.error(glucose_data);
    var iob_inputs = {
        profile: profile_data
    ,   history: opts.pumphistory
    };
    var COB_inputs = {
        glucose_data: glucose_data
    ,   iob_inputs: iob_inputs
    ,   basalprofile: opts.basalprofile
    ,   mealTime: mealCarbTime
    };
    var mealCOB = 0;
    var csf_glucose_data = [];
    var isf_glucose_data = [];
    var basal_glucose_data = [];

    var bucketed_data = [];
    bucketed_data[0] = glucose_data[0];
    j=0;
    for (var i=1; i < glucose_data.length; ++i) {
        var bgTime;
        var lastbgTime;
        if (glucose_data[i].display_time) {
            bgTime = new Date(glucose_data[i].display_time.replace('T', ' '));
        } else if (glucose_data[i].dateString) {
            bgTime = new Date(glucose_data[i].dateString);
        } else { console.error("Could not determine BG time"); }
        if (glucose_data[i-1].display_time) {
            lastbgTime = new Date(glucose_data[i-1].display_time.replace('T', ' '));
        } else if (glucose_data[i-1].dateString) {
            lastbgTime = new Date(glucose_data[i-1].dateString);
        } else { console.error("Could not determine last BG time"); }
        if (glucose_data[i].glucose < 39 || glucose_data[i-1].glucose < 39) {
            continue;
        }
        var elapsed_minutes = (bgTime - lastbgTime)/(60*1000);
        if(Math.abs(elapsed_minutes) > 2) {
            j++;
            bucketed_data[j]=glucose_data[i];
            bucketed_data[j].date = bgTime.getTime();
        } else {
            bucketed_data[j].glucose = (bucketed_data[j].glucose + glucose_data[i].glucose)/2;
        }
    }
    //console.error(bucketed_data);
    //console.error(bucketed_data[bucketed_data.length-1]);
    absorbing = 0;
    var type="";
    for (var i=bucketed_data.length-4; i > 0; --i) {
        var glucose_datum = bucketed_data[i];
        //console.error(glucose_datum);
        var bgDate = new Date(glucose_datum.date);
        var bgTime = bgDate.getTime();
        // TODO: if there is already a record with bgTime in the prepped_glucose_data, use that
        COB_inputs.bgTime = bgDate;
        mealCOB = 0;
        mealCarbs = 0;
        var carbs = 0;
        treatments.forEach(function(treatment) {
            var dia_ago = bgTime - 1.5*profile_data.dia*60*60*1000;
            var treatmentDate = new Date(tz(treatment.timestamp));
            var treatmentTime = treatmentDate.getTime();
            if (treatmentTime > dia_ago && treatmentTime <= bgTime) {
                if (treatment.carbs >= 1) {
                    //console.error(treatment.carbs, maxCarbs, treatmentDate);
                    carbs += parseFloat(treatment.carbs);
                    mealCarbs += parseFloat(treatment.carbs);
                    COB_inputs.mealTime = treatmentTime;
                    var myCarbsAbsorbed = calcMealCOB(COB_inputs).carbsAbsorbed;
                    //console.error("myCarbsAbsorbed: ",myCarbsAbsorbed);
                    var myMealCOB = Math.max(0, carbs - myCarbsAbsorbed);
                    if (myMealCOB == 0) { mealCarbs = 0; }
                    //console.error("myMealCOB: ",myMealCOB);
                    mealCOB = Math.max(mealCOB, myMealCOB);
                }
                if (treatment.bolus >= 0.1) {
                    boluses += parseFloat(treatment.bolus);
                }
            }
        });
        glucose_datum.mealCarbs = mealCarbs;

        var bg;
        var avgDelta;
        var delta;
        if (typeof(bucketed_data[i].glucose) != 'undefined') {
            bg = bucketed_data[i].glucose;
            if ( bg < 40 || bucketed_data[i+3].glucose < 40) {
                process.stderr.write("!");
                continue;
            }
            avgDelta = (bg - bucketed_data[i+3].glucose)/3;
            delta = (bg - bucketed_data[i+1].glucose);
        } else { console.error("Could not find glucose data"); }

        avgDelta = avgDelta.toFixed(2);
        glucose_datum.avgDelta = avgDelta;

        var sens = isf.isfLookup(iob_inputs.profile.isfProfile,bgDate);
        iob_inputs.clock=bgDate.toISOString();
        currentBasal = basal.basalLookup(opts.basalprofile, bgDate);
        iob_inputs.profile.current_basal = currentBasal;
        basalBgi = Math.round(( currentBasal * sens / 60 * 5 )*100)/100; // U/hr * mg/dL/U * 1 hr / 60 minutes * 5 = mg/dL/5m
        //console.log(JSON.stringify(iob_inputs.profile));
        var iob = get_iob(iob_inputs)[0];
        //console.error(JSON.stringify(iob));

        var bgi = Math.round(( -iob.activity * sens * 5 )*100)/100;
        glucose_datum.bgi = bgi;
        deviation = avgDelta-bgi;
        deviation = deviation.toFixed(2);
        glucose_datum.deviation = deviation;
        // If mealCOB is zero but all deviations since hitting COB=0 are positive, assign those data points to csf_glucose_data
        // Once deviations go negative for at least one data point after COB=0, we can use the rest of the data to tune ISF or basals
        if (mealCOB > 0 || absorbing || mealCarbs > 0) {
            if (deviation > 0) {
                absorbing = 1;
            } else {
                absorbing = 0;
            }
            if ( ! absorbing && ! mealCOB ) {
                mealCarbs = 0;
            }
            // check previous "type" value, and if it wasn't csf, set a mealAbsorption start flag
            //console.error(type);
            if ( type != "csf" ) {
                glucose_datum.mealAbsorption = "start";
                console.error(glucose_datum);
            }
            type="csf";
            csf_glucose_data.push(glucose_datum);
        } else {
            // check previous "type" value, and if it was csf, set a mealAbsorption end flag
            if ( type === "csf" ) {
                csf_glucose_data[csf_glucose_data.length-1].mealAbsorption = "end";
                console.error(csf_glucose_data[csf_glucose_data.length-1]);
            }

            // Go through the remaining time periods and divide them into periods where scheduled basal insulin activity dominates. This would be determined by calculating the BG impact of scheduled basal insulin (for example 1U/hr * 48 mg/dL/U ISF = 48 mg/dL/hr = 5 mg/dL/5m), and comparing that to BGI from bolus and net basal insulin activity.
            // When BGI is positive (insulin activity is negative) (or BG is rising?), we want to use that data to tune basals
            // When BGI is smaller than about 1/4 of basalBGI, we want to use that data to tune basals
            // When BGI is negative and more than about 1/4 of basalBGI, we can use that data to tune ISF
            // TODO: figure out if rising BGs work better in basal or ISF
            //if (basalBgi > -4 * bgi || avgDelta > 0) {
            if (basalBgi > -4 * bgi) {
                type="basal";
                basal_glucose_data.push(glucose_datum);
            } else {
                type="isf";
                isf_glucose_data.push(glucose_datum);
            }
        }
        console.error(absorbing.toString(),"MealCOB:",mealCOB.toFixed(1),"MealCarbs:",mealCarbs,"basal BGI:",basalBgi.toFixed(1),"BGI:",bgi.toFixed(1),"at",bgDate, "Dev:",deviation,"avgDelta:",avgDelta,type);
    }

    return {
        csf_glucose_data: csf_glucose_data,
        isf_glucose_data: isf_glucose_data,
        basal_glucose_data: basal_glucose_data
    };
}

exports = module.exports = diaCarbs;

<|endoftext|>


<commit_before>/**
 * @file 检查资源引用路径
 *
 * @author ielgnaw(wuji0223@gmail.com)
 */

var edp = require( 'edp-core' );
var fs = require( 'fs' );

/**
 * 匹配css中图片的正则
 */
var REG_CSS_IMG = /\burl\s*\((["']?)([^\)]+)\1\)/g;

/**
 * 匹配html中图片的正则
 */
var REG_HTML_IMG = /<img[^>]+src\s*=\s*(['\"])([^'\"]+)\1[^>]*>/g;

/**
 * 匹配注释的正则
 * from esl
 */
var REG_COMMENT = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg;

/**
 * 检查引用的资源是否正确
 * @param {string} file 文件的路径.
 */
function checkResouce( file ) {
    var invalidResource = [];

    var pattern = /\.(css|less)$/.test( file ) ? REG_CSS_IMG : REG_HTML_IMG;
    var data = fs.readFileSync( file, 'utf-8' );

    var match = null;
    while ( !!( match = pattern.exec( data ) ) ) {
        data = data.replace(REG_COMMENT, '');
        var url = match[ 2 ];
        if ( !edp.path.isLocalPath( url ) || /(\{[\s\S]*\}|@\w+)/.test( url ) ) {
            continue;
        }

        var resourceUrl = edp.path.normalize(
            edp.path.join( edp.path.dirname( file ), url )
        );
        resourceUrl = resourceUrl.replace( /[#\?].*$/g, '' );
        if ( !fs.existsSync( resourceUrl ) ) {
            invalidResource.push( url );
        }
    }

    function dump( resourceUrl) {
        edp.log.error( '→ %s', resourceUrl );
    }

    if (invalidResource.length) {
        edp.log.info('%s', edp.path.relative( process.cwd(), file ) );
        invalidResource.forEach( dump );
    }
}

module.exports = function(args, opts) {
   edp.log.info( 'Checking resource path...' );

    // 检测src目录以及项目根目录下的css文件和html/tpl文件
    var srcDir = edp.path.join( process.cwd(), 'src' );
    if ( !fs.existsSync( srcDir ) ) {
        edp.log.error( '→ No such dir %s', srcDir );
        return;
    }

    edp.glob.sync([
        '**/*.{css,less,html,htm,vm,phtml,tpl}',
        '!**/output/**',
        '!**/test/**',
        '!**/node_modules/**'
    ]).forEach( checkResouce );
};
<commit_msg>optimize code<commit_after>/**
 * @file 检查资源引用路径
 *
 * @author ielgnaw(wuji0223@gmail.com)
 */

var edp = require( 'edp-core' );
var fs = require( 'fs' );

/**
 * 匹配css中图片的正则
 */
var REG_CSS_IMG = /\burl\s*\((["']?)([^\)]+)\1\)/g;

/**
 * 匹配html中图片的正则
 */
var REG_HTML_IMG = /<img[^>]+src\s*=\s*(['\"])([^'\"]+)\1[^>]*>/g;

/**
 * 匹配注释的正则
 * from esl
 */
var REG_COMMENT = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg;

/**
 * 检查引用的资源是否正确
 * @param {string} file 文件的路径.
 */
function checkResouce( file ) {
    var invalidResource = [];

    var pattern = /\.(css|less)$/.test( file ) ? REG_CSS_IMG : REG_HTML_IMG;
    var data = fs.readFileSync( file, 'utf-8' );

    data = data.replace(REG_COMMENT, '');

    var match = null;
    while ( !!( match = pattern.exec( data ) ) ) {
        var url = match[ 2 ];
        if ( !edp.path.isLocalPath( url ) || /(\{[\s\S]*\}|@\w+)/.test( url ) ) {
            continue;
        }

        var resourceUrl = edp.path.normalize(
            edp.path.join( edp.path.dirname( file ), url )
        );
        resourceUrl = resourceUrl.replace( /[#\?].*$/g, '' );
        if ( !fs.existsSync( resourceUrl ) ) {
            invalidResource.push( url );
        }
    }

    function dump( resourceUrl) {
        edp.log.error( '→ %s', resourceUrl );
    }

    if (invalidResource.length) {
        edp.log.info('%s', edp.path.relative( process.cwd(), file ) );
        invalidResource.forEach( dump );
    }
}

module.exports = function(args, opts) {
   edp.log.info( 'Checking resource path...' );

    // 检测src目录以及项目根目录下的css文件和html/tpl文件
    var srcDir = edp.path.join( process.cwd(), 'src' );
    if ( !fs.existsSync( srcDir ) ) {
        edp.log.error( '→ No such dir %s', srcDir );
        return;
    }

    edp.glob.sync([
        '**/*.{css,less,html,htm,vm,phtml,tpl}',
        '!**/output/**',
        '!**/test/**',
        '!**/node_modules/**'
    ]).forEach( checkResouce );
};
<|endoftext|>


<commit_before>/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Skywriter.
 *
 * The Initial Developer of the Original Code is
 * Mozilla.
 * Portions created by the Initial Developer are Copyright (C) 2009
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Joe Walker (jwalker@mozilla.com)
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

define(function(require, exports, module) {

var editorCss = require("text!cockpit/ui/cli_view.css");
var event = require("pilot/event");
var dom = require("pilot/dom");
dom.importCssString(editorCss);

var event = require("pilot/event");
var keys = require("pilot/keys");
var canon = require("pilot/canon");
var Status = require('pilot/types').Status;

var CliRequisition = require('cockpit/cli').CliRequisition;
var Hint = require('cockpit/cli').Hint;
var RequestView = require('cockpit/ui/request_view').RequestView;

var NO_HINT = new Hint(Status.VALID, '', 0, 0);

/**
 * On startup we need to:
 * 1. Add 3 sets of elements to the DOM for:
 * - command line output
 * - input hints
 * - completion
 * 2. Attach a set of events so the command line works
 */
exports.startup = function(data, reason) {
    var cli = new CliRequisition(data.env);
    var cliView = new CliView(cli, data.env);
};

/**
 * A class to handle the simplest UI implementation
 */
function CliView(cli, env) {
    this.cli = cli;
    this.doc = document;
    this.win = dom.getParentWindow(this.doc);

    // TODO: we should have a better way to specify command lines???
    this.element = this.doc.getElementById('cockpitInput');
    if (!this.element) {
        // console.log('No element with an id of cockpit. Bailing on cli');
        return;
    }

    this.settings = env.settings;
    this.hintDirection = this.settings.getSetting('hintDirection');
    this.outputDirection = this.settings.getSetting('outputDirection');
    this.outputHeight = this.settings.getSetting('outputHeight');

    // If the requisition tells us something has changed, we use this to know
    // if we should ignore it
    this.isUpdating = false;

    this.createElements();
    this.update();
}
CliView.prototype = {
    /**
     * Create divs for completion, hints and output
     */
    createElements: function() {
        var input = this.element;

        this.element.spellcheck = false;

        this.output = this.doc.getElementById('cockpitOutput');
        this.popupOutput = (this.output == null);
        if (!this.output) {
            this.output = this.doc.createElement('div');
            this.output.id = 'cockpitOutput';
            this.output.className = 'cptFocusPopup';
            input.parentNode.insertBefore(this.output, input.nextSibling);

            var setMaxOutputHeight = function() {
                this.output.style.maxHeight = this.outputHeight.get() + 'px';
            }.bind(this);
            this.outputHeight.addEventListener('change', setMaxOutputHeight);
            setMaxOutputHeight();
        }

        this.completer = this.doc.createElement('div');
        this.completer.className = 'cptCompletion VALID';
        ;
        this.completer.style.color = dom.computedStyle(input, "color");
        this.completer.style.fontSize = dom.computedStyle(input, "fontSize");
        this.completer.style.fontFamily = dom.computedStyle(input, "fontFamily");
        this.completer.style.fontWeight = dom.computedStyle(input, "fontWeight");
        this.completer.style.fontStyle = dom.computedStyle(input, "fontStyle");
        input.parentNode.insertBefore(this.completer, input.nextSibling);

        // Transfer background styling to the completer.
        this.completer.style.backgroundColor = input.style.backgroundColor;
        input.style.backgroundColor = 'transparent';

        this.hinter = this.doc.createElement('div');
        this.hinter.className = 'cptHints cptFocusPopup';
        input.parentNode.insertBefore(this.hinter, input.nextSibling);

        var resizer = this.resizer.bind(this);
        event.addListener(this.win, 'resize', resizer);
        this.hintDirection.addEventListener('change', resizer);
        this.outputDirection.addEventListener('change', resizer);
        resizer();

        canon.addEventListener('output',  function(ev) {
            new RequestView(ev.request, this);
        }.bind(this));
        event.addCommandKeyListener(input, this.onCommandKey.bind(this));
        event.addListener(input, 'keyup', this.onKeyUp.bind(this));

        // cursor position affects hint severity. TODO: shortcuts for speed
        event.addListener(input, 'mouseup', function(ev) {
            this.isUpdating = true;
            this.update();
            this.isUpdating = false;
        }.bind(this));

        this.cli.addEventListener('argumentChange', this.onArgChange.bind(this));
    },

    /**
     * We need to see the output of the latest command entered
     */
    scrollOutputToBottom: function() {
        // Certain browsers have a bug such that scrollHeight is too small
        // when content does not fill the client area of the element
        var scrollHeight = Math.max(this.output.scrollHeight, this.output.clientHeight);
        this.output.scrollTop = scrollHeight - this.output.clientHeight;
    },

    /**
     * To be called on window resize or any time we want to align the elements
     * with the input box.
     */
    resizer: function() {
        var rect = this.element.getClientRects()[0];

        this.completer.style.top = rect.top + 'px';
        var height = rect.bottom - rect.top;
        this.completer.style.height = height + 'px';
        this.completer.style.lineHeight = height + 'px';
        this.completer.style.left = rect.left + 'px';
        var width = rect.right - rect.left;
        this.completer.style.width = width + 'px';

        if (this.hintDirection.get() === 'below') {
            this.hinter.style.top = rect.bottom + 'px';
            this.hinter.style.bottom = 'auto';
        }
        else {
            this.hinter.style.top = 'auto';
            this.hinter.style.bottom = (this.doc.documentElement.clientHeight - rect.top) + 'px';
        }
        this.hinter.style.left = (rect.left + 30) + 'px';
        this.hinter.style.maxWidth = (width - 110) + 'px';

        if (this.popupOutput) {
            if (this.outputDirection.get() === 'below') {
                this.output.style.top = rect.bottom + 'px';
                this.output.style.bottom = 'auto';
            }
            else {
                this.output.style.top = 'auto';
                this.output.style.bottom = (this.doc.documentElement.clientHeight - rect.top) + 'px';
            }
            this.output.style.left = rect.left + 'px';
            this.output.style.width = (width - 80) + 'px';
        }
    },

    /**
     * Ensure that TAB isn't handled by the browser
     */
    onCommandKey: function(ev, hashId, keyCode) {
        var handled;
        // var handled = keyboardManager.processKeyEvent(ev, this, {
        //     isCommandLine: true, isKeyUp: false
        // });
        if (keyCode === keys.TAB ||
                keyCode === keys.UP ||
                keyCode === keys.DOWN) {
            event.stopEvent(ev);
        }
        return handled;
    },

    /**
     * The main keyboard processing loop
     */
    onKeyUp: function(ev) {
        var handled;
        /*
        var handled = keyboardManager.processKeyEvent(ev, this, {
            isCommandLine: true, isKeyUp: true
        });
        */

        // RETURN does a special exec/highlight thing
        if (ev.keyCode === keys.RETURN) {
            var worst = this.cli.getWorstHint();
            // Deny RETURN unless the command might work
            if (worst.status === Status.VALID) {
                this.cli.exec();
                this.element.value = '';
            }
            else {
                // If we've denied RETURN because the command was not VALID,
                // select the part of the command line that is causing problems
                // TODO: if there are 2 errors are we picking the right one?
                dom.setSelectionStart(this.element, worst.start);
                dom.setSelectionEnd(this.element, worst.end);
            }
        }

        this.update();

        // Special actions which delegate to the assignment
        var current = this.cli.getAssignmentAt(dom.getSelectionStart(this.element));
        if (current) {
            // TAB does a special complete thing
            if (ev.keyCode === keys.TAB) {
                current.complete();
                this.update();
            }

            // UP/DOWN look for some history
            if (ev.keyCode === keys.UP) {
                current.increment();
                this.update();
            }
            if (ev.keyCode === keys.DOWN) {
                current.decrement();
                this.update();
            }
        }

        return handled;
    },

    /**
     * Actually parse the input and make sure we're all up to date
     */
    update: function() {
        this.isUpdating = true;
        var input = {
            typed: this.element.value,
            cursor: {
                start: dom.getSelectionStart(this.element),
                end: dom.getSelectionEnd(this.element.selectionEnd)
            }
        };
        this.cli.update(input);

        var display = this.cli.getAssignmentAt(input.cursor.start).getHint();

        // 1. Update the completer with prompt/error marker/TAB info
        dom.removeCssClass(this.completer, Status.VALID.toString());
        dom.removeCssClass(this.completer, Status.INCOMPLETE.toString());
        dom.removeCssClass(this.completer, Status.INVALID.toString());

        var completion = '> ';
        if (this.element.value.length > 0) {
            var scores = this.cli.getInputStatusMarkup();
            completion += this.markupStatusScore(scores);
        }

        // Display the "-> prediction" at the end of the completer
        if (this.element.value.length > 0 &&
                display.predictions && display.predictions.length > 0) {
            var tab = display.predictions[0];
            completion += '  ⇥ ' + (tab.name ? tab.name : tab);
        }
        this.completer.innerHTML = completion;
        dom.addCssClass(this.completer, this.cli.getWorstHint().status.toString());

        // 2. Update the hint element
        var hint = '';
        if (this.element.value.length !== 0) {
            hint += display.message;
            if (display.predictions && display.predictions.length > 0) {
                hint += ': [ ';
                display.predictions.forEach(function(prediction) {
                    hint += (prediction.name ? prediction.name : prediction);
                    hint += ' | ';
                }, this);
                hint = hint.replace(/\| $/, ']');
            }
        }

        this.hinter.innerHTML = hint;
        if (hint.length === 0) {
            dom.addCssClass(this.hinter, 'cptNoPopup');
        }
        else {
            dom.removeCssClass(this.hinter, 'cptNoPopup');
        }

        this.isUpdating = false;
    },

    /**
     * Markup an array of Status values with spans
     */
    markupStatusScore: function(scores) {
        var completion = '';
        // Create mark-up
        var i = 0;
        var lastStatus = -1;
        while (true) {
            if (lastStatus !== scores[i]) {
                completion += '';
                lastStatus = scores[i];
            }
            completion += this.element.value[i];
            i++;
            if (i === this.element.value.length) {
                completion += '';
                break;
            }
            if (lastStatus !== scores[i]) {
                completion += '';
            }
        }

        return completion;
    },

    /**
     * Update the input element to reflect the changed argument
     */
    onArgChange: function(ev) {
        if (this.isUpdating) {
            return;
        }

        var prefix = this.element.value.substring(0, ev.argument.start);
        var suffix = this.element.value.substring(ev.argument.end);
        var insert = typeof ev.text === 'string' ? ev.text : ev.text.name;
        this.element.value = prefix + insert + suffix;
        // Fix the cursor.
        var insertEnd = (prefix + insert).length;
        this.element.selectionStart = insertEnd;
        this.element.selectionEnd = insertEnd;
    }
};
exports.CliView = CliView;

});
<commit_msg>Expose Cockpit on the environment<commit_after>/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Skywriter.
 *
 * The Initial Developer of the Original Code is
 * Mozilla.
 * Portions created by the Initial Developer are Copyright (C) 2009
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Joe Walker (jwalker@mozilla.com)
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

define(function(require, exports, module) {

var editorCss = require("text!cockpit/ui/cli_view.css");
var event = require("pilot/event");
var dom = require("pilot/dom");
dom.importCssString(editorCss);

var event = require("pilot/event");
var keys = require("pilot/keys");
var canon = require("pilot/canon");
var Status = require('pilot/types').Status;

var CliRequisition = require('cockpit/cli').CliRequisition;
var Hint = require('cockpit/cli').Hint;
var RequestView = require('cockpit/ui/request_view').RequestView;

var NO_HINT = new Hint(Status.VALID, '', 0, 0);

/**
 * On startup we need to:
 * 1. Add 3 sets of elements to the DOM for:
 * - command line output
 * - input hints
 * - completion
 * 2. Attach a set of events so the command line works
 */
exports.startup = function(data, reason) {
    var cli = new CliRequisition(data.env);
    var cliView = new CliView(cli, data.env);
    data.env.cli = cli;
};

/**
 * A class to handle the simplest UI implementation
 */
function CliView(cli, env) {
    cli.cliView = this;
    this.cli = cli;
    this.doc = document;
    this.win = dom.getParentWindow(this.doc);

    // TODO: we should have a better way to specify command lines???
    this.element = this.doc.getElementById('cockpitInput');
    if (!this.element) {
        // console.log('No element with an id of cockpit. Bailing on cli');
        return;
    }

    this.settings = env.settings;
    this.hintDirection = this.settings.getSetting('hintDirection');
    this.outputDirection = this.settings.getSetting('outputDirection');
    this.outputHeight = this.settings.getSetting('outputHeight');

    // If the requisition tells us something has changed, we use this to know
    // if we should ignore it
    this.isUpdating = false;

    this.createElements();
    this.update();
}
CliView.prototype = {
    /**
     * Create divs for completion, hints and output
     */
    createElements: function() {
        var input = this.element;

        this.element.spellcheck = false;

        this.output = this.doc.getElementById('cockpitOutput');
        this.popupOutput = (this.output == null);
        if (!this.output) {
            this.output = this.doc.createElement('div');
            this.output.id = 'cockpitOutput';
            this.output.className = 'cptFocusPopup';
            input.parentNode.insertBefore(this.output, input.nextSibling);

            var setMaxOutputHeight = function() {
                this.output.style.maxHeight = this.outputHeight.get() + 'px';
            }.bind(this);
            this.outputHeight.addEventListener('change', setMaxOutputHeight);
            setMaxOutputHeight();
        }

        this.completer = this.doc.createElement('div');
        this.completer.className = 'cptCompletion VALID';
        ;
        this.completer.style.color = dom.computedStyle(input, "color");
        this.completer.style.fontSize = dom.computedStyle(input, "fontSize");
        this.completer.style.fontFamily = dom.computedStyle(input, "fontFamily");
        this.completer.style.fontWeight = dom.computedStyle(input, "fontWeight");
        this.completer.style.fontStyle = dom.computedStyle(input, "fontStyle");
        input.parentNode.insertBefore(this.completer, input.nextSibling);

        // Transfer background styling to the completer.
        this.completer.style.backgroundColor = input.style.backgroundColor;
        input.style.backgroundColor = 'transparent';

        this.hinter = this.doc.createElement('div');
        this.hinter.className = 'cptHints cptFocusPopup';
        input.parentNode.insertBefore(this.hinter, input.nextSibling);

        var resizer = this.resizer.bind(this);
        event.addListener(this.win, 'resize', resizer);
        this.hintDirection.addEventListener('change', resizer);
        this.outputDirection.addEventListener('change', resizer);
        resizer();

        canon.addEventListener('output',  function(ev) {
            new RequestView(ev.request, this);
        }.bind(this));
        event.addCommandKeyListener(input, this.onCommandKey.bind(this));
        event.addListener(input, 'keyup', this.onKeyUp.bind(this));

        // cursor position affects hint severity. TODO: shortcuts for speed
        event.addListener(input, 'mouseup', function(ev) {
            this.isUpdating = true;
            this.update();
            this.isUpdating = false;
        }.bind(this));

        this.cli.addEventListener('argumentChange', this.onArgChange.bind(this));
    },

    /**
     * We need to see the output of the latest command entered
     */
    scrollOutputToBottom: function() {
        // Certain browsers have a bug such that scrollHeight is too small
        // when content does not fill the client area of the element
        var scrollHeight = Math.max(this.output.scrollHeight, this.output.clientHeight);
        this.output.scrollTop = scrollHeight - this.output.clientHeight;
    },

    /**
     * To be called on window resize or any time we want to align the elements
     * with the input box.
     */
    resizer: function() {
        var rect = this.element.getClientRects()[0];

        this.completer.style.top = rect.top + 'px';
        var height = rect.bottom - rect.top;
        this.completer.style.height = height + 'px';
        this.completer.style.lineHeight = height + 'px';
        this.completer.style.left = rect.left + 'px';
        var width = rect.right - rect.left;
        this.completer.style.width = width + 'px';

        if (this.hintDirection.get() === 'below') {
            this.hinter.style.top = rect.bottom + 'px';
            this.hinter.style.bottom = 'auto';
        }
        else {
            this.hinter.style.top = 'auto';
            this.hinter.style.bottom = (this.doc.documentElement.clientHeight - rect.top) + 'px';
        }
        this.hinter.style.left = (rect.left + 30) + 'px';
        this.hinter.style.maxWidth = (width - 110) + 'px';

        if (this.popupOutput) {
            if (this.outputDirection.get() === 'below') {
                this.output.style.top = rect.bottom + 'px';
                this.output.style.bottom = 'auto';
            }
            else {
                this.output.style.top = 'auto';
                this.output.style.bottom = (this.doc.documentElement.clientHeight - rect.top) + 'px';
            }
            this.output.style.left = rect.left + 'px';
            this.output.style.width = (width - 80) + 'px';
        }
    },

    /**
     * Ensure that TAB isn't handled by the browser
     */
    onCommandKey: function(ev, hashId, keyCode) {
        var handled;
        // var handled = keyboardManager.processKeyEvent(ev, this, {
        //     isCommandLine: true, isKeyUp: false
        // });
        if (keyCode === keys.TAB ||
                keyCode === keys.UP ||
                keyCode === keys.DOWN) {
            event.stopEvent(ev);
        }
        return handled;
    },

    /**
     * The main keyboard processing loop
     */
    onKeyUp: function(ev) {
        var handled;
        /*
        var handled = keyboardManager.processKeyEvent(ev, this, {
            isCommandLine: true, isKeyUp: true
        });
        */

        // RETURN does a special exec/highlight thing
        if (ev.keyCode === keys.RETURN) {
            var worst = this.cli.getWorstHint();
            // Deny RETURN unless the command might work
            if (worst.status === Status.VALID) {
                this.cli.exec();
                this.element.value = '';
            }
            else {
                // If we've denied RETURN because the command was not VALID,
                // select the part of the command line that is causing problems
                // TODO: if there are 2 errors are we picking the right one?
                dom.setSelectionStart(this.element, worst.start);
                dom.setSelectionEnd(this.element, worst.end);
            }
        }

        this.update();

        // Special actions which delegate to the assignment
        var current = this.cli.getAssignmentAt(dom.getSelectionStart(this.element));
        if (current) {
            // TAB does a special complete thing
            if (ev.keyCode === keys.TAB) {
                current.complete();
                this.update();
            }

            // UP/DOWN look for some history
            if (ev.keyCode === keys.UP) {
                current.increment();
                this.update();
            }
            if (ev.keyCode === keys.DOWN) {
                current.decrement();
                this.update();
            }
        }

        return handled;
    },

    /**
     * Actually parse the input and make sure we're all up to date
     */
    update: function() {
        this.isUpdating = true;
        var input = {
            typed: this.element.value,
            cursor: {
                start: dom.getSelectionStart(this.element),
                end: dom.getSelectionEnd(this.element.selectionEnd)
            }
        };
        this.cli.update(input);

        var display = this.cli.getAssignmentAt(input.cursor.start).getHint();

        // 1. Update the completer with prompt/error marker/TAB info
        dom.removeCssClass(this.completer, Status.VALID.toString());
        dom.removeCssClass(this.completer, Status.INCOMPLETE.toString());
        dom.removeCssClass(this.completer, Status.INVALID.toString());

        var completion = '> ';
        if (this.element.value.length > 0) {
            var scores = this.cli.getInputStatusMarkup();
            completion += this.markupStatusScore(scores);
        }

        // Display the "-> prediction" at the end of the completer
        if (this.element.value.length > 0 &&
                display.predictions && display.predictions.length > 0) {
            var tab = display.predictions[0];
            completion += '  ⇥ ' + (tab.name ? tab.name : tab);
        }
        this.completer.innerHTML = completion;
        dom.addCssClass(this.completer, this.cli.getWorstHint().status.toString());

        // 2. Update the hint element
        var hint = '';
        if (this.element.value.length !== 0) {
            hint += display.message;
            if (display.predictions && display.predictions.length > 0) {
                hint += ': [ ';
                display.predictions.forEach(function(prediction) {
                    hint += (prediction.name ? prediction.name : prediction);
                    hint += ' | ';
                }, this);
                hint = hint.replace(/\| $/, ']');
            }
        }

        this.hinter.innerHTML = hint;
        if (hint.length === 0) {
            dom.addCssClass(this.hinter, 'cptNoPopup');
        }
        else {
            dom.removeCssClass(this.hinter, 'cptNoPopup');
        }

        this.isUpdating = false;
    },

    /**
     * Markup an array of Status values with spans
     */
    markupStatusScore: function(scores) {
        var completion = '';
        // Create mark-up
        var i = 0;
        var lastStatus = -1;
        while (true) {
            if (lastStatus !== scores[i]) {
                completion += '';
                lastStatus = scores[i];
            }
            completion += this.element.value[i];
            i++;
            if (i === this.element.value.length) {
                completion += '';
                break;
            }
            if (lastStatus !== scores[i]) {
                completion += '';
            }
        }

        return completion;
    },

    /**
     * Update the input element to reflect the changed argument
     */
    onArgChange: function(ev) {
        if (this.isUpdating) {
            return;
        }

        var prefix = this.element.value.substring(0, ev.argument.start);
        var suffix = this.element.value.substring(ev.argument.end);
        var insert = typeof ev.text === 'string' ? ev.text : ev.text.name;
        this.element.value = prefix + insert + suffix;
        // Fix the cursor.
        var insertEnd = (prefix + insert).length;
        this.element.selectionStart = insertEnd;
        this.element.selectionEnd = insertEnd;
    }
};
exports.CliView = CliView;

});
<|endoftext|>


<commit_before>/**
* Codemirror mode for Octo Assembler
**/

CodeMirror.defineMode('octo', function(config, options) {

	const TOKEN = /[^\s]+/

	const CONTROL = {
		return:1, if:1, then:1, begin:1, else:1, end:1,
		loop:1, again:1, while:1, jump:1, jump0:1, ';':1,
	}
	const STATEMENTS = {
		clear:1, bcd:1, save:1, load:1, sprite:1, hex:1, random:1,
		delay:1, key:1, '-key':1, buzzer:1, native:1, hires:1, lores:1,
		'scroll-down':1, 'scroll-left':1, 'scroll-right':1, bighex:1,
		exit:1, saveflags:1, loadflags:1, long:1, plane:1, audio:1, 'scroll-up':1,
	}
	const DIRECTIVES = {
		':alias':1, ':const':1, ':unpack':1, ':next':1, ':org':1,
		':byte':1, ':breakpoint':1, ':macro':1, ':calc':1, ':call':1
	}

	function token(stream, state) {
		stream.eatSpace()

		// comments are a special case
		if (stream.peek() == '#') {
			stream.skipToEnd()
			return 'comment'
		}

		// otherwise, octo tokens are whitespace-separated
		const t = stream.match(TOKEN)

		if (/^([vV][0-9a-fA-F]|i)$/.test(t)) {
			return 'def' // registers
		}
		if (/^(\:=|\+=|\-=|=\-|\|=|&=|\^=|<<=|>>=)$/.test(t)) {
			return 'keyword' // assignment
		}
		if (/^(==|!=|<=|>=|<|>)\s+$/.test(t)) {
			return 'keyword' // relationals
		}
		if (/^(([+\-]?0b[01]+)|([+\-]?0x[0-9a-fA-F]+)|([+\-]?\d+))$/.test(t)) {
			return 'number' // numeric literals
		}
		if (CONTROL[t]) {
			return 'keyword' // control flow
		}
		if (STATEMENTS[t]) {
			return 'keyword' // statements
		}
		if (DIRECTIVES[t]) {
			return 'variable-2' // compiler directives
		}
		if (t == ':') { // labels
			stream.eatSpace()
			stream.match(TOKEN)
			return 'attribute'
		}
		return null
	}

	return {
		startState:  _ => ({}),
		copyState:   x => ({}),
		token:       token,
		lineComment: '# ',
	}
})
<commit_msg>fix codemirror octo mode regex for relational operators.<commit_after>/**
* Codemirror mode for Octo Assembler
**/

CodeMirror.defineMode('octo', function(config, options) {

	const TOKEN = /[^\s]+/

	const CONTROL = {
		return:1, if:1, then:1, begin:1, else:1, end:1,
		loop:1, again:1, while:1, jump:1, jump0:1, ';':1,
	}
	const STATEMENTS = {
		clear:1, bcd:1, save:1, load:1, sprite:1, hex:1, random:1,
		delay:1, key:1, '-key':1, buzzer:1, native:1, hires:1, lores:1,
		'scroll-down':1, 'scroll-left':1, 'scroll-right':1, bighex:1,
		exit:1, saveflags:1, loadflags:1, long:1, plane:1, audio:1, 'scroll-up':1,
	}
	const DIRECTIVES = {
		':alias':1, ':const':1, ':unpack':1, ':next':1, ':org':1,
		':byte':1, ':breakpoint':1, ':macro':1, ':calc':1, ':call':1
	}

	function token(stream, state) {
		stream.eatSpace()

		// comments are a special case
		if (stream.peek() == '#') {
			stream.skipToEnd()
			return 'comment'
		}

		// otherwise, octo tokens are whitespace-separated
		const t = stream.match(TOKEN)

		if (/^([vV][0-9a-fA-F]|i)$/.test(t)) {
			return 'def' // registers
		}
		if (/^(\:=|\+=|\-=|=\-|\|=|&=|\^=|<<=|>>=)$/.test(t)) {
			return 'keyword' // assignment
		}
		if (/^(==|!=|<=|>=|<|>)$/.test(t)) {
			return 'keyword' // relationals
		}
		if (/^(([+\-]?0b[01]+)|([+\-]?0x[0-9a-fA-F]+)|([+\-]?\d+))$/.test(t)) {
			return 'number' // numeric literals
		}
		if (CONTROL[t]) {
			return 'keyword' // control flow
		}
		if (STATEMENTS[t]) {
			return 'keyword' // statements
		}
		if (DIRECTIVES[t]) {
			return 'variable-2' // compiler directives
		}
		if (t == ':') { // labels
			stream.eatSpace()
			stream.match(TOKEN)
			return 'attribute'
		}
		return null
	}

	return {
		startState:  _ => ({}),
		copyState:   x => ({}),
		token:       token,
		lineComment: '# ',
	}
})
<|endoftext|>


<commit_before>var utils = require('cordova/utils'),
    exec = require('cordova/exec');

var mediaObjects = {};

/**
 * This class provides access to the device media, interfaces to both sound and video
 *
 * @constructor
 * @param src                   The file name or url to play
 * @param successCallback       The callback to be called when the file is done playing or recording.
 *                                  successCallback()
 * @param errorCallback         The callback to be called if there is an error.
 *                                  errorCallback(int errorCode) - OPTIONAL
 * @param statusCallback        The callback to be called when media status has changed.
 *                                  statusCallback(int statusCode) - OPTIONAL
 */
var Media = function(src, successCallback, errorCallback, statusCallback) {

    // successCallback optional
    if (successCallback && (typeof successCallback !== "function")) {
        console.log("Media Error: successCallback is not a function");
        return;
    }

    // errorCallback optional
    if (errorCallback && (typeof errorCallback !== "function")) {
        console.log("Media Error: errorCallback is not a function");
        return;
    }

    // statusCallback optional
    if (statusCallback && (typeof statusCallback !== "function")) {
        console.log("Media Error: statusCallback is not a function");
        return;
    }

    this.id = utils.createUUID();
    mediaObjects[this.id] = this;
    this.src = src;
    this.successCallback = successCallback;
    this.errorCallback = errorCallback;
    this.statusCallback = statusCallback;
    this._duration = -1;
    this._position = -1;
    exec(null, this.errorCallback, "Media", "create", [this.id, this.src]);
};

// Media messages
Media.MEDIA_STATE = 1;
Media.MEDIA_DURATION = 2;
Media.MEDIA_POSITION = 3;
Media.MEDIA_ERROR = 9;

// Media states
Media.MEDIA_NONE = 0;
Media.MEDIA_STARTING = 1;
Media.MEDIA_RUNNING = 2;
Media.MEDIA_PAUSED = 3;
Media.MEDIA_STOPPED = 4;
Media.MEDIA_MSG = ["None", "Starting", "Running", "Paused", "Stopped"];

// "static" function to return existing objs.
Media.get = function(id) {
    return mediaObjects[id];
};

/**
 * Start or resume playing audio file.
 */
Media.prototype.play = function(options) {
    exec(this.successCallback, this.errorCallback, "Media", "startPlayingAudio", [this.id, this.src, options]);
};

/**
 * Stop playing audio file.
 */
Media.prototype.stop = function() {
    var me = this;
    exec(function() {
        me._position = 0;
        me.successCallback();
    }, this.errorCallback, "Media", "stopPlayingAudio", [this.id]);
};

/**
 * Seek or jump to a new time in the track..
 */
Media.prototype.seekTo = function(milliseconds) {
    var me = this;
    exec(function(p) {
        me._position = p;
    }, this.errorCallback, "Media", "seekToAudio", [this.id, milliseconds]);
};

/**
 * Pause playing audio file.
 */
Media.prototype.pause = function() {
    exec(null, this.errorCallback, "Media", "pausePlayingAudio", [this.id]);
};

/**
 * Get duration of an audio file.
 * The duration is only set for audio that is playing, paused or stopped.
 *
 * @return      duration or -1 if not known.
 */
Media.prototype.getDuration = function() {
    return this._duration;
};

/**
 * Get position of audio.
 */
Media.prototype.getCurrentPosition = function(success, fail) {
    var me = this;
    exec(function(p) {
        me._position = p;
        success(p);
    }, fail, "Media", "getCurrentPositionAudio", [this.id]);
};

/**
 * Start recording audio file.
 */
Media.prototype.startRecord = function() {
    exec(this.successCallback, this.errorCallback, "Media", "startRecordingAudio", [this.id, this.src]);
};

/**
 * Stop recording audio file.
 */
Media.prototype.stopRecord = function() {
    exec(this.successCallback, this.errorCallback, "Media", "stopRecordingAudio", [this.id]);
};

/**
 * Release the resources.
 */
Media.prototype.release = function() {
    exec(null, this.errorCallback, "Media", "release", [this.id]);
};

/**
 * Adjust the volume.
 */
Media.prototype.setVolume = function(volume) {
    exec(null, null, "Media", "setVolume", [this.id, volume]);
};

/**
 * Audio has status update.
 * PRIVATE
 *
 * @param id            The media object id (string)
 * @param status        The status code (int)
 * @param msg           The status message (string)
 */
Media.onStatus = function(id, msg, value) {
    var media = mediaObjects[id];
    // If state update
    if (msg === Media.MEDIA_STATE) {
        if (value === Media.MEDIA_STOPPED) {
            if (media.successCallback) {
                media.successCallback();
            }
        }
        if (media.statusCallback) {
            media.statusCallback(value);
        }
    }
    else if (msg === Media.MEDIA_DURATION) {
        media._duration = value;
    }
    else if (msg === Media.MEDIA_ERROR) {
        if (media.errorCallback) {
        	// value should be a MediaError object when msg == MEDIA_ERROR
            media.errorCallback(value);
        }
    }
    else if (msg === Media.MEDIA_POSITION) {
        media._position = value;
    }
};

module.exports = Media;
<commit_msg>CB-321: Media API: 'mediaSuccess' callback param to new Media() is called soon after new obj created<commit_after>var utils = require('cordova/utils'),
    exec = require('cordova/exec');

var mediaObjects = {};

/**
 * This class provides access to the device media, interfaces to both sound and video
 *
 * @constructor
 * @param src                   The file name or url to play
 * @param successCallback       The callback to be called when the file is done playing or recording.
 *                                  successCallback()
 * @param errorCallback         The callback to be called if there is an error.
 *                                  errorCallback(int errorCode) - OPTIONAL
 * @param statusCallback        The callback to be called when media status has changed.
 *                                  statusCallback(int statusCode) - OPTIONAL
 */
var Media = function(src, successCallback, errorCallback, statusCallback) {

    // successCallback optional
    if (successCallback && (typeof successCallback !== "function")) {
        console.log("Media Error: successCallback is not a function");
        return;
    }

    // errorCallback optional
    if (errorCallback && (typeof errorCallback !== "function")) {
        console.log("Media Error: errorCallback is not a function");
        return;
    }

    // statusCallback optional
    if (statusCallback && (typeof statusCallback !== "function")) {
        console.log("Media Error: statusCallback is not a function");
        return;
    }

    this.id = utils.createUUID();
    mediaObjects[this.id] = this;
    this.src = src;
    this.successCallback = successCallback;
    this.errorCallback = errorCallback;
    this.statusCallback = statusCallback;
    this._duration = -1;
    this._position = -1;
    exec(null, this.errorCallback, "Media", "create", [this.id, this.src]);
};

// Media messages
Media.MEDIA_STATE = 1;
Media.MEDIA_DURATION = 2;
Media.MEDIA_POSITION = 3;
Media.MEDIA_ERROR = 9;

// Media states
Media.MEDIA_NONE = 0;
Media.MEDIA_STARTING = 1;
Media.MEDIA_RUNNING = 2;
Media.MEDIA_PAUSED = 3;
Media.MEDIA_STOPPED = 4;
Media.MEDIA_MSG = ["None", "Starting", "Running", "Paused", "Stopped"];

// "static" function to return existing objs.
Media.get = function(id) {
    return mediaObjects[id];
};

/**
 * Start or resume playing audio file.
 */
Media.prototype.play = function(options) {
    exec(null, null, "Media", "startPlayingAudio", [this.id, this.src, options]);
};

/**
 * Stop playing audio file.
 */
Media.prototype.stop = function() {
    var me = this;
    exec(function() {
        me._position = 0;
        me.successCallback();
    }, this.errorCallback, "Media", "stopPlayingAudio", [this.id]);
};

/**
 * Seek or jump to a new time in the track..
 */
Media.prototype.seekTo = function(milliseconds) {
    var me = this;
    exec(function(p) {
        me._position = p;
    }, this.errorCallback, "Media", "seekToAudio", [this.id, milliseconds]);
};

/**
 * Pause playing audio file.
 */
Media.prototype.pause = function() {
    exec(null, this.errorCallback, "Media", "pausePlayingAudio", [this.id]);
};

/**
 * Get duration of an audio file.
 * The duration is only set for audio that is playing, paused or stopped.
 *
 * @return      duration or -1 if not known.
 */
Media.prototype.getDuration = function() {
    return this._duration;
};

/**
 * Get position of audio.
 */
Media.prototype.getCurrentPosition = function(success, fail) {
    var me = this;
    exec(function(p) {
        me._position = p;
        success(p);
    }, fail, "Media", "getCurrentPositionAudio", [this.id]);
};

/**
 * Start recording audio file.
 */
Media.prototype.startRecord = function() {
    exec(this.successCallback, this.errorCallback, "Media", "startRecordingAudio", [this.id, this.src]);
};

/**
 * Stop recording audio file.
 */
Media.prototype.stopRecord = function() {
    exec(this.successCallback, this.errorCallback, "Media", "stopRecordingAudio", [this.id]);
};

/**
 * Release the resources.
 */
Media.prototype.release = function() {
    exec(null, this.errorCallback, "Media", "release", [this.id]);
};

/**
 * Adjust the volume.
 */
Media.prototype.setVolume = function(volume) {
    exec(null, null, "Media", "setVolume", [this.id, volume]);
};

/**
 * Audio has status update.
 * PRIVATE
 *
 * @param id            The media object id (string)
 * @param status        The status code (int)
 * @param msg           The status message (string)
 */
Media.onStatus = function(id, msg, value) {
    var media = mediaObjects[id];
    // If state update
    if (msg === Media.MEDIA_STATE) {
        if (value === Media.MEDIA_STOPPED) {
            if (media.successCallback) {
                media.successCallback();
            }
        }
        if (media.statusCallback) {
            media.statusCallback(value);
        }
    }
    else if (msg === Media.MEDIA_DURATION) {
        media._duration = value;
    }
    else if (msg === Media.MEDIA_ERROR) {
        if (media.errorCallback) {
        	// value should be a MediaError object when msg == MEDIA_ERROR
            media.errorCallback(value);
        }
    }
    else if (msg === Media.MEDIA_POSITION) {
        media._position = value;
    }
};

module.exports = Media;
<|endoftext|>