<commit_before>
import Store from './Storage';
import validate from '../util/validate';
import numberUtils from '../util/number';

const DEFAULT_MASTER_VOLUME = 0.5;

/* *******************************
  Harrison and Elliot Audio Deck
******************************* */

class HeadAudio {

  constructor ( name, channels = 10 ) {

  	// set the store key
    this.storeKey = `_${ name }__`;

    this.subscribers = [];

    // set up the channels
    this.channels = [];
    this.channelIndex = 0;

    let channelCount = 0;

    while ( channelCount < channels ) {
      this.channels.push({
        audio: document.createElement('audio'),
        volume: 0
      });
      channelCount += 1;
    }

    // get and set the master volume
    if ( Store.has( this.masterVolumeStoreKey ) ) {
      // if has volume stored - use it
      this.masterVolume = Store.get( this.masterVolumeStoreKey );
    }

    // get and set the volume
    if ( Store.has( this.volumeStoreKey ) ) {
      // if has volume stored - use it
      this.volume = Store.get( this.volumeStoreKey );
    }
  }

  updateVolume () {
    this.channels.forEach( ( channel ) => {
      if ( typeof channel.audio === 'object' ) {
        channel.audio.volume = Math.min( 1, Math.max( 0, channel.volume * this.volume * this.masterVolume ) );
      }
    });
  }

  play ( src, volume = 1 ) {
    const channel = this.nextChannel;
    channel.volume = volume;
    channel.audio.src = src;
    channel.audio.play();
    this.updateVolume();
  }

  pause () {
  	const channel = this.currentChannel;
    channel.audio.pause();
  }

  stop () {
    const channel = this.currentChannel;
    channel.audio.pause();
    channel.audio.src = '';
  }

  isValidVolume ( vol ) {
    return validate.number.between( vol, 0, 1 );
  }

  subscribe ( subscription ) {
    this.subscribers.push( subscription );
    this.emitUpdate();
  }

  unsubscribe ( subscription ) {
    const index = this.subscribers.indexOf( subscription );
    if ( index !== -1 ) {
      console.log('unsubscribed!!')
      this.subscribers.splice( index, 1 );
    }
  }

  emitUpdate () {
    this.subscribers.forEach( ( subscription ) => {
      subscription( this.state );
    });
  }

  turnUp ( by = 0.1 ) {
    this.volume = numberUtils.safeIncrementBy( this.volume, by );
  }

  turnDown ( by = 0.1 ) {
    this.volume = numberUtils.safeIncrementBy( this.volume, -by );
  }

  turnUpMaster ( by = 0.1 ) {
    this.masterVolume = numberUtils.safeIncrementBy( this.masterVolume, by );
  }

  turnDownMaster ( by = 0.1 ) {
    this.masterVolume = numberUtils.safeIncrementBy( this.masterVolume, -by );
  }

  get currentChannel () {
    return this.channels[ this.channelIndex ];
  }

  get nextChannel () {
    this.channelIndex += 1;

    if ( this.channelIndex >= this.channels.length ) {
      this.channelIndex = 0;
    }

    return this.currentChannel;
  }

  // Store keys for saving state
  // Master volume: represents the volume of all audio
  get masterVolumeStoreKey () {
    return `_HeadAudio__master_volume`;
  }

  // Volume: represents the volume of the class (ie HeadRadio)
  get volumeStoreKey () {
    return `${ this.storeKey }volume`;
  }

  // The store key of the class (ie )
  get storeKey () {
    return this._storeKey;
  }

  set storeKey ( key ) {
    this._storeKey = key;
  }

  get volume () {
    if ( typeof this._volume === 'undefined' ) {
      return 1;
    }

    return this._volume;
  }

  set volume ( vol ) {
    if ( !this.isValidVolume( vol ) ) {
      return;
    }
    // store volume
    Store.set( this.volumeStoreKey, vol );
    // set volumne
    this._volume = vol;
    this.updateVolume();
    this.emitUpdate();
  }

  get masterVolume () {
    if ( typeof this._masterVolume === 'undefined' ) {
      return DEFAULT_MASTER_VOLUME;
    }

    return this._masterVolume;
  }

  set masterVolume ( vol ) {
    if ( !this.isValidVolume( vol ) ) {
      return;
    }
    // store volume
    Store.set( this.masterVolumeStoreKey, vol );
    // set volumne
    this._masterVolume = vol;
    this.updateVolume();
    this.emitUpdate();
  }

  get state () {
    const state = {
      volume: this.volume,
      masterVolume: this.masterVolume
    };

    return state;
  }
}

export default HeadAudio;
<commit_msg>Set master volume across all instances<commit_after>
import Store from './Storage';
import validate from '../util/validate';
import numberUtils from '../util/number';

const DEFAULT_MASTER_VOLUME = 0.5;

/* *******************************
  Harrison and Elliot Audio Deck
******************************* */

class HeadAudio {

  constructor ( name, channels = 10 ) {

  	// set the store key
    this.storeKey = `_${ name }__`;

    this.subscribers = [];

    // set up the channels
    this.channels = [];
    this.channelIndex = 0;

    let channelCount = 0;

    while ( channelCount < channels ) {
      this.channels.push({
        audio: document.createElement('audio'),
        volume: 0
      });
      channelCount += 1;
    }

    // get and set the volume
    if ( Store.has( this.volumeStoreKey ) ) {
      // if has volume stored - use it
      this.volume = Store.get( this.volumeStoreKey );
    }
  }

  updateVolume () {
    this.channels.forEach( ( channel ) => {
      if ( typeof channel.audio === 'object' ) {
        channel.audio.volume = Math.min( 1, Math.max( 0, channel.volume * this.volume * this.masterVolume ) );
      }
    });
  }

  play ( src, volume = 1 ) {
    const channel = this.nextChannel;
    channel.volume = volume;
    channel.audio.src = src;
    channel.audio.play();
    this.updateVolume();
  }

  pause () {
  	const channel = this.currentChannel;
    channel.audio.pause();
  }

  stop () {
    const channel = this.currentChannel;
    channel.audio.pause();
    channel.audio.src = '';
  }

  isValidVolume ( vol ) {
    return validate.number.between( vol, 0, 1 );
  }

  subscribe ( subscription ) {
    this.subscribers.push( subscription );
    this.emitUpdate();
  }

  unsubscribe ( subscription ) {
    const index = this.subscribers.indexOf( subscription );
    if ( index !== -1 ) {
      console.log('unsubscribed!!')
      this.subscribers.splice( index, 1 );
    }
  }

  emitUpdate () {
    this.subscribers.forEach( ( subscription ) => {
      subscription( this.state );
    });
  }

  turnUp ( by = 0.1 ) {
    this.volume = numberUtils.safeIncrementBy( this.volume, by );
  }

  turnDown ( by = 0.1 ) {
    this.volume = numberUtils.safeIncrementBy( this.volume, -by );
  }

  turnUpMaster ( by = 0.1 ) {
    this.masterVolume = numberUtils.safeIncrementBy( this.masterVolume, by );
  }

  turnDownMaster ( by = 0.1 ) {
    this.masterVolume = numberUtils.safeIncrementBy( this.masterVolume, -by );
  }

  get currentChannel () {
    return this.channels[ this.channelIndex ];
  }

  get nextChannel () {
    this.channelIndex += 1;

    if ( this.channelIndex >= this.channels.length ) {
      this.channelIndex = 0;
    }

    return this.currentChannel;
  }

  // Volume: represents the volume of the class (ie HeadRadio)
  get volumeStoreKey () {
    return `${ this.storeKey }volume`;
  }

  // The store key of the class (ie )
  get storeKey () {
    return this._storeKey;
  }

  set storeKey ( key ) {
    this._storeKey = key;
  }

  get volume () {
    if ( typeof this._volume === 'undefined' ) {
      return 1;
    }

    return this._volume;
  }

  set volume ( vol ) {
    if ( !this.isValidVolume( vol ) ) {
      return;
    }
    // store volume
    Store.set( this.volumeStoreKey, vol );
    // set volumne
    this._volume = vol;
    this.updateVolume();
    this.emitUpdate();
  }

  get masterVolume () {
    return HeadAudio.masterVolume;
  }

  set masterVolume ( vol ) {
    if ( !this.isValidVolume( vol ) ) {
      return;
    }
    // store volume
    Store.set( HeadAudio.masterVolumeStoreKey, vol );
    // set volumne
    HeadAudio.masterVolume = vol;
    this.updateVolume();
    this.emitUpdate();
  }

  get state () {
    const state = {
      volume: this.volume,
      masterVolume: this.masterVolume
    };

    return state;
  }
}

HeadAudio.masterVolume = DEFAULT_MASTER_VOLUME;
HeadAudio.masterVolumeStoreKey = '_HeadAudio__master_volume';

// get and set the master volume
if ( Store.has( HeadAudio.masterVolumeStoreKey ) ) {
  // if has volume stored - use it
  HeadAudio.masterVolume = Store.get( HeadAudio.masterVolumeStoreKey );
}

export default HeadAudio;
<|endoftext|>


<commit_before>
/*!
 * CSS - Evaluator
 * Copyright(c) 2010 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Visitor = require('./')
  , nodes = require('../nodes')
  , Stack = require('../stack')
  , Frame = require('../stack/frame')
  , Scope = require('../stack/scope')
  , utils = require('../utils')
  , bifs = require('../functions')
  , dirname = require('path').dirname
  , fs = require('fs');

/**
 * Initialize a new `Evaluator` with the given `root` Node
 * and the following `options`.
 *
 * Options:
 *
 *   - `compress`  Compress the css output, defaults to false
 *
 * @param {Node} root
 * @api public
 */

var Evaluator = module.exports = function Evaluator(root, options) {
  options = options || {};
  Visitor.call(this, root);
  this.stack = new Stack;
  this.functions = options.functions || {};
  this.paths = options.paths || [dirname(options.filename || '.')];
  this.stack.push(this.global = new Frame(root));
};

/**
 * Inherit from `Visitor.prototype`.
 */

Evaluator.prototype.__proto__ = Visitor.prototype;

/**
 * Proxy visit to expose node line numbers.
 *
 * @param {Node} node
 * @return {Node}
 * @api public
 */

var visit = Visitor.prototype.visit;
Evaluator.prototype.visit = function(node){
  this.lineno = node.lineno;
  return visit.call(this, node);
};

/**
 * Evaluate the tree.
 *
 * @return {Node}
 * @api public
 */

Evaluator.prototype.evaluate = function(){
  return this.visit(this.root);
};

/**
 * Visit Root.
 */

Evaluator.prototype.visitRoot = function(block){
  for (var i = 0; i < block.nodes.length; ++i) {
    block.nodes[i] = this.visit(block.nodes[i]);
  }
  return block;
};

/**
 * Visit Block.
 */

Evaluator.prototype.visitBlock = function(block){
  this.stack.push(new Frame(block));
  for (var i = 0, len = block.nodes.length; i < len; ++i) {
    block.nodes[i] = this.visit(block.nodes[i]);
  }
  this.stack.pop();
  return block;
};

/**
 * Visit Color.
 */

Evaluator.prototype.visitColor = function(color){
  return color;
};

/**
 * Visit HSLA.
 */

Evaluator.prototype.visitHSLA = function(hsla){
  return hsla;
};

/**
 * Visit Literal.
 */

Evaluator.prototype.visitLiteral = function(lit){
  return lit;
};

/**
 * Visit Boolean.
 */

Evaluator.prototype.visitBoolean = function(bool){
  return bool;
};

/**
 * Visit Unit.
 */

Evaluator.prototype.visitUnit = function(unit){
  return unit;
};

/**
 * Visit Ident.
 */

Evaluator.prototype.visitIdent = function(id){
  return id;
};

/**
 * Visit String.
 */

Evaluator.prototype.visitString = function(string){
  return string;
};

/**
 * Visit Null.
 */

Evaluator.prototype.visitNull = function(node){
  return node;
};

/**
 * Visit Function.
 */

Evaluator.prototype.visitFunction = function(fn){
  return fn;
};

/**
 * Visit RuleSet.
 */

Evaluator.prototype.visitRuleSet = function(set){
  for (var i = 0, len = set.nodes.length; i < len; ++i) {
    set.nodes[i] = this.visit(set.nodes[i]);
  }
  return set;
};

/**
 * Visit Selector.
 */

Evaluator.prototype.visitSelector = function(selector){
  selector.block = this.visit(selector.block);
  return selector;
};

/**
 * Visit Charset.
 */

Evaluator.prototype.visitCharset = function(charset){
  return charset;
};

/**
 * Visit Call.
 */

Evaluator.prototype.visitCall = function(call){
  // TODO: refactor
  var fn = this.lookupFunction(call.name);

  // Undefined function, render literal css
  if (!fn) {
    call.args = this.visit(call.args);
    return call;
  }

  // First node in expression
  if (fn instanceof nodes.Expression) {
    fn = fn.first;
  }

  var ret, body
    , params = fn.params
    , stack = this.stack;

  // Evaluate arguments
  var args = this.visit(call.args);

  // Built-in
  if ('function' == typeof fn) {
    args = args.nodes.map(function(node){
      return node.first;
    });
    body = fn.apply(this, args);
    if (!(body instanceof nodes.Expression)) {
      var expr = new nodes.Expression;
      expr.push(body);
      body = expr;
    }
  // User-defined
  } else if (fn instanceof nodes.Function) {
    body = fn.block.clone();

    // Inject arguments as locals
    stack.push(new Frame(body));
    params.nodes.forEach(function(node, i){
      node.val = args.nodes[i] || node.val;
      if (node.val instanceof nodes.Null) {
        throw new Error('argument ' + node + ' required for ' + fn);
      }
      stack.currentFrame.scope.add(node);
    });

    // Evaluate
    body = this.visit(body);
    stack.pop();
  } else {
    throw new Error('tried to call ' + call.name + '(), but cannot call non-function ' + fn.first);
  }

  // Return
  if (this.return) {
    ret = body.nodes[body.nodes.length - 1];
  // Mixin
  } else {
    body.nodes.forEach(function(node){
      stack.currentFrame.block.nodes.push(node);
    });
    ret = nodes.null;
  }

  return ret;
};

/**
 * Visit Variable.
 */

Evaluator.prototype.visitVariable = function(variable){
  // Lookup
  if (nodes.null == variable.val) {
    var val = this.stack.lookup(variable.name);
    if (!val) throw new Error('undefined variable ' + variable);
    return this.visit(val);
  // Assign
  } else {
    variable.val = this.visit(variable.val);
    this.stack.currentFrame.scope.add(variable);
    return variable.val;
  }
};

/**
 * Visit BinOp.
 */

Evaluator.prototype.visitBinOp = function(binop){
  // Special-case "is defined" pseudo binop
  if ('is defined' == binop.op) return this.isDefined(binop.left);

  var ret = this.return;
  this.return = true;
  // Visit operands
  var op = binop.op
    , left = this.visit(binop.left).first
    , right = this.visit(binop.right).first;
  this.return = ret;

  // Coercion
  var ignore = ['||', '&&', 'is a'];
  if (!~ignore.indexOf(op)) {
    right = left.coerce(right);
  }

  // Operate
  return this.visit(left.operate(op, right));
};

/**
 * Visit UnaryOp.
 */

Evaluator.prototype.visitUnaryOp = function(unary){
  var op = unary.op
    , node = this.visit(unary.expr).first;

  if ('!' != op) utils.assertType(node, nodes.Unit);

  switch (op) {
    case '-':
      node.val = -node.val;
      break;
    case '+':
      node.val = +node.val;
      break;
    case '~':
      node.val = ~node.val;
      break;
    case '!':
      return node.toBoolean().negate();
  }

  return node;
};

/**
 * Visit TernaryOp.
 */

Evaluator.prototype.visitTernary = function(ternary){
  var ok = this.visit(ternary.cond).toBoolean();
  return nodes.true == ok
    ? this.visit(ternary.trueExpr)
    : this.visit(ternary.falseExpr);
};

/**
 * Visit Expression.
 */

Evaluator.prototype.visitExpression = function(expr){
  for (var i = 0, len = expr.nodes.length; i < len; ++i) {
    expr.nodes[i] = this.visit(expr.nodes[i]);
  }
  return expr;
};

/**
 * Visit Property.
 */

Evaluator.prototype.visitProperty = function(prop){
  var fn = this.stack.lookup(prop.name)
    , call = fn instanceof nodes.Function
    , literal = prop.name == this.callingProperty;

  // Function of the same name
  if (call && !literal) {
    this.callingProperty = prop.name;
    var ret = this.visit(new nodes.Call(prop.name, prop.expr));
    this.callingProperty = null;
    return ret;
  // Regular property
  } else {
    var ret = this.return;
    this.return = true;
    prop.expr = this.visit(prop.expr);
    this.return = ret;
  }
  return prop;
};

/**
 * Visit Import.
 */

Evaluator.prototype.visitImport = function(import){
  var lookup
    , found
    , stylus = require('../stylus')
    , path = import.path;

  // Literal
  if (/\.css$/.test(path)) return import;
  path += '.css'; // TODO: .styl ?

  // Lookup
  // TODO: abstract
  for (var i = 0, len = this.paths.length; i < len; ++i) {
    try {
      lookup = this.paths[i] + '/' + path;
      fs.statSync(lookup);
      found = lookup;
      break;
    } catch (err) {
      // Ignore
    }
  }

  // Throw if import failed
  if (!found) throw new Error('failed to locate @import file ' + path);

  // TODO: clone options and provide new filename
  // TODO: import exceptions should pass through
  // TODO: fix import lookup
  // TODO: test nested imports
  var str = fs.readFileSync(found, 'utf8')
    , root = stylus.parse(str, { filename: found, root: this.root });

  return nodes.null;
};

/**
 * Lookup function by the given `name`.
 *
 * @param {String} name
 * @return {Function}
 * @api public
 */

Evaluator.prototype.lookupFunction = function(name){
  return this.stack.lookup(name)
    || this.functions[name]
    || bifs[name];
};

/**
 * Check if the given `node` is a variable, and if it is defined.
 *
 * @param {Node} node
 * @return {Boolean}
 * @api private
 */

Evaluator.prototype.isDefined = function(node){
  if (node instanceof nodes.Variable) {
    return nodes.Boolean(this.stack.lookup(node.name));
  } else {
    throw new Error('invalid "is defined" check on non-variable ' + node);
  }
};
<commit_msg>debugging<commit_after>
/*!
 * CSS - Evaluator
 * Copyright(c) 2010 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Visitor = require('./')
  , nodes = require('../nodes')
  , Stack = require('../stack')
  , Frame = require('../stack/frame')
  , Scope = require('../stack/scope')
  , utils = require('../utils')
  , bifs = require('../functions')
  , dirname = require('path').dirname
  , fs = require('fs');

/**
 * Initialize a new `Evaluator` with the given `root` Node
 * and the following `options`.
 *
 * Options:
 *
 *   - `compress`  Compress the css output, defaults to false
 *
 * @param {Node} root
 * @api public
 */

var Evaluator = module.exports = function Evaluator(root, options) {
  options = options || {};
  Visitor.call(this, root);
  this.stack = new Stack;
  this.functions = options.functions || {};
  this.paths = options.paths || [dirname(options.filename || '.')];
  this.stack.push(this.global = new Frame(root));
};

/**
 * Inherit from `Visitor.prototype`.
 */

Evaluator.prototype.__proto__ = Visitor.prototype;

/**
 * Proxy visit to expose node line numbers.
 *
 * @param {Node} node
 * @return {Node}
 * @api public
 */

var visit = Visitor.prototype.visit;
Evaluator.prototype.visit = function(node){
  this.lineno = node.lineno;
  return visit.call(this, node);
};

/**
 * Evaluate the tree.
 *
 * @return {Node}
 * @api public
 */

Evaluator.prototype.evaluate = function(){
  return this.visit(this.root);
};

/**
 * Visit Root.
 */

Evaluator.prototype.visitRoot = function(block){
  for (var i = 0; i < block.nodes.length; ++i) {
    block.nodes[i] = this.visit(block.nodes[i]);
  }
  return block;
};

/**
 * Visit Block.
 */

Evaluator.prototype.visitBlock = function(block){
  this.stack.push(new Frame(block));
  for (var i = 0, len = block.nodes.length; i < len; ++i) {
    block.nodes[i] = this.visit(block.nodes[i]);
  }
  this.stack.pop();
  return block;
};

/**
 * Visit Color.
 */

Evaluator.prototype.visitColor = function(color){
  return color;
};

/**
 * Visit HSLA.
 */

Evaluator.prototype.visitHSLA = function(hsla){
  return hsla;
};

/**
 * Visit Literal.
 */

Evaluator.prototype.visitLiteral = function(lit){
  return lit;
};

/**
 * Visit Boolean.
 */

Evaluator.prototype.visitBoolean = function(bool){
  return bool;
};

/**
 * Visit Unit.
 */

Evaluator.prototype.visitUnit = function(unit){
  return unit;
};

/**
 * Visit Ident.
 */

Evaluator.prototype.visitIdent = function(id){
  return id;
};

/**
 * Visit String.
 */

Evaluator.prototype.visitString = function(string){
  return string;
};

/**
 * Visit Null.
 */

Evaluator.prototype.visitNull = function(node){
  return node;
};

/**
 * Visit Function.
 */

Evaluator.prototype.visitFunction = function(fn){
  return fn;
};

/**
 * Visit RuleSet.
 */

Evaluator.prototype.visitRuleSet = function(set){
  for (var i = 0, len = set.nodes.length; i < len; ++i) {
    set.nodes[i] = this.visit(set.nodes[i]);
  }
  return set;
};

/**
 * Visit Selector.
 */

Evaluator.prototype.visitSelector = function(selector){
  selector.block = this.visit(selector.block);
  return selector;
};

/**
 * Visit Charset.
 */

Evaluator.prototype.visitCharset = function(charset){
  return charset;
};

/**
 * Visit Call.
 */

Evaluator.prototype.visitCall = function(call){
  // TODO: refactor
  var fn = this.lookupFunction(call.name);
console.log('@' + call.name + '()');
  // Undefined function, render literal css
  if (!fn) {
    call.args = this.visit(call.args);
    return call;
  }

  // First node in expression
  if (fn instanceof nodes.Expression) {
    fn = fn.first;
  }

  var ret, body
    , params = fn.params
    , stack = this.stack;

  // Evaluate arguments
  var args = this.visit(call.args);

  // Built-in
  if ('function' == typeof fn) {
    args = args.nodes.map(function(node){
      return node.first;
    });
    body = fn.apply(this, args);
    if (!(body instanceof nodes.Expression)) {
      var expr = new nodes.Expression;
      expr.push(body);
      body = expr;
    }
  // User-defined
  } else if (fn instanceof nodes.Function) {
    body = fn.block.clone();

    // Inject arguments as locals
    stack.push(new Frame(body));
    params.nodes.forEach(function(node, i){
      node.val = args.nodes[i] || node.val;
      if (node.val instanceof nodes.Null) {
        throw new Error('argument ' + node + ' required for ' + fn);
      }
      stack.currentFrame.scope.add(node);
    });

    // Evaluate
    body = this.visit(body);
    stack.pop();
  } else {
    throw new Error('tried to call ' + call.name + '(), but cannot call non-function ' + fn.first);
  }

  // Return
  if (this.return) {
    ret = body.nodes[body.nodes.length - 1];
  // Mixin
  } else {
    body.nodes.forEach(function(node){
      stack.currentFrame.block.nodes.push(node);
    });
    ret = nodes.null;
  }

  return ret;
};

/**
 * Visit Variable.
 */

Evaluator.prototype.visitVariable = function(variable){
  // Lookup
  if (nodes.null == variable.val) {
    var val = this.stack.lookup(variable.name);
    if (!val) throw new Error('undefined variable ' + variable);
    return this.visit(val);
  // Assign
  } else {
    variable.val = this.visit(variable.val);
    this.stack.currentFrame.scope.add(variable);
    return variable.val;
  }
};

/**
 * Visit BinOp.
 */

Evaluator.prototype.visitBinOp = function(binop){
  // Special-case "is defined" pseudo binop
  if ('is defined' == binop.op) return this.isDefined(binop.left);

  var ret = this.return;
  this.return = true;
  // Visit operands
  var op = binop.op
    , left = this.visit(binop.left).first
    , right = this.visit(binop.right).first;
  this.return = ret;

  // Coercion
  var ignore = ['||', '&&', 'is a'];
  if (!~ignore.indexOf(op)) {
    right = left.coerce(right);
  }

  // Operate
  return this.visit(left.operate(op, right));
};

/**
 * Visit UnaryOp.
 */

Evaluator.prototype.visitUnaryOp = function(unary){
  var op = unary.op
    , node = this.visit(unary.expr).first;

  if ('!' != op) utils.assertType(node, nodes.Unit);

  switch (op) {
    case '-':
      node.val = -node.val;
      break;
    case '+':
      node.val = +node.val;
      break;
    case '~':
      node.val = ~node.val;
      break;
    case '!':
      return node.toBoolean().negate();
  }

  return node;
};

/**
 * Visit TernaryOp.
 */

Evaluator.prototype.visitTernary = function(ternary){
  var ok = this.visit(ternary.cond).toBoolean();
  return nodes.true == ok
    ? this.visit(ternary.trueExpr)
    : this.visit(ternary.falseExpr);
};

/**
 * Visit Expression.
 */

Evaluator.prototype.visitExpression = function(expr){
  for (var i = 0, len = expr.nodes.length; i < len; ++i) {
    expr.nodes[i] = this.visit(expr.nodes[i]);
  }
  return expr;
};

/**
 * Visit Property.
 */

Evaluator.prototype.visitProperty = function(prop){
  var fn = this.stack.lookup(prop.name)
    , call = fn instanceof nodes.Function
    , literal = prop.name == this.callingProperty;

  // Function of the same name
  if (call && !literal) {
    this.callingProperty = prop.name;
    var ret = this.visit(new nodes.Call(prop.name, prop.expr));
    this.callingProperty = null;
    return ret;
  // Regular property
  } else {
    var ret = this.return;
    this.return = true;
    prop.expr = this.visit(prop.expr);
    this.return = ret;
  }
  return prop;
};

/**
 * Visit Import.
 */

Evaluator.prototype.visitImport = function(import){
  var lookup
    , found
    , stylus = require('../stylus')
    , path = import.path;

  // Literal
  if (/\.css$/.test(path)) return import;
  path += '.css'; // TODO: .styl ?

  // Lookup
  // TODO: abstract
  for (var i = 0, len = this.paths.length; i < len; ++i) {
    try {
      lookup = this.paths[i] + '/' + path;
      fs.statSync(lookup);
      found = lookup;
      break;
    } catch (err) {
      // Ignore
    }
  }

  // Throw if import failed
  if (!found) throw new Error('failed to locate @import file ' + path);

  // TODO: clone options and provide new filename
  // TODO: import exceptions should pass through
  // TODO: fix import lookup
  // TODO: test nested imports
  var str = fs.readFileSync(found, 'utf8')
    , root = stylus.parse(str, { filename: found, root: this.root });

  return nodes.null;
};

/**
 * Lookup function by the given `name`.
 *
 * @param {String} name
 * @return {Function}
 * @api public
 */

Evaluator.prototype.lookupFunction = function(name){
  return this.stack.lookup(name)
    || this.functions[name]
    || bifs[name];
};

/**
 * Check if the given `node` is a variable, and if it is defined.
 *
 * @param {Node} node
 * @return {Boolean}
 * @api private
 */

Evaluator.prototype.isDefined = function(node){
  if (node instanceof nodes.Variable) {
    return nodes.Boolean(this.stack.lookup(node.name));
  } else {
    throw new Error('invalid "is defined" check on non-variable ' + node);
  }
};
<|endoftext|>


<commit_before>module.exports = setup;

function setup(app) {
	setInterval(function () {
		var inst = app.get('instagram');
		var models = app.get('models');
		var sql = 'SELECT * FROM tags t JOIN issue_tags it ON it.tagId = t.name JOIN issues i ON it.issueId = i.id';

		models._sequelize.query(sql, models.Tag)
			.success(function (tags) {
				ingest(inst, tags, models);
			});
	}, 30 * 1000);
}

function ingest(inst, tags, models) {
	for (var t = 0; t < tags.length; t++) {
		var tag = tags[t].name;

		inst.tags.recent({
			name: tag,

			error: function (errorMessage, errorObject, caller) {
				console.log('error getting media');
				console.log(errorMessage);
				console.log(errorObject);
			},

			complete: function (images, pagination) {
				console.log('retrieved ' + images.length + ' images for #' + tag);

				// string array of all required tags
				var tagsNeeded = [];
				for (var ti = 0; ti < images.length; ti++)
					tagsNeeded = tagsNeeded.concat(images[ti].tags);

				// deduplicate
				tagsNeeded = tagsNeeded.filter(function (obj, pos, arr) {
					return arr.indexOf(obj) == pos;
				});
				for (var ti = 0; ti < tags.length; ti++) {
					var j = tagsNeeded.indexOf(tags[ti].name);
					if (j > -1) tagsNeeded[j] = null;
				}

				// remove null entries
				var cleanedTags = [];
				for (var ti = 0; ti < tagsNeeded.length; ti++)
					if (tagsNeeded[ti])
						cleanedTags.push(tagsNeeded[ti]);
				tagsNeeded = cleanedTags;
				delete cleanedTags;

				// create new tags
				for (var ti = 0; ti < tagsNeeded.length; ti++)
					tagsNeeded[ti] = { name: tagsNeeded[ti] };

				models.Tag.bulkCreate(tagsNeeded)
					.error(function (err) {
						console.log('error creating new tags');
						console.log(err);
					})
					.success(function (createdTags) {
						tags = tags.concat(createdTags);

						// array<Tag> -> map<string, Tag>
						tagMap = {};
						for (var i = 0; i < tags.length; i++)
							tagMap[tags[i].name] = tags[i];
						tags = tagMap;
						delete tagMap;

						for (var i = 0; i < images.length; i++) {
							var image = images[i];

							var thumb = image.images.thumbnail.url;
							var standard = image.images.standard_resolution.url;

							var media = {
								instagramId: image.id,
								date: new Date(image.created_time * 1000),
								thumbnailUrl: thumb,
								imageUrl: standard
							};

							models.Media.create(media)
								.error(function (err) {
									if (err.code === 'ER_DUP_ENTRY')
										return;

									console.log('error creating media');
									console.log(err);
								})
								.success(function (media, created) {
									var mediaTags = [];
									for (var i = 0; i < image.tags.length; i++)
									 	mediaTags.push(tags[image.tags[i]]);

									media.setTags(mediaTags)
										.error(function (err) {
											console.log('error adding tags to media');
											console.log(err);
										});
								});
						}
					});
			}
		});
	}
}
<commit_msg>refactor<commit_after>module.exports = setup;

function setup(app) {
	setInterval(function () {
		var models = app.get('models');
		var sql = 'SELECT * FROM tags t JOIN issue_tags it ON it.tagId = t.name JOIN issues i ON it.issueId = i.id';

		models._sequelize.query(sql, models.Tag)
			.success(function (tags) {
				ingest(app, tags);
			});
	}, 30 * 1000);
}

function ingest(app, tags) {
	var inst = app.get('instagram');
	var models = app.get('models');

	for (var t = 0; t < tags.length; t++) {
		var tag = tags[t].name;

		inst.tags.recent({
			name: tag,

			error: function (errorMessage, errorObject, caller) {
				console.log('error getting media');
				console.log(errorMessage);
				console.log(errorObject);
			},

			complete: function (images, pagination) {
				console.log('retrieved ' + images.length + ' images for #' + tag);

				// string array of all required tags
				var tagsNeeded = [];
				for (var ti = 0; ti < images.length; ti++)
					tagsNeeded = tagsNeeded.concat(images[ti].tags);

				getTags(app, tagsNeeded, function (err, tags) {
					if (err) {
						console.log('error getting needed tags');
						console.log(err);
						return;
					}

					for (var i = 0; i < images.length; i++) {
						var image = images[i];

						var thumb = image.images.thumbnail.url;
						var standard = image.images.standard_resolution.url;

						var media = {
							instagramId: image.id,
							date: new Date(image.created_time * 1000),
							thumbnailUrl: thumb,
							imageUrl: standard
						};

						models.Media.create(media)
							.error(function (err) {
								if (err.code === 'ER_DUP_ENTRY')
									return;

								console.log('error creating media');
								console.log(err);
							})
							.success(function (media, created) {
								var mediaTags = [];
								for (var i = 0; i < image.tags.length; i++)
								 	mediaTags.push(tags[image.tags[i]]);

								media.setTags(mediaTags)
									.error(function (err) {
										console.log('error adding tags to media');
										console.log(err);
									});
							});
					}
				});
			}
		});
	}
}

function getTags(app, tags, callback) {
	var models = app.get('models');

	models.Tag.findAll()
		.error(callback)
		.success(function (existingTags) {
			// deduplicate
			tags = tags.filter(function (obj, pos, arr) {
				return arr.indexOf(obj) == pos;
			});

			// remove existing
			for (var i = 0; i < existingTags.length; i++) {
				var j = tags.indexOf(existingTags[i].name);
				if (j > -1) tags[j] = null;
			}

			var cleanedTags = [];
			for (var i = 0; i < tags.length; i++)
				if (tags[i])
					cleanedTags.push(tags[i]);
			tags = cleanedTags;
			delete cleanedTags;

			// create new tags
			tags = tags.map(function (t) { return { name: t }; });

			models.Tag.bulkCreate(tags)
				.error(callback)
				.success(function (newTags) {
					tags = existingTags.concat(newTags);

					// array<Tag> -> map<string, Tag>
					tagMap = {};
					for (var i = 0; i < tags.length; i++)
						tagMap[tags[i].name] = tags[i];
					tags = tagMap;
					delete tagMap;

					callback(null, tagMap);
				});
		});
}
<|endoftext|>


<commit_before>
var map;
var markers= [];
var polygons= [];

var initialize= function( elem ) {
    var mapOptions = {
        zoom: 10,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        mapTypeControl: true,
        mapTypeControlOptions: {
            style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
            position: google.maps.ControlPosition.TOP_CENTER
        },
        panControl: false,
        panControlOptions: {
            position: google.maps.ControlPosition.TOP_LEFT
        },
        zoomControl: false,
        zoomControlOptions: {
            style: google.maps.ZoomControlStyle.LARGE,
            position: google.maps.ControlPosition.LEFT_CENTER
        },
        scaleControl: false,
        scaleControlOptions: {
            position: google.maps.ControlPosition.TOP_LEFT
        },
        streetViewControl: false,
        streetViewControlOptions: {
            position: google.maps.ControlPosition.LEFT_TOP
        }
    }

    map = new google.maps.Map(elem, mapOptions);

    var $closeDiv= $('

');

    $closeDiv.click(hideMap);

    map.controls[google.maps.ControlPosition.TOP_RIGHT].push($closeDiv[0]);

    markers.forEach(function( marker ) {
        marker.setMap(map);
    });
}

var removeMarkers= function() {
    while ( markers.length ) markers.shift().setMap(null);
};

var removePolygons= function() {
    while ( polygons.length ) polygons.shift().polygon.setMap(null);
};

var addMarker= function( lon, lat, options ) {
    if ( _.isArray(lon) ) {
        options= lat;
        lat= lon[1];
        lon= lon[0];
    }

    if ( !options ) options= {};

    var markerOptions= {
        position: new google.maps.LatLng(lat, lon),
    }

    if ( map ) markerOptions.map= map;

    if ( 'infotext' in options ) {
        var infowindow = new google.maps.InfoWindow({
          content: options.infotext,
        });

        delete options.infotext;
    }

    if ( options ) {
        for ( var key in options ) {
            markerOptions[key]= options[key];
        }
    }

    var marker= new google.maps.Marker(markerOptions);

    if ( infowindow ) {
        google.maps.event.addListener(marker, 'click', function() {
            infowindow.open(map, marker);
        });
    }

    markers.push(marker);

    if ( map ) map.setCenter(markerOptions.position);
};

var setViewRange= function( northEast, southWest ) {
    map.panToBounds(new google.maps.LatLngBounds(
        new google.maps.LatLng(northEast[0], northEast[1]),
        new google.maps.LatLng(southWest[0], southWest[1])
    ));
};

var get$container= function() {
    return $('#google-map-dialog');
    return $('#google-maps-container');
};

var get$map= function() {
    return $('#google-map-canvas');
};

var showMap= function( cb ) {
//    get$container().show();
    SpongeTools.showModal(get$container(), function() {
        var $map= get$map();
        initialize($map[0]);
        if ( cb ) cb();
    });
};

var hideMap= function() {
    get$container().modal('hide');
//    get$container().hide();
};

var clearMap= function() {
    removeMarkers();
    removePolygons();
}

SpongeTools.Map= {
    removeMarkers: removeMarkers,
    addMarker: addMarker,
    setViewRange: setViewRange,
    show: showMap,
    hide: hideMap,
    clear: clearMap,
};
<commit_msg>added support for event hanlders on map events<commit_after>
var map;
var markers= [];
var polygons= [];

var bounds= undefined;
var eventHandlers= {};

var initialize= function( elem ) {
    var mapOptions = {
        zoom: 10,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        mapTypeControl: true,
        mapTypeControlOptions: {
            style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
            position: google.maps.ControlPosition.TOP_CENTER
        },
        panControl: false,
        panControlOptions: {
            position: google.maps.ControlPosition.TOP_LEFT
        },
        zoomControl: false,
        zoomControlOptions: {
            style: google.maps.ZoomControlStyle.LARGE,
            position: google.maps.ControlPosition.LEFT_CENTER
        },
        scaleControl: false,
        scaleControlOptions: {
            position: google.maps.ControlPosition.TOP_LEFT
        },
        streetViewControl: false,
        streetViewControlOptions: {
            position: google.maps.ControlPosition.LEFT_TOP
        }
    };

    map = new google.maps.Map(elem, mapOptions);

    bounds= undefined;
    clearEvents();

    google.maps.event.addListener(map, 'bounds_changed', function() {
        var b= map.getBounds();

        if ( !b ) return;

        var northEast= b.getNorthEast();
        var southWest= b.getSouthWest();

        var newBounds= {
            north: northEast.lat(),
            east:  northEast.lng(),
            south: southWest.lat(),
            west:  southWest.lng(),
        };
        if ( bounds && _.isEqual(bounds, newBounds) ) return;

        bounds= newBounds;
        fireEvents('bounds_changed', [bounds]);
    });

    var $closeDiv= $('

');

    $closeDiv.click(hideMap);

    map.controls[google.maps.ControlPosition.TOP_RIGHT].push($closeDiv[0]);

    markers.forEach(function( marker ) {
        marker.setMap(map);
    });
}

var fireEvents= function( event, args ) {
    if ( !(event in eventHandlers) ) return;

    return eventHandlers[event].forEach(function( handler ) {
        handler.call.apply(handler.context, args);
    });
};

var unregisterEventHandler= function( event, id ) {
    if ( !id || !(event in eventHandlers) ) return;

    eventHandlers[event]= eventHandlers[event].filter(function( handler ) { return handler.id !== id; });
};

var registerEventHandler= function( event, handler, id, context ) {
    if ( event in eventHandlers ) {
        unregisterHandler(event, id);
    }
    else {
        eventHandlers[event]= [];
    }

    if ( !id ) id= 'autoId_' + eventHandlers[event].length;

    eventHandlers[event].push({
        call: handler,
        context: context,
        id: id,
    });
};

var removeMarkers= function() {
    while ( markers.length ) markers.shift().setMap(null);
};

var removePolygons= function() {
    while ( polygons.length ) polygons.shift().polygon.setMap(null);
};

var clearEvents= function() {
    eventHandlers= {};
};

var addMarker= function( lon, lat, options ) {
    if ( _.isArray(lon) ) {
        options= lat;
        lat= lon[1];
        lon= lon[0];
    }

    if ( !options ) options= {};

    var markerOptions= {
        position: new google.maps.LatLng(lat, lon),
    }

    if ( map ) markerOptions.map= map;

    if ( 'infotext' in options ) {
        var infowindow = new google.maps.InfoWindow({
          content: options.infotext,
        });

        delete options.infotext;
    }

    if ( options ) {
        for ( var key in options ) {
            markerOptions[key]= options[key];
        }
    }

    var marker= new google.maps.Marker(markerOptions);

    if ( infowindow ) {
        google.maps.event.addListener(marker, 'click', function() {
            infowindow.open(map, marker);
        });
    }

    markers.push(marker);

    if ( map ) map.setCenter(markerOptions.position);
};

var setViewRange= function( northEast, southWest ) {
    map.fitBounds(new google.maps.LatLngBounds(
        new google.maps.LatLng(southWest[0], southWest[1]),
        new google.maps.LatLng(northEast[0], northEast[1])
    ));
};

var getViewRange= function() {
    return bounds;
};

var get$container= function() {
    return $('#google-map-dialog');
    return $('#google-maps-container');
};

var get$map= function() {
    return $('#google-map-canvas');
};

var showMap= function( cb ) {
//    get$container().show();
    SpongeTools.showModal(get$container(), function() {
        var $map= get$map();
        initialize($map[0]);
        if ( cb ) cb();
    });
};

var hideMap= function() {
    get$container().modal('hide');
//    get$container().hide();
};

var clearMap= function() {
    removeMarkers();
    removePolygons();
}

SpongeTools.Map= {
    removeMarkers: removeMarkers,
    addMarker: addMarker,
    setViewRange: setViewRange,
    getViewRange: getViewRange,
    show: showMap,
    hide: hideMap,
    clear: clearMap,
    registerEventHandler: registerEventHandler,
    unregisterEventHandler: unregisterEventHandler,
};
<|endoftext|>


<commit_before>
// Playbill Client

(function (name, dependencies, definition, context) {
    if (typeof context.define !== 'undefined' && context.define === 'function' && context.define.amd) { define(name, (dependencies || []), definition); }
    else { context[name] = definition.call(context, context.jQuery, context._, context.Backbone, context.when); }
})('Playbill', ['jquery','underscore','backbone','when'], function ($, _, Backbone, when) {

    var root = this;

    function Playbill(options) {
        this.options = options = options || {};

        this.base = options.base || '/';
        this.baseRegex = new RegExp('^'+this.base);

        this.started = false;
        this._hasPushState = root.history && root.history.pushState;

        this._currentlyLoaded = undefined;

        _.bindAll(this, '_checkUrl');
    }

    _.extend(Playbill.prototype, Backbone.Events);

    Playbill.prototype._request = function (options) {
        var playbill = this;

        if (options.url) {
            // Works around servers that deny requests to "files"
            // that start with a dot.
            options.url += /\/$/.test(options.url) ? '?type=json' : '.json';
        }

        return when($.ajax(_.extend({
            type: 'GET',
            dataType: 'json'
        }, options)));
    };

    Playbill.prototype.listPosts = function (options) {
        var playbill = this;

        options = options || {};
        options.page = options.page || 1;

        return playbill._request({
            url: playbill.base + (options.page !== 1 ? ('p'+options.page+'/') : '')
        });
    };

    Playbill.prototype.loadPost = function (slug) {
        var playbill = this;

        return playbill._request({
            url: playbill.base + encodeURIComponent(slug)
        });
    };

    Playbill.prototype.navigate = function (url) {
        var playbill = this;

        if (playbill._hasPushState) {
            root.history.pushState({}, root.document.title, url);

            playbill.loadUrl(url);
        } else {
            root.document.location.assign(url);
        }
    };

    Playbill.prototype.start = function () {
        var playbill = this;

        if (playbill.started) throw new Error('Playbill already started');

        playbill.started = true;
        playbill._currentlyLoaded = root.document.location.pathname;

        playbill._captureLinks();
        $(root).on('popstate', playbill._checkUrl);

        return playbill;
    };

    Playbill.prototype.stop = function () {
        var playbill = this;

        playbill.started = false;

        playbill._releaseLinks();
        $(root).off('popstate', playbill._checkUrl);

        return playbill;
    };

    Playbill.prototype._checkUrl = function (e) {
        var playbill = this;

        var path = root.document.location.pathname;

        if (playbill.baseRegex.test(path)) {
            playbill.loadUrl(path);
        }
    };

    Playbill.prototype.loadUrl = function (url) {
        var playbill = this;

        if (playbill._currentlyLoaded === url) return;
        playbill._currentlyLoaded = url;

        playbill.trigger('loading', url);

        return playbill._request({
            url: url
        })
        .then(function (data) {
            playbill.trigger('loaded', data, url);
        });
    };

    Playbill.prototype._captureLinks = function () {
        var playbill = this;

        $(root.document).on('click.playbill', 'a', function (e) {
            if (e.meta || e.ctrlKey) return; // Don't block user if they want to open a new tab.

            var href = $(this).attr('href');

            if (href && playbill.baseRegex.test(href)) {
                e.preventDefault();

                playbill.navigate(href);
            }
        });
    };

    Playbill.prototype._releaseLinks = function () {
        $(root.document).off('click.playbill');
    };

    return Playbill;

}, (this || {}));
<commit_msg>Client now properly catches absolute URLs that are still on the right host.<commit_after>
// Playbill Client

(function (name, dependencies, definition, context) {
    if (typeof context.define !== 'undefined' && context.define === 'function' && context.define.amd) { define(name, (dependencies || []), definition); }
    else { context[name] = definition.call(context, context.jQuery, context._, context.Backbone, context.when); }
})('Playbill', ['jquery','underscore','backbone','when'], function ($, _, Backbone, when) {

    var root = this;

    function Playbill(options) {
        this.options = options = options || {};

        this.base = options.base || '/';
        this.baseRegex = new RegExp('^'+this.base);

        this.started = false;
        this._hasPushState = root.history && root.history.pushState;

        this._currentlyLoaded = undefined;

        _.bindAll(this, '_checkUrl');
    }

    _.extend(Playbill.prototype, Backbone.Events);

    Playbill.prototype._request = function (options) {
        var playbill = this;

        if (options.url) {
            // Works around servers that deny requests to "files"
            // that start with a dot.
            options.url += /\/$/.test(options.url) ? '?type=json' : '.json';
        }

        return when($.ajax(_.extend({
            type: 'GET',
            dataType: 'json'
        }, options)));
    };

    Playbill.prototype.listPosts = function (options) {
        var playbill = this;

        options = options || {};
        options.page = options.page || 1;

        return playbill._request({
            url: playbill.base + (options.page !== 1 ? ('p'+options.page+'/') : '')
        });
    };

    Playbill.prototype.loadPost = function (slug) {
        var playbill = this;

        return playbill._request({
            url: playbill.base + encodeURIComponent(slug)
        });
    };

    Playbill.prototype.navigate = function (url) {
        var playbill = this;

        if (playbill._hasPushState) {
            root.history.pushState({}, root.document.title, url);

            playbill.loadUrl(url);
        } else {
            root.document.location.assign(url);
        }
    };

    Playbill.prototype.start = function () {
        var playbill = this;

        if (playbill.started) throw new Error('Playbill already started');

        playbill.started = true;
        playbill._currentlyLoaded = root.document.location.pathname;

        playbill._captureLinks();
        $(root).on('popstate', playbill._checkUrl);

        return playbill;
    };

    Playbill.prototype.stop = function () {
        var playbill = this;

        playbill.started = false;

        playbill._releaseLinks();
        $(root).off('popstate', playbill._checkUrl);

        return playbill;
    };

    Playbill.prototype._checkUrl = function (e) {
        var playbill = this;

        var path = root.document.location.pathname;

        if (playbill.baseRegex.test(path)) {
            playbill.loadUrl(path);
        }
    };

    Playbill.prototype.loadUrl = function (url) {
        var playbill = this;

        if (playbill._currentlyLoaded === url) return;
        playbill._currentlyLoaded = url;

        playbill.trigger('loading', url);

        return playbill._request({
            url: url
        })
        .then(function (data) {
            playbill.trigger('loaded', data, url);
        });
    };

    Playbill.prototype._captureLinks = function () {
        var playbill = this;

        $(root.document).on('click.playbill', 'a', function (e) {
            if (e.meta || e.ctrlKey) return; // Don't block user if they want to open a new tab.

            if (!(
                this.protocol === root.location.protocol &&
                this.hostname === root.location.hostname &&
                this.port === root.location.port
            )) return;

            var path = this.pathname.replace(/^([^\/])/,'/$1');

            if (path && playbill.baseRegex.test(path)) {
                e.preventDefault();

                playbill.navigate(path);
            }
        });
    };

    Playbill.prototype._releaseLinks = function () {
        $(root.document).off('click.playbill');
    };

    return Playbill;

}, (this || {}));
<|endoftext|>


<commit_before>// Filtered view manager
// We define local filter objects for each different type of field (SetFilter,
// RangeFilter, dateFilter, etc.). We then define a global `Filter` object whose
// goal is to filter complete documents by using the local filters for each
// fields.

function showFilterSidebar() {
  Sidebar.setView('filter');
}

// Use a "set" filter for a field that is a set of documents uniquely
// identified. For instance `{ labels: ['labelA', 'labelC', 'labelD'] }`.
// use "subField" for searching inside object Fields.
// For instance '{ 'customFields._id': ['field1','field2']} (subField would be: _id)
class SetFilter {
  constructor(subField = '') {
    this._dep = new Tracker.Dependency();
    this._selectedElements = [];
    this.subField = subField;
  }

  isSelected(val) {
    this._dep.depend();
    return this._selectedElements.indexOf(val) > -1;
  }

  add(val) {
    if (this._indexOfVal(val) === -1) {
      this._selectedElements.push(val);
      this._dep.changed();
      showFilterSidebar();
    }
  }

  remove(val) {
    const indexOfVal = this._indexOfVal(val);
    if (this._indexOfVal(val) !== -1) {
      this._selectedElements.splice(indexOfVal, 1);
      this._dep.changed();
    }
  }

  toggle(val) {
    if (this._indexOfVal(val) === -1) {
      this.add(val);
    } else {
      this.remove(val);
    }
  }

  reset() {
    this._selectedElements = [];
    this._dep.changed();
  }

  _indexOfVal(val) {
    return this._selectedElements.indexOf(val);
  }

  _isActive() {
    this._dep.depend();
    return this._selectedElements.length !== 0;
  }

  _getMongoSelector() {
    this._dep.depend();
    return { $in: this._selectedElements };
  }

  _getEmptySelector() {
    this._dep.depend();
    let includeEmpty = false;
    this._selectedElements.forEach((el) => {
      if (el === undefined) {
        includeEmpty = true;
      }
    });
    return includeEmpty ? { $eq: [] } : null;
  }
}

// Advanced filter forms a MongoSelector from a users String.
// Build by: Ignatz 19.05.2018 (github feuerball11)
class AdvancedFilter {
  constructor() {
    this._dep = new Tracker.Dependency();
    this._filter = '';
  }

  set(str)
  {
    this._filter = str;
    this._dep.changed();
  }

  reset() {
    this._filter = '';
    this._dep.changed();
  }

  _isActive() {
    this._dep.depend();
    return this._filter !== '';
  }

  _filterToCommands(){
    const commands = [];
    let current = '';
    let string = false;
    let wasString = false;
    let ignore = false;
    for (let i = 0; i < this._filter.length; i++)
    {
      const char = this._filter.charAt(i);
      if (ignore)
      {
        ignore = false;
        continue;
      }
      if (char === '\'')
      {
        string = !string;
        if (string) wasString = true;
        continue;
      }
      if (char === '\\')
      {
        ignore = true;
        continue;
      }
      if (char === ' ' && !string)
      {
        commands.push({'cmd':current, 'string':wasString});
        wasString = false;
        current = '';
        continue;
      }
      current += char;
    }
    if (current !== '')
    {
      commands.push({'cmd':current, 'string':wasString});
    }
    return commands;
  }

  _fieldNameToId(field)
  {
    console.log("searching: "+field);
    const found = CustomFields.findOne({'name':field});
    console.log(found);
    return found._id;
  }

  _arrayToSelector(commands)
  {
    console.log(commands);
    try {
      //let changed = false;
      for (let i = 0; i < commands.length; i++)
      {
        if (!commands[i].string && commands[i].cmd)
        {
          switch (commands[i].cmd)
          {
          case '=':
          case '==':
          case '===':
          {
            const field = commands[i-1].cmd;
            const str = commands[i+1].cmd;
            commands[i] = {'customFields._id':this._fieldNameToId(field), 'customFields.value':str};
            commands.splice(i-1, 1);
            commands.splice(i, 1);
            //changed = true;
            i--;
            break;
          }

          }
        }
      }
    }
    catch (e){return { $in: [] };}
    return {$or: commands};
  }

  _getMongoSelector() {
    this._dep.depend();
    const commands = this._filterToCommands();
    return this._arrayToSelector(commands);
  }

}

// The global Filter object.
// XXX It would be possible to re-write this object more elegantly, and removing
// the need to provide a list of `_fields`. We also should move methods into the
// object prototype.
Filter = {
  // XXX I would like to rename this field into `labels` to be consistent with
  // the rest of the schema, but we need to set some migrations architecture
  // before changing the schema.
  labelIds: new SetFilter(),
  members: new SetFilter(),
  customFields: new SetFilter('_id'),
  advanced: new AdvancedFilter(),

  _fields: ['labelIds', 'members', 'customFields'],

  // We don't filter cards that have been added after the last filter change. To
  // implement this we keep the id of these cards in this `_exceptions` fields
  // and use a `$or` condition in the mongo selector we return.
  _exceptions: [],
  _exceptionsDep: new Tracker.Dependency(),

  isActive() {
    return _.any(this._fields, (fieldName) => {
      return this[fieldName]._isActive();
    }) || this.advanced._isActive();
  },

  _getMongoSelector() {
    if (!this.isActive())
      return {};

    const filterSelector = {};
    const emptySelector = {};
    let includeEmptySelectors = false;
    this._fields.forEach((fieldName) => {
      const filter = this[fieldName];
      if (filter._isActive()) {
        if (filter.subField !== '')
        {
          filterSelector[`${fieldName}.${filter.subField}`] = filter._getMongoSelector();
        }
        else
        {
          filterSelector[fieldName] = filter._getMongoSelector();
        }
        emptySelector[fieldName] = filter._getEmptySelector();
        if (emptySelector[fieldName] !== null) {
          includeEmptySelectors = true;
        }
      }
    });

    const exceptionsSelector = {_id: {$in: this._exceptions}};
    this._exceptionsDep.depend();

    const selectors = [exceptionsSelector];

    if (_.any(this._fields, (fieldName) => {
      return this[fieldName]._isActive();
    })) selectors.push(filterSelector);
    if (includeEmptySelectors) selectors.push(emptySelector);
    if (this.advanced._isActive()) selectors.push(this.advanced._getMongoSelector());

    return {$or: selectors};
  },

  mongoSelector(additionalSelector) {
    const filterSelector = this._getMongoSelector();
    if (_.isUndefined(additionalSelector))
      return filterSelector;
    else
      return {$and: [filterSelector, additionalSelector]};
  },

  reset() {
    this._fields.forEach((fieldName) => {
      const filter = this[fieldName];
      filter.reset();
    });
    this.resetExceptions();
  },

  addException(_id) {
    if (this.isActive()) {
      this._exceptions.push(_id);
      this._exceptionsDep.changed();
      Tracker.flush();
    }
  },

  resetExceptions() {
    this._exceptions = [];
    this._exceptionsDep.changed();
  },
};

Blaze.registerHelper('Filter', Filter);
<commit_msg>Testing 'or' condition for advanced Filter<commit_after>// Filtered view manager
// We define local filter objects for each different type of field (SetFilter,
// RangeFilter, dateFilter, etc.). We then define a global `Filter` object whose
// goal is to filter complete documents by using the local filters for each
// fields.

function showFilterSidebar() {
  Sidebar.setView('filter');
}

// Use a "set" filter for a field that is a set of documents uniquely
// identified. For instance `{ labels: ['labelA', 'labelC', 'labelD'] }`.
// use "subField" for searching inside object Fields.
// For instance '{ 'customFields._id': ['field1','field2']} (subField would be: _id)
class SetFilter {
  constructor(subField = '') {
    this._dep = new Tracker.Dependency();
    this._selectedElements = [];
    this.subField = subField;
  }

  isSelected(val) {
    this._dep.depend();
    return this._selectedElements.indexOf(val) > -1;
  }

  add(val) {
    if (this._indexOfVal(val) === -1) {
      this._selectedElements.push(val);
      this._dep.changed();
      showFilterSidebar();
    }
  }

  remove(val) {
    const indexOfVal = this._indexOfVal(val);
    if (this._indexOfVal(val) !== -1) {
      this._selectedElements.splice(indexOfVal, 1);
      this._dep.changed();
    }
  }

  toggle(val) {
    if (this._indexOfVal(val) === -1) {
      this.add(val);
    } else {
      this.remove(val);
    }
  }

  reset() {
    this._selectedElements = [];
    this._dep.changed();
  }

  _indexOfVal(val) {
    return this._selectedElements.indexOf(val);
  }

  _isActive() {
    this._dep.depend();
    return this._selectedElements.length !== 0;
  }

  _getMongoSelector() {
    this._dep.depend();
    return { $in: this._selectedElements };
  }

  _getEmptySelector() {
    this._dep.depend();
    let includeEmpty = false;
    this._selectedElements.forEach((el) => {
      if (el === undefined) {
        includeEmpty = true;
      }
    });
    return includeEmpty ? { $eq: [] } : null;
  }
}

// Advanced filter forms a MongoSelector from a users String.
// Build by: Ignatz 19.05.2018 (github feuerball11)
class AdvancedFilter {
  constructor() {
    this._dep = new Tracker.Dependency();
    this._filter = '';
  }

  set(str)
  {
    this._filter = str;
    this._dep.changed();
  }

  reset() {
    this._filter = '';
    this._dep.changed();
  }

  _isActive() {
    this._dep.depend();
    return this._filter !== '';
  }

  _filterToCommands(){
    const commands = [];
    let current = '';
    let string = false;
    let wasString = false;
    let ignore = false;
    for (let i = 0; i < this._filter.length; i++)
    {
      const char = this._filter.charAt(i);
      if (ignore)
      {
        ignore = false;
        continue;
      }
      if (char === '\'')
      {
        string = !string;
        if (string) wasString = true;
        continue;
      }
      if (char === '\\')
      {
        ignore = true;
        continue;
      }
      if (char === ' ' && !string)
      {
        commands.push({'cmd':current, 'string':wasString});
        wasString = false;
        current = '';
        continue;
      }
      current += char;
    }
    if (current !== '')
    {
      commands.push({'cmd':current, 'string':wasString});
    }
    return commands;
  }

  _fieldNameToId(field)
  {
    console.log(`searching: ${field}`);
    const found = CustomFields.findOne({'name':field});
    console.log(found);
    return found._id;
  }

  _arrayToSelector(commands)
  {
    console.log(commands);
    try {
      //let changed = false;
      this._processConditions(commands);
      this._processLogicalOperators(commands);
    }
    catch (e){return { $in: [] };}
    return {$or: commands};
  }

  _processConditions(commands)
  {
    for (let i = 0; i < commands.length; i++)
    {
      if (!commands[i].string && commands[i].cmd)
      {
        switch (commands[i].cmd)
        {
        case '=':
        case '==':
        case '===':
        {
          const field = commands[i-1].cmd;
          const str = commands[i+1].cmd;
          commands[i] = {'customFields._id':this._fieldNameToId(field), 'customFields.value':str};
          commands.splice(i-1, 1);
          commands.splice(i, 1);
          //changed = true;
          i--;
          break;
        }

        }
      }
    }
  }

  _processLogicalOperators(commands)
  {
    for (let i = 0; i < commands.length; i++)
    {
      if (!commands[i].string && commands[i].cmd)
      {
        switch (commands[i].cmd)
        {
        case 'or':
        case 'Or':
        case 'OR':
        case '|':
        case '||':
        {
          const op1 = commands[i-1].cmd;
          const op2 = commands[i+1].cmd;
          commands[i] = {$or: [op1, op2]};
          commands.splice(i-1, 1);
          commands.splice(i, 1);
          //changed = true;
          i--;
          break;
        }

        }
      }
    }
  }

  _getMongoSelector() {
    this._dep.depend();
    const commands = this._filterToCommands();
    return this._arrayToSelector(commands);
  }

}

// The global Filter object.
// XXX It would be possible to re-write this object more elegantly, and removing
// the need to provide a list of `_fields`. We also should move methods into the
// object prototype.
Filter = {
  // XXX I would like to rename this field into `labels` to be consistent with
  // the rest of the schema, but we need to set some migrations architecture
  // before changing the schema.
  labelIds: new SetFilter(),
  members: new SetFilter(),
  customFields: new SetFilter('_id'),
  advanced: new AdvancedFilter(),

  _fields: ['labelIds', 'members', 'customFields'],

  // We don't filter cards that have been added after the last filter change. To
  // implement this we keep the id of these cards in this `_exceptions` fields
  // and use a `$or` condition in the mongo selector we return.
  _exceptions: [],
  _exceptionsDep: new Tracker.Dependency(),

  isActive() {
    return _.any(this._fields, (fieldName) => {
      return this[fieldName]._isActive();
    }) || this.advanced._isActive();
  },

  _getMongoSelector() {
    if (!this.isActive())
      return {};

    const filterSelector = {};
    const emptySelector = {};
    let includeEmptySelectors = false;
    this._fields.forEach((fieldName) => {
      const filter = this[fieldName];
      if (filter._isActive()) {
        if (filter.subField !== '')
        {
          filterSelector[`${fieldName}.${filter.subField}`] = filter._getMongoSelector();
        }
        else
        {
          filterSelector[fieldName] = filter._getMongoSelector();
        }
        emptySelector[fieldName] = filter._getEmptySelector();
        if (emptySelector[fieldName] !== null) {
          includeEmptySelectors = true;
        }
      }
    });

    const exceptionsSelector = {_id: {$in: this._exceptions}};
    this._exceptionsDep.depend();

    const selectors = [exceptionsSelector];

    if (_.any(this._fields, (fieldName) => {
      return this[fieldName]._isActive();
    })) selectors.push(filterSelector);
    if (includeEmptySelectors) selectors.push(emptySelector);
    if (this.advanced._isActive()) selectors.push(this.advanced._getMongoSelector());

    return {$or: selectors};
  },

  mongoSelector(additionalSelector) {
    const filterSelector = this._getMongoSelector();
    if (_.isUndefined(additionalSelector))
      return filterSelector;
    else
      return {$and: [filterSelector, additionalSelector]};
  },

  reset() {
    this._fields.forEach((fieldName) => {
      const filter = this[fieldName];
      filter.reset();
    });
    this.resetExceptions();
  },

  addException(_id) {
    if (this.isActive()) {
      this._exceptions.push(_id);
      this._exceptionsDep.changed();
      Tracker.flush();
    }
  },

  resetExceptions() {
    this._exceptions = [];
    this._exceptionsDep.changed();
  },
};

Blaze.registerHelper('Filter', Filter);
<|endoftext|>


<commit_before>
var util = require('util');
var assert = require('assert');
const kueThreads = process.env.KUE_THREADS || 4;
const neo4jThreads = process.env.NEO4J_THREADS || 4;

const metrics = require('../../../lib/crow.js').init("importer", {
  api: "twitter",
  module: "friends",
  mvc: "controller",
  function: "save",
  kue: "saveFriend",
  kueThreads: kueThreads,
  neo4jThreads: neo4jThreads,
});
var queue = require('../../../lib/kue.js');
var neo4j = require('../../../lib/neo4j.js');
var RSVP = require('rsvp');
var logger = require('tracer').colorConsole( {
  level: 'info'
} );
var redis = require("redis").createClient({
  host: process.env.REDIS_HOST,
  port: parseInt(process.env.REDIS_PORT),
});

setInterval( function() {
  queue.inactiveCount( 'saveFriend', function( err, total ) { // others are activeCount, completeCount, failedCount, delayedCount
    metrics.setGauge("queue.inactive", total);
  });
  }, 15 * 1000 );

const metricFinish = metrics.counter("finish");
const metricStart = metrics.counter("start");
const metricKueTimer = metrics.distribution("kueue_ms");
const metricNeo4jTimer = metrics.distribution("neo4j_ms");
const metricRelFindError = metrics.counter("rel_find_error");
const metricRelAlreadyExists = metrics.counter("rel_already_exists");
const metricRelSaved = metrics.counter("rel_saved");

function saveFriend (job, done) {
  var startTime = process.hrtime();
  logger.trace("received job %j", job);
  var user = job.data.user;
  var friend = job.data.friend;
  var rel = job.data;
  metricStart.increment();

  function finished (done){
    metricFinish.increment();
    var diff = process.hrtime(startTime);
    metricKueTimer.add(diff[0] * 1e9 + diff[1]);
    logger.trace("finish")
    done();
  }

  upsertRelationship(user, friend).then(finished);

  var sem = require('semaphore')(neo4jThreads);
  function upsertRelationship(node, friend) {
    assert( typeof(node.id) == "number" );
    assert( typeof(friend.id) == "number" );
    return new RSVP.Promise( function (resolve, reject) {
    sem.take(function() {//timings
      var startNeo4jTime = process.hrtime();
      neo4j.queryRaw("start x=node({idx}), n=node({idn}) create unique (x)-[r:follows]->(n) RETURN r",
        { idx: node.id, idn: friend.id }, function(err, results) {
        sem.leave();
        var diff = process.hrtime(startNeo4jTime);
        metricKueTimer.add(diff[0] * 1e9 + diff[1]);
        if (err){
          if (err.code == "Neo.ClientError.Statement.ConstraintViolation") {
            metricRelAlreadyExists.increment();
            resolve();
          } else {
            logger.error("neo4j save error %j %j", { node: node, friend: friend }, err);
            reject("error");
          }
        } else {
          logger.debug("saved relationship %j", results);
          metricRelSaved.increment();
          resolve();
        }
      });
    });
  });
  }

};

queue.process('saveFriend', kueThreads, saveFriend );
<commit_msg>fix promise handling<commit_after>
var util = require('util');
var assert = require('assert');
const kueThreads = process.env.KUE_THREADS || 4;
const neo4jThreads = process.env.NEO4J_THREADS || 4;

const metrics = require('../../../lib/crow.js').init("importer", {
  api: "twitter",
  module: "friends",
  mvc: "controller",
  function: "save",
  kue: "saveFriend",
  kueThreads: kueThreads,
  neo4jThreads: neo4jThreads,
});
var queue = require('../../../lib/kue.js');
var neo4j = require('../../../lib/neo4j.js');
var RSVP = require('rsvp');
var logger = require('tracer').colorConsole( {
  level: 'info'
} );
var redis = require("redis").createClient({
  host: process.env.REDIS_HOST,
  port: parseInt(process.env.REDIS_PORT),
});

setInterval( function() {
  queue.inactiveCount( 'saveFriend', function( err, total ) { // others are activeCount, completeCount, failedCount, delayedCount
    metrics.setGauge("queue.inactive", total);
  });
  }, 15 * 1000 );

const metricFinish = metrics.counter("finish");
const metricStart = metrics.counter("start");
const metricKueTimer = metrics.distribution("kueue_ms");
const metricNeo4jTimer = metrics.distribution("neo4j_ms");
const metricRelFindError = metrics.counter("rel_find_error");
const metricRelAlreadyExists = metrics.counter("rel_already_exists");
const metricRelSaved = metrics.counter("rel_saved");

function saveFriend (job, done) {
  var startTime = process.hrtime();
  logger.trace("received job %j", job);
  var user = job.data.user;
  var friend = job.data.friend;
  var rel = job.data;
  metricStart.increment();

  function finished (done){
    metricFinish.increment();
    var diff = process.hrtime(startTime);
    metricKueTimer.add(diff[0] * 1e9 + diff[1]);
    logger.trace("finish")
    done();
  }

  upsertRelationship(user, friend).then(finished, done);

  var sem = require('semaphore')(neo4jThreads);
  function upsertRelationship(node, friend) {
    assert( typeof(node.id) == "number" );
    assert( typeof(friend.id) == "number" );
    return new RSVP.Promise( function (resolve, reject) {
    sem.take(function() {//timings
      var startNeo4jTime = process.hrtime();
      neo4j.queryRaw("start x=node({idx}), n=node({idn}) create unique (x)-[r:follows]->(n) RETURN r",
        { idx: node.id, idn: friend.id }, function(err, results) {
        sem.leave();
        var diff = process.hrtime(startNeo4jTime);
        metricKueTimer.add(diff[0] * 1e9 + diff[1]);
        if (err){
          if (err.code == "Neo.ClientError.Statement.ConstraintViolation") {
            metricRelAlreadyExists.increment();
            resolve();
          } else {
            logger.error("neo4j save error %j %j", { node: node, friend: friend }, err);
            reject("error");
          }
        } else {
          logger.debug("saved relationship %j", results);
          metricRelSaved.increment();
          resolve();
        }
      });
    });
  });
  }

};

queue.process('saveFriend', kueThreads, saveFriend );
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var path = require('path');
var webpack = require('webpack');
var findUp = require('find-up');

var hopsConfig = require('hops-config');

var checkEsnext = require('../lib/check-esnext');

function findNodeModules(start) {
  var modulesDir = findUp.sync('node_modules', { cwd: start });
  var files = fs.readdirSync(modulesDir);
  var containsModules = files.some(function(file) {
    return file.indexOf('.') !== 0;
  });
  if (!containsModules) {
    return findNodeModules(path.dirname(path.dirname(modulesDir)));
  }
  return modulesDir;
}

function shouldIncludeExternalModuleInBundle(module) {
  return (
    module.indexOf('hops') === 0 ||
    module.indexOf('core-js') === 0 ||
    module.indexOf('babel-polyfill') === 0 ||
    /^.*\.(?!js(?:on)?$)/.test(module) ||
    checkEsnext(module)
  );
}

var modulesDir = findNodeModules(process.cwd());

module.exports = {
  target: 'node',
  entry: require.resolve('../shims/node'),
  output: {
    path: hopsConfig.cacheDir,
    publicPath: '/',
    filename: 'server.js',
    libraryTarget: 'commonjs2',
    devtoolModuleFilenameTemplate: '[absolute-resource-path]',
    devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]',
  },
  context: hopsConfig.appDir,
  resolve: require('../sections/resolve')('node'),
  externals: [
    require('webpack-node-externals')({
      modulesDir: modulesDir,
      whitelist: shouldIncludeExternalModuleInBundle,
    }),
  ],
  module: {
    rules: require('../sections/module-rules')('node'),
  },
  plugins: [
    new webpack.optimize.LimitChunkCountPlugin({
      maxChunks: 1,
    }),
    new webpack.EnvironmentPlugin(
      Object.assign(
        {
          NODE_ENV: 'development',
        },
        hopsConfig.envVars
      )
    ),
  ],
  performance: {
    hints: false,
  },
  devtool: process.env.NODE_ENV !== 'production' && '#inline-source-map',
};
<commit_msg>feat(build-config): add .node files to exclusion regex<commit_after>'use strict';

var fs = require('fs');
var path = require('path');
var webpack = require('webpack');
var findUp = require('find-up');

var hopsConfig = require('hops-config');

var checkEsnext = require('../lib/check-esnext');

function findNodeModules(start) {
  var modulesDir = findUp.sync('node_modules', { cwd: start });
  var files = fs.readdirSync(modulesDir);
  var containsModules = files.some(function(file) {
    return file.indexOf('.') !== 0;
  });
  if (!containsModules) {
    return findNodeModules(path.dirname(path.dirname(modulesDir)));
  }
  return modulesDir;
}

function shouldIncludeExternalModuleInBundle(module) {
  return (
    module.indexOf('hops') === 0 ||
    module.indexOf('core-js') === 0 ||
    module.indexOf('babel-polyfill') === 0 ||
    // bundle everything the native require implementation can not handle
    // see: https://nodejs.org/api/modules.html#modules_all_together
    /^.*\.(?!(?:js|json|mjs|node)$)/.test(module) ||
    checkEsnext(module)
  );
}

var modulesDir = findNodeModules(process.cwd());

module.exports = {
  target: 'node',
  entry: require.resolve('../shims/node'),
  output: {
    path: hopsConfig.cacheDir,
    publicPath: '/',
    filename: 'server.js',
    libraryTarget: 'commonjs2',
    devtoolModuleFilenameTemplate: '[absolute-resource-path]',
    devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]',
  },
  context: hopsConfig.appDir,
  resolve: require('../sections/resolve')('node'),
  externals: [
    require('webpack-node-externals')({
      modulesDir: modulesDir,
      whitelist: shouldIncludeExternalModuleInBundle,
    }),
  ],
  module: {
    rules: require('../sections/module-rules')('node'),
  },
  plugins: [
    new webpack.optimize.LimitChunkCountPlugin({
      maxChunks: 1,
    }),
    new webpack.EnvironmentPlugin(
      Object.assign(
        {
          NODE_ENV: 'development',
        },
        hopsConfig.envVars
      )
    ),
  ],
  performance: {
    hints: false,
  },
  devtool: process.env.NODE_ENV !== 'production' && '#inline-source-map',
};
<|endoftext|>


<commit_before>/*
@license
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/

import Xen from '../../components/xen/xen.js';
import Arcs from '../lib/arcs.js';
import ArcsUtils from '../lib/arcs-utils.js';

const log = Xen.logFactory('ArcPlanner', '#104a91');
const error = Xen.logFactory('ArcPlanner', '#104a91', 'error');

// proposed:
// metaplans -> map of plans, generations
// metaplan -> map of plans, generations, plan
// suggestions -> filtered array of (simple-)plans
// suggestion -> (simple-)plan

class ArcPlanner extends Xen.Debug(Xen.Base, log) {
  static get observedAttributes() {
    return ['config', 'arc', 'suggestion', 'search', 'userid'];
  }
  _getInitialState() {
    return {
      pendingPlans: [],
      invalid: 0
    };
  }
  _willReceiveProps(props, state, oldProps) {
    const changed = name => props[name] !== oldProps[name];
    const {arc, suggestion, search, userid} = props;
    if (suggestion && changed('suggestion')) {
      state.pendingPlans.push(suggestion.plan);
    }
    if (arc && userid) {
      let {planificator} = state;
      if (changed('arc') || changed('userid')) {
        state.pendingPlans = [];
        if (planificator) {
          planificator.dispose();
          planificator = null;
        }
      }
      if (!planificator) {
        planificator = this._createPlanificator(arc, userid);
        planificator.setSearch(search);
      } else if (changed('search')) {
        planificator.setSearch(search);
      }
      this._setState({planificator});
    }
  }
  _update({arc}, {pendingPlans}) {
    if (arc && pendingPlans.length) {
      this._instantiatePlan(arc, pendingPlans.shift());
    }
  }
  _createPlanificator(arc, userid) {
    let planificatorMode = ArcsUtils.getUrlParam('planificator');
    const planificator = new Arcs.Planificator(arc, {userid, mode: planificatorMode});
    planificator.registerPlansChangedCallback(current => this._plansChanged(current, planificator.getLastActivatedPlan()));
    planificator.registerSuggestChangedCallback(suggestions => this._suggestionsChanged(suggestions));
    return planificator;
  }
  _plansChanged(metaplans, metaplan) {
    this._fire('metaplans', metaplans);
    this._fire('metaplan', metaplan);
  }
  _suggestionsChanged(suggestions) {
    this._fire('suggestions', suggestions);
  }
  async _instantiatePlan(arc, plan) {
    log('instantiating plan', plan);
    try {
      await arc.instantiate(plan);
    } catch (x) {
      error('plan instantiation failed', x);
    }
    // need new suggestions
    this._fire('suggestions', null);
  }
}
customElements.define('arc-planner', ArcPlanner);
<commit_msg>fix path to arcs-utils (#1927)<commit_after>/*
@license
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/

import Xen from '../../components/xen/xen.js';
import Arcs from '../../lib/arcs.js';
import ArcsUtils from '../../lib/arcs-utils.js';

const log = Xen.logFactory('ArcPlanner', '#104a91');
const error = Xen.logFactory('ArcPlanner', '#104a91', 'error');

// proposed:
// metaplans -> map of plans, generations
// metaplan -> map of plans, generations, plan
// suggestions -> filtered array of (simple-)plans
// suggestion -> (simple-)plan

class ArcPlanner extends Xen.Debug(Xen.Base, log) {
  static get observedAttributes() {
    return ['config', 'arc', 'suggestion', 'search', 'userid'];
  }
  _getInitialState() {
    return {
      pendingPlans: [],
      invalid: 0
    };
  }
  _willReceiveProps(props, state, oldProps) {
    const changed = name => props[name] !== oldProps[name];
    const {arc, suggestion, search, userid} = props;
    if (suggestion && changed('suggestion')) {
      state.pendingPlans.push(suggestion.plan);
    }
    if (arc && userid) {
      let {planificator} = state;
      if (changed('arc') || changed('userid')) {
        state.pendingPlans = [];
        if (planificator) {
          planificator.dispose();
          planificator = null;
        }
      }
      if (!planificator) {
        planificator = this._createPlanificator(arc, userid);
        planificator.setSearch(search);
      } else if (changed('search')) {
        planificator.setSearch(search);
      }
      this._setState({planificator});
    }
  }
  _update({arc}, {pendingPlans}) {
    if (arc && pendingPlans.length) {
      this._instantiatePlan(arc, pendingPlans.shift());
    }
  }
  _createPlanificator(arc, userid) {
    let planificatorMode = ArcsUtils.getUrlParam('planificator');
    const planificator = new Arcs.Planificator(arc, {userid, mode: planificatorMode});
    planificator.registerPlansChangedCallback(current => this._plansChanged(current, planificator.getLastActivatedPlan()));
    planificator.registerSuggestChangedCallback(suggestions => this._suggestionsChanged(suggestions));
    return planificator;
  }
  _plansChanged(metaplans, metaplan) {
    this._fire('metaplans', metaplans);
    this._fire('metaplan', metaplan);
  }
  _suggestionsChanged(suggestions) {
    this._fire('suggestions', suggestions);
  }
  async _instantiatePlan(arc, plan) {
    log('instantiating plan', plan);
    try {
      await arc.instantiate(plan);
    } catch (x) {
      error('plan instantiation failed', x);
    }
    // need new suggestions
    this._fire('suggestions', null);
  }
}
customElements.define('arc-planner', ArcPlanner);
<|endoftext|>


<commit_before>// A template handling library that brings in all Handlebars templates and partials and adds functions for more easily using them.
//
// Requires Handlebars.js and Pagedown (for markdown rendering)

(function ($) {
    "use strict";
    var templates = fluid.registerNamespace("ctr.components.templates");
    templates.compiled = {};

    // Add support for markdown if pagedown is available
    templates.mdHelper = function(options) {
        if (Markdown && Markdown.getSanitizingConverter) {
            var converter = Markdown.getSanitizingConverter();
            // Double all single carriage returns so that they result in new paragraphs, at least for now
            converter.hooks.chain("preConversion", function (text) { return text.replace(/[\r\n]+/g, "\n\n"); });
            return converter.makeHtml(options.fn(this));
        }
        else {
            console.log("Pagedown or one of its dependencies is not available, so markdown will be passed on without any changes.");
        }

        // If we can't evolve the output, we just pass it through.
        return options.fn(this);
    };

    Handlebars.registerHelper('md', templates.mdHelper);

    templates.render = function(key,context) {
        // If a template exists, load that.  Otherwise, try to load the partial.
        var element = $("#partial-" + key).length ? $("#partial-" + key) : $("#template-" + key);

        // Cache each compiled template the first time we use it...
        if (templates.compiled[key]) {
            return templates.compiled[key](context);
        }
        else {
            if (!element || !element.html()) {
                console.log("Template '" + key + "' does not have any content. Skipping");
                return;
            }

            var template = Handlebars.compile(element.html());
            templates.compiled[key] = template;
            return template(context);
        }
    };

    templates.replaceWith = function(element,key,context) {
        element.html(templates.render(key,context));
    };

    templates.appendTo = function(element,key,context) {
        element.append(templates.render(key,context));
    };

    templates.prependTo = function (element,key,context) {
        element.prepend(templates.render(key,context));
    };

    templates.appendToBody = function (data, textStatus, jqXHR) {
        // TODO:  Replace this with a {that} reference
        $("body").append(data);

        // load all partials so that we can use them in context
        $("[id^=partial-]").each(function(index, element) {
            var id = element.id;
            var key = id.substring(id.indexOf("-")+1);
            Handlebars.registerPartial(key,$("#" + id).html());
        });
    };

    templates.loadTemplates = function(callback){
        var settings = {
            url: "/hbs",
            success: templates.appendToBody
        };
        if (callback) {
            $.ajax(settings).then(callback);
        }
        else {
            $.ajax(settings);
        }
    };
})(jQuery);

<commit_msg>Added "stringify" helper to convert objects to JSON strings (useful for troubleshooting as well as converting to hidden form values).<commit_after>// A template handling library that brings in all Handlebars templates and partials and adds functions for more easily using them.
//
// Requires Handlebars.js and Pagedown (for markdown rendering)

(function ($) {
    "use strict";
    var templates = fluid.registerNamespace("ctr.components.templates");
    templates.compiled = {};

    // Add support for markdown if pagedown is available
    templates.stringify = function(options) {
        return options.fn(JSON.stringify(this));
    };

    templates.mdHelper = function(options) {
        if (Markdown && Markdown.getSanitizingConverter) {
            var converter = Markdown.getSanitizingConverter();
            // Double all single carriage returns so that they result in new paragraphs, at least for now
            converter.hooks.chain("preConversion", function (text) { return text.replace(/[\r\n]+/g, "\n\n"); });
            return converter.makeHtml(options.fn(this));
        }
        else {
            console.log("Pagedown or one of its dependencies is not available, so markdown will be passed on without any changes.");
        }

        // If we can't evolve the output, we just pass it through.
        return options.fn(this);
    };

    Handlebars.registerHelper('md', templates.mdHelper);
    Handlebars.registerHelper('stringify', templates.stringify);

    templates.render = function(key,context) {
        // If a template exists, load that.  Otherwise, try to load the partial.
        var element = $("#partial-" + key).length ? $("#partial-" + key) : $("#template-" + key);

        // Cache each compiled template the first time we use it...
        if (templates.compiled[key]) {
            return templates.compiled[key](context);
        }
        else {
            if (!element || !element.html()) {
                console.log("Template '" + key + "' does not have any content. Skipping");
                return;
            }

            var template = Handlebars.compile(element.html());
            templates.compiled[key] = template;
            return template(context);
        }
    };

    templates.replaceWith = function(element,key,context) {
        element.html(templates.render(key,context));
    };

    templates.appendTo = function(element,key,context) {
        element.append(templates.render(key,context));
    };

    templates.prependTo = function (element,key,context) {
        element.prepend(templates.render(key,context));
    };

    templates.appendToBody = function (data, textStatus, jqXHR) {
        // TODO:  Replace this with a {that} reference
        $("body").append(data);

        // load all partials so that we can use them in context
        $("[id^=partial-]").each(function(index, element) {
            var id = element.id;
            var key = id.substring(id.indexOf("-")+1);
            Handlebars.registerPartial(key,$("#" + id).html());
        });
    };

    templates.loadTemplates = function(callback){
        var settings = {
            url: "/hbs",
            success: templates.appendToBody
        };
        if (callback) {
            $.ajax(settings).then(callback);
        }
        else {
            $.ajax(settings);
        }
    };
})(jQuery);

<|endoftext|>


<commit_before>/**
 * Crowi context class for client
 */

import axios from 'axios'
import io from 'socket.io-client';

export default class Crowi {
  constructor(context, window) {
    this.context = context;
    this.config = {};
    this.csrfToken = context.csrfToken;

    this.window = window;
    this.location = window.location || {};
    this.document = window.document || {};
    this.localStorage = window.localStorage || {};

    this.fetchUsers = this.fetchUsers.bind(this);
    this.apiGet = this.apiGet.bind(this);
    this.apiPost = this.apiPost.bind(this);
    this.apiRequest = this.apiRequest.bind(this);

    // FIXME
    this.me = context.me;

    this.users = [];
    this.userByName = {};
    this.userById   = {};
    this.draft = {};

    this.recoverData();

    this.socket = io();
  }

  getContext() {
    return context;
  }

  setConfig(config) {
    this.config = config;
  }

  getConfig() {
    return this.config;
  }

  getWebSocket() {
    return this.socket;
  }

  recoverData() {
    const keys = [
      'userByName',
      'userById',
      'users',
      'draft',
    ];

    keys.forEach(key => {
      if (this.localStorage[key]) {
        try {
          this[key] = JSON.parse(this.localStorage[key]);
        } catch (e) {
          this.localStorage.removeItem(key);
        }
      }
    });
  }

  fetchUsers () {
    const interval = 1000*60*15; // 15min
    const currentTime = new Date();
    if (this.localStorage.lastFetched && interval > currentTime - new Date(this.localStorage.lastFetched)) {
      return ;
    }

    this.apiGet('/users.list', {})
    .then(data => {
      this.users = data.users;
      this.localStorage.users = JSON.stringify(data.users);

      let userByName = {};
      let userById = {};
      for (let i = 0; i < data.users.length; i++) {
        const user = data.users[i];
        userByName[user.username] = user;
        userById[user._id] = user;
      }
      this.userByName = userByName;
      this.localStorage.userByName = JSON.stringify(userByName);

      this.userById = userById;
      this.localStorage.userById = JSON.stringify(userById);

      this.localStorage.lastFetched = new Date();
    }).catch(err => {
      this.localStorage.removeItem('lastFetched');
      // ignore errors
    });
  }

  clearDraft(path) {
    delete this.draft[path];
    this.localStorage.draft = JSON.stringify(this.draft);
  }

  saveDraft(path, body) {
    this.draft[path] = body;
    this.localStorage.draft = JSON.stringify(this.draft);
  }

  findDraft(path) {
    if (this.draft && this.draft[path]) {
      return this.draft[path];
    }

    return null;
  }

  findUserById(userId) {
    if (this.userById && this.userById[userId]) {
      return this.userById[userId];
    }

    return null;
  }

  findUserByIds(userIds) {
    let users = [];
    for (let userId of userIds) {
      let user = this.findUserById(userId);
      if (user) {
        users.push(user);
      }
    }

    return users;
  }

  findUser(username) {
    if (this.userByName && this.userByName[username]) {
      return this.userByName[username];
    }

    return null;
  }

  apiGet(path, params) {
    return this.apiRequest('get', path, {params: params});
  }

  apiPost(path, params) {
    if (!params._csrf) {
      params._csrf = this.csrfToken;
    }

    return this.apiRequest('post', path, params);
  }

  apiRequest(method, path, params) {
    return new Promise((resolve, reject) => {
      const createError = (message, info = {}) => {
        let error = new Error(message);
        error.info = info;
        return error;
      };
      axios[method](`/_api${path}`, params)
      .then(({ error, data }) => {
        if (data.ok) {
          resolve(data);
        } else {
          // FIXME?
          reject(createError(error, data.info));
        }
      }).catch(() => {
        // FIXME?
        reject(createError('Error'));
      });
    });
  }

  static escape (html, encode) {
    return html
      .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
      .replace(/</g, '<')
      .replace(/>/g, '>')
      .replace(/"/g, '"')
      .replace(/'/g, ''');
  }

  static unescape(html) {
    return html.replace(/&([#\w]+);/g, function(_, n) {
      n = n.toLowerCase();
      if (n === 'colon') return ':';
      if (n.charAt(0) === '#') {
        return n.charAt(1) === 'x'
          ? String.fromCharCode(parseInt(n.substring(2), 16))
          : String.fromCharCode(+n.substring(1));
      }
      return '';
    });
  }
}

<commit_msg>Use async/await<commit_after>/**
 * Crowi context class for client
 */

import axios from 'axios'
import io from 'socket.io-client';

export default class Crowi {
  constructor(context, window) {
    this.context = context;
    this.config = {};
    this.csrfToken = context.csrfToken;

    this.window = window;
    this.location = window.location || {};
    this.document = window.document || {};
    this.localStorage = window.localStorage || {};

    this.fetchUsers = this.fetchUsers.bind(this);
    this.apiGet = this.apiGet.bind(this);
    this.apiPost = this.apiPost.bind(this);
    this.apiRequest = this.apiRequest.bind(this);

    // FIXME
    this.me = context.me;

    this.users = [];
    this.userByName = {};
    this.userById   = {};
    this.draft = {};

    this.recoverData();

    this.socket = io();
  }

  getContext() {
    return context;
  }

  setConfig(config) {
    this.config = config;
  }

  getConfig() {
    return this.config;
  }

  getWebSocket() {
    return this.socket;
  }

  recoverData() {
    const keys = [
      'userByName',
      'userById',
      'users',
      'draft',
    ];

    keys.forEach(key => {
      if (this.localStorage[key]) {
        try {
          this[key] = JSON.parse(this.localStorage[key]);
        } catch (e) {
          this.localStorage.removeItem(key);
        }
      }
    });
  }

  fetchUsers () {
    const interval = 1000*60*15; // 15min
    const currentTime = new Date();
    if (this.localStorage.lastFetched && interval > currentTime - new Date(this.localStorage.lastFetched)) {
      return ;
    }

    this.apiGet('/users.list', {})
    .then(data => {
      this.users = data.users;
      this.localStorage.users = JSON.stringify(data.users);

      let userByName = {};
      let userById = {};
      for (let i = 0; i < data.users.length; i++) {
        const user = data.users[i];
        userByName[user.username] = user;
        userById[user._id] = user;
      }
      this.userByName = userByName;
      this.localStorage.userByName = JSON.stringify(userByName);

      this.userById = userById;
      this.localStorage.userById = JSON.stringify(userById);

      this.localStorage.lastFetched = new Date();
    }).catch(err => {
      this.localStorage.removeItem('lastFetched');
      // ignore errors
    });
  }

  clearDraft(path) {
    delete this.draft[path];
    this.localStorage.draft = JSON.stringify(this.draft);
  }

  saveDraft(path, body) {
    this.draft[path] = body;
    this.localStorage.draft = JSON.stringify(this.draft);
  }

  findDraft(path) {
    if (this.draft && this.draft[path]) {
      return this.draft[path];
    }

    return null;
  }

  findUserById(userId) {
    if (this.userById && this.userById[userId]) {
      return this.userById[userId];
    }

    return null;
  }

  findUserByIds(userIds) {
    let users = [];
    for (let userId of userIds) {
      let user = this.findUserById(userId);
      if (user) {
        users.push(user);
      }
    }

    return users;
  }

  findUser(username) {
    if (this.userByName && this.userByName[username]) {
      return this.userByName[username];
    }

    return null;
  }

  async apiGet(path, params) {
    return await this.apiRequest('get', path, {params: params});
  }

  async apiPost(path, params) {
    if (!params._csrf) {
      params._csrf = this.csrfToken;
    }

    return await this.apiRequest('post', path, params);
  }

  async apiRequest(method, path, params) {
    const createError = (message, info = {}) => {
      let error = new Error(message);
      error.info = info;
      return error;
    };
    const { data } = await axios[method](`/_api${path}`, params)
      .catch(function () {
        throw createError("Error");
      });
    const { ok, error, info } = data;
    if (ok) {
      return data;
    }
    throw createError(error, info);
  }

  static escape (html, encode) {
    return html
      .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
      .replace(/</g, '<')
      .replace(/>/g, '>')
      .replace(/"/g, '"')
      .replace(/'/g, ''');
  }

  static unescape(html) {
    return html.replace(/&([#\w]+);/g, function(_, n) {
      n = n.toLowerCase();
      if (n === 'colon') return ':';
      if (n.charAt(0) === '#') {
        return n.charAt(1) === 'x'
          ? String.fromCharCode(parseInt(n.substring(2), 16))
          : String.fromCharCode(+n.substring(1));
      }
      return '';
    });
  }
}

<|endoftext|>