<commit_before>// Phase2Heuristic estimates the lower bound for the number of moves to solve a
// Phase2Cube.
function Phase2Heuristic(coords) {
  // This stores the number of moves needed to solve both the corners and the
  // E slice edges for each case. The cases are encoded as:
  // CornerSym*24 + SlicePerm.
  this.cornersSlice = new CompactTable(2768 * 24);

  // This stores the number of moves needed to solve the edges and to bring all
  // the top-layer edges to the top layer.
  this.edgesChoose = new CompactTable(2768 * 70);

  // This stores the number of moves needed to solve both the edges and the E
  // slice edges for each case. The cases are encoded as:
  // EdgeSym*24 + SlicePerm.
  this.edgesSlice = new CompactTable(2768 * 24);

  this._generateCornersSlice(coords);
  this._generateEdgesChoose(coords);
  this._generateEdgesSlice(coords);
}

// lowerBound returns a lower bound for the number of moves to solve a given
// Phase2Cube. This requires a Phase2Coords table.
Phase2Heuristic.prototype.lowerBound = function(c, coords) {
  // Figure out the edge+slice heuristic coordinate.
  var eHash = hashEdgesSlice(c.edgeCoord, c.sliceCoord, coords);
  var eMoves = this.edgesSlice.get(eHash);

  // Figure out the corner+slice heuristic coordinate.
  var cHash = hashCornersSlice(c.cornerCoord, c.sliceCoord, coords);
  var cMoves = this.cornersSlice.get(cHash);

  // Figure out the edge+choose heuristic coordinate.
  var ecHash = hashEdgesChoose(c.edgeCoord, c.chooseCoord, coords);
  var ecMoves = this.edgesChoose.get(ecHash);

  return Math.max(ecMoves, Math.max(cMoves, eMoves));
};

Phase2Heuristic.prototype._generateCornersSlice = function(coords) {
  var maxDepth = 12;
  this.cornersSlice.fillWith(maxDepth);

  // The arrangement of bits in the queue's nodes are as follows:
  // (LSB) (4 bits: depth) (5 bits: slice) (12 bits: corners) (MSB)

  // Setup the queue to have the start node.
  var queue = new NumberQueue(13590);
  queue.push(0);

  // We have explored the start node. It's depth is zero (obviously).
  this.cornersSlice.set(0, 0);

  // While there's still stuff in the queue, do the search.
  while (!queue.empty()) {
    // Shift a node and extract its bitfields.
    var node = queue.shift();
    var depth = (node & 0xf);
    var slice = (node >>> 4) & 0x1f;
    var corners = (node >>> 9);

    // Apply all 10 moves to the node.
    for (var m = 0; m < 10; ++m) {
      var newSlice = coords.slice.move(slice, m);
      var newCorners = coords.corners.move(corners << 4, m);
      var invSym = symmetry.udSymmetryInverse(newCorners & 0xf);
      var symSlice = coords.slice.conjSym(invSym, newSlice);
      var symCorners = (newCorners >>> 4);
      hash = symSlice + symCorners*24;

      // If this node has not been visited, push it to the queue.
      if (this.cornersSlice.get(hash) === maxDepth) {
        this.cornersSlice.set(hash, depth + 1);
        if (depth < maxDepth-2) {
          queue.push((depth + 1) | (symSlice << 4) | (symCorners << 9));
        }
      }
    }
  }
};

Phase2Heuristic.prototype._generateEdgesChoose = function(coords) {
  var maxDepth = 10;
  this.edgesChoose.fillWith(maxDepth);

  // The arrangement of bits in the queue's nodes are as follows:
  // (LSB) (4 bits: depth) (7 bits: choose) (12 bits: edges) (MSB)

  // Setup the queue to have the start node.
  var queue = new NumberQueue(46680);
  queue.push(60 << 4);

  // We have visited the first node.
  this.edgesChoose.set(60 << 4, 0);

  while (!queue.empty()) {
    // Shift a node and extract its bitfields.
    var node = queue.shift();
    var depth = (node & 0xf);
    var choose = (node >>> 4) & 0x7f;
    var edges = (node >>> 11);

    // Apply all 10 moves to the node.
    for (var m = 0; m < 10; ++m) {
      var newChoose = coords.choose.move(choose, m);
      var newEdges = coords.edges.move(edges << 4, m);
      var invSym = symmetry.udSymmetryInverse(newEdges & 0xf);
      var symChoose = coords.choose.conjSym(invSym, newChoose);
      var symEdges = (newEdges >>> 4);
      hash = symChoose + symEdges*70;

      // If this node has not been visited, push it to the queue.
      if (this.edgesChoose.get(hash) === maxDepth) {
        this.edgesChoose.set(hash, depth + 1);
        if (depth < maxDepth-2) {
          queue.push((depth + 1) | (symChoose << 4) | (symEdges << 11));
        }
      }
    }
  }
};

Phase2Heuristic.prototype._generateEdgesSlice = function(coords) {
  var maxDepth = 9;
  this.edgesSlice.fillWith(maxDepth);

  // The arrangement of bits in the queue's nodes are as follows:
  // (LSB) (4 bits: depth) (5 bits: slice) (12 bits: edges) (MSB)

  // Setup the queue to have the start node.
  var queue = new NumberQueue(19350);
  queue.push(0);

  // We have visited the first node.
  this.edgesSlice.set(0, 0);

  while (!queue.empty()) {
    // Shift a node and extract its bitfields.
    var node = queue.shift();
    var depth = (node & 0xf);
    var slice = (node >>> 4) & 0x1f;
    var edges = (node >>> 9);

    // Apply all 10 moves to the node.
    for (var m = 0; m < 10; ++m) {
      var newSlice = coords.slice.move(slice, m);
      var newEdges = coords.edges.move(edges << 4, m);
      var invSym = symmetry.udSymmetryInverse(newEdges & 0xf);
      var symSlice = coords.slice.conjSym(invSym, newSlice);
      var symEdges = (newEdges >>> 4);
      hash = symSlice + symEdges*24;

      // If this node has not been visited, push it to the queue.
      if (this.edgesSlice.get(hash) === maxDepth) {
        this.edgesSlice.set(hash, depth + 1);
        if (depth < maxDepth-2) {
          queue.push((depth + 1) | (symSlice << 4) | (symEdges << 9));
        }
      }
    }
  }
};

function hashCornersSlice(corners, slice, coords) {
  var invSym = symmetry.udSymmetryInverse(corners & 0xf);
  var symSlice = coords.slice.conjSym(invSym, slice);
  var symCorners = (corners >>> 4);
  return symSlice + symCorners*24;
}

function hashEdgesChoose(edges, choose, coords) {
  var invSym = symmetry.udSymmetryInverse(edges & 0xf);
  var symChoose = coords.choose.conjSym(invSym, choose);
  var symEdges = (edges >>> 4);
  return symChoose + symEdges*70;
}

function hashEdgesSlice(edges, slice, coords) {
  var invSym = symmetry.udSymmetryInverse(edges & 0xf);
  var symSlice = coords.slice.conjSym(invSym, slice);
  var symEdges = (edges >>> 4);
  return symSlice + symEdges*24;
}

exports.Phase2Heuristic = Phase2Heuristic;
<commit_msg>fixed edgesChoose heuristic bug<commit_after>// Phase2Heuristic estimates the lower bound for the number of moves to solve a
// Phase2Cube.
function Phase2Heuristic(coords) {
  // This stores the number of moves needed to solve both the corners and the
  // E slice edges for each case. The cases are encoded as:
  // CornerSym*24 + SlicePerm.
  this.cornersSlice = new CompactTable(2768 * 24);

  // This stores the number of moves needed to solve the edges and to bring all
  // the top-layer edges to the top layer.
  this.edgesChoose = new CompactTable(2768 * 70);

  // This stores the number of moves needed to solve both the edges and the E
  // slice edges for each case. The cases are encoded as:
  // EdgeSym*24 + SlicePerm.
  this.edgesSlice = new CompactTable(2768 * 24);

  this._generateCornersSlice(coords);
  this._generateEdgesChoose(coords);
  this._generateEdgesSlice(coords);
}

// lowerBound returns a lower bound for the number of moves to solve a given
// Phase2Cube. This requires a Phase2Coords table.
Phase2Heuristic.prototype.lowerBound = function(c, coords) {
  // Figure out the edge+slice heuristic coordinate.
  var eHash = hashEdgesSlice(c.edgeCoord, c.sliceCoord, coords);
  var eMoves = this.edgesSlice.get(eHash);

  // Figure out the corner+slice heuristic coordinate.
  var cHash = hashCornersSlice(c.cornerCoord, c.sliceCoord, coords);
  var cMoves = this.cornersSlice.get(cHash);

  // Figure out the edge+choose heuristic coordinate.
  var ecHash = hashEdgesChoose(c.edgeCoord, c.chooseCoord, coords);
  var ecMoves = this.edgesChoose.get(ecHash);

  return Math.max(ecMoves, Math.max(cMoves, eMoves));
};

Phase2Heuristic.prototype._generateCornersSlice = function(coords) {
  var maxDepth = 12;
  this.cornersSlice.fillWith(maxDepth);

  // The arrangement of bits in the queue's nodes are as follows:
  // (LSB) (4 bits: depth) (5 bits: slice) (12 bits: corners) (MSB)

  // Setup the queue to have the start node.
  var queue = new NumberQueue(13590);
  queue.push(0);

  // We have explored the start node. It's depth is zero (obviously).
  this.cornersSlice.set(0, 0);

  // While there's still stuff in the queue, do the search.
  while (!queue.empty()) {
    // Shift a node and extract its bitfields.
    var node = queue.shift();
    var depth = (node & 0xf);
    var slice = (node >>> 4) & 0x1f;
    var corners = (node >>> 9);

    // Apply all 10 moves to the node.
    for (var m = 0; m < 10; ++m) {
      var newSlice = coords.slice.move(slice, m);
      var newCorners = coords.corners.move(corners << 4, m);
      var invSym = symmetry.udSymmetryInverse(newCorners & 0xf);
      var symSlice = coords.slice.conjSym(invSym, newSlice);
      var symCorners = (newCorners >>> 4);
      hash = symSlice + symCorners*24;

      // If this node has not been visited, push it to the queue.
      if (this.cornersSlice.get(hash) === maxDepth) {
        this.cornersSlice.set(hash, depth + 1);
        if (depth < maxDepth-2) {
          queue.push((depth + 1) | (symSlice << 4) | (symCorners << 9));
        }
      }
    }
  }
};

Phase2Heuristic.prototype._generateEdgesChoose = function(coords) {
  var maxDepth = 10;
  this.edgesChoose.fillWith(maxDepth);

  // The arrangement of bits in the queue's nodes are as follows:
  // (LSB) (4 bits: depth) (7 bits: choose) (12 bits: edges) (MSB)

  // Setup the queue to have the start node.
  var queue = new NumberQueue(46680);
  queue.push(60 << 4);

  // We have visited the first node.
  this.edgesChoose.set(60, 0);

  while (!queue.empty()) {
    // Shift a node and extract its bitfields.
    var node = queue.shift();
    var depth = (node & 0xf);
    var choose = (node >>> 4) & 0x7f;
    var edges = (node >>> 11);

    // Apply all 10 moves to the node.
    for (var m = 0; m < 10; ++m) {
      var newChoose = coords.choose.move(choose, m);
      var newEdges = coords.edges.move(edges << 4, m);
      var invSym = symmetry.udSymmetryInverse(newEdges & 0xf);
      var symChoose = coords.choose.conjSym(invSym, newChoose);
      var symEdges = (newEdges >>> 4);
      hash = symChoose + symEdges*70;

      // If this node has not been visited, push it to the queue.
      if (this.edgesChoose.get(hash) === maxDepth) {
        this.edgesChoose.set(hash, depth + 1);
        if (depth < maxDepth-2) {
          queue.push((depth + 1) | (symChoose << 4) | (symEdges << 11));
        }
      }
    }
  }
};

Phase2Heuristic.prototype._generateEdgesSlice = function(coords) {
  var maxDepth = 9;
  this.edgesSlice.fillWith(maxDepth);

  // The arrangement of bits in the queue's nodes are as follows:
  // (LSB) (4 bits: depth) (5 bits: slice) (12 bits: edges) (MSB)

  // Setup the queue to have the start node.
  var queue = new NumberQueue(19350);
  queue.push(0);

  // We have visited the first node.
  this.edgesSlice.set(0, 0);

  while (!queue.empty()) {
    // Shift a node and extract its bitfields.
    var node = queue.shift();
    var depth = (node & 0xf);
    var slice = (node >>> 4) & 0x1f;
    var edges = (node >>> 9);

    // Apply all 10 moves to the node.
    for (var m = 0; m < 10; ++m) {
      var newSlice = coords.slice.move(slice, m);
      var newEdges = coords.edges.move(edges << 4, m);
      var invSym = symmetry.udSymmetryInverse(newEdges & 0xf);
      var symSlice = coords.slice.conjSym(invSym, newSlice);
      var symEdges = (newEdges >>> 4);
      hash = symSlice + symEdges*24;

      // If this node has not been visited, push it to the queue.
      if (this.edgesSlice.get(hash) === maxDepth) {
        this.edgesSlice.set(hash, depth + 1);
        if (depth < maxDepth-2) {
          queue.push((depth + 1) | (symSlice << 4) | (symEdges << 9));
        }
      }
    }
  }
};

function hashCornersSlice(corners, slice, coords) {
  var invSym = symmetry.udSymmetryInverse(corners & 0xf);
  var symSlice = coords.slice.conjSym(invSym, slice);
  var symCorners = (corners >>> 4);
  return symSlice + symCorners*24;
}

function hashEdgesChoose(edges, choose, coords) {
  var invSym = symmetry.udSymmetryInverse(edges & 0xf);
  var symChoose = coords.choose.conjSym(invSym, choose);
  var symEdges = (edges >>> 4);
  return symChoose + symEdges*70;
}

function hashEdgesSlice(edges, slice, coords) {
  var invSym = symmetry.udSymmetryInverse(edges & 0xf);
  var symSlice = coords.slice.conjSym(invSym, slice);
  var symEdges = (edges >>> 4);
  return symSlice + symEdges*24;
}

exports.Phase2Heuristic = Phase2Heuristic;
<|endoftext|>


<commit_before>(function() {

  function extractParams() {
    if(! document.location.hash) return;
    return document.location.hash.slice(1).split('&').reduce(function(m, kvs) {
      var kv = kvs.split('=');
      m[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1]);
      return m;
    }, {});
  };

  RemoteStorage.Authorize = function(authURL, storageApi, scopes, redirectUri) {
    RemoteStorage.log('Authorize authURL = ',authURL)
    var scope = [];
    for(var key in scopes) {
      var mode = scopes[key];
      if(key == 'root') {
        if(! storageApi.match(/^draft-dejong-remotestorage-/)) {
          key = '';
        }
      }
      scope.push(key + ':' + mode);
    }
    scope = scope.join(' ');

    var clientId = redirectUri.match(/^(https?:\/\/[^\/]+)/)[0];

    var url = authURL;
    url += authURL.indexOf('?') > 0 ? '&' : '?';
    url += 'redirect_uri=' + encodeURIComponent(redirectUri.replace(/#.*$/, ''));
    url += '&scope=' + encodeURIComponent(scope);
    url += '&client_id=' + encodeURIComponent(clientId);
    document.location = url;
  };

  RemoteStorage.prototype.authorize = function(authURL) {
    RemoteStorage.Authorize(authURL, this.remote.storageApi, this.access.scopeModeMap, String(document.location));
  };

  RemoteStorage.Authorize._rs_init = function(remoteStorage) {
    var params = extractParams();
    if(params) {
      document.location.hash = '';
    }
    remoteStorage.on('features-loaded', function() {
      if(params) {
        if(params.access_token) {
          remoteStorage.remote.configure(undefined, undefined, undefined, params.access_token);
        }
        if(params.remotestorage) {
          remoteStorage.connect(params.remotestorage);
        }
        if(params.error) {
          throw "Authorization server errored: " + params.error;
        }
      }
    });
  }

})();
<commit_msg>set response_type=token in oauth redirect<commit_after>(function() {

  function extractParams() {
    if(! document.location.hash) return;
    return document.location.hash.slice(1).split('&').reduce(function(m, kvs) {
      var kv = kvs.split('=');
      m[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1]);
      return m;
    }, {});
  };

  RemoteStorage.Authorize = function(authURL, storageApi, scopes, redirectUri) {
    RemoteStorage.log('Authorize authURL = ',authURL)
    var scope = [];
    for(var key in scopes) {
      var mode = scopes[key];
      if(key == 'root') {
        if(! storageApi.match(/^draft-dejong-remotestorage-/)) {
          key = '';
        }
      }
      scope.push(key + ':' + mode);
    }
    scope = scope.join(' ');

    var clientId = redirectUri.match(/^(https?:\/\/[^\/]+)/)[0];

    var url = authURL;
    url += authURL.indexOf('?') > 0 ? '&' : '?';
    url += 'redirect_uri=' + encodeURIComponent(redirectUri.replace(/#.*$/, ''));
    url += '&scope=' + encodeURIComponent(scope);
    url += '&client_id=' + encodeURIComponent(clientId);
    url += '&response_type=token';
    document.location = url;
  };

  RemoteStorage.prototype.authorize = function(authURL) {
    RemoteStorage.Authorize(authURL, this.remote.storageApi, this.access.scopeModeMap, String(document.location));
  };

  RemoteStorage.Authorize._rs_init = function(remoteStorage) {
    var params = extractParams();
    if(params) {
      document.location.hash = '';
    }
    remoteStorage.on('features-loaded', function() {
      if(params) {
        if(params.access_token) {
          remoteStorage.remote.configure(undefined, undefined, undefined, params.access_token);
        }
        if(params.remotestorage) {
          remoteStorage.connect(params.remotestorage);
        }
        if(params.error) {
          throw "Authorization server errored: " + params.error;
        }
      }
    });
  }

})();
<|endoftext|>


<commit_before>var config = require('./config');
var ERROR = config.ERROR;
var WARNING = config.WARNING;
var IGNORE = config.IGNORE;

/**
 * ## Stylistic Issues
 *
 * These rules are purely matters of style and are quite subjective.
 *
 * @see http://eslint.org/docs/rules/#stylistic-issues
 */
module.exports = {
  rules: {
    // enforce spacing inside array brackets
    'array-bracket-spacing': IGNORE,
    // enforce one true brace style
    'brace-style': [ERROR, '1tbs', {
      allowSingleLine: true
    }],
    // require camel case names
    camelcase: [ERROR, {
      properties: 'never'
    }],
    // enforce spacing before and after comma
    'comma-spacing': [ERROR, {
      before: false,
      after: true
    }],
    // enforce one true comma style
    'comma-style': [ERROR, 'last'],
    // require or disallow padding inside computed properties
    'computed-property-spacing': IGNORE,
    // enforces consistent naming when capturing the current execution context
    'consistent-this': IGNORE,
    // enforce newline at the end of file, with no multiple empty lines
    'eol-last': ERROR,
    // require function expressions to have a name
    /**
     * @differ - This is for advanced debugging.
     */
    'func-names': IGNORE,
    // enforces use of function declarations or expressions
    'func-style': IGNORE,
    // this option enforces minimum and maximum identifier lengths (variable names, property names etc.)
    'id-length': [ERROR, {
      min: 0,
      properties: 'never'
    }],
    // this option sets a specific tab width for your code
    indent: [ERROR, 2, {"SwitchCase": 1}],
    // specify whether double or single quotes should be used in JSX attributes
    'jsx-quotes': ERROR,
    // enforces spacing between keys and values in object literal properties
    'key-spacing': [ERROR, {
      beforeColon: false,
      afterColon: true
    }],
    // enforces empty lines around comments
    'lines-around-comment': IGNORE,
    // disallow mixed 'LF' and 'CRLF' as linebreaks
    'linebreak-style': IGNORE,
    // specify the maximum depth callbacks can be nested
    'max-nested-callbacks': IGNORE,
    // require a capital letter for constructors
    'new-cap': [ERROR, {
      newIsCap: true
    }],
    // disallow the omission of parentheses when invoking a constructor with no arguments
    'new-parens': IGNORE,
    // allow/disallow an empty newline after var statement
    'newline-after-var': IGNORE,
    // disallow use of the Array constructor
    'no-array-constructor': IGNORE,
    // disallow use of the continue statement
    'no-continue': IGNORE,
    // disallow comments inline after code
    'no-inline-comments': IGNORE,
    // disallow if as the only statement in an else block
    'no-lonely-if': WARNING,
    // disallow mixed spaces and tabs for indentation
    // @differ - Not ignored as your environment is most likely not properly configured!
    'no-mixed-spaces-and-tabs': ERROR,
    // disallow multiple empty lines
    'no-multiple-empty-lines': [ERROR, {
      max: 2
    }],
    // disallow nested ternary expressions
    // @differ - Yes, this may be brittle but sometimes brevity is preferable.
    'no-nested-ternary': WARNING,
    // disallow use of the Object constructor
    'no-new-object': ERROR,
    // disallow space between function identifier and application
    'no-spaced-func': ERROR,
    // disallow the use of ternary operators
    'no-ternary': IGNORE,
    // disallow trailing whitespace at the end of lines
    'no-trailing-spaces': ERROR,
    // disallow dangling underscores in identifiers
    'no-underscore-dangle': IGNORE,
    // disallow the use of Boolean literals in conditional expressions
    'no-unneeded-ternary': IGNORE,
    // require or disallow padding inside curly braces
    'object-curly-spacing': IGNORE,
    // allow just one var statement per function
    'one-var': [ERROR, 'never'],
    // require assignment operator shorthand where possible or prohibit it entirely
    'operator-assignment': IGNORE,
    // enforce operators to be placed before or after line breaks
    'operator-linebreak': IGNORE,
    // enforce padding within blocks
    'padded-blocks': [ERROR, 'never'],
    // require quotes around object literal property names
    'quote-props': IGNORE,
    // specify whether double or single quotes should be used
    quotes: [ERROR, 'single', 'avoid-escape'],
    // require identifiers to match the provided regular expression
    'id-match': IGNORE,
    // enforce spacing before and after semicolons
    'semi-spacing': [ERROR, {
      before: false,
      after: true
    }],
    // require or disallow use of semicolons instead of ASI
    semi: [ERROR, 'always'],
    // sort variables within the same declaration block
    'sort-vars': IGNORE,
    // require a space after certain keywords
    'space-after-keywords': ERROR,
    // require or disallow space before blocks
    'space-before-blocks': ERROR,
    // require or disallow space before function opening parenthesis
    'space-before-function-paren': [ERROR, 'never'],
    // require or disallow spaces inside parentheses
    'space-in-parens': IGNORE,
    // require spaces around operators
    'space-infix-ops': ERROR,
    // require a space after return, throw, and case
    'space-return-throw-case': ERROR,
    // Require or disallow spaces before/after unary operators
    'space-unary-ops': IGNORE,
    // require or disallow a space immediately following the // or /* in a comment
    // @differ - Don't mark `/*eslint #{rule_name}:#{rule_args}*/` as an error.
    'spaced-comment': [ERROR, 'always', {
      line: {
        markers: ['/'],
        exceptions: ['-', '+']
      },
      block: {
        markers: ['!'],
        exceptions: ['*']
      }
    }],
    // require regex literals to be wrapped in parentheses
    'wrap-regex': 0
  }
};
<commit_msg>:shirt:<commit_after>var config = require('./config');
var ERROR = config.ERROR;
var WARNING = config.WARNING;
var IGNORE = config.IGNORE;

/**
 * ## Stylistic Issues
 *
 * These rules are purely matters of style and are quite subjective.
 *
 * @see http://eslint.org/docs/rules/#stylistic-issues
 */
module.exports = {
  rules: {
    // enforce spacing inside array brackets
    'array-bracket-spacing': IGNORE,
    // enforce one true brace style
    'brace-style': [ERROR, '1tbs', {
      allowSingleLine: true
    }],
    // require camel case names
    camelcase: [ERROR, {
      properties: 'never'
    }],
    // enforce spacing before and after comma
    'comma-spacing': [ERROR, {
      before: false,
      after: true
    }],
    // enforce one true comma style
    'comma-style': [ERROR, 'last'],
    // require or disallow padding inside computed properties
    'computed-property-spacing': IGNORE,
    // enforces consistent naming when capturing the current execution context
    'consistent-this': IGNORE,
    // enforce newline at the end of file, with no multiple empty lines
    'eol-last': ERROR,
    // require function expressions to have a name
    /**
     * @differ - This is for advanced debugging.
     */
    'func-names': IGNORE,
    // enforces use of function declarations or expressions
    'func-style': IGNORE,
    // this option enforces minimum and maximum identifier lengths (variable names, property names etc.)
    'id-length': [ERROR, {
      min: 0,
      properties: 'never'
    }],
    // this option sets a specific tab width for your code
    indent: [ERROR, 2, {
      SwitchCase: 1
    }],
    // specify whether double or single quotes should be used in JSX attributes
    'jsx-quotes': ERROR,
    // enforces spacing between keys and values in object literal properties
    'key-spacing': [ERROR, {
      beforeColon: false,
      afterColon: true
    }],
    // enforces empty lines around comments
    'lines-around-comment': IGNORE,
    // disallow mixed 'LF' and 'CRLF' as linebreaks
    'linebreak-style': IGNORE,
    // specify the maximum depth callbacks can be nested
    'max-nested-callbacks': IGNORE,
    // require a capital letter for constructors
    'new-cap': [ERROR, {
      newIsCap: true
    }],
    // disallow the omission of parentheses when invoking a constructor with no arguments
    'new-parens': IGNORE,
    // allow/disallow an empty newline after var statement
    'newline-after-var': IGNORE,
    // disallow use of the Array constructor
    'no-array-constructor': IGNORE,
    // disallow use of the continue statement
    'no-continue': IGNORE,
    // disallow comments inline after code
    'no-inline-comments': IGNORE,
    // disallow if as the only statement in an else block
    'no-lonely-if': WARNING,
    // disallow mixed spaces and tabs for indentation
    // @differ - Not ignored as your environment is most likely not properly configured!
    'no-mixed-spaces-and-tabs': ERROR,
    // disallow multiple empty lines
    'no-multiple-empty-lines': [ERROR, {
      max: 2
    }],
    // disallow nested ternary expressions
    // @differ - Yes, this may be brittle but sometimes brevity is preferable.
    'no-nested-ternary': WARNING,
    // disallow use of the Object constructor
    'no-new-object': ERROR,
    // disallow space between function identifier and application
    'no-spaced-func': ERROR,
    // disallow the use of ternary operators
    'no-ternary': IGNORE,
    // disallow trailing whitespace at the end of lines
    'no-trailing-spaces': ERROR,
    // disallow dangling underscores in identifiers
    'no-underscore-dangle': IGNORE,
    // disallow the use of Boolean literals in conditional expressions
    'no-unneeded-ternary': IGNORE,
    // require or disallow padding inside curly braces
    'object-curly-spacing': IGNORE,
    // allow just one var statement per function
    'one-var': [ERROR, 'never'],
    // require assignment operator shorthand where possible or prohibit it entirely
    'operator-assignment': IGNORE,
    // enforce operators to be placed before or after line breaks
    'operator-linebreak': IGNORE,
    // enforce padding within blocks
    'padded-blocks': [ERROR, 'never'],
    // require quotes around object literal property names
    'quote-props': IGNORE,
    // specify whether double or single quotes should be used
    quotes: [ERROR, 'single', 'avoid-escape'],
    // require identifiers to match the provided regular expression
    'id-match': IGNORE,
    // enforce spacing before and after semicolons
    'semi-spacing': [ERROR, {
      before: false,
      after: true
    }],
    // require or disallow use of semicolons instead of ASI
    semi: [ERROR, 'always'],
    // sort variables within the same declaration block
    'sort-vars': IGNORE,
    // require a space after certain keywords
    'space-after-keywords': ERROR,
    // require or disallow space before blocks
    'space-before-blocks': ERROR,
    // require or disallow space before function opening parenthesis
    'space-before-function-paren': [ERROR, 'never'],
    // require or disallow spaces inside parentheses
    'space-in-parens': IGNORE,
    // require spaces around operators
    'space-infix-ops': ERROR,
    // require a space after return, throw, and case
    'space-return-throw-case': ERROR,
    // Require or disallow spaces before/after unary operators
    'space-unary-ops': IGNORE,
    // require or disallow a space immediately following the // or /* in a comment
    // @differ - Don't mark `/*eslint #{rule_name}:#{rule_args}*/` as an error.
    'spaced-comment': [ERROR, 'always', {
      line: {
        markers: ['/'],
        exceptions: ['-', '+']
      },
      block: {
        markers: ['!'],
        exceptions: ['*']
      }
    }],
    // require regex literals to be wrapped in parentheses
    'wrap-regex': 0
  }
};
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/**
 * @fileoverview Representation of an enum.
 */

/**
 * @class
 * Base interface for all enum objects.
 * This class allows containers to use constants for fields that are usually
 * have a common set of values.
 * There are two main ways to use this class.
 *
 *

 * If your gadget just wants to display how much of a smoker someone is,
 * it can simply use:
 *

 *
 *
html = "This person smokes: " + person.getField('smoker').getValue();

 *
 *

 * This value field will be correctly set up by the container. This is a place
 * where the container can even localize the value for the gadget so that it
 * always shows the right thing.
 *

 *
 *

 * If your gadget wants to have some logic around the smoker
 * field it can use:
 *

 *
 *
if (person.getField('smoker').getKey() != "NO") { //gadget logic here }

 *
 *

 * Note:
 * The key may be null if the person's smoker field cannot be coerced
 * into one of the standard enum types.
 * The value, on the other hand, is never null.
 *

 *
 * @name opensocial.Enum
 */

/**
 * Base interface for all enum objects.
 *
 * @private
 * @constructor
 */
opensocial.Enum = function(key, displayValue) {
  this.key = key;
  this.displayValue = displayValue;
};

/**
 * Use this for logic within your gadget. If they key is null then the value
 * does not fit in the defined enums.
 *
 * @return {String} The enum's key. This should be one of the defined enums
 *     below.
 */
opensocial.Enum.prototype.getKey = function() {
  return this.key;
};

/**
 * The value of this enum. This will be a user displayable string. If the
 * container supports localization, the string will be localized.
 *
 * @return {String} The enum's value.
 */
opensocial.Enum.prototype.getDisplayValue = function() {
  return this.displayValue;
};

/**
 * @static
 * @class
 * The enum keys used by the smoker field.
 *
See also:
 *
 * opensocial.Person.Field.Smoker
 *

 *
 * @name opensocial.Enum.Smoker
 */
opensocial.Enum.Smoker = {
  /** @member opensocial.Enum.Smoker */
  NO : 'NO',
  /** @member opensocial.Enum.Smoker */
  YES : 'YES',
  /** @member opensocial.Enum.Smoker */
  SOCIALLY : 'SOCIALLY',
  /** @member opensocial.Enum.Smoker */
  OCCASIONALLY : 'OCCASIONALLY',
  /** @member opensocial.Enum.Smoker */
  REGULARLY : 'REGULARLY',
  /** @member opensocial.Enum.Smoker */
  HEAVILY : 'HEAVILY',
  /** @member opensocial.Enum.Smoker */
  QUITTING : 'QUITTING',
  /** @member opensocial.Enum.Smoker */
  QUIT : 'QUIT'
};

/**
 * @static
 * @class
 * The enum keys used by the drinker field.
 *
See also:
 *
 * opensocial.Person.Field.Drinker
 *

 *
 * @name opensocial.Enum.Drinker
 */
opensocial.Enum.Drinker = {
  /** @member opensocial.Enum.Drinker */
  NO : 'NO',
  /** @member opensocial.Enum.Drinker */
  YES : 'YES',
  /** @member opensocial.Enum.Drinker */
  SOCIALLY : 'SOCIALLY',
  /** @member opensocial.Enum.Drinker */
  OCCASIONALLY : 'OCCASIONALLY',
  /** @member opensocial.Enum.Drinker */
  REGULARLY : 'REGULARLY',
  /** @member opensocial.Enum.Drinker */
  HEAVILY : 'HEAVILY',
  /** @member opensocial.Enum.Drinker */
  QUITTING : 'QUITTING',
  /** @member opensocial.Enum.Drinker */
  QUIT : 'QUIT'
};

/**
 * @static
 * @class
 * The enum keys used by the gender field.
 *
See also:
 *
 * opensocial.Person.Field.Gender
 *

 *
 * @name opensocial.Enum.Gender
 */
opensocial.Enum.Gender = {
  /** @member opensocial.Enum.Gender */
  MALE : 'MALE',
  /** @member opensocial.Enum.Gender */
  FEMALE : 'FEMALE'
};
<commit_msg>Also added escaping to enum.js  (Forgot this one in the last commit)<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/**
 * @fileoverview Representation of an enum.
 */

/**
 * @class
 * Base interface for all enum objects.
 * This class allows containers to use constants for fields that are usually
 * have a common set of values.
 * There are two main ways to use this class.
 *
 *

 * If your gadget just wants to display how much of a smoker someone is,
 * it can simply use:
 *

 *
 *
html = "This person smokes: " + person.getField('smoker').getValue();

 *
 *

 * This value field will be correctly set up by the container. This is a place
 * where the container can even localize the value for the gadget so that it
 * always shows the right thing.
 *

 *
 *

 * If your gadget wants to have some logic around the smoker
 * field it can use:
 *

 *
 *
if (person.getField('smoker').getKey() != "NO") { //gadget logic here }

 *
 *

 * Note:
 * The key may be null if the person's smoker field cannot be coerced
 * into one of the standard enum types.
 * The value, on the other hand, is never null.
 *

 *
 * @name opensocial.Enum
 */

/**
 * Base interface for all enum objects.
 *
 * @private
 * @constructor
 */
opensocial.Enum = function(key, displayValue) {
  this.key = key;
  this.displayValue = displayValue;
};

/**
 * Use this for logic within your gadget. If they key is null then the value
 * does not fit in the defined enums.
 *
 * @return {String} The enum's key. This should be one of the defined enums
 *     below.
 */
opensocial.Enum.prototype.getKey = function() {
  return gadgets.util.escapeString(this.key);
};

/**
 * The value of this enum. This will be a user displayable string. If the
 * container supports localization, the string will be localized.
 *
 * @return {String} The enum's value.
 */
opensocial.Enum.prototype.getDisplayValue = function() {
  return gadgets.util.escapeString(this.displayValue);
};

/**
 * @static
 * @class
 * The enum keys used by the smoker field.
 *
See also:
 *
 * opensocial.Person.Field.Smoker
 *

 *
 * @name opensocial.Enum.Smoker
 */
opensocial.Enum.Smoker = {
  /** @member opensocial.Enum.Smoker */
  NO : 'NO',
  /** @member opensocial.Enum.Smoker */
  YES : 'YES',
  /** @member opensocial.Enum.Smoker */
  SOCIALLY : 'SOCIALLY',
  /** @member opensocial.Enum.Smoker */
  OCCASIONALLY : 'OCCASIONALLY',
  /** @member opensocial.Enum.Smoker */
  REGULARLY : 'REGULARLY',
  /** @member opensocial.Enum.Smoker */
  HEAVILY : 'HEAVILY',
  /** @member opensocial.Enum.Smoker */
  QUITTING : 'QUITTING',
  /** @member opensocial.Enum.Smoker */
  QUIT : 'QUIT'
};

/**
 * @static
 * @class
 * The enum keys used by the drinker field.
 *
See also:
 *
 * opensocial.Person.Field.Drinker
 *

 *
 * @name opensocial.Enum.Drinker
 */
opensocial.Enum.Drinker = {
  /** @member opensocial.Enum.Drinker */
  NO : 'NO',
  /** @member opensocial.Enum.Drinker */
  YES : 'YES',
  /** @member opensocial.Enum.Drinker */
  SOCIALLY : 'SOCIALLY',
  /** @member opensocial.Enum.Drinker */
  OCCASIONALLY : 'OCCASIONALLY',
  /** @member opensocial.Enum.Drinker */
  REGULARLY : 'REGULARLY',
  /** @member opensocial.Enum.Drinker */
  HEAVILY : 'HEAVILY',
  /** @member opensocial.Enum.Drinker */
  QUITTING : 'QUITTING',
  /** @member opensocial.Enum.Drinker */
  QUIT : 'QUIT'
};

/**
 * @static
 * @class
 * The enum keys used by the gender field.
 *
See also:
 *
 * opensocial.Person.Field.Gender
 *

 *
 * @name opensocial.Enum.Gender
 */
opensocial.Enum.Gender = {
  /** @member opensocial.Enum.Gender */
  MALE : 'MALE',
  /** @member opensocial.Enum.Gender */
  FEMALE : 'FEMALE'
};
<|endoftext|>


<commit_before>function InterpreterMethodFactory () {
  "use strict";
  this.CodePointer = CodePointer;
}

InterpreterMethodFactory
.callInterpreterMethod = function(interpreter, methodName, codePointer) {
  if(typeof interpreter[methodName] !== "function") {
    throw new Error(methodName + " is not a method of the interpreter");
  }
  return interpreter[methodName](codePointer, methodName);
};

InterpreterMethodFactory.preInstructionMaker =
function(interpreter, methodFactory, method, code, debuggingOrMethodName) {
  var v = {};

  if(code instanceof CodePointer) {
    v.isInternalCall = true;
    v.codePointer = code;
    v.methodName = debuggingOrMethodName;
    v.oldIndentation = v.codePointer.indentation;
    v.codePointer.indentation = v.oldIndentation+"  ";
  } else {
    v.isInternalCall = false;
    v.codePointer = new methodFactory.CodePointer(code, debuggingOrMethodName);
    v.methodName = methodFactory.nameOf(interpreter, method);
    v.codePointer.indentation = "";
  }

  v.codePointer.logParseStart(v.methodName);
  v.backup = v.codePointer.backup();

  return v;
};

InterpreterMethodFactory.postInstructionMaker =
function(v, interpreter, maybeInstruction) {

  if(!maybeInstruction){
    v.codePointer.restore(v.backup);
  }

  v.codePointer.logParseEnd(v.methodName, !!maybeInstruction);
  v.codePointer.indentation = v.oldIndentation;
  if(!v.isInternalCall) {
    if(!maybeInstruction) {
      throw new Error(v.codePointer.getParseErrorDescription());
    } else if(v.codePointer.getUnparsed() !== "") {
      throw new Error("Trailing code: '" + v.codePointer.getUnparsed() + "'.");
    }

  }

};

InterpreterMethodFactory.prototype
.makeMethod = function(instructionMaker) {
  "use strict";
  var methodFactory = this;
  var method = function(code, debuggingOrMethodName) {
    var v = InterpreterMethodFactory.preInstructionMaker(this, methodFactory,
    method, code, debuggingOrMethodName);

    var maybeInstruction;
    var heads = v.codePointer.heads[v.backup] =
        v.codePointer.heads[v.backup] || Object.create(null);
    if(heads[v.methodName]) {
      maybeInstruction = heads[v.methodName].cache;
      v.codePointer.restore(heads[v.methodName].end);
      heads[v.methodName].recursionDetected = true;
    } else {
      var head = heads[v.methodName] = {};
      v.codePointer.heads[v.backup] = Object.create(heads);
      maybeInstruction = instructionMaker(v.codePointer, this);
      if(head.recursionDetected) {
        var progress = true;
        while(progress && maybeInstruction) {
          head.cache = maybeInstruction;
          head.end = v.codePointer.backup();
          v.codePointer.heads[v.backup] = Object.create(heads);
          v.codePointer.restore(v.backup);
          maybeInstruction = instructionMaker(v.codePointer, this);
          progress = v.codePointer.backup() > head.end;
        }

        maybeInstruction = head.cache;
        v.codePointer.restore(head.end);
      }

      head.cache = maybeInstruction;
      head.end = v.codePointer.backup();
    }

    InterpreterMethodFactory.
        postInstructionMaker(v, this, maybeInstruction);

    return v.isInternalCall?maybeInstruction:maybeInstruction.call(this);
  };

  return method;
};

InterpreterMethodFactory.prototype
.nameOf = function(o, propertyValue) {
  for(var propertyName in o) {
    if(o[propertyName] === propertyValue) {
      return propertyName;
    }
  }
};

InterpreterMethodFactory.prototype
.atom = function(regExp, interpretationOrButNot) {
  "use strict";
  var that = this;
  var interpretation;
  var butNot;
  if(typeof interpretationOrButNot === "function") {
    interpretation = interpretationOrButNot;
  } else {
    butNot = interpretationOrButNot;
    interpretation = arguments[2];
  }

  return this.makeMethod(function(codePointer, interpreter) {
    var match = that
    .parseInsignificantAndToken(codePointer, regExp, interpreter);
    if(match === null) {
      return null;
    }

    var result = match[0];
    if(butNot && butNot.indexOf(result) > -1) {
      return null;
    }

    return function instruction() {
      return interpretation?interpretation.call(this, result):result;
    };

  });

};

InterpreterMethodFactory.prototype
.empty = function(interpretation) {
  "use strict";
  if(!interpretation) {
    throw new Error("The empty string atom should be called with a function");
  }

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    return interpretation;
  });

};

InterpreterMethodFactory.prototype
.group = function() {
  "use strict";
  var that = this;
  var partNames;
  var interpretation = arguments[arguments.length-1];
  if(interpretation instanceof Function) {
    partNames = Array.prototype.slice.call(arguments, 0, -1);
  } else {
    interpretation = null;
    partNames = Array.prototype.slice.call(arguments);
  }

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var partInstructions = [];
    for(var i = 0; i < partNames.length; i++) {
      var partName = partNames[i];
      if(typeof partName === "string") {
        var maybeInstruction = InterpreterMethodFactory
          .callInterpreterMethod(interpreter, partName, codePointer);
        if(!maybeInstruction){
          return null;
        }
        maybeInstruction.partName = partName;
        partInstructions.push(maybeInstruction);
      } else if(partName instanceof RegExp) {
        if(!that
            .parseInsignificantAndToken(codePointer, partName, interpreter)) {
          return null;
        }
      }
    }

    if(interpretation) {
      return function instruction() {
        return interpretation.apply(this, InterpreterMethodFactory
            .mapRunAsMethod(this, partInstructions));
      };
    } else {
      return function instruction() {
        var that = this;
        var mpo = new InterpreterMethodFactory.MultiPropertyObject();
        var result = {};
        partInstructions.map(function(pi) {
          mpo.appendProperty.call(result, pi.partName, pi.call(that));
        });

        return result;
      };
    }
  });

};

InterpreterMethodFactory.mapRunAsMethod = function(that, partInstructions) {
  return partInstructions.map(function(partInstruction) {
    return partInstruction.call(that);
  });

};

InterpreterMethodFactory.MultiPropertyObject = function() {
  var nameCount = Object.create(null);
  this.appendProperty = function(name, partResult) {
    var result = this;
    if(nameCount[name] === undefined) {
      nameCount[name] = 0;
    }

    if(nameCount[name] === 0) {
      this[name] = partResult;
    } else if(nameCount[name] === 1) {
      this[name] = [this[name], partResult];
    } else {
      this[name].push(partResult);
    }

    nameCount[name]++;
  };

};

InterpreterMethodFactory.prototype.select = function(index) {
  var factory = this;
  var partNames = Array.prototype.slice.call(arguments, 1);
  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var partInstructions = [];
    for(var i = 0; i < partNames.length; i++) {
      var partName = partNames[i];
      var maybeInstruction;
      if(typeof partName === "string") {
        maybeInstruction = InterpreterMethodFactory
          .callInterpreterMethod(interpreter, partName, codePointer);
      } else if(partName instanceof RegExp) {
        var regex = factory.parseInsignificantAndToken(
          codePointer, partName, interpreter);
        maybeInstruction = regex?factory.functionReturning(regex):null;
      }
      if(!maybeInstruction){
        return null;
      }
      partInstructions.push(maybeInstruction);
    }

    return index>0? partInstructions[index-1]:function instruction() {
        var that = this;
        var partResults = partInstructions.map(function(partInstruction) {
          return partInstruction.call(that);
        });

        return partResults;
      };

  });

};

InterpreterMethodFactory.prototype.wrap = function(partName, interpretation) {
  "use strict";
  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var maybeInstruction = InterpreterMethodFactory
        .callInterpreterMethod(interpreter, partName, codePointer);
    return !maybeInstruction?null:function instruction() {
      return interpretation.call(this, maybeInstruction.call(this));
    };

  });

};

InterpreterMethodFactory.prototype.functionReturning = function(value) {
  return function() {
    return value;
  };

};

InterpreterMethodFactory.prototype.or = function() {
  var alternativesNames = arguments;

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var maybeInstruction = null;
    var i = 0;
    while(!maybeInstruction && i < alternativesNames.length) {
      maybeInstruction = InterpreterMethodFactory
      .callInterpreterMethod(interpreter, alternativesNames[i++], codePointer);
    }

    return maybeInstruction;
  });
};

InterpreterMethodFactory.prototype.longest = function() {
  "use strict";
  var alternativesNames = Array.prototype.slice.call(arguments);

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var backup = codePointer.backup();
    var nullObject = {end:backup};
    var maybeInstruction = nullObject;
    alternativesNames.map(function(name) {
      codePointer.restore(backup);
      var partInstruction = InterpreterMethodFactory
          .callInterpreterMethod(interpreter, name, codePointer);
      if(codePointer.backup() > maybeInstruction.end) {
        maybeInstruction = partInstruction;
        maybeInstruction.end = codePointer.backup();
      }
    });

    codePointer.restore(maybeInstruction.end);

    return maybeInstruction===nullObject?null:maybeInstruction;
  });
};

InterpreterMethodFactory.prototype
.star = function(partName) {
  "use strict";
  var interpretation;
  var delimiter;
  var delimiterAndPart;
  if(arguments[1] instanceof Function) {
    interpretation = arguments[1];
  } else {
    delimiter = arguments[1];
    delimiterAndPart = this.group(delimiter, partName, function(partName) {
      return partName;
    });

    interpretation = arguments[2];
  }

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var partInstructions = [];
    var maybeInstruction = InterpreterMethodFactory
    .callInterpreterMethod(interpreter, partName, codePointer);
    while(maybeInstruction) {
      partInstructions.push(maybeInstruction);
      if(delimiter) {
        maybeInstruction =
        delimiterAndPart.call(interpreter, codePointer,
          delimiter + " and " + partName);
      } else {
        maybeInstruction = InterpreterMethodFactory
          .callInterpreterMethod(interpreter, partName, codePointer);
      }
    }

    return function instruction() {
      var that = this;
      var results = partInstructions.map(function(partInstruction) {
        return partInstruction.call(that);
      });

      return interpretation?interpretation.apply(this, results):results;
    };

  });

};

InterpreterMethodFactory.prototype
.plus = function(partName) {
  "use strict";
  var interpretation;
  var delimiter;
  var delimiterAndPart;
  if(arguments[1] instanceof Function) {
    interpretation = arguments[1];
  } else {
    delimiter = arguments[1];
    delimiterAndPart = this.group(delimiter, partName, function(partName) {
      return partName;
    });

    interpretation = arguments[2];
  }

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var partInstructions = [];
    var maybeInstruction = InterpreterMethodFactory
    .callInterpreterMethod(interpreter, partName, codePointer);
    if(!maybeInstruction) {
      return null;
    }

    while(maybeInstruction) {
      partInstructions.push(maybeInstruction);
      if(delimiter) {
        maybeInstruction =
        delimiterAndPart.call(interpreter, codePointer,
          delimiter + " and " + partName);
      } else {
        maybeInstruction = InterpreterMethodFactory
          .callInterpreterMethod(interpreter, partName, codePointer);
      }
    }

    return function instruction() {
      var that = this;
      var results = partInstructions.map(function(partInstruction) {
        return partInstruction.call(that);
      });

      return interpretation?interpretation.apply(this, results):results;
    };

  });

};

InterpreterMethodFactory.prototype
.opt = function(name, interpretation) {
  var defaultInterpretation = function() {
    return undefined;
  };

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var maybeInstruction = InterpreterMethodFactory
    .callInterpreterMethod(interpreter, name, codePointer);
    return maybeInstruction || interpretation || defaultInterpretation;
  });
};

InterpreterMethodFactory.prototype
.methodFactory = function(name) {
  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var instructionToDeferre = InterpreterMethodFactory
    .callInterpreterMethod(interpreter, name, codePointer);
    if(!instructionToDeferre) {
      return null;
    }

    return function instruction() {
      return instructionToDeferre;
    };

  });

};

InterpreterMethodFactory.prototype
.parseInsignificantAndToken = function(codePointer, token, interpreter) {
  if(!this.parseInsignificant(codePointer, interpreter)) {
    return null;
  }

  return codePointer.parse(token);
};

InterpreterMethodFactory.prototype
.parseInsignificant = function(codePointer, interpreter) {
  if(codePointer.insignificant instanceof RegExp) {
    return codePointer.parse(codePointer.insignificant);
  } else if(typeof codePointer.insignificant === "string"){
    var justInsignificantMethod = this.justInsignificant(undefined,
    codePointer.insignificant);
    return justInsignificantMethod
    .call(interpreter, codePointer, "(insignificant) " +
    codePointer.insignificant);
  } else {
    return true;
  }
};

InterpreterMethodFactory.prototype
.shiftInsignificant = function(insignificant, partName, codePointer,
interpreter) {
  var outerInsignificant = codePointer.insignificant;
  codePointer.insignificant = insignificant;
  var instruction = InterpreterMethodFactory
  .callInterpreterMethod(interpreter, partName, codePointer);
  if(!this.parseInsignificant(codePointer, interpreter)){
    instruction = null;
  }

  codePointer.insignificant = outerInsignificant;
  return instruction;
};

InterpreterMethodFactory.prototype
.justInsignificant = function(insignificant, partName) {
  "use strict";
  var that = this;

  return this.makeMethod(function(codePointer, interpreter) {
    var instruction = that.shiftInsignificant(insignificant, partName,
    codePointer, interpreter);
    return instruction;
  });
};

InterpreterMethodFactory.prototype
.insignificant = function(insignificant, partName) {
  "use strict";
  var that = this;

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var instruction;
    if(that.parseInsignificant(codePointer, interpreter)) {
      instruction = that.shiftInsignificant(insignificant, partName,
      codePointer, interpreter);
    }
    return instruction;
  });
};
<commit_msg>Stress testing Semantics! refactorization. <commit_after>function InterpreterMethodFactory () {
  "use strict";
  this.CodePointer = CodePointer;
}

InterpreterMethodFactory
.callInterpreterMethod = function(interpreter, methodName, codePointer) {
  if(typeof interpreter[methodName] !== "function") {
    throw new Error(methodName + " is not a method of the interpreter");
  }
  return interpreter[methodName](codePointer, methodName);
};

InterpreterMethodFactory.preInstructionMaker =
function(interpreter, methodFactory, method, code, debuggingOrMethodName) {
  var v = {};

  if(code instanceof CodePointer) {
    v.isInternalCall = true;
    v.codePointer = code;
    v.methodName = debuggingOrMethodName;
    v.oldIndentation = v.codePointer.indentation;
    v.codePointer.indentation = v.oldIndentation+"  ";
  } else {
    v.isInternalCall = false;
    v.codePointer = new methodFactory.CodePointer(code, debuggingOrMethodName);
    v.methodName = methodFactory.nameOf(interpreter, method);
    v.codePointer.indentation = "";
  }

  v.codePointer.logParseStart(v.methodName);
  v.backup = v.codePointer.backup();

  return v;
};

InterpreterMethodFactory.postInstructionMaker =
function(v, interpreter, maybeInstruction) {

  if(!maybeInstruction){
    v.codePointer.restore(v.backup);
  }

  v.codePointer.logParseEnd(v.methodName, !!maybeInstruction);
  v.codePointer.indentation = v.oldIndentation;
  if(!v.isInternalCall) {
    if(!maybeInstruction) {
      throw new Error(v.codePointer.getParseErrorDescription());
    } else if(v.codePointer.getUnparsed() !== "") {
      throw new Error("Trailing code: '" + v.codePointer.getUnparsed() + "'.");
    }

  }

};

InterpreterMethodFactory.prototype
.makeMethod = function(instructionMaker) {
  "use strict";
  var methodFactory = this;
  var method = function(code, debuggingOrMethodName) {
    var v = InterpreterMethodFactory.preInstructionMaker(this, methodFactory,
    method, code, debuggingOrMethodName);

    var maybeInstruction;
    var heads = v.codePointer.heads[v.backup] =
        v.codePointer.heads[v.backup] || Object.create(null);
    if(heads[v.methodName]) {
      maybeInstruction = heads[v.methodName].cache;
      v.codePointer.restore(heads[v.methodName].end);
      heads[v.methodName].recursionDetected = true;
    } else {
      var head = heads[v.methodName] = {};
      v.codePointer.heads[v.backup] = Object.create(heads);
      maybeInstruction = instructionMaker(v.codePointer, this);
      if(head.recursionDetected) {
        var progress = true;
        while(progress && maybeInstruction) {
          head.cache = maybeInstruction;
          head.end = v.codePointer.backup();
          v.codePointer.heads[v.backup] = Object.create(heads);
          v.codePointer.restore(v.backup);
          maybeInstruction = instructionMaker(v.codePointer, this);
          progress = v.codePointer.backup() > head.end;
        }

        maybeInstruction = head.cache;
        v.codePointer.restore(head.end);
      }

      head.cache = maybeInstruction;
      head.end = v.codePointer.backup();
    }

    InterpreterMethodFactory.
        postInstructionMaker(v, this, maybeInstruction);

    return v.isInternalCall?maybeInstruction:maybeInstruction.call(this);
  };

  return method;
};

InterpreterMethodFactory.prototype
.nameOf = function(o, propertyValue) {
  for(var propertyName in o) {
    if(o[propertyName] === propertyValue) {
      return propertyName;
    }
  }
};

InterpreterMethodFactory.prototype
.atom = function(regExp, interpretationOrButNot) {
  "use strict";
  var that = this;
  var interpretation;
  var butNot;
  if(typeof interpretationOrButNot === "function") {
    interpretation = interpretationOrButNot;
  } else {
    butNot = interpretationOrButNot;
    interpretation = arguments[2];
  }

  return this.makeMethod(function(codePointer, interpreter) {
    var match = that
    .parseInsignificantAndToken(codePointer, regExp, interpreter);
    if(match === null) {
      return null;
    }

    var result = match[0];
    if(butNot && butNot.indexOf(result) > -1) {
      return null;
    }

    return function instruction() {
      return interpretation?interpretation.call(this, result):result;
    };

  });

};

InterpreterMethodFactory.prototype
.empty = function(interpretation) {
  "use strict";
  if(!interpretation) {
    throw new Error("The empty string atom should be called with a function");
  }

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    return interpretation;
  });

};

InterpreterMethodFactory.prototype
.group = function() {
  "use strict";
  var that = this;
  var partNames;
  var interpretation = arguments[arguments.length-1];
  if(interpretation instanceof Function) {
    partNames = Array.prototype.slice.call(arguments, 0, -1);
  } else {
    interpretation = null;
    partNames = Array.prototype.slice.call(arguments);
  }

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var partInstructions = [];
    for(var i = 0; i < partNames.length; i++) {
      var partName = partNames[i];
      if(typeof partName === "string") {
        var maybeInstruction = InterpreterMethodFactory
          .callInterpreterMethod(interpreter, partName, codePointer);
        if(!maybeInstruction){
          return null;
        }
        maybeInstruction.partName = partName;
        partInstructions.push(maybeInstruction);
      } else if(partName instanceof RegExp) {
        if(!that
            .parseInsignificantAndToken(codePointer, partName, interpreter)) {
          return null;
        }
      }
    }

    if(interpretation) {
      return function instruction() {
        return interpretation.apply(this, InterpreterMethodFactory
            .mapRunAsMethod(this, partInstructions));
      };
    } else {
      return function instruction() {
        var that = this;
        var mpo = new InterpreterMethodFactory.MultiPropertyObject();
        var result = {};
        partInstructions.map(function(pi) {
          mpo.appendProperty.call(result, pi.partName, pi.call(that));
        });

        return result;
      };
    }
  });

};

InterpreterMethodFactory.mapRunAsMethod = function(that, partInstructions) {
  return partInstructions.map(function(partInstruction) {
    return partInstruction.call(that);
  });

};

InterpreterMethodFactory.MultiPropertyObject = function() {
  var nameCount = Object.create(null);
  this.appendProperty = function(name, partResult) {
    var result = this;
    if(nameCount[name] === undefined) {
      nameCount[name] = 0;
    }

    if(nameCount[name] === 0) {
      this[name] = partResult;
    } else if(nameCount[name] === 1) {
      this[name] = [this[name], partResult];
    } else {
      this[name].push(partResult);
    }

    nameCount[name]++;
  };

};

InterpreterMethodFactory.prototype.select = function(index) {
  var factory = this;
  var partNames = Array.prototype.slice.call(arguments, 1);
  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var partInstructions = [];
    for(var i = 0; i < partNames.length; i++) {
      var partName = partNames[i];
      var maybeInstruction;
      if(typeof partName === "string") {
        maybeInstruction = InterpreterMethodFactory
          .callInterpreterMethod(interpreter, partName, codePointer);
      } else if(partName instanceof RegExp) {
        var regex = factory.parseInsignificantAndToken(
          codePointer, partName, interpreter);
        maybeInstruction = regex?factory.functionReturning(regex):null;
      }
      if(!maybeInstruction){
        return null;
      }
      partInstructions.push(maybeInstruction);
    }

    return index>0? partInstructions[index-1]:function instruction() {
        var that = this;
        var partResults = partInstructions.map(function(partInstruction) {
          return partInstruction.call(that);
        });

        return partResults;
      };

  });

};

InterpreterMethodFactory.prototype.wrap = function(partName, interpretation) {
  "use strict";
  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var maybeInstruction = InterpreterMethodFactory
        .callInterpreterMethod(interpreter, partName, codePointer);
    return !maybeInstruction?null:function instruction() {
      return interpretation.call(this, maybeInstruction.call(this));
    };

  });

};

InterpreterMethodFactory.prototype.functionReturning = function(value) {
  return function() {
    return value;
  };

};

InterpreterMethodFactory.prototype.or = function() {
  var alternativesNames = arguments;

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var maybeInstruction = null;
    var i = 0;
    while(!maybeInstruction && i < alternativesNames.length) {
      maybeInstruction = InterpreterMethodFactory
      .callInterpreterMethod(interpreter, alternativesNames[i++], codePointer);
    }

    return maybeInstruction;
  });
};

InterpreterMethodFactory.prototype.longest = function() {
  "use strict";
  var alternativesNames = Array.prototype.slice.call(arguments);

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var backup = codePointer.backup();
    var nullObject = {end:backup};
    var maybeInstruction = nullObject;
    alternativesNames.map(function(name) {
      codePointer.restore(backup);
      var partInstruction = InterpreterMethodFactory
          .callInterpreterMethod(interpreter, name, codePointer);
      if(codePointer.backup() > maybeInstruction.end) {
        maybeInstruction = partInstruction;
        maybeInstruction.end = codePointer.backup();
      }
    });

    codePointer.restore(maybeInstruction.end);

    return maybeInstruction===nullObject?null:maybeInstruction;
  });
};

InterpreterMethodFactory.prototype
.star = function(partName) {
  "use strict";
  var interpretation;
  var delimiter;
  var delimiterAndPart;
  if(arguments[1] instanceof Function) {
    interpretation = arguments[1];
  } else {
    delimiter = arguments[1];
    delimiterAndPart = this.group(delimiter, partName, function(partName) {
      return partName;
    });

    interpretation = arguments[2];
  }

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var partInstructions = [];
    var maybeInstruction = InterpreterMethodFactory
    .callInterpreterMethod(interpreter, partName, codePointer);
    while(maybeInstruction) {
      partInstructions.push(maybeInstruction);
      if(delimiter) {
        maybeInstruction =
        delimiterAndPart.call(interpreter, codePointer,
          delimiter + " and " + partName);
      } else {
        maybeInstruction = InterpreterMethodFactory
          .callInterpreterMethod(interpreter, partName, codePointer);
      }
    }

    return function instruction() {
      var results = InterpreterMethodFactory
          .mapRunAsMethod(this, partInstructions);
      return interpretation?interpretation.apply(this, results):results;
    };

  });

};

InterpreterMethodFactory.prototype
.plus = function(partName) {
  "use strict";
  var interpretation;
  var delimiter;
  var delimiterAndPart;
  if(arguments[1] instanceof Function) {
    interpretation = arguments[1];
  } else {
    delimiter = arguments[1];
    delimiterAndPart = this.group(delimiter, partName, function(partName) {
      return partName;
    });

    interpretation = arguments[2];
  }

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var partInstructions = [];
    var maybeInstruction = InterpreterMethodFactory
    .callInterpreterMethod(interpreter, partName, codePointer);
    if(!maybeInstruction) {
      return null;
    }

    while(maybeInstruction) {
      partInstructions.push(maybeInstruction);
      if(delimiter) {
        maybeInstruction =
        delimiterAndPart.call(interpreter, codePointer,
          delimiter + " and " + partName);
      } else {
        maybeInstruction = InterpreterMethodFactory
          .callInterpreterMethod(interpreter, partName, codePointer);
      }
    }

    return function instruction() {
      var results = InterpreterMethodFactory
          .mapRunAsMethod(this, partInstructions);
      return interpretation?interpretation.apply(this, results):results;
    };

  });

};

InterpreterMethodFactory.prototype
.opt = function(name, interpretation) {
  var defaultInterpretation = function() {
    return undefined;
  };

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var maybeInstruction = InterpreterMethodFactory
    .callInterpreterMethod(interpreter, name, codePointer);
    return maybeInstruction || interpretation || defaultInterpretation;
  });
};

InterpreterMethodFactory.prototype
.methodFactory = function(name) {
  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var instructionToDeferre = InterpreterMethodFactory
    .callInterpreterMethod(interpreter, name, codePointer);
    if(!instructionToDeferre) {
      return null;
    }

    return function instruction() {
      return instructionToDeferre;
    };

  });

};

InterpreterMethodFactory.prototype
.parseInsignificantAndToken = function(codePointer, token, interpreter) {
  if(!this.parseInsignificant(codePointer, interpreter)) {
    return null;
  }

  return codePointer.parse(token);
};

InterpreterMethodFactory.prototype
.parseInsignificant = function(codePointer, interpreter) {
  if(codePointer.insignificant instanceof RegExp) {
    return codePointer.parse(codePointer.insignificant);
  } else if(typeof codePointer.insignificant === "string"){
    var justInsignificantMethod = this.justInsignificant(undefined,
    codePointer.insignificant);
    return justInsignificantMethod
    .call(interpreter, codePointer, "(insignificant) " +
    codePointer.insignificant);
  } else {
    return true;
  }
};

InterpreterMethodFactory.prototype
.shiftInsignificant = function(insignificant, partName, codePointer,
interpreter) {
  var outerInsignificant = codePointer.insignificant;
  codePointer.insignificant = insignificant;
  var instruction = InterpreterMethodFactory
  .callInterpreterMethod(interpreter, partName, codePointer);
  if(!this.parseInsignificant(codePointer, interpreter)){
    instruction = null;
  }

  codePointer.insignificant = outerInsignificant;
  return instruction;
};

InterpreterMethodFactory.prototype
.justInsignificant = function(insignificant, partName) {
  "use strict";
  var that = this;

  return this.makeMethod(function(codePointer, interpreter) {
    var instruction = that.shiftInsignificant(insignificant, partName,
    codePointer, interpreter);
    return instruction;
  });
};

InterpreterMethodFactory.prototype
.insignificant = function(insignificant, partName) {
  "use strict";
  var that = this;

  return this.makeMethod(function instructionMaker(codePointer, interpreter) {
    var instruction;
    if(that.parseInsignificant(codePointer, interpreter)) {
      instruction = that.shiftInsignificant(insignificant, partName,
      codePointer, interpreter);
    }
    return instruction;
  });
};
<|endoftext|>


<commit_before>
ElmRuntime.Render.Collage = function() {
'use strict';

var Render = ElmRuntime.use(ElmRuntime.Render.Element);
var Matrix = Elm.Matrix2D({});
var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
var newElement = Utils.newElement,
    extract = Utils.extract, fromList = Utils.fromList,
    fromString = Utils.fromString, addTransform = Utils.addTransform;

function trace(ctx, path) {
    var points = fromList(path);
    var i = points.length - 1;
    if (i <= 0) return;
    ctx.moveTo(points[i]._0, points[i]._1);
    while (i--) { ctx.lineTo(points[i]._0, points[i]._1); }
    if (path.closed) {
        i = points.length - 1;
        ctx.lineTo(points[i]._0, points[i]._1);
    }
}

function line(ctx,style,path) {
    style.dashing.ctor === 'Nil' ? trace(ctx, path) : customLineHelp(ctx, style, path);
    ctx.stroke();
}

function customLineHelp(ctx, style, path) {
    var points = fromList(path);
    if (path.closed) points.push(points[0]);
    var pattern = fromList(style.dashing);
    var i = points.length - 1;
    if (i <= 0) return;
    var x0 = points[i]._0, y0 = points[i]._1;
    var x1=0, y1=0, dx=0, dy=0, remaining=0, nx=0, ny=0;
    var pindex = 0, plen = pattern.length;
    var draw = true, segmentLength = pattern[0];
    ctx.moveTo(x0,y0);
    while (i--) {
        x1 = points[i]._0; y1 = points[i]._1;
        dx = x1 - x0; dy = y1 - y0;
        remaining = Math.sqrt(dx * dx + dy * dy);
        while (segmentLength <= remaining) {
            x0 += dx * segmentLength / remaining;
            y0 += dy * segmentLength / remaining;
            ctx[draw ? 'lineTo' : 'moveTo'](x0, y0);
            // update starting position
            dx = x1 - x0; dy = y1 - y0;
            remaining = Math.sqrt(dx * dx + dy * dy);
            // update pattern
            draw = !draw;
            pindex = (pindex + 1) % plen;
            segmentLength = pattern[pindex];
        }
        if (remaining > 0) {
            ctx[draw ? 'lineTo' : 'moveTo'](x1, y1);
            segmentLength -= remaining;
        }
        x0 = x1; y0 = y1;
    }
}

function drawLine(ctx, style, path) {
    ctx.lineWidth = style.width;
    ctx.lineCap = style.cap.ctor.toLowerCase();
    var join = style.join.ctor;
    ctx.lineJoin = join === 'Smooth' ? 'round' :
                   join === 'Sharp' ? 'miter' : 'bevel';
    ctx.miterLimit = style.miterLimit;
    ctx.strokeStyle = extract(style.color);
    return line(ctx, style, path);
}

function texture(redo, ctx, src) {
    var img = new Image();
    img.src = fromString(src);
    img.onload = redo;
    return ctx.createPattern(img, 'repeat');
}

function gradient(ctx, grad) {
  var g;
  var stops = [];
  if (grad.ctor === 'Linear') {
    var p0 = grad._0, p1 = grad._1;
    g = ctx.createLinearGradient(p0._0, p0._1, p1._0, p1._1);
    stops = fromList(grad._2);
  } else {
    var p0 = grad._0, p2 = grad._2;
    g = ctx.createRadialGradient(p0._0, p0._1, grad._1, p2._0, p2._1, grad._3);
    stops = fromList(grad._4);
  }
  var len = stops.length;
  for (var i = 0; i < len; ++i) {
    var stop = stops[i];
    g.addColorStop(stop._0, extract(stop._1));
  }
  return g;
}

function drawShape(redo, ctx, style, path) {
    trace(ctx, path);
    var sty = style.ctor;
    ctx.fillStyle =
        sty === 'Solid' ? extract(style._0) :
        sty === 'Texture' ? texture(redo, ctx, style._0) : gradient(ctx, style._0);
    ctx.fill();
}

function drawImage(redo, ctx, form) {
    var img = new Image();
    img.onload = redo;
    img.src = fromString(form._3);
    var w = form._0,
        h = form._1,
        pos = form._2,
        srcX = pos._0,
        srcY = pos._1,
        srcW = w,
        srcH = h,
        destX = -w/2,
        destY = -h/2,
        destW = w,
        destH = h;

    ctx.drawImage(img, srcX, srcY, srcW, srcH, destX, destY, destW, destH);
}

function renderForm(redo, ctx, form) {
    ctx.save();
    var x = form.x, y = form.y, theta = form.theta, scale = form.scale;
    if (x !== 0 || y !== 0) ctx.translate(x, y);
    if (theta !== 0) ctx.rotate(theta);
    ctx.scale(scale,-scale);
    ctx.beginPath();
    var f = form.form;
    switch(f.ctor) {
    case 'FPath' : drawLine(ctx, f._0, f._1); break;
    case 'FImage': drawImage(redo, ctx, f); break;
    case 'FShape':
	if (f._0.ctor === 'Left') {
	    f._1.closed = true;
	    drawLine(ctx, f._0._0, f._1);
	} else {
            drawShape(redo, ctx, f._0._0, f._1);
        }
	break;
    }
    ctx.restore();
}

function formToMatrix(form) {
   var scale = form.scale;
   var matrix = A6( Matrix.matrix, scale, 0, 0, scale, scale * form.x, scale * form.y );

   var theta = form.theta
   if (theta !== 0) matrix = A2( Matrix.rotate, theta, matrix );

   return matrix;
}

function makeTransform(w, h, form, matrices) {
    var props = form.form._0.props;
    var m = A6( Matrix.matrix, 1, 0, 0, 1,
                (w - props.width)/2,
                (h - props.height)/2 );
    var len = matrices.length;
    for (var i = 0; i < len; ++i) { m = A2( Matrix.multiply, m, matrices[i] ); }
    m = A2( Matrix.multiply, m, formToMatrix(form) );

    return 'matrix(' +   m[0]  + ',' +   m[3]  + ',' +
                       (-m[1]) + ',' + (-m[4]) + ',' +
                         m[2]  + ',' +   m[5]  + ')';
}

function stepperHelp(list) {
    var arr = fromList(list);
    var i = 0;
    function peekNext() {
        return i < arr.length ? arr[i].form.ctor : '';
    }
    // assumes that there is a next element
    function next() {
        var out = arr[i];
        ++i;
        return out;
    }
    return { peekNext:peekNext, next:next };
}

function stepper(forms) {
    var ps = [stepperHelp(forms)];
    var matrices = [];
    function peekNext() {
        var len = ps.length;
        var formType = '';
        for (var i = 0; i < len; ++i ) {
            if (formType = ps[i].peekNext()) return formType;
        }
        return '';
    }
    // assumes that there is a next element
    function next(ctx) {
        while (!ps[0].peekNext()) { ps.shift(); matrices.pop(); ctx.restore(); }
        var out = ps[0].next();
        var f = out.form;
        if (f.ctor === 'FGroup') {
            ps.unshift(stepperHelp(f._1));
            var m = A2( Matrix.multiply, f._0, formToMatrix(out));
            ctx.save();
            ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]);
            matrices.push(m);
        }
        return out;
    }
    function transforms() { return matrices; }
    return { peekNext:peekNext, next:next, transforms:transforms };
}

function makeCanvas(w,h) {
    var canvas = newElement('canvas');
    canvas.style.width  = w + 'px';
    canvas.style.height = h + 'px';
    canvas.style.display = "block";
    canvas.style.position = "absolute";
    canvas.width  = w;
    canvas.height = h;
    return canvas;
}

function render(model) {
    var div = newElement('div');
    update(div, model, model);
    return div;
}

function updateTracker(w,h,div) {
    var kids = div.childNodes;
    var i = 0;
    function transform(transforms, ctx) {
        ctx.translate(w/2, h/2);
        var len = transforms.length;
        for (var i = 0; i < len; ++i) {
            var m = transforms[i];
            ctx.save();
            ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]);
        }
        return ctx;
    }
    function getContext(transforms) {
        while (i < kids.length) {
            var node = kids[i++];
            if (node.getContext) {
                node.width = w;
                node.height = h;
                node.style.width = w + 'px';
                node.style.height = h + 'px';
                return transform(transforms, node.getContext('2d'));
            }
            div.removeChild(node);
        }
        var canvas = makeCanvas(w,h);
        div.appendChild(canvas);
        // we have added a new node, so we must step our position
        ++i;
        return transform(transforms, canvas.getContext('2d'));
    }
    function element(matrices, form) {
        var container = kids[i];
        if (!container || container.getContext) {
            container = newElement('div');
            container.style.overflow = 'hidden';
            container.style.position = 'absolute';
            addTransform(container.style, 'scaleY(-1)');
            if (!container) {
                div.appendChild(container);
            } else {
                div.insertBefore(container, kids[i]);
            }
        }
        // we have added a new node, so we must step our position
        ++i;

        container.style.width = w + 'px';
        container.style.height = h + 'px';

        var elem = form.form._0;
        var node = container.firstChild;
        if (node) {
            Render.update(node, node.oldElement, elem);
        } else {
            node = Render.render(elem);
            container.appendChild(node);
        }
        node.oldElement = elem;
        addTransform(node.style, makeTransform(w, h, form, matrices));
    }
    return { getContext:getContext, element:element };
}

function update(div, _, model) {
    var w = model.w;
    var h = model.h;
    div.style.width = w + 'px';
    div.style.height = h + 'px';
    if (model.forms.ctor === 'Nil') {
        while (div.hasChildNodes()) {
            div.removeChild(div.lastChild);
        }
    }
    var stpr = stepper(model.forms);
    var tracker = updateTracker(w,h,div);
    var ctx = null;
    var formType = '';

    while (formType = stpr.peekNext()) {
        if (ctx === null && formType !== 'FElement') {
            ctx = tracker.getContext(stpr.transforms());
            ctx.scale(1,-1);
        }
        var form = stpr.next(ctx);
        if (formType === 'FElement') {
            tracker.element(stpr.transforms(), form);
            ctx = null;
        } else if (formType !== 'FGroup') {
            renderForm(function() { update(div, model, model); }, ctx, form);
        }
    }
    return div;
}

return { render:render, update:update };

};
<commit_msg>Change the names of line caps and joins.<commit_after>
ElmRuntime.Render.Collage = function() {
'use strict';

var Render = ElmRuntime.use(ElmRuntime.Render.Element);
var Matrix = Elm.Matrix2D({});
var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
var newElement = Utils.newElement,
    extract = Utils.extract, fromList = Utils.fromList,
    fromString = Utils.fromString, addTransform = Utils.addTransform;

function trace(ctx, path) {
    var points = fromList(path);
    var i = points.length - 1;
    if (i <= 0) return;
    ctx.moveTo(points[i]._0, points[i]._1);
    while (i--) { ctx.lineTo(points[i]._0, points[i]._1); }
    if (path.closed) {
        i = points.length - 1;
        ctx.lineTo(points[i]._0, points[i]._1);
    }
}

function line(ctx,style,path) {
    style.dashing.ctor === 'Nil' ? trace(ctx, path) : customLineHelp(ctx, style, path);
    ctx.stroke();
}

function customLineHelp(ctx, style, path) {
    var points = fromList(path);
    if (path.closed) points.push(points[0]);
    var pattern = fromList(style.dashing);
    var i = points.length - 1;
    if (i <= 0) return;
    var x0 = points[i]._0, y0 = points[i]._1;
    var x1=0, y1=0, dx=0, dy=0, remaining=0, nx=0, ny=0;
    var pindex = 0, plen = pattern.length;
    var draw = true, segmentLength = pattern[0];
    ctx.moveTo(x0,y0);
    while (i--) {
        x1 = points[i]._0; y1 = points[i]._1;
        dx = x1 - x0; dy = y1 - y0;
        remaining = Math.sqrt(dx * dx + dy * dy);
        while (segmentLength <= remaining) {
            x0 += dx * segmentLength / remaining;
            y0 += dy * segmentLength / remaining;
            ctx[draw ? 'lineTo' : 'moveTo'](x0, y0);
            // update starting position
            dx = x1 - x0; dy = y1 - y0;
            remaining = Math.sqrt(dx * dx + dy * dy);
            // update pattern
            draw = !draw;
            pindex = (pindex + 1) % plen;
            segmentLength = pattern[pindex];
        }
        if (remaining > 0) {
            ctx[draw ? 'lineTo' : 'moveTo'](x1, y1);
            segmentLength -= remaining;
        }
        x0 = x1; y0 = y1;
    }
}

function drawLine(ctx, style, path) {
    ctx.lineWidth = style.width;
    var cap = style.cap.ctor;
    ctx.lineCap = cap === 'Flat' ? 'butt' :
                  cap === 'Round' ? 'round' : 'square';
    var join = style.join.ctor;
    ctx.lineJoin = join === 'Smooth' ? 'round' :
                   join === 'Sharp' ? 'miter' : 'bevel';
    ctx.miterLimit = style.join._0 || 10;
    ctx.strokeStyle = extract(style.color);
    return line(ctx, style, path);
}

function texture(redo, ctx, src) {
    var img = new Image();
    img.src = fromString(src);
    img.onload = redo;
    return ctx.createPattern(img, 'repeat');
}

function gradient(ctx, grad) {
  var g;
  var stops = [];
  if (grad.ctor === 'Linear') {
    var p0 = grad._0, p1 = grad._1;
    g = ctx.createLinearGradient(p0._0, p0._1, p1._0, p1._1);
    stops = fromList(grad._2);
  } else {
    var p0 = grad._0, p2 = grad._2;
    g = ctx.createRadialGradient(p0._0, p0._1, grad._1, p2._0, p2._1, grad._3);
    stops = fromList(grad._4);
  }
  var len = stops.length;
  for (var i = 0; i < len; ++i) {
    var stop = stops[i];
    g.addColorStop(stop._0, extract(stop._1));
  }
  return g;
}

function drawShape(redo, ctx, style, path) {
    trace(ctx, path);
    var sty = style.ctor;
    ctx.fillStyle =
        sty === 'Solid' ? extract(style._0) :
        sty === 'Texture' ? texture(redo, ctx, style._0) : gradient(ctx, style._0);
    ctx.fill();
}

function drawImage(redo, ctx, form) {
    var img = new Image();
    img.onload = redo;
    img.src = fromString(form._3);
    var w = form._0,
        h = form._1,
        pos = form._2,
        srcX = pos._0,
        srcY = pos._1,
        srcW = w,
        srcH = h,
        destX = -w/2,
        destY = -h/2,
        destW = w,
        destH = h;

    ctx.drawImage(img, srcX, srcY, srcW, srcH, destX, destY, destW, destH);
}

function renderForm(redo, ctx, form) {
    ctx.save();
    var x = form.x, y = form.y, theta = form.theta, scale = form.scale;
    if (x !== 0 || y !== 0) ctx.translate(x, y);
    if (theta !== 0) ctx.rotate(theta);
    ctx.scale(scale,-scale);
    ctx.beginPath();
    var f = form.form;
    switch(f.ctor) {
    case 'FPath' : drawLine(ctx, f._0, f._1); break;
    case 'FImage': drawImage(redo, ctx, f); break;
    case 'FShape':
	if (f._0.ctor === 'Left') {
	    f._1.closed = true;
	    drawLine(ctx, f._0._0, f._1);
	} else {
            drawShape(redo, ctx, f._0._0, f._1);
        }
	break;
    }
    ctx.restore();
}

function formToMatrix(form) {
   var scale = form.scale;
   var matrix = A6( Matrix.matrix, scale, 0, 0, scale, scale * form.x, scale * form.y );

   var theta = form.theta
   if (theta !== 0)
       matrix = A2( Matrix.multiply, Matrix.rotation(theta), matrix );

   return matrix;
}

function makeTransform(w, h, form, matrices) {
    var props = form.form._0.props;
    var m = A6( Matrix.matrix, 1, 0, 0, 1,
                (w - props.width)/2,
                (h - props.height)/2 );
    var len = matrices.length;
    for (var i = 0; i < len; ++i) { m = A2( Matrix.multiply, m, matrices[i] ); }
    m = A2( Matrix.multiply, m, formToMatrix(form) );

    return 'matrix(' +   m[0]  + ',' +   m[3]  + ',' +
                       (-m[1]) + ',' + (-m[4]) + ',' +
                         m[2]  + ',' +   m[5]  + ')';
}

function stepperHelp(list) {
    var arr = fromList(list);
    var i = 0;
    function peekNext() {
        return i < arr.length ? arr[i].form.ctor : '';
    }
    // assumes that there is a next element
    function next() {
        var out = arr[i];
        ++i;
        return out;
    }
    return { peekNext:peekNext, next:next };
}

function stepper(forms) {
    var ps = [stepperHelp(forms)];
    var matrices = [];
    function peekNext() {
        var len = ps.length;
        var formType = '';
        for (var i = 0; i < len; ++i ) {
            if (formType = ps[i].peekNext()) return formType;
        }
        return '';
    }
    // assumes that there is a next element
    function next(ctx) {
        while (!ps[0].peekNext()) { ps.shift(); matrices.pop(); ctx.restore(); }
        var out = ps[0].next();
        var f = out.form;
        if (f.ctor === 'FGroup') {
            ps.unshift(stepperHelp(f._1));
            var m = A2( Matrix.multiply, f._0, formToMatrix(out));
            ctx.save();
            ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]);
            matrices.push(m);
        }
        return out;
    }
    function transforms() { return matrices; }
    return { peekNext:peekNext, next:next, transforms:transforms };
}

function makeCanvas(w,h) {
    var canvas = newElement('canvas');
    canvas.style.width  = w + 'px';
    canvas.style.height = h + 'px';
    canvas.style.display = "block";
    canvas.style.position = "absolute";
    canvas.width  = w;
    canvas.height = h;
    return canvas;
}

function render(model) {
    var div = newElement('div');
    update(div, model, model);
    return div;
}

function updateTracker(w,h,div) {
    var kids = div.childNodes;
    var i = 0;
    function transform(transforms, ctx) {
        ctx.translate(w/2, h/2);
        var len = transforms.length;
        for (var i = 0; i < len; ++i) {
            var m = transforms[i];
            ctx.save();
            ctx.transform(m[0], m[3], m[1], m[4], m[2], m[5]);
        }
        return ctx;
    }
    function getContext(transforms) {
        while (i < kids.length) {
            var node = kids[i++];
            if (node.getContext) {
                node.width = w;
                node.height = h;
                node.style.width = w + 'px';
                node.style.height = h + 'px';
                return transform(transforms, node.getContext('2d'));
            }
            div.removeChild(node);
        }
        var canvas = makeCanvas(w,h);
        div.appendChild(canvas);
        // we have added a new node, so we must step our position
        ++i;
        return transform(transforms, canvas.getContext('2d'));
    }
    function element(matrices, form) {
        var container = kids[i];
        if (!container || container.getContext) {
            container = newElement('div');
            container.style.overflow = 'hidden';
            container.style.position = 'absolute';
            addTransform(container.style, 'scaleY(-1)');
            if (!container) {
                div.appendChild(container);
            } else {
                div.insertBefore(container, kids[i]);
            }
        }
        // we have added a new node, so we must step our position
        ++i;

        container.style.width = w + 'px';
        container.style.height = h + 'px';

        var elem = form.form._0;
        var node = container.firstChild;
        if (node) {
            Render.update(node, node.oldElement, elem);
        } else {
            node = Render.render(elem);
            container.appendChild(node);
        }
        node.oldElement = elem;
        addTransform(node.style, makeTransform(w, h, form, matrices));
    }
    return { getContext:getContext, element:element };
}

function update(div, _, model) {
    var w = model.w;
    var h = model.h;
    div.style.width = w + 'px';
    div.style.height = h + 'px';
    if (model.forms.ctor === 'Nil') {
        while (div.hasChildNodes()) {
            div.removeChild(div.lastChild);
        }
    }
    var stpr = stepper(model.forms);
    var tracker = updateTracker(w,h,div);
    var ctx = null;
    var formType = '';

    while (formType = stpr.peekNext()) {
        if (ctx === null && formType !== 'FElement') {
            ctx = tracker.getContext(stpr.transforms());
            ctx.scale(1,-1);
        }
        var form = stpr.next(ctx);
        if (formType === 'FElement') {
            tracker.element(stpr.transforms(), form);
            ctx = null;
        } else if (formType !== 'FGroup') {
            renderForm(function() { update(div, model, model); }, ctx, form);
        }
    }
    return div;
}

return { render:render, update:update };

};
<|endoftext|>