<commit_before>"use strict";

let errors = require('../errors.js');
let Expression = require('./expression.js');
let Types = require('../types/types.js');
let NumberType = require('../types/number.js').Type;
let RangeType = require('../types/range.js').Type;
let makeExpression = require('./factory.js');
let makeType = require('../types/factory.js');
let _ = require('lodash');

class BaseFunction {
  constructor(name, numargs, numgargs) {
    this.name = name;
    this.numargs = numargs;
    if (numgargs === undefined) {
      this.numgargs = 0;
    } else {
      this.numgargs = numgargs;
    }
    this.pure = true;
  }
  typecheck(params, env, gargs) {
    if (gargs.length != this.numgargs) {
      throw new errors.Type(`${this.name} takes exactly ${this.numgargs} generic arguments`);
    }
    if (params.length != this.numargs) {
      throw new errors.Type(`${this.name} takes exactly ${this.numargs} arguments`);
    }
    params.forEach((param) => param.typecheck());

    if (typeof this.typecheckSub !== 'function') {
      throw new errors.Unimplemented(`The function ${this.name} ` +
        `has not implemented typecheckSub()`);
    }
    let type = this.typecheckSub(params, env, gargs);
    if (type === undefined) {
      throw new errors.Internal(`The function ${this.name} ` +
        `returned nothing in typecheckSub()`);
    }
    return type;
  }
  evaluate(args, env, gargs) {
    if (typeof this.evaluateSub !== 'function') {
      throw new errors.Unimplemented(`The function ${this.name} ` +
        `has not implemented evaluateSub()`);
    }
    let value = this.evaluateSub(args, env, gargs);
    if (value === undefined) {
      throw new errors.Internal(`The function ${this.name} ` +
        `returned nothing in evaluateSub()`);
    }
    return value;
  }
}

class NegateFunction extends BaseFunction {
  constructor() {
    super('!', 1);
  }
  typecheckSub(params, env) {
    let boolType = env.getType('Boolean');
    if (!Types.subtypeOf(params[0].type, boolType)) {
      throw new errors.Type(`Cannot negate ${params[0].type}`);
    }
    return boolType;
  }
  evaluateSub(args, env) {
    let isFalse = (args[0].equals(env.getVar('False')));
    return env.getVar(isFalse ? 'True' : 'False');
  }
}

class EqualityFunction extends BaseFunction {
  typecheckSub(params, env) {
    if (!Types.haveEquality(params[0].type, params[1].type)) {
      throw new errors.Type(`Cannot compare (${this.name}) ` +
        `${params[0].type} to ${params[1].type}`);
    }
    return env.getType('Boolean');
  }
}

class EqualsFunction extends EqualityFunction {
  constructor() {
    super('==', 2);
  }
  evaluateSub(args, env) {
    let eq = args[0].equals(args[1]);
    return env.getVar(eq ? 'True' : 'False');
  }
}

class NotEqualsFunction extends EqualityFunction {
  constructor() {
    super('!=', 2);
  }
  evaluateSub(args, env) {
    let eq = args[0].equals(args[1]);
    return env.getVar(eq ? 'False' : 'True');
  }
}

class BinaryBooleanFunction extends BaseFunction {
  constructor(name) {
    super(name, 2);
    this.shortCircuit = true;
  }
  typecheckSub(params, env) {
    let type = env.getType('Boolean');
    if (!Types.subtypeOf(params[0].type, type)) {
      throw new errors.Type(`${this.name} only works on Boolean ` +
        `but given ${params[0].type}`);
    }
    if (!Types.subtypeOf(params[0].type, type)) {
      throw new errors.Type(`${this.name} only works on Boolean ` +
        `but given ${params[1].type}`);
    }
    return type;
  }
}

class AndFunction extends BinaryBooleanFunction {
  constructor() {
    super('&&');
  }
  evaluateSub(args, env) {
    if (args[0].evaluate().equals(env.getVar('True'))) {
      return args[1].evaluate();
    } else {
      return env.getVar('False');
    }
  }
}

class OrFunction extends BinaryBooleanFunction {
  constructor() {
    super('||');
  }
  evaluateSub(args, env) {
    let True = env.getVar('True');
    if (args[0].evaluate().equals(True)) {
      return True;
    } else {
      return args[1].evaluate();
    }
  }
}

class OrderingFunction extends BaseFunction {
  constructor(name, nativeFn) {
    super(name, 2);
    this.nativeFn = nativeFn;
  }
  typecheckSub(params, env) {
    if (!Types.haveOrdering(params[0].type, params[1].type)) {
      throw new errors.Type(`Cannot compare (${this.name}) ` +
        `${params[0].type} to ${params[1].type}`);
    }
    return env.getType('Boolean');
  }
  evaluateSub(args, env) {
    let result = this.nativeFn(args[0].value, args[1].value);
    return env.getVar(result ? 'True' : 'False');
  }
}

let toNumber = v => {
  let n = NumberType.singleton.makeDefaultValue();
  n.assign(v);
  return n;
};

class ArithmeticFunction extends BaseFunction {
  constructor(name, nativeFn) {
    super(name, 2);
    this.nativeFn = nativeFn;
  }
  typecheckSub(params, env) {
    if (!Types.isNumeric(params[0].type) ||
      !Types.isNumeric(params[1].type)) {
      throw new errors.Type(`Cannot do arithmetic (${this.name}) on ` +
        `${params[0].type} and ${params[1].type}`);
    }
    return NumberType.singleton;
  }
  evaluateSub(args, env) {
    return toNumber(this.nativeFn(args[0].value, args[1].value));
  }
}

class PushFunction extends BaseFunction {
  constructor() {
    super('push', 2);
    this.pure = false;
  }
  typecheckSub(params, env) {
    if (!Types.implementsSet(params[0].type)) {
      throw new errors.Type(`Cannot call push() on ${params[0].type}`);
    }
    if (!Types.subtypeOf(params[1].type, params[0].type.valuetype)) {
      throw new errors.Type(`Cannot call push() on ${params[0].type} ` +
        `with ${params[1].type}`);
    }
    return env.getType('Boolean'); // TODO: unit
  }
  evaluateSub(args, env) {
    args[0].push(args[1]);
    return env.getVar('True'); // TODO: unit
  }
}

class PopFunction extends BaseFunction {
  constructor() {
    super('pop', 1);
    this.pure = false;
  }
  typecheckSub(params, env) {
    if (!Types.implementsSet(params[0].type)) {
      throw new errors.Type(`Cannot call pop() on ${params[0].type}`);
    }
    return params[0].type.valuetype;
  }
  evaluateSub(args, env) {
    return args[0].pop();
  }
}

class RemoveFunction extends BaseFunction {
  constructor() {
    super('remove', 2);
    this.pure = false;
  }
  typecheckSub(params, env) {
    if (!Types.implementsSet(params[0].type)) {
      throw new errors.Type(`Cannot call remove() on ${params[0].type}`);
    }
    if (!Types.subtypeOf(params[1].type, params[0].type.valuetype)) {
      throw new errors.Type(`Cannot call remove() on ${params[0].type} ` +
        `with ${params[1].type}`);
    }
    return env.getType('Boolean');
  }
  evaluateSub(args, env) {
    return env.getVar(args[0].remove(args[1]) ? 'True' : 'False');
  }
}

class ContainsFunction extends BaseFunction {
  constructor() {
    super('contains', 2);
  }
  typecheckSub(params, env) {
    if (!Types.implementsSet(params[0].type)) {
      throw new errors.Type(`Cannot call contains() on ${params[0].type}`);
    }
    if (!Types.subtypeOf(params[1].type, params[0].type.valuetype)) {
      throw new errors.Type(`Cannot call contains() on ${params[0].type} ` +
        `with ${params[1].type}`);
    }
    return env.getType('Boolean');
  }
  evaluateSub(args, env) {
    return env.getVar(args[0].contains(args[1]) ? 'True' : 'False');
  }
}

class EmptyFunction extends BaseFunction {
  constructor() {
    super('empty', 1);
  }
  typecheckSub(params, env) {
    if (!Types.implementsSet(params[0].type)) {
      throw new errors.Type(`Cannot call empty() on ${params[0].type}`);
    }
    return env.getType('Boolean');
  }
  evaluateSub(args, env) {
    return env.getVar(args[0].empty() ? 'True' : 'False');
  }
}

class FullFunction extends BaseFunction {
  constructor() {
    super('full', 1);
  }
  typecheckSub(params, env) {
    if (!Types.implementsSet(params[0].type)) {
      throw new errors.Type(`Cannot call empty() on ${params[0].type}`);
    }
    return env.getType('Boolean');
  }
  evaluateSub(args, env) {
    return env.getVar(args[0].full() ? 'True' : 'False');
  }
}

class SizeFunction extends BaseFunction {
  constructor() {
    super('size', 1);
  }
  typecheckSub(params, env) {
    if (!Types.implementsIterable(params[0].type)) {
      throw new errors.Type(`Cannot call size() on ${params[0].type}`);
    }
    return NumberType.singleton;
  }
  evaluateSub(args, env) {
    return toNumber(args[0].size());
  }
}

class CapacityFunction extends BaseFunction {
  constructor() {
    super('capacity', 1);
  }
  typecheckSub(params, env) {
    if (!Types.implementsIterable(params[0].type)) {
      throw new errors.Type(`Cannot call capacity() on ${params[0].type}`);
    }
    return NumberType.singleton;
  }
  evaluateSub(args, env) {
    return toNumber(args[0].capacity());
  }
}

class URandomFunction extends BaseFunction {
  constructor() {
    super('urandom', 0, 1);
  }
  typecheckSub(params, env, gargs) {
    if (!(gargs[0] instanceof RangeType)) {
      throw new errors.type(`Need RangeType as generic argument to urandom`);
    }
    return gargs[0];
  }
  evaluateSub(args, env, gargs) {
    let range = gargs[0];
    let number = _.random(range.low, range.high + 1);
    let value = gargs[0].makeDefaultValue();
    value.assign(number);
    return value;
  }
}

let functions = [
  new NegateFunction(),
  new EqualsFunction(),
  new NotEqualsFunction(),
  new OrderingFunction('<', (x, y) => (x < y)),
  new OrderingFunction('<=', (x, y) => (x <= y)),
  new OrderingFunction('>=', (x, y) => (x >= y)),
  new OrderingFunction('>', (x, y) => (x > y)),
  new ArithmeticFunction('+', (x, y) => (x + y)),
  new ArithmeticFunction('-', (x, y) => (x - y)),
  new ArithmeticFunction('*', (x, y) => (x * y)),
  new ArithmeticFunction('/', (x, y) => Math.floor(x / y)),
  new ArithmeticFunction('%', (x, y) => (x % y)),
  new ArithmeticFunction('pow', (x, y) => Math.pow(x, y)),
  new ArithmeticFunction('urandomRange', (x, y) => _.random(x, y + 1)),
  new PushFunction(),
  new PopFunction(),
  new RemoveFunction(),
  new ContainsFunction(),
  new EmptyFunction(),
  new FullFunction(),
  new SizeFunction(),
  new CapacityFunction(),
  new AndFunction(),
  new OrFunction(),
  new URandomFunction(),
];

class Apply extends Expression {
  constructor(parsed, env) {
    super(parsed, env);
    if (this.parsed.genericargs === undefined) {
      this.gargs = [];
    } else {
      this.gargs = this.parsed.genericargs.map((a) => makeType.make(a, this.env));
    }
    this.args = this.parsed.args.map((a) => makeExpression.make(a, this.env));
    this.fn = undefined;
  }

  typecheck() {
    functions.forEach((fn) => {
      if (fn.name == this.parsed.func.value) {
        this.fn = fn;
      }
    });
    if (this.fn === undefined) {
      this.fn = this.env.functions.get(this.parsed.func.value);
      if (this.fn !== undefined) {
        this.type = this.fn.returntype;
        this.fn.typecheckApply(this.args);
        return; // don't type-check the declaration again
      }
    }
    if (this.fn === undefined) {
      throw new errors.Unimplemented(`The function ` +
        `${this.parsed.func.value} is not implemented. ` +
        `Called at ${this.parsed.source}`);
    }
    this.type = this.fn.typecheck(this.args, this.env, this.gargs);
  }

  evaluate() {
    let args = this.args;
    if (this.fn.shortCircuit !== true) {
      args = this.args.map((arg) => arg.evaluate());
    }
    return this.fn.evaluate(args, this.env, this.gargs);
  }

  toString(indent) {
    let inner = this.args.map((arg) => arg.toString()).join(', ');
    return `${this.parsed.func.value}(${inner})`
  }
}

module.exports = Apply;
<commit_msg>Fix random off-by-one<commit_after>"use strict";

let errors = require('../errors.js');
let Expression = require('./expression.js');
let Types = require('../types/types.js');
let NumberType = require('../types/number.js').Type;
let RangeType = require('../types/range.js').Type;
let makeExpression = require('./factory.js');
let makeType = require('../types/factory.js');
let _ = require('lodash');

class BaseFunction {
  constructor(name, numargs, numgargs) {
    this.name = name;
    this.numargs = numargs;
    if (numgargs === undefined) {
      this.numgargs = 0;
    } else {
      this.numgargs = numgargs;
    }
    this.pure = true;
  }
  typecheck(params, env, gargs) {
    if (gargs.length != this.numgargs) {
      throw new errors.Type(`${this.name} takes exactly ${this.numgargs} generic arguments`);
    }
    if (params.length != this.numargs) {
      throw new errors.Type(`${this.name} takes exactly ${this.numargs} arguments`);
    }
    params.forEach((param) => param.typecheck());

    if (typeof this.typecheckSub !== 'function') {
      throw new errors.Unimplemented(`The function ${this.name} ` +
        `has not implemented typecheckSub()`);
    }
    let type = this.typecheckSub(params, env, gargs);
    if (type === undefined) {
      throw new errors.Internal(`The function ${this.name} ` +
        `returned nothing in typecheckSub()`);
    }
    return type;
  }
  evaluate(args, env, gargs) {
    if (typeof this.evaluateSub !== 'function') {
      throw new errors.Unimplemented(`The function ${this.name} ` +
        `has not implemented evaluateSub()`);
    }
    let value = this.evaluateSub(args, env, gargs);
    if (value === undefined) {
      throw new errors.Internal(`The function ${this.name} ` +
        `returned nothing in evaluateSub()`);
    }
    return value;
  }
}

class NegateFunction extends BaseFunction {
  constructor() {
    super('!', 1);
  }
  typecheckSub(params, env) {
    let boolType = env.getType('Boolean');
    if (!Types.subtypeOf(params[0].type, boolType)) {
      throw new errors.Type(`Cannot negate ${params[0].type}`);
    }
    return boolType;
  }
  evaluateSub(args, env) {
    let isFalse = (args[0].equals(env.getVar('False')));
    return env.getVar(isFalse ? 'True' : 'False');
  }
}

class EqualityFunction extends BaseFunction {
  typecheckSub(params, env) {
    if (!Types.haveEquality(params[0].type, params[1].type)) {
      throw new errors.Type(`Cannot compare (${this.name}) ` +
        `${params[0].type} to ${params[1].type}`);
    }
    return env.getType('Boolean');
  }
}

class EqualsFunction extends EqualityFunction {
  constructor() {
    super('==', 2);
  }
  evaluateSub(args, env) {
    let eq = args[0].equals(args[1]);
    return env.getVar(eq ? 'True' : 'False');
  }
}

class NotEqualsFunction extends EqualityFunction {
  constructor() {
    super('!=', 2);
  }
  evaluateSub(args, env) {
    let eq = args[0].equals(args[1]);
    return env.getVar(eq ? 'False' : 'True');
  }
}

class BinaryBooleanFunction extends BaseFunction {
  constructor(name) {
    super(name, 2);
    this.shortCircuit = true;
  }
  typecheckSub(params, env) {
    let type = env.getType('Boolean');
    if (!Types.subtypeOf(params[0].type, type)) {
      throw new errors.Type(`${this.name} only works on Boolean ` +
        `but given ${params[0].type}`);
    }
    if (!Types.subtypeOf(params[0].type, type)) {
      throw new errors.Type(`${this.name} only works on Boolean ` +
        `but given ${params[1].type}`);
    }
    return type;
  }
}

class AndFunction extends BinaryBooleanFunction {
  constructor() {
    super('&&');
  }
  evaluateSub(args, env) {
    if (args[0].evaluate().equals(env.getVar('True'))) {
      return args[1].evaluate();
    } else {
      return env.getVar('False');
    }
  }
}

class OrFunction extends BinaryBooleanFunction {
  constructor() {
    super('||');
  }
  evaluateSub(args, env) {
    let True = env.getVar('True');
    if (args[0].evaluate().equals(True)) {
      return True;
    } else {
      return args[1].evaluate();
    }
  }
}

class OrderingFunction extends BaseFunction {
  constructor(name, nativeFn) {
    super(name, 2);
    this.nativeFn = nativeFn;
  }
  typecheckSub(params, env) {
    if (!Types.haveOrdering(params[0].type, params[1].type)) {
      throw new errors.Type(`Cannot compare (${this.name}) ` +
        `${params[0].type} to ${params[1].type}`);
    }
    return env.getType('Boolean');
  }
  evaluateSub(args, env) {
    let result = this.nativeFn(args[0].value, args[1].value);
    return env.getVar(result ? 'True' : 'False');
  }
}

let toNumber = v => {
  let n = NumberType.singleton.makeDefaultValue();
  n.assign(v);
  return n;
};

class ArithmeticFunction extends BaseFunction {
  constructor(name, nativeFn) {
    super(name, 2);
    this.nativeFn = nativeFn;
  }
  typecheckSub(params, env) {
    if (!Types.isNumeric(params[0].type) ||
      !Types.isNumeric(params[1].type)) {
      throw new errors.Type(`Cannot do arithmetic (${this.name}) on ` +
        `${params[0].type} and ${params[1].type}`);
    }
    return NumberType.singleton;
  }
  evaluateSub(args, env) {
    return toNumber(this.nativeFn(args[0].value, args[1].value));
  }
}

class PushFunction extends BaseFunction {
  constructor() {
    super('push', 2);
    this.pure = false;
  }
  typecheckSub(params, env) {
    if (!Types.implementsSet(params[0].type)) {
      throw new errors.Type(`Cannot call push() on ${params[0].type}`);
    }
    if (!Types.subtypeOf(params[1].type, params[0].type.valuetype)) {
      throw new errors.Type(`Cannot call push() on ${params[0].type} ` +
        `with ${params[1].type}`);
    }
    return env.getType('Boolean'); // TODO: unit
  }
  evaluateSub(args, env) {
    args[0].push(args[1]);
    return env.getVar('True'); // TODO: unit
  }
}

class PopFunction extends BaseFunction {
  constructor() {
    super('pop', 1);
    this.pure = false;
  }
  typecheckSub(params, env) {
    if (!Types.implementsSet(params[0].type)) {
      throw new errors.Type(`Cannot call pop() on ${params[0].type}`);
    }
    return params[0].type.valuetype;
  }
  evaluateSub(args, env) {
    return args[0].pop();
  }
}

class RemoveFunction extends BaseFunction {
  constructor() {
    super('remove', 2);
    this.pure = false;
  }
  typecheckSub(params, env) {
    if (!Types.implementsSet(params[0].type)) {
      throw new errors.Type(`Cannot call remove() on ${params[0].type}`);
    }
    if (!Types.subtypeOf(params[1].type, params[0].type.valuetype)) {
      throw new errors.Type(`Cannot call remove() on ${params[0].type} ` +
        `with ${params[1].type}`);
    }
    return env.getType('Boolean');
  }
  evaluateSub(args, env) {
    return env.getVar(args[0].remove(args[1]) ? 'True' : 'False');
  }
}

class ContainsFunction extends BaseFunction {
  constructor() {
    super('contains', 2);
  }
  typecheckSub(params, env) {
    if (!Types.implementsSet(params[0].type)) {
      throw new errors.Type(`Cannot call contains() on ${params[0].type}`);
    }
    if (!Types.subtypeOf(params[1].type, params[0].type.valuetype)) {
      throw new errors.Type(`Cannot call contains() on ${params[0].type} ` +
        `with ${params[1].type}`);
    }
    return env.getType('Boolean');
  }
  evaluateSub(args, env) {
    return env.getVar(args[0].contains(args[1]) ? 'True' : 'False');
  }
}

class EmptyFunction extends BaseFunction {
  constructor() {
    super('empty', 1);
  }
  typecheckSub(params, env) {
    if (!Types.implementsSet(params[0].type)) {
      throw new errors.Type(`Cannot call empty() on ${params[0].type}`);
    }
    return env.getType('Boolean');
  }
  evaluateSub(args, env) {
    return env.getVar(args[0].empty() ? 'True' : 'False');
  }
}

class FullFunction extends BaseFunction {
  constructor() {
    super('full', 1);
  }
  typecheckSub(params, env) {
    if (!Types.implementsSet(params[0].type)) {
      throw new errors.Type(`Cannot call empty() on ${params[0].type}`);
    }
    return env.getType('Boolean');
  }
  evaluateSub(args, env) {
    return env.getVar(args[0].full() ? 'True' : 'False');
  }
}

class SizeFunction extends BaseFunction {
  constructor() {
    super('size', 1);
  }
  typecheckSub(params, env) {
    if (!Types.implementsIterable(params[0].type)) {
      throw new errors.Type(`Cannot call size() on ${params[0].type}`);
    }
    return NumberType.singleton;
  }
  evaluateSub(args, env) {
    return toNumber(args[0].size());
  }
}

class CapacityFunction extends BaseFunction {
  constructor() {
    super('capacity', 1);
  }
  typecheckSub(params, env) {
    if (!Types.implementsIterable(params[0].type)) {
      throw new errors.Type(`Cannot call capacity() on ${params[0].type}`);
    }
    return NumberType.singleton;
  }
  evaluateSub(args, env) {
    return toNumber(args[0].capacity());
  }
}

class URandomFunction extends BaseFunction {
  constructor() {
    super('urandom', 0, 1);
  }
  typecheckSub(params, env, gargs) {
    if (!(gargs[0] instanceof RangeType)) {
      throw new errors.type(`Need RangeType as generic argument to urandom`);
    }
    return gargs[0];
  }
  evaluateSub(args, env, gargs) {
    let range = gargs[0];
    let number = _.random(range.low, range.high);
    let value = gargs[0].makeDefaultValue();
    value.assign(number);
    return value;
  }
}

let functions = [
  new NegateFunction(),
  new EqualsFunction(),
  new NotEqualsFunction(),
  new OrderingFunction('<', (x, y) => (x < y)),
  new OrderingFunction('<=', (x, y) => (x <= y)),
  new OrderingFunction('>=', (x, y) => (x >= y)),
  new OrderingFunction('>', (x, y) => (x > y)),
  new ArithmeticFunction('+', (x, y) => (x + y)),
  new ArithmeticFunction('-', (x, y) => (x - y)),
  new ArithmeticFunction('*', (x, y) => (x * y)),
  new ArithmeticFunction('/', (x, y) => Math.floor(x / y)),
  new ArithmeticFunction('%', (x, y) => (x % y)),
  new ArithmeticFunction('pow', (x, y) => Math.pow(x, y)),
  new ArithmeticFunction('urandomRange', (x, y) => _.random(x, y)),
  new PushFunction(),
  new PopFunction(),
  new RemoveFunction(),
  new ContainsFunction(),
  new EmptyFunction(),
  new FullFunction(),
  new SizeFunction(),
  new CapacityFunction(),
  new AndFunction(),
  new OrFunction(),
  new URandomFunction(),
];

class Apply extends Expression {
  constructor(parsed, env) {
    super(parsed, env);
    if (this.parsed.genericargs === undefined) {
      this.gargs = [];
    } else {
      this.gargs = this.parsed.genericargs.map((a) => makeType.make(a, this.env));
    }
    this.args = this.parsed.args.map((a) => makeExpression.make(a, this.env));
    this.fn = undefined;
  }

  typecheck() {
    functions.forEach((fn) => {
      if (fn.name == this.parsed.func.value) {
        this.fn = fn;
      }
    });
    if (this.fn === undefined) {
      this.fn = this.env.functions.get(this.parsed.func.value);
      if (this.fn !== undefined) {
        this.type = this.fn.returntype;
        this.fn.typecheckApply(this.args);
        return; // don't type-check the declaration again
      }
    }
    if (this.fn === undefined) {
      throw new errors.Unimplemented(`The function ` +
        `${this.parsed.func.value} is not implemented. ` +
        `Called at ${this.parsed.source}`);
    }
    this.type = this.fn.typecheck(this.args, this.env, this.gargs);
  }

  evaluate() {
    let args = this.args;
    if (this.fn.shortCircuit !== true) {
      args = this.args.map((arg) => arg.evaluate());
    }
    return this.fn.evaluate(args, this.env, this.gargs);
  }

  toString(indent) {
    let inner = this.args.map((arg) => arg.toString()).join(', ');
    return `${this.parsed.func.value}(${inner})`
  }
}

module.exports = Apply;
<|endoftext|>


<commit_before>import './polyfills';
import renderToString from '.';
import { indent, encodeEntities, assign } from './util';
import prettyFormat from 'pretty-format';

// we have to patch in Array support, Possible issue in npm.im/pretty-format
let preactPlugin = {
	test(object) {
		return object && typeof object==='object' && 'nodeName' in object && 'attributes' in object && 'children' in object && !('nodeType' in object);
	},
	print(val, print, indent) {
		return renderToString(val, preactPlugin.context, preactPlugin.opts, true);
	}
};

let prettyFormatOpts = {
	plugins: [preactPlugin]
};

function attributeHook(name, value, context, opts) {
	if (value==null) return '';

	let indentChar = typeof opts.pretty==='string' ? opts.pretty : '\t';
	if (typeof value!=='string') {
		preactPlugin.context = context;
		preactPlugin.opts = opts;
		value = prettyFormat(value, prettyFormatOpts);
		if (~value.indexOf('\n')) {
			value = `${indent('\n'+value, indentChar)}\n`;
		}
		return indent(`\n${name}={${value}}`, indentChar);
	}
	return `\n${indentChar}${name}="${encodeEntities(value)}"`;
}

let defaultOpts = {
	attributeHook,
	jsx: true,
	xml: true,
	pretty: '  '
};

export default function renderToJsxString(vnode, context, opts, inner) {
	opts = assign(assign({}, defaultOpts), opts || {});
	return renderToString(vnode, context, opts, inner);
}
<commit_msg>Dont use self-closing tags in JSX mode<commit_after>import './polyfills';
import renderToString from '.';
import { indent, encodeEntities, assign } from './util';
import prettyFormat from 'pretty-format';

// we have to patch in Array support, Possible issue in npm.im/pretty-format
let preactPlugin = {
	test(object) {
		return object && typeof object==='object' && 'nodeName' in object && 'attributes' in object && 'children' in object && !('nodeType' in object);
	},
	print(val, print, indent) {
		return renderToString(val, preactPlugin.context, preactPlugin.opts, true);
	}
};

let prettyFormatOpts = {
	plugins: [preactPlugin]
};

function attributeHook(name, value, context, opts) {
	if (value==null) return '';

	let indentChar = typeof opts.pretty==='string' ? opts.pretty : '\t';
	if (typeof value!=='string') {
		preactPlugin.context = context;
		preactPlugin.opts = opts;
		value = prettyFormat(value, prettyFormatOpts);
		if (~value.indexOf('\n')) {
			value = `${indent('\n'+value, indentChar)}\n`;
		}
		return indent(`\n${name}={${value}}`, indentChar);
	}
	return `\n${indentChar}${name}="${encodeEntities(value)}"`;
}

let defaultOpts = {
	attributeHook,
	jsx: true,
	xml: false,
	pretty: '  '
};

export default function renderToJsxString(vnode, context, opts, inner) {
	opts = assign(assign({}, defaultOpts), opts || {});
	return renderToString(vnode, context, opts, inner);
}
<|endoftext|>


<commit_before>var agePerCentury = {};

ancestry.forEach(function(person) {
    var century = Math.ceil(person.died / 100);
    if (!(century in agePerCentury))
        agePerCentury[century] = [];

    agePerCentury[century].push(person.died - person.born);
});

for (var century in agePerCentury)
    console.log(century + ": " + average(agePerCentury[century]));

// Or, alternatively, for bonus points

function groupBy(array, groupFunc) {
    var mapping = {};
    array.forEach(function(element) {
        var mapped = groupFunc(element);
        if (!(mapped in mapping))
            mapping[mapped] = [];

        mapping[mapped].push(element);
    });
    return mapping;
}

var byCentury = groupBy(ancestry, function(person) {
    return Math.ceil(person.died / 100);
});

for (var century in byCentury) {
    var ages = byCentury[century].map(function(person) {
        return person.died - person.born;
    });
    console.log(century + ": " + average(ages));
}
<commit_msg>Add Chapter 05, exercise 3<commit_after>function every1(array, test) {
    for (let elem of array) {
        if (!test(elem)) return false;
    }
    return true;
}

function every2(array, test) {
    const revTest = elem => !test(elem);
    return !array.some(revTest);
}

console.log(every1([1, 3, 5], n => n < 10));
// → true
console.log(every1([2, 4, 16], n => n < 10));
// → false
console.log(every1([], n => n < 10));
// → true

console.log(every2([1, 3, 5], n => n < 10));
// → true
console.log(every2([2, 4, 16], n => n < 10));
// → false
console.log(every2([], n => n < 10));
// → true
<|endoftext|>


<commit_before>'use strict';

const OFF = 0;
const ERROR = 2;

module.exports = {
  extends: 'fbjs',

  plugins: [
    'react',
    'react-internal',
  ],

  // We're stricter than the default config, mostly. We'll override a few rules
  // and then enable some React specific ones.
  rules: {
    'accessor-pairs': OFF,
    'brace-style': [ERROR, '1tbs'],
    'comma-dangle': [ERROR, 'always-multiline'],
    'consistent-return': OFF,
    'dot-location': [ERROR, 'property'],
    'dot-notation': ERROR,
    'eol-last': ERROR,
    'eqeqeq': [ERROR, 'allow-null'],
    'indent': OFF,
    'jsx-quotes': [ERROR, 'prefer-double'],
    'keyword-spacing': [ERROR, {after: true, before: true}],
    'no-bitwise': OFF,
    'no-inner-declarations': [ERROR, 'functions'],
    'no-multi-spaces': ERROR,
    'no-restricted-syntax': [ERROR, 'WithStatement'],
    'no-shadow': ERROR,
    'no-unused-expressions': ERROR,
    'no-unused-vars': [ERROR, {args: 'none'}],
    'no-useless-concat': OFF,
    'quotes': [ERROR, 'single', {avoidEscape: true, allowTemplateLiterals: true }],
    'space-before-blocks': ERROR,
    'space-before-function-paren': OFF,

    // React & JSX
    // Our transforms set this automatically
    'react/jsx-boolean-value': [ERROR, 'always'],
    'react/jsx-no-undef': ERROR,
    // We don't care to do this
    'react/jsx-sort-prop-types': OFF,
    'react/jsx-space-before-closing': ERROR,
    'react/jsx-uses-react': ERROR,
    'react/no-is-mounted': OFF,
    // This isn't useful in our test code
    'react/react-in-jsx-scope': ERROR,
    'react/self-closing-comp': ERROR,
    // We don't care to do this
    'react/jsx-wrap-multilines': [ERROR, {declaration: false, assignment: false}],

    // CUSTOM RULES
    // the second argument of warning/invariant should be a literal string
    'react-internal/warning-and-invariant-args': ERROR,
    'react-internal/no-primitive-constructors': ERROR,
  },

  globals: {
    spyOnDev: true,
    spyOnDevAndProd: true,
    spyOnProd: true,
  },
};
<commit_msg>Stop ESLint from looking for a configuration file in parent folders (#11695)<commit_after>'use strict';

const OFF = 0;
const ERROR = 2;

module.exports = {
  extends: 'fbjs',

  // Stop ESLint from looking for a configuration file in parent folders
  'root': true,

  plugins: [
    'react',
    'react-internal',
  ],

  // We're stricter than the default config, mostly. We'll override a few rules
  // and then enable some React specific ones.
  rules: {
    'accessor-pairs': OFF,
    'brace-style': [ERROR, '1tbs'],
    'comma-dangle': [ERROR, 'always-multiline'],
    'consistent-return': OFF,
    'dot-location': [ERROR, 'property'],
    'dot-notation': ERROR,
    'eol-last': ERROR,
    'eqeqeq': [ERROR, 'allow-null'],
    'indent': OFF,
    'jsx-quotes': [ERROR, 'prefer-double'],
    'keyword-spacing': [ERROR, {after: true, before: true}],
    'no-bitwise': OFF,
    'no-inner-declarations': [ERROR, 'functions'],
    'no-multi-spaces': ERROR,
    'no-restricted-syntax': [ERROR, 'WithStatement'],
    'no-shadow': ERROR,
    'no-unused-expressions': ERROR,
    'no-unused-vars': [ERROR, {args: 'none'}],
    'no-useless-concat': OFF,
    'quotes': [ERROR, 'single', {avoidEscape: true, allowTemplateLiterals: true }],
    'space-before-blocks': ERROR,
    'space-before-function-paren': OFF,

    // React & JSX
    // Our transforms set this automatically
    'react/jsx-boolean-value': [ERROR, 'always'],
    'react/jsx-no-undef': ERROR,
    // We don't care to do this
    'react/jsx-sort-prop-types': OFF,
    'react/jsx-space-before-closing': ERROR,
    'react/jsx-uses-react': ERROR,
    'react/no-is-mounted': OFF,
    // This isn't useful in our test code
    'react/react-in-jsx-scope': ERROR,
    'react/self-closing-comp': ERROR,
    // We don't care to do this
    'react/jsx-wrap-multilines': [ERROR, {declaration: false, assignment: false}],

    // CUSTOM RULES
    // the second argument of warning/invariant should be a literal string
    'react-internal/warning-and-invariant-args': ERROR,
    'react-internal/no-primitive-constructors': ERROR,
  },

  globals: {
    spyOnDev: true,
    spyOnDevAndProd: true,
    spyOnProd: true,
  },
};
<|endoftext|>


<commit_before>/**
 * Created by sebastian.kaim on 26.04.2016.
 */
"use strict";

(function ($) {

    // dot helper class
    var dot = function (_x, _y, _text) {
        this.x = _x;
        this.y = _y;
        this.text = _text;
        this.radius = 16; // hover event radius

        this.render = function (context) {
            context.beginPath();
            context.arc(this.x, this.y, 4, 0, Math.PI * 2, true);
            context.fill();
        };
    };

    // register the plugin
    $.fn.dotHover = function (dots, options) {

        // settings
        var settings = $.extend({
            // defaults
            img: "karte.png", //$('#example.jpg').first(),
            dots: [],
            width: "100px",
            height: "100px",
            setmode: true,
            setcallback: function (dot) {}
        }, options );

        //
        // create tooltip canvas
        //
        var tooltip = $('<div/>')
            .appendTo('body')
            .addClass('hoverDotTooltip')
            .css({
                backgroundColor: 'white',
                border: '1px solid blue',
                position: 'absolute',
                padding: '5px',
                marginLeft: '-50px'
            })
            .hide();

        var contexts = [];

        //
        // handle tooltip positioning on mouse move
        //
        var mouseMoveEvent = function(event, img, offsetX, offsetY) {
            var mouseX = parseInt(event.clientX - offsetX);
            var mouseY = parseInt(event.clientY - offsetY);

            var hit = false;
            for (var i = 0; i < settings.dots.length; i++) {
                var dot = settings.dots[i];
                var dx = mouseX - dot.x;
                var dy = mouseY - dot.y;

                if (dx * dx + dy * dy < dot.radius) {
                    tooltip.get(0).style.top = (dot.y - 40) + "px";
                    tooltip.get(0).style.left = (dot.x) + "px";
                    tooltip.get(0).style.marginLeft = ((-tooltip.width() / 2) + 3) + "px";

                    tooltip.html(dot.text);
                    hit = true;
                }
            }

            if(hit) tooltip.show(); else tooltip.hide();
        };

        // re-renders all dots
        var render = function () {
            $.each(contexts, function (i, ctx) {
                $.each(settings.dots, function (j, dot) {
                    dot.render(ctx);
                });
            });
        };

        //
        // places a new dot
        //
        var placedot = function (e) {
            var ndot = new dot(e.clientX  - 7, e.clientY - 7, "Example Text"); // -7,-7 for cursor offset

            settings.dots.push(ndot);
            render();
            settings.setcallback(ndot);
        };

        //
        // removes a dot
        //
        this.removeDot = function(x, y)
        {
            settings.dots = settings.dots.filter(function(el, index) {
                return dot.x == x && dot.y == y;
            });
        };

        // init mouse move on each element
        this.each(function(i, el) {
            el.style= 'background: url(' + settings.img + ');' +
            'background-repeat: no-repeat; ' +
            'background-size: contain;' +
            'width: ' + settings.width + '; ';
            //'height: ' + settings.height + '; '

            contexts.push(el.getContext('2d'));

            $(el).mousemove (function (event) {
                mouseMoveEvent(event, el, el.offsetLeft, el.offsetTop);
            });

            if(settings.setmode) $(el).click(placedot);
        });

        return this;
    };

})(jQuery);
<commit_msg>Refactored tooltip showhide<commit_after>/**
 * Created by sebastian.kaim on 26.04.2016.
 */
"use strict";

(function ($) {

    // dot helper class
    var dot = function (_x, _y, _text) {
        this.x = _x;
        this.y = _y;
        this.text = _text;
        this.radius = 16; // hover event radius

        this.render = function (context) {
            context.beginPath();
            context.arc(this.x, this.y, 4, 0, Math.PI * 2, true);
            context.fill();
        };
    };

    // register the plugin
    $.fn.dotHover = function (dots, options) {

        // settings
        var settings = $.extend({
            // defaults
            img: "karte.png", //$('#example.jpg').first(),
            dots: [],
            width: "100px",
            height: "100px",
            setmode: true,
            setcallback: function (dot) {}
        }, options );

        //
        // create tooltip canvas
        //
        var tooltip = $('<div/>')
            .appendTo('body')
            .addClass('hoverDotTooltip')
            .css({
                backgroundColor: 'white',
                border: '1px solid blue',
                position: 'absolute',
                padding: '5px',
                marginLeft: '-50px'
            })
            .hide();

        var contexts = [];

        var showHideTooltip = function (show) {
            if(show)
            {
                tooltip.show();
                tooltip.get(0).style.marginLeft = ((-tooltip.width() / 2) + 3) + "px";
            }
            else
            {
                tooltip.hide();
            }
        };

        //
        // handle tooltip positioning on mouse move
        //
        var mouseMoveEvent = function(event, img, offsetX, offsetY) {
            var mouseX = parseInt(event.clientX - offsetX);
            var mouseY = parseInt(event.clientY - offsetY);

            var hit = false;
            for (var i = 0; i < settings.dots.length; i++) {
                var dot = settings.dots[i];
                var dx = mouseX - dot.x;
                var dy = mouseY - dot.y;

                if (dx * dx + dy * dy < dot.radius) {
                    tooltip.get(0).style.top = (dot.y - 40) + "px";
                    tooltip.get(0).style.left = (dot.x) + "px";

                    tooltip.html(dot.text);
                    hit = true;
                }
            }

            showHideTooltip(hit);
        };

        // re-renders all dots
        var render = function () {
            $.each(contexts, function (i, ctx) {
                $.each(settings.dots, function (j, dot) {
                    dot.render(ctx);
                });
            });
        };

        //
        // places a new dot
        //
        var placedot = function (e) {
            var ndot = new dot(e.clientX  - 7, e.clientY - 7, "Example Text"); // -7,-7 for cursor offset

            settings.dots.push(ndot);
            render();
            settings.setcallback(ndot);
        };

        //
        // removes a dot
        //
        this.removeDot = function(x, y)
        {
            settings.dots = settings.dots.filter(function(el, index) {
                return dot.x == x && dot.y == y;
            });
        };

        // init mouse move on each element
        this.each(function(i, el) {
            el.style= 'background: url(' + settings.img + ');' +
            'background-repeat: no-repeat; ' +
            'background-size: contain;' +
            'width: ' + settings.width + '; ';
            //'height: ' + settings.height + '; '

            contexts.push(el.getContext('2d'));

            $(el).mousemove (function (event) {
                mouseMoveEvent(event, el, el.offsetLeft, el.offsetTop);
            });

            if(settings.setmode) $(el).click(placedot);
        });

        return this;
    };

})(jQuery);
<|endoftext|>


<commit_before>var request = require('request');
var async = require('async');
var util = require('util');
var mongoose = require('mongoose');

var Client = mongoose.model('Client');
var getter = require('./getter');
var mongoose = require('mongoose')

var adSchema = mongoose.model('Ad');

var _sent;

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

	getter.get(function (err, data){

		console.log(data);

		adSchema.find({})

			/*.where('temperature.max').lt(data.temperature)
			.where('temperature.min').gt(data.temperature)

			.where('humidity.max').lt(data.illuminance)
			.where('humidity.min').gt(data.illuminance)

			.where('illuminance.max').lt(data.relativeHumidity)
			.where('humidity.min').gt(data.relativeHumidity)

			.select('url')*/

		.exec(function (err, ads){

			async.map(ads, function (ad, cb){

				cb(null, ad.url);

			}, function (err, ads){

				socket.emit('ads', ads);

			});

			console.log(ads);

		});

	});

	socket.on('fid', function (data) {
		Client.list(function (err, clients) {
			Client.find({fid: data.fid}, function (er, client) {

				socket.emit('ads', {
					ads: client.ads
				});

			});
		});
	});
});

setInterval(function (){

	getter.get(function (err, data){

		adSchema.find({})

			.where('conditions.temperature.max').lt(Number(data.temperature))
			.where('conditions.temperature.min').gt(Number(data.temperature))

			.where('conditions.lux.max').lt(Number(data.illuminance))
			.where('conditions.lux.min').gt(Number(data.illuminance))

			.where('conditions.humidity.max').lt(Number(data.relativeHumidity))
			.where('conditions.humidity.min').gt(Number(data.relativeHumidity))

			.select('url')

		.exec(function (err, ads){

			async.map(ads, function (ad, cb){

				cb(null, ad.url);

			}, function (err, ads){

				io.sockets.emit('ads', ads);

				console.log(data, ads);

			});

		});

	});

}, 1000);<commit_msg>Testing socket algorithm output<commit_after>var request = require('request');
var async = require('async');
var util = require('util');
var mongoose = require('mongoose');

var Client = mongoose.model('Client');
var getter = require('./getter');
var mongoose = require('mongoose')

var adSchema = mongoose.model('Ad');

var _sent;

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

	getter.get(function (err, data){

		console.log(data);

		adSchema.find({})

			/*.where('temperature.max').lt(data.temperature)
			.where('temperature.min').gt(data.temperature)

			.where('humidity.max').lt(data.illuminance)
			.where('humidity.min').gt(data.illuminance)

			.where('illuminance.max').lt(data.relativeHumidity)
			.where('humidity.min').gt(data.relativeHumidity)

			.select('url')*/

		.exec(function (err, ads){

			async.map(ads, function (ad, cb){

				cb(null, ad.url);

			}, function (err, ads){

				socket.emit('ads', ads);

			});

			console.log(ads);

		});

	});

	socket.on('fid', function (data) {
		Client.list(function (err, clients) {
			Client.find({fid: data.fid}, function (er, client) {

				socket.emit('ads', {
					ads: client.ads
				});

			});
		});
	});
});

setInterval(function (){

	getter.get(function (err, data){

		adSchema.find({})

			.where('conditions.temperature.max').gt(Number(data.temperature))
			/*.where('conditions.temperature.min').gt(Number(data.temperature))

			.where('conditions.lux.max').lt(Number(data.illuminance))
			.where('conditions.lux.min').gt(Number(data.illuminance))

			.where('conditions.humidity.max').lt(Number(data.relativeHumidity))
			.where('conditions.humidity.min').gt(Number(data.relativeHumidity))

			.select('url')*/

		.exec(function (err, ads){

			async.map(ads, function (ad, cb){

				cb(null, ad.url);

			}, function (err, ads){

				io.sockets.emit('ads', ads);

				console.log(data, ads);

			});

		});

	});

}, 1000);<|endoftext|>


<commit_before>'use strict';

var directive = {};

directive.runnableExample = ['$templateCache', '$document', function($templateCache, $document) {
  var exampleClassNameSelector = '.runnable-example-file';
  var doc = $document[0];
  var tpl =
    '' +
    '  ' +
    '    {{ tab }}' +
    '  ' +
    '';

  return {
    restrict: 'C',
    controller : ['$scope', function($scope) {
      $scope.setTab = function(index) {
        var tab = $scope.tabs[index];
        $scope.activeTabIndex = index;
        $scope.$broadcast('tabChange', index, tab);
      };
    }],
    compile : function(element) {
      element.html(tpl + element.html());
      return function(scope, element) {
        var tabs = [], now = Date.now();
        angular.forEach(doc.querySelectorAll(exampleClassNameSelector),
          function(child, index) {

          tabs.push(child.getAttribute('name'));
        });

        if(tabs.length > 0) {
          scope.tabs = tabs;
          scope.$on('tabChange', function(e, index, title) {
            var elements = doc.querySelectorAll(exampleClassNameSelector);
            angular.forEach(elements, function(child) {
              child.style.display = 'none';
            });
            var selected = elements[index];
            selected.style.display = 'block';
          });
          scope.setTab(0);
        }
      }
    }
  };
}];

directive.dropdownToggle =
          ['$document', '$location', '$window',
  function ($document,   $location,   $window) {
    var openElement = null, close;
    return {
      restrict: 'C',
      link: function(scope, element, attrs) {
        scope.$watch(function dropdownTogglePathWatch(){return $location.path();}, function dropdownTogglePathWatchAction() {
          close && close();
        });

        element.parent().on('click', function(event) {
          close && close();
        });

        element.on('click', function(event) {
          event.preventDefault();
          event.stopPropagation();

          var iWasOpen = false;

          if (openElement) {
            iWasOpen = openElement === element;
            close();
          }

          if (!iWasOpen){
            element.parent().addClass('open');
            openElement = element;

            close = function (event) {
              event && event.preventDefault();
              event && event.stopPropagation();
              $document.off('click', close);
              element.parent().removeClass('open');
              close = null;
              openElement = null;
            }

            $document.on('click', close);
          }
        });
      }
    };
  }];

directive.syntax = function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      function makeLink(type, text, link, icon) {
        return '' +
                ' ' + text +
               '';
      };

      var html = '';
      var types = {
        'github' : {
          text : 'View on Github',
          key : 'syntaxGithub',
          icon : 'icon-github'
        },
        'plunkr' : {
          text : 'View on Plunkr',
          key : 'syntaxPlunkr',
          icon : 'icon-arrow-down'
        },
        'jsfiddle' : {
          text : 'View on JSFiddle',
          key : 'syntaxFiddle',
          icon : 'icon-cloud'
        }
      };
      for(var type in types) {
        var data = types[type];
        var link = attrs[data.key];
        if(link) {
          html += makeLink(type, data.text, link, data.icon);
        }
      };

      var nav = document.createElement('nav');
      nav.className = 'syntax-links';
      nav.innerHTML = html;

      var node = element[0];
      var par = node.parentNode;
      par.insertBefore(nav, node);
    }
  }
}

directive.tabbable = function() {
  return {
    restrict: 'C',
    compile: function(element) {
      var navTabs = angular.element('

'),
          tabContent = angular.element('

');

      tabContent.append(element.contents());
      element.append(navTabs).append(tabContent);
    },
    controller: ['$scope', '$element', function($scope, $element) {
      var navTabs = $element.contents().eq(0),
          ngModel = $element.controller('ngModel') || {},
          tabs = [],
          selectedTab;

      ngModel.$render = function() {
        var $viewValue = this.$viewValue;

        if (selectedTab ? (selectedTab.value != $viewValue) : $viewValue) {
          if(selectedTab) {
            selectedTab.paneElement.removeClass('active');
            selectedTab.tabElement.removeClass('active');
            selectedTab = null;
          }
          if($viewValue) {
            for(var i = 0, ii = tabs.length; i < ii; i++) {
              if ($viewValue == tabs[i].value) {
                selectedTab = tabs[i];
                break;
              }
            }
            if (selectedTab) {
              selectedTab.paneElement.addClass('active');
              selectedTab.tabElement.addClass('active');
            }
          }

        }
      };

      this.addPane = function(element, attr) {
        var li = angular.element('

'),
            a = li.find('a'),
            tab = {
              paneElement: element,
              paneAttrs: attr,
              tabElement: li
            };

        tabs.push(tab);

        attr.$observe('value', update)();
        attr.$observe('title', function(){ update(); a.text(tab.title); })();

        function update() {
          tab.title = attr.title;
          tab.value = attr.value || attr.title;
          if (!ngModel.$setViewValue && (!ngModel.$viewValue || tab == selectedTab)) {
            // we are not part of angular
            ngModel.$viewValue = tab.value;
          }
          ngModel.$render();
        }

        navTabs.append(li);
        li.on('click', function(event) {
          event.preventDefault();
          event.stopPropagation();
          if (ngModel.$setViewValue) {
            $scope.$apply(function() {
              ngModel.$setViewValue(tab.value);
              ngModel.$render();
            });
          } else {
            // we are not part of angular
            ngModel.$viewValue = tab.value;
            ngModel.$render();
          }
        });

        return function() {
          tab.tabElement.remove();
          for(var i = 0, ii = tabs.length; i < ii; i++ ) {
            if (tab == tabs[i]) {
              tabs.splice(i, 1);
            }
          }
        };
      }
    }]
  };
};

directive.table = function() {
  return {
    restrict: 'E',
    link: function(scope, element, attrs) {
      if (!attrs['class']) {
        element.addClass('table table-bordered table-striped code-table');
      }
    }
  };
};

var popoverElement = function() {
  var object = {
    init : function() {
      this.element = angular.element(
        '
' +
          '

' +
          '
' +
            '

' +
            '

' +
          '
' +
        '
'
      );
      this.node = this.element[0];
      this.element.css({
        'display':'block',
        'position':'absolute'
      });
      angular.element(document.body).append(this.element);

      var inner = this.element.children()[1];
      this.titleElement   = angular.element(inner.childNodes[0].firstChild);
      this.contentElement = angular.element(inner.childNodes[1]);

      //stop the click on the tooltip
      this.element.bind('click', function(event) {
        event.preventDefault();
        event.stopPropagation();
      });

      var self = this;
      angular.element(document.body).bind('click',function(event) {
        if(self.visible()) self.hide();
      });
    },

    show : function(x,y) {
      this.element.addClass('visible');
      this.position(x || 0, y || 0);
    },

    hide : function() {
      this.element.removeClass('visible');
      this.position(-9999,-9999);
    },

    visible : function() {
      return this.position().y >= 0;
    },

    isSituatedAt : function(element) {
      return this.besideElement ? element[0] == this.besideElement[0] : false;
    },

    title : function(value) {
      return this.titleElement.html(value);
    },

    content : function(value) {
      if(value && value.length > 0) {
        value = marked(value);
      }
      return this.contentElement.html(value);
    },

    positionArrow : function(position) {
      this.node.className = 'popover ' + position;
    },

    positionAway : function() {
      this.besideElement = null;
      this.hide();
    },

    positionBeside : function(element) {
      this.besideElement = element;

      var elm = element[0];
      var x = elm.offsetLeft;
      var y = elm.offsetTop;
      x -= 30;
      y -= this.node.offsetHeight + 10;
      this.show(x,y);
    },

    position : function(x,y) {
      if(x != null && y != null) {
        this.element.css('left',x + 'px');
        this.element.css('top', y + 'px');
      }
      else {
        return {
          x : this.node.offsetLeft,
          y : this.node.offsetTop
        };
      }
    }
  };

  object.init();
  object.hide();

  return object;
};

directive.popover = ['popoverElement', function(popover) {
  return {
    restrict: 'A',
    priority : 500,
    link: function(scope, element, attrs) {
      element.bind('click',function(event) {
        event.preventDefault();
        event.stopPropagation();
        if(popover.isSituatedAt(element) && popover.visible()) {
          popover.title('');
          popover.content('');
          popover.positionAway();
        }
        else {
          popover.title(attrs.title);
          popover.content(attrs.content);
          popover.positionBeside(element);
        }
      });
    }
  }
}];

directive.tabPane = function() {
  return {
    require: '^tabbable',
    restrict: 'C',
    link: function(scope, element, attrs, tabsCtrl) {
      element.on('$remove', tabsCtrl.addPane(element, attrs));
    }
  };
};

directive.foldout = ['$http', '$animate','$window', function($http, $animate, $window) {
  return {
    restrict: 'A',
    priority : 500,
    link: function(scope, element, attrs) {
      var container, loading, url = attrs.url;
      if(/\/build\//.test($window.location.href)) {
        url = '/build/docs' + url;
      }
      element.bind('click',function() {
        scope.$apply(function() {
          if(!container) {
            if(loading) return;

            loading = true;
            var par = element.parent();
            container = angular.element('
loading...
');
            $animate.enter(container, null, par);

            $http.get(url, { cache : true }).success(function(html) {
              loading = false;

              html = '
' +
                      '

' +
                      html +
                     '
';
              container.html(html);

              //avoid showing the element if the user has already closed it
              if(container.css('display') == 'block') {
                container.css('display','none');
                $animate.addClass(container, 'ng-hide');
              }
            });
          }
          else {
            container.hasClass('ng-hide') ? $animate.removeClass(container, 'ng-hide') : $animate.addClass(container, 'ng-hide');
          }
        });
      });
    }
  }
}];

angular.module('bootstrap', [])
  .directive(directive)
  .factory('popoverElement', popoverElement)
  .run(function() {
    marked.setOptions({
      gfm: true,
      tables: true
    });
  });
<commit_msg>chore(docs): fix broken example tabs<commit_after>'use strict';

var directive = {};

directive.runnableExample = ['$templateCache', '$document', function($templateCache, $document) {
  var exampleClassNameSelector = '.runnable-example-file';
  var doc = $document[0];
  var tpl =
    '' +
    '  ' +
    '    {{ tab }}' +
    '  ' +
    '';

  return {
    restrict: 'C',
    scope : true,
    controller : ['$scope', function($scope) {
      $scope.setTab = function(index) {
        var tab = $scope.tabs[index];
        $scope.activeTabIndex = index;
        $scope.$broadcast('tabChange', index, tab);
      };
    }],
    compile : function(element) {
      element.html(tpl + element.html());
      return function(scope, element) {
        var node = element[0];
        var examples = node.querySelectorAll(exampleClassNameSelector);
        var tabs = [], now = Date.now();
        angular.forEach(examples, function(child, index) {
          tabs.push(child.getAttribute('name'));
        });

        if(tabs.length > 0) {
          scope.tabs = tabs;
          scope.$on('tabChange', function(e, index, title) {
            angular.forEach(examples, function(child) {
              child.style.display = 'none';
            });
            var selected = examples[index];
            selected.style.display = 'block';
          });
          scope.setTab(0);
        }
      }
    }
  };
}];

directive.dropdownToggle =
          ['$document', '$location', '$window',
  function ($document,   $location,   $window) {
    var openElement = null, close;
    return {
      restrict: 'C',
      link: function(scope, element, attrs) {
        scope.$watch(function dropdownTogglePathWatch(){return $location.path();}, function dropdownTogglePathWatchAction() {
          close && close();
        });

        element.parent().on('click', function(event) {
          close && close();
        });

        element.on('click', function(event) {
          event.preventDefault();
          event.stopPropagation();

          var iWasOpen = false;

          if (openElement) {
            iWasOpen = openElement === element;
            close();
          }

          if (!iWasOpen){
            element.parent().addClass('open');
            openElement = element;

            close = function (event) {
              event && event.preventDefault();
              event && event.stopPropagation();
              $document.off('click', close);
              element.parent().removeClass('open');
              close = null;
              openElement = null;
            }

            $document.on('click', close);
          }
        });
      }
    };
  }];

directive.syntax = function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      function makeLink(type, text, link, icon) {
        return '' +
                ' ' + text +
               '';
      };

      var html = '';
      var types = {
        'github' : {
          text : 'View on Github',
          key : 'syntaxGithub',
          icon : 'icon-github'
        },
        'plunkr' : {
          text : 'View on Plunkr',
          key : 'syntaxPlunkr',
          icon : 'icon-arrow-down'
        },
        'jsfiddle' : {
          text : 'View on JSFiddle',
          key : 'syntaxFiddle',
          icon : 'icon-cloud'
        }
      };
      for(var type in types) {
        var data = types[type];
        var link = attrs[data.key];
        if(link) {
          html += makeLink(type, data.text, link, data.icon);
        }
      };

      var nav = document.createElement('nav');
      nav.className = 'syntax-links';
      nav.innerHTML = html;

      var node = element[0];
      var par = node.parentNode;
      par.insertBefore(nav, node);
    }
  }
}

directive.tabbable = function() {
  return {
    restrict: 'C',
    compile: function(element) {
      var navTabs = angular.element('

'),
          tabContent = angular.element('

');

      tabContent.append(element.contents());
      element.append(navTabs).append(tabContent);
    },
    controller: ['$scope', '$element', function($scope, $element) {
      var navTabs = $element.contents().eq(0),
          ngModel = $element.controller('ngModel') || {},
          tabs = [],
          selectedTab;

      ngModel.$render = function() {
        var $viewValue = this.$viewValue;

        if (selectedTab ? (selectedTab.value != $viewValue) : $viewValue) {
          if(selectedTab) {
            selectedTab.paneElement.removeClass('active');
            selectedTab.tabElement.removeClass('active');
            selectedTab = null;
          }
          if($viewValue) {
            for(var i = 0, ii = tabs.length; i < ii; i++) {
              if ($viewValue == tabs[i].value) {
                selectedTab = tabs[i];
                break;
              }
            }
            if (selectedTab) {
              selectedTab.paneElement.addClass('active');
              selectedTab.tabElement.addClass('active');
            }
          }

        }
      };

      this.addPane = function(element, attr) {
        var li = angular.element('

'),
            a = li.find('a'),
            tab = {
              paneElement: element,
              paneAttrs: attr,
              tabElement: li
            };

        tabs.push(tab);

        attr.$observe('value', update)();
        attr.$observe('title', function(){ update(); a.text(tab.title); })();

        function update() {
          tab.title = attr.title;
          tab.value = attr.value || attr.title;
          if (!ngModel.$setViewValue && (!ngModel.$viewValue || tab == selectedTab)) {
            // we are not part of angular
            ngModel.$viewValue = tab.value;
          }
          ngModel.$render();
        }

        navTabs.append(li);
        li.on('click', function(event) {
          event.preventDefault();
          event.stopPropagation();
          if (ngModel.$setViewValue) {
            $scope.$apply(function() {
              ngModel.$setViewValue(tab.value);
              ngModel.$render();
            });
          } else {
            // we are not part of angular
            ngModel.$viewValue = tab.value;
            ngModel.$render();
          }
        });

        return function() {
          tab.tabElement.remove();
          for(var i = 0, ii = tabs.length; i < ii; i++ ) {
            if (tab == tabs[i]) {
              tabs.splice(i, 1);
            }
          }
        };
      }
    }]
  };
};

directive.table = function() {
  return {
    restrict: 'E',
    link: function(scope, element, attrs) {
      if (!attrs['class']) {
        element.addClass('table table-bordered table-striped code-table');
      }
    }
  };
};

var popoverElement = function() {
  var object = {
    init : function() {
      this.element = angular.element(
        '
' +
          '

' +
          '
' +
            '

' +
            '

' +
          '
' +
        '
'
      );
      this.node = this.element[0];
      this.element.css({
        'display':'block',
        'position':'absolute'
      });
      angular.element(document.body).append(this.element);

      var inner = this.element.children()[1];
      this.titleElement   = angular.element(inner.childNodes[0].firstChild);
      this.contentElement = angular.element(inner.childNodes[1]);

      //stop the click on the tooltip
      this.element.bind('click', function(event) {
        event.preventDefault();
        event.stopPropagation();
      });

      var self = this;
      angular.element(document.body).bind('click',function(event) {
        if(self.visible()) self.hide();
      });
    },

    show : function(x,y) {
      this.element.addClass('visible');
      this.position(x || 0, y || 0);
    },

    hide : function() {
      this.element.removeClass('visible');
      this.position(-9999,-9999);
    },

    visible : function() {
      return this.position().y >= 0;
    },

    isSituatedAt : function(element) {
      return this.besideElement ? element[0] == this.besideElement[0] : false;
    },

    title : function(value) {
      return this.titleElement.html(value);
    },

    content : function(value) {
      if(value && value.length > 0) {
        value = marked(value);
      }
      return this.contentElement.html(value);
    },

    positionArrow : function(position) {
      this.node.className = 'popover ' + position;
    },

    positionAway : function() {
      this.besideElement = null;
      this.hide();
    },

    positionBeside : function(element) {
      this.besideElement = element;

      var elm = element[0];
      var x = elm.offsetLeft;
      var y = elm.offsetTop;
      x -= 30;
      y -= this.node.offsetHeight + 10;
      this.show(x,y);
    },

    position : function(x,y) {
      if(x != null && y != null) {
        this.element.css('left',x + 'px');
        this.element.css('top', y + 'px');
      }
      else {
        return {
          x : this.node.offsetLeft,
          y : this.node.offsetTop
        };
      }
    }
  };

  object.init();
  object.hide();

  return object;
};

directive.popover = ['popoverElement', function(popover) {
  return {
    restrict: 'A',
    priority : 500,
    link: function(scope, element, attrs) {
      element.bind('click',function(event) {
        event.preventDefault();
        event.stopPropagation();
        if(popover.isSituatedAt(element) && popover.visible()) {
          popover.title('');
          popover.content('');
          popover.positionAway();
        }
        else {
          popover.title(attrs.title);
          popover.content(attrs.content);
          popover.positionBeside(element);
        }
      });
    }
  }
}];

directive.tabPane = function() {
  return {
    require: '^tabbable',
    restrict: 'C',
    link: function(scope, element, attrs, tabsCtrl) {
      element.on('$remove', tabsCtrl.addPane(element, attrs));
    }
  };
};

directive.foldout = ['$http', '$animate','$window', function($http, $animate, $window) {
  return {
    restrict: 'A',
    priority : 500,
    link: function(scope, element, attrs) {
      var container, loading, url = attrs.url;
      if(/\/build\//.test($window.location.href)) {
        url = '/build/docs' + url;
      }
      element.bind('click',function() {
        scope.$apply(function() {
          if(!container) {
            if(loading) return;

            loading = true;
            var par = element.parent();
            container = angular.element('
loading...
');
            $animate.enter(container, null, par);

            $http.get(url, { cache : true }).success(function(html) {
              loading = false;

              html = '
' +
                      '

' +
                      html +
                     '
';
              container.html(html);

              //avoid showing the element if the user has already closed it
              if(container.css('display') == 'block') {
                container.css('display','none');
                $animate.addClass(container, 'ng-hide');
              }
            });
          }
          else {
            container.hasClass('ng-hide') ? $animate.removeClass(container, 'ng-hide') : $animate.addClass(container, 'ng-hide');
          }
        });
      });
    }
  }
}];

angular.module('bootstrap', [])
  .directive(directive)
  .factory('popoverElement', popoverElement)
  .run(function() {
    marked.setOptions({
      gfm: true,
      tables: true
    });
  });
<|endoftext|>


<commit_before>import define, {extend} from "./define";
import {Color, rgbConvert, Rgb} from "./color";
import {deg2rad, rad2deg} from "./math";

// https://beta.observablehq.com/@mbostock/lab-and-rgb
var K = 18,
    Xn = 0.96422,
    Yn = 1,
    Zn = 0.82521,
    t0 = 4 / 29,
    t1 = 6 / 29,
    t2 = 3 * t1 * t1,
    t3 = t1 * t1 * t1;

function labConvert(o) {
  if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
  if (o instanceof Hcl) {
    if (isNaN(o.h)) return new Lab(o.l, 0, 0, o.opacity);
    var h = o.h * deg2rad;
    return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
  }
  if (!(o instanceof Rgb)) o = rgbConvert(o);
  var r = rgb2lrgb(o.r),
      g = rgb2lrgb(o.g),
      b = rgb2lrgb(o.b),
      y = xyz2lab((0.2225045 * r + 0.7168786 * g + 0.0606169 * b) / Yn), x, z;
  if (r === g && g === b) x = z = y; else {
    x = xyz2lab((0.4360747 * r + 0.3850649 * g + 0.1430804 * b) / Xn);
    z = xyz2lab((0.0139322 * r + 0.0971045 * g + 0.7141733 * b) / Zn);
  }
  return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);
}

export default function lab(l, a, b, opacity) {
  return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
}

export function Lab(l, a, b, opacity) {
  this.l = +l;
  this.a = +a;
  this.b = +b;
  this.opacity = +opacity;
}

define(Lab, lab, extend(Color, {
  brighter: function(k) {
    return new Lab(this.l + K * (k == null ? 1 : k), this.a, this.b, this.opacity);
  },
  darker: function(k) {
    return new Lab(this.l - K * (k == null ? 1 : k), this.a, this.b, this.opacity);
  },
  rgb: function() {
    var y = (this.l + 16) / 116,
        x = isNaN(this.a) ? y : y + this.a / 500,
        z = isNaN(this.b) ? y : y - this.b / 200;
    x = Xn * lab2xyz(x);
    y = Yn * lab2xyz(y);
    z = Zn * lab2xyz(z);
    var r =  3.1338561 * x - 1.6168667 * y - 0.4906146 * z,
        g = -0.9787684 * x + 1.9161415 * y + 0.0334540 * z,
        b =  0.0719453 * x - 0.2289914 * y + 1.4052427 * z;
    return new Rgb(lrgb2rgb(r), lrgb2rgb(g), lrgb2rgb(b), this.opacity);
  }
}));

function xyz2lab(t) {
  return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
}

function lab2xyz(t) {
  return t > t1 ? t * t * t : t2 * (t - t0);
}

function lrgb2rgb(x) {
  return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
}

function rgb2lrgb(x) {
  return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
}

function hclConvert(o) {
  if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
  if (!(o instanceof Lab)) o = labConvert(o);
  if (o.a === 0 && o.b === 0) return new Hcl(NaN, 0, o.l, o.opacity);
  var h = Math.atan2(o.b, o.a) * rad2deg;
  return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
}

export function hcl(h, c, l, opacity) {
  return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
}

export function Hcl(h, c, l, opacity) {
  this.h = +h;
  this.c = +c;
  this.l = +l;
  this.opacity = +opacity;
}

define(Hcl, hcl, extend(Color, {
  brighter: function(k) {
    return new Hcl(this.h, this.c, this.l + K * (k == null ? 1 : k), this.opacity);
  },
  darker: function(k) {
    return new Hcl(this.h, this.c, this.l - K * (k == null ? 1 : k), this.opacity);
  },
  rgb: function() {
    return labConvert(this).rgb();
  }
}));
<commit_msg>Shorten.<commit_after>import define, {extend} from "./define";
import {Color, rgbConvert, Rgb} from "./color";
import {deg2rad, rad2deg} from "./math";

// https://beta.observablehq.com/@mbostock/lab-and-rgb
var K = 18,
    Xn = 0.96422,
    Yn = 1,
    Zn = 0.82521,
    t0 = 4 / 29,
    t1 = 6 / 29,
    t2 = 3 * t1 * t1,
    t3 = t1 * t1 * t1;

function labConvert(o) {
  if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
  if (o instanceof Hcl) {
    if (isNaN(o.h)) return new Lab(o.l, 0, 0, o.opacity);
    var h = o.h * deg2rad;
    return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
  }
  if (!(o instanceof Rgb)) o = rgbConvert(o);
  var r = rgb2lrgb(o.r),
      g = rgb2lrgb(o.g),
      b = rgb2lrgb(o.b),
      y = xyz2lab((0.2225045 * r + 0.7168786 * g + 0.0606169 * b) / Yn), x, z;
  if (r === g && g === b) x = z = y; else {
    x = xyz2lab((0.4360747 * r + 0.3850649 * g + 0.1430804 * b) / Xn);
    z = xyz2lab((0.0139322 * r + 0.0971045 * g + 0.7141733 * b) / Zn);
  }
  return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);
}

export default function lab(l, a, b, opacity) {
  return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
}

export function Lab(l, a, b, opacity) {
  this.l = +l;
  this.a = +a;
  this.b = +b;
  this.opacity = +opacity;
}

define(Lab, lab, extend(Color, {
  brighter: function(k) {
    return new Lab(this.l + K * (k == null ? 1 : k), this.a, this.b, this.opacity);
  },
  darker: function(k) {
    return new Lab(this.l - K * (k == null ? 1 : k), this.a, this.b, this.opacity);
  },
  rgb: function() {
    var y = (this.l + 16) / 116,
        x = isNaN(this.a) ? y : y + this.a / 500,
        z = isNaN(this.b) ? y : y - this.b / 200;
    x = Xn * lab2xyz(x);
    y = Yn * lab2xyz(y);
    z = Zn * lab2xyz(z);
    return new Rgb(
      lrgb2rgb( 3.1338561 * x - 1.6168667 * y - 0.4906146 * z),
      lrgb2rgb(-0.9787684 * x + 1.9161415 * y + 0.0334540 * z),
      lrgb2rgb( 0.0719453 * x - 0.2289914 * y + 1.4052427 * z),
      this.opacity
    );
  }
}));

function xyz2lab(t) {
  return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
}

function lab2xyz(t) {
  return t > t1 ? t * t * t : t2 * (t - t0);
}

function lrgb2rgb(x) {
  return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
}

function rgb2lrgb(x) {
  return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
}

function hclConvert(o) {
  if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
  if (!(o instanceof Lab)) o = labConvert(o);
  if (o.a === 0 && o.b === 0) return new Hcl(NaN, 0, o.l, o.opacity);
  var h = Math.atan2(o.b, o.a) * rad2deg;
  return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
}

export function hcl(h, c, l, opacity) {
  return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
}

export function Hcl(h, c, l, opacity) {
  this.h = +h;
  this.c = +c;
  this.l = +l;
  this.opacity = +opacity;
}

define(Hcl, hcl, extend(Color, {
  brighter: function(k) {
    return new Hcl(this.h, this.c, this.l + K * (k == null ? 1 : k), this.opacity);
  },
  darker: function(k) {
    return new Hcl(this.h, this.c, this.l - K * (k == null ? 1 : k), this.opacity);
  },
  rgb: function() {
    return labConvert(this).rgb();
  }
}));
<|endoftext|>


<commit_before>module.exports = {
    "env": {
        "browser": true,
        "jquery": true,
        "es6": true,
        "node": true,
        "jest": true
    },
    "plugins": [
    	"testcafe"
    ],
    "extends": [
	"eslint:recommended",
	"plugin:testcafe/recommended"
    ],
    "globals": {
        // Browser API
        "MediaMetadata": "readonly"
    },
    "parserOptions": {
        "ecmaVersion": 2018,
        "sourceType": "module"
    },
    "rules": {
        "comma-dangle": ["error", "only-multiline"],
        "space-before-blocks": ["error"],
        "keyword-spacing": [2, {"before": true, "after": true}],
        "indent": ["error", 2],
        "no-console": "off", // Used too often behind `debug` options; not dealing with this now
        "no-empty": ["error", { "allowEmptyCatch": true }],
        "no-trailing-spaces": ["error"],
        "no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": false }], // set args:none; this is generally more annoying than useful
        "no-var": ["error"],
        "prefer-const": ["error"],
        "space-infix-ops": ["error", { "int32Hint": false }],
        "eol-last": ["error", "always"]
    },
    "overrides": [
        { // TODO; these should be cleaned up as well
            "files": [
                "src/js/BookReader.js"
            ],
            "rules": {
                "no-var": ["off"],
            }
        },
    ],
};
<commit_msg>Update eslint parserOptions to use ecma 2020<commit_after>module.exports = {
    "env": {
        "browser": true,
        "jquery": true,
        "es6": true,
        "node": true,
        "jest": true
    },
    "plugins": [
    	"testcafe"
    ],
    "extends": [
	"eslint:recommended",
	"plugin:testcafe/recommended"
    ],
    "globals": {
        // Browser API
        "MediaMetadata": "readonly"
    },
    "parserOptions": {
        "ecmaVersion": 2020,
        "sourceType": "module"
    },
    "rules": {
        "comma-dangle": ["error", "only-multiline"],
        "space-before-blocks": ["error"],
        "keyword-spacing": [2, {"before": true, "after": true}],
        "indent": ["error", 2],
        "no-console": "off", // Used too often behind `debug` options; not dealing with this now
        "no-empty": ["error", { "allowEmptyCatch": true }],
        "no-trailing-spaces": ["error"],
        "no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": false }], // set args:none; this is generally more annoying than useful
        "no-var": ["error"],
        "prefer-const": ["error"],
        "space-infix-ops": ["error", { "int32Hint": false }],
        "eol-last": ["error", "always"]
    },
    "overrides": [
        { // TODO; these should be cleaned up as well
            "files": [
                "src/js/BookReader.js"
            ],
            "rules": {
                "no-var": ["off"],
            }
        },
    ],
};
<|endoftext|>


<commit_before>var http = require('http'),
    firmata = require('firmata'),
    xbee_api = require('xbee-api'),
    serialPort = require('serialport'),
    XbeeApiStream = require('./XbeeApiStream.js');

const PORT = 8080;

xbeeAPI = new xbee_api.XBeeAPI({
    api_mode: 2
});

var serialOptions = {
    baudrate: 9600,
    parser: xbeeAPI.rawParser()
};

var deviceList = [];

var Serial = new serialPort.SerialPort(process.argv[2], serialOptions, true, function() {
    console.log('Opened serial port');
    Serial.flush();

    xbeeAPI.on('frame_object', function(frame) {
        if (frame.type === xbee_api.constants.FRAME_TYPE.NODE_IDENTIFICATION) {
            deviceList.push(frame.remote64);
            console.log(frame);
        }
    });
    var server = http.createServer(httpRequestHandler);

    server.listen(PORT, function() {
        console.log("Server listening on: http://localhost:%s", PORT);
    });

});

function httpRequestHandler(request, response) {
    var url = request.url.split('/').slice(1);
    console.log(request.url);
    if (url.length > 0) {
        if (url[0] === 'device') {
            if (url.length > 1) {
                if (deviceList.filter(function(element) {
                        return element === url[1];
                    }).length > 0) {
                    var xbeeStream = new XbeeApiStream(url[1], Serial, xbeeAPI);
                    var arduino = new firmata.Board(xbeeStream, function() {
                        if (url[2] === 'pin') {
                            if (request.method === 'GET')
                                response.end(JSON.stringify(getPin(arduino, url[3])));
                            else if (request.method === 'POST') response.end(setPin(arduino, url[3], url[4]));
                        } else response.end(JSON.stringify(arduino.pins)); // send device ID, pins
                    });
                } else response.end('Error: No device found with that ID'); // send error in device ID request
            } else response.end(JSON.stringify(deviceList)); // send array of devices and IDs
        } else response.end('error in request, must request in the format /device/deviceID/pin/pinID'); // send error in request
    } else response.end('error in url'); // send error in url received
    if (xbeeStream) xbeeStream.detachEventHandlers();
}

function setPin(arduino, pin, value) {
    if (pin && value) {
        if (value === 'HIGH') value = arduino.HIGH;
        else if (value === 'LOW') value = arduino.LOW;
        arduino.pinMode(pin, arduino.MODES.OUTPUT);
        arduino.digitalWrite(pin, value);
    }
}

function getPin(arduino, pin) {
    if (pin) {
        var _isAnalog = false;
        if (pin[0] === 'A') {
            _isAnalog = true;
            pin = pin.slice(1);
        }
        pin = parseInt(pin);
        if (_isAnalog) {
            var analogPins = arduino.pins.filter(getAnalogPins);
            if (pin < analogPins.length) return analogPins[pin];
        } else {
            var digitalPins = arduino.pins.filter(getDigitalPins);
            if (pin < digitalPins.length) return digitalPins[pin];
        }
    }
    return 'ERROR: No matching pin found';
}

function getDigitalPins(item) {
    return item.analogChannel === 127;
}

function getAnalogPins(item) {
    return item.analogChannel !== 127;
}
<commit_msg>Added timeout, collision avoidance and unique IDs in deviceList<commit_after>var http = require('http'),
    firmata = require('firmata'),
    xbee_api = require('xbee-api'),
    serialPort = require('serialport'),
    XbeeApiStream = require('./XbeeApiStream.js');

const PORT = 8080;

xbeeAPI = new xbee_api.XBeeAPI({
    api_mode: 2
});

var serialOptions = {
    baudrate: 9600,
    parser: xbeeAPI.rawParser()
};

var deviceList = [];
var busyDevices = [];

var Serial = new serialPort.SerialPort(process.argv[2], serialOptions, true, function() {
    console.log('Opened serial port');
    Serial.flush();

    xbeeAPI.on('frame_object', function(frame) {
        if (frame.type === xbee_api.constants.FRAME_TYPE.NODE_IDENTIFICATION) {
            if (deviceList.filter(function(item) {
                    return item === frame.remote64;
                }).length === 0)
                deviceList.push(frame.remote64);
            console.log(frame);
        }
    });
    var server = http.createServer(httpRequestHandler);

    server.listen(PORT, function() {
        console.log("Server listening on: http://localhost:%s", PORT);
    });

});

function httpRequestHandler(request, response) {
    var url = request.url.split('/').slice(1);
    console.log(request.url);
    if (url.length > 0) {
        if (url[0] === 'device') {
            if (url.length > 1) {
                if (deviceList.filter(function(element) {
                        return element === url[1];
                    }).length > 0) {
                    if (busyDevices.filter(function(deviceID) {
                            return deviceID === url[1];
                        }).length > 0) {
                        response.end('ERROR: Device is busy. Please try again soon.');
                        return;
                    }
                    busyDevices.push(url[1]);
                    var xbeeStream = new XbeeApiStream(url[1], Serial, xbeeAPI);
                    var arduino = new firmata.Board(xbeeStream, function() {
                        setTimeout(function() {
                            if (!response.finished) {
                                response.end('ERROR: Device communication timed out. Try again.');
                                if (xbeeStream) xbeeStream.detachEventHandlers();
                                busyDevices.filter(function(deviceID) {
                                    return deviceID !== url[1];
                                });
                            }
                        }, 10000);
                        if (url[2] === 'pin') {
                            if (request.method === 'GET')
                                response.end(JSON.stringify(getPin(arduino, url[3])));
                            else if (request.method === 'POST') response.end(setPin(arduino, url[3], url[4]));
                        } else response.end(JSON.stringify(arduino.pins)); // send device ID, pins
                    });
                } else response.end('Error: No device found with that ID'); // send error in device ID request
            } else response.end(JSON.stringify(deviceList)); // send array of devices and IDs
        } else response.end('error in request, must request in the format /device/deviceID/pin/pinID'); // send error in request
    } else response.end('error in url'); // send error in url received
    if (xbeeStream) xbeeStream.detachEventHandlers();
    busyDevices.filter(function(deviceID) {
        return deviceID !== url[1];
    });
}

function setPin(arduino, pin, value) {
    if (pin && value) {
        if (value === 'HIGH') value = arduino.HIGH;
        else if (value === 'LOW') value = arduino.LOW;
        arduino.pinMode(pin, arduino.MODES.OUTPUT);
        arduino.digitalWrite(pin, value);
    }
}

function getPin(arduino, pin) {
    if (pin) {
        var _isAnalog = false;
        if (pin[0] === 'A') {
            _isAnalog = true;
            pin = pin.slice(1);
        }
        pin = parseInt(pin);
        if (_isAnalog) {
            var analogPins = arduino.pins.filter(getAnalogPins);
            if (pin < analogPins.length) return analogPins[pin];
        } else {
            var digitalPins = arduino.pins.filter(getDigitalPins);
            if (pin < digitalPins.length) return digitalPins[pin];
        }
    }
    return 'ERROR: No matching pin found';
}

function getDigitalPins(item) {
    return item.analogChannel === 127;
}

function getAnalogPins(item) {
    return item.analogChannel !== 127;
}
<|endoftext|>


<commit_before>(function() {
'use strict';

angular.module('myApp.main', ['ngRoute'])

.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/main', {
      // resolve: {
      //     "check": function ($rootScope, $location) {
      //             if(!$rootScope.loggedIn) {
      //                 $location.path('/login');
      //             }
      //         }
      //     },
      templateUrl: 'views/main/main.html',
      controller: 'mainCtrl',
      controllerAs: 'main'
  });
}])

.controller('mainCtrl', ['$location', '$routeParams', 'mainService', function($location ,$routeParams, mainService) {
    var self = this;

    mainService.getPosts().then(function (response) {
        self.posts = response.data;
        console.log(self.posts);
    });

    this.postsCount = 15;
    this.showMorePosts = function () {
        self.postsCount += 15;
    };

    this.postId = $routeParams.postId;
}]);

})();<commit_msg>adding some css<commit_after>(function() {
'use strict';

angular.module('myApp.main', ['ngRoute'])

.config(['$routeProvider', function($routeProvider) {
  $routeProvider
      .when('/main', {
      // resolve: {
      //     "check": function ($rootScope, $location) {
      //             if(!$rootScope.loggedIn) {
      //                 $location.path('/login');
      //             }
      //         }
      //     },
          templateUrl: 'views/main/main.html',
          controller: 'mainCtrl',
          controllerAs: 'main'
      })
      .when('/post', {
          templateUrl: 'views/main/post.html',
          controller: 'mainCtrl',
          controllerAs: 'main'
      });
}])

.controller('mainCtrl', ['$location', '$routeParams', 'mainService', function($location ,$routeParams, mainService) {
    var self = this;

    mainService.getPosts().then(function (response) {
        self.posts = response.data;
        console.log(self.posts);
    });

    this.postsCount = 15;
    this.showMorePosts = function () {
        self.postsCount += 15;
    };

    this.postId = $routeParams.postId;
}]);

})();<|endoftext|>