<commit_before>import * as I from 'immutable';

import { rationalLinearAlgebra,
         rationalLinearAlgebraModular } from '../arithmetic/types';

import modularSolver from '../arithmetic/solveRational';
import * as solveRational from '../arithmetic/solveRational';

class VectorLabeledEdge {
  constructor(head, tail, shift) {
    this.head = head;
    this.tail = tail;
    this.shift = shift;
  }

  toString() {
    return `VectorLabeledEdge(${this.head}, ${this.tail}, ${this.shift})`;
  }

  reverse() {
    return new VectorLabeledEdge(
      this.tail, this.head, rationalLinearAlgebra.negative(this.shift));
  }

  canonical() {
    if (this.tail < this.head
        || (this.tail == this.head && this.shift.find(x => x != 0) < 0)
       )
      return this.reverse();
    else
      return this;
  }

  get __typeName() { return 'VectorLabeledEdge'; }
};

export const ops = rationalLinearAlgebra.register({
  __repr__  : {
    VectorLabeledEdge: x => ({
      head: ops.repr(x.head),
      tail: ops.repr(x.tail),
      shift: ops.repr(x.shift)
    })
  },
  __VectorLabeledEdge__: {
    Object: ({ VectorLabeledEdge: obj }) =>
      new VectorLabeledEdge(
        ops.fromRepr(obj.head),
        ops.fromRepr(obj.tail),
        ops.fromRepr(obj.shift))
  }
});

class Graph {
  constructor(dim, edges) {
    this.dim = dim;
    this.edges = edges;
  }

  toString() {
    return `PGraph(${this.edges})`;
  }
};

const encode = value => ops.serialize(value);
const decode = value => ops.deserialize(value);

const dedupe = as => {
  const seen = {};
  const out = [];

  for (const a of as) {
    const key = encode(a);
    if (!seen[key]) {
      seen[key] = true;
      out.push(a);
    }
  }

  return out;
};

export const makeEdge = (head, tail, shift) =>
  new VectorLabeledEdge(head, tail, shift);

export const make = data => {
  const edges = dedupe(data.map(([h, t, s]) => makeEdge(h, t, s).canonical()));

  if (edges.length == 0)
    throw new Error('cannot be empty');

  const dim = edges[0].shift.length;
  if (edges.some(e => e.shift.length != dim))
    throw new Error('must have consistent shift dimensions');

  return new Graph(dim, edges);
};

export const asObject = graph => ({
  PeriodicGraph: {
    dim: graph.dim,
    edges: graph.edges.map(e => ops.repr(e))
  }
});

export const fromObject = ({ PeriodicGraph: obj }) => new Graph(
  obj.dim,
  obj.edges.map(e => ops.fromRepr(e))
);

export const vertices = graph => {
  const verts = [];
  for (const e of graph.edges) {
    verts.push(e.head);
    verts.push(e.tail);
  }
  return dedupe(verts);
};

export const adjacencies = graph => {
  const target = e => ({ v: e.tail, s: e.shift });

  const res = {};
  for (const e of graph.edges) {
    if (res[e.head] == null)
      res[e.head] = [];
    res[e.head].push(target(e));

    if (res[e.tail] == null)
      res[e.tail] = [];
    res[e.tail].push(target(e.reverse()));
  }
  return res;
};

export const coordinationSeq = (graph, start, dist) => {
  const adj  = adjacencies(graph);
  const zero = ops.vector(graph.dim);

  let oldShell = {};
  let thisShell = { [JSON.stringify([start, zero])]: true };
  const res = [1];

  for (let i = 0; i < dist; ++i) {
    const nextShell = {};
    for (const item of Object.keys(thisShell)) {
      const [v, s] = JSON.parse(item);
      for (const { v: w, s: t } of adj[v]) {
        const key = JSON.stringify([w, ops.plus(s, t)]);
        if (!oldShell[key] && !thisShell[key])
          nextShell[key] = true;
      }
    }

    res.push(Object.keys(nextShell).length);
    oldShell = thisShell;
    thisShell = nextShell;
  }

  return res;
};

const _componentInOrbitGraph = (graph, start) => {
  const adj = adjacencies(graph);
  const queue = [start]
  const bridges = [];
  const nodeShifts = I.Map([[start, ops.vector(graph.dim)]]).asMutable();

  while (queue.length) {
    const v = queue.shift();
    const av = nodeShifts.get(v);

    for (const {v: w, s: shift} of adj[v]) {
      if (nodeShifts.get(w) == undefined) {
        queue.push(w);
        nodeShifts.set(w, ops.minus(av, shift));
      }
      else {
        const aw = nodeShifts.get(w);
        const newShift = ops.plus(shift, ops.minus(aw, av));
        const pivot = newShift.find(x => ops.ne(x, 0));

        if (pivot != undefined && ops.gt(pivot, 0))
          bridges.push({ v, w, s: newShift });
      }
    }
  }

  return {
    nodes: I.Set(nodeShifts.keys()),
    nodeShifts,
    bridges
  };
};

const _isConnectedOrbitGraph = (graph) => {
  const verts = vertices(graph);
  const comp = _componentInOrbitGraph(graph, verts[0]);

  return comp.nodes.size >= verts.length;
};

const _makeBasis = M => {
  let basis = null;
  for (const row of M)
    basis = rationalLinearAlgebraModular.extendBasis(row, basis);
  return basis;
};

const _makeCoordinateTransform = (B, dim) => {
  if (B.length < dim) {
    B = B.slice();
    for (const vec of ops.identityMatrix(dim)) {
      if (ops.rank(B.concat([vec])) > ops.rank(B)) {
        B.push(vec);
      }
    }
  }

  return ops.inverse(B);
};

const _componentInCoverGraph = (graph, start) => {
  const { nodes, nodeShifts, bridges } = _componentInOrbitGraph(graph, start);
  const basis = _makeBasis(bridges.map(b => b.s));
  const thisDim = basis.length;
  const transform = _makeCoordinateTransform(basis, graph.dim);
  const old2new = I.Map(I.List(nodes).zip(I.Range(1, nodes.size+1)));

  const newEdges = graph.edges
    .filter(({ head, tail }) =>
            old2new.get(head) != null && old2new.get(tail) != null)
    .map(({ head, tail, shift }) => {
      const [v, w] = [old2new.get(head), old2new.get(tail)];
      const [av, aw] = [nodeShifts.get(head), nodeShifts.get(tail)];
      const t = ops.times(ops.plus(shift, ops.minus(aw, av)), transform);
      return [v, w, t.slice(0, thisDim)];
    });

  const multiplicity =
    thisDim == graph.dim ? ops.abs(ops.determinant(basis)) : 0;

  return {
    basis,
    multiplicity,
    nodes: nodes.toArray(),
    graph: make(newEdges)
  };
};

export const isConnected = graph => {
  const verts = vertices(graph);
  const comp = _componentInCoverGraph(graph, verts[0]);

  return comp.nodes.length >= verts.length && comp.multiplicity == 1;
};

export const connectedComponents = graph => {
  const verts = vertices(graph);
  const seen = I.Set().asMutable();
  const result = [];

  for (const start of verts) {
    if (!seen.contains(start)) {
      const comp = _componentInCoverGraph(graph, start);
      result.push(comp);
      comp.nodes.forEach(v => seen.add(v));
    }
  }

  return result;
};

export const barycentricPlacement = graph => {
  if (graph._$pos != undefined)
    return graph._$pos;

  const adj   = adjacencies(graph);
  const verts = vertices(graph);
  const vIdcs = I.Map(I.Range(0, verts.length).map(i => [verts[i], i]));

  const n = verts.length;
  const d = graph.dim;
  let A = ops.matrix(n, n);
  let t = ops.matrix(n, d);

  A[0][0] = 1;

  verts.forEach((v, i) => {
    if (i > 0) {
      adj[v].forEach(c => {
        if (c.v != v) {
          const j = vIdcs.get(c.v);
          A[i][j] -= 1;
          A[i][i] += 1;
          t[i] = ops.plus(t[i], c.s);
        }
      });
    }
  });

  const p = modularSolver(A, t);

  const result = I.Map(I.Range(0, n).map(i => [verts[i], p[i]]));

  graph._$pos = result;

  return result;
};

export const isStable = graph => {
  const pos = barycentricPlacement(graph);
  const verts = vertices(graph);
  const seen = I.Set().asMutable();

  for (const v of verts) {
    const p = pos.get(v);
    const key = encode(p.map(x => ops.mod(x, 1)));
    if (seen.contains(key))
      return false;
    else
      seen.add(key);
  }

  return true;
};

export const isLocallyStable = graph => {
  const pos = barycentricPlacement(graph);

  const adj = adjacencies(graph);
  const verts = vertices(graph);

  for (const v of verts) {
    const seen = I.Set().asMutable();

    for (const w of adj[v]) {
      const p = ops.plus(pos.get(w.v), w.s);
      const key = encode(p);
      if (seen.contains(key)) {
        return false;
      }
      else
        seen.add(key);
    }
  }

  return true;
};

export const allIncidences = (graph, v, adj=adjacencies(graph)) =>
  adj[v].map(({v: w, s}) => makeEdge(v, w, s));

export const edgeVector = (e, pos) =>
  ops.plus(e.shift, ops.minus(pos.get(e.tail), pos.get(e.head)));

if (require.main == module) {
  Array.prototype.toString = function() {
    return '[ ' + this.map(x => x.toString()).join(', ') + ' ]';
  };

  const test = g => {
    console.log('g = '+g);
    console.log('  cs  = '+coordinationSeq(g, 1, 10));
    if (isConnected(g)) {
      console.log('  pos = '+barycentricPlacement(g));
      console.log('  stable: '+isStable(g));
      console.log('  locally stable: '+isLocallyStable(g));
    }

    for (const comp of connectedComponents(g)) {
      console.log('  component:');
      console.log('    nodes = '+comp.nodes);
      console.log('    graph = '+comp.graph);
      console.log('    basis = '+comp.basis);
      console.log('    multiplicity = '+comp.multiplicity);
    }
    console.log();
  };

  test(make([ [ 1, 2, [ 0, 0 ] ],
              [ 1, 2, [ 1, 0 ] ],
              [ 1, 2, [ 0, 1 ] ] ]));

  test(make([ [ 1, 2, [ 0, 0, 0 ] ],
              [ 1, 2, [ 0, 1, 0 ] ],
              [ 1, 2, [ 0, 0, 1 ] ] ]));

  test(make([ [ 1, 2, [ 0, 0, 0 ] ],
              [ 1, 2, [ 1, 0, 0 ] ],
              [ 1, 2, [ 0, 1, 0 ] ],
              [ 1, 2, [ 0, 0, 1 ] ] ]));

  test(make([ [ 1, 1, [ 1, 0 ] ],
              [ 1, 1, [ 0, 1 ] ],
              [ 1, 2, [ 0, 0 ] ],
              [ 1, 2, [ 1, 1 ] ],
              [ 1, 3, [ 0, 0 ] ],
              [ 1, 3, [ 1, -1 ] ] ]));

  test(make([ [ 1, 1, [ 1, 0 ] ],
              [ 1, 1, [ 0, 1 ] ],
              [ 1, 2, [ 0, 0 ] ],
              [ 1, 2, [ 1, 1 ] ],
              [ 1, 3, [ 0, 0 ] ],
              [ 1, 3, [ 1, -1 ] ],
              [ 1, 4, [ 0, 0 ] ],
              [ 1, 4, [ 1, -1 ] ] ]));

  test(make([ [ 1, 1, [ -1,  1,  1 ] ],
              [ 1, 1, [  0, -1,  1 ] ],
              [ 1, 1, [  0,  0, -1 ] ] ]));

  test(make([ [ 1, 2, [ 0, 0, 0 ] ],
              [ 1, 2, [ 2, 0, 0 ] ],
              [ 1, 2, [ 0, 2, 0 ] ],
              [ 1, 2, [ 0, 0, 2 ] ] ]));

  test(make([ [ 1, 3, [ 0, 0, 0 ] ],
              [ 1, 3, [ 2, 0, 0 ] ],
              [ 1, 3, [ 0, 2, 0 ] ],
              [ 1, 3, [ 0, 0, 2 ] ],
              [ 2, 4, [ 0, 0, 0 ] ],
              [ 2, 4, [ 2, 0, 0 ] ],
              [ 2, 4, [ 0, 2, 0 ] ],
              [ 2, 4, [ 0, 0, 2 ] ] ]));

  test(make([ [ 1, 2, [ 0, 0, 0 ] ],
              [ 2, 3, [ 0, 0, 0 ] ],
              [ 3, 4, [ 0, 0, 0 ] ],
              [ 4, 5, [ 0, 0, 0 ] ],
              [ 5, 6, [ 0, 0, 0 ] ],
              [ 6, 1, [ 0, 0, 0 ] ],
              [ 1, 2, [ 1, 0, 0 ] ],
              [ 2, 3, [ 0, 1, 0 ] ],
              [ 3, 4, [ 0, 0, 1 ] ],
              [ 4, 5, [ -1, 0, 0 ] ],
              [ 5, 6, [ 0, -1, 0 ] ],
              [ 6, 1, [ 0, 0, -1 ] ] ]));
}
<commit_msg>revise some internal periodic graph code<commit_after>import * as I from 'immutable';

import { rationalLinearAlgebra,
         rationalLinearAlgebraModular } from '../arithmetic/types';

import modularSolver from '../arithmetic/solveRational';
import * as solveRational from '../arithmetic/solveRational';

class VectorLabeledEdge {
  constructor(head, tail, shift) {
    this.head = head;
    this.tail = tail;
    this.shift = shift;
  }

  toString() {
    return `VectorLabeledEdge(${this.head}, ${this.tail}, ${this.shift})`;
  }

  reverse() {
    return new VectorLabeledEdge(
      this.tail, this.head, rationalLinearAlgebra.negative(this.shift));
  }

  canonical() {
    if (this.tail < this.head
        || (this.tail == this.head && this.shift.find(x => x != 0) < 0)
       )
      return this.reverse();
    else
      return this;
  }

  get __typeName() { return 'VectorLabeledEdge'; }
};

export const ops = rationalLinearAlgebra.register({
  __repr__  : {
    VectorLabeledEdge: x => ({
      head: ops.repr(x.head),
      tail: ops.repr(x.tail),
      shift: ops.repr(x.shift)
    })
  },
  __VectorLabeledEdge__: {
    Object: ({ VectorLabeledEdge: obj }) =>
      new VectorLabeledEdge(
        ops.fromRepr(obj.head),
        ops.fromRepr(obj.tail),
        ops.fromRepr(obj.shift))
  }
});

class Graph {
  constructor(dim, edges) {
    this.dim = dim;
    this.edges = edges;
  }

  toString() {
    return `PGraph(${this.edges})`;
  }
};

const encode = value => ops.serialize(value);
const decode = value => ops.deserialize(value);

const dedupe = as => {
  const seen = {};
  const out = [];

  for (const a of as) {
    const key = encode(a);
    if (!seen[key]) {
      seen[key] = true;
      out.push(a);
    }
  }

  return out;
};

export const makeEdge = (head, tail, shift) =>
  new VectorLabeledEdge(head, tail, shift);

export const make = data => {
  const edges = dedupe(data.map(([h, t, s]) => makeEdge(h, t, s).canonical()));

  if (edges.length == 0)
    throw new Error('cannot be empty');

  const dim = edges[0].shift.length;
  if (edges.some(e => e.shift.length != dim))
    throw new Error('must have consistent shift dimensions');

  return new Graph(dim, edges);
};

export const asObject = graph => ({
  PeriodicGraph: {
    dim: graph.dim,
    edges: graph.edges.map(e => ops.repr(e))
  }
});

export const fromObject = ({ PeriodicGraph: obj }) => new Graph(
  obj.dim,
  obj.edges.map(e => ops.fromRepr(e))
);

export const vertices = graph => {
  const verts = [];
  for (const e of graph.edges) {
    verts.push(e.head);
    verts.push(e.tail);
  }
  return dedupe(verts);
};

export const adjacencies = graph => {
  const target = e => ({ v: e.tail, s: e.shift });

  const res = {};
  for (const e of graph.edges) {
    if (res[e.head] == null)
      res[e.head] = [];
    res[e.head].push(target(e));

    if (res[e.tail] == null)
      res[e.tail] = [];
    res[e.tail].push(target(e.reverse()));
  }
  return res;
};

export const coordinationSeq = (graph, start, dist) => {
  const adj  = adjacencies(graph);
  const zero = ops.vector(graph.dim);

  let oldShell = {};
  let thisShell = { [JSON.stringify([start, zero])]: true };
  const res = [1];

  for (let i = 0; i < dist; ++i) {
    const nextShell = {};
    for (const item of Object.keys(thisShell)) {
      const [v, s] = JSON.parse(item);
      for (const { v: w, s: t } of adj[v]) {
        const key = JSON.stringify([w, ops.plus(s, t)]);
        if (!oldShell[key] && !thisShell[key])
          nextShell[key] = true;
      }
    }

    res.push(Object.keys(nextShell).length);
    oldShell = thisShell;
    thisShell = nextShell;
  }

  return res;
};

const _componentInOrbitGraph = (graph, start) => {
  const adj = adjacencies(graph);
  const bridges = [];
  const nodes = [start];
  const nodeShifts = { [start]: ops.vector(graph.dim) };

  for (let i = 0; i < nodes.length; ++i) {
    const v = nodes[i];
    const av = nodeShifts[v];

    for (const {v: w, s: shift} of adj[v]) {
      if (nodeShifts[w] == null) {
        nodes.push(w);
        nodeShifts[w] = ops.minus(av, shift);
      }
      else {
        const aw = nodeShifts[w];
        const newShift = ops.plus(shift, ops.minus(aw, av));
        if (ops.sgn(newShift) > 0)
          bridges.push({ v, w, s: newShift });
      }
    }
  }

  return { nodes, nodeShifts, bridges };
};

const _makeBasis = M => {
  let basis = null;
  for (const row of M)
    basis = rationalLinearAlgebraModular.extendBasis(row, basis);
  return basis;
};

const _makeCoordinateTransform = (B, dim) => {
  if (B.length < dim) {
    B = B.slice();
    for (const vec of ops.identityMatrix(dim)) {
      if (ops.rank(B.concat([vec])) > ops.rank(B))
        B.push(vec);
    }
  }

  return ops.inverse(B);
};

const _componentInCoverGraph = (graph, start) => {
  const { nodes, nodeShifts, bridges } = _componentInOrbitGraph(graph, start);
  const basis = _makeBasis(bridges.map(b => b.s));
  const dim = basis.length;
  const transform = _makeCoordinateTransform(basis, graph.dim);

  const old2new = {};
  for (let i = 0; i < nodes.length; ++i)
    old2new[nodes[i]] = i + 1;

  const newEdges = graph.edges
    .filter(({ head, tail }) => old2new[head] != null && old2new[tail] != null)
    .map(({ head, tail, shift }) => {
      const [v, w] = [old2new[head], old2new[tail]];
      const [av, aw] = [nodeShifts[head], nodeShifts[tail]];
      const t = ops.times(ops.plus(shift, ops.minus(aw, av)), transform);
      return [v, w, t.slice(0, dim)];
    });

  const multiplicity = dim == graph.dim ? ops.abs(ops.determinant(basis)) : 0;

  return { basis, multiplicity, nodes, graph: make(newEdges) };
};

export const isConnected = graph => {
  const verts = vertices(graph);
  const comp = _componentInCoverGraph(graph, verts[0]);

  return comp.nodes.length >= verts.length && comp.multiplicity == 1;
};

export const connectedComponents = graph => {
  const verts = vertices(graph);
  const seen = {};
  const result = [];

  for (const start of verts) {
    if (!seen[start]) {
      const comp = _componentInCoverGraph(graph, start);
      result.push(comp);
      for (const v of comp.nodes)
        seen[v] = true;
    }
  }

  return result;
};

export const barycentricPlacement = graph => {
  if (graph._$pos != undefined)
    return graph._$pos;

  const adj   = adjacencies(graph);
  const verts = vertices(graph);
  const vIdcs = I.Map(I.Range(0, verts.length).map(i => [verts[i], i]));

  const n = verts.length;
  const d = graph.dim;
  let A = ops.matrix(n, n);
  let t = ops.matrix(n, d);

  A[0][0] = 1;

  verts.forEach((v, i) => {
    if (i > 0) {
      adj[v].forEach(c => {
        if (c.v != v) {
          const j = vIdcs.get(c.v);
          A[i][j] -= 1;
          A[i][i] += 1;
          t[i] = ops.plus(t[i], c.s);
        }
      });
    }
  });

  const p = modularSolver(A, t);

  const result = I.Map(I.Range(0, n).map(i => [verts[i], p[i]]));

  graph._$pos = result;

  return result;
};

export const isStable = graph => {
  const pos = barycentricPlacement(graph);
  const verts = vertices(graph);
  const seen = I.Set().asMutable();

  for (const v of verts) {
    const p = pos.get(v);
    const key = encode(p.map(x => ops.mod(x, 1)));
    if (seen.contains(key))
      return false;
    else
      seen.add(key);
  }

  return true;
};

export const isLocallyStable = graph => {
  const pos = barycentricPlacement(graph);

  const adj = adjacencies(graph);
  const verts = vertices(graph);

  for (const v of verts) {
    const seen = I.Set().asMutable();

    for (const w of adj[v]) {
      const p = ops.plus(pos.get(w.v), w.s);
      const key = encode(p);
      if (seen.contains(key)) {
        return false;
      }
      else
        seen.add(key);
    }
  }

  return true;
};

export const allIncidences = (graph, v, adj=adjacencies(graph)) =>
  adj[v].map(({v: w, s}) => makeEdge(v, w, s));

export const edgeVector = (e, pos) =>
  ops.plus(e.shift, ops.minus(pos.get(e.tail), pos.get(e.head)));

if (require.main == module) {
  Array.prototype.toString = function() {
    return '[ ' + this.map(x => x.toString()).join(', ') + ' ]';
  };

  const test = g => {
    console.log('g = '+g);
    console.log('  cs  = '+coordinationSeq(g, 1, 10));
    if (isConnected(g)) {
      console.log('  pos = '+barycentricPlacement(g));
      console.log('  stable: '+isStable(g));
      console.log('  locally stable: '+isLocallyStable(g));
    }

    for (const comp of connectedComponents(g)) {
      console.log('  component:');
      console.log('    nodes = '+comp.nodes);
      console.log('    graph = '+comp.graph);
      console.log('    basis = '+comp.basis);
      console.log('    multiplicity = '+comp.multiplicity);
    }
    console.log();
  };

  test(make([ [ 1, 2, [ 0, 0 ] ],
              [ 1, 2, [ 1, 0 ] ],
              [ 1, 2, [ 0, 1 ] ] ]));

  test(make([ [ 1, 2, [ 0, 0, 0 ] ],
              [ 1, 2, [ 0, 1, 0 ] ],
              [ 1, 2, [ 0, 0, 1 ] ] ]));

  test(make([ [ 1, 2, [ 0, 0, 0 ] ],
              [ 1, 2, [ 1, 0, 0 ] ],
              [ 1, 2, [ 0, 1, 0 ] ],
              [ 1, 2, [ 0, 0, 1 ] ] ]));

  test(make([ [ 1, 1, [ 1, 0 ] ],
              [ 1, 1, [ 0, 1 ] ],
              [ 1, 2, [ 0, 0 ] ],
              [ 1, 2, [ 1, 1 ] ],
              [ 1, 3, [ 0, 0 ] ],
              [ 1, 3, [ 1, -1 ] ] ]));

  test(make([ [ 1, 1, [ 1, 0 ] ],
              [ 1, 1, [ 0, 1 ] ],
              [ 1, 2, [ 0, 0 ] ],
              [ 1, 2, [ 1, 1 ] ],
              [ 1, 3, [ 0, 0 ] ],
              [ 1, 3, [ 1, -1 ] ],
              [ 1, 4, [ 0, 0 ] ],
              [ 1, 4, [ 1, -1 ] ] ]));

  test(make([ [ 1, 1, [ -1,  1,  1 ] ],
              [ 1, 1, [  0, -1,  1 ] ],
              [ 1, 1, [  0,  0, -1 ] ] ]));

  test(make([ [ 1, 2, [ 0, 0, 0 ] ],
              [ 1, 2, [ 2, 0, 0 ] ],
              [ 1, 2, [ 0, 2, 0 ] ],
              [ 1, 2, [ 0, 0, 2 ] ] ]));

  test(make([ [ 1, 3, [ 0, 0, 0 ] ],
              [ 1, 3, [ 2, 0, 0 ] ],
              [ 1, 3, [ 0, 2, 0 ] ],
              [ 1, 3, [ 0, 0, 2 ] ],
              [ 2, 4, [ 0, 0, 0 ] ],
              [ 2, 4, [ 2, 0, 0 ] ],
              [ 2, 4, [ 0, 2, 0 ] ],
              [ 2, 4, [ 0, 0, 2 ] ] ]));

  test(make([ [ 1, 2, [ 0, 0, 0 ] ],
              [ 2, 3, [ 0, 0, 0 ] ],
              [ 3, 4, [ 0, 0, 0 ] ],
              [ 4, 5, [ 0, 0, 0 ] ],
              [ 5, 6, [ 0, 0, 0 ] ],
              [ 6, 1, [ 0, 0, 0 ] ],
              [ 1, 2, [ 1, 0, 0 ] ],
              [ 2, 3, [ 0, 1, 0 ] ],
              [ 3, 4, [ 0, 0, 1 ] ],
              [ 4, 5, [ -1, 0, 0 ] ],
              [ 5, 6, [ 0, -1, 0 ] ],
              [ 6, 1, [ 0, 0, -1 ] ] ]));
}
<|endoftext|>


<commit_before>/* vuex-i18n-store defines a vuex module to store locale translations. Make sure
** to also include the file vuex-i18n.js to enable easy access to localized
** strings in your vue components.
*/

// define a simple vuex module to handle locale translations
const i18nVuexModule =  {
	state: {
		locale: null,
		translations: {}
	},
	mutations: {

		// set the current locale
		SET_LOCALE(state, payload) {
			state.locale = payload.locale;
		},

		// add a new locale
		ADD_LOCALE(state, payload) {
			// reduce the given translations to a single-depth tree
			var translations = flattenTranslations(payload.translations);
			state.translations[payload.locale] = translations;
		},

		// add a new locale
		REMOVE_LOCALE(state, payload) {

			// check if the given locale is present in the state
			if (state.translations.hasOwnProperty(payload.locale)) {

				// check if the current locale is the given locale to remvoe
				if (state.locale === payload.locale) {
					// reset the current locale
					state.locale = null;
				}

				// create a copy of the translations object
				let translationCopy = Object.assign({}, state.translations);

				// remove the given locale
				delete translationCopy[payload.locale];

				// set the state to the new object
				state.translations = copy;

			}
		}

	},
	actions: {

		// set the current locale
		setLocale(context, payload) {
			context.commit({
				type: 'SET_LOCALE',
				locale: payload.locale
			});
		},

		// add a new locale with translations
		addLocale(context, payload) {
			context.commit({
				type: 'ADD_LOCALE',
				locale: payload.locale,
				translations: payload.translations
			});
		},

		// remove the given locale translations
		removeLocale(context, payload) {
			context.commit({
				type: 'REMOVE_LOCALE',
				locale: payload.locale,
				translations: payload.translations
			});
		}

	}
};

// flattenTranslations will convert object trees for translations into a
// single-depth object tree
const flattenTranslations = function flattenTranslations(translations) {

	let toReturn = {};

	for (let i in translations) {

		// check if the property is present
		if (!translations.hasOwnProperty(i)) {
			continue;
		}

		// get the type of the property
		let objType = typeof translations[i];

		// allow unflattened array of strings
		if (isArray(translations[i])) {

			let count = translations[i].length;

			for (let index = 0; index < count; index++) {
				let itemType = typeof translations[i][index];

				if (itemType !== 'string') {
					console.warn('vuex-i18n:','currently only arrays of strings are fully supported', translations[i]);
					break;
				}
			}

			toReturn[i] = translations[i];

		} else if (objType == 'object' && objType !== null) {

			let flatObject = flattenTranslations(translations[i]);

			for (let x in flatObject) {
				if (!flatObject.hasOwnProperty(x)) continue;

				toReturn[i + '.' + x] = flatObject[x];
			}

		} else {
			toReturn[i] = translations[i];

		}
	}
	return toReturn;
};

// check if the given object is an array
function isArray(obj) {
	return !!obj && Array === obj.constructor;
}

export default i18nVuexModule;
<commit_msg>bugfix for remove locale function<commit_after>/* vuex-i18n-store defines a vuex module to store locale translations. Make sure
** to also include the file vuex-i18n.js to enable easy access to localized
** strings in your vue components.
*/

// define a simple vuex module to handle locale translations
const i18nVuexModule =  {
	state: {
		locale: null,
		translations: {}
	},
	mutations: {

		// set the current locale
		SET_LOCALE(state, payload) {
			state.locale = payload.locale;
		},

		// add a new locale
		ADD_LOCALE(state, payload) {
			// reduce the given translations to a single-depth tree
			var translations = flattenTranslations(payload.translations);
			state.translations[payload.locale] = translations;
		},

		// add a new locale
		REMOVE_LOCALE(state, payload) {

			// check if the given locale is present in the state
			if (state.translations.hasOwnProperty(payload.locale)) {

				// check if the current locale is the given locale to remvoe
				if (state.locale === payload.locale) {
					// reset the current locale
					state.locale = null;
				}

				// create a copy of the translations object
				let translationCopy = Object.assign({}, state.translations);

				// remove the given locale
				delete translationCopy[payload.locale];

				// set the state to the new object
				state.translations = translationCopy;

			}
		}

	},
	actions: {

		// set the current locale
		setLocale(context, payload) {
			context.commit({
				type: 'SET_LOCALE',
				locale: payload.locale
			});
		},

		// add a new locale with translations
		addLocale(context, payload) {
			context.commit({
				type: 'ADD_LOCALE',
				locale: payload.locale,
				translations: payload.translations
			});
		},

		// remove the given locale translations
		removeLocale(context, payload) {
			context.commit({
				type: 'REMOVE_LOCALE',
				locale: payload.locale,
				translations: payload.translations
			});
		}

	}
};

// flattenTranslations will convert object trees for translations into a
// single-depth object tree
const flattenTranslations = function flattenTranslations(translations) {

	let toReturn = {};

	for (let i in translations) {

		// check if the property is present
		if (!translations.hasOwnProperty(i)) {
			continue;
		}

		// get the type of the property
		let objType = typeof translations[i];

		// allow unflattened array of strings
		if (isArray(translations[i])) {

			let count = translations[i].length;

			for (let index = 0; index < count; index++) {
				let itemType = typeof translations[i][index];

				if (itemType !== 'string') {
					console.warn('vuex-i18n:','currently only arrays of strings are fully supported', translations[i]);
					break;
				}
			}

			toReturn[i] = translations[i];

		} else if (objType == 'object' && objType !== null) {

			let flatObject = flattenTranslations(translations[i]);

			for (let x in flatObject) {
				if (!flatObject.hasOwnProperty(x)) continue;

				toReturn[i + '.' + x] = flatObject[x];
			}

		} else {
			toReturn[i] = translations[i];

		}
	}
	return toReturn;
};

// check if the given object is an array
function isArray(obj) {
	return !!obj && Array === obj.constructor;
}

export default i18nVuexModule;
<|endoftext|>


<commit_before>/*
 * Spreed WebRTC.
 * Copyright (C) 2013-2014 struktur AG
 *
 * This file is part of Spreed WebRTC.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
/*jshint -W030 */
({
	baseUrl: '../static/js',
	mainConfigFile: '../static/js/main.js',
	optimize: 'uglify2',
	uglify2: {
		output: {
			beautify: false
		},
		compress: {
			sequences: true,
			global_defs: {
				DEBUG: false
			}
		},
		warnings: true,
		mangle: true
	},
	wrap: false,
	useStrict: true,
	dir: './out',
	skipDirOptimize: true,
	removeCombined: true,
	modules: [
		{
			name: 'main',
			exclude: [
				'base'
			]
		},
		{
			name: 'base',
		},
		{
			name: 'app',
			exclude: [
				'main',
				'base'
			],
			inlineText: true,
		},
		{
			name: 'libs/pdf/pdf.worker',
		}
	]
})
<commit_msg>Updated building of pdf.js files.<commit_after>/*
 * Spreed WebRTC.
 * Copyright (C) 2013-2014 struktur AG
 *
 * This file is part of Spreed WebRTC.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
/*jshint -W030 */
({
	baseUrl: '../static/js',
	mainConfigFile: '../static/js/main.js',
	optimize: 'uglify2',
	uglify2: {
		output: {
			beautify: false
		},
		compress: {
			sequences: true,
			global_defs: {
				DEBUG: false
			}
		},
		warnings: true,
		mangle: true
	},
	wrap: false,
	useStrict: true,
	dir: './out',
	skipDirOptimize: true,
	removeCombined: true,
	modules: [
		{
			name: 'main',
			exclude: [
				'base'
			]
		},
		{
			name: 'base',
			include: [
				'pdf.compatibility'
			]
		},
		{
			name: 'app',
			exclude: [
				'main',
				'base'
			],
			inlineText: true,
		},
		{
			name: 'pdf',
			dir: './out/libs/pdf',
			exclude: [
				'base'
			]
		},
		{
			name: 'pdf.worker',
			dir: './out/libs/pdf',
			override: {
				skipModuleInsertion: true
			}
		}
	]
})
<|endoftext|>


<commit_before>'use strict';

var _BN = require('bn.js');
var $ = require('../util/preconditions');
var _ = require('lodash');

var BN = function BN(n, base) {
  if (!(this instanceof BN)) {
    return new BN(n, base);
  }
  _BN.apply(this, arguments);
};

BN.prototype = _BN.prototype;

var reversebuf = function(buf) {
  var buf2 = new Buffer(buf.length);
  for (var i = 0; i < buf.length; i++) {
    buf2[i] = buf[buf.length - 1 - i];
  }
  return buf2;
};

BN.fromNumber = function(n) {
  $.checkArgument(_.isNumber(n));
  return BN(n);
};

BN.prototype.toNumber = function() {
  return parseInt(this.toString(10), 10);
};

BN.fromString = function(str) {
  $.checkArgument(_.isString(str));
  return BN(str);
};

BN.fromBuffer = function(buf, opts) {
  if (typeof opts !== 'undefined' && opts.endian === 'little') {
    buf = reversebuf(buf);
  }
  var hex = buf.toString('hex');
  var bn = new BN(hex, 16);
  return bn;
};

BN.trim = function(buf, natlen) {
  return buf.slice(natlen - buf.length, buf.length);
};

BN.pad = function(buf, natlen, size) {
  var rbuf = new Buffer(size);
  for (var i = 0; i < buf.length; i++) {
    rbuf[rbuf.length - 1 - i] = buf[buf.length - 1 - i];
  }
  for (i = 0; i < size - natlen; i++) {
    rbuf[i] = 0;
  }
  return rbuf;
};

BN.prototype.toBuffer = function(opts) {
  var buf, hex;
  if (opts && opts.size) {
    hex = this.toString(16, 2);
    var natlen = hex.length / 2;
    buf = new Buffer(hex, 'hex');

    if (natlen === opts.size) {
      buf = buf;
    } else if (natlen > opts.size) {
      buf = BN.trim(buf, natlen);
    } else if (natlen < opts.size) {
      buf = BN.pad(buf, natlen, opts.size);
    }
  } else {
    hex = this.toString(16, 2);
    buf = new Buffer(hex, 'hex');
  }

  if (typeof opts !== 'undefined' && opts.endian === 'little') {
    buf = reversebuf(buf);
  }

  return buf;
};

// signed magnitude buffer
// most significant bit represents sign (0 = positive, -1 = negative)
BN.fromSM = function(buf, opts) {
  var ret;
  if (buf.length === 0) {
    return BN.fromBuffer(new Buffer([0]));
  }

  var endian = 'big';
  if (opts) {
    endian = opts.endian;
  }
  if (endian === 'little') {
    buf = reversebuf(buf);
  }

  if (buf[0] & 0x80) {
    buf[0] = buf[0] & 0x7f;
    ret = BN.fromBuffer(buf);
    ret.neg().copy(ret);
  } else {
    ret = BN.fromBuffer(buf);
  }
  return ret;
};

BN.prototype.toSMBigEndian = function() {
  var buf;
  if (this.cmp(0) === -1) {
    buf = this.neg().toBuffer();
    if (buf[0] & 0x80) {
      buf = Buffer.concat([new Buffer([0x80]), buf]);
    } else {
      buf[0] = buf[0] | 0x80;
    }
  } else {
    buf = this.toBuffer();
    if (buf[0] & 0x80) {
      buf = Buffer.concat([new Buffer([0x00]), buf]);
    }
  }

  if (buf.length === 1 & buf[0] === 0) {
    buf = new Buffer([]);
  }
  return buf;
};
BN.prototype.toSM = function(opts) {
  var endian = opts ? opts.endian : 'big';
  var buf = this.toSMBigEndian();

  if (endian === 'little') {
    buf = reversebuf(buf);
  }
  return buf;
};

// This is analogous to the constructor for CScriptNum in bitcoind. Many ops in
// bitcoind's script interpreter use CScriptNum, which is not really a proper
// bignum. Instead, an error is thrown if trying to input a number bigger than
// 4 bytes. We copy that behavior here.
BN.fromScriptNumBuffer = function(buf, fRequireMinimal) {
  var nMaxNumSize = 4;
  $.checkArgument(buf.length <= nMaxNumSize, new Error('script number overflow'));
  if (fRequireMinimal && buf.length > 0) {
    // Check that the number is encoded with the minimum possible
    // number of bytes.
    //
    // If the most-significant-byte - excluding the sign bit - is zero
    // then we're not minimal. Note how this test also rejects the
    // negative-zero encoding, 0x80.
    if ((buf[buf.length - 1] & 0x7f) === 0) {
      // One exception: if there's more than one byte and the most
      // significant bit of the second-most-significant-byte is set
      // it would conflict with the sign bit. An example of this case
      // is +-255, which encode to 0xff00 and 0xff80 respectively.
      // (big-endian).
      if (buf.length <= 1 || (buf[buf.length - 2] & 0x80) === 0) {
        throw new Error('non-minimally encoded script number');
      }
    }
  }
  return BN.fromSM(buf, {
    endian: 'little'
  });
};

// The corollary to the above, with the notable exception that we do not throw
// an error if the output is larger than four bytes. (Which can happen if
// performing a numerical operation that results in an overflow to more than 4
// bytes).
BN.prototype.toScriptNumBuffer = function() {
  return this.toSM({
    endian: 'little'
  });
};

var decorate = function decorate(name) {
  BN.prototype['_' + name] = BN.prototype[name];
  var f = function(b) {
    if (typeof b === 'string') {
      b = new BN(b);
    } else if (typeof b === 'number') {
      b = new BN(b.toString());
    }
    return this['_' + name](b);
  };
  BN.prototype[name] = f;
};

BN.prototype.gt = function(b) {
  return this.cmp(b) > 0;
};

BN.prototype.lt = function(b) {
  return this.cmp(b) < 0;
};

decorate('add');
decorate('sub');
decorate('mul');
decorate('mod');
decorate('div');
decorate('cmp');
decorate('gt');
decorate('lt');

module.exports = BN;
<commit_msg>Drop prototypal inheritance for bn<commit_after>'use strict';

var BN = require('bn.js');
var $ = require('../util/preconditions');
var _ = require('lodash');

var reversebuf = function(buf) {
  var buf2 = new Buffer(buf.length);
  for (var i = 0; i < buf.length; i++) {
    buf2[i] = buf[buf.length - 1 - i];
  }
  return buf2;
};

BN.fromNumber = function(n) {
  $.checkArgument(_.isNumber(n));
  return BN(n);
};

BN.fromString = function(str) {
  $.checkArgument(_.isString(str));
  return BN(str);
};

BN.fromBuffer = function(buf, opts) {
  if (typeof opts !== 'undefined' && opts.endian === 'little') {
    buf = reversebuf(buf);
  }
  var hex = buf.toString('hex');
  var bn = new BN(hex, 16);
  return bn;
};

/**
 * Instantiate a BigNumber from a "signed magnitude buffer"
 * (a buffer where the most significant bit represents the sign (0 = positive, -1 = negative))
 */
BN.fromSM = function(buf, opts) {
  var ret;
  if (buf.length === 0) {
    return BN.fromBuffer(new Buffer([0]));
  }

  var endian = 'big';
  if (opts) {
    endian = opts.endian;
  }
  if (endian === 'little') {
    buf = reversebuf(buf);
  }

  if (buf[0] & 0x80) {
    buf[0] = buf[0] & 0x7f;
    ret = BN.fromBuffer(buf);
    ret.neg().copy(ret);
  } else {
    ret = BN.fromBuffer(buf);
  }
  return ret;
};

BN.prototype.toNumber = function() {
  return parseInt(this.toString(10), 10);
};

BN.prototype.toBuffer = function(opts) {
  var buf, hex;
  if (opts && opts.size) {
    hex = this.toString(16, 2);
    var natlen = hex.length / 2;
    buf = new Buffer(hex, 'hex');

    if (natlen === opts.size) {
      buf = buf;
    } else if (natlen > opts.size) {
      buf = BN.trim(buf, natlen);
    } else if (natlen < opts.size) {
      buf = BN.pad(buf, natlen, opts.size);
    }
  } else {
    hex = this.toString(16, 2);
    buf = new Buffer(hex, 'hex');
  }

  if (typeof opts !== 'undefined' && opts.endian === 'little') {
    buf = reversebuf(buf);
  }

  return buf;
};

BN.prototype.toSMBigEndian = function() {
  var buf;
  if (this.cmp(0) === -1) {
    buf = this.neg().toBuffer();
    if (buf[0] & 0x80) {
      buf = Buffer.concat([new Buffer([0x80]), buf]);
    } else {
      buf[0] = buf[0] | 0x80;
    }
  } else {
    buf = this.toBuffer();
    if (buf[0] & 0x80) {
      buf = Buffer.concat([new Buffer([0x00]), buf]);
    }
  }

  if (buf.length === 1 & buf[0] === 0) {
    buf = new Buffer([]);
  }
  return buf;
};

BN.prototype.toSM = function(opts) {
  var endian = opts ? opts.endian : 'big';
  var buf = this.toSMBigEndian();

  if (endian === 'little') {
    buf = reversebuf(buf);
  }
  return buf;
};

/**
 * Create a BN from a "ScriptNum":
 * This is analogous to the constructor for CScriptNum in bitcoind. Many ops in
 * bitcoind's script interpreter use CScriptNum, which is not really a proper
 * bignum. Instead, an error is thrown if trying to input a number bigger than
 * 4 bytes. We copy that behavior here.
 */
BN.fromScriptNumBuffer = function(buf, fRequireMinimal) {
  var nMaxNumSize = 4;
  $.checkArgument(buf.length <= nMaxNumSize, new Error('script number overflow'));
  if (fRequireMinimal && buf.length > 0) {
    // Check that the number is encoded with the minimum possible
    // number of bytes.
    //
    // If the most-significant-byte - excluding the sign bit - is zero
    // then we're not minimal. Note how this test also rejects the
    // negative-zero encoding, 0x80.
    if ((buf[buf.length - 1] & 0x7f) === 0) {
      // One exception: if there's more than one byte and the most
      // significant bit of the second-most-significant-byte is set
      // it would conflict with the sign bit. An example of this case
      // is +-255, which encode to 0xff00 and 0xff80 respectively.
      // (big-endian).
      if (buf.length <= 1 || (buf[buf.length - 2] & 0x80) === 0) {
        throw new Error('non-minimally encoded script number');
      }
    }
  }
  return BN.fromSM(buf, {
    endian: 'little'
  });
};

/**
 * The corollary to the above, with the notable exception that we do not throw
 * an error if the output is larger than four bytes. (Which can happen if
 * performing a numerical operation that results in an overflow to more than 4
 * bytes).
 */
BN.prototype.toScriptNumBuffer = function() {
  return this.toSM({
    endian: 'little'
  });
};

BN.prototype.gt = function(b) {
  return this.cmp(b) > 0;
};

BN.prototype.lt = function(b) {
  return this.cmp(b) < 0;
};

BN.trim = function(buf, natlen) {
  return buf.slice(natlen - buf.length, buf.length);
};

BN.pad = function(buf, natlen, size) {
  var rbuf = new Buffer(size);
  for (var i = 0; i < buf.length; i++) {
    rbuf[rbuf.length - 1 - i] = buf[buf.length - 1 - i];
  }
  for (i = 0; i < size - natlen; i++) {
    rbuf[i] = 0;
  }
  return rbuf;
};

module.exports = BN;
<|endoftext|>


<commit_before>var fs = require('fs'),
    jshint = require('jshint'),
    UglifyJS = require('uglify-js'),

    deps = require('./deps.js').deps,
    hintrc = require('./hintrc.js').config;

function lintFiles(files) {

	var errorsFound = 0,
	    i, j, len, len2, src, errors, e;

	for (i = 0, len = files.length; i < len; i++) {

		jshint.JSHINT(fs.readFileSync(files[i], 'utf8'), hintrc);
		errors = jshint.JSHINT.errors;

		for (j = 0, len2 = errors.length; j < len2; j++) {
			e = errors[i];
			console.log(files[i] + '\tline ' + e.line + '\tcol ' + e.character + '\t ' + e.reason);
		}

		errorsFound += len2;
	}

	return errorsFound;
}

function getFiles(compsBase32) {
	var memo = {},
	    comps;

	if (compsBase32) {
		comps = parseInt(compsBase32, 32).toString(2).split('');
		console.log('Managing dependencies...')
	}

	function addFiles(srcs) {
		for (var j = 0, len = srcs.length; j < len; j++) {
			memo[srcs[j]] = true;
		}
	}

	for (var i in deps) {
		if (comps) {
			if (parseInt(comps.pop(), 2) === 1) {
				console.log('\t* ' + i);
				addFiles(deps[i].src);
			} else {
				console.log('\t  ' + i);
			}
		} else {
			addFiles(deps[i].src);
		}
	}

	var files = [];

	for (var src in memo) {
		files.push('src/' + src);
	}

	return files;
}

exports.lint = function () {

	var files = getFiles();

	console.log('Checking for JS errors...');

	var errorsFound = lintFiles(files);

	if (errorsFound > 0) {
		console.log(errorsFound + ' error(s) found.\n');
		fail();
	} else {
		console.log('\tCheck passed');
	}
};

function getSizeDelta(newContent, oldContent) {
	if (!oldContent) {
		return 'new';
	}
	var newLen = newContent.replace(/\r\n?/g, '\n').length,
		oldLen = oldContent.replace(/\r\n?/g, '\n').length,
		delta = newLen - oldLen;

	return (delta >= 0 ? '+' : '') + delta;
}

function loadSilently(path) {
	try {
		return fs.readFileSync(path, 'utf8');
	} catch (e) {
		return null;
	}
}

function combineFiles(files) {
	var content = '';
	for (var i = 0, len = files.length; i < len; i++) {
		content += fs.readFileSync(files[i], 'utf8') + '\n\n';
	}
	return content;
}

exports.build = function (compsBase32, buildName) {

	var files = getFiles(compsBase32);

	console.log('Concatenating ' + files.length + ' files...');

	var copy = fs.readFileSync('src/copyright.js', 'utf8'),
	    intro = '(function (window, document, undefined) {',
	    outro = '}(this, document));',
	    newSrc = copy + intro + combineFiles(files) + outro,

	    pathPart = 'dist/leaflet' + (buildName ? '-' + buildName : ''),
	    srcPath = pathPart + '-src.js',

	    oldSrc = loadSilently(srcPath),
	    srcDelta = getSizeDelta(newSrc, oldSrc);

	console.log('\tUncompressed size: ' + newSrc.length + ' bytes (' + srcDelta + ')');

	if (newSrc === oldSrc) {
		console.log('\tNo changes');
	} else {
		fs.writeFileSync(srcPath, newSrc);
		console.log('\tSaved to ' + srcPath);
	}

	console.log('Compressing...');

	var path = pathPart + '.js',
	    oldCompressed = loadSilently(path),
	    newCompressed = copy + UglifyJS.minify(newSrc, {
	        warnings: true,
	        fromString: true
	    }).code,
	    delta = getSizeDelta(newCompressed, oldCompressed);

	console.log('\tCompressed size: ' + newCompressed.length + ' bytes (' + delta + ')');

	if (newCompressed === oldCompressed) {
		console.log('\tNo changes');
	} else {
		fs.writeFileSync(path, newCompressed);
		console.log('\tSaved to ' + path);
	}
};
<commit_msg>Update build/build.js<commit_after>var fs = require('fs'),
    jshint = require('jshint'),
    UglifyJS = require('uglify-js'),

    deps = require('./deps.js').deps,
    hintrc = require('./hintrc.js').config;

function lintFiles(files) {

	var errorsFound = 0,
	    i, j, len, len2, src, errors, e;

	for (i = 0, len = files.length; i < len; i++) {

		jshint.JSHINT(fs.readFileSync(files[i], 'utf8'), hintrc);
		errors = jshint.JSHINT.errors;

		for (j = 0, len2 = errors.length; j < len2; j++) {
			e = errors[j];
			console.log(files[i] + '\tline ' + e.line + '\tcol ' + e.character + '\t ' + e.reason);
		}

		errorsFound += len2;
	}

	return errorsFound;
}

function getFiles(compsBase32) {
	var memo = {},
	    comps;

	if (compsBase32) {
		comps = parseInt(compsBase32, 32).toString(2).split('');
		console.log('Managing dependencies...')
	}

	function addFiles(srcs) {
		for (var j = 0, len = srcs.length; j < len; j++) {
			memo[srcs[j]] = true;
		}
	}

	for (var i in deps) {
		if (comps) {
			if (parseInt(comps.pop(), 2) === 1) {
				console.log('\t* ' + i);
				addFiles(deps[i].src);
			} else {
				console.log('\t  ' + i);
			}
		} else {
			addFiles(deps[i].src);
		}
	}

	var files = [];

	for (var src in memo) {
		files.push('src/' + src);
	}

	return files;
}

exports.lint = function () {

	var files = getFiles();

	console.log('Checking for JS errors...');

	var errorsFound = lintFiles(files);

	if (errorsFound > 0) {
		console.log(errorsFound + ' error(s) found.\n');
		fail();
	} else {
		console.log('\tCheck passed');
	}
};

function getSizeDelta(newContent, oldContent) {
	if (!oldContent) {
		return 'new';
	}
	var newLen = newContent.replace(/\r\n?/g, '\n').length,
		oldLen = oldContent.replace(/\r\n?/g, '\n').length,
		delta = newLen - oldLen;

	return (delta >= 0 ? '+' : '') + delta;
}

function loadSilently(path) {
	try {
		return fs.readFileSync(path, 'utf8');
	} catch (e) {
		return null;
	}
}

function combineFiles(files) {
	var content = '';
	for (var i = 0, len = files.length; i < len; i++) {
		content += fs.readFileSync(files[i], 'utf8') + '\n\n';
	}
	return content;
}

exports.build = function (compsBase32, buildName) {

	var files = getFiles(compsBase32);

	console.log('Concatenating ' + files.length + ' files...');

	var copy = fs.readFileSync('src/copyright.js', 'utf8'),
	    intro = '(function (window, document, undefined) {',
	    outro = '}(this, document));',
	    newSrc = copy + intro + combineFiles(files) + outro,

	    pathPart = 'dist/leaflet' + (buildName ? '-' + buildName : ''),
	    srcPath = pathPart + '-src.js',

	    oldSrc = loadSilently(srcPath),
	    srcDelta = getSizeDelta(newSrc, oldSrc);

	console.log('\tUncompressed size: ' + newSrc.length + ' bytes (' + srcDelta + ')');

	if (newSrc === oldSrc) {
		console.log('\tNo changes');
	} else {
		fs.writeFileSync(srcPath, newSrc);
		console.log('\tSaved to ' + srcPath);
	}

	console.log('Compressing...');

	var path = pathPart + '.js',
	    oldCompressed = loadSilently(path),
	    newCompressed = copy + UglifyJS.minify(newSrc, {
	        warnings: true,
	        fromString: true
	    }).code,
	    delta = getSizeDelta(newCompressed, oldCompressed);

	console.log('\tCompressed size: ' + newCompressed.length + ' bytes (' + delta + ')');

	if (newCompressed === oldCompressed) {
		console.log('\tNo changes');
	} else {
		fs.writeFileSync(path, newCompressed);
		console.log('\tSaved to ' + path);
	}
};
<|endoftext|>


<commit_before>'use strict';

var CSScomb = require('csscomb');
var stream = require('stream');
var util = require('util');

module.exports = function (config) {
    config = CSScomb.getCustomConfig(config);
    var comb = new CSScomb(config);

    util.inherits(CSSLinter, stream);

    /**
     * Сохраняет в буфер входной поток данных и прогоняет полученный результат через csscomb.
     *
     * @type {Stream}
     */
    function CSSLinter(config) {
        if (!(this instanceof CSSLinter)) {
            return new CSSLinter(config);
        }

        this._buf = '';
        this._comb = comb;
    }

    CSSLinter.prototype.write = function (chunk) {
        this._buf += chunk;
    };

    CSSLinter.prototype.end = function (chunk) {
        if (chunk) {
            this.write(chunk);
        }

        this.processString();
    };

    /**
     * Processes a string.
     *
     * @param {String}   text
     * @param {Object}   options
     * @param {String}   options.context
     * @param {String}   options.filename
     * @param {String}   options.syntax
     * @return {Boolean}                  Valid string or not.
     */
    CSSLinter.prototype.processString = function (string, options) {
        string = string || this._buf;
        options = options || {};

        var combed = this._comb.processString(string, options);
        var isValid = string === combed;

        if (!isValid) {
            this.emit('data', options.filename ?
                util.format('%s: use csscomb for that\n', options.filename) : 'use csscomb for the specified data\n');
        }

        return isValid;
    };

    return CSSLinter;
};<commit_msg>if custom config not found, will use csscomb config as default<commit_after>'use strict';

var CSScomb = require('csscomb');
var stream = require('stream');
var util = require('util');

module.exports = function (config) {
    config = CSScomb.getCustomConfig(config);
    var comb = new CSScomb(config || 'csscomb');

    util.inherits(CSSLinter, stream);

    /**
     * Сохраняет в буфер входной поток данных и прогоняет полученный результат через csscomb.
     *
     * @type {Stream}
     */
    function CSSLinter(config) {
        if (!(this instanceof CSSLinter)) {
            return new CSSLinter(config);
        }

        this._buf = '';
        this._comb = comb;
    }

    CSSLinter.prototype.write = function (chunk) {
        this._buf += chunk;
    };

    CSSLinter.prototype.end = function (chunk) {
        if (chunk) {
            this.write(chunk);
        }

        this.processString();
    };

    /**
     * Processes a string.
     *
     * @param {String}   text
     * @param {Object}   options
     * @param {String}   options.context
     * @param {String}   options.filename
     * @param {String}   options.syntax
     * @return {Boolean}                  Valid string or not.
     */
    CSSLinter.prototype.processString = function (string, options) {
        string = string || this._buf;
        options = options || {};

        var combed = this._comb.processString(string, options);
        var isValid = string === combed;

        if (!isValid) {
            this.emit('data', options.filename ?
                util.format('%s: use csscomb for that\n', options.filename) : 'use csscomb for the specified data\n');
        }

        return isValid;
    };

    return CSSLinter;
};<|endoftext|>


<commit_before>/**
 * The datastore itself
 * TODO
 * Improve serialization (for types such as Dates, handle new lines in strings)
 * Queue inserts, removes and updates
 */

var fs = require('fs')
  , path = require('path')
  , customUtils = require('./customUtils')
  ;

/**
 * Create a new collection
 */
function Datastore (filename) {
  this.filename = filename;
  this.data = [];
}

/**
 * Load the database
 * For now this means pulling data out of the data file or creating it
 * if it doesn't exist
 * @param {Function} cb Optional callback, signature: err
 */
Datastore.prototype.loadDatabase = function (cb) {
  var callback = cb || function () {}
    , self = this
    ;

  customUtils.ensureDirectoryExists(path.dirname(self.filename), function (err) {
    fs.exists(self.filename, function (exists) {
      if (!exists) {
        self.data = [];
        fs.writeFile(self.filename, '', 'utf8', function (err) { return callback(err); });
      } else {
        fs.readFile(self.filename, 'utf8', function (err, rawData) {
          if (err) { return callback(err); }
          self.data = Datastore.treatRawData(rawData);
          return callback();
        });
      }
    });
  });
};

/**
 * From a database's raw data, return the corresponding
 * machine understandable collection
 */
Datastore.treatRawData = function (rawData) {
  var data = rawData.split('\n')
    , res = [];

  data.forEach(function (d) {
    var doc;

    try {
      doc = JSON.parse(d);
      res.push(doc);
    } catch (e) {
    }
  });

  return res;
};

/**
 * Insert a new document
 * @param {Function} cb Optional callback, signature: err, insertedDoc
 */
Datastore.prototype.insert = function (newDoc, cb) {
  var callback = cb || function () {}
    , self = this
    , persistableNewDoc
    ;

  try {
    newDoc._id = customUtils.uid(16);
    persistableNewDoc = JSON.stringify(newDoc);
  } catch (e) {
    return callback(e);
  }

  fs.appendFile(self.filename, persistableNewDoc + '\n', 'utf8', function (err) {
    if (err) { return callback(err); }

    var insertedDoc = JSON.parse(persistableNewDoc);
    self.data.push(insertedDoc);   // Make sure the doc is the same on the disk and in memory
                                                     // Some docs can't be stringified correctly
    return callback(null, insertedDoc);
  });
};

/**
 * Check whether object is matched by the given query
 */
Datastore.match = function (obj, query) {
  var match = true;

  Object.keys(query).forEach(function (k) {
    if (obj[k] !== query[k]) { match = false; }
  });

  return match;
};

/**
 * Find all documents matching the query
 * @param {Object} query MongoDB-style query
 */
Datastore.prototype.find = function (query, callback) {
  var res = []
    , self = this
    ;

  self.data.forEach(function (d) {
    if (Datastore.match(d, query)) {
      res.push(d);
    }
  });

  return callback(null, res);
};

/**
 * Find one document matching the query
 * @param {Object} query MongoDB-style query
 */
Datastore.prototype.findOne = function (query, callback) {
  var self = this
    , i
    ;

  for (i = 0; i < self.data.length; i += 1) {
    if (Datastore.match(self.data[i], query)) {
      return callback(null, self.data[i]);
    }
  }

  return callback(null, null);
};

/**
 * Persist the whole database
 * @param {Function} cb Optional callback, signature: err
 */
Datastore.prototype.persistWholeDatabase = function (cb) {
  var callback = cb || function () {}
    , self = this
    , newContents = '';

  self.data.forEach(function (d) {
    newContents += JSON.stringify(d) + '\n';
  });

  fs.writeFile(self.filename, newContents, 'utf8', callback);
};

var d = new Datastore('workspace/test.db');
d.loadDatabase(function (err) {
  console.log(d.data);
  d.data = [{ff: 'mec'}, {ee: 'test'}];

  d.persistWholeDatabase();

});

<commit_msg>Can persist the data we want, not just the cached version<commit_after>/**
 * The datastore itself
 * TODO
 * Improve serialization (for types such as Dates, handle new lines in strings)
 * Queue inserts, removes and updates
 */

var fs = require('fs')
  , path = require('path')
  , customUtils = require('./customUtils')
  ;

/**
 * Create a new collection
 */
function Datastore (filename) {
  this.filename = filename;
  this.data = [];
}

/**
 * Load the database
 * For now this means pulling data out of the data file or creating it
 * if it doesn't exist
 * @param {Function} cb Optional callback, signature: err
 */
Datastore.prototype.loadDatabase = function (cb) {
  var callback = cb || function () {}
    , self = this
    ;

  customUtils.ensureDirectoryExists(path.dirname(self.filename), function (err) {
    fs.exists(self.filename, function (exists) {
      if (!exists) {
        self.data = [];
        fs.writeFile(self.filename, '', 'utf8', function (err) { return callback(err); });
      } else {
        fs.readFile(self.filename, 'utf8', function (err, rawData) {
          if (err) { return callback(err); }
          self.data = Datastore.treatRawData(rawData);
          return callback();
        });
      }
    });
  });
};

/**
 * From a database's raw data, return the corresponding
 * machine understandable collection
 */
Datastore.treatRawData = function (rawData) {
  var data = rawData.split('\n')
    , res = [];

  data.forEach(function (d) {
    var doc;

    try {
      doc = JSON.parse(d);
      res.push(doc);
    } catch (e) {
    }
  });

  return res;
};

/**
 * Insert a new document
 * @param {Function} cb Optional callback, signature: err, insertedDoc
 */
Datastore.prototype.insert = function (newDoc, cb) {
  var callback = cb || function () {}
    , self = this
    , persistableNewDoc
    ;

  try {
    newDoc._id = customUtils.uid(16);
    persistableNewDoc = JSON.stringify(newDoc);
  } catch (e) {
    return callback(e);
  }

  fs.appendFile(self.filename, persistableNewDoc + '\n', 'utf8', function (err) {
    if (err) { return callback(err); }

    var insertedDoc = JSON.parse(persistableNewDoc);
    self.data.push(insertedDoc);   // Make sure the doc is the same on the disk and in memory
                                                     // Some docs can't be stringified correctly
    return callback(null, insertedDoc);
  });
};

/**
 * Check whether object is matched by the given query
 */
Datastore.match = function (obj, query) {
  var match = true;

  Object.keys(query).forEach(function (k) {
    if (obj[k] !== query[k]) { match = false; }
  });

  return match;
};

/**
 * Find all documents matching the query
 * @param {Object} query MongoDB-style query
 */
Datastore.prototype.find = function (query, callback) {
  var res = []
    , self = this
    ;

  self.data.forEach(function (d) {
    if (Datastore.match(d, query)) {
      res.push(d);
    }
  });

  return callback(null, res);
};

/**
 * Find one document matching the query
 * @param {Object} query MongoDB-style query
 */
Datastore.prototype.findOne = function (query, callback) {
  var self = this
    , i
    ;

  for (i = 0; i < self.data.length; i += 1) {
    if (Datastore.match(self.data[i], query)) {
      return callback(null, self.data[i]);
    }
  }

  return callback(null, null);
};

/**
 * Persist the whole database
 * @param {Array} data Optional data to persist. If not set, we use the database data
 * @param {Function} cb Optional callback, signature: err
 */
Datastore.prototype.persistWholeDatabase = function (data, cb) {
  var callback
    , self = this
    , newContents = '';

  if (!data) {
    data = self.data;
  }

  if (typeof data === 'function') {
    cb = data;
    data = self.data;
  }

  callback = cb || function () {};

  data.forEach(function (d) {
    newContents += JSON.stringify(d) + '\n';
  });

  fs.writeFile(self.filename, newContents, 'utf8', callback);
};

/**
 * Update the first doc matching query
 * @param {Object} query
 * @param {Object} newDoc Will replace the former doc
 * @param {Function} cb Optional callback, signature: err, replaced?, newDoc
 */
Datastore.prototype.updateOne = function (query, newDoc, cb) {
  var callback = cb || function () {};

};

var d = new Datastore('workspace/test.db');
d.loadDatabase(function (err) {
  console.log(d.data);
  d.data = [{ff: 'mec'}, {ee: 'test'}];

});

<|endoftext|>


<commit_before>const fs = require('fs-extra');
const buildPath = __dirname;
const projectPath = buildPath.split('/').slice(0, -1).join('/');
const packageJsonPath = projectPath + '/package.json';
const weeJsonPath = projectPath + '/wee.json';
const config = require(weeJsonPath);
const sourcePath = `${projectPath}/${config.paths.source}`;
const rootPath = `${projectPath}/${config.paths.root}`;
const modulesPath = projectPath + '/node_modules';

module.exports = {
	project: projectPath,
	packageJson: packageJsonPath,
	wee: weeJsonPath,
	temp: buildPath + '/temp',
	build: buildPath,
	root: rootPath,
	source: sourcePath,
	styles: `${sourcePath}/styles`,
	scripts: `${sourcePath}/scripts`,
	components: `${sourcePath}/components`,
	images: `${sourcePath}/images`,
	fonts: `${sourcePath}/fonts`,
	output: {
		styles: `${rootPath}/${config.paths.assets}/styles`,
		scripts: `${rootPath}/${config.paths.assets}/scripts`,
		images: `${rootPath}/${config.paths.assets}/images`,
		fonts: `${rootPath}/${config.paths.assets}/fonts`
	},
	nodeModules: modulesPath,
	weeCore: modulesPath + '/wee-core',

	/**
	 * Set paths on path object
	 *
	 * @param {string} key
	 * @param {string|Object} value
	 */
	set(key, value) {
		this[key] = value;
	}
};<commit_msg>Remove unused setter in paths build module<commit_after>const fs = require('fs-extra');
const buildPath = __dirname;
const projectPath = buildPath.split('/').slice(0, -1).join('/');
const packageJsonPath = projectPath + '/package.json';
const weeJsonPath = projectPath + '/wee.json';
const config = require(weeJsonPath);
const sourcePath = `${projectPath}/${config.paths.source}`;
const rootPath = `${projectPath}/${config.paths.root}`;
const modulesPath = projectPath + '/node_modules';

module.exports = {
	project: projectPath,
	packageJson: packageJsonPath,
	wee: weeJsonPath,
	temp: buildPath + '/temp',
	build: buildPath,
	root: rootPath,
	source: sourcePath,
	styles: `${sourcePath}/styles`,
	scripts: `${sourcePath}/scripts`,
	components: `${sourcePath}/components`,
	images: `${sourcePath}/images`,
	fonts: `${sourcePath}/fonts`,
	output: {
		styles: `${rootPath}/${config.paths.assets}/styles`,
		scripts: `${rootPath}/${config.paths.assets}/scripts`,
		images: `${rootPath}/${config.paths.assets}/images`,
		fonts: `${rootPath}/${config.paths.assets}/fonts`
	},
	nodeModules: modulesPath,
	weeCore: modulesPath + '/wee-core'
};<|endoftext|>


<commit_before>const fs = require('fs');
const path = require('path');
const Promise = require('promise');
const debug = require('debug')('winston:elasticsearch');
const retry = require('retry');

const BulkWriter = function BulkWriter(client, options) {
  this.client = client;
  this.options = options;
  this.interval = options.interval || 5000;
  this.waitForActiveShards = options.waitForActiveShards;
  this.pipeline = options.pipeline;

  this.bulk = []; // bulk to be flushed
  this.running = false;
  this.timer = false;
  debug('created', this);
};

BulkWriter.prototype.start = function start() {
  this.checkEsConnection();
  this.running = true;
  this.tick();
  debug('started');
};

BulkWriter.prototype.stop = function stop() {
  this.running = false;
  if (!this.timer) { return; }
  clearTimeout(this.timer);
  this.timer = null;
  debug('stopped');
};

BulkWriter.prototype.schedule = function schedule() {
  const thiz = this;
  this.timer = setTimeout(() => {
    thiz.tick();
  }, this.interval);
};

BulkWriter.prototype.tick = function tick() {
  debug('tick');
  const thiz = this;
  if (!this.running) { return; }
  this.flush()
    .then(() => {
      // Emulate finally with last .then()
    })
    .then(() => { // finally()
      thiz.schedule();
    });
};

BulkWriter.prototype.flush = function flush() {
  // write bulk to elasticsearch
  const thiz = this;
  if (this.bulk.length === 0) {
    debug('nothing to flush');
    return new Promise((resolve) => {
      return resolve();
    });
  }
  const bulk = this.bulk.concat();
  this.bulk = [];
  debug('going to write', bulk);
  return this.client.bulk({
    body: bulk,
    waitForActiveShards: this.waitForActiveShards,
    timeout: this.interval + 'ms',
    type: this.type
  }).then((res) => {
    if (res.errors && res.items) {
      res.items.forEach((item) => {
        if (item.index && item.index.error) {
          // eslint-disable-next-line no-console
          console.error('Elasticsearch index error', item.index.error);
        }
      });
    }
  }).catch((e) => { // prevent [DEP0018] DeprecationWarning
    // rollback this.bulk array
    thiz.bulk = bulk.concat(thiz.bulk);
    // eslint-disable-next-line no-console
    console.error(e);
    debug('error occrrued', e);
    this.stop();
    this.checkEsConnection();
  });
};

BulkWriter.prototype.append = function append(index, type, doc) {
  this.bulk.push({
    index: {
      _index: index, _type: type, pipeline: this.pipeline
    }
  });
  this.bulk.push(doc);
};

BulkWriter.prototype.checkEsConnection = function checkEsConnection() {
  const thiz = this;
  thiz.esConnection = false;

  const operation = retry.operation({
    forever: true,
    retries: 1,
    factor: 1,
    minTimeout: 1 * 1000,
    maxTimeout: 60 * 1000,
    randomize: false
  });
  return new Promise((fulfill, reject) => {
    operation.attempt((currentAttempt) => {
      debug('checking for connection');
      thiz.client.ping().then(
        (res) => {
          thiz.esConnection = true;
          // Ensure mapping template is existing if desired
          if (thiz.options.ensureMappingTemplate) {
            thiz.ensureMappingTemplate(fulfill, reject);
          } else {
            fulfill(true);
          }
          debug('starting bulk writer');
          thiz.running = true;
          thiz.tick();
        },
        (err) => {
          debug('checking for connection');
          if (operation.retry(err)) {
            return;
          }
          // thiz.esConnection = false;
          reject(new Error('Cannot connect to ES'));
        }
      );
    });
  });
};

BulkWriter.prototype.ensureMappingTemplate = function ensureMappingTemplate(fulfill, reject) {
  const thiz = this;
  // eslint-disable-next-line prefer-destructuring
  let mappingTemplate = thiz.options.mappingTemplate;
  if (mappingTemplate === null || typeof mappingTemplate === 'undefined') {
    const rawdata = fs.readFileSync(path.join(__dirname, 'index-template-mapping.json'));
    mappingTemplate = JSON.parse(rawdata);
  }
  const tmplCheckMessage = {
    name: 'template_' + thiz.options.indexPrefix
  };
  thiz.client.indices.getTemplate(tmplCheckMessage).then(
    (res) => {
      fulfill(res);
    },
    (res) => {
      if (res.status && res.status === 404) {
        const tmplMessage = {
          name: 'template_' + thiz.options.indexPrefix,
          create: true,
          body: mappingTemplate
        };
        thiz.client.indices.putTemplate(tmplMessage).then(
          (res1) => {
            fulfill(res1);
          },
          (err1) => {
            reject(err1);
          }
        );
      }
    }
  );
};

module.exports = BulkWriter;
<commit_msg>added possibility to use a function for the indexPrefix option to enable to log to multiple indices within one transport<commit_after>const fs = require('fs');
const path = require('path');
const Promise = require('promise');
const debug = require('debug')('winston:elasticsearch');
const retry = require('retry');

const BulkWriter = function BulkWriter(client, options) {
  this.client = client;
  this.options = options;
  this.interval = options.interval || 5000;
  this.waitForActiveShards = options.waitForActiveShards;
  this.pipeline = options.pipeline;

  this.bulk = []; // bulk to be flushed
  this.running = false;
  this.timer = false;
  debug('created', this);
};

BulkWriter.prototype.start = function start() {
  this.checkEsConnection();
  this.running = true;
  this.tick();
  debug('started');
};

BulkWriter.prototype.stop = function stop() {
  this.running = false;
  if (!this.timer) { return; }
  clearTimeout(this.timer);
  this.timer = null;
  debug('stopped');
};

BulkWriter.prototype.schedule = function schedule() {
  const thiz = this;
  this.timer = setTimeout(() => {
    thiz.tick();
  }, this.interval);
};

BulkWriter.prototype.tick = function tick() {
  debug('tick');
  const thiz = this;
  if (!this.running) { return; }
  this.flush()
    .then(() => {
      // Emulate finally with last .then()
    })
    .then(() => { // finally()
      thiz.schedule();
    });
};

BulkWriter.prototype.flush = function flush() {
  // write bulk to elasticsearch
  const thiz = this;
  if (this.bulk.length === 0) {
    debug('nothing to flush');
    return new Promise((resolve) => {
      return resolve();
    });
  }
  const bulk = this.bulk.concat();
  this.bulk = [];
  debug('going to write', bulk);
  return this.client.bulk({
    body: bulk,
    waitForActiveShards: this.waitForActiveShards,
    timeout: this.interval + 'ms',
    type: this.type
  }).then((res) => {
    if (res.errors && res.items) {
      res.items.forEach((item) => {
        if (item.index && item.index.error) {
          // eslint-disable-next-line no-console
          console.error('Elasticsearch index error', item.index.error);
        }
      });
    }
  }).catch((e) => { // prevent [DEP0018] DeprecationWarning
    // rollback this.bulk array
    thiz.bulk = bulk.concat(thiz.bulk);
    // eslint-disable-next-line no-console
    console.error(e);
    debug('error occrrued', e);
    this.stop();
    this.checkEsConnection();
  });
};

BulkWriter.prototype.append = function append(index, type, doc) {
  this.bulk.push({
    index: {
      _index: index, _type: type, pipeline: this.pipeline
    }
  });
  this.bulk.push(doc);
};

BulkWriter.prototype.checkEsConnection = function checkEsConnection() {
  const thiz = this;
  thiz.esConnection = false;

  const operation = retry.operation({
    forever: true,
    retries: 1,
    factor: 1,
    minTimeout: 1 * 1000,
    maxTimeout: 60 * 1000,
    randomize: false
  });
  return new Promise((fulfill, reject) => {
    operation.attempt((currentAttempt) => {
      debug('checking for connection');
      thiz.client.ping().then(
        (res) => {
          thiz.esConnection = true;
          // Ensure mapping template is existing if desired
          if (thiz.options.ensureMappingTemplate) {
            thiz.ensureMappingTemplate(fulfill, reject);
          } else {
            fulfill(true);
          }
          debug('starting bulk writer');
          thiz.running = true;
          thiz.tick();
        },
        (err) => {
          debug('checking for connection');
          if (operation.retry(err)) {
            return;
          }
          // thiz.esConnection = false;
          reject(new Error('Cannot connect to ES'));
        }
      );
    });
  });
};

BulkWriter.prototype.ensureMappingTemplate = function ensureMappingTemplate(fulfill, reject) {
  const thiz = this;
  // eslint-disable-next-line prefer-destructuring
  let mappingTemplate = thiz.options.mappingTemplate;
  if (mappingTemplate === null || typeof mappingTemplate === 'undefined') {
    const rawdata = fs.readFileSync(path.join(__dirname, 'index-template-mapping.json'));
    mappingTemplate = JSON.parse(rawdata);
  }
  const tmplCheckMessage = {
    name: 'template_' + (typeof thiz.options.indexPrefix === 'function' ? thiz.options.indexPrefix() : thiz.options.indexPrefix)
  };
  thiz.client.indices.getTemplate(tmplCheckMessage).then(
    (res) => {
      fulfill(res);
    },
    (res) => {
      if (res.status && res.status === 404) {
        const tmplMessage = {
          name: 'template_' + (typeof thiz.options.indexPrefix === 'function' ? thiz.options.indexPrefix() : thiz.options.indexPrefix),
          create: true,
          body: mappingTemplate
        };
        thiz.client.indices.putTemplate(tmplMessage).then(
          (res1) => {
            fulfill(res1);
          },
          (err1) => {
            reject(err1);
          }
        );
      }
    }
  );
};

module.exports = BulkWriter;
<|endoftext|>


<commit_before>
(function(){

  var addVotesMenuButton = function() {
    var name = window.SteemMoreInfo.Utils.getPageAccountName();
    if(!name){
      return;
    }
    console.log('Adding votes menu: ' + name);

    window.SteemMoreInfo.Utils.getUserTopMenusForAccountName(name, function(menus){
      var menu = menus.eq(0); // first menu
      var votesLi = menu.find('li.menu-votes-tab-li');
      if(!votesLi.length){
        votesLi = $('
Votes
');
        votesLi.find('a').on('click', function(e) {
          e.preventDefault();
          showVotesTab();
        });
        menu.append(votesLi);
      }
    });
  };

  var showVotesTab = function() {
    var container = $('.UserProfile');
    var divs = container.children();
    var realSelectedTab;
    var otherTabs = [];
    var votesTab;
    for (var i = divs.length - 1; i >= 0; i--) {
      var tab = $(divs[i]);
      if(!tab.hasClass('smi-tabs-div')){
        realSelectedTab = tab;
        otherTabs.push(tab);
        break;
      }else if(tab.hasClass('smi-votes-tab')){
        votesTab = tab;
      }else{
        otherTabs.push(tab);
      }
    }
    if(!votesTab){
      votesTab = $('

');
      container.append(votesTab);
    }
    votesTab.html('
\

\

\

\

\

\
                    Votes History\

\
                      <input type="radio" id="votes-history-type-incoming" name="votes-history-type" class="votes-history-type" value="0" checked/>\
                      Incoming\
                      <input type="radio" id="votes-history-type-outgoing" name="votes-history-type" class="votes-history-type" value="1" />\
                      Outgoing\
                      <input type="radio" id="votes-history-type-both" name="votes-history-type" class="votes-history-type" value="2" />\
                      Both\

\

\

\

\

\

\

\
          \

\

\

\
          \
          \
             <button>\
              Load more... \
            </button>\
          \

\

');
    otherTabs.forEach(function(otherTab){
      otherTab.hide();
    });
    $('.UserProfile__top-menu ul.menu li a').removeClass('active');
    $('li.menu-votes-tab-li a').addClass('active');
    votesTab.show();

    votesTab.find('.VotesTabLoadMore button').on('click', function(){
      var loadMore = $(this).parent();
      loadMore.hide();
      votesTab.find('.VotesTabLoading').show();
      var from = parseInt(loadMore.data('from'), 10);
      getVotes(votesTab, window.SteemMoreInfo.Utils.getPageAccountName(), from);
    });

    votesTab.find('.votes-history-type').on('change', function(e) {
      var v = $(e.target).val();
      var container = votesTab.find('.votes-container');
      if(v == 1){
        container.removeClass('show-incoming');
        container.addClass('show-outgoing');
      }else if(v == 2){
        container.addClass('show-incoming');
        container.addClass('show-outgoing');
      }else{
        container.addClass('show-incoming');
        container.removeClass('show-outgoing');
      }
    });

    getVotes(votesTab, window.SteemMoreInfo.Utils.getPageAccountName());
  };

  var onMenuItemClick = function() {
    var li = $(this).parent();
    if(!li.hasClass('smi-menu-li')){
      if(li.is('li') && li.find('a').attr('aria-haspopup') == 'true'){
        return;
      }
      var container = $('.UserProfile');
      var divs = container.children();
      var realSelectedTab;
      var otherTabs = [];
      for (var i = divs.length - 1; i >= 0; i--) {
        var tab = $(divs[i]);
        if(!tab.hasClass('smi-tabs-div')){
          realSelectedTab = tab;
          otherTabs.push(tab);
          break;
        }else{
          otherTabs.push(tab);
        }
      }
      otherTabs.forEach(function(otherTab){
        otherTab.hide();
      });
      if(realSelectedTab){
        realSelectedTab.show();
        $('.UserProfile__top-menu ul.menu li a').removeClass('active');
        if(li.is('li')){
          li.find('a').addClass('active');
        }
      }
    }
  };
  $('body').on('click', '.UserProfile__top-menu ul.menu li a', onMenuItemClick);
  $('body').on('click', '.dropdown-pane.is-open .VerticalMenu.menu.vertical li a', onMenuItemClick);
  $('body').on('click', '.UserProfile__stats span a', onMenuItemClick);

  var createVoteEl = function(tx) {
    var voter = tx.op[1].voter;
    var author = tx.op[1].author;
    var permlink = tx.op[1].permlink;
    var weight = Math.round(tx.op[1].weight / 100);
    var timestamp = tx.timestamp + 'Z';
    var date = new Date(timestamp);
    var mdate = moment(date);
    var timeagoTitle = mdate.format();
    var timeago = mdate.fromNow();

    var verb = weight >= 0 ? 'upvoted' : 'downvoted';
    var voteType = '';

    var pageAccountName = window.SteemMoreInfo.Utils.getPageAccountName();
    if(author === pageAccountName && voter !== pageAccountName){
      voteType = 'vote-incoming';
    }else if(author !== pageAccountName && voter === pageAccountName) {
      voteType = 'vote-outgoing';
    }

    var el = $('
\
      \
        \
      \

\
        \
          ' + voter + '\
          ' + verb + ' \
          @' + author + '/' + permlink + '\
        \
        ' + timeago + '\
        \
          Weight: ' + weight + '%\
          \
        \

\

');

    return el;
  };

  var getVotes = function(votesTab, name, fromOrNull) {
    window.SteemMoreInfo.Utils.getUserHistory(name, fromOrNull, function(err, result){
      if(!result){
        return; //TODO: error
      }
      var uniqueCommentTargets = {};
      for (var i = result.length - 1; i >= 0; i--) {
        var tx = result[i][1];
        if(tx && tx.op && tx.op[0] === 'vote'){
          var voter = tx.op[1].voter;
          var author = tx.op[1].author;
          var permlink = tx.op[1].permlink;
          var uniqueId = author + '__' + permlink;
          uniqueCommentTargets[uniqueId] = uniqueCommentTargets[uniqueId] || {
            author: author,
            permlink: permlink,
            voteEls: {}
          };
          var voteEl = createVoteEl(tx);
          uniqueCommentTargets[uniqueId].voteEls[voter] = uniqueCommentTargets[uniqueId].voteEls[voter] || [];
          uniqueCommentTargets[uniqueId].voteEls[voter].push(voteEl);
          votesTab.find('.votes-container').append(voteEl);
        }
      }
      votesTab.find('.VotesTabLoading').hide();
      votesTab.find('.VotesTab').show();
      if(result[0][0] > 0){
        var from = result[0][0] - 1;
        var loadMore = votesTab.find('.VotesTabLoadMore');
        loadMore.data('from', from);
        loadMore.show();
      }
      _.each(uniqueCommentTargets, function(target){
        window.SteemMoreInfo.Utils.getContent(target.author, target.permlink, function(err, result){
          if(!result){
            return;
          }
          _.each(result.active_votes, function(vote) {
            var voter = vote.voter;
            var voteDollar = vote.voteDollar;
            if(voteDollar){
              var voteEls = target.voteEls[voter];
              _.each(voteEls, function(voteEl) {
                voteEl.find('.vote-dollar').text(' ≈ ' + voteDollar + '$');
              });
            }
          });
        });
      });
    });
  };

  window.SteemMoreInfo.Events.addEventListener(window, 'page-account-name', function() {
    addVotesMenuButton();
  });

  addVotesMenuButton();

})();
<commit_msg>Votes tab hash<commit_after>
(function(){

  var addVotesMenuButton = function() {
    var name = window.SteemMoreInfo.Utils.getPageAccountName();
    if(!name){
      return;
    }
    console.log('Adding votes menu: ' + name);

    window.SteemMoreInfo.Utils.getUserTopMenusForAccountName(name, function(menus){
      var menu = menus.eq(0); // first menu
      var votesLi = menu.find('li.menu-votes-tab-li');
      if(!votesLi.length){
        votesLi = $('
Votes
');
        votesLi.find('a').on('click', function(e) {
          e.preventDefault();
          showVotesTab();
        });
        menu.append(votesLi);
      }

      if(window.location.hash === '#votes'){
        showVotesTab();
      }

    });
  };

  var showVotesTab = function() {
    var container = $('.UserProfile');
    var divs = container.children();
    var realSelectedTab;
    var otherTabs = [];
    var votesTab;
    for (var i = divs.length - 1; i >= 0; i--) {
      var tab = $(divs[i]);
      if(!tab.hasClass('smi-tabs-div')){
        realSelectedTab = tab;
        otherTabs.push(tab);
        break;
      }else if(tab.hasClass('smi-votes-tab')){
        votesTab = tab;
      }else{
        otherTabs.push(tab);
      }
    }
    if(!votesTab){
      votesTab = $('

');
      container.append(votesTab);
    }
    votesTab.html('
\

\

\

\

\

\
                    Votes History\

\
                      <input type="radio" id="votes-history-type-incoming" name="votes-history-type" class="votes-history-type" value="0" checked/>\
                      Incoming\
                      <input type="radio" id="votes-history-type-outgoing" name="votes-history-type" class="votes-history-type" value="1" />\
                      Outgoing\
                      <input type="radio" id="votes-history-type-both" name="votes-history-type" class="votes-history-type" value="2" />\
                      Both\

\

\

\

\

\

\

\
          \

\

\

\
          \
          \
             <button>\
              Load more... \
            </button>\
          \

\

');
    otherTabs.forEach(function(otherTab){
      otherTab.hide();
    });
    $('.UserProfile__top-menu ul.menu li a').removeClass('active');
    $('li.menu-votes-tab-li a').addClass('active');
    votesTab.show();
    window.location.hash = '#votes';

    votesTab.find('.VotesTabLoadMore button').on('click', function(){
      var loadMore = $(this).parent();
      loadMore.hide();
      votesTab.find('.VotesTabLoading').show();
      var from = parseInt(loadMore.data('from'), 10);
      getVotes(votesTab, window.SteemMoreInfo.Utils.getPageAccountName(), from);
    });

    votesTab.find('.votes-history-type').on('change', function(e) {
      var v = $(e.target).val();
      var container = votesTab.find('.votes-container');
      if(v == 1){
        container.removeClass('show-incoming');
        container.addClass('show-outgoing');
      }else if(v == 2){
        container.addClass('show-incoming');
        container.addClass('show-outgoing');
      }else{
        container.addClass('show-incoming');
        container.removeClass('show-outgoing');
      }
    });

    getVotes(votesTab, window.SteemMoreInfo.Utils.getPageAccountName());
  };

  var onMenuItemClick = function() {
    var li = $(this).parent();
    if(!li.hasClass('smi-menu-li')){
      if(li.is('li') && li.find('a').attr('aria-haspopup') == 'true'){
        return;
      }
      var container = $('.UserProfile');
      var divs = container.children();
      var realSelectedTab;
      var otherTabs = [];
      for (var i = divs.length - 1; i >= 0; i--) {
        var tab = $(divs[i]);
        if(!tab.hasClass('smi-tabs-div')){
          realSelectedTab = tab;
          otherTabs.push(tab);
          break;
        }else{
          otherTabs.push(tab);
        }
      }
      otherTabs.forEach(function(otherTab){
        otherTab.hide();
      });
      if(realSelectedTab){
        realSelectedTab.show();
        $('.UserProfile__top-menu ul.menu li a').removeClass('active');
        if(li.is('li')){
          li.find('a').addClass('active');
        }
      }
    }
  };
  $('body').on('click', '.UserProfile__top-menu ul.menu li a', onMenuItemClick);
  $('body').on('click', '.dropdown-pane.is-open .VerticalMenu.menu.vertical li a', onMenuItemClick);
  $('body').on('click', '.UserProfile__stats span a', onMenuItemClick);

  var createVoteEl = function(tx) {
    var voter = tx.op[1].voter;
    var author = tx.op[1].author;
    var permlink = tx.op[1].permlink;
    var weight = Math.round(tx.op[1].weight / 100);
    var timestamp = tx.timestamp + 'Z';
    var date = new Date(timestamp);
    var mdate = moment(date);
    var timeagoTitle = mdate.format();
    var timeago = mdate.fromNow();

    var verb = weight >= 0 ? 'upvoted' : 'downvoted';
    var voteType = '';

    var pageAccountName = window.SteemMoreInfo.Utils.getPageAccountName();
    if(author === pageAccountName && voter !== pageAccountName){
      voteType = 'vote-incoming';
    }else if(author !== pageAccountName && voter === pageAccountName) {
      voteType = 'vote-outgoing';
    }

    var el = $('
\
      \
        \
      \

\
        \
          ' + voter + '\
          ' + verb + ' \
          @' + author + '/' + permlink + '\
        \
        ' + timeago + '\
        \
          Weight: ' + weight + '%\
          \
        \

\

');

    return el;
  };

  var getVotes = function(votesTab, name, fromOrNull) {
    window.SteemMoreInfo.Utils.getUserHistory(name, fromOrNull, function(err, result){
      if(!result){
        return; //TODO: error
      }
      var uniqueCommentTargets = {};
      for (var i = result.length - 1; i >= 0; i--) {
        var tx = result[i][1];
        if(tx && tx.op && tx.op[0] === 'vote'){
          var voter = tx.op[1].voter;
          var author = tx.op[1].author;
          var permlink = tx.op[1].permlink;
          var uniqueId = author + '__' + permlink;
          uniqueCommentTargets[uniqueId] = uniqueCommentTargets[uniqueId] || {
            author: author,
            permlink: permlink,
            voteEls: {}
          };
          var voteEl = createVoteEl(tx);
          uniqueCommentTargets[uniqueId].voteEls[voter] = uniqueCommentTargets[uniqueId].voteEls[voter] || [];
          uniqueCommentTargets[uniqueId].voteEls[voter].push(voteEl);
          votesTab.find('.votes-container').append(voteEl);
        }
      }
      votesTab.find('.VotesTabLoading').hide();
      votesTab.find('.VotesTab').show();
      if(result[0][0] > 0){
        var from = result[0][0] - 1;
        var loadMore = votesTab.find('.VotesTabLoadMore');
        loadMore.data('from', from);
        loadMore.show();
      }
      _.each(uniqueCommentTargets, function(target){
        window.SteemMoreInfo.Utils.getContent(target.author, target.permlink, function(err, result){
          if(!result){
            return;
          }
          _.each(result.active_votes, function(vote) {
            var voter = vote.voter;
            var voteDollar = vote.voteDollar;
            if(voteDollar){
              var voteEls = target.voteEls[voter];
              _.each(voteEls, function(voteEl) {
                voteEl.find('.vote-dollar').text(' ≈ ' + voteDollar + '$');
              });
            }
          });
        });
      });
    });
  };

  // $('.Header__top.header .Header__userpic > a').on('click', function() {
  //   var userHref = $(this).attr('href');
  //   setTimeout(function() {
  //     if($('body > div > div > div.dropdown-pane ul.menu li.smi-votes-tab-li').length){
  //       return;
  //     }

  //     var recentRepliesLi = $('body > div > div > div.dropdown-pane ul.menu li').filter(function(){
  //       var href = $(this).find('a').attr('href');
  //       return href && href.indexOf('recent-replies') !== -1;
  //     });
  //     var li = $('
\
  //       \
  //         \
  //           <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><title>reply</title><path d="M14 24.238v7.762l-12-12 12-12v7.932c13.961 0.327 13.362-9.493 9.808-15.932 8.772 9.482 6.909 24.674-9.808 24.238z"></path></svg>\
  //         \
  //         Votes\
  //       \
  //
');

  //     recentRepliesLi.after(li)
  //   }, 250);
  // });

  window.SteemMoreInfo.Events.addEventListener(window, 'page-account-name', function() {
    addVotesMenuButton();
  });

  addVotesMenuButton();

})();
<|endoftext|>


<commit_before>import moment from 'moment';
import { logger } from './config';

class WakeLight {

  /**
   * adds a Johnny Five led to the wakelight
   * @method addLED
   * @param [Object] led  a Johnny Five LED
   * @see http://johnny-five.io/examples/led/
   */
  addLED(led) {
    logger.debug('adding led');
    this.led = led;
    // Blink every half second
    led.blink(500);
    setTimeout(() => {
      led.stop();
      led.off();
    }, 5000);
  }

  /**
   * add or update wakelight alarms. calling this method
   * will restart the alarms timer and immediately check
   * if the alarms should be active
   * @param {Object}  An object where each key contains an alarm
   */
  addAlarms(alarms) {
    logger.debug('updating alarms');
    this.alarms = alarms;
  }

  /**
   * Enable the alarm
   */
  enableAlarm() {
    logger.debug('Alarm enabled!');
    this.alarmActive = true;
    if (this.led) {
      this.led.on();
    }
  }

  /**
   * Disable the alarm
   */
  disableAlarm() {
    logger.debug('Alarm disabled!');
    this.alarmActive = false;
    if (this.led) {
      this.led.off();
    }
  }

  /**
   * Check an array of alarms to see if any of them are alarmActive
   * @param [Array] alarms an array of alarm objects
   */
  checkAlarms(time) {
    if (!this.alarms) {
      throw Error('alarms not set =/');
    }
    Object.keys(this.alarms).forEach(key => {
      const alarm = this.alarms[key];
      const { hour: alarmHour,
        minute: alarmMinute,
        duration: alarmDuration } = alarm;

      // get current time reference
      const now = time || moment();

      // create time reference for the alarm enable
      const alarmEnable = moment()
        .hour(alarmHour)
        .minute(alarmMinute);

      // create time reference for the alarm disable
      const alarmDisable = moment()
        .hour(alarmHour)
        .minute(alarmMinute)
        .add(alarmDuration, 'minutes');

      if (now.isAfter(alarmEnable) && now.isBefore(alarmDisable)) {
        this.enableAlarm();
      } else {
        this.disableAlarm();
      }
    });
  }

  run() {
    logger.silly('running wake light');
    if (!this.alarms) {
      logger.error('alarms not set');
      return;
    }
    this.checkAlarms();

    // set an interval to check the time and see if the alarm should be activated
    this.timer = setInterval(() => {
      // get current time reference
      this.checkAlarms();
    }, 60000);
  }

  stop() {
    this.disableAlarm();
    clearTimeout(this.timer);
  }

  restart() {
    this.stop();
    this.run();
  }
}

export default WakeLight;
<commit_msg>trying without led.stop method<commit_after>import moment from 'moment';
import { logger } from './config';

class WakeLight {

  /**
   * adds a Johnny Five led to the wakelight
   * @method addLED
   * @param [Object] led  a Johnny Five LED
   * @see http://johnny-five.io/examples/led/
   */
  addLED(led) {
    logger.debug('adding led');
    this.led = led;
    // Blink every half second
    this.led.on();
    setTimeout(() => {
      this.led.off();
    }, 5000);
  }

  /**
   * add or update wakelight alarms. calling this method
   * will restart the alarms timer and immediately check
   * if the alarms should be active
   * @param {Object}  An object where each key contains an alarm
   */
  addAlarms(alarms) {
    logger.debug('updating alarms');
    this.alarms = alarms;
  }

  /**
   * Enable the alarm
   */
  enableAlarm() {
    logger.debug('Alarm enabled!');
    this.alarmActive = true;
    if (this.led) {
      this.led.on();
    }
  }

  /**
   * Disable the alarm
   */
  disableAlarm() {
    logger.debug('Alarm disabled!');
    this.alarmActive = false;
    if (this.led) {
      this.led.off();
    }
  }

  /**
   * Check an array of alarms to see if any of them are alarmActive
   * @param [Array] alarms an array of alarm objects
   */
  checkAlarms(time) {
    if (!this.alarms) {
      throw Error('alarms not set =/');
    }
    Object.keys(this.alarms).forEach(key => {
      const alarm = this.alarms[key];
      const { hour: alarmHour,
        minute: alarmMinute,
        duration: alarmDuration } = alarm;

      // get current time reference
      const now = time || moment();

      // create time reference for the alarm enable
      const alarmEnable = moment()
        .hour(alarmHour)
        .minute(alarmMinute);

      // create time reference for the alarm disable
      const alarmDisable = moment()
        .hour(alarmHour)
        .minute(alarmMinute)
        .add(alarmDuration, 'minutes');

      if (now.isAfter(alarmEnable) && now.isBefore(alarmDisable)) {
        this.enableAlarm();
      } else {
        this.disableAlarm();
      }
    });
  }

  run() {
    logger.silly('running wake light');
    if (!this.alarms) {
      logger.error('alarms not set');
      return;
    }
    this.checkAlarms();

    // set an interval to check the time and see if the alarm should be activated
    this.timer = setInterval(() => {
      // get current time reference
      this.checkAlarms();
    }, 60000);
  }

  stop() {
    this.disableAlarm();
    clearTimeout(this.timer);
  }

  restart() {
    this.stop();
    this.run();
  }
}

export default WakeLight;
<|endoftext|>