<commit_before>exports.encode = encode
exports.decode = decode

var seen = []
function encode (obj, indent) {
  var deep = arguments[2]
  if (!indent) indent = "  "

  if (obj instanceof String ||
      Object.prototype.toString.call(obj) === "[object String]") {
    obj = obj.toString()
  }

  if (obj instanceof Number ||
      Object.prototype.toString.call(obj) === "[object Number]") {
    obj = obj.valueOf()
  }

  // take out the easy ones.
  switch (typeof obj) {
    case "string":
      obj = obj.trim()
      if (obj.indexOf("\n") !== -1) {
        return "|\n" + indent + obj.split(/\r?\n/).join("\n"+indent)
      } else if (obj.indexOf(":") !== -1) {
        return JSON.stringify(obj)
      } else {
        return obj
      }

    case "number":
      return obj.toString(10)

    case "function":
      return encode(obj.toString(), indent, true)

    case "boolean":
      return obj.toString()

    case "undefined":
      // fallthrough
    case "object":
      // at this point we know it types as an object
      if (!obj) return "~"

      if (obj instanceof Date ||
          Object.prototype.toString.call(obj) === "[object Date]") {
        return "[Date " + obj.toISOString() + "]"
      }

      if (obj instanceof RegExp ||
          Object.prototype.toString.call(obj) === "[object RegExp]" ||
          obj instanceof Boolean ||
          Object.prototype.toString.call(obj) === "[object Boolean]"
         ) {
        return obj.toString()
      }

      if (seen.indexOf(obj) !== -1) {
        return "[Circular]"
      }
      seen.push(obj)

      if (typeof Buffer === "function" &&
          typeof Buffer.isBuffer === "function" &&
          Buffer.isBuffer(obj)) return obj.inspect()

      if (obj instanceof Error) {
        var o = { name: obj.name
                , message: obj.message
                , type: obj.type }

        if (obj.code) o.code = obj.code
        if (obj.errno) o.errno = obj.errno
        if (obj.type) o.type = obj.type
        obj = o
      }

      var out = ""

      if (Array.isArray(obj)) {
        var out = "\n" + indent + "- " +obj.map(function (item) {
          return encode(item, indent + "  ", true)
        }).join("\n"+indent + "- ")
        break
      }

      // an actual object
      var keys = Object.keys(obj)
        , niceKeys = keys.map(function (k) {
            return (k.match(/^[a-zA-Z0-9_]+$/) ? k : JSON.stringify(k)) + ": "
          })
      //console.error(keys, niceKeys, obj)
      var maxLength = Math.max.apply(Math, niceKeys.map(function (k) {
            return k.length
          }).concat(0))
      //console.error(niceKeys, maxLength)

      var spaces = new Array(maxLength + 1).join(" ")

      if (!deep) indent += "  "
      out = "\n" + indent + keys.map(function (k, i) {
        var niceKey = niceKeys[i]
        return niceKey + spaces.substr(niceKey.length)
                       + encode(obj[k], indent + "  ", true)
      }).join("\n" + indent)
      break

    default: return ""
  }
  if (!deep) seen.length = 0
  return out
}

function decode (str) {
  var v = str.trim()
    , d
  if (v === "~") return null
  if (v.match(/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}/)
      && (d = Date.parse(v))) {
    return new Date(d)
  }
  if (v === "true" || v === "false") return JSON.parse(v)
  if (v && !isNaN(v)) return parseInt(v, 10)
  // something interesting.
  var lines = str.split(/\r?\n/)
  // check if it's some kind of string or something.
  // if the first line is > or | then it's a wrapping indented string.
  // if the first line is blank, and there are many lines,
  // then it's an array or object.
  // otherwise, it's just ""
  var first = lines.shift().trim()
  if (lines.length) lines = undent(lines)
  switch (first) {
    case "|":
      return lines.join("\n")
    case ">":
      return lines.join("\n").split(/\n{2,}/).map(function (l) {
        return l.split(/\n/).join(" ")
      }).join("\n")
    default:
      if (!lines.length) return first
      // array or object.
      // the first line will be either "- value" or "key: value"
      return lines[0].charAt(0) === "-" ? decodeArr(lines) : decodeObj(lines)
  }
}

function decodeArr (lines) {
  var out = []
    , key = 0
    , val = []
  for (var i = 0, l = lines.length; i < l; i ++) {
    // if it starts with a -, then it's a new thing
    var line = lines[i]
    if (line.charAt(0) === "-") {
      if (val.length) {
        out[key ++] = decode(val.join("\n"))
        val.length = 0
      }
      val.push(line.substr(1).trim())
    } else if (line.charAt(0) === " ") {
      val.push(line)
    } else return []
  }
  if (val.length) {
    out[key ++] = decode(val.join("\n"))
  }
  return out
}

function decodeObj (lines) {
  var out = {}
    , val = []
    , key = null

  for (var i = 0, l = lines.length; i < l; i ++) {
    var line = lines[i]
    if (line.charAt(0) === " ") {
      val.push(line)
      continue
    }
    // some key:val
    if (val.length) {
      out[key] = decode(val.join("\n"))
      val.length = 0
    }
    // parse out the quoted key
    var first
    if (line.charAt(0) === "\"") {
      for (var ii = 1, ll = line.length, esc = false; ii < ll; ii ++) {
        var c = line.charAt(ii)
        if (c === "\\") {
          esc = !esc
        } else if (c === "\"" && !esc) {
          break
        }
      }
      key = JSON.parse(line.substr(0, ii + 1))
      line = line.substr(ii + 1)
      first = line.substr(line.indexOf(":") + 1).trim()
    } else {
      var kv = line.split(":")
      key = kv.shift()
      first = kv.join(":").trim()
    }
    // now we've set a key, and "first" has the first line of the value.
    val.push(first.trim())
  }
  if (val.length) out[key] = decode(val.join("\n"))
  return out
}

function undent (lines) {
  var i = lines[0].match(/^\s*/)[0].length
  return lines.map(function (line) {
    return line.substr(i)
  })
}

if (require.main === module) {
var obj = [{"bigstring":new Error().stack}
          ,{ar:[{list:"of"},{some:"objects"}]}
          ,{date:new Date()}
          ,{"super huge string":new Error().stack}
          ]

Date.prototype.toJSON = function (k, val) {
  console.error(k, val, this)
  return this.toISOString() + " (it's a date)"
}
var enc = encode(obj)
  , dec = decode(enc)
  , encDec = encode(dec)

console.error(JSON.stringify({ obj : obj
                             , enc : enc.split(/\n/)
                             , dec : dec }, null, 2), encDec === enc)

var num = 100
  , encNum = encode(num)
  , decEncNum = decode(encNum)
console.error([num, encNum, decEncNum])
}
<commit_msg>Quote all strings. Parse dates properly.<commit_after>exports.encode = encode
exports.decode = decode

var seen = []
function encode (obj, indent) {
  var deep = arguments[2]
  if (!indent) indent = "  "

  if (obj instanceof String ||
      Object.prototype.toString.call(obj) === "[object String]") {
    obj = obj.toString()
  }

  if (obj instanceof Number ||
      Object.prototype.toString.call(obj) === "[object Number]") {
    obj = obj.valueOf()
  }

  // take out the easy ones.
  switch (typeof obj) {
    case "string":
      obj = obj.trim()
      if (obj.indexOf("\n") !== -1) {
        return "|\n" + indent + obj.split(/\r?\n/).join("\n"+indent)
      } else {
        return JSON.stringify(obj)
      }

    case "number":
      return obj.toString(10)

    case "function":
      return encode(obj.toString(), indent, true)

    case "boolean":
      return obj.toString()

    case "undefined":
      // fallthrough
    case "object":
      // at this point we know it types as an object
      if (!obj) return "~"

      if (obj instanceof Date ||
          Object.prototype.toString.call(obj) === "[object Date]") {
        return JSON.stringify("[Date " + obj.toISOString() + "]")
      }

      if (obj instanceof RegExp ||
          Object.prototype.toString.call(obj) === "[object RegExp]") {
        return JSON.stringify(obj.toString())
      }

      if (obj instanceof Boolean ||
          Object.prototype.toString.call(obj) === "[object Boolean]") {
        return obj.toString()
      }

      if (seen.indexOf(obj) !== -1) {
        return "[Circular]"
      }
      seen.push(obj)

      if (typeof Buffer === "function" &&
          typeof Buffer.isBuffer === "function" &&
          Buffer.isBuffer(obj)) return obj.inspect()

      if (obj instanceof Error) {
        var o = { name: obj.name
                , message: obj.message
                , type: obj.type }

        if (obj.code) o.code = obj.code
        if (obj.errno) o.errno = obj.errno
        if (obj.type) o.type = obj.type
        obj = o
      }

      var out = ""

      if (Array.isArray(obj)) {
        var out = "\n" + indent + "- " +obj.map(function (item) {
          return encode(item, indent + "  ", true)
        }).join("\n"+indent + "- ")
        break
      }

      // an actual object
      var keys = Object.keys(obj)
        , niceKeys = keys.map(function (k) {
            return (k.match(/^[a-zA-Z0-9_]+$/) ? k : JSON.stringify(k)) + ": "
          })
      //console.error(keys, niceKeys, obj)
      var maxLength = Math.max.apply(Math, niceKeys.map(function (k) {
            return k.length
          }).concat(0))
      //console.error(niceKeys, maxLength)

      var spaces = new Array(maxLength + 1).join(" ")

      if (!deep) indent += "  "
      out = "\n" + indent + keys.map(function (k, i) {
        var niceKey = niceKeys[i]
        return niceKey + spaces.substr(niceKey.length)
                       + encode(obj[k], indent + "  ", true)
      }).join("\n" + indent)
      break

    default: return ""
  }
  if (!deep) seen.length = 0
  return out
}

function decode (str) {
  var v = str.trim()
    , d
    , dateRe = /^\[Date ([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}(?::[0-9]{2})?(?:\.[0-9]{3})?(?:[A-Z]+)?)\]$/

  if (v === "~") return null

  try {
    var jp = JSON.parse(str)
  } catch (e) {
    var jp = ""
  }

  if (jp &&
      typeof jp === "string" &&
      (d = jp.match(dateRe)) &&
      (d = Date.parse(d[1]))) {
    return new Date(d)
  }

  if (typeof jp === "boolean") return jp
  if (v && !isNaN(v)) return parseInt(v, 10)

  // something interesting.
  var lines = str.split(/\r?\n/)
  // check if it's some kind of string or something.
  // if the first line is > or | then it's a wrapping indented string.
  // if the first line is blank, and there are many lines,
  // then it's an array or object.
  // otherwise, it's just ""
  var first = lines.shift().trim()
  if (lines.length) lines = undent(lines)
  switch (first) {
    case "|":
      return lines.join("\n")
    case ">":
      return lines.join("\n").split(/\n{2,}/).map(function (l) {
        return l.split(/\n/).join(" ")
      }).join("\n")
    default:
      if (!lines.length) return first
      // array or object.
      // the first line will be either "- value" or "key: value"
      return lines[0].charAt(0) === "-" ? decodeArr(lines) : decodeObj(lines)
  }
}

function decodeArr (lines) {
  var out = []
    , key = 0
    , val = []
  for (var i = 0, l = lines.length; i < l; i ++) {
    // if it starts with a -, then it's a new thing
    var line = lines[i]
    if (line.charAt(0) === "-") {
      if (val.length) {
        out[key ++] = decode(val.join("\n"))
        val.length = 0
      }
      val.push(line.substr(1).trim())
    } else if (line.charAt(0) === " ") {
      val.push(line)
    } else return []
  }
  if (val.length) {
    out[key ++] = decode(val.join("\n"))
  }
  return out
}

function decodeObj (lines) {
  var out = {}
    , val = []
    , key = null

  for (var i = 0, l = lines.length; i < l; i ++) {
    var line = lines[i]
    if (line.charAt(0) === " ") {
      val.push(line)
      continue
    }
    // some key:val
    if (val.length) {
      out[key] = decode(val.join("\n"))
      val.length = 0
    }
    // parse out the quoted key
    var first
    if (line.charAt(0) === "\"") {
      for (var ii = 1, ll = line.length, esc = false; ii < ll; ii ++) {
        var c = line.charAt(ii)
        if (c === "\\") {
          esc = !esc
        } else if (c === "\"" && !esc) {
          break
        }
      }
      key = JSON.parse(line.substr(0, ii + 1))
      line = line.substr(ii + 1)
      first = line.substr(line.indexOf(":") + 1).trim()
    } else {
      var kv = line.split(":")
      key = kv.shift()
      first = kv.join(":").trim()
    }
    // now we've set a key, and "first" has the first line of the value.
    val.push(first.trim())
  }
  if (val.length) out[key] = decode(val.join("\n"))
  return out
}

function undent (lines) {
  var i = lines[0].match(/^\s*/)[0].length
  return lines.map(function (line) {
    return line.substr(i)
  })
}

// XXX Turn this into proper tests.
if (require.main === module) {
var obj = [{"bigstring":new Error().stack}
          ,{ar:[{list:"of"},{some:"objects"}]}
          ,{date:new Date()}
          ,{"super huge string":new Error().stack}
          ]

Date.prototype.toJSON = function (k, val) {
  console.error(k, val, this)
  return this.toISOString() + " (it's a date)"
}

var enc = encode(obj)
  , dec = decode(enc)
  , encDec = encode(dec)

console.error(JSON.stringify({ obj : obj
                             , enc : enc.split(/\n/)
                             , dec : dec }, null, 2), encDec === enc)

var num = 100
  , encNum = encode(num)
  , decEncNum = decode(encNum)
console.error([num, encNum, decEncNum])
}
<|endoftext|>


<commit_before>import JSInterpreter from 'js-interpreter';
import { observer as globalObserver } from 'binary-common-utils/lib/observer';
import { createScope } from './CliTools';
import Interface from './Interface';

const unrecoverableErrors = ['InsufficientBalance', 'CustomLimitsReached'];
const botInitialized = bot => bot && bot.tradeEngine.options;
const botStarted = bot => botInitialized(bot) && bot.tradeEngine.tradeOptions;
const shouldRestartOnError = (bot, errorName = '') =>
    !unrecoverableErrors.includes(errorName) && botInitialized(bot) && bot.tradeEngine.options.shouldRestartOnError;
const timeMachineEnabled = bot => botInitialized(bot) && bot.tradeEngine.options.timeMachineEnabled;

export default class Interpreter {
    constructor() {
        this.init();
    }
    init() {
        this.$scope = createScope();
        this.bot = new Interface(this.$scope);
        this.stopped = false;
        this.$scope.observer.register('REVERT', watchName =>
            this.revert(watchName === 'before' ? this.beforeState : this.duringState)
        );
    }
    run(code) {
        const initFunc = (interpreter, scope) => {
            const BotIf = this.bot.getInterface('Bot');
            const ticksIf = this.bot.getTicksInterface();
            const { alert, prompt, sleep, console: customConsole } = this.bot.getInterface();

            interpreter.setProperty(scope, 'console', interpreter.nativeToPseudo(customConsole));

            interpreter.setProperty(scope, 'alert', interpreter.nativeToPseudo(alert));

            interpreter.setProperty(scope, 'prompt', interpreter.nativeToPseudo(prompt));

            const pseudoBotIf = interpreter.nativeToPseudo(BotIf);

            Object.entries(ticksIf).forEach(([name, f]) =>
                interpreter.setProperty(pseudoBotIf, name, this.createAsync(interpreter, f))
            );

            interpreter.setProperty(
                pseudoBotIf,
                'start',
                interpreter.nativeToPseudo((...args) => {
                    const { start } = BotIf;
                    if (shouldRestartOnError(this.bot)) {
                        this.startState = interpreter.takeStateSnapshot();
                    }
                    start(...args);
                })
            );

            interpreter.setProperty(pseudoBotIf, 'purchase', this.createAsync(interpreter, BotIf.purchase));

            interpreter.setProperty(pseudoBotIf, 'sellAtMarket', this.createAsync(interpreter, BotIf.sellAtMarket));

            interpreter.setProperty(scope, 'Bot', pseudoBotIf);

            interpreter.setProperty(
                scope,
                'watch',
                this.createAsync(interpreter, watchName => {
                    const { watch } = this.bot.getInterface();

                    if (timeMachineEnabled(this.bot)) {
                        const snapshot = this.interpreter.takeStateSnapshot();
                        if (watchName === 'before') {
                            this.beforeState = snapshot;
                        } else {
                            this.duringState = snapshot;
                        }
                    }

                    return watch(watchName);
                })
            );

            interpreter.setProperty(scope, 'sleep', this.createAsync(interpreter, sleep));
        };

        return new Promise((resolve, reject) => {
            const onError = e => {
                if (this.stopped) {
                    return;
                }
                if (!shouldRestartOnError(this.bot, e.name) || !botStarted(this.bot)) {
                    reject(e);
                    return;
                }
                globalObserver.emit('Error', e);
                const { initArgs, tradeOptions } = this.bot.tradeEngine;
                this.stop();
                this.init();
                this.$scope.observer.register('Error', onError);
                this.bot.tradeEngine.init(...initArgs);
                this.bot.tradeEngine.start(tradeOptions);
                this.revert(this.startState);
            };

            this.$scope.observer.register('Error', onError);

            this.interpreter = new JSInterpreter(code, initFunc);

            this.onFinish = resolve;
            this.loop();
        });
    }
    loop() {
        if (this.stopped || !this.interpreter.run()) {
            this.onFinish(this.interpreter.pseudoToNative(this.interpreter.value));
        }
    }
    revert(state) {
        this.interpreter.restoreStateSnapshot(state);
        // eslint-disable-next-line no-underscore-dangle
        this.interpreter.paused_ = false;
        this.loop();
    }
    stop() {
        this.$scope.api.disconnect();
        globalObserver.emit('bot.stop');
        this.stopped = true;
    }
    createAsync(interpreter, func) {
        return interpreter.createAsyncFunction((...args) => {
            const callback = args.pop();

            func(...args.map(arg => interpreter.pseudoToNative(arg)))
                .then(rv => {
                    callback(interpreter.nativeToPseudo(rv));
                    this.loop();
                })
                .catch(e => this.$scope.observer.emit('Error', e));
        });
    }
}
<commit_msg>Update unrecoverable error list (#469)<commit_after>import JSInterpreter from 'js-interpreter';
import { observer as globalObserver } from 'binary-common-utils/lib/observer';
import { createScope } from './CliTools';
import Interface from './Interface';

const unrecoverableErrors = [
    'InsufficientBalance',
    'CustomLimitsReached',
    'OfferingsValidationError',
    'InvalidCurrency',
    'ContractBuyValidationError',
    'NotDefaultCurrency',
];
const botInitialized = bot => bot && bot.tradeEngine.options;
const botStarted = bot => botInitialized(bot) && bot.tradeEngine.tradeOptions;
const shouldRestartOnError = (bot, errorName = '') =>
    !unrecoverableErrors.includes(errorName) && botInitialized(bot) && bot.tradeEngine.options.shouldRestartOnError;
const timeMachineEnabled = bot => botInitialized(bot) && bot.tradeEngine.options.timeMachineEnabled;

export default class Interpreter {
    constructor() {
        this.init();
    }
    init() {
        this.$scope = createScope();
        this.bot = new Interface(this.$scope);
        this.stopped = false;
        this.$scope.observer.register('REVERT', watchName =>
            this.revert(watchName === 'before' ? this.beforeState : this.duringState)
        );
    }
    run(code) {
        const initFunc = (interpreter, scope) => {
            const BotIf = this.bot.getInterface('Bot');
            const ticksIf = this.bot.getTicksInterface();
            const { alert, prompt, sleep, console: customConsole } = this.bot.getInterface();

            interpreter.setProperty(scope, 'console', interpreter.nativeToPseudo(customConsole));

            interpreter.setProperty(scope, 'alert', interpreter.nativeToPseudo(alert));

            interpreter.setProperty(scope, 'prompt', interpreter.nativeToPseudo(prompt));

            const pseudoBotIf = interpreter.nativeToPseudo(BotIf);

            Object.entries(ticksIf).forEach(([name, f]) =>
                interpreter.setProperty(pseudoBotIf, name, this.createAsync(interpreter, f))
            );

            interpreter.setProperty(
                pseudoBotIf,
                'start',
                interpreter.nativeToPseudo((...args) => {
                    const { start } = BotIf;
                    if (shouldRestartOnError(this.bot)) {
                        this.startState = interpreter.takeStateSnapshot();
                    }
                    start(...args);
                })
            );

            interpreter.setProperty(pseudoBotIf, 'purchase', this.createAsync(interpreter, BotIf.purchase));

            interpreter.setProperty(pseudoBotIf, 'sellAtMarket', this.createAsync(interpreter, BotIf.sellAtMarket));

            interpreter.setProperty(scope, 'Bot', pseudoBotIf);

            interpreter.setProperty(
                scope,
                'watch',
                this.createAsync(interpreter, watchName => {
                    const { watch } = this.bot.getInterface();

                    if (timeMachineEnabled(this.bot)) {
                        const snapshot = this.interpreter.takeStateSnapshot();
                        if (watchName === 'before') {
                            this.beforeState = snapshot;
                        } else {
                            this.duringState = snapshot;
                        }
                    }

                    return watch(watchName);
                })
            );

            interpreter.setProperty(scope, 'sleep', this.createAsync(interpreter, sleep));
        };

        return new Promise((resolve, reject) => {
            const onError = e => {
                if (this.stopped) {
                    return;
                }
                if (!shouldRestartOnError(this.bot, e.name) || !botStarted(this.bot)) {
                    reject(e);
                    return;
                }
                globalObserver.emit('Error', e);
                const { initArgs, tradeOptions } = this.bot.tradeEngine;
                this.stop();
                this.init();
                this.$scope.observer.register('Error', onError);
                this.bot.tradeEngine.init(...initArgs);
                this.bot.tradeEngine.start(tradeOptions);
                this.revert(this.startState);
            };

            this.$scope.observer.register('Error', onError);

            this.interpreter = new JSInterpreter(code, initFunc);

            this.onFinish = resolve;
            this.loop();
        });
    }
    loop() {
        if (this.stopped || !this.interpreter.run()) {
            this.onFinish(this.interpreter.pseudoToNative(this.interpreter.value));
        }
    }
    revert(state) {
        this.interpreter.restoreStateSnapshot(state);
        // eslint-disable-next-line no-underscore-dangle
        this.interpreter.paused_ = false;
        this.loop();
    }
    stop() {
        this.$scope.api.disconnect();
        globalObserver.emit('bot.stop');
        this.stopped = true;
    }
    createAsync(interpreter, func) {
        return interpreter.createAsyncFunction((...args) => {
            const callback = args.pop();

            func(...args.map(arg => interpreter.pseudoToNative(arg)))
                .then(rv => {
                    callback(interpreter.nativeToPseudo(rv));
                    this.loop();
                })
                .catch(e => this.$scope.observer.emit('Error', e));
        });
    }
}
<|endoftext|>


<commit_before>/**
 * @fileOverview This file is the core of tQuery library.
*/

/**
 * Create a tQuery element
 *
 * @class root class
 *
 * @param {} object
 * @param {THREE.Object3D} rootnode
 * @returns {tQuery.*} the tQuery object created
*/
var tQuery	= function(object, root)
{
	// support for tQuery(geometry, material)
	if( arguments.length === 2 &&
			(arguments[0] instanceof THREE.Geometry
				|| arguments[0] instanceof THREE.BufferGeometry
				|| arguments[0] instanceof tQuery.Geometry)
			&&
			(arguments[1] instanceof THREE.Material || arguments[1] instanceof tQuery.Material)
			){
		var tGeometry	= arguments[0] instanceof tQuery.Geometry ? arguments[0].get(0) : arguments[0];
		var tMaterial	= arguments[1] instanceof tQuery.Material ? arguments[1].get(0) : arguments[1];
		var tMesh	= new THREE.Mesh(tGeometry, tMaterial);
		return tQuery( tMesh );
	}

// TODO make tthat cleaner
// - there is a list of functions registered by each plugins
//   - handle() object instanceof THREE.Mesh
//   - create() return new tQuery(object)
// - this list is processed in order here

	// if the object is an array, compare only the first element
	// - up to the subconstructor to check if the whole array has proper type
	var instance	= Array.isArray(object) ? object[0] : object;

	if( instance instanceof THREE.Mesh  && tQuery.Mesh){
		return new tQuery.Mesh(object);
	}else if( instance instanceof THREE.DirectionalLight && tQuery.DirectionalLight){
		return new tQuery.DirectionalLight(object);
	}else if( instance instanceof THREE.AmbientLight && tQuery.AmbientLight){
		return new tQuery.AmbientLight(object);
	}else if( instance instanceof THREE.Light && tQuery.Light){
		return new tQuery.Light(object);

	}else if( instance instanceof THREE.Object3D  && tQuery.Object3D){
		return new tQuery.Object3D(object);
	}else if( instance instanceof THREE.Geometry && tQuery.Geometry){
		return new tQuery.Geometry(object);
	}else if( instance instanceof THREE.Material && tQuery.Material){
		return new tQuery.Material(object);
	}else if( typeof instance === "string" && tQuery.Object3D){
		return new tQuery.Object3D(object, root);
	}else{
		console.assert(false, "unsupported type")
	}
	return undefined;
};

/**
 * The version of tQuery
*/
tQuery.VERSION	= "r56.0";

//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

/**
 * generic getter/setter
 *
 * @param {Object} object the object in which store the data
 * @param {String} key the key/name of the data to get/set
 * @param {*} value the value to set (optional)
 * @param {Boolean} mustNotExist if true, ensure that the key doesnt already exist, optional default to false
 *
 * @returns {*} return the value stored in this object for this key
*/
tQuery.data	= function(object, key, value, mustNotExist)
{
	// sanity check
	console.assert( object, 'invalid parameters' );
	console.assert( typeof key === 'string', 'invalid parameters');
	// handle default arguments values
	if( mustNotExist === undefined && value !== undefined )	mustNotExist = true;

	// init _tqData
	object['_tqData']	= object['_tqData']	|| {};
	// honor mustNotExist
	if( mustNotExist ){
		console.assert(object['_tqData'][key] === undefined, "This key already exists "+key);
	}
	// set the value if any
	if( value ){
		object['_tqData'][key]	= value;
	}
	// return the value
	return object['_tqData'][key];
};

/**
 * test if the data exist
 * @param  {Object}  object the object which may or may not contain the data
 * @param  {string}  key    the key of the data
 * @return {Boolean}        true if the data exist, false otherwise
 */
tQuery.hasData	= function(object, key){
	// if there is no data at all, return false
	if( object['_tqData'] === undefined )		return false;
	// if this data doesnt exist, return false
	if( object['_tqData'][key] === undefined )	return false;
	// if all previous test passed, return true
	return true;
}

/**
 * Same as jQuery.removeData()
 *
 * @param {Boolean} mustExist if true, ensure the key does exist, default to false
*/
tQuery.removeData	= function(object, key, mustExist)
{
	// handle the 'key as Array' case
	if( key instanceof Array ){
		key.forEach(function(key){
			tQuery.removeData(object, key);
		})
		return;
	}
	// sanity check
	console.assert( typeof key === "string");
	// honor mustNotExist
	if( mustExist ){
		console.assert(object['_tqData'][key] !== undefined, "This key doesnt already exists "+key);
	}
	// do delete the key
	delete object['_tqData'][key];
	// TOTO remove object[_tqData] if empty now
}

//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

/**
 * loop over a Array.
 *
 * @param {Array} arr the array to traverse.
 * @param {Function} callback the function to notify. function(element){ }.
 * 			loop interrupted if it returns false
 *
 * @returns {Boolean} return true if completed, false if interrupted
*/
tQuery.each	= function(arr, callback){
	for(var i = 0; i < arr.length; i++){
		var keepLooping	= callback(arr[i], i)
		if( keepLooping === false )	return false;
	}
	return true;
};

/**
 * precise version of Date.now() -
 * It provide submillisecond precision based on window.performance.now() when
 * available, fall back on Date.now()
 * see http://updates.html5rocks.com/2012/05/requestAnimationFrame-API-now-with-sub-millisecond-precision
*/
tQuery.now	= (function(){
	var p			= window.performance	|| {};
	if( p.now )		return function(){ return p.timing.navigationStart + p.now();		};
	else if( p.mozNow )	return function(){ return p.timing.navigationStart + p.mozNow();	};
	else if( p.webkitNow )	return function(){ return p.timing.navigationStart + p.webkitNow()	};
	else if( p.mskitNow )	return function(){ return p.timing.navigationStart + p.msNow()		};
	else if( p.okitNow )	return function(){ return p.timing.navigationStart + p.oNow()		};
	else			return function(){ return Date.now;					};
})();

/**
 * Make a child Class inherit from the parent class.
 *
 * @param {Object} childClass the child class which gonna inherit
 * @param {Object} parentClass the class which gonna be inherited
*/
tQuery.inherit	= function(childClass, parentClass){
	// trick to avoid calling parentClass constructor
	var tempFn		= function() {};
	tempFn.prototype	= parentClass.prototype;
	childClass.prototype	= new tempFn();

	childClass.parent	= parentClass.prototype;
	childClass.prototype.constructor= childClass;
};

/**
 * extend function. mainly aimed at handling default values - jme: im not sure at all it is the proper one.
 * http://jsapi.info/_/extend
 * similar to jquery one but much smaller
*/
tQuery.extend = function(obj, base, deep){
	// handle parameter polymorphism
	deep		= deep !== undefined ? deep	: true;
	var extendFn	= deep ? deepExtend : shallowExtend;
	var result	= {};
	base	&& extendFn(result, base);
	obj	&& extendFn(result, obj);
	return result;

	function shallowExtend(dst, src){
		Object.keys(src).forEach(function(key){
			dst[key]	= src[key];
		})
	};
	// from http://andrewdupont.net/2009/08/28/deep-extending-objects-in-javascript/
	function deepExtend(dst, src){
		for (var property in src) {
			if (src[property] && src[property].constructor && src[property].constructor === Object) {
				dst[property] = dst[property] || {};
				arguments.callee(dst[property], src[property]);
			} else {
				dst[property] = src[property];
			}
		}
		return dst;
	};
};

//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

/**
 * Make an object pluginable
 *
 * @param {Object} object the object on which you mixin function
 * @param {Object} dest the object in which to register the plugin
 * @param {string} suffix the suffix to add to the function name
*/
tQuery._pluginsOn	= function(object, dest, fnNameSuffix){
	dest		= dest	|| object.prototype || object;
	fnNameSuffix	= fnNameSuffix || '';
	// sanity check
	console.assert(object['register'+fnNameSuffix] === undefined);
	console.assert(object['unregister'+fnNameSuffix] === undefined);
	console.assert(object['registered'+fnNameSuffix] === undefined);

	object['register'+fnNameSuffix]		= function(name, funct) {
		console.assert(dest[name] === undefined, 'Conflict! Already method called: ' + name);
		dest[name]	= funct;
	};
	object['unregister'+fnNameSuffix]	= function(name){
		if( dest.hasOwnProperty(name) === false ){
			throw new Error('Plugin not found: ' + name);
		}
		delete dest[name];
	};
	object['registered'+fnNameSuffix]	= function(name){
		return dest.hasOwnProperty(name) === true;
	}
};

tQuery.pluginsInstanceOn= function(klass){
	tQuery._pluginsOn(klass, undefined, 'Instance');
};
tQuery.pluginsStaticOn	= function(klass){
	tQuery._pluginsOn(klass, klass, 'Static');
};

// make it pluginable as static
tQuery.pluginsStaticOn(tQuery);

//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

tQuery.mixinAttributes	= function(dstObject, properties){
	// mixin the new property
	// FIXME the inheritance should work now... not sure
	dstObject.prototype._attrProps	= tQuery.extend(dstObject.prototype._attrProps, properties);

	dstObject.prototype.attr	= function(name, args){
		// handle parameters
		if( name instanceof Object && args === undefined ){
			Object.keys(name).forEach(function(key){
				this.attr(key, name[key]);
			}.bind(this));
		}else if( typeof(name) === 'string' ){
			console.assert( Object.keys(this._attrProps).indexOf(name) !== -1, 'invalid property name:'+name);
		}else	console.assert(false, 'invalid parameter');

		// handle setter
		if( args !== undefined ){
			var convertFn	= this._attrProps[name];
			var value	= convertFn.apply(convertFn, args);
			this.each(function(element){
				element[name]	= value;
			})
			return this;
		}
		// handle getter
		if( this.length === 0 )	return undefined
		var element	= this.get(0);
		return element[name];
	};

	// add shortcuts
	Object.keys(properties).forEach(function(name){
		dstObject.prototype[name]	= function(/* arguments */){
			return this.attr(name, arguments);
		};
	}.bind(this));
};

//////////////////////////////////////////////////////////////////////////////////
//		put some helpers						//
//////////////////////////////////////////////////////////////////////////////////

/**
 * Flow control - from https://github.com/jeromeetienne/gowiththeflow.js
*/
tQuery.Flow	= function(){
	var self, stack = [], timerId = setTimeout(function(){ timerId = null; self._next(); }, 0);
	return self = {
		destroy	: function(){ timerId && clearTimeout(timerId);	},
		par	: function(callback, isSeq){
			if(isSeq || !(stack[stack.length-1] instanceof Array)) stack.push([]);
			stack[stack.length-1].push(callback);
			return self;
		},seq	: function(callback){ return self.par(callback, true);	},
		_next	: function(err, result){
			var errors = [], results = [], callbacks = stack.shift() || [], nbReturn = callbacks.length, isSeq = nbReturn == 1;
			callbacks && callbacks.forEach(function(fct, index){
				fct(function(error, result){
					errors[index]	= error;
					results[index]	= result;
					if(--nbReturn == 0)	self._next(isSeq?errors[0]:errors, isSeq?results[0]:results)
				}, err, result)
			})
		}
	}
};

/**
 * microevents.js - https://github.com/jeromeetienne/microevent.js
*/
tQuery.MicroeventMixin	= function(destObj){
	var bind	= function(event, fct){
		if(this._events === undefined) 	this._events	= {};
		this._events[event] = this._events[event]	|| [];
		this._events[event].push(fct);
		return fct;
	};
	var unbind	= function(event, fct){
		if(this._events === undefined) 	this._events	= {};
		if( event in this._events === false  )	return;
		this._events[event].splice(this._events[event].indexOf(fct), 1);
	};
	var trigger	= function(event /* , args... */){
		if(this._events === undefined) 	this._events	= {};
		if( this._events[event] === undefined )	return;
		var tmpArray	= this._events[event].slice();
		for(var i = 0; i < tmpArray.length; i++){
			var result	= tmpArray[i].apply(this, Array.prototype.slice.call(arguments, 1))
			if( result !== undefined )	return result;
		}
		return undefined;
	};

	// backward compatibility
	destObj.bind	= bind;
	destObj.unbind	= unbind;
	destObj.trigger	= trigger;

	destObj.addEventListener	= function(event, fct){
		this.bind(event, fct)
		return this;	// for chained API
	}
	destObj.removeEventListener	= function(event, fct){
		this.unbind(event, fct)
		return this;	// for chained API
	}
	destObj.dispatchEvent		= function(event /* , args... */){
		return this.trigger.apply(this, arguments)
	}
};

/**
 * https://github.com/jeromeetienne/MicroCache.js
*/
tQuery.MicroCache	= function(){
	var _values	= {};
	return {
		get	: function(key){ return _values[key];	},
		contains: function(key){ return key in _values;	},
		remove	: function(key){ delete _values[key];	},
		set	: function(key, value){	_values[key] = value;},
		values	: function(){ return _values;	},
		getSet	: function(key, value){
			if( !this.contains(key) ){
				this.set(key, typeof value == 'function' ? value() : value )
			}
			return this.get(key);
		}
	}
}

<commit_msg>return destObject in microevent. allow chaining<commit_after>/**
 * @fileOverview This file is the core of tQuery library.
*/

/**
 * Create a tQuery element
 *
 * @class root class
 *
 * @param {} object
 * @param {THREE.Object3D} rootnode
 * @returns {tQuery.*} the tQuery object created
*/
var tQuery	= function(object, root)
{
	// support for tQuery(geometry, material)
	if( arguments.length === 2 &&
			(arguments[0] instanceof THREE.Geometry
				|| arguments[0] instanceof THREE.BufferGeometry
				|| arguments[0] instanceof tQuery.Geometry)
			&&
			(arguments[1] instanceof THREE.Material || arguments[1] instanceof tQuery.Material)
			){
		var tGeometry	= arguments[0] instanceof tQuery.Geometry ? arguments[0].get(0) : arguments[0];
		var tMaterial	= arguments[1] instanceof tQuery.Material ? arguments[1].get(0) : arguments[1];
		var tMesh	= new THREE.Mesh(tGeometry, tMaterial);
		return tQuery( tMesh );
	}

// TODO make tthat cleaner
// - there is a list of functions registered by each plugins
//   - handle() object instanceof THREE.Mesh
//   - create() return new tQuery(object)
// - this list is processed in order here

	// if the object is an array, compare only the first element
	// - up to the subconstructor to check if the whole array has proper type
	var instance	= Array.isArray(object) ? object[0] : object;

	if( instance instanceof THREE.Mesh  && tQuery.Mesh){
		return new tQuery.Mesh(object);
	}else if( instance instanceof THREE.DirectionalLight && tQuery.DirectionalLight){
		return new tQuery.DirectionalLight(object);
	}else if( instance instanceof THREE.AmbientLight && tQuery.AmbientLight){
		return new tQuery.AmbientLight(object);
	}else if( instance instanceof THREE.Light && tQuery.Light){
		return new tQuery.Light(object);

	}else if( instance instanceof THREE.Object3D  && tQuery.Object3D){
		return new tQuery.Object3D(object);
	}else if( instance instanceof THREE.Geometry && tQuery.Geometry){
		return new tQuery.Geometry(object);
	}else if( instance instanceof THREE.Material && tQuery.Material){
		return new tQuery.Material(object);
	}else if( typeof instance === "string" && tQuery.Object3D){
		return new tQuery.Object3D(object, root);
	}else{
		console.assert(false, "unsupported type")
	}
	return undefined;
};

/**
 * The version of tQuery
*/
tQuery.VERSION	= "r56.0";

//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

/**
 * generic getter/setter
 *
 * @param {Object} object the object in which store the data
 * @param {String} key the key/name of the data to get/set
 * @param {*} value the value to set (optional)
 * @param {Boolean} mustNotExist if true, ensure that the key doesnt already exist, optional default to false
 *
 * @returns {*} return the value stored in this object for this key
*/
tQuery.data	= function(object, key, value, mustNotExist)
{
	// sanity check
	console.assert( object, 'invalid parameters' );
	console.assert( typeof key === 'string', 'invalid parameters');
	// handle default arguments values
	if( mustNotExist === undefined && value !== undefined )	mustNotExist = true;

	// init _tqData
	object['_tqData']	= object['_tqData']	|| {};
	// honor mustNotExist
	if( mustNotExist ){
		console.assert(object['_tqData'][key] === undefined, "This key already exists "+key);
	}
	// set the value if any
	if( value ){
		object['_tqData'][key]	= value;
	}
	// return the value
	return object['_tqData'][key];
};

/**
 * test if the data exist
 * @param  {Object}  object the object which may or may not contain the data
 * @param  {string}  key    the key of the data
 * @return {Boolean}        true if the data exist, false otherwise
 */
tQuery.hasData	= function(object, key){
	// if there is no data at all, return false
	if( object['_tqData'] === undefined )		return false;
	// if this data doesnt exist, return false
	if( object['_tqData'][key] === undefined )	return false;
	// if all previous test passed, return true
	return true;
}

/**
 * Same as jQuery.removeData()
 *
 * @param {Boolean} mustExist if true, ensure the key does exist, default to false
*/
tQuery.removeData	= function(object, key, mustExist)
{
	// handle the 'key as Array' case
	if( key instanceof Array ){
		key.forEach(function(key){
			tQuery.removeData(object, key);
		})
		return;
	}
	// sanity check
	console.assert( typeof key === "string");
	// honor mustNotExist
	if( mustExist ){
		console.assert(object['_tqData'][key] !== undefined, "This key doesnt already exists "+key);
	}
	// do delete the key
	delete object['_tqData'][key];
	// TOTO remove object[_tqData] if empty now
}

//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

/**
 * loop over a Array.
 *
 * @param {Array} arr the array to traverse.
 * @param {Function} callback the function to notify. function(element){ }.
 * 			loop interrupted if it returns false
 *
 * @returns {Boolean} return true if completed, false if interrupted
*/
tQuery.each	= function(arr, callback){
	for(var i = 0; i < arr.length; i++){
		var keepLooping	= callback(arr[i], i)
		if( keepLooping === false )	return false;
	}
	return true;
};

/**
 * precise version of Date.now() -
 * It provide submillisecond precision based on window.performance.now() when
 * available, fall back on Date.now()
 * see http://updates.html5rocks.com/2012/05/requestAnimationFrame-API-now-with-sub-millisecond-precision
*/
tQuery.now	= (function(){
	var p			= window.performance	|| {};
	if( p.now )		return function(){ return p.timing.navigationStart + p.now();		};
	else if( p.mozNow )	return function(){ return p.timing.navigationStart + p.mozNow();	};
	else if( p.webkitNow )	return function(){ return p.timing.navigationStart + p.webkitNow()	};
	else if( p.mskitNow )	return function(){ return p.timing.navigationStart + p.msNow()		};
	else if( p.okitNow )	return function(){ return p.timing.navigationStart + p.oNow()		};
	else			return function(){ return Date.now;					};
})();

/**
 * Make a child Class inherit from the parent class.
 *
 * @param {Object} childClass the child class which gonna inherit
 * @param {Object} parentClass the class which gonna be inherited
*/
tQuery.inherit	= function(childClass, parentClass){
	// trick to avoid calling parentClass constructor
	var tempFn		= function() {};
	tempFn.prototype	= parentClass.prototype;
	childClass.prototype	= new tempFn();

	childClass.parent	= parentClass.prototype;
	childClass.prototype.constructor= childClass;
};

/**
 * extend function. mainly aimed at handling default values - jme: im not sure at all it is the proper one.
 * http://jsapi.info/_/extend
 * similar to jquery one but much smaller
*/
tQuery.extend = function(obj, base, deep){
	// handle parameter polymorphism
	deep		= deep !== undefined ? deep	: true;
	var extendFn	= deep ? deepExtend : shallowExtend;
	var result	= {};
	base	&& extendFn(result, base);
	obj	&& extendFn(result, obj);
	return result;

	function shallowExtend(dst, src){
		Object.keys(src).forEach(function(key){
			dst[key]	= src[key];
		})
	};
	// from http://andrewdupont.net/2009/08/28/deep-extending-objects-in-javascript/
	function deepExtend(dst, src){
		for (var property in src) {
			if (src[property] && src[property].constructor && src[property].constructor === Object) {
				dst[property] = dst[property] || {};
				arguments.callee(dst[property], src[property]);
			} else {
				dst[property] = src[property];
			}
		}
		return dst;
	};
};

//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

/**
 * Make an object pluginable
 *
 * @param {Object} object the object on which you mixin function
 * @param {Object} dest the object in which to register the plugin
 * @param {string} suffix the suffix to add to the function name
*/
tQuery._pluginsOn	= function(object, dest, fnNameSuffix){
	dest		= dest	|| object.prototype || object;
	fnNameSuffix	= fnNameSuffix || '';
	// sanity check
	console.assert(object['register'+fnNameSuffix] === undefined);
	console.assert(object['unregister'+fnNameSuffix] === undefined);
	console.assert(object['registered'+fnNameSuffix] === undefined);

	object['register'+fnNameSuffix]		= function(name, funct) {
		console.assert(dest[name] === undefined, 'Conflict! Already method called: ' + name);
		dest[name]	= funct;
	};
	object['unregister'+fnNameSuffix]	= function(name){
		if( dest.hasOwnProperty(name) === false ){
			throw new Error('Plugin not found: ' + name);
		}
		delete dest[name];
	};
	object['registered'+fnNameSuffix]	= function(name){
		return dest.hasOwnProperty(name) === true;
	}
};

tQuery.pluginsInstanceOn= function(klass){
	tQuery._pluginsOn(klass, undefined, 'Instance');
};
tQuery.pluginsStaticOn	= function(klass){
	tQuery._pluginsOn(klass, klass, 'Static');
};

// make it pluginable as static
tQuery.pluginsStaticOn(tQuery);

//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

tQuery.mixinAttributes	= function(dstObject, properties){
	// mixin the new property
	// FIXME the inheritance should work now... not sure
	dstObject.prototype._attrProps	= tQuery.extend(dstObject.prototype._attrProps, properties);

	dstObject.prototype.attr	= function(name, args){
		// handle parameters
		if( name instanceof Object && args === undefined ){
			Object.keys(name).forEach(function(key){
				this.attr(key, name[key]);
			}.bind(this));
		}else if( typeof(name) === 'string' ){
			console.assert( Object.keys(this._attrProps).indexOf(name) !== -1, 'invalid property name:'+name);
		}else	console.assert(false, 'invalid parameter');

		// handle setter
		if( args !== undefined ){
			var convertFn	= this._attrProps[name];
			var value	= convertFn.apply(convertFn, args);
			this.each(function(element){
				element[name]	= value;
			})
			return this;
		}
		// handle getter
		if( this.length === 0 )	return undefined
		var element	= this.get(0);
		return element[name];
	};

	// add shortcuts
	Object.keys(properties).forEach(function(name){
		dstObject.prototype[name]	= function(/* arguments */){
			return this.attr(name, arguments);
		};
	}.bind(this));
};

//////////////////////////////////////////////////////////////////////////////////
//		put some helpers						//
//////////////////////////////////////////////////////////////////////////////////

/**
 * Flow control - from https://github.com/jeromeetienne/gowiththeflow.js
*/
tQuery.Flow	= function(){
	var self, stack = [], timerId = setTimeout(function(){ timerId = null; self._next(); }, 0);
	return self = {
		destroy	: function(){ timerId && clearTimeout(timerId);	},
		par	: function(callback, isSeq){
			if(isSeq || !(stack[stack.length-1] instanceof Array)) stack.push([]);
			stack[stack.length-1].push(callback);
			return self;
		},seq	: function(callback){ return self.par(callback, true);	},
		_next	: function(err, result){
			var errors = [], results = [], callbacks = stack.shift() || [], nbReturn = callbacks.length, isSeq = nbReturn == 1;
			callbacks && callbacks.forEach(function(fct, index){
				fct(function(error, result){
					errors[index]	= error;
					results[index]	= result;
					if(--nbReturn == 0)	self._next(isSeq?errors[0]:errors, isSeq?results[0]:results)
				}, err, result)
			})
		}
	}
};

/**
 * microevents.js - https://github.com/jeromeetienne/microevent.js
*/
tQuery.MicroeventMixin	= function(destObj){
	var bind	= function(event, fct){
		if(this._events === undefined) 	this._events	= {};
		this._events[event] = this._events[event]	|| [];
		this._events[event].push(fct);
		return fct;
	};
	var unbind	= function(event, fct){
		if(this._events === undefined) 	this._events	= {};
		if( event in this._events === false  )	return;
		this._events[event].splice(this._events[event].indexOf(fct), 1);
	};
	var trigger	= function(event /* , args... */){
		if(this._events === undefined) 	this._events	= {};
		if( this._events[event] === undefined )	return;
		var tmpArray	= this._events[event].slice();
		for(var i = 0; i < tmpArray.length; i++){
			var result	= tmpArray[i].apply(this, Array.prototype.slice.call(arguments, 1))
			if( result !== undefined )	return result;
		}
		return undefined;
	};

	// backward compatibility
	destObj.bind	= bind;
	destObj.unbind	= unbind;
	destObj.trigger	= trigger;

	destObj.addEventListener	= function(event, fct){
		this.bind(event, fct)
		return this;	// for chained API
	}
	destObj.removeEventListener	= function(event, fct){
		this.unbind(event, fct)
		return this;	// for chained API
	}
	destObj.dispatchEvent		= function(event /* , args... */){
		return this.trigger.apply(this, arguments)
	}
	return destObj;
};

/**
 * https://github.com/jeromeetienne/MicroCache.js
*/
tQuery.MicroCache	= function(){
	var _values	= {};
	return {
		get	: function(key){ return _values[key];	},
		contains: function(key){ return key in _values;	},
		remove	: function(key){ delete _values[key];	},
		set	: function(key, value){	_values[key] = value;},
		values	: function(){ return _values;	},
		getSet	: function(key, value){
			if( !this.contains(key) ){
				this.set(key, typeof value == 'function' ? value() : value )
			}
			return this.get(key);
		}
	}
}

<|endoftext|>


<commit_before>var expect = require('chai').expect;
var path = require('path');

var TMPDIR = require('os').tmpdir();

var ics = require('../index.js');

describe('ics', function() {

  describe('getEvent()', function() {

    it('creates a default event when no options passed', function() {
      var evnt = ics.getEvent({});
      expect(evnt.search(/BEGIN:VCALENDAR\r\n/)).to.equal(0);
      expect(evnt.search(/VERSION:2.0\r\n/)).to.equal(17);
      expect(evnt.search(/BEGIN:VEVENT\r\n/)).to.equal(30);
      expect(evnt.search(/DESCRIPTION/)).to.equal(-1);
      expect(evnt.search(/SUMMARY:New Event\r\n/)).to.equal(120);
      expect(evnt.search(/END:VEVENT\r\n/)).to.equal(139);
      expect(evnt.search(/END:VCALENDAR/)).to.equal(151);
    })
  })

  xdescribe('createEvent()', function() {
    it('create event with every option passed', function() {
      var expected = path.join(TMPDIR, 'calendar-event.ics');

      ics.createEvent({
        eventName: 'Welcome Event to ICS',
        description: 'Meet Down at the index.js',
        fileName: 'example.ics',
        dtstart:'20160126T154700Z',
        dtend:'20160126T164700Z',
        location: 'Fort Worth, Texas',
        organizer: {
            name: 'greenpioneersolutions',
            email: 'info@greenpioneersolutions.com'
        },
        attendees:[{
            name: 'Support greenpioneersolutions',
            email: 'Support@greenpioneersolutions.com',
            rsvp:false

        },{
            name: 'Accounting greenpioneersolutions',
            email: 'Accounting@greenpioneersolutions.com',
            rsvp:true
        },{
            name: 'Sales greenpioneersolutions',
            email: 'Sales@greenpioneersolutions.com',
            rsvp:true
        },{
            name: 'no RSVP default to true',
            email: 'Sales@greenpioneersolutions.com'
        }]
      }, null, function(err, filepath) {
        if (err) throw err;
        expect(filepath).to.equal(expected);
      });
    });
    it('returns a default filepath when no filename or filepath provided', function() {
      var expected = path.join(TMPDIR, 'calendar-event.ics');

      ics.createEvent({}, null, function(err, filepath) {
        if (err) throw err;
        expect(filepath).to.equal(expected);
      });
    });

    it('returns a default filepath and custom filename when filename provided', function() {
      var expected = path.join(TMPDIR, 'custom-name.ics');

      ics.createEvent({filename: 'custom-name'}, null, function(err, filepath) {
        if (err) throw err;
        expect(filepath).to.equal(expected);
      })
    });

    it('returns a custom filepath when one is provided', function() {
      var expected = '/Users/gibber/Desktop/my-file.ics';

      ics.createEvent({}, '/Users/gibber/Desktop/my-file.ics', function(err, filepath) {
        if (err) throw err;
        expect(filepath).to.equal(expected);
      })
    })
  });

});
<commit_msg>fixes tests<commit_after>var expect = require('chai').expect;
var path = require('path');

var TMPDIR = require('os').tmpdir();

var ics = require('../index.js');

describe('ics', function() {

  describe('getEvent()', function() {

    it('creates a default event when no options passed', function() {
      var evnt = ics.getEvent({});
      expect(evnt.search(/BEGIN:VCALENDAR\r\n/)).to.equal(0);
      expect(evnt.search(/VERSION:2.0\r\n/)).to.equal(17);
      expect(evnt.search(/BEGIN:VEVENT\r\n/)).to.equal(30);
      expect(evnt.search(/DESCRIPTION/)).to.equal(-1);
      expect(evnt.search(/SUMMARY:New Event\r\n/)).to.equal(120);
      expect(evnt.search(/END:VEVENT\r\n/)).to.equal(139);
      expect(evnt.search(/END:VCALENDAR/)).to.equal(151);
    })
  })

  describe('createEvent()', function() {
    it('create event with every option passed', function() {
      var expected = path.join(TMPDIR, 'calendar-event.ics');

      ics.createEvent({
        eventName: 'Welcome Event to ICS',
        description: 'Meet Down at the index.js',
        fileName: 'example.ics',
        dtstart:'Sat Nov 02 2014 13:15:00 GMT-0700 (PDT)',
        dtend:'Sat Nov 02 2014 15:20:00 GMT-0700 (PDT)',
        location: 'Fort Worth, Texas',
        organizer: {
            name: 'greenpioneersolutions',
            email: 'info@greenpioneersolutions.com'
        },
        attendees:[
          {
            name: 'Support',
            email: 'Support@greenpioneersolutions.com',
            rsvp: true
          },
          {
            name: 'Accounting greenpioneersolutions',
            email: 'Accounting@greenpioneersolutions.com'
          }
        ]
      }, null, function(err, filepath) {
        if (err) throw err;
        expect(filepath).to.equal(expected);
      });
    });

    it('returns a default filepath when no filename or filepath provided', function() {
      var expected = path.join(TMPDIR, 'calendar-event.ics');

      ics.createEvent({}, null, function(err, filepath) {
        if (err) throw err;
        expect(filepath).to.equal(expected);
      });
    });

    it('returns a default filepath and custom filename when filename provided', function() {
      var expected = path.join(TMPDIR, 'custom-name.ics');

      ics.createEvent({filename: 'custom-name'}, null, function(err, filepath) {
        if (err) throw err;
        expect(filepath).to.equal(expected);
      })
    });

    it('returns a custom filepath when one is provided', function() {
      var expected = '/Users/gibber/Desktop/my-file.ics';

      ics.createEvent({}, '/Users/gibber/Desktop/my-file.ics', function(err, filepath) {
        if (err) throw err;
        expect(filepath).to.equal(expected);
      })
    })
  });

});
<|endoftext|>


<commit_before>// @flow

import { userRelationshipStatus } from '../types/relationship-types';
import {
  type ThreadInfo,
  type ThreadType,
  threadTypes,
} from '../types/thread-types';
import type { AccountUserInfo, UserListItem } from '../types/user-types';
import SearchIndex from './search-index';
import { userIsMember } from './thread-utils';

function getPotentialMemberItems(
  text: string,
  userInfos: { [id: string]: AccountUserInfo },
  searchIndex: SearchIndex,
  excludeUserIDs: $ReadOnlyArray<string>,
  parentThreadInfo: ?ThreadInfo,
  threadType: ?ThreadType,
): UserListItem[] {
  let results = [];
  const appendUserInfo = (userInfo: AccountUserInfo) => {
    if (!excludeUserIDs.includes(userInfo.id)) {
      results.push({
        ...userInfo,
        isMemberOfParentThread: userIsMember(parentThreadInfo, userInfo.id),
      });
    }
  };
  if (text === '') {
    for (const id in userInfos) {
      appendUserInfo(userInfos[id]);
    }
  } else {
    const ids = searchIndex.getSearchResults(text);
    for (const id of ids) {
      appendUserInfo(userInfos[id]);
    }
  }

  if (text === '') {
    results = results.filter((userInfo) =>
      parentThreadInfo
        ? userInfo.isMemberOfParentThread &&
          userInfo.relationshipStatus !==
            userRelationshipStatus.BLOCKED_BY_VIEWER
        : userInfo.relationshipStatus === userRelationshipStatus.FRIEND,
    );
  }

  const nonFriends = [];
  const blockedUsers = [];
  const friendsAndParentMembers = [];

  for (const userResult of results) {
    const relationshipStatus = userResult.relationshipStatus;
    if (
      userResult.isMemberOfParentThread &&
      relationshipStatus !== userRelationshipStatus.BLOCKED_BY_VIEWER
    ) {
      friendsAndParentMembers.unshift(userResult);
    } else if (relationshipStatus === userRelationshipStatus.FRIEND) {
      friendsAndParentMembers.push(userResult);
    } else if (
      relationshipStatus === userRelationshipStatus.BLOCKED_BY_VIEWER
    ) {
      blockedUsers.push(userResult);
    } else {
      nonFriends.push(userResult);
    }
  }

  const sortedResults = friendsAndParentMembers
    .concat(nonFriends)
    .concat(blockedUsers);

  return sortedResults.map(
    ({ isMemberOfParentThread, relationshipStatus, ...result }) => {
      if (
        isMemberOfParentThread &&
        relationshipStatus !== userRelationshipStatus.BLOCKED_BY_VIEWER
      ) {
        return { ...result };
      }
      let notice, alertText, alertTitle;
      const userText = result.username;
      if (!isMemberOfParentThread && threadType === threadTypes.SIDEBAR) {
        notice = 'not in parent thread';
        alertTitle = 'Not in parent thread';
        alertText =
          'You can only add members of the parent thread to a sidebar';
      } else if (
        relationshipStatus === userRelationshipStatus.BLOCKED_BY_VIEWER
      ) {
        notice = "you've blocked this user";
        alertTitle = 'Not a friend';
        alertText =
          `Before you add ${userText} to this thread, ` +
          "you'll need to unblock them and send a friend request. " +
          'You can do this from the Block List and Friend List in the More tab.';
      } else if (relationshipStatus !== userRelationshipStatus.FRIEND) {
        notice = 'not friend';
        alertTitle = 'Not a friend';
        alertText =
          `Before you add ${userText} to this thread, ` +
          "you'll need to send them a friend request. " +
          'You can do this from the Friend List in the More tab.';
      } else if (parentThreadInfo) {
        notice = 'not in parent thread';
      }
      return { ...result, notice, alertText, alertTitle };
    },
  );
}

export { getPotentialMemberItems };
<commit_msg>[lib] Update comments to reference profile tab instead of more<commit_after>// @flow

import { userRelationshipStatus } from '../types/relationship-types';
import {
  type ThreadInfo,
  type ThreadType,
  threadTypes,
} from '../types/thread-types';
import type { AccountUserInfo, UserListItem } from '../types/user-types';
import SearchIndex from './search-index';
import { userIsMember } from './thread-utils';

function getPotentialMemberItems(
  text: string,
  userInfos: { [id: string]: AccountUserInfo },
  searchIndex: SearchIndex,
  excludeUserIDs: $ReadOnlyArray<string>,
  parentThreadInfo: ?ThreadInfo,
  threadType: ?ThreadType,
): UserListItem[] {
  let results = [];
  const appendUserInfo = (userInfo: AccountUserInfo) => {
    if (!excludeUserIDs.includes(userInfo.id)) {
      results.push({
        ...userInfo,
        isMemberOfParentThread: userIsMember(parentThreadInfo, userInfo.id),
      });
    }
  };
  if (text === '') {
    for (const id in userInfos) {
      appendUserInfo(userInfos[id]);
    }
  } else {
    const ids = searchIndex.getSearchResults(text);
    for (const id of ids) {
      appendUserInfo(userInfos[id]);
    }
  }

  if (text === '') {
    results = results.filter((userInfo) =>
      parentThreadInfo
        ? userInfo.isMemberOfParentThread &&
          userInfo.relationshipStatus !==
            userRelationshipStatus.BLOCKED_BY_VIEWER
        : userInfo.relationshipStatus === userRelationshipStatus.FRIEND,
    );
  }

  const nonFriends = [];
  const blockedUsers = [];
  const friendsAndParentMembers = [];

  for (const userResult of results) {
    const relationshipStatus = userResult.relationshipStatus;
    if (
      userResult.isMemberOfParentThread &&
      relationshipStatus !== userRelationshipStatus.BLOCKED_BY_VIEWER
    ) {
      friendsAndParentMembers.unshift(userResult);
    } else if (relationshipStatus === userRelationshipStatus.FRIEND) {
      friendsAndParentMembers.push(userResult);
    } else if (
      relationshipStatus === userRelationshipStatus.BLOCKED_BY_VIEWER
    ) {
      blockedUsers.push(userResult);
    } else {
      nonFriends.push(userResult);
    }
  }

  const sortedResults = friendsAndParentMembers
    .concat(nonFriends)
    .concat(blockedUsers);

  return sortedResults.map(
    ({ isMemberOfParentThread, relationshipStatus, ...result }) => {
      if (
        isMemberOfParentThread &&
        relationshipStatus !== userRelationshipStatus.BLOCKED_BY_VIEWER
      ) {
        return { ...result };
      }
      let notice, alertText, alertTitle;
      const userText = result.username;
      if (!isMemberOfParentThread && threadType === threadTypes.SIDEBAR) {
        notice = 'not in parent thread';
        alertTitle = 'Not in parent thread';
        alertText =
          'You can only add members of the parent thread to a sidebar';
      } else if (
        relationshipStatus === userRelationshipStatus.BLOCKED_BY_VIEWER
      ) {
        notice = "you've blocked this user";
        alertTitle = 'Not a friend';
        alertText =
          `Before you add ${userText} to this thread, ` +
          "you'll need to unblock them and send a friend request. " +
          'You can do this from the Block List and Friend List ' +
          'in the Profile tab.';
      } else if (relationshipStatus !== userRelationshipStatus.FRIEND) {
        notice = 'not friend';
        alertTitle = 'Not a friend';
        alertText =
          `Before you add ${userText} to this thread, ` +
          "you'll need to send them a friend request. " +
          'You can do this from the Friend List in the Profile tab.';
      } else if (parentThreadInfo) {
        notice = 'not in parent thread';
      }
      return { ...result, notice, alertText, alertTitle };
    },
  );
}

export { getPotentialMemberItems };
<|endoftext|>


<commit_before>/** Lines **/
Flotr.addType('lines', {
  options: {
    show: false,           // => setting to true will show lines, false will hide
    lineWidth: 2,          // => line width in pixels
    fill: false,           // => true to fill the area from the line to the x axis, false for (transparent) no fill
    fillColor: null,       // => fill color
    fillOpacity: 0.4,      // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
    stacked: false         // => setting to true will show stacked lines, false will show normal lines
  },
  /**
   * Draws lines series in the canvas element.
   * @param {Object} series - Series with options.lines.show = true.
   */
  draw: function(series){

    var ctx = this.ctx,
      lineWidth = series.lines.lineWidth,
      shadowSize = series.shadowSize,
      offset;

    series = series || this.series;

    ctx.save();
    ctx.translate(this.plotOffset.left, this.plotOffset.top);
    ctx.lineJoin = 'round';
    this.lines.clip();

    if(shadowSize){

      ctx.lineWidth = shadowSize / 2;
      offset = lineWidth/2 + ctx.lineWidth/2;

      ctx.strokeStyle = "rgba(0,0,0,0.1)";
      this.lines.plot(series, offset + shadowSize/2, false);

      ctx.strokeStyle = "rgba(0,0,0,0.2)";
      this.lines.plot(series, offset, false);

      if(series.lines.fill) {
        ctx.fillStyle = "rgba(0,0,0,0.05)";
        this.lines.plotArea(series, offset + shadowSize/2, false);
      }
    }

    ctx.lineWidth = lineWidth;
    ctx.strokeStyle = series.color;
    if(series.lines.fill){
      ctx.fillStyle = this.processColor(series.lines.fillColor || series.color, {opacity: series.lines.fillOpacity});
      this.lines.plotArea(series, 0, true);
    }

    this.lines.plot(series, 0, true);
    ctx.restore();
  },

  plot: function(series, offset, incStack){

    var ctx = this.ctx,
      xa = series.xaxis,
      ya = series.yaxis,
      data = series.data,
      length = data.length - 1,
      width = this.plotWidth,
      height = this.plotHeight,
      prevx = null,
      prevy = null,
      x1, x2, y1, y2, stack1, stack2, i;

    if(length < 2) return;

    ctx.beginPath();

    for(i = 0; i < length; ++i){

      // To allow empty values
      if (data[i][1] === null || data[i+1][1] === null) continue;

      // Zero is infinity for log scales
      if (xa.options.scaling === 'logarithmic' && (data[i][0] <= 0 || data[i+1][0] <= 0)) continue;
      if (ya.options.scaling === 'logarithmic' && (data[i][1] <= 0 || data[i+1][1] <= 0)) continue;

      x1 = xa.d2p(data[i][0]);
      x2 = xa.d2p(data[i+1][0]);

      if (series.lines.stacked) {

        stack1 = xa.values[data[i][0]].stack || 0;
        stack2 = xa.values[data[i+1][0]].stack || xa.values[data[i][0]].stack || 0;

        y1 = ya.d2p(data[i][1] + stack1);
        y2 = ya.d2p(data[i+1][1] + stack2);

        if(incStack){
          xa.values[data[i][0]].stack = data[i][1]+stack1;

          if(i == length-1)
            xa.values[data[i+1][0]].stack = data[i+1][1]+stack2;
        }
      }
      else{
        y1 = ya.d2p(data[i][1]);
        y2 = ya.d2p(data[i+1][1]);
      }

      if ((y1 >= height && y2 >= width) ||
        (y1 <= 0 && y2 <= 0) ||
        (x1 <= 0 && x2 <= 0) ||
        (x1 >= width && x2 >= width)) continue;

      if((prevx != x1) || (prevy != y1 + offset))
        ctx.moveTo(x1, y1 + offset);

      prevx = x2;
      prevy = y2 + offset;
      ctx.lineTo(prevx, prevy);
    }

    ctx.stroke();
    ctx.closePath();
  },

  clip : function () {
    var ctx = this.ctx;
    ctx.beginPath();
    ctx.rect(0, 0, this.plotWidth, this.plotHeight);
    ctx.clip();
  },

  /**
   * Function used to fill
   * @param {Object} series - The series to draw
   * @param {Object} offset
   */
  plotArea: function(series, offset, saveStrokePath){

    var ctx = this.ctx,
      xa = series.xaxis,
      ya = series.yaxis,
      data = series.data,
      length = data.length - 1,
      bottom = Math.min(Math.max(0, ya.min), ya.max),
      lastX = 0,
      first = true,
      strokePath = [],
      pathIdx = 0,
      stack1 = 0,
      stack2 = 0,
      top, x1, x2, y1, y2, i,
      x1old, x2old,
      x1PointValue,
      x2PointValue,
      yaMaxPointValue,
      yaMinPointValue,
      path;

    function addStrokePath(xVal, yVal) {
      if (saveStrokePath) {
        strokePath[pathIdx] = [];
        strokePath[pathIdx][0] = xVal;
        strokePath[pathIdx][1] = yVal;
        pathIdx++;
      }
    }

    if(data.length < 2) return;

    ctx.beginPath();

    for(i = 0; i < length; ++i){
      x1 = data[i][0];
      x2 = data[i+1][0];

      if (series.lines.stacked) {

        stack1 = xa.values[data[i][0]].stack || 0;
        stack2 = xa.values[data[i+1][0]].stack || xa.values[data[i][0]].stack || 0;

        y1 = data[i][1] + stack1;
        y2 = data[i+1][1] + stack2;
      }
      else{
        y1 = data[i][1];
        y2 = data[i+1][1];
      }

      if(x1 <= x2 && x1 < xa.min){
        if(x2 < xa.min) continue;
        y1 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;
        x1 = xa.min;
      }
      else if(x2 <= x1 && x2 < xa.min){
        if(x1 < xa.min) continue;
        y2 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;
        x2 = xa.min;
      }

      if(x1 >= x2 && x1 > xa.max){
        if(x2 > xa.max) continue;
        y1 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;
        x1 = xa.max;
      }
      else if(x2 >= x1 && x2 > xa.max){
        if (x1 > xa.max) continue;
        y2 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;
        x2 = xa.max;
      }

      if(first){
        ctx.moveTo(x1PointValue, ya.d2p(bottom + stack1) + offset);
        addStrokePath(x1PointValue, ya.d2p(bottom + stack1) + offset);
        first = false;
      }
      lastX = Math.max(x2, lastX);

      // Now check the case where both is outside.
      if(y1 >= ya.max && y2 >= ya.max){
        ctx.lineTo(x1PointValue, yaMaxPointValue + offset);
        ctx.lineTo(x2PointValue, yaMaxPointValue + offset);
        addStrokePath(x1PointValue, yaMaxPointValue + offset);
        addStrokePath(x2PointValue, yaMaxPointValue + offset);
        continue;
      }
      else if(y1 <= ya.min && y2 <= ya.min){
        ctx.lineTo(x1PointValue, yaMinPointValue + offset);
        ctx.lineTo(x2PointValue, yaMinPointValue + offset);
        addStrokePath(x1PointValue, yaMinPointValue + offset);
        addStrokePath(x2PointValue, yaMinPointValue + offset);
        continue;
      }

      /**
       * Else it's a bit more complicated, there might
       * be two rectangles and two triangles we need to fill
       * in; to find these keep track of the current x values.
       */
      x1old = x1;
      x2old = x2;

      x1NewPointValue = xa.d2p(x1); // Cache d2p values
      x2NewPointValue = xa.d2p(x2);
      y1PointValue = ya.d2p(y1);
      y2PointValue = ya.d2p(y2);

      // If the x value was changed we got a rectangle to fill.
      if(x1 != x1old){
        top = (y1 <= ya.min) ? yaMinPointValue : yaMaxPointValue;
        ctx.lineTo(x1PointValue, top + offset);
        ctx.lineTo(x1NewPointValue, top + offset);
        addStrokePath(x1PointValue, top + offset);
        addStrokePath(x1NewPointValue, top + offset);
      }

      // Fill the triangles.
      ctx.lineTo(x1NewPointValue, y1PointValue + offset);
      ctx.lineTo(x2NewPointValue, y2PointValue + offset);
      addStrokePath(x1NewPointValue, y1PointValue + offset);
      addStrokePath(x2NewPointValue, y2PointValue + offset);

      // Fill the other rectangle if it's there.
      if(x2 != x2old){
        top = (y2 <= ya.min) ? yaMinPointValue : yaMaxPointValue;
        ctx.lineTo(x2PointValue, top + offset);
        addStrokePath(x2PointValue, top + offset);
      }

      lastX = Math.max(x2, x2old, lastX);
    }

    ctx.lineTo(xa.d2p(lastX), ya.d2p(bottom) + offset);
    addStrokePath(xa.d2p(lastX), ya.d2p(bottom) + offset);

    // go back along previous stroke path
    path = xa.lastStrokePath;

    if (series.lines.stacked) {
      if (path) {
        for(i = path.length-1; i >= 0; --i){
          ctx.lineTo(path[i][0], path[i][1] - offset/2);
        }
      }
      // add stroke path to series data
      if (saveStrokePath) {
        xa.lastStrokePath = strokePath;
      }
    }

    ctx.closePath();
    ctx.fill();
  },

  extendYRange: function(axis){
    var o = axis.options;
    if((!o.max && o.max !== 0) || (!o.min && o.min !== 0)){
      var newmax = axis.max,
          newmin = axis.min,
          x, i, j, s, l,
          stackedSumsPos = {},
          stackedSumsNeg = {},
          lastSerie = null;

      for(i = 0; i < this.series.length; ++i){
        s = this.series[i];
        l = s.lines;
        if (l.show && !s.hide && s.yaxis == axis) {
          // For stacked lines
          if(l.stacked){
            for (j = 0; j < s.data.length; j++) {
              x = s.data[j][0]+'';
              if(s.data[j][1]>0)
                stackedSumsPos[x] = (stackedSumsPos[x] || 0) + s.data[j][1];
              else
                stackedSumsNeg[x] = (stackedSumsNeg[x] || 0) + s.data[j][1];
              lastSerie = s;
            }

            for (j in stackedSumsPos) {
              newmax = Math.max(stackedSumsPos[j], newmax);
            }
            for (j in stackedSumsNeg) {
              newmin = Math.min(stackedSumsNeg[j], newmin);
            }
          }
        }
      }
      axis.lastSerie = lastSerie;
      axis.max = newmax;
      axis.min = newmin;
    }
  }
});
<commit_msg>Refactored the area plotting.<commit_after>/** Lines **/
Flotr.addType('lines', {
  options: {
    show: false,           // => setting to true will show lines, false will hide
    lineWidth: 2,          // => line width in pixels
    fill: false,           // => true to fill the area from the line to the x axis, false for (transparent) no fill
    fillColor: null,       // => fill color
    fillOpacity: 0.4,      // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
    stacked: false         // => setting to true will show stacked lines, false will show normal lines
  },
  /**
   * Draws lines series in the canvas element.
   * @param {Object} series - Series with options.lines.show = true.
   */
  draw: function(series){

    var ctx = this.ctx,
      lineWidth = series.lines.lineWidth,
      shadowSize = series.shadowSize,
      offset;

    series = series || this.series;

    ctx.save();
    ctx.translate(this.plotOffset.left, this.plotOffset.top);
    ctx.lineJoin = 'round';
    this.lines.clip();

    if(shadowSize){

      ctx.lineWidth = shadowSize / 2;
      offset = lineWidth/2 + ctx.lineWidth/2;

      ctx.strokeStyle = "rgba(0,0,0,0.1)";
      this.lines.plot(series, offset + shadowSize/2, false);

      ctx.strokeStyle = "rgba(0,0,0,0.2)";
      this.lines.plot(series, offset, false);
    }

    ctx.lineWidth = lineWidth;
    ctx.strokeStyle = series.color;

    this.lines.plot(series, 0, true);

    ctx.restore();
  },

  plot: function(series, offset, incStack){

    var ctx = this.ctx,
      xa = series.xaxis,
      ya = series.yaxis,
      data = series.data,
      length = data.length - 1,
      width = this.plotWidth,
      height = this.plotHeight,
      prevx = null,
      prevy = null,
      x1, x2, y1, y2, stack1, stack2, i;

    if(length < 2) return;

    ctx.beginPath();

    for(i = 0; i < length; ++i){

      // To allow empty values
      if (data[i][1] === null || data[i+1][1] === null) continue;

      // Zero is infinity for log scales
      if (xa.options.scaling === 'logarithmic' && (data[i][0] <= 0 || data[i+1][0] <= 0)) continue;
      if (ya.options.scaling === 'logarithmic' && (data[i][1] <= 0 || data[i+1][1] <= 0)) continue;

      x1 = xa.d2p(data[i][0]);
      x2 = xa.d2p(data[i+1][0]);

      if (series.lines.stacked) {

        stack1 = xa.values[data[i][0]].stack || 0;
        stack2 = xa.values[data[i+1][0]].stack || xa.values[data[i][0]].stack || 0;

        y1 = ya.d2p(data[i][1] + stack1);
        y2 = ya.d2p(data[i+1][1] + stack2);

        if(incStack){
          xa.values[data[i][0]].stack = data[i][1]+stack1;

          if(i == length-1)
            xa.values[data[i+1][0]].stack = data[i+1][1]+stack2;
        }
      }
      else{
        y1 = ya.d2p(data[i][1]);
        y2 = ya.d2p(data[i+1][1]);
      }

      if ((y1 >= height && y2 >= width) ||
        (y1 <= 0 && y2 <= 0) ||
        (x1 <= 0 && x2 <= 0) ||
        (x1 >= width && x2 >= width)) continue;

      if((prevx != x1) || (prevy != y1 + offset))
        ctx.moveTo(x1, y1 + offset);

      prevx = x2;
      prevy = y2 + offset;
      ctx.lineTo(prevx, prevy);
    }

    ctx.stroke();

    // TODO stacked lines and shadow area
    if(series.lines.fill){
      ctx.fillStyle = this.processColor(series.lines.fillColor || series.color, {opacity: series.lines.fillOpacity});
      ctx.lineTo(this.plotWidth, ya.d2p(0));
      ctx.lineTo(0, ya.d2p(0));
      ctx.fill();
    }

    ctx.closePath();
  },

  clip : function () {
    var ctx = this.ctx;
    ctx.beginPath();
    ctx.rect(0, 0, this.plotWidth, this.plotHeight);
    ctx.clip();
  },

  extendYRange: function(axis){
    var o = axis.options;
    if((!o.max && o.max !== 0) || (!o.min && o.min !== 0)){
      var newmax = axis.max,
          newmin = axis.min,
          x, i, j, s, l,
          stackedSumsPos = {},
          stackedSumsNeg = {},
          lastSerie = null;

      for(i = 0; i < this.series.length; ++i){
        s = this.series[i];
        l = s.lines;
        if (l.show && !s.hide && s.yaxis == axis) {
          // For stacked lines
          if(l.stacked){
            for (j = 0; j < s.data.length; j++) {
              x = s.data[j][0]+'';
              if(s.data[j][1]>0)
                stackedSumsPos[x] = (stackedSumsPos[x] || 0) + s.data[j][1];
              else
                stackedSumsNeg[x] = (stackedSumsNeg[x] || 0) + s.data[j][1];
              lastSerie = s;
            }

            for (j in stackedSumsPos) {
              newmax = Math.max(stackedSumsPos[j], newmax);
            }
            for (j in stackedSumsNeg) {
              newmin = Math.min(stackedSumsNeg[j], newmin);
            }
          }
        }
      }
      axis.lastSerie = lastSerie;
      axis.max = newmax;
      axis.min = newmin;
    }
  }
});
<|endoftext|>


<commit_before>var buster = require("buster-node");
var assert = buster.assert;
var refute = buster.refute;

var when = require("when");
var th = require("./test-helper.js");

buster.testCase("Capturing", {
    setUp: function () {
        return th.setUpHelpers(this, [th.ph, th.rs]);
    },

    tearDown: function () {
        return th.tearDownHelpers(this);
    },

    "one browser": function (done) {
        var self = this;

        this.ph.createPage(function (page) {
            page.open(self.rs.captureUrl, function (status) {
                th.httpGet(self.rs.serverUrl + "/slaves", done(function (res, body) {
                    assert.equals(res.statusCode, 200);
                    var body = JSON.parse(body);
                    assert.equals(body.length, 1)
                    assert(body[0].id);
                    assert(body[0].userAgent);
                    assert.match(body[0].userAgent, /phantomjs/i);
                }));
            });
        });
    },

    "two browsers": function (done) {
        var self = this;

        var slaveADeferred = when.defer();
        this.ph.createPage(function (page) {
            page.open(self.rs.captureUrl, function (status) {
                slaveADeferred.resolve();
            });
        });

        var slaveBDeferred = when.defer();
        this.ph.createPage(function (page) {
            page.open(self.rs.captureUrl, function (status) {
                slaveBDeferred.resolve();
            });
        });

        when.all([slaveADeferred.promise, slaveBDeferred.promise]).then(function () {
            th.httpGet(self.rs.serverUrl + "/slaves", done(function (res, body) {
                assert.equals(res.statusCode, 200);
                var body = JSON.parse(body);
                assert.equals(body.length, 2)
            }))
        });
    }
});
<commit_msg>Updating capturing test to account for readyness.<commit_after>var buster = require("buster-node");
var assert = buster.assert;
var refute = buster.refute;

var when = require("when");
var th = require("./test-helper.js");

buster.testCase("Capturing", {
    setUp: function () {
        return th.setUpHelpers(this, [th.ph, th.rs]);
    },

    tearDown: function () {
        return th.tearDownHelpers(this);
    },

    "one browser": function (done) {
        var self = this;

        th.capture(this, function () {
            th.httpGet(self.rs.serverUrl + "/slaves", done(function (res, body) {
                assert.equals(res.statusCode, 200);
                var body = JSON.parse(body);
                assert.equals(body.length, 1)
                assert(body[0].id);
                assert(body[0].userAgent);
                assert.match(body[0].userAgent, /phantomjs/i);
            }));
        });
    },

    "two browsers": function (done) {
        var self = this;

        var slaveADeferred = when.defer();
        th.capture(this, slaveADeferred.resolve);

        var slaveBDeferred = when.defer();
        th.capture(this, slaveBDeferred.resolve);

        when.all([slaveADeferred.promise, slaveBDeferred.promise]).then(function () {
            th.httpGet(self.rs.serverUrl + "/slaves", done(function (res, body) {
                assert.equals(res.statusCode, 200);
                var body = JSON.parse(body);
                assert.equals(body.length, 2)
            }))
        });
    }
});
<|endoftext|>


<commit_before>// Copyright 2018, University of Colorado Boulder

/*
 * IMPORTANT: This file was auto-generated by "grunt generate-config". Please do not modify this directly. Instead
 * please modify vibe/package.json to control dependencies.
 *
 * RequireJS configuration file for the vibe sim.
 * Paths are relative to the location of this file.
 */

require.config( {

  deps: [ 'vibe-main' ],

  paths: {

    // Third-party libs
    text: '../../sherpa/lib/text-2.0.12',

    // PhET plugins
    audio: '../../chipper/js/requirejs-plugins/audio',
    image: '../../chipper/js/requirejs-plugins/image',
    mipmap: '../../chipper/js/requirejs-plugins/mipmap',
    string: '../../chipper/js/requirejs-plugins/string',
    ifphetio: '../../chipper/js/requirejs-plugins/ifphetio',

    // PhET libs, uppercase names to identify them in require.js imports.
    // IMPORTANT: DO NOT modify. This file is auto-generated. See documentation at the top.
    AXON: '../../axon/js',
    BRAND: '../../brand/' + phet.chipper.brand + '/js',
    DOT: '../../dot/js',
    JOIST: '../../joist/js',
    KITE: '../../kite/js',
    PHETCOMMON: '../../phetcommon/js',
    PHET_CORE: '../../phet-core/js',
    PHET_IO: '../../phet-io/js',
    REPOSITORY: '..',
    SCENERY: '../../scenery/js',
    SCENERY_PHET: '../../scenery-phet/js',
    SUN: '../../sun/js',
    TANDEM: '../../tandem/js',
    VIBE: '.'
  },

  // optional cache buster to make browser refresh load all included scripts, can be disabled with ?cacheBuster=false
  urlArgs: phet.chipper.getCacheBusterArgs()
} );
<commit_msg>added the tambo sound library as a dependency for all active runnables, see https://github.com/phetsims/joist/issues/497<commit_after>// Copyright 2018, University of Colorado Boulder

/*
 * IMPORTANT: This file was auto-generated by "grunt generate-config". Please do not modify this directly. Instead
 * please modify vibe/package.json to control dependencies.
 *
 * RequireJS configuration file for the vibe sim.
 * Paths are relative to the location of this file.
 */

require.config( {

  deps: [ 'vibe-main' ],

  paths: {

    // Third-party libs
    text: '../../sherpa/lib/text-2.0.12',

    // PhET plugins
    audio: '../../chipper/js/requirejs-plugins/audio',
    image: '../../chipper/js/requirejs-plugins/image',
    mipmap: '../../chipper/js/requirejs-plugins/mipmap',
    string: '../../chipper/js/requirejs-plugins/string',
    ifphetio: '../../chipper/js/requirejs-plugins/ifphetio',

    // PhET libs, uppercase names to identify them in require.js imports.
    // IMPORTANT: DO NOT modify. This file is auto-generated. See documentation at the top.
    AXON: '../../axon/js',
    BRAND: '../../brand/' + phet.chipper.brand + '/js',
    DOT: '../../dot/js',
    JOIST: '../../joist/js',
    KITE: '../../kite/js',
    PHETCOMMON: '../../phetcommon/js',
    PHET_CORE: '../../phet-core/js',
    PHET_IO: '../../phet-io/js',
    REPOSITORY: '..',
    SCENERY: '../../scenery/js',
    SCENERY_PHET: '../../scenery-phet/js',
    SUN: '../../sun/js',
    TAMBO: '../../tambo/js',
    TANDEM: '../../tandem/js',
    VIBE: '.'
  },

  // optional cache buster to make browser refresh load all included scripts, can be disabled with ?cacheBuster=false
  urlArgs: phet.chipper.getCacheBusterArgs()
} );
<|endoftext|>


<commit_before>var devices = require('./devices')
describe('devices', function () {
  it('samsung smart-tv', function () {
    check({
      list: devices.samsungSmartTv,
      platform: 'samsung',
      device: 'tv'
    })
  })

  it('lg smart-tv', function () {
    check({
      list: devices.lgSmartTv,
      platform: 'lg',
      device: 'tv'
    })
  })

  it('chromeCast', function () {
    check({
      list: devices.chromeCast,
      platform: 'chromecast',
      device: 'chromecast'
    })
  })
})

function check (params) {
  var result
  for (var i in params.list) {
    result = ua.parse(params.list[i])
    result.device.should.msg('device is incorrect\n\n'+params.list[i]+'\n\n').equal(params.device)
    result.platform.should.msg('platform is incorrect\n\n'+params.list[i]+'\n\n').equal(params.platform)
  }
}
<commit_msg>cleanup tests<commit_after>describe('devices', function () {
  var ua = require('../../')
  var useragents = require('./useragents')
  it('samsung smart-tv', function () {
    check({
      list: useragents.samsungSmartTv,
      platform: 'samsung',
      device: 'tv'
    })
  })

  it('lg smart-tv', function () {
    check({
      list: useragents.lgSmartTv,
      platform: 'lg',
      device: 'tv'
    })
  })

  it('chromeCast', function () {
    check({
      list: useragents.chromeCast,
      platform: 'chromecast',
      device: 'chromecast'
    })
  })

  function check (params) {
    var result
    for (var i in params.list) {
      result = ua.parse(params.list[i])
      result.device.should.msg('device is incorrect\n\n' + params.list[i] + '\n\n').equal(params.device)
      result.platform.should.msg('platform is incorrect\n\n' + params.list[i] + '\n\n').equal(params.platform)
    }
  }
})
<|endoftext|>


<commit_before>import Log from '../plugins/log'
import PlayerError from '../components/error'

const ErrorMixin = {
  /**
   * creates an error.
   * @method createError
   * @param {Object} error should be an object with code, description, level and raw error.
   * @return {Object} Object with formatted error data including origin and scope
   */
  createError(error) {
    const scope = this.constructor && this.constructor.type || ''
    const origin = this.name || scope
    const i18n = this.i18n || this.core && this.core.i18n || this.container && this.container.i18n

    const defaultError = {
      description: '',
      level: PlayerError.Levels.FATAL,
      origin,
      scope,
      raw: {},
    }

    const errorData = Object.assign({}, defaultError, error, {
      code: `${origin}:${error && error.code || 'unknown'}`
    })

    if (i18n && errorData.level == PlayerError.Levels.FATAL && !errorData.UI) {
      const defaultUI = {
        title: i18n.t('default_error_title'),
        message: i18n.t('default_error_message')
      }
      errorData.UI = defaultUI
    }

    if (this.playerError)
      this.playerError.error(errorData)
    else
      Log.warn(origin, 'PlayerError is not defined. Error: ', errorData)

    return errorData
  }
}

export default ErrorMixin
<commit_msg>feat(error_mixin): add useCodePrefix option<commit_after>import Log from '../plugins/log'
import PlayerError from '../components/error'

const ErrorMixin = {
  /**
   * creates an error.
   * @method createError
   * @param {Object} error should be an object with code, description, level and raw error.
   * @return {Object} Object with formatted error data including origin and scope
   */
  createError(error, options = { useCodePrefix: true }) {
    const scope = this.constructor && this.constructor.type || ''
    const origin = this.name || scope
    const i18n = this.i18n || this.core && this.core.i18n || this.container && this.container.i18n

    const prefixedCode = `${origin}:${error && error.code || 'unknown'}`
    const defaultError = {
      description: '',
      level: PlayerError.Levels.FATAL,
      origin,
      scope,
      raw: {},
    }

    const errorData = Object.assign({}, defaultError, error, {
      code: options.useCodePrefix ? prefixedCode : error.code
    })

    if (i18n && errorData.level == PlayerError.Levels.FATAL && !errorData.UI) {
      const defaultUI = {
        title: i18n.t('default_error_title'),
        message: i18n.t('default_error_message')
      }
      errorData.UI = defaultUI
    }

    if (this.playerError)
      this.playerError.error(errorData)
    else
      Log.warn(origin, 'PlayerError is not defined. Error: ', errorData)

    return errorData
  }
}

export default ErrorMixin
<|endoftext|>