<commit_before>// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

var $JSON = global.JSON;

function Revive(holder, name, reviver) {
  var val = holder[name];
  if (IS_OBJECT(val)) {
    if (IS_ARRAY(val)) {
      var length = val.length;
      for (var i = 0; i < length; i++) {
        var newElement = Revive(val, $String(i), reviver);
        val[i] = newElement;
      }
    } else {
      for (var p in val) {
        if (%_CallFunction(val, p, ObjectHasOwnProperty)) {
          var newElement = Revive(val, p, reviver);
          if (IS_UNDEFINED(newElement)) {
            delete val[p];
          } else {
            val[p] = newElement;
          }
        }
      }
    }
  }
  return %_CallFunction(holder, name, val, reviver);
}

function JSONParse(text, reviver) {
  var unfiltered = %ParseJson(TO_STRING_INLINE(text));
  if (IS_SPEC_FUNCTION(reviver)) {
    return Revive({'': unfiltered}, '', reviver);
  } else {
    return unfiltered;
  }
}

function SerializeArray(value, replacer, stack, indent, gap) {
  if (!%PushIfAbsent(stack, value)) {
    throw MakeTypeError('circular_structure', $Array());
  }
  var stepback = indent;
  indent += gap;
  var partial = new InternalArray();
  var len = value.length;
  for (var i = 0; i < len; i++) {
    var strP = JSONSerialize($String(i), value, replacer, stack,
                             indent, gap);
    if (IS_UNDEFINED(strP)) {
      strP = "null";
    }
    partial.push(strP);
  }
  var final;
  if (gap == "") {
    final = "[" + partial.join(",") + "]";
  } else if (partial.length > 0) {
    var separator = ",\n" + indent;
    final = "[\n" + indent + partial.join(separator) + "\n" +
        stepback + "]";
  } else {
    final = "[]";
  }
  stack.pop();
  return final;
}

function SerializeObject(value, replacer, stack, indent, gap) {
  if (!%PushIfAbsent(stack, value)) {
    throw MakeTypeError('circular_structure', $Array());
  }
  var stepback = indent;
  indent += gap;
  var partial = new InternalArray();
  if (IS_ARRAY(replacer)) {
    var length = replacer.length;
    for (var i = 0; i < length; i++) {
      if (%_CallFunction(replacer, i, ObjectHasOwnProperty)) {
        var p = replacer[i];
        var strP = JSONSerialize(p, value, replacer, stack, indent, gap);
        if (!IS_UNDEFINED(strP)) {
          var member = %QuoteJSONString(p) + ":";
          if (gap != "") member += " ";
          member += strP;
          partial.push(member);
        }
      }
    }
  } else {
    for (var p in value) {
      if (%_CallFunction(value, p, ObjectHasOwnProperty)) {
        var strP = JSONSerialize(p, value, replacer, stack, indent, gap);
        if (!IS_UNDEFINED(strP)) {
          var member = %QuoteJSONString(p) + ":";
          if (gap != "") member += " ";
          member += strP;
          partial.push(member);
        }
      }
    }
  }
  var final;
  if (gap == "") {
    final = "{" + partial.join(",") + "}";
  } else if (partial.length > 0) {
    var separator = ",\n" + indent;
    final = "{\n" + indent + partial.join(separator) + "\n" +
        stepback + "}";
  } else {
    final = "{}";
  }
  stack.pop();
  return final;
}

function JSONSerialize(key, holder, replacer, stack, indent, gap) {
  var value = holder[key];
  if (IS_SPEC_OBJECT(value)) {
    var toJSON = value.toJSON;
    if (IS_SPEC_FUNCTION(toJSON)) {
      value = %_CallFunction(value, key, toJSON);
    }
  }
  if (IS_SPEC_FUNCTION(replacer)) {
    value = %_CallFunction(holder, key, value, replacer);
  }
  if (IS_STRING(value)) {
    return %QuoteJSONString(value);
  } else if (IS_NUMBER(value)) {
    return JSON_NUMBER_TO_STRING(value);
  } else if (IS_BOOLEAN(value)) {
    return value ? "true" : "false";
  } else if (IS_NULL(value)) {
    return "null";
  } else if (IS_SPEC_OBJECT(value) && !(typeof value == "function")) {
    // Non-callable object. If it's a primitive wrapper, it must be unwrapped.
    if (IS_ARRAY(value)) {
      return SerializeArray(value, replacer, stack, indent, gap);
    } else if (IS_NUMBER_WRAPPER(value)) {
      value = ToNumber(value);
      return JSON_NUMBER_TO_STRING(value);
    } else if (IS_STRING_WRAPPER(value)) {
      return %QuoteJSONString(ToString(value));
    } else if (IS_BOOLEAN_WRAPPER(value)) {
      return %_ValueOf(value) ? "true" : "false";
    } else {
      return SerializeObject(value, replacer, stack, indent, gap);
    }
  }
  // Undefined or a callable object.
  return void 0;
}

function BasicSerializeArray(value, stack, builder) {
  var len = value.length;
  if (len == 0) {
    builder.push("[]");
    return;
  }
  if (!%PushIfAbsent(stack, value)) {
    throw MakeTypeError('circular_structure', $Array());
  }
  builder.push("[");
  var val = value[0];
  if (IS_STRING(val)) {
    // First entry is a string. Remaining entries are likely to be strings too.
    var array_string = %QuoteJSONStringArray(value);
    if (!IS_UNDEFINED(array_string)) {
      // array_string also includes bracket characters so we are done.
      builder[builder.length - 1] = array_string;
      stack.pop();
      return;
    } else {
      builder.push(%QuoteJSONString(val));
      for (var i = 1; i < len; i++) {
        val = value[i];
        if (IS_STRING(val)) {
          builder.push(%QuoteJSONStringComma(val));
        } else {
          builder.push(",");
          var before = builder.length;
          BasicJSONSerialize(i, val, stack, builder);
          if (before == builder.length) builder[before - 1] = ",null";
        }
      }
    }
  } else if (IS_NUMBER(val)) {
    // First entry is a number. Remaining entries are likely to be numbers too.
    builder.push(JSON_NUMBER_TO_STRING(val));
    for (var i = 1; i < len; i++) {
      builder.push(",");
      val = value[i];
      if (IS_NUMBER(val)) {
        builder.push(JSON_NUMBER_TO_STRING(val));
      } else {
        var before = builder.length;
        BasicJSONSerialize(i, val, stack, builder);
        if (before == builder.length) builder[before - 1] = ",null";
      }
    }
  } else {
    var before = builder.length;
    BasicJSONSerialize(0, val, stack, builder);
    if (before == builder.length) builder.push("null");
    for (var i = 1; i < len; i++) {
      builder.push(",");
      before = builder.length;
      BasicJSONSerialize(i, value[i], stack, builder);
      if (before == builder.length) builder[before - 1] = ",null";
    }
  }
  stack.pop();
  builder.push("]");
}

function BasicSerializeObject(value, stack, builder) {
  if (!%PushIfAbsent(stack, value)) {
    throw MakeTypeError('circular_structure', $Array());
  }
  builder.push("{");
  var first = true;
  for (var p in value) {
    if (%HasLocalProperty(value, p)) {
      if (!first) {
        builder.push(%QuoteJSONStringComma(p));
      } else {
        builder.push(%QuoteJSONString(p));
      }
      builder.push(":");
      var before = builder.length;
      BasicJSONSerialize(p, value[p], stack, builder);
      if (before == builder.length) {
        builder.pop();
        builder.pop();
      } else {
        first = false;
      }
    }
  }
  stack.pop();
  builder.push("}");
}

function BasicJSONSerialize(key, value, stack, builder) {
  if (IS_SPEC_OBJECT(value)) {
    var toJSON = value.toJSON;
    if (IS_SPEC_FUNCTION(toJSON)) {
      value = %_CallFunction(value, ToString(key), toJSON);
    }
  }
  if (IS_STRING(value)) {
    builder.push(value !== "" ? %QuoteJSONString(value) : '""');
  } else if (IS_NUMBER(value)) {
    builder.push(JSON_NUMBER_TO_STRING(value));
  } else if (IS_BOOLEAN(value)) {
    builder.push(value ? "true" : "false");
  } else if (IS_NULL(value)) {
    builder.push("null");
  } else if (IS_SPEC_OBJECT(value) && !(typeof value == "function")) {
    // Value is a non-callable object.
    // Unwrap value if necessary
    if (IS_NUMBER_WRAPPER(value)) {
      value = ToNumber(value);
      builder.push(JSON_NUMBER_TO_STRING(value));
    } else if (IS_STRING_WRAPPER(value)) {
      builder.push(%QuoteJSONString(ToString(value)));
    } else if (IS_BOOLEAN_WRAPPER(value)) {
      builder.push(%_ValueOf(value) ? "true" : "false");
    } else if (IS_ARRAY(value)) {
      BasicSerializeArray(value, stack, builder);
    } else {
      BasicSerializeObject(value, stack, builder);
    }
  }
}

function JSONStringify(value, replacer, space) {
  if (%_ArgumentsLength() == 1) {
    var builder = new InternalArray();
    BasicJSONSerialize('', value, new InternalArray(), builder);
    if (builder.length == 0) return;
    var result = %_FastAsciiArrayJoin(builder, "");
    if (!IS_UNDEFINED(result)) return result;
    return %StringBuilderConcat(builder, builder.length, "");
  }
  if (IS_OBJECT(space)) {
    // Unwrap 'space' if it is wrapped
    if (IS_NUMBER_WRAPPER(space)) {
      space = ToNumber(space);
    } else if (IS_STRING_WRAPPER(space)) {
      space = ToString(space);
    }
  }
  var gap;
  if (IS_NUMBER(space)) {
    space = MathMax(0, MathMin(ToInteger(space), 10));
    gap = SubString("          ", 0, space);
  } else if (IS_STRING(space)) {
    if (space.length > 10) {
      gap = SubString(space, 0, 10);
    } else {
      gap = space;
    }
  } else {
    gap = "";
  }
  return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap);
}

function SetUpJSON() {
  %CheckIsBootstrapping();
  InstallFunctions($JSON, DONT_ENUM, $Array(
    "parse", JSONParse,
    "stringify", JSONStringify
  ));
}

SetUpJSON();
<commit_msg>Directly use %ObjectKeys in json stringify.<commit_after>// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

var $JSON = global.JSON;

function Revive(holder, name, reviver) {
  var val = holder[name];
  if (IS_OBJECT(val)) {
    if (IS_ARRAY(val)) {
      var length = val.length;
      for (var i = 0; i < length; i++) {
        var newElement = Revive(val, $String(i), reviver);
        val[i] = newElement;
      }
    } else {
      for (var p in val) {
        if (%_CallFunction(val, p, ObjectHasOwnProperty)) {
          var newElement = Revive(val, p, reviver);
          if (IS_UNDEFINED(newElement)) {
            delete val[p];
          } else {
            val[p] = newElement;
          }
        }
      }
    }
  }
  return %_CallFunction(holder, name, val, reviver);
}

function JSONParse(text, reviver) {
  var unfiltered = %ParseJson(TO_STRING_INLINE(text));
  if (IS_SPEC_FUNCTION(reviver)) {
    return Revive({'': unfiltered}, '', reviver);
  } else {
    return unfiltered;
  }
}

function SerializeArray(value, replacer, stack, indent, gap) {
  if (!%PushIfAbsent(stack, value)) {
    throw MakeTypeError('circular_structure', $Array());
  }
  var stepback = indent;
  indent += gap;
  var partial = new InternalArray();
  var len = value.length;
  for (var i = 0; i < len; i++) {
    var strP = JSONSerialize($String(i), value, replacer, stack,
                             indent, gap);
    if (IS_UNDEFINED(strP)) {
      strP = "null";
    }
    partial.push(strP);
  }
  var final;
  if (gap == "") {
    final = "[" + partial.join(",") + "]";
  } else if (partial.length > 0) {
    var separator = ",\n" + indent;
    final = "[\n" + indent + partial.join(separator) + "\n" +
        stepback + "]";
  } else {
    final = "[]";
  }
  stack.pop();
  return final;
}

function SerializeObject(value, replacer, stack, indent, gap) {
  if (!%PushIfAbsent(stack, value)) {
    throw MakeTypeError('circular_structure', $Array());
  }
  var stepback = indent;
  indent += gap;
  var partial = new InternalArray();
  if (IS_ARRAY(replacer)) {
    var length = replacer.length;
    for (var i = 0; i < length; i++) {
      if (%_CallFunction(replacer, i, ObjectHasOwnProperty)) {
        var p = replacer[i];
        var strP = JSONSerialize(p, value, replacer, stack, indent, gap);
        if (!IS_UNDEFINED(strP)) {
          var member = %QuoteJSONString(p) + ":";
          if (gap != "") member += " ";
          member += strP;
          partial.push(member);
        }
      }
    }
  } else {
    for (var p in value) {
      if (%_CallFunction(value, p, ObjectHasOwnProperty)) {
        var strP = JSONSerialize(p, value, replacer, stack, indent, gap);
        if (!IS_UNDEFINED(strP)) {
          var member = %QuoteJSONString(p) + ":";
          if (gap != "") member += " ";
          member += strP;
          partial.push(member);
        }
      }
    }
  }
  var final;
  if (gap == "") {
    final = "{" + partial.join(",") + "}";
  } else if (partial.length > 0) {
    var separator = ",\n" + indent;
    final = "{\n" + indent + partial.join(separator) + "\n" +
        stepback + "}";
  } else {
    final = "{}";
  }
  stack.pop();
  return final;
}

function JSONSerialize(key, holder, replacer, stack, indent, gap) {
  var value = holder[key];
  if (IS_SPEC_OBJECT(value)) {
    var toJSON = value.toJSON;
    if (IS_SPEC_FUNCTION(toJSON)) {
      value = %_CallFunction(value, key, toJSON);
    }
  }
  if (IS_SPEC_FUNCTION(replacer)) {
    value = %_CallFunction(holder, key, value, replacer);
  }
  if (IS_STRING(value)) {
    return %QuoteJSONString(value);
  } else if (IS_NUMBER(value)) {
    return JSON_NUMBER_TO_STRING(value);
  } else if (IS_BOOLEAN(value)) {
    return value ? "true" : "false";
  } else if (IS_NULL(value)) {
    return "null";
  } else if (IS_SPEC_OBJECT(value) && !(typeof value == "function")) {
    // Non-callable object. If it's a primitive wrapper, it must be unwrapped.
    if (IS_ARRAY(value)) {
      return SerializeArray(value, replacer, stack, indent, gap);
    } else if (IS_NUMBER_WRAPPER(value)) {
      value = ToNumber(value);
      return JSON_NUMBER_TO_STRING(value);
    } else if (IS_STRING_WRAPPER(value)) {
      return %QuoteJSONString(ToString(value));
    } else if (IS_BOOLEAN_WRAPPER(value)) {
      return %_ValueOf(value) ? "true" : "false";
    } else {
      return SerializeObject(value, replacer, stack, indent, gap);
    }
  }
  // Undefined or a callable object.
  return void 0;
}

function BasicSerializeArray(value, stack, builder) {
  var len = value.length;
  if (len == 0) {
    builder.push("[]");
    return;
  }
  if (!%PushIfAbsent(stack, value)) {
    throw MakeTypeError('circular_structure', $Array());
  }
  builder.push("[");
  var val = value[0];
  if (IS_STRING(val)) {
    // First entry is a string. Remaining entries are likely to be strings too.
    var array_string = %QuoteJSONStringArray(value);
    if (!IS_UNDEFINED(array_string)) {
      // array_string also includes bracket characters so we are done.
      builder[builder.length - 1] = array_string;
      stack.pop();
      return;
    } else {
      builder.push(%QuoteJSONString(val));
      for (var i = 1; i < len; i++) {
        val = value[i];
        if (IS_STRING(val)) {
          builder.push(%QuoteJSONStringComma(val));
        } else {
          builder.push(",");
          var before = builder.length;
          BasicJSONSerialize(i, val, stack, builder);
          if (before == builder.length) builder[before - 1] = ",null";
        }
      }
    }
  } else if (IS_NUMBER(val)) {
    // First entry is a number. Remaining entries are likely to be numbers too.
    builder.push(JSON_NUMBER_TO_STRING(val));
    for (var i = 1; i < len; i++) {
      builder.push(",");
      val = value[i];
      if (IS_NUMBER(val)) {
        builder.push(JSON_NUMBER_TO_STRING(val));
      } else {
        var before = builder.length;
        BasicJSONSerialize(i, val, stack, builder);
        if (before == builder.length) builder[before - 1] = ",null";
      }
    }
  } else {
    var before = builder.length;
    BasicJSONSerialize(0, val, stack, builder);
    if (before == builder.length) builder.push("null");
    for (var i = 1; i < len; i++) {
      builder.push(",");
      before = builder.length;
      BasicJSONSerialize(i, value[i], stack, builder);
      if (before == builder.length) builder[before - 1] = ",null";
    }
  }
  stack.pop();
  builder.push("]");
}

function BasicSerializeObject(value, stack, builder) {
  if (!%PushIfAbsent(stack, value)) {
    throw MakeTypeError('circular_structure', $Array());
  }
  builder.push("{");
  var first = true;
  var keys = %ObjectKeys(value);
  var len = keys.length;
  for (var i = 0; i < len; i++) {
    var p = keys[i];
    if (!first) {
      builder.push(%QuoteJSONStringComma(p));
    } else {
      builder.push(%QuoteJSONString(p));
    }
    builder.push(":");
    var before = builder.length;
    BasicJSONSerialize(p, value[p], stack, builder);
    if (before == builder.length) {
      builder.pop();
      builder.pop();
    } else {
      first = false;
    }
  }
  stack.pop();
  builder.push("}");
}

function BasicJSONSerialize(key, value, stack, builder) {
  if (IS_SPEC_OBJECT(value)) {
    var toJSON = value.toJSON;
    if (IS_SPEC_FUNCTION(toJSON)) {
      value = %_CallFunction(value, ToString(key), toJSON);
    }
  }
  if (IS_STRING(value)) {
    builder.push(value !== "" ? %QuoteJSONString(value) : '""');
  } else if (IS_NUMBER(value)) {
    builder.push(JSON_NUMBER_TO_STRING(value));
  } else if (IS_BOOLEAN(value)) {
    builder.push(value ? "true" : "false");
  } else if (IS_NULL(value)) {
    builder.push("null");
  } else if (IS_SPEC_OBJECT(value) && !(typeof value == "function")) {
    // Value is a non-callable object.
    // Unwrap value if necessary
    if (IS_NUMBER_WRAPPER(value)) {
      value = ToNumber(value);
      builder.push(JSON_NUMBER_TO_STRING(value));
    } else if (IS_STRING_WRAPPER(value)) {
      builder.push(%QuoteJSONString(ToString(value)));
    } else if (IS_BOOLEAN_WRAPPER(value)) {
      builder.push(%_ValueOf(value) ? "true" : "false");
    } else if (IS_ARRAY(value)) {
      BasicSerializeArray(value, stack, builder);
    } else {
      BasicSerializeObject(value, stack, builder);
    }
  }
}

function JSONStringify(value, replacer, space) {
  if (%_ArgumentsLength() == 1) {
    var builder = new InternalArray();
    BasicJSONSerialize('', value, new InternalArray(), builder);
    if (builder.length == 0) return;
    var result = %_FastAsciiArrayJoin(builder, "");
    if (!IS_UNDEFINED(result)) return result;
    return %StringBuilderConcat(builder, builder.length, "");
  }
  if (IS_OBJECT(space)) {
    // Unwrap 'space' if it is wrapped
    if (IS_NUMBER_WRAPPER(space)) {
      space = ToNumber(space);
    } else if (IS_STRING_WRAPPER(space)) {
      space = ToString(space);
    }
  }
  var gap;
  if (IS_NUMBER(space)) {
    space = MathMax(0, MathMin(ToInteger(space), 10));
    gap = SubString("          ", 0, space);
  } else if (IS_STRING(space)) {
    if (space.length > 10) {
      gap = SubString(space, 0, 10);
    } else {
      gap = space;
    }
  } else {
    gap = "";
  }
  return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap);
}

function SetUpJSON() {
  %CheckIsBootstrapping();
  InstallFunctions($JSON, DONT_ENUM, $Array(
    "parse", JSONParse,
    "stringify", JSONStringify
  ));
}

SetUpJSON();
<|endoftext|>


<commit_before>import {
  serialize as encode,
  deserialize as decode
} from '../common/pickler';

import { buffered } from '../common/iterators';
import { rationalLinearAlgebra as ops } from '../arithmetic/types';
import * as pg from './periodic';
import * as ps from './symmetries';

class Basis {
  constructor() {
    this.dim = null;
    this.vectors = [];
    this.matrix = null;
  }

  add(vecIn) {
    const n = this.vectors.length;

    if (this.dim == null) {
      this.dim = vecIn.length;
      this.matrix = ops.identityMatrix(this.dim);
    }

    if (this.dim > n && ops.rank(this.vectors.concat([vecIn])) > n) {
      this.vectors.push(vecIn);

      const basis = this.vectors.slice();
      for (const vec of ops.identityMatrix(this.dim)) {
        if (ops.rank(basis.concat([vec])) > basis.length)
          basis.push(vec);
      }
      this.matrix = ops.inverse(basis);
    }
    return ops.times(vecIn, this.matrix);
  }
};

const placeOrderedTraversal = function*(graph, start, transform) {
  const pos = pg.barycentricPlacement(graph);
  const seen = {};
  const queue = [start];

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

    if (!seen[v]) {
      seen[v] = true;

      const incidences = pg.incidences(graph)[v].map(e => [
        e, ops.times(pg.edgeVector(e, pos), transform)
      ]);
      incidences.sort(([ea, da], [eb, db]) => ops.cmp(da, db));

      for (const [e] of incidences) {
        queue.push(e.tail);
        yield e;
      }
    }
  }
};

const adjustedTraversal = function*(traversal) {
  const shifts = {};
  const vertexMapping = {};
  const edgeMapping = {};
  const basis = new Basis();
  let nrVerticesMapped = 0;

  for (const edge of traversal) {
    if (vertexMapping[edge.head] == null) {
      vertexMapping[edge.head] = ++nrVerticesMapped;
      shifts[edge.head] = ops.times(0, edge.shift);
    }
    const v = vertexMapping[edge.head];

    if (vertexMapping[edge.tail] == null) {
      vertexMapping[edge.tail] = ++nrVerticesMapped;
      shifts[edge.tail] = ops.plus(edge.shift, shifts[edge.head]);
    }
    const w = vertexMapping[edge.tail];

    if (v <= w) {
      const d = ops.minus(shifts[edge.head], shifts[edge.tail]);
      const shift = basis.add(ops.plus(edge.shift, d));

      if (v < w || ops.sgn(shift) < 0) {
        edgeMapping[encode(edge)] = encode(pg.makeEdge(v, w, shift));
        yield [v, w, shift];
      }
    }
  }

  return { vertexMapping, edgeMapping, basisChange: basis.matrix };
};

const findPivot = (A, col, startRow) => {
  const pairs = A
    .map((row, i) => [ops.abs(row[col]), i])
    .filter(([x, i]) => i >= startRow && ops.sgn(x));

  if (pairs.length)
    return pairs.reduce((acc, val) => ops.lt(val[0], acc[0]) ? val : acc)[1];
};

const triangulate = matrix => {
  const A = matrix.map(v => v.slice());
  const [nrows, ncols] = ops.shape(A);

  let row = 0;

  for (let col = 0; col < ncols; ++col) {
    while (true) {
      const pivotRow = findPivot(A, col, row);
      if (pivotRow == null)
        break;

      if (pivotRow != row)
        [A[row], A[pivotRow]] = [A[pivotRow], A[row]];

      if (ops.sgn(A[row]) < 0)
        A[row] = ops.negative(A[row]);

      for (let i = row + 1; i < nrows; ++i) {
        if (ops.ne(0, A[i][col])) {
          const f = ops.idiv(A[i][col], A[row][col]);
          A[i] = ops.minus(A[i], ops.times(f, A[row]));
        }
      }

      if (A.every((v, i) => i <= row || ops.eq(0, v[col]))) {
        row += 1;
        break;
      }
    }
  }

  return A.slice(0, ncols);
};

const transformEdges = (edges, M) => edges.map(([head, tail, shift]) => {
  const newShift = ops.times(shift, M);

  if (newShift.some(x => !ops.isInteger(x)))
    throw new Error("panic: produced non-integer shift");

  if (head == tail && ops.sgn(newShift) > 0)
    return [head, tail, ops.negative(newShift)];
  else
    return [head, tail, newShift];
});

const transformEdgeMapping = (mapping, M) => {
  const result = {};

  for (const [key, val] of Object.entries(mapping)) {
    const edge = decode(val);
    const shift = ops.times(edge.shift, M);
    result[key] = encode(pg.makeEdge(edge.head, edge.tail, shift));
  }

  return result;
};

export const invariantWithMapping = graph => {
  const pos = pg.barycentricPlacement(graph);
  const sym = ps.symmetries(graph);

  const _cmpSteps = ([headA, tailA, shiftA], [headB, tailB, shiftB]) =>
    (headA - headB) || (tailA - tailB) || ops.cmp(shiftA, shiftB);

  let best = null;

  const bases = sym.representativeEdgeLists;

  for (const edgeList of bases) {
    const transform = ops.inverse(edgeList.map(e => pg.edgeVector(e, pos)));
    const base = placeOrderedTraversal(graph, edgeList[0].head, transform);
    const trav = buffered(adjustedTraversal(base));

    if (best == null)
      best = trav;
    else {
      for (let i = 0; ; ++i) {
        const next = trav.get(i);
        if (next == null)
          break;

        const d = _cmpSteps(next, best.get(i));
        if (d < 0)
          best = trav;
        else if (d > 0)
          break;
      }
    }
  }

  const { generated, returned } = best.result();
  const shifts = generated.map(([head, tail, shift]) => shift);
  const M = ops.inverse(triangulate(shifts));

  const edges = transformEdges(generated, M).sort(_cmpSteps);
  const basisChange = ops.times(returned.basisChange, M);
  const vertexMapping = returned.vertexMapping;
  const edgeMapping = transformEdgeMapping(returned.edgeMapping, M);

  return { edges, vertexMapping, edgeMapping, basisChange };
};

export const invariant = graph => invariantWithMapping(graph).edges;

export const systreKey = graph => {
  const seq = [graph.dim];

  for (const [from, to, shift] of invariant(graph)) {
    seq.push(from);
    seq.push(to);
    for (const x of shift)
      seq.push(x);
  }

  return seq.join(' ');
};

export const keyVersion = '1.0';

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

  const test = g => {
    const inv = invariantWithMapping(g);

    for (const e of g.edges)
      console.log(`${e}`);
    console.log();

    for (const k of Object.keys(inv.vertexMapping))
      console.log(`${k} => ${inv.vertexMapping[k]}`);
    console.log();

    for (const k of Object.keys(inv.edgeMapping))
      console.log(`(${decode(k)}) => (${decode(inv.edgeMapping[k])})`);
    console.log();

    console.log(inv.basisChange);
    console.log();

    for (const e of inv.edges)
      console.log(`${pg.makeEdge(...e)}`);
    console.log();

    console.log();
  };

  test(pg.makeGraph(
    [ [ 1, 2, [ 0, 0, 0 ] ],
      [ 1, 2, [ 1, 0, 0 ] ],
      [ 1, 2, [ 0, 1, 0 ] ],
      [ 1, 2, [ 0, 0, 1 ] ] ]
  ));

  test(pg.makeGraph(
    [ [ 1, 2, [ 0, 0 ] ],
      [ 1, 2, [ 1, 0 ] ],
      [ 2, 3, [ 0, 0 ] ],
      [ 2, 3, [ 0, 1 ] ],
      [ 1, 3, [ 0, 0 ] ],
      [ 1, 3, [ 1, 1 ] ] ]
  ));
}
<commit_msg>invariant: skip unnecessary serialization; add a test example<commit_after>import {
  serialize as encode,
  deserialize as decode
} from '../common/pickler';

import { buffered } from '../common/iterators';
import { rationalLinearAlgebra as ops } from '../arithmetic/types';
import * as pg from './periodic';
import * as ps from './symmetries';

class Basis {
  constructor() {
    this.dim = null;
    this.vectors = [];
    this.matrix = null;
  }

  add(vecIn) {
    const n = this.vectors.length;

    if (this.dim == null) {
      this.dim = vecIn.length;
      this.matrix = ops.identityMatrix(this.dim);
    }

    if (this.dim > n && ops.rank(this.vectors.concat([vecIn])) > n) {
      this.vectors.push(vecIn);

      const basis = this.vectors.slice();
      for (const vec of ops.identityMatrix(this.dim)) {
        if (ops.rank(basis.concat([vec])) > basis.length)
          basis.push(vec);
      }
      this.matrix = ops.inverse(basis);
    }
    return ops.times(vecIn, this.matrix);
  }
};

const placeOrderedTraversal = function*(graph, start, transform) {
  const pos = pg.barycentricPlacement(graph);
  const seen = {};
  const queue = [start];

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

    if (!seen[v]) {
      seen[v] = true;

      const incidences = pg.incidences(graph)[v].map(e => [
        e, ops.times(pg.edgeVector(e, pos), transform)
      ]);
      incidences.sort(([ea, da], [eb, db]) => ops.cmp(da, db));

      for (const [e] of incidences) {
        queue.push(e.tail);
        yield e;
      }
    }
  }
};

const adjustedTraversal = function*(traversal) {
  const shifts = {};
  const vertexMapping = {};
  const edgeMapping = {};
  const basis = new Basis();
  let nrVerticesMapped = 0;

  for (const edge of traversal) {
    if (vertexMapping[edge.head] == null) {
      vertexMapping[edge.head] = ++nrVerticesMapped;
      shifts[edge.head] = ops.times(0, edge.shift);
    }
    const v = vertexMapping[edge.head];

    if (vertexMapping[edge.tail] == null) {
      vertexMapping[edge.tail] = ++nrVerticesMapped;
      shifts[edge.tail] = ops.plus(edge.shift, shifts[edge.head]);
    }
    const w = vertexMapping[edge.tail];

    if (v <= w) {
      const d = ops.minus(shifts[edge.head], shifts[edge.tail]);
      const shift = basis.add(ops.plus(edge.shift, d));

      if (v < w || ops.sgn(shift) < 0) {
        edgeMapping[encode(edge)] = pg.makeEdge(v, w, shift);
        yield [v, w, shift];
      }
    }
  }

  return { vertexMapping, edgeMapping, basisChange: basis.matrix };
};

const findPivot = (A, col, startRow) => {
  const pairs = A
    .map((row, i) => [ops.abs(row[col]), i])
    .filter(([x, i]) => i >= startRow && ops.sgn(x));

  if (pairs.length)
    return pairs.reduce((acc, val) => ops.lt(val[0], acc[0]) ? val : acc)[1];
};

const triangulate = matrix => {
  const A = matrix.map(v => v.slice());
  const [nrows, ncols] = ops.shape(A);

  let row = 0;

  for (let col = 0; col < ncols; ++col) {
    while (true) {
      const pivotRow = findPivot(A, col, row);
      if (pivotRow == null)
        break;

      if (pivotRow != row)
        [A[row], A[pivotRow]] = [A[pivotRow], A[row]];

      if (ops.sgn(A[row]) < 0)
        A[row] = ops.negative(A[row]);

      for (let i = row + 1; i < nrows; ++i) {
        if (ops.ne(0, A[i][col])) {
          const f = ops.idiv(A[i][col], A[row][col]);
          A[i] = ops.minus(A[i], ops.times(f, A[row]));
        }
      }

      if (A.every((v, i) => i <= row || ops.eq(0, v[col]))) {
        row += 1;
        break;
      }
    }
  }

  return A.slice(0, ncols);
};

const transformEdges = (edges, M) => edges.map(([head, tail, shift]) => {
  const newShift = ops.times(shift, M);

  if (newShift.some(x => !ops.isInteger(x)))
    throw new Error("panic: produced non-integer shift");

  if (head == tail && ops.sgn(newShift) > 0)
    return [head, tail, ops.negative(newShift)];
  else
    return [head, tail, newShift];
});

const transformEdgeMapping = (mapping, M) => {
  const result = {};

  for (const [key, edge] of Object.entries(mapping)) {
    const shift = ops.times(edge.shift, M);
    result[key] = pg.makeEdge(edge.head, edge.tail, shift);
  }

  return result;
};

export const invariantWithMapping = graph => {
  const pos = pg.barycentricPlacement(graph);
  const sym = ps.symmetries(graph);

  const _cmpSteps = ([headA, tailA, shiftA], [headB, tailB, shiftB]) =>
    (headA - headB) || (tailA - tailB) || ops.cmp(shiftA, shiftB);

  let best = null;

  const bases = sym.representativeEdgeLists;

  for (const edgeList of bases) {
    const transform = ops.inverse(edgeList.map(e => pg.edgeVector(e, pos)));
    const base = placeOrderedTraversal(graph, edgeList[0].head, transform);
    const trav = buffered(adjustedTraversal(base));

    if (best == null)
      best = trav;
    else {
      for (let i = 0; ; ++i) {
        const next = trav.get(i);
        if (next == null)
          break;

        const d = _cmpSteps(next, best.get(i));
        if (d < 0)
          best = trav;
        else if (d > 0)
          break;
      }
    }
  }

  const { generated, returned } = best.result();
  const shifts = generated.map(([head, tail, shift]) => shift);
  const M = ops.inverse(triangulate(shifts));

  const edges = transformEdges(generated, M).sort(_cmpSteps);
  const basisChange = ops.times(returned.basisChange, M);
  const vertexMapping = returned.vertexMapping;
  const edgeMapping = transformEdgeMapping(returned.edgeMapping, M);

  return { edges, vertexMapping, edgeMapping, basisChange };
};

export const invariant = graph => invariantWithMapping(graph).edges;

export const systreKey = graph => {
  const seq = [graph.dim];

  for (const [from, to, shift] of invariant(graph)) {
    seq.push(from);
    seq.push(to);
    for (const x of shift)
      seq.push(x);
  }

  return seq.join(' ');
};

export const keyVersion = '1.0';

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

  const test = g => {
    const inv = invariantWithMapping(g);

    for (const e of g.edges)
      console.log(`${e}`);
    console.log();

    for (const k of Object.keys(inv.vertexMapping))
      console.log(`${k} => ${inv.vertexMapping[k]}`);
    console.log();

    for (const k of Object.keys(inv.edgeMapping))
      console.log(`(${decode(k)}) => (${inv.edgeMapping[k]})`);
    console.log();

    console.log(inv.basisChange);
    console.log();

    for (const e of inv.edges)
      console.log(`${pg.makeEdge(...e)}`);
    console.log();

    console.log();
  };

  test(pg.makeGraph(
    [ [ 1, 2, [ 0, 0, 0 ] ],
      [ 1, 2, [ 1, 0, 0 ] ],
      [ 1, 2, [ 0, 1, 0 ] ],
      [ 1, 2, [ 0, 0, 1 ] ] ]
  ));

  test(pg.makeGraph(
    [ [ 1, 2, [ 0, 0 ] ],
      [ 1, 2, [ 1, 0 ] ],
      [ 2, 3, [ 0, 0 ] ],
      [ 2, 3, [ 0, 1 ] ],
      [ 1, 3, [ 0, 0 ] ],
      [ 1, 3, [ 1, 1 ] ] ]
  ));

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


<commit_before>import { VNode, emptyINode, emptyAttrMap, attrEntries, ivalue, finalize, push } from './pvnode';
import { children } from "./access";
import { ensureRoot } from "./construct";
import { array2str, str2array, convert } from "./l3";

function process(entry, parent, key) {
	var cc = entry.constructor;
	if (cc === Object) {
		if(entry.$children){
			let name = entry.$name;
			let node = emptyINode(1, name,emptyAttrMap(entry.$attrs));
			parent = push(parent, [name, node]);
			for (var i = 0, l = entry.$children.length; i<l; i++) {
				process(entry.$children[i], node, i);
			}
			node = finalize(node);
		} else {
			let name = key !== undefined ? key : "#object";
			let node = emptyINode(6, name);
			parent = push(parent, [name, node]);
			let keys = Object.keys(entry);
			for (let k of keys) {
				process(entry[k], node, k);
			}
			node = finalize(node);
		}
	} else if (cc === Array) {
		let name = key !== undefined ? key : "#array";
		let node = emptyINode(5, name);
		parent = push(parent, [name, node]);
		for (let i = 0, len = entry.length; i < len; i++) {
			process(entry[i], node, i);
		}
		node = finalize(node);
	} else {
		let node = ivalue(entry.constructor === String ? 3 : 12, key, entry);
		parent = push(parent,[key, node]);
	}
}

export function fromJS(json) {
	var doc = emptyINode(9, "#document", emptyAttrMap());
	process(json, doc);
	return finalize(doc);
}

export function toJS(doc) {
	function process(node, out, key) {
		let type = node.type,
		    name = node.name,
			inode = node.inode;
		if (type == 1) {
			let attrs = {}, arr = [];
			for (let attr of attrEntries(inode)) {
				attrs[attr[0]] = attr[1];
			}
			for (let n of children(node)) {
				process(n, arr, n.name);
			}
			let e = { $name: name, $attrs: attrs, $children: arr };
			if (out === undefined) {
				out = e;
			} else {
				out[key] = e;
			}
		} else if (type == 3 || type == 12) {
			if (out === undefined) {
				out = node.value;
			} else {
				out[key] = node.value;
			}
		} else if (type == 5) {
			let arr = [];
			for (let n of children(node)) {
				process(n, arr, n.indexInParent);
			}
			if (out === undefined) {
				out = arr;
			} else {
				out[key] = arr;
			}
		} else if (type == 6) {
			var obj = {};
			for (let n of children(node)) {
				process(n, obj, n.name);
			}
			if (out === undefined) {
				out = obj;
			} else {
				out[key] = obj;
			}
		}
		return out;
	}
	// discard DOC for now
	return process(ensureRoot(doc));
}

function step(node,depth){
	return {
		__isStep:true,
		node:node,
		depth:depth
	};
}

function getType(val){
	let cc = val.constructor;
	return cc == Array ? 5 : cc == Object ? 6 : cc == String ? 3 : 12;
}

export function iter(json,fn){
	var parents = [], pindexes = [], indexInParent = 0;
	function next(node, skipFirst) {
		var type = node[0],
			depth = node[1],
			entry = node[3];
		if (type == 6) {
			let ks = Object.keys(entry);
			var klen = ks.length;
			// try first entry
			if(klen > 0 && !skipFirst){
				//console.log("found first",ks[0], depth);
				pindexes[depth] = indexInParent;
				parents[depth] = entry;
				indexInParent = 0;
				depth++;
				pindexes[depth] = 0;
				let key = ks[0];
				let val = entry[key];
				return [getType(val),depth,key,val];
			} else {
				pindexes[depth] = ++indexInParent;
				if(indexInParent < klen){
					//console.log("found next",indexInParent,ks[indexInParent]);
					// continue with next
					let key = ks[indexInParent];
					let val = entry[key];
					return [getType(val),depth,key,val];
				} else {
					// go up
					depth--;
					if(depth == 1) return;
					indexInParent = pindexes[depth];
					let parent = parents[depth-1];
					return next([getType(parent),depth,0,parent],true);
				}
			}
		} else if (type == 5) {
			let len = entry.length;
			// try first entry
			if(len > 0 && !skipFirst){
				//console.log("found first",entry[0], depth);
				pindexes[depth] = indexInParent;
				parents[depth] = entry;
				indexInParent = 0;
				depth++;
				pindexes[depth] = 0;
				let key = 0;
				let val = entry[key];
				return [getType(val),depth,key,val];
			} else {
				pindexes[depth] = ++indexInParent;
				if(indexInParent < len){
					//console.log("found next",indexInParent);
					// continue with next
					let key = indexInParent;
					let val = entry[key];
					return [getType(val),depth,key,val];
				} else {
					// go up
					depth--;
					if(depth == 1) return;
					indexInParent = pindexes[depth];
					//console.log("go up a",depth,indexInParent);
					let parent = parents[depth-1];
					return next([getType(parent),depth,0,parent],true);
				}
			}
		} else {
			indexInParent = pindexes[depth];
			let parent = parents[depth-1];
			return next([getType(parent),depth,0,parent],true);
		}
	}
	// this is not the doc, so depth starts at 1
	var node = [getType(json),1,"#",json];
	fn(node);
	do {
		node = next(node);
		if(node) fn(node);
	} while(node);
}

const isObject = function(parent){
	return !!parent && parent.constructor === Object;
};

export function fromL3(l3) {
	var names = {},
	    parents = [],
		n = 0;
	const process = function(entry){
		var type = entry[0],
			depth = entry[1];
		if(type == 15){
			n++;
			names[n] = array2str(entry,1);
		} else {
			let parent = parents[depth - 1];
			let isObj = isObject(parent);
			let index = isObj ? 3 : 2;
			let key = isObj ? names[entry[2]] : null;
			//console.log("key",key, depth, parents[depth]);
			var val;
			if(type == 3){
				val = array2str(entry,index);
			} else if(type == 12){
				val = convert(array2str(entry,index));
			} else if(type == 5){
				val = [];
				parents[depth] = val;
			} else if(type == 6){
				val = {};
				parents[depth] = val;
			}
			if (parent !== undefined) {
				if(isObj){
					parent[key] = val;
				} else {
					push(parent,val);
				}
			}
		}
	};
	var entry = [];
	for (var i = 0, l = l3.length; i < l; i++) {
		if(l3[i] === 0){
			process(entry);
			entry = [];
		} else {
			entry.push(l3[i]);
		}
	}
    process(entry);
	return parents[1];
}

export function toL3(doc){
	var out = [],
	    names = {},
	    i = 1;
	const process = function (node) {
		let type = node[0],
		    depth = node[1],
		    name = node[2],
			val = node[3];
		// detect if parent is object/map, otherwise use integer
		var nameIndex;
		if (typeof name === "string") {
			if(!names[name]) {
				names[name] = i;
				i++;
				out.push(0);
				out.push(15);
				str2array(name,out);
			}
			nameIndex = names[name];
		}
		out.push(0);
		out.push(type);
		out.push(depth);
		if(nameIndex) out.push(nameIndex);
		if (type == 3) {
			str2array(val,out);
		} else if(type == 12) {
			str2array(val+"",out);
		}
	};
	iter(doc, process);
	out.shift();
	return out;
}
<commit_msg>use persist<commit_after>import { VNode, emptyINode, emptyAttrMap, attrEntries, ivalue, finalize, push } from './persist';
import { children } from "./access";
import { ensureRoot } from "./construct";
import { array2str, str2array, convert } from "./l3";

function process(entry, parent, key) {
	var cc = entry.constructor;
	if (cc === Object) {
		if(entry.$children){
			let name = entry.$name;
			let node = emptyINode(1, name,emptyAttrMap(entry.$attrs));
			parent = push(parent, [name, node]);
			for (var i = 0, l = entry.$children.length; i<l; i++) {
				process(entry.$children[i], node, i);
			}
			node = finalize(node);
		} else {
			let name = key !== undefined ? key : "#object";
			let node = emptyINode(6, name);
			parent = push(parent, [name, node]);
			let keys = Object.keys(entry);
			for (let k of keys) {
				process(entry[k], node, k);
			}
			node = finalize(node);
		}
	} else if (cc === Array) {
		let name = key !== undefined ? key : "#array";
		let node = emptyINode(5, name);
		parent = push(parent, [name, node]);
		for (let i = 0, len = entry.length; i < len; i++) {
			process(entry[i], node, i);
		}
		node = finalize(node);
	} else {
		let node = ivalue(entry.constructor === String ? 3 : 12, key, entry);
		parent = push(parent,[key, node]);
	}
}

export function fromJS(json) {
	var doc = emptyINode(9, "#document", emptyAttrMap());
	process(json, doc);
	return finalize(doc);
}

export function toJS(doc) {
	function process(node, out, key) {
		let type = node.type,
		    name = node.name,
			inode = node.inode;
		if (type == 1) {
			let attrs = {}, arr = [];
			for (let attr of attrEntries(inode)) {
				attrs[attr[0]] = attr[1];
			}
			for (let n of children(node)) {
				process(n, arr, n.name);
			}
			let e = { $name: name, $attrs: attrs, $children: arr };
			if (out === undefined) {
				out = e;
			} else {
				out[key] = e;
			}
		} else if (type == 3 || type == 12) {
			if (out === undefined) {
				out = node.value;
			} else {
				out[key] = node.value;
			}
		} else if (type == 5) {
			let arr = [];
			for (let n of children(node)) {
				process(n, arr, n.indexInParent);
			}
			if (out === undefined) {
				out = arr;
			} else {
				out[key] = arr;
			}
		} else if (type == 6) {
			var obj = {};
			for (let n of children(node)) {
				process(n, obj, n.name);
			}
			if (out === undefined) {
				out = obj;
			} else {
				out[key] = obj;
			}
		}
		return out;
	}
	// discard DOC for now
	return process(ensureRoot(doc));
}

function step(node,depth){
	return {
		__isStep:true,
		node:node,
		depth:depth
	};
}

function getType(val){
	let cc = val.constructor;
	return cc == Array ? 5 : cc == Object ? 6 : cc == String ? 3 : 12;
}

export function iter(json,fn){
	var parents = [], pindexes = [], indexInParent = 0;
	function next(node, skipFirst) {
		var type = node[0],
			depth = node[1],
			entry = node[3];
		if (type == 6) {
			let ks = Object.keys(entry);
			var klen = ks.length;
			// try first entry
			if(klen > 0 && !skipFirst){
				//console.log("found first",ks[0], depth);
				pindexes[depth] = indexInParent;
				parents[depth] = entry;
				indexInParent = 0;
				depth++;
				pindexes[depth] = 0;
				let key = ks[0];
				let val = entry[key];
				return [getType(val),depth,key,val];
			} else {
				pindexes[depth] = ++indexInParent;
				if(indexInParent < klen){
					//console.log("found next",indexInParent,ks[indexInParent]);
					// continue with next
					let key = ks[indexInParent];
					let val = entry[key];
					return [getType(val),depth,key,val];
				} else {
					// go up
					depth--;
					if(depth == 1) return;
					indexInParent = pindexes[depth];
					let parent = parents[depth-1];
					return next([getType(parent),depth,0,parent],true);
				}
			}
		} else if (type == 5) {
			let len = entry.length;
			// try first entry
			if(len > 0 && !skipFirst){
				//console.log("found first",entry[0], depth);
				pindexes[depth] = indexInParent;
				parents[depth] = entry;
				indexInParent = 0;
				depth++;
				pindexes[depth] = 0;
				let key = 0;
				let val = entry[key];
				return [getType(val),depth,key,val];
			} else {
				pindexes[depth] = ++indexInParent;
				if(indexInParent < len){
					//console.log("found next",indexInParent);
					// continue with next
					let key = indexInParent;
					let val = entry[key];
					return [getType(val),depth,key,val];
				} else {
					// go up
					depth--;
					if(depth == 1) return;
					indexInParent = pindexes[depth];
					//console.log("go up a",depth,indexInParent);
					let parent = parents[depth-1];
					return next([getType(parent),depth,0,parent],true);
				}
			}
		} else {
			indexInParent = pindexes[depth];
			let parent = parents[depth-1];
			return next([getType(parent),depth,0,parent],true);
		}
	}
	// this is not the doc, so depth starts at 1
	var node = [getType(json),1,"#",json];
	fn(node);
	do {
		node = next(node);
		if(node) fn(node);
	} while(node);
}

const isObject = function(parent){
	return !!parent && parent.constructor === Object;
};

export function fromL3(l3) {
	var names = {},
	    parents = [],
		n = 0;
	const process = function(entry){
		var type = entry[0],
			depth = entry[1];
		if(type == 15){
			n++;
			names[n] = array2str(entry,1);
		} else {
			let parent = parents[depth - 1];
			let isObj = isObject(parent);
			let index = isObj ? 3 : 2;
			let key = isObj ? names[entry[2]] : null;
			//console.log("key",key, depth, parents[depth]);
			var val;
			if(type == 3){
				val = array2str(entry,index);
			} else if(type == 12){
				val = convert(array2str(entry,index));
			} else if(type == 5){
				val = [];
				parents[depth] = val;
			} else if(type == 6){
				val = {};
				parents[depth] = val;
			}
			if (parent !== undefined) {
				if(isObj){
					parent[key] = val;
				} else {
					push(parent,val);
				}
			}
		}
	};
	var entry = [];
	for (var i = 0, l = l3.length; i < l; i++) {
		if(l3[i] === 0){
			process(entry);
			entry = [];
		} else {
			entry.push(l3[i]);
		}
	}
    process(entry);
	return parents[1];
}

export function toL3(doc){
	var out = [],
	    names = {},
	    i = 1;
	const process = function (node) {
		let type = node[0],
		    depth = node[1],
		    name = node[2],
			val = node[3];
		// detect if parent is object/map, otherwise use integer
		var nameIndex;
		if (typeof name === "string") {
			if(!names[name]) {
				names[name] = i;
				i++;
				out.push(0);
				out.push(15);
				str2array(name,out);
			}
			nameIndex = names[name];
		}
		out.push(0);
		out.push(type);
		out.push(depth);
		if(nameIndex) out.push(nameIndex);
		if (type == 3) {
			str2array(val,out);
		} else if(type == 12) {
			str2array(val+"",out);
		}
	};
	iter(doc, process);
	out.shift();
	return out;
}
<|endoftext|>


<commit_before>"use strict";

var Proto = require("./proto.js");
var ObjectUtils = require("./utils/object.js");
var assert = require("./assert.js");

module.exports = function(coreModule) {
    coreModule.register("$promise", ["$window"], provider);
};

function provider($window){
    var Promise = Proto.define([
        function ctor(resolver) {
            assert(ObjectUtils.isFunction(resolver), "Promise resolver {0} is not a function", resolver);

            this._subscribers = [];

            function resolveHandler(value) {
                if (this._resolved || this._rejected) {
                    return;
                }

                resolve(this, value);
            }

            function rejectHandler(reason) {
                if (this._resolved || this._rejected) {
                    return;
                }

                reject(this, reason);
            }

            async(function(){
                try {
                    resolver(resolveHandler, rejectHandler);
                }
                catch (error) {
                    rejectHandler(error);
                }
            });
        },

        {
            then: function(onFulfilled, onRejected) {
                var deferred = {};
                deferred.promise = new Promise(function(resolve, reject) {
                    deferred.resolve = resolve;
                    deferred.reject = reject;
                });

                var subscriber = new Subscriber(onFulfilled, onRejected, deferred);

                if (this._fulfilled) {
                    subscriber.fulfilled(this._value);
                }
                else if (this._rejected) {
                    subscriber.rejected(this._value);
                }
                else {
                    this._subscribers.push(subscriber);
                }

                return deferred.promise;
            },

            "catch": function(onRejected) {
                return this.then(null, onRejected);
            }
        },

        {
            resolve: function(value) {
                if (isPromiseLike(value)) {
                    return value;
                }

                return new Promise(function(resolve) {
                    resolve(value);
                });
            },

            reject: function(reason) {
                return new Promise(function(resolve, reject) {
                    reject(reason);
                });
            },

            all: function(iterable) {
                assert(ObjectUtils.isArray(iterable), "array must be passed to Promise.all");

                var results = [];
                var countLeft = iterable.length;

                return new Promise(function(resolve, reject) {
                    if (0 === iterable.length) {
                        resolve(results);
                    }

                    function resolveWithValueHandler(index, value) {
                        results[index] = value;
                        countLeft--;

                        if (0 === countLeft) {
                            resolve(results);
                        }
                    }

                    function resolveHandler(index) {
                        return function(value) {
                            resolveWithValueHandler(index, value)
                        }
                    }

                    ObjectUtils.forEach(iterable, function(value, index) {
                        if (isPromiseLike(value)) {
                            value.then(resolveHandler(index), reject);
                        }
                        else {
                            resolveWithValueHandler(index, value);
                        }
                    });
                });
            },

            race: function(iterable) {
                assert(ObjectUtils.isArray(iterable), "array must be passed to Promise.race");

                return new Promise(function(resolve, reject) {
                    ObjectUtils.forEach(iterable, function(value) {
                        if (isPromiseLike(value)) {
                            value.then(resolve, reject);
                        }
                        else {
                            resolve(value);
                        }
                    });
                });
            }
        }
    ]);

    function isPromiseLike(obj) {
        return obj && ObjectUtils.isFunction(obj.then);
    }

    function resolve(promise, value) {
        function resolveHandler(resolvedValue) {
            promise._fulfilled = true;
            promise._value = resolvedValue;

            ObjectUtils.forEach(promise._subscribers, function(subscriber) {
                subscriber.fulfilled(resolvedValue);
            });

            promise._subscribers = null;
        }

        function rejectHandler(reason) {
            reject(promise, reason);
        }

        if (isPromiseLike(value)) {
            value.then(resolveHandler, rejectHandler);
        }
        else {
            resolveHandler(value);
        }
    }

    function reject(promise, reason) {
        promise._rejected = true;
        promise._value = reason;

        ObjectUtils.forEach(promise._subscribers, function(subscriber) {
            subscriber.rejected(reason);
        });

        promise._subscribers = null;
    }

    function async(method) {
        $window.setTimeout(method, 0);
    }

    var Subscriber = Proto.define([
        function ctor(onFulfilled, onRejected, deferred) {
            this._onFulfilled = onFulfilled;
            this._onRejected = onRejected;
            this._deferred = deferred;
        },

        {
            fulfilled: function(value) {
                if (this._onFulfilled) {
                    invokeCallback(this._onFulfilled, value, this._deferred);
                }
                else {
                    async(function(){
                        this._deferred.resolve(value);
                    });
                }
            },

            rejected: function(reason) {
                if (this._onRejected) {
                    invokeCallback(this._onRejected, reason, this._deferred);
                }
                else {
                    async(function(){
                        this._deferred.reject(reason);
                    });
                }
            }
        }
    ]);

    function invokeCallback(callback, value, deferred) {
        async(function() {
            try {
                var result = callback(value);
                if (result && isPromiseLike(result)) {
                    result.then(deferred.resolve, deferred.reject);
                }
                else {
                    deferred.resolve(result);
                }
            }
            catch (error) {
                deferred.reject(error);
            }

        });
    }

    return Promise;
}<commit_msg>fix closure contexts<commit_after>"use strict";

var Proto = require("./proto.js");
var ObjectUtils = require("./utils/object.js");
var assert = require("./assert.js");

module.exports = function(coreModule) {
    coreModule.register("$promise", ["$window"], provider);
};

function provider($window){
    var Promise = Proto.define([
        function ctor(resolver) {
            assert(ObjectUtils.isFunction(resolver), "Promise resolver {0} is not a function", resolver);

            this._subscribers = [];
            var that = this;

            function resolveHandler(value) {
                if (that._resolved || that._rejected) {
                    return;
                }

                resolve(that, value);
            }

            function rejectHandler(reason) {
                if (that._resolved || that._rejected) {
                    return;
                }

                reject(that, reason);
            }

            async(function(){
                try {
                    resolver(resolveHandler, rejectHandler);
                }
                catch (error) {
                    rejectHandler(error);
                }
            });
        },

        {
            then: function(onFulfilled, onRejected) {
                var deferred = {};
                deferred.promise = new Promise(function(resolve, reject) {
                    deferred.resolve = resolve;
                    deferred.reject = reject;
                });

                var subscriber = new Subscriber(onFulfilled, onRejected, deferred);

                if (this._fulfilled) {
                    subscriber.fulfilled(this._value);
                }
                else if (this._rejected) {
                    subscriber.rejected(this._value);
                }
                else {
                    this._subscribers.push(subscriber);
                }

                return deferred.promise;
            },

            "catch": function(onRejected) {
                return this.then(null, onRejected);
            }
        },

        {
            resolve: function(value) {
                if (isPromiseLike(value)) {
                    return value;
                }

                return new Promise(function(resolve) {
                    resolve(value);
                });
            },

            reject: function(reason) {
                return new Promise(function(resolve, reject) {
                    reject(reason);
                });
            },

            all: function(iterable) {
                assert(ObjectUtils.isArray(iterable), "array must be passed to Promise.all");

                var results = [];
                var countLeft = iterable.length;

                return new Promise(function(resolve, reject) {
                    if (0 === iterable.length) {
                        resolve(results);
                    }

                    function resolveWithValueHandler(index, value) {
                        results[index] = value;
                        countLeft--;

                        if (0 === countLeft) {
                            resolve(results);
                        }
                    }

                    function resolveHandler(index) {
                        return function(value) {
                            resolveWithValueHandler(index, value)
                        }
                    }

                    ObjectUtils.forEach(iterable, function(value, index) {
                        if (isPromiseLike(value)) {
                            value.then(resolveHandler(index), reject);
                        }
                        else {
                            resolveWithValueHandler(index, value);
                        }
                    });
                });
            },

            race: function(iterable) {
                assert(ObjectUtils.isArray(iterable), "array must be passed to Promise.race");

                return new Promise(function(resolve, reject) {
                    ObjectUtils.forEach(iterable, function(value) {
                        if (isPromiseLike(value)) {
                            value.then(resolve, reject);
                        }
                        else {
                            resolve(value);
                        }
                    });
                });
            }
        }
    ]);

    function isPromiseLike(obj) {
        return obj && ObjectUtils.isFunction(obj.then);
    }

    function resolve(promise, value) {
        function resolveHandler(resolvedValue) {
            promise._fulfilled = true;
            promise._value = resolvedValue;

            ObjectUtils.forEach(promise._subscribers, function(subscriber) {
                subscriber.fulfilled(resolvedValue);
            });

            promise._subscribers = null;
        }

        function rejectHandler(reason) {
            reject(promise, reason);
        }

        if (isPromiseLike(value)) {
            value.then(resolveHandler, rejectHandler);
        }
        else {
            resolveHandler(value);
        }
    }

    function reject(promise, reason) {
        promise._rejected = true;
        promise._value = reason;

        ObjectUtils.forEach(promise._subscribers, function(subscriber) {
            subscriber.rejected(reason);
        });

        promise._subscribers = null;
    }

    function async(method) {
        $window.setTimeout(method, 0);
    }

    var Subscriber = Proto.define([
        function ctor(onFulfilled, onRejected, deferred) {
            this._onFulfilled = onFulfilled;
            this._onRejected = onRejected;
            this._deferred = deferred;
        },

        {
            fulfilled: function(value) {
                if (this._onFulfilled) {
                    invokeCallback(this._onFulfilled, value, this._deferred);
                }
                else {
                    var that = this;

                    async(function(){
                        that._deferred.resolve(value);
                    });
                }
            },

            rejected: function(reason) {
                if (this._onRejected) {
                    invokeCallback(this._onRejected, reason, this._deferred);
                }
                else {
                    var that = this;

                    async(function(){
                        that._deferred.reject(reason);
                    });
                }
            }
        }
    ]);

    function invokeCallback(callback, value, deferred) {
        async(function() {
            try {
                var result = callback(value);
                if (result && isPromiseLike(result)) {
                    result.then(deferred.resolve, deferred.reject);
                }
                else {
                    deferred.resolve(result);
                }
            }
            catch (error) {
                deferred.reject(error);
            }

        });
    }

    return Promise;
}<|endoftext|>


<commit_before>import {Container} from 'aurelia-dependency-injection';
import {Pipeline} from './pipeline';
import {BuildNavigationPlanStep} from './navigation-plan';
import {LoadRouteStep} from './route-loading';
import {CommitChangesStep} from './navigation-instruction';
import {
  CanDeactivatePreviousStep,
  CanActivateNextStep,
  DeactivatePreviousStep,
  ActivateNextStep
} from './activation';

/**
* Class responsible for creating the navigation pipeline.
*/
export class PipelineProvider {
  static inject() { return [Container]; }

  constructor(container: Container) {
    this.container = container;
    this.steps = [
      BuildNavigationPlanStep,
      CanDeactivatePreviousStep, //optional
      LoadRouteStep,
      this._createPipelineSlot('authorize'),
      CanActivateNextStep, //optional
      this._createPipelineSlot('preActivate', 'modelbind'),
      //NOTE: app state changes start below - point of no return
      DeactivatePreviousStep, //optional
      ActivateNextStep, //optional
      this._createPipelineSlot('preRender', 'precommit'),
      CommitChangesStep,
      this._createPipelineSlot('postRender', 'postcomplete')
    ];
  }

  /**
  * Create the navigation pipeline.
  */
  createPipeline(): Pipeline {
    let pipeline = new Pipeline();
    this.steps.forEach(step => pipeline.addStep(this.container.get(step)));
    return pipeline;
  }

  /**
  * Adds a step into the pipeline at a known slot location.
  */
  addStep(name: string, step: PipelineStep): void {
    let found = this.steps.find(x => x.slotName === name || x.slotAlias === name);
    if (found) {
      found.steps.push(step);
    } else {
      throw new Error(`Invalid pipeline slot name: ${name}.`);
    }
  }

  _createPipelineSlot(name, alias) {
    class PipelineSlot {
      static inject = [Container];
      static slotName = name;
      static slotAlias = alias;
      static steps = [];

      constructor(container) {
        this.container = container;
      }

      getSteps() {
        return PipelineSlot.steps.map(x => this.container.get(x));
      }
    }

    return PipelineSlot;
  }
}
<commit_msg>feat(PipelineProvider): add methods for removing pipeline steps<commit_after>import {Container} from 'aurelia-dependency-injection';
import {Pipeline} from './pipeline';
import {BuildNavigationPlanStep} from './navigation-plan';
import {LoadRouteStep} from './route-loading';
import {CommitChangesStep} from './navigation-instruction';
import {
  CanDeactivatePreviousStep,
  CanActivateNextStep,
  DeactivatePreviousStep,
  ActivateNextStep
} from './activation';

class PipelineSlot {
  steps = [];

  constructor(container, name, alias) {
    this.container = container;
    this.slotName = name;
    this.slotAlias = alias;
  }

  getSteps() {
    return this.steps.map(x => this.container.get(x));
  }
}

/**
* Class responsible for creating the navigation pipeline.
*/
export class PipelineProvider {
  static inject() { return [Container]; }

  constructor(container: Container) {
    this.container = container;
    this.steps = [
      BuildNavigationPlanStep,
      CanDeactivatePreviousStep, //optional
      LoadRouteStep,
      this._createPipelineSlot('authorize'),
      CanActivateNextStep, //optional
      this._createPipelineSlot('preActivate', 'modelbind'),
      //NOTE: app state changes start below - point of no return
      DeactivatePreviousStep, //optional
      ActivateNextStep, //optional
      this._createPipelineSlot('preRender', 'precommit'),
      CommitChangesStep,
      this._createPipelineSlot('postRender', 'postcomplete')
    ];
  }

  /**
  * Create the navigation pipeline.
  */
  createPipeline(): Pipeline {
    let pipeline = new Pipeline();
    this.steps.forEach(step => pipeline.addStep(this.container.get(step)));
    return pipeline;
  }

  _findStep(name: string) {
    return this.steps.find(x => x.slotName === name || x.slotAlias === name);
  }

  /**
  * Adds a step into the pipeline at a known slot location.
  */
  addStep(name: string, step: PipelineStep): void {
    let found = this._findStep(name);
    if (found) {
      if (!found.steps.includes(step)) { // prevent duplicates
        found.steps.push(step);
      }
    } else {
      throw new Error(`Invalid pipeline slot name: ${name}.`);
    }
  }

  /**
   * Removes a step from a slot in the pipeline
   */
  removeStep(name: string, step: PipelineStep) {
    let slot = this._findStep(name);
    if (slot) {
      slot.steps.splice(slot.steps.indexOf(step), 1);
    }
  }

  /**
   * Clears all steps from a slot in the pipeline
   */
  _clearSteps(name: string = '') {
    let slot = this._findStep(name);
    if (slot) {
      slot.steps = [];
    }
  }

  /**
   * Resets all pipeline slots
   */
  reset() {
    this._clearSteps('authorize');
    this._clearSteps('preActivate');
    this._clearSteps('preRender');
    this._clearSteps('postRender');
  }

  _createPipelineSlot(name, alias) {
    return new PipelineSlot(this.container, name, alias);
  }
}
<|endoftext|>


<commit_before>/*
json - a complete serializer and deserializer for JSON

json.load(datastring)
json.decode(datastring)
json.parse(datastring)
  returns a javascript object deserialized from the JSON string

json.dump(obj)
json.encode(obj)
  returns a string of JSON that represents the object
*/

/*global TJP*/
//context:browser
//context:console

var
  DOUBLE_QUOTE = 1,
  SINGLE_QUOTE = 2,
  OTHER = 8,
  BACKSLASH = 9,
  //////////////
  OPEN_BRACKET = 3,
  CLOSE_BRACKET = 4,
  OPEN_BRACE = 5,
  CLOSE_BRACE = 6,
  COMMA = 7,
  COLON = 10,
  //////////////
  STRING = 11,
  NUMBER = 12,
  TRUE = 13,
  FALSE = 14,
  NULL = 15,
  UNDEFINED = 16,
  INFINITY = 17,
  NEGATIVE_INFINITY = 18,
  IDENTIFIER = 19;

/* comment this out for production
var ltrim_regex = RegExp('^\\s\\s*'),
    space_regex = RegExp('\\s');
var TJP = TJP || {
  base: {
    trim: function(str) {
      var i;
      str = str.replace(ltrim_regex, '');
      i = str.length;
      while (space_regex.test(str.charAt(--i)));
      return str.slice(0, i + 1);
    }
  }
};

var rev = {};
rev[DOUBLE_QUOTE] = 'DOUBLE_QUOTE';
rev[SINGLE_QUOTE] = 'SINGLE_QUOTE';
rev[OPEN_BRACKET] = 'OPEN_BRACKET';
rev[CLOSE_BRACKET] = 'CLOSE_BRACKET';
rev[OPEN_BRACE] = 'OPEN_BRACE';
rev[CLOSE_BRACE] = 'CLOSE_BRACE';
rev[COMMA] = 'COMMA';
rev[OTHER] = 'OTHER';
rev[BACKSLASH] = 'BACKSLASH';
rev[COLON] = 'COLON';
rev[STRING] = 'STRING';
rev[NUMBER] = 'NUMBER';
rev[TRUE] = 'TRUE';
rev[FALSE] = 'FALSE';
rev[NULL] = 'NULL';
rev[UNDEFINED] = 'UNDEFINED';
rev[INFINITY] = 'INFINITY';
rev[NEGATIVE_INFINITY] = 'NEGATIVE_INFINITY';
rev[IDENTIFIER] = 'IDENTIFIER';

function show(tokens) {
  var i, j, token, spaces;
  for (i = 0; i < tokens.length; i++) {
    token = tokens[i];
    for (spaces = [], j = rev[token[0]].length; j <= 17; j++) spaces.push(' ');
    print(rev[token[0]] + spaces.join('') + token[1]);
  }
};
*/

TJP.json = TJP.json || {};

var CHAR_TOKENS = {
  '"': DOUBLE_QUOTE,
  "'": SINGLE_QUOTE,
  '[': OPEN_BRACKET,
  ']': CLOSE_BRACKET,
  '{': OPEN_BRACE,
  '}': CLOSE_BRACE,
  ',': COMMA,
  '\\': BACKSLASH,
  ':': COLON
};

var REMOVE_SLASHES = {
  'n': '\n',
  'r': '\r',
  't': '\t',
  'b': '\b',
  'f': '\f'
};

function tokenize(data) {
  var i, ch, tokens = [], buffer = [], token;

  for (i = 0; i < data.length; i++) {
    ch = data[i];
    token = CHAR_TOKENS[ch];
    if (token) {
      if (buffer.length) {
        tokens.push([OTHER, buffer.join('')]);
        buffer = [];
      }
      tokens.push([token, ch]);
    } else buffer.push(ch);
  }
  if (buffer.length) tokens.push([OTHER, buffer.join('')]);

  return tokens;
};

var number_regex = /^-?((\d+(\.(\d+)?)?)|(\.\d+))([eE]-?\d+)?$/;

function reduce_tokens(tokens) {
  var i, token, next, replacement, buffer, instr, val, strtype;

  // scan for BACKSLASHes and replace as necessary
  for (i = 0; i < tokens.length; i++) {
    token = tokens[i];
    if (token[0] === BACKSLASH) {
      next = tokens[i + 1];
      switch(next[0]) {
        case BACKSLASH:
          tokens.splice(i, 2, [OTHER, '\\\\']);
          break;
        case OTHER:
          replacement = REMOVE_SLASHES[next[1].slice(0, 1)];
          if (replacement)
            tokens.splice(i, 2, [OTHER, replacement + next[1].slice(1)]);
          else tokens.splice(i--, 1);
          break;
        case SINGLE_QUOTE:
        case DOUBLE_QUOTE:
          // this is the only case in which we keep the BACKSLASH token
          break;
        default:
          throw new Error("Bad context for a \\");
      }
    }
  }

  // combine adjacent OTHER tokens
  for (i = 0; i < tokens.length; i++) {
    if (tokens[i][0] === OTHER && tokens[i + 1] &&
        tokens[i + 1][0] === OTHER)
      tokens.splice(i, 2, [OTHER, tokens[i][1] + tokens[i + 1][1]]);
  }

  // find STRINGs
  for (i = 0, buffer = [], instr = false; i < tokens.length; i++) {
    token = tokens[i];
    if (token[0] === SINGLE_QUOTE || token[0] === DOUBLE_QUOTE) {
      if (instr) {
        if (tokens[i - 1] && tokens[i - 1][0] === BACKSLASH) {
          buffer.push(token[1]);
          tokens.splice(--i, 2);
          continue;
        } else if (token[0] !== strtype) {
          buffer.push(token[1]);
          tokens.splice(i--, 1);
          continue;
        }
        else {
          tokens.splice(i, 1, [STRING, buffer.join('')]);
          buffer = [];
        }
      }  else {
        strtype = token[0];
        tokens.splice(i--, 1);
      }
      instr = !instr;
    } else if (instr) {
      buffer.push(token[1]);
      tokens.splice(i--, 1);
    }
  }

  // trim whitespace and identify the OTHERs
  for (i = 0; i < tokens.length; i++) {
    token = tokens[i];
    if (token[0] === OTHER) {
      val = TJP.base.trim(token[1]);
      if (!val) tokens.splice(i, 1);
      else {
        token[1] = val;
        if (val === "true") token[0] = TRUE;
        else if (val === "false") token[0] = FALSE;
        else if (val === "null") token[0] = NULL;
        else if (val === "undefined") token[0] = UNDEFINED;
        else if (val === "Infinity") token[0] = INFINITY;
        else if (val === "-Infinity") token[0] = NEGATIVE_INFINITY;
        else if (number_regex.test(val))
          token[0] = NUMBER;
        else token[0] = IDENTIFIER;
      }
    }
  }
};

function apply_value(stack, value) {
  var stacktop = stack[stack.length - 1];
  if (stacktop.type === OPEN_BRACE) {
    if (stacktop.postcolon) {
      stacktop.obj[stacktop.key] = value;
      stacktop.postcolon = false;
    } else throw new Error("Bad syntax");
  } else if (stacktop.type === OPEN_BRACKET) {
    if (stacktop.postcomma || stacktop.juststarted) {
      stacktop.obj.push(value);
      stacktop.postcomma = stacktop.juststarted = false;
    } else throw new Error("Bad syntax");
  } else throw new Error("Parser Error");
};

function find_matching(opener, closer, tokens) {
  var i, token, count = 1;
  for (i = 0; i < tokens.length; i++) {
    token = tokens[i][0];
    if (token === opener) count++;
    else if (token === closer) count--;
    if (!count) return i;
  }
  throw new Error("No matching '" + closer + "' found");
};

function parse_open_straight(stack, token) {
  stack.push({
    type: OPEN_BRACKET,
    obj: [],
    postcomma: false,
    juststarted: true
  });
};

function parse_close_straight(stack, token) {
  var stacktop = stack[stack.length - 1], arr;
  if (stacktop.type !== OPEN_BRACKET) throw new Error("mismatched ']'");
  arr = stack.pop().obj;
  stacktop = stack[stack.length - 1];
  switch(stacktop.type) {
    case OPEN_BRACE:
      stacktop.obj[stacktop.key] = arr;
      break;
    case OPEN_BRACKET:
      stacktop.obj.push(arr);
      break;
    default:
      throw new Error("bad context for an array");
  }
};

function parse_open_curly(stack, token) {
  stack.push({
    type: OPEN_BRACE,
    obj: {},
    key: '',
    postcomma: false,
    postcolon: false,
    juststarted: true
  });
};

function parse_close_curly(stack, token) {
  var stacktop = stack[stack.length - 1], arr, obj;
  if (stacktop.type !== OPEN_BRACE) throw new Error("mismatched ']'");
  obj = stack.pop().obj;
  stacktop = stack[stack.length - 1];
  switch(stacktop.type) {
    case OPEN_BRACE:
      stacktop.obj[stacktop.key] = obj;
      break;
    case OPEN_BRACKET:
      stacktop.obj.push(obj);
      break;
    default:
      throw new Error("bad context for an array");
  }
};

function parse_identifier(stack, token) {
  var stacktop = stack[stack.length - 1];
  if (stacktop.type === OPEN_BRACE &&
      (stacktop.postcomma || stacktop.juststarted)) {
    stacktop.key = token[1];
    stacktop.postcomma = stacktop.juststarted = false;
  } else throw new Error("Bad syntax");
};

function parse_comma(stack, token) {
  var stacktop = stack[stack.length - 1];
  stacktop.postcomma = true;
};

function parse_colon(stack, token) {
  var stacktop = stack[stack.length - 1];
  if (stacktop.type !== OPEN_BRACE) throw new Error("bad context for a COLON");
  stacktop.postcolon = true;
};

function parse_string(stack, token) {
  var stacktop = stack[stack.length - 1];
  if (stacktop.type === OPEN_BRACE &&
      (stacktop.postcomma || stacktop.juststarted)) {
    stacktop.key = token[1];
    stacktop.postcomma = stacktop.juststarted = false;
  } else apply_value(stack, token[1]);
};

function parse_number(stack, token) {
  apply_value(stack, eval(token[1]));
};

var simple_values = {};
simple_values[TRUE] = true;
simple_values[FALSE] = false;
simple_values[UNDEFINED] = undefined;
simple_values[NULL] = null;
simple_values[INFINITY] = Infinity;
simple_values[NEGATIVE_INFINITY] = -Infinity;

function parse_simple_value(stack, token) {
  apply_value(stack, simple_values[token[0]]);
};

var parsers = {};
parsers[OPEN_BRACKET] = parse_open_straight;
parsers[CLOSE_BRACKET] = parse_close_straight;
parsers[OPEN_BRACE] = parse_open_curly;
parsers[CLOSE_BRACE] = parse_close_curly;
parsers[COMMA] = parse_comma;
parsers[COLON] = parse_colon;
parsers[STRING] = parse_string;
parsers[NUMBER] = parse_number;
parsers[NEGATIVE_INFINITY] = parsers[NULL] = parse_simple_value;
parsers[UNDEFINED] = parsers[INFINITY] = parse_simple_value;
parsers[TRUE] = parsers[FALSE] = parse_simple_value;
parsers[IDENTIFIER] = parse_identifier;

function parse_tokens(tokens) {
  var stack = [{
    type: OPEN_BRACKET,
    obj: [],
    postcomma: false,
    juststarted: true
  }], token;
  while (tokens.length) {
    token = tokens.shift();
    parsers[token[0]](stack, token);
  }
  return stack[0].obj[0];
};

TJP.json.load = TJP.json.decode = TJP.json.parse = function(data) {
  var tokens = tokenize(data);
  reduce_tokens(tokens);
  return parse_tokens(tokens);
};

function dump_array(arr) {
  var dumped = [], i;
  for (i = 0; i < arr.length; i++) {
    dumped.push(TJP.json.dump(arr[i]));
  }
  return dumped.join('');
};

function dump_object(obj) {
  var dumped = [], name;
  for (name in obj) {
    dumped.push(name + ":" + TJP.json.dump(obj[name]));
  }
  return "{" + dumped.join(',') + "}";
};

var ADD_SLASHES = {
  "\n": "\\n",
  "\r": "\\r",
  "\t": "\\t",
  "\b": "\\b",
  "\f": "\\f",
  '"': '\\"'
};

function dump_string(str) {
  var from;
  str = str.replace('\\', '\\\\', 'g');
  for (from in ADD_SLASHES) str = str.replace(from, ADD_SLASHES[from], 'g');
  return '"' + str + '"';
};

TJP.json.dump = TJP.json.encode = function(data) {
  var type = TJP.base.gettype(data);
  switch(type) {
    case "number":
    case "boolean":
      return data.toString();
    case "string":
      return dump_string(data);
    case "undefined":
    case "NaN":
    case "null":
      return type;
    case "array":
      return dump_array(data);
    case "object":
      return dump_object(data);
    case "date":
    case "regexp":
      throw new Error("can't serialize a " + type);
  }
};
<commit_msg>wow epic FAIL in json.encode<commit_after>/*
json - a complete serializer and deserializer for JSON

json.load(datastring)
json.decode(datastring)
json.parse(datastring)
  returns a javascript object deserialized from the JSON string

json.dump(obj)
json.encode(obj)
  returns a string of JSON that represents the object
*/

/*global TJP*/
//context:browser
//context:console

var
  DOUBLE_QUOTE = 1,
  SINGLE_QUOTE = 2,
  OTHER = 8,
  BACKSLASH = 9,
  //////////////
  OPEN_BRACKET = 3,
  CLOSE_BRACKET = 4,
  OPEN_BRACE = 5,
  CLOSE_BRACE = 6,
  COMMA = 7,
  COLON = 10,
  //////////////
  STRING = 11,
  NUMBER = 12,
  TRUE = 13,
  FALSE = 14,
  NULL = 15,
  UNDEFINED = 16,
  INFINITY = 17,
  NEGATIVE_INFINITY = 18,
  IDENTIFIER = 19;

/* comment this out for production
var ltrim_regex = RegExp('^\\s\\s*'),
    space_regex = RegExp('\\s');
var TJP = TJP || {
  base: {
    trim: function(str) {
      var i;
      str = str.replace(ltrim_regex, '');
      i = str.length;
      while (space_regex.test(str.charAt(--i)));
      return str.slice(0, i + 1);
    }
  }
};

var rev = {};
rev[DOUBLE_QUOTE] = 'DOUBLE_QUOTE';
rev[SINGLE_QUOTE] = 'SINGLE_QUOTE';
rev[OPEN_BRACKET] = 'OPEN_BRACKET';
rev[CLOSE_BRACKET] = 'CLOSE_BRACKET';
rev[OPEN_BRACE] = 'OPEN_BRACE';
rev[CLOSE_BRACE] = 'CLOSE_BRACE';
rev[COMMA] = 'COMMA';
rev[OTHER] = 'OTHER';
rev[BACKSLASH] = 'BACKSLASH';
rev[COLON] = 'COLON';
rev[STRING] = 'STRING';
rev[NUMBER] = 'NUMBER';
rev[TRUE] = 'TRUE';
rev[FALSE] = 'FALSE';
rev[NULL] = 'NULL';
rev[UNDEFINED] = 'UNDEFINED';
rev[INFINITY] = 'INFINITY';
rev[NEGATIVE_INFINITY] = 'NEGATIVE_INFINITY';
rev[IDENTIFIER] = 'IDENTIFIER';

function show(tokens) {
  var i, j, token, spaces;
  for (i = 0; i < tokens.length; i++) {
    token = tokens[i];
    for (spaces = [], j = rev[token[0]].length; j <= 17; j++) spaces.push(' ');
    print(rev[token[0]] + spaces.join('') + token[1]);
  }
};
*/

TJP.json = TJP.json || {};

var CHAR_TOKENS = {
  '"': DOUBLE_QUOTE,
  "'": SINGLE_QUOTE,
  '[': OPEN_BRACKET,
  ']': CLOSE_BRACKET,
  '{': OPEN_BRACE,
  '}': CLOSE_BRACE,
  ',': COMMA,
  '\\': BACKSLASH,
  ':': COLON
};

var REMOVE_SLASHES = {
  'n': '\n',
  'r': '\r',
  't': '\t',
  'b': '\b',
  'f': '\f'
};

function tokenize(data) {
  var i, ch, tokens = [], buffer = [], token;

  for (i = 0; i < data.length; i++) {
    ch = data[i];
    token = CHAR_TOKENS[ch];
    if (token) {
      if (buffer.length) {
        tokens.push([OTHER, buffer.join('')]);
        buffer = [];
      }
      tokens.push([token, ch]);
    } else buffer.push(ch);
  }
  if (buffer.length) tokens.push([OTHER, buffer.join('')]);

  return tokens;
};

var number_regex = /^-?((\d+(\.(\d+)?)?)|(\.\d+))([eE]-?\d+)?$/;

function reduce_tokens(tokens) {
  var i, token, next, replacement, buffer, instr, val, strtype;

  // scan for BACKSLASHes and replace as necessary
  for (i = 0; i < tokens.length; i++) {
    token = tokens[i];
    if (token[0] === BACKSLASH) {
      next = tokens[i + 1];
      switch(next[0]) {
        case BACKSLASH:
          tokens.splice(i, 2, [OTHER, '\\\\']);
          break;
        case OTHER:
          replacement = REMOVE_SLASHES[next[1].slice(0, 1)];
          if (replacement)
            tokens.splice(i, 2, [OTHER, replacement + next[1].slice(1)]);
          else tokens.splice(i--, 1);
          break;
        case SINGLE_QUOTE:
        case DOUBLE_QUOTE:
          // this is the only case in which we keep the BACKSLASH token
          break;
        default:
          throw new Error("Bad context for a \\");
      }
    }
  }

  // combine adjacent OTHER tokens
  for (i = 0; i < tokens.length; i++) {
    if (tokens[i][0] === OTHER && tokens[i + 1] &&
        tokens[i + 1][0] === OTHER)
      tokens.splice(i, 2, [OTHER, tokens[i][1] + tokens[i + 1][1]]);
  }

  // find STRINGs
  for (i = 0, buffer = [], instr = false; i < tokens.length; i++) {
    token = tokens[i];
    if (token[0] === SINGLE_QUOTE || token[0] === DOUBLE_QUOTE) {
      if (instr) {
        if (tokens[i - 1] && tokens[i - 1][0] === BACKSLASH) {
          buffer.push(token[1]);
          tokens.splice(--i, 2);
          continue;
        } else if (token[0] !== strtype) {
          buffer.push(token[1]);
          tokens.splice(i--, 1);
          continue;
        }
        else {
          tokens.splice(i, 1, [STRING, buffer.join('')]);
          buffer = [];
        }
      }  else {
        strtype = token[0];
        tokens.splice(i--, 1);
      }
      instr = !instr;
    } else if (instr) {
      buffer.push(token[1]);
      tokens.splice(i--, 1);
    }
  }

  // trim whitespace and identify the OTHERs
  for (i = 0; i < tokens.length; i++) {
    token = tokens[i];
    if (token[0] === OTHER) {
      val = TJP.base.trim(token[1]);
      if (!val) tokens.splice(i, 1);
      else {
        token[1] = val;
        if (val === "true") token[0] = TRUE;
        else if (val === "false") token[0] = FALSE;
        else if (val === "null") token[0] = NULL;
        else if (val === "undefined") token[0] = UNDEFINED;
        else if (val === "Infinity") token[0] = INFINITY;
        else if (val === "-Infinity") token[0] = NEGATIVE_INFINITY;
        else if (number_regex.test(val))
          token[0] = NUMBER;
        else token[0] = IDENTIFIER;
      }
    }
  }
};

function apply_value(stack, value) {
  var stacktop = stack[stack.length - 1];
  if (stacktop.type === OPEN_BRACE) {
    if (stacktop.postcolon) {
      stacktop.obj[stacktop.key] = value;
      stacktop.postcolon = false;
    } else throw new Error("Bad syntax");
  } else if (stacktop.type === OPEN_BRACKET) {
    if (stacktop.postcomma || stacktop.juststarted) {
      stacktop.obj.push(value);
      stacktop.postcomma = stacktop.juststarted = false;
    } else throw new Error("Bad syntax");
  } else throw new Error("Parser Error");
};

function find_matching(opener, closer, tokens) {
  var i, token, count = 1;
  for (i = 0; i < tokens.length; i++) {
    token = tokens[i][0];
    if (token === opener) count++;
    else if (token === closer) count--;
    if (!count) return i;
  }
  throw new Error("No matching '" + closer + "' found");
};

function parse_open_straight(stack, token) {
  stack.push({
    type: OPEN_BRACKET,
    obj: [],
    postcomma: false,
    juststarted: true
  });
};

function parse_close_straight(stack, token) {
  var stacktop = stack[stack.length - 1], arr;
  if (stacktop.type !== OPEN_BRACKET) throw new Error("mismatched ']'");
  arr = stack.pop().obj;
  stacktop = stack[stack.length - 1];
  switch(stacktop.type) {
    case OPEN_BRACE:
      stacktop.obj[stacktop.key] = arr;
      break;
    case OPEN_BRACKET:
      stacktop.obj.push(arr);
      break;
    default:
      throw new Error("bad context for an array");
  }
};

function parse_open_curly(stack, token) {
  stack.push({
    type: OPEN_BRACE,
    obj: {},
    key: '',
    postcomma: false,
    postcolon: false,
    juststarted: true
  });
};

function parse_close_curly(stack, token) {
  var stacktop = stack[stack.length - 1], arr, obj;
  if (stacktop.type !== OPEN_BRACE) throw new Error("mismatched ']'");
  obj = stack.pop().obj;
  stacktop = stack[stack.length - 1];
  switch(stacktop.type) {
    case OPEN_BRACE:
      stacktop.obj[stacktop.key] = obj;
      break;
    case OPEN_BRACKET:
      stacktop.obj.push(obj);
      break;
    default:
      throw new Error("bad context for an array");
  }
};

function parse_identifier(stack, token) {
  var stacktop = stack[stack.length - 1];
  if (stacktop.type === OPEN_BRACE &&
      (stacktop.postcomma || stacktop.juststarted)) {
    stacktop.key = token[1];
    stacktop.postcomma = stacktop.juststarted = false;
  } else throw new Error("Bad syntax");
};

function parse_comma(stack, token) {
  var stacktop = stack[stack.length - 1];
  stacktop.postcomma = true;
};

function parse_colon(stack, token) {
  var stacktop = stack[stack.length - 1];
  if (stacktop.type !== OPEN_BRACE) throw new Error("bad context for a COLON");
  stacktop.postcolon = true;
};

function parse_string(stack, token) {
  var stacktop = stack[stack.length - 1];
  if (stacktop.type === OPEN_BRACE &&
      (stacktop.postcomma || stacktop.juststarted)) {
    stacktop.key = token[1];
    stacktop.postcomma = stacktop.juststarted = false;
  } else apply_value(stack, token[1]);
};

function parse_number(stack, token) {
  apply_value(stack, eval(token[1]));
};

var simple_values = {};
simple_values[TRUE] = true;
simple_values[FALSE] = false;
simple_values[UNDEFINED] = undefined;
simple_values[NULL] = null;
simple_values[INFINITY] = Infinity;
simple_values[NEGATIVE_INFINITY] = -Infinity;

function parse_simple_value(stack, token) {
  apply_value(stack, simple_values[token[0]]);
};

var parsers = {};
parsers[OPEN_BRACKET] = parse_open_straight;
parsers[CLOSE_BRACKET] = parse_close_straight;
parsers[OPEN_BRACE] = parse_open_curly;
parsers[CLOSE_BRACE] = parse_close_curly;
parsers[COMMA] = parse_comma;
parsers[COLON] = parse_colon;
parsers[STRING] = parse_string;
parsers[NUMBER] = parse_number;
parsers[NEGATIVE_INFINITY] = parsers[NULL] = parse_simple_value;
parsers[UNDEFINED] = parsers[INFINITY] = parse_simple_value;
parsers[TRUE] = parsers[FALSE] = parse_simple_value;
parsers[IDENTIFIER] = parse_identifier;

function parse_tokens(tokens) {
  var stack = [{
    type: OPEN_BRACKET,
    obj: [],
    postcomma: false,
    juststarted: true
  }], token;
  while (tokens.length) {
    token = tokens.shift();
    parsers[token[0]](stack, token);
  }
  return stack[0].obj[0];
};

TJP.json.load = TJP.json.decode = TJP.json.parse = function(data) {
  var tokens = tokenize(data);
  reduce_tokens(tokens);
  return parse_tokens(tokens);
};

function dump_array(arr) {
  var dumped = [], i;
  for (i = 0; i < arr.length; i++) {
    dumped.push(TJP.json.dump(arr[i]));
  }
  return dumped.join(',');
};

function dump_object(obj) {
  var dumped = [], name;
  for (name in obj) {
    dumped.push(name + ":" + TJP.json.dump(obj[name]));
  }
  return "{" + dumped.join(',') + "}";
};

var ADD_SLASHES = {
  "\n": "\\n",
  "\r": "\\r",
  "\t": "\\t",
  "\b": "\\b",
  "\f": "\\f",
  '"': '\\"'
};

function dump_string(str) {
  var from;
  str = str.replace('\\', '\\\\', 'g');
  for (from in ADD_SLASHES) str = str.replace(from, ADD_SLASHES[from], 'g');
  return '"' + str + '"';
};

TJP.json.dump = TJP.json.encode = function(data) {
  var type = TJP.base.gettype(data);
  switch(type) {
    case "number":
    case "boolean":
      return data.toString();
    case "string":
      return dump_string(data);
    case "undefined":
    case "NaN":
    case "null":
      return type;
    case "array":
      return dump_array(data);
    case "object":
      return dump_object(data);
    case "date":
    case "regexp":
      throw new Error("can't serialize a " + type);
  }
};
<|endoftext|>


<commit_before>// This list is used both by the grunt build and index.html (in debug mode)

(typeof exports != "undefined" ? exports : pskl_exports).styles = [
  "css/reset.css",
  "css/style.css",
  "css/layout.css",
  "css/font-icon.css",
  "css/forms.css",
  "css/settings.css",
  "css/settings-application.css",
  "css/settings-export.css",
  "css/settings-import.css",
  "css/settings-resize.css",
  "css/tools.css",
  "css/icons.css",
  "css/cheatsheet.css",
  "css/color-picker-slider.css",
  "css/dialogs.css",
  "css/dialogs-import-image.css",
  "css/dialogs-browse-local.css",
  "css/dialogs-create-palette.css",
  "css/notifications.css",
  "css/toolbox.css",
  "css/toolbox-layers-list.css",
  "css/toolbox-palettes-list.css",
  "css/toolbox-animated-preview.css",
  "css/transformations.css",
  "css/spectrum/spectrum.css",
  "css/spectrum/spectrum-overrides.css",
  "css/bootstrap/bootstrap.css",
  "css/bootstrap/bootstrap-tooltip-custom.css",
  "css/frames-list.css",
  "css/minimap.css"
];<commit_msg>Issue #277 : Add new css file to style list<commit_after>// This list is used both by the grunt build and index.html (in debug mode)

(typeof exports != "undefined" ? exports : pskl_exports).styles = [
  "css/reset.css",
  "css/style.css",
  "css/layout.css",
  "css/font-icon.css",
  "css/forms.css",
  "css/settings.css",
  "css/settings-application.css",
  "css/settings-export.css",
  "css/settings-import.css",
  "css/settings-resize.css",
  "css/settings-save.css",
  "css/tools.css",
  "css/icons.css",
  "css/cheatsheet.css",
  "css/color-picker-slider.css",
  "css/dialogs.css",
  "css/dialogs-import-image.css",
  "css/dialogs-browse-local.css",
  "css/dialogs-create-palette.css",
  "css/notifications.css",
  "css/toolbox.css",
  "css/toolbox-layers-list.css",
  "css/toolbox-palettes-list.css",
  "css/toolbox-animated-preview.css",
  "css/transformations.css",
  "css/spectrum/spectrum.css",
  "css/spectrum/spectrum-overrides.css",
  "css/bootstrap/bootstrap.css",
  "css/bootstrap/bootstrap-tooltip-custom.css",
  "css/frames-list.css",
  "css/minimap.css"
];<|endoftext|>