<commit_before>'use strict';
var path = require('path');
var child_process = require('child_process');

/**
 * @constructor
 */
function ChangeLog(opt_options) {
  opt_options = opt_options || {};

  this.cwd = path.resolve(process.cwd(), opt_options.cwd || '');

  this.since = opt_options.since || '--tags';

  this.commitURL = opt_options.commitURL || '<commit-url>';
  this.pullRequestURL = opt_options.pullRequestURL || '<pr-url>';

  this.group = opt_options.group || false;
  this.author = opt_options.author || false;
  this.link = opt_options.link || false;
  this.merge = opt_options.merge || false;

  this._subjectRE = /(subject":)((".*"),"author")/;
  this._bodyRE = /("body":)(".*")\}/;
  this._scopeRE = /^([a-zA-Z0-9]+[a-zA-Z0-9\/\._-]*)(?:,\s[a-zA-Z0-9]+[a-zA-Z0-9\/\._-]*)*:/;
  this._format = '{"hash":"%H","time":%at,"subject":"%s","author":{"name":"%an","email":"%ae"},"body":"%b"}';
}
module.exports = ChangeLog;

ChangeLog.prototype.getDate = function(commitish, callback) {
  var cmd = 'git show -s --format=%ad `git rev-list --max-count=1 ' + commitish + '`';

  child_process.exec(cmd, {
    cwd: this.cwd
  }, function(err, stdout) {
    if (err) {
      return callback(err);
    }
    var date = stdout.trim();

    callback(null, date);
  });
};

ChangeLog.prototype.getLog = function(since, callback) {
  var self = this;
  var subst_, cmd = 'git log --format=\'' + this._format + '\'';

  if (since) {
    cmd += ' --since="' + since + '"';
  }

  child_process.exec(cmd, {
    cwd: this.cwd
  }, function(err, stdout) {
    if (err) {
      return callback(err);
    }

    var i, commit, subject, matches;
    var commits = [];
    var raw = stdout
        .substr(1)
        .trim()
        .replace(/\n/g, '\\n')
        .replace(/\t/g, '\\t')
        .split('}\\n{');

    raw.pop(); // remove limiting commit AND closing curly

    for (i = 0; i < raw.length; ++i) {
      raw[i] = '{' + raw[i] + '}';

      matches = raw[i].match(self._subjectRE);
      if (matches) {
        subst_ = matches[2].substr(1, matches[2].length - 11); // cut off ',"author"'
        subst_ = subst_.replace(/"/g, '\\"');
        subst_ = '"' + subst_ + '"';

        raw[i] = raw[i].replace('subject":' + matches[3], 'subject":' + subst_);
      }

      matches = raw[i].match(self._bodyRE);
      if (matches) {
        subst_ = matches[2].substr(1, matches[2].length - 2); // cut off '"'
        subst_ = subst_.replace(/"/g, '\\"');
        subst_ = '"' + subst_ + '"';

        raw[i] = raw[i].replace('body":' + matches[2], 'body":' + subst_);
      }

      try {
        commit = JSON.parse(raw[i]);
      } catch (err) {
        // TODO: propagate error
        continue;
      }

      subject = commit.subject;

      if (subject.toLowerCase().indexOf('working on') > -1 ||
          !self.merge && subject.substr(0, 5) === 'Merge') {
        continue;
      }

      // detect scopes
      matches = subject.match(self._scopeRE);

      if (matches) {
        commit.scope = subject.substr(0, matches[0].length - 1);
        commit.subject = subject.substr(matches[0].length).trim();
      }

      // detect semver tags
      if (commit.body && commit.body.indexOf('SEMVER-MAJOR') > -1) {
        commit.semver = 'SEMVER-MAJOR';

      } else if (commit.body && commit.body.indexOf('SEMVER-MINOR') > -1) {
        commit.semver = 'SEMVER-MINOR';
      }

      commits.push(commit);
    }

    callback(null, commits);
  });
};

ChangeLog.prototype._sortByScope = function(a, b) {
  if (a.scope > b.scope) {
    return 1;
  } else if (a.scope < b.scope) {
    return -1;
  } else {
    if (a.time > b.time) {
      return -1;
    } else {
      return 1;
    }
  }
};

ChangeLog.prototype.toMarkdown = function(commits) {
  var i, commit, md;
  var markdown = [];

  if (this.group) {
    commits.sort(this._sortByScope);
  }

  for (i = 0; i < commits.length; ++i) {
    commit = commits[i];

    if (this.link) {
      md = '[[`' + commit.hash.substr(0, 10) + '`](' +
          this.commitURL + '/' + commit.hash + ')] - ';
    } else {
      md = '[`' + commit.hash.substr(0, 10) + '`] - ';
    }

    if (commit.scope || commit.semver) {
      md += '**';

      if (commit.semver) {
        md += '(' + commit.semver + ')';

        if (commit.scope) {
          md += ' ';
        }
      }
      if (commit.scope) {
        md += commit.scope;
      }

      md += '**';

      if (commit.scope) {
        md += ': ';
      }
    }

    md += commit.subject
        .replace(/([\[\]])/g, '\\$1');

    if (this.author) {
      md += ' (' + commit.author.name + ')';
    }

    markdown.push(md);
  }

  return markdown;
};
<commit_msg>lib: working on windows support<commit_after>'use strict';
var path = require('path');
var child_process = require('child_process');

/**
 * @constructor
 */
function ChangeLog(opt_options) {
  opt_options = opt_options || {};

  this.cwd = path.resolve(process.cwd(), opt_options.cwd || '');

  this.since = opt_options.since || '--tags';

  this.commitURL = opt_options.commitURL || '<commit-url>';
  this.pullRequestURL = opt_options.pullRequestURL || '<pr-url>';

  this.group = opt_options.group || false;
  this.author = opt_options.author || false;
  this.link = opt_options.link || false;
  this.merge = opt_options.merge || false;

  this._subjectRE = /(subject":)((".*"),"author")/;
  this._bodyRE = /("body":)(".*")\}/;
  this._scopeRE = /^([a-zA-Z0-9]+[a-zA-Z0-9\/\._-]*)(?:,\s[a-zA-Z0-9]+[a-zA-Z0-9\/\._-]*)*:/;
  this._format = '{"hash":"%H","time":%at,"subject":"%s","author":{"name":"%an","email":"%ae"},"body":"%b"}';
}
module.exports = ChangeLog;

ChangeLog.prototype.getDate = function(commitish, callback) {

  var self = this;
  var cmdGitRevList = 'git rev-list --max-count=1 ' + commitish + '';

  child_process.exec(cmdGitRevList, {
    cwd: self.cwd
  }, function(err1, revList) {
    if (err1) {
      return callback(err1);
    }

    var cmd = 'git show -s --format=%ad ' + revList;
    child_process.exec(cmd, {
      cwd: self.cwd
    }, function(err2, stdout) {
      if (err2) {
        return callback(err2);
      }
      var date = stdout.trim();

      callback(null, date);
    });

  });

};

ChangeLog.prototype.getLog = function(since, callback) {
  var self = this;
  var subst_, cmd = 'git log --format="' + this._format.replace(/"/g, '\\"') + '"';
  if (since) {
    cmd += ' --since="' + since + '"';
  }
  child_process.exec(cmd, {
    cwd: this.cwd
  }, function(err, stdout) {
    if (err) {
      return callback(err);
    }
    var i, commit, subject, matches;
    var commits = [];
    var raw = stdout
        .substr(1)
        .trim()
        .replace(/\n/g, '\\n')
        .replace(/\t/g, '\\t')
        .split('}\\n{');
    raw.pop(); // remove limiting commit AND closing curly
    for (i = 0; i < raw.length; ++i) {
      raw[i] = '{' + raw[i] + '}';

      matches = raw[i].match(self._subjectRE);
      if (matches) {
        subst_ = matches[2].substr(1, matches[2].length - 11); // cut off ',"author"'
        subst_ = subst_.replace(/"/g, '\\"');
        subst_ = '"' + subst_ + '"';

        raw[i] = raw[i].replace('subject":' + matches[3], 'subject":' + subst_);
      }
      matches = raw[i].match(self._bodyRE);
      if (matches) {
        subst_ = matches[2].substr(1, matches[2].length - 2); // cut off '"'
        subst_ = subst_.replace(/"/g, '\\"');
        subst_ = '"' + subst_ + '"';

        raw[i] = raw[i].replace('body":' + matches[2], 'body":' + subst_);
      }

      try {
        commit = JSON.parse(raw[i]);
      } catch (err) {
        // TODO: propagate error
        continue;
      }

      subject = commit.subject;

      if (subject.toLowerCase().indexOf('working on') > -1 ||
          !self.merge && subject.substr(0, 5) === 'Merge') {
        continue;
      }

      // detect scopes
      matches = subject.match(self._scopeRE);

      if (matches) {
        commit.scope = subject.substr(0, matches[0].length - 1);
        commit.subject = subject.substr(matches[0].length).trim();
      }

      // detect semver tags
      if (commit.body && commit.body.indexOf('SEMVER-MAJOR') > -1) {
        commit.semver = 'SEMVER-MAJOR';

      } else if (commit.body && commit.body.indexOf('SEMVER-MINOR') > -1) {
        commit.semver = 'SEMVER-MINOR';
      }
      commits.push(commit);
    }

    callback(null, commits);
  });
};

ChangeLog.prototype._sortByScope = function(a, b) {
  if (a.scope > b.scope) {
    return 1;
  } else if (a.scope < b.scope) {
    return -1;
  } else {
    if (a.time > b.time) {
      return -1;
    } else {
      return 1;
    }
  }
};

ChangeLog.prototype.toMarkdown = function(commits) {
  var i, commit, md;
  var markdown = [];

  if (this.group) {
    commits.sort(this._sortByScope);
  }

  for (i = 0; i < commits.length; ++i) {
    commit = commits[i];

    if (this.link) {
      md = '[[`' + commit.hash.substr(0, 10) + '`](' +
          this.commitURL + '/' + commit.hash + ')] - ';
    } else {
      md = '[`' + commit.hash.substr(0, 10) + '`] - ';
    }

    if (commit.scope || commit.semver) {
      md += '**';

      if (commit.semver) {
        md += '(' + commit.semver + ')';

        if (commit.scope) {
          md += ' ';
        }
      }
      if (commit.scope) {
        md += commit.scope;
      }

      md += '**';

      if (commit.scope) {
        md += ': ';
      }
    }

    md += commit.subject
        .replace(/([\[\]])/g, '\\$1');

    if (this.author) {
      md += ' (' + commit.author.name + ')';
    }

    markdown.push(md);
  }

  return markdown;
};
<|endoftext|>


<commit_before>#!/usr/bin/env node

var when = require('when');
var exec = require('child_process').exec;
var sh = require('shelljs');
var fs = require('fs');
var git = require('./git');
var changelog42 = require('changelog42')

var _getChangelog = function(commitURL) {

  var changelog = new changelog42({
    since: '--tags',
    group: true,
    author: false,
    body: false,
    link: true,
    merge: false,
    commitURL: commitURL
  });

  return when.promise(function(resolve, reject) {
    changelog.getDate(changelog.since, function(err, date) {
      if (err) {
        return reject(err.message);
      }

      changelog.getLog(date, function(err2, commits) {
        if (err2) {
          return reject(err2.message);
        }
        var markdown = changelog.toMarkdown(commits);
        var joint = '\n  - ';
        var result = [];
        result.push('\n### Commits');
        result.push(joint + markdown.join(joint) + '\n');
        resolve(result.join(''));
      });
    });
  });
};

var _createChangelog = function(doIt, folder, filename, title, commitURL) {
  return when.promise(function(resolve, reject) {

    if (!doIt) {
      return resolve();
    }

    sh.mkdir('-p', folder);

    git.getUser().then(function(username) {

      _getChangelog(commitURL).then(function(changelog) {
        var fileContentArray = ['##', title, '\n\n'];
        fileContentArray.push('*Created by: ');
        fileContentArray.push(username);
        fileContentArray.push('*');
        fileContentArray.push('\n');
        fileContentArray.push(changelog);
        var fileContent = fileContentArray.join('');
        fs.writeFile('changelogs/' + filename + '.md', fileContent, function(error) {
          if (error) {
            reject('Bei der Erstellung des Changelogs ist ein Fehler aufgetreten: ' + error);
          } else {
            resolve();
          }
        });
      }, reject);
    }, reject);

  });
};

module.exports = _createChangelog;<commit_msg>show author in changelog<commit_after>#!/usr/bin/env node

var when = require('when');
var exec = require('child_process').exec;
var sh = require('shelljs');
var fs = require('fs');
var git = require('./git');
var changelog42 = require('changelog42')

var _getChangelog = function(commitURL) {

  var changelog = new changelog42({
    since: '--tags',
    group: true,
    author: true,
    body: false,
    link: true,
    merge: false,
    commitURL: commitURL
  });

  return when.promise(function(resolve, reject) {
    changelog.getDate(changelog.since, function(err, date) {
      if (err) {
        return reject(err.message);
      }

      changelog.getLog(date, function(err2, commits) {
        if (err2) {
          return reject(err2.message);
        }
        var markdown = changelog.toMarkdown(commits);
        var joint = '\n  - ';
        var result = [];
        result.push('\n### Commits');
        result.push(joint + markdown.join(joint) + '\n');
        resolve(result.join(''));
      });
    });
  });
};

var _createChangelog = function(doIt, folder, filename, title, commitURL) {
  return when.promise(function(resolve, reject) {

    if (!doIt) {
      return resolve();
    }

    sh.mkdir('-p', folder);

    git.getUser().then(function(username) {

      _getChangelog(commitURL).then(function(changelog) {
        var fileContentArray = ['##', title, '\n\n'];
        fileContentArray.push('*Created by: ');
        fileContentArray.push(username);
        fileContentArray.push('*');
        fileContentArray.push('\n');
        fileContentArray.push(changelog);
        var fileContent = fileContentArray.join('');
        fs.writeFile('changelogs/' + filename + '.md', fileContent, function(error) {
          if (error) {
            reject('Bei der Erstellung des Changelogs ist ein Fehler aufgetreten: ' + error);
          } else {
            resolve();
          }
        });
      }, reject);
    }, reject);

  });
};

module.exports = _createChangelog;<|endoftext|>


<commit_before>/**
* resource.GameData Module
*
* Description
*/
angular.module('resource.GameData', [])
.factory('GameData', [function () {
    var data = {
        speed: 800,
        level: 1,
        score: 0,
        gameBoard: {
            borderWidth: 10,
            boardWidthInPixel: 380,
            pieceWidthInPixel: 380 / 10,
            boardWidth: 10,
            boardHeight: 20,
            boardPosition: {
                x: 0,
                y: 0
            },
            coordinatePosition: 0
        }
    };

    return data;
}]);<commit_msg>add rotate and pattern limit<commit_after>/**
* resource.GameData Module
*
* Description
*/
angular.module('resource.GameData', [])
.factory('GameData', [function () {
    var data = {
        speed: 800,
        level: 1,
        score: 0,
        rotationLimit: 4,
        patternLimit: 7,
        gameBoard: {
            borderWidth: 10,
            boardWidthInPixel: 380,
            pieceWidthInPixel: 380 / 10,
            boardWidth: 10,
            boardHeight: 20,
            boardPosition: {
                x: 0,
                y: 0
            },
            coordinatePosition: 0
        }
    };

    return data;
}]);<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Gonçalo Baltazar <me@goncalomb.com>
 *
 * P3JS is released under the terms of the MIT License.
 * See LICENSE.txt for details.
 */

var p3js = module.exports = { };

if (typeof window != "undefined") {
	window.p3js = p3js;
}

p3js.pseudoInstructions = {
	"ORIG": { type: "0c", requiresLabel: false },
	"EQU":  { type: "0c", requiresLabel: true  },
	"WORD": { type: "0c", requiresLabel: true  },
	"STR":  { type: "s",  requiresLabel: true  },
	"TAB":  { type: "0c", requiresLabel: true  }
};

//   Name  Opcode   Type
var instructions_raw = [
	// 0 operands
	"NOP   000000   0",
	"ENI   000001   0",
	"DSI   000010   0",
	"STC   000011   0",
	"CLC   000100   0",
	"CMC   000101   0",
	"RET   000110   0",
	"RTI   000111   0",
	// 0 operands with constant
	"INT   001000   0c",
	"RETN  001001   0c",
	// 1 operand
	"NEG   010000   1",
	"INC   010001   1",
	"DEC   010010   1",
	"COM   010011   1",
	"PUSH  010100   1",
	"POP   010101   1",
	// 1 operand with constant
	"SHR   011000   1c",
	"SHL   011001   1c",
	"SHRA  011010   1c",
	"SHLA  011011   1c",
	"ROR   011100   1c",
	"ROL   011101   1c",
	"RORC  011110   1c",
	"ROLC  011111   1c",
	// 2 operands
	"CMP   100000   2",
	"ADD   100001   2",
	"ADDC  100010   2",
	"SUB   100011   2",
	"SUBB  100100   2",
	"MUL   100101   2",
	"DIV   100110   2",
	"TEST  100111   2",
	"AND   101000   2",
	"OR    101001   2",
	"XOR   101010   2",
	"MOV   101011   2",
	"MVBH  101100   2",
	"MVBL  101101   2",
	"XCH   101110   2",
	// jump
	"JMP   110000   j",
	"CALL  110010   j",
	// jump conditional
	"JMP.  110001   jc",
	"CALL. 110011   jc",
	// jump relative
	"BR    111000   jr",
	// jump relative conditional
	"BR.   111001   jrc"
];

p3js.instructions = { };
for (var i = 0, l = instructions_raw.length; i < l; i++) {
	var parts = instructions_raw[i].replace(/\s+/g, " ").split(" ");
	p3js.instructions[parts[0].toUpperCase()] = {
		opcode: parseInt(parts[1], 2),
		type: parts[2]
	};
}

p3js.conditions = {
	"Z":  { code: 0 },
	"NZ": { code: 1 },
	"C":  { code: 2 },
	"NC": { code: 3 },
	"N":  { code: 4 },
	"NN": { code: 5 },
	"O":  { code: 6 },
	"NO": { code: 7 },
	"P":  { code: 8 },
	"NP": { code: 9 },
	"I":  { code: 10 },
	"NI": { code: 11 }
};

p3js.constants = {
	P3AS_MAGIC_NUMBER: 56347333,
	P3AS_MAGIC_NUMBER_OLD: 936854375,

	ROM_A_SIZE: (1 << 6),   // 64 positions
	ROM_A_WORD_SIZE: 2,     // 16 bits (only 9 are used)
	ROM_B_SIZE: (1 << 2),   // 16 positions
	ROM_B_WORD_SIZE: 2,     // 16 bits (only 9 are used)
	ROM_C_SIZE: (1 << 9),   // 512 positions
	ROM_C_WORD_SIZE: 4,     // 32 bits

	INTERRUPT_VECTOR_ADDRESS: 0xfe00,
};

p3js.extractConstants = function() {
	var code = ["// use eval(p3js.extractConstants());\n"];
	for (var key in p3js.constants) {
		code.push("var " + key + " = p3js.constants[" + JSON.stringify(key) + "];\n");
	}
	return code.join("");
}

eval(p3js.extractConstants());

p3js.getNumOperands = function(type) {
	if (type == "0")  return 0;
	if (type == "0c") return 1;
	if (type == "1")  return 1;
	if (type == "1c") return 2;
	if (type == "2")  return 2;
	if (type.charAt(0) == "j") return 1;
	return null
}

p3js.writeObjectFormat = function(memory, oldFormat, usedAddresses) {
	var view_mem = new DataView(memory);
	var buffer = new ArrayBuffer(memory.byteLength * 2);
	var view = new DataView(buffer);
	var p = 0; // position on the output buffer
	if (!oldFormat) {
		view.setUint32(0, P3AS_MAGIC_NUMBER, true); // 32bit integer
		p = 4;
	} else {
		view.setUint32(0, P3AS_MAGIC_NUMBER_OLD, true); // 64bit integer
		view.setUint32(4, 0, true);
		p = 8
	}
	for (var i = 0, l = memory.byteLength; i < l; i += 2) {
		if (usedAddresses) {
			if (!usedAddresses[i/2]) {
				continue;
			}
		} else if (view_mem.getInt16(i, true) == 0) {
			continue;
		}
		var length_pos = p;
		p += 2;
		// write address of block
		view.setInt16(p, i/2, true);
		p += 2;
		// write data
		var j = i;
		for (; j < l; j += 2) {
			var v = view_mem.getInt16(j, true);
			if (usedAddresses) {
				if (!usedAddresses[j/2]) {
					break;
				}
			} else if (v == 0) {
				break;
			}
			view.setInt16(p, v, true);
			p += 2;
		}
		// write length of block
		view.setInt16(length_pos, (j - i)/2, true);
		i = j;
	}
	view.setInt16(p, 0, true);
	p += 2;
	return buffer.slice(0, p);
}

p3js.devices = require("./devices");
p3js.assembly = require("./assembly");
p3js.Simulator = require("./Simulator.js");
<commit_msg>Remove unnecessary code<commit_after>/*
 * Copyright (c) 2016 Gonçalo Baltazar <me@goncalomb.com>
 *
 * P3JS is released under the terms of the MIT License.
 * See LICENSE.txt for details.
 */

var p3js = module.exports = { };

if (typeof window != "undefined") {
	window.p3js = p3js;
}

p3js.pseudoInstructions = {
	"ORIG": { type: "0c", requiresLabel: false },
	"EQU":  { type: "0c", requiresLabel: true  },
	"WORD": { type: "0c", requiresLabel: true  },
	"STR":  { type: "s",  requiresLabel: true  },
	"TAB":  { type: "0c", requiresLabel: true  }
};

//   Name  Opcode   Type
var instructions_raw = [
	// 0 operands
	"NOP   000000   0",
	"ENI   000001   0",
	"DSI   000010   0",
	"STC   000011   0",
	"CLC   000100   0",
	"CMC   000101   0",
	"RET   000110   0",
	"RTI   000111   0",
	// 0 operands with constant
	"INT   001000   0c",
	"RETN  001001   0c",
	// 1 operand
	"NEG   010000   1",
	"INC   010001   1",
	"DEC   010010   1",
	"COM   010011   1",
	"PUSH  010100   1",
	"POP   010101   1",
	// 1 operand with constant
	"SHR   011000   1c",
	"SHL   011001   1c",
	"SHRA  011010   1c",
	"SHLA  011011   1c",
	"ROR   011100   1c",
	"ROL   011101   1c",
	"RORC  011110   1c",
	"ROLC  011111   1c",
	// 2 operands
	"CMP   100000   2",
	"ADD   100001   2",
	"ADDC  100010   2",
	"SUB   100011   2",
	"SUBB  100100   2",
	"MUL   100101   2",
	"DIV   100110   2",
	"TEST  100111   2",
	"AND   101000   2",
	"OR    101001   2",
	"XOR   101010   2",
	"MOV   101011   2",
	"MVBH  101100   2",
	"MVBL  101101   2",
	"XCH   101110   2",
	// jump
	"JMP   110000   j",
	"CALL  110010   j",
	// jump conditional
	"JMP.  110001   jc",
	"CALL. 110011   jc",
	// jump relative
	"BR    111000   jr",
	// jump relative conditional
	"BR.   111001   jrc"
];

p3js.instructions = { };
for (var i = 0, l = instructions_raw.length; i < l; i++) {
	var parts = instructions_raw[i].replace(/\s+/g, " ").split(" ");
	p3js.instructions[parts[0].toUpperCase()] = {
		opcode: parseInt(parts[1], 2),
		type: parts[2]
	};
}

p3js.conditions = {
	"Z":  { code: 0 },
	"NZ": { code: 1 },
	"C":  { code: 2 },
	"NC": { code: 3 },
	"N":  { code: 4 },
	"NN": { code: 5 },
	"O":  { code: 6 },
	"NO": { code: 7 },
	"P":  { code: 8 },
	"NP": { code: 9 },
	"I":  { code: 10 },
	"NI": { code: 11 }
};

p3js.constants = {
	P3AS_MAGIC_NUMBER: 56347333,
	P3AS_MAGIC_NUMBER_OLD: 936854375,

	ROM_A_SIZE: (1 << 6),   // 64 positions
	ROM_A_WORD_SIZE: 2,     // 16 bits (only 9 are used)
	ROM_B_SIZE: (1 << 2),   // 16 positions
	ROM_B_WORD_SIZE: 2,     // 16 bits (only 9 are used)
	ROM_C_SIZE: (1 << 9),   // 512 positions
	ROM_C_WORD_SIZE: 4,     // 32 bits

	INTERRUPT_VECTOR_ADDRESS: 0xfe00,
};

p3js.getNumOperands = function(type) {
	if (type == "0")  return 0;
	if (type == "0c") return 1;
	if (type == "1")  return 1;
	if (type == "1c") return 2;
	if (type == "2")  return 2;
	if (type.charAt(0) == "j") return 1;
	return null
}

p3js.writeObjectFormat = function(memory, oldFormat, usedAddresses) {
	var view_mem = new DataView(memory);
	var buffer = new ArrayBuffer(memory.byteLength * 2);
	var view = new DataView(buffer);
	var p = 0; // position on the output buffer
	if (!oldFormat) {
		view.setUint32(0, p3js.constants.P3AS_MAGIC_NUMBER, true); // 32bit integer
		p = 4;
	} else {
		view.setUint32(0, p3js.constants.P3AS_MAGIC_NUMBER_OLD, true); // 64bit integer
		view.setUint32(4, 0, true);
		p = 8
	}
	for (var i = 0, l = memory.byteLength; i < l; i += 2) {
		if (usedAddresses) {
			if (!usedAddresses[i/2]) {
				continue;
			}
		} else if (view_mem.getInt16(i, true) == 0) {
			continue;
		}
		var length_pos = p;
		p += 2;
		// write address of block
		view.setInt16(p, i/2, true);
		p += 2;
		// write data
		var j = i;
		for (; j < l; j += 2) {
			var v = view_mem.getInt16(j, true);
			if (usedAddresses) {
				if (!usedAddresses[j/2]) {
					break;
				}
			} else if (v == 0) {
				break;
			}
			view.setInt16(p, v, true);
			p += 2;
		}
		// write length of block
		view.setInt16(length_pos, (j - i)/2, true);
		i = j;
	}
	view.setInt16(p, 0, true);
	p += 2;
	return buffer.slice(0, p);
}

p3js.devices = require("./devices");
p3js.assembly = require("./assembly");
p3js.Simulator = require("./Simulator.js");
<|endoftext|>


<commit_before>/**
 * @author mr.doob / http://mrdoob.com/
 */

THREE.Object3D = function ( material ) {

	this.position = new THREE.Vector3();
	this.rotation = new THREE.Vector3();
	this.scale = new THREE.Vector3( 1, 1, 1 );
	/** the offset from the position vector about which this object is rotated */
	this.centerOfRotation = new THREE.Vector3(0,0,0);

	this.matrix = new THREE.Matrix4();
	this.screen = new THREE.Vector3();

	this.material = material instanceof Array ? material : [ material ];
	this.overdraw = false;

	this.autoUpdateMatrix = true;

	/** flags an update in the object3d's values requiring a recalculation of it's matrix */
	this.dirty = true;
	/* internal flag to update all the object's children's matricies before they are rendered. */
	this.updateChildren = false;

	this.updateMatrix = function () {

		//Reducing render time by skipping matricies which need no update
		if (this.isDirty()==false) return;
		this.dirty = false;
		this.updateChildren = true;

		this.matrix.identity();
		//Translation (and matrix inheritance)
		if (this.parent != null)
		{
		  this.matrix.multiplySelf( this.parent.childTranslationMatrix( this.position.x, this.position.y, this.position.z ) );
		}
		else
		{
		  this.matrix.multiplySelf( THREE.Matrix4.translationMatrix( this.position.x, this.position.y, this.position.z ) );
		}
		//Rotation
		this.matrix.multiplySelf( THREE.Matrix4.rotationXMatrix( this.rotation.x ) );
		this.matrix.multiplySelf( THREE.Matrix4.rotationYMatrix( this.rotation.y ) );
		this.matrix.multiplySelf( THREE.Matrix4.rotationZMatrix( this.rotation.z ) );
		//Center of Rotation offsets
		if (this.centerOfRotation.x != 0 && this.centerOfRotation.y != 0 && this.centerOfRotation.z != 0)
		  this.matrix.multiplySelf( THREE.Matrix4.translationMatrix( -this.centerOfRotation.x, -this.centerOfRotation.y, -this.centerOfRotation.z ) );
		//Scaling
		this.matrix.multiplySelf( THREE.Matrix4.scaleMatrix( this.scale.x, this.scale.y, this.scale.z ) );

	};

	this.childTranslationMatrix = function(cx, cy, cz) {

		this.updateMatrix();
		m = THREE.Matrix4.translationMatrix(cx, cy, cz);
		m.multiplySelf(this.matrix);
		return m;

	};

	/** returns true if this object or any of it's parent's objects dirty flag is set to true*/
	this.isDirty = function()
	{
		return this.dirty || ( (this.parent!=null)? (this.parent.isDirty() == true ||this.parent.updateChildren == true ) : false );
	}

};
<commit_msg>Fixed a bug in center of rotation<commit_after>/**
 * @author mr.doob / http://mrdoob.com/
 */

THREE.Object3D = function ( material ) {

	this.position = new THREE.Vector3();
	this.rotation = new THREE.Vector3();
	this.scale = new THREE.Vector3( 1, 1, 1 );
	/** the offset from the position vector about which this object is rotated */
	this.centerOfRotation = new THREE.Vector3(0,0,0);

	this.matrix = new THREE.Matrix4();
	this.screen = new THREE.Vector3();

	this.material = material instanceof Array ? material : [ material ];
	this.overdraw = false;

	this.autoUpdateMatrix = true;

	/** flags an update in the object3d's values requiring a recalculation of it's matrix */
	this.dirty = true;
	/* internal flag to update all the object's children's matricies before they are rendered. */
	this.updateChildren = false;

	this.updateMatrix = function () {

		//Reducing render time by skipping matricies which need no update
		if (this.isDirty()==false) return;
		this.dirty = false;
		this.updateChildren = true;

		this.matrix.identity();
		//Translation (and matrix inheritance)
		if (this.parent != null)
		{
		  this.matrix.multiplySelf( this.parent.childTranslationMatrix( this.position.x, this.position.y, this.position.z ) );
		}
		else
		{
		  this.matrix.multiplySelf( THREE.Matrix4.translationMatrix( this.position.x, this.position.y, this.position.z ) );
		}
		//Rotation
		this.matrix.multiplySelf( THREE.Matrix4.rotationXMatrix( this.rotation.x ) );
		this.matrix.multiplySelf( THREE.Matrix4.rotationYMatrix( this.rotation.y ) );
		this.matrix.multiplySelf( THREE.Matrix4.rotationZMatrix( this.rotation.z ) );
		//Center of Rotation offsets
		if (this.centerOfRotation.x != 0 || this.centerOfRotation.y != 0 || this.centerOfRotation.z != 0)
			this.matrix.multiplySelf( THREE.Matrix4.translationMatrix( -this.centerOfRotation.x, -this.centerOfRotation.y, -this.centerOfRotation.z ) );
		//Scaling
		this.matrix.multiplySelf( THREE.Matrix4.scaleMatrix( this.scale.x, this.scale.y, this.scale.z ) );

	};

	this.childTranslationMatrix = function(cx, cy, cz) {

		this.updateMatrix();
		m = THREE.Matrix4.translationMatrix(cx, cy, cz);
		m.multiplySelf(this.matrix);
		return m;

	};

	/** returns true if this object or any of it's parent's objects dirty flag is set to true*/
	this.isDirty = function()
	{
		return this.dirty || ( (this.parent!=null)? (this.parent.isDirty() == true ||this.parent.updateChildren == true ) : false );
	}

};
<|endoftext|>


<commit_before>/*
 * patternlab-node - v2.4.0 - 2016
 *
 * Brian Muenzenmeyer, Geoff Pursell, and the web community.
 * Licensed under the MIT license.
 *
 * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
 *
 */

"use strict";

var diveSync = require('diveSync'),
  glob = require('glob'),
  _ = require('lodash'),
  path = require('path');

// GTP: these two diveSync pattern processors factored out so they can be reused
// from unit tests to reduce code dupe!

function buildPatternData(dataFilesPath, fs) {
  var dataFilesPath = dataFilesPath;
  var dataFiles = glob.sync(dataFilesPath + '*.json', {"ignore" : [dataFilesPath + 'listitems.json']});
  var mergeObject = {};
  dataFiles.forEach(function (filePath) {
    var jsonData = fs.readJSONSync(path.resolve(filePath), 'utf8');
    mergeObject = _.merge(mergeObject, jsonData);
  });
  return mergeObject;
}

function processAllPatternsIterative(pattern_assembler, patterns_dir, patternlab) {
  diveSync(
    patterns_dir,
    function (err, file) {
      //log any errors
      if (err) {
        console.log(err);
        return;
      }
      pattern_assembler.process_pattern_iterative(path.relative(patterns_dir, file), patternlab);
    }
  );
}

function processAllPatternsRecursive(pattern_assembler, patterns_dir, patternlab) {
  diveSync(
    patterns_dir,
    function (err, file) {
      //log any errors
      if (err) {
        console.log(err);
        return;
      }
      pattern_assembler.process_pattern_recursive(path.relative(patterns_dir, file), patternlab);
    }
  );
}

var patternlab_engine = function (config) {
  'use strict';

  var JSON5 = require('json5'),
    fs = require('fs-extra'),
    pa = require('./pattern_assembler'),
    pe = require('./pattern_exporter'),
    lh = require('./lineage_hunter'),
    ui = require('./ui_builder'),
    plutils = require('./utilities'),
    sm = require('./starterkit_manager'),
    patternlab = {};

  patternlab.package = fs.readJSONSync(path.resolve(__dirname, '../../package.json'));
  patternlab.config = config || fs.readJSONSync(path.resolve(__dirname, '../../patternlab-config.json'));

  var paths = patternlab.config.paths;

  function getVersion() {
    console.log(patternlab.package.version);
  }

  function help() {

    console.log('');

    console.log('|=======================================|');
    plutils.logGreen('     Pattern Lab Node Help v' + patternlab.package.version);
    console.log('|=======================================|');

    console.log('');
    console.log('Command Line Interface - usually consumed by an edition');
    console.log('');

    plutils.logGreen(' patternlab:build');
    console.log('   > Compiles the patterns and frontend, outputting to config.paths.public');
    console.log('');

    plutils.logGreen(' patternlab:patternsonly');
    console.log('   > Compiles the patterns only, outputting to config.paths.public');
    console.log('');

    plutils.logGreen(' patternlab:version');
    console.log('   > Return the version of patternlab-node you have installed');
    console.log('');

    plutils.logGreen(' patternlab:help');
    console.log('   > Get more information about patternlab-node, pattern lab in general, and where to report issues.');
    console.log('');

    plutils.logGreen(' patternlab:liststarterkits');
    console.log('   > Returns a url with the list of available starterkits hosted on the Pattern Lab organization Github account');
    console.log('');

    plutils.logGreen(' patternlab:loadstarterkit');
    console.log('   > Load a starterkit into config.paths.source/*');
    console.log('   > NOTE: Overwrites existing content, and only cleans out existing directory if --clean=true argument is passed.');
    console.log('   > NOTE: In most cases, `npm install starterkit-name` will precede this call.');
    console.log('   > arguments:');
    console.log('      -- kit ');
    console.log('      > the name of the starter kit to load');
    console.log('      -- clean ');
    console.log('      > removes all files from config.paths.source/ prior to load');
    console.log('   > example (gulp):');
    console.log('    `gulp patternlab:loadstarterkit --kit=starterkit-mustache-demo`');
    console.log('');

    console.log('===============================');
    console.log('');
    console.log('Visit http://patternlab.io/ for more info about Pattern Lab');
    console.log('Visit https://github.com/pattern-lab/patternlab-node/issues to open an issue.');
    console.log('Visit https://github.com/pattern-lab/patternlab-node/wiki to view the changelog, roadmap, and other info.');
    console.log('');
    console.log('===============================');
  }

  function printDebug() {
    // A replacer function to pass to stringify below; this is here to prevent
    // the debug output from blowing up into a massive fireball of circular
    // references. This happens specifically with the Handlebars engine. Remove
    // if you like 180MB log files.
    function propertyStringReplacer(key, value) {
      if (key === 'engine' && value && value.engineName) {
        return '{' + value.engineName + ' engine object}';
      }
      return value;
    }

    //debug file can be written by setting flag on patternlab-config.json
    if (patternlab.config.debug) {
      console.log('writing patternlab debug file to ./patternlab.json');
      fs.outputFileSync('./patternlab.json', JSON.stringify(patternlab, propertyStringReplacer, 3));
    }
  }

  function setCacheBust() {
    if (patternlab.config.cacheBust) {
      if (patternlab.config.debug) {
        console.log('setting cacheBuster value for frontend assets.');
      }
      patternlab.cacheBuster = new Date().getTime();
    } else {
      patternlab.cacheBuster = 0;
    }
  }

  function listStarterkits() {
    var starterkit_manager = new sm(patternlab.config);
    return starterkit_manager.list_starterkits();
  }

  function loadStarterKit(starterkitName, clean) {
    var starterkit_manager = new sm(patternlab);
    starterkit_manager.load_starterkit(starterkitName, clean);
  }

  function buildPatterns(deletePatternDir) {
    try {
      patternlab.data = buildPatternData(paths.source.data, fs);
    } catch (ex) {
      plutils.logRed('missing or malformed' + paths.source.data + 'data.json  Pattern Lab may not work without this file.');
      patternlab.data = {};
    }
    try {
      patternlab.listitems = fs.readJSONSync(path.resolve(paths.source.data, 'listitems.json'));
    } catch (ex) {
      plutils.logRed('missing or malformed' + paths.source.data + 'listitems.json  Pattern Lab may not work without this file.');
      patternlab.listitems = {};
    }
    try {
      patternlab.header = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'partials', 'general-header.mustache'), 'utf8');
      patternlab.footer = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'partials', 'general-footer.mustache'), 'utf8');
      patternlab.patternSection = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'partials', 'patternSection.mustache'), 'utf8');
      patternlab.patternSectionSubType = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'partials', 'patternSectionSubtype.mustache'), 'utf8');
      patternlab.viewAll = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'viewall.mustache'), 'utf8');
    } catch (ex) {
      console.log(ex);
      plutils.logRed('\nERROR: missing an essential file from ' + paths.source.patternlabFiles + '. Pattern Lab won\'t work without this file.\n');
      process.exit(1);
    }
    patternlab.patterns = [];
    patternlab.subtypePatterns = {};
    patternlab.partials = {};
    patternlab.data.link = {};

    setCacheBust();

    var pattern_assembler = new pa(),
      pattern_exporter = new pe(),
      lineage_hunter = new lh(),
      patterns_dir = paths.source.patterns;

    pattern_assembler.combine_listItems(patternlab);

    // diveSync once to perform iterative populating of patternlab object
    processAllPatternsIterative(pattern_assembler, patterns_dir, patternlab);

    //diveSync again to recursively include partials, filling out the
    //extendedTemplate property of the patternlab.patterns elements
    processAllPatternsRecursive(pattern_assembler, patterns_dir, patternlab);

    //set user defined head and foot if they exist
    try {
      patternlab.userHead = fs.readFileSync(path.resolve(paths.source.meta, '_00-head.mustache'), 'utf8');
    }
    catch (ex) {
      plutils.logRed('\nWARNING: Could not find the user-editable header template, currently configured to be at ' + path.join(config.paths.source.meta, '_00-head.mustache') + '. Your configured path may be incorrect (check paths.source.meta in your config file), the file may have been deleted, or it may have been left in the wrong place during a migration or update.\n');
      if (patternlab.config.debug) { console.log(ex); }
      process.exit(1);
    }
    try {
      patternlab.userFoot = fs.readFileSync(path.resolve(paths.source.meta, '_01-foot.mustache'), 'utf8');
    }
    catch (ex) {
      plutils.logRed('\nWARNING: Could not find the user-editable footer template, currently configured to be at ' + path.join(config.paths.source.meta, '_01-foot.mustache') + '. Your configured path may be incorrect (check paths.source.meta in your config file), the file may have been deleted, or it may have been left in the wrong place during a migration or update.\n');
      if (patternlab.config.debug) { console.log(ex); }
      process.exit(1);
    }

    //now that all the main patterns are known, look for any links that might be within data and expand them
    //we need to do this before expanding patterns & partials into extendedTemplates, otherwise we could lose the data -> partial reference
    pattern_assembler.parse_data_links(patternlab);

    //cascade any patternStates
    lineage_hunter.cascade_pattern_states(patternlab);

    //delete the contents of config.patterns.public before writing
    if (deletePatternDir) {
      fs.removeSync(paths.public.patterns);
      fs.emptyDirSync(paths.public.patterns);
    }

    //set pattern-specific header if necessary
    var head;
    if (patternlab.userHead) {
      head = patternlab.userHead;
    } else {
      head = patternlab.header;
    }

    //set the pattern-specific header by compiling the general-header with data, and then adding it to the meta header
    patternlab.data.patternLabHead = pattern_assembler.renderPattern(patternlab.header, {
      cacheBuster: patternlab.cacheBuster
    });

    //render all patterns last, so lineageR works
    patternlab.patterns.forEach(function (pattern) {

      if (!pattern.isPattern) {
        return false;
      }

      pattern.header = head;

      //todo move this into lineage_hunter
      pattern.patternLineages = pattern.lineage;
      pattern.patternLineageExists = pattern.lineage.length > 0;
      pattern.patternLineagesR = pattern.lineageR;
      pattern.patternLineageRExists = pattern.lineageR.length > 0;
      pattern.patternLineageEExists = pattern.patternLineageExists || pattern.patternLineageRExists;

      //render the pattern, but first consolidate any data we may have
      var allData;
      try {
        allData = JSON5.parse(JSON5.stringify(patternlab.data));
      } catch (err) {
        console.log('There was an error parsing JSON for ' + pattern.relPath);
        console.log(err);
      }
      allData = plutils.mergeData(allData, pattern.jsonFileData);
      allData.cacheBuster = patternlab.cacheBuster;

      var headHTML = pattern_assembler.renderPattern(pattern.header, allData);

      //render the extendedTemplate with all data
      pattern.patternPartialCode = pattern_assembler.renderPattern(pattern, allData);

      //todo see if this is still needed
      //pattern.patternPartialCodeE = entity_encoder.encode(pattern.patternPartialCode);

      // stringify this data for individual pattern rendering and use on the styleguide
      // see if patternData really needs these other duped values
      pattern.patternData = JSON.stringify({
        cssEnabled: false,
        patternLineageExists: pattern.patternLineageExists,
        patternLineages: pattern.patternLineages,
        lineage: pattern.patternLineages,
        patternLineageRExists: pattern.patternLineageRExists,
        patternLineagesR: pattern.patternLineagesR,
        lineageR: pattern.patternLineagesR,
        patternLineageEExists: pattern.patternLineageExists || pattern.patternLineageRExists,
        patternDesc: pattern.patternDescExists ? pattern.patternDesc : '',
        patternBreadcrumb:
          pattern.patternGroup === pattern.patternSubGroup ?
          {
            patternType: pattern.patternGroup
          } : {
            patternType: pattern.patternGroup,
            patternSubtype: pattern.patternSubGroup
          },
        patternExtension: pattern.fileExtension.substr(1), //remove the dot because styleguide asset default adds it for us
        patternName: pattern.patternName,
        patternPartial: pattern.patternPartial,
        patternState: pattern.patternState,
        extraOutput: {}
      });

      //set the pattern-specific footer by compiling the general-footer with data, and then adding it to the meta footer
      var footerPartial = pattern_assembler.renderPattern(patternlab.footer, {
        isPattern: pattern.isPattern,
        patternData: pattern.patternData,
        cacheBuster: patternlab.cacheBuster
      });

      var footerHTML = pattern_assembler.renderPattern(patternlab.userFoot, {
        patternLabFoot : footerPartial
      });

      //default the output suffixes if not present
      var outputFileSuffixes = {
        rendered: '',
        rawTemplate: '',
        markupOnly: '.markup-only'
      }
      outputFileSuffixes = _.extend(outputFileSuffixes, patternlab.config.outputFileSuffixes);

      //write the compiled template to the public patterns directory
      var patternPage = headHTML + pattern.patternPartialCode + footerHTML;
      fs.outputFileSync(paths.public.patterns + pattern.patternLink.replace('.html', outputFileSuffixes.rendered + '.html'), patternPage);

      //write the mustache file too
      fs.outputFileSync(paths.public.patterns + pattern.patternLink.replace('.html', outputFileSuffixes.rawTemplate + pattern.fileExtension), pattern.template);

      //write the encoded version too
      fs.outputFileSync(paths.public.patterns + pattern.patternLink.replace('.html', outputFileSuffixes.markupOnly + '.html'), pattern.patternPartialCode);

      return true;
    });

    //export patterns if necessary
    pattern_exporter.export_patterns(patternlab);
  }

  return {
    version: function () {
      return getVersion();
    },
    build: function (callback, deletePatternDir) {
      buildPatterns(deletePatternDir);
      new ui().buildFrontend(patternlab);
      printDebug();
      callback();
    },
    help: function () {
      help();
    },
    patternsonly: function (callback, deletePatternDir) {
      buildPatterns(deletePatternDir);
      printDebug();
      callback();
    },
    liststarterkits: function () {
      return listStarterkits();
    },
    loadstarterkit: function (starterkitName, clean) {
      loadStarterKit(starterkitName, clean);
    }
  };
};

// export these free functions so they're available without calling the exported
// function, for use in reducing code dupe in unit tests. At least, until we
// have a better way to do this
patternlab_engine.build_pattern_data = buildPatternData;
patternlab_engine.process_all_patterns_iterative = processAllPatternsIterative;
patternlab_engine.process_all_patterns_recursive = processAllPatternsRecursive;

module.exports = patternlab_engine;
<commit_msg>Pass config object to starterkit_manager<commit_after>/*
 * patternlab-node - v2.4.0 - 2016
 *
 * Brian Muenzenmeyer, Geoff Pursell, and the web community.
 * Licensed under the MIT license.
 *
 * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
 *
 */

"use strict";

var diveSync = require('diveSync'),
  glob = require('glob'),
  _ = require('lodash'),
  path = require('path');

// GTP: these two diveSync pattern processors factored out so they can be reused
// from unit tests to reduce code dupe!

function buildPatternData(dataFilesPath, fs) {
  var dataFilesPath = dataFilesPath;
  var dataFiles = glob.sync(dataFilesPath + '*.json', {"ignore" : [dataFilesPath + 'listitems.json']});
  var mergeObject = {};
  dataFiles.forEach(function (filePath) {
    var jsonData = fs.readJSONSync(path.resolve(filePath), 'utf8');
    mergeObject = _.merge(mergeObject, jsonData);
  });
  return mergeObject;
}

function processAllPatternsIterative(pattern_assembler, patterns_dir, patternlab) {
  diveSync(
    patterns_dir,
    function (err, file) {
      //log any errors
      if (err) {
        console.log(err);
        return;
      }
      pattern_assembler.process_pattern_iterative(path.relative(patterns_dir, file), patternlab);
    }
  );
}

function processAllPatternsRecursive(pattern_assembler, patterns_dir, patternlab) {
  diveSync(
    patterns_dir,
    function (err, file) {
      //log any errors
      if (err) {
        console.log(err);
        return;
      }
      pattern_assembler.process_pattern_recursive(path.relative(patterns_dir, file), patternlab);
    }
  );
}

var patternlab_engine = function (config) {
  'use strict';

  var JSON5 = require('json5'),
    fs = require('fs-extra'),
    pa = require('./pattern_assembler'),
    pe = require('./pattern_exporter'),
    lh = require('./lineage_hunter'),
    ui = require('./ui_builder'),
    plutils = require('./utilities'),
    sm = require('./starterkit_manager'),
    patternlab = {};

  patternlab.package = fs.readJSONSync(path.resolve(__dirname, '../../package.json'));
  patternlab.config = config || fs.readJSONSync(path.resolve(__dirname, '../../patternlab-config.json'));

  var paths = patternlab.config.paths;

  function getVersion() {
    console.log(patternlab.package.version);
  }

  function help() {

    console.log('');

    console.log('|=======================================|');
    plutils.logGreen('     Pattern Lab Node Help v' + patternlab.package.version);
    console.log('|=======================================|');

    console.log('');
    console.log('Command Line Interface - usually consumed by an edition');
    console.log('');

    plutils.logGreen(' patternlab:build');
    console.log('   > Compiles the patterns and frontend, outputting to config.paths.public');
    console.log('');

    plutils.logGreen(' patternlab:patternsonly');
    console.log('   > Compiles the patterns only, outputting to config.paths.public');
    console.log('');

    plutils.logGreen(' patternlab:version');
    console.log('   > Return the version of patternlab-node you have installed');
    console.log('');

    plutils.logGreen(' patternlab:help');
    console.log('   > Get more information about patternlab-node, pattern lab in general, and where to report issues.');
    console.log('');

    plutils.logGreen(' patternlab:liststarterkits');
    console.log('   > Returns a url with the list of available starterkits hosted on the Pattern Lab organization Github account');
    console.log('');

    plutils.logGreen(' patternlab:loadstarterkit');
    console.log('   > Load a starterkit into config.paths.source/*');
    console.log('   > NOTE: Overwrites existing content, and only cleans out existing directory if --clean=true argument is passed.');
    console.log('   > NOTE: In most cases, `npm install starterkit-name` will precede this call.');
    console.log('   > arguments:');
    console.log('      -- kit ');
    console.log('      > the name of the starter kit to load');
    console.log('      -- clean ');
    console.log('      > removes all files from config.paths.source/ prior to load');
    console.log('   > example (gulp):');
    console.log('    `gulp patternlab:loadstarterkit --kit=starterkit-mustache-demo`');
    console.log('');

    console.log('===============================');
    console.log('');
    console.log('Visit http://patternlab.io/ for more info about Pattern Lab');
    console.log('Visit https://github.com/pattern-lab/patternlab-node/issues to open an issue.');
    console.log('Visit https://github.com/pattern-lab/patternlab-node/wiki to view the changelog, roadmap, and other info.');
    console.log('');
    console.log('===============================');
  }

  function printDebug() {
    // A replacer function to pass to stringify below; this is here to prevent
    // the debug output from blowing up into a massive fireball of circular
    // references. This happens specifically with the Handlebars engine. Remove
    // if you like 180MB log files.
    function propertyStringReplacer(key, value) {
      if (key === 'engine' && value && value.engineName) {
        return '{' + value.engineName + ' engine object}';
      }
      return value;
    }

    //debug file can be written by setting flag on patternlab-config.json
    if (patternlab.config.debug) {
      console.log('writing patternlab debug file to ./patternlab.json');
      fs.outputFileSync('./patternlab.json', JSON.stringify(patternlab, propertyStringReplacer, 3));
    }
  }

  function setCacheBust() {
    if (patternlab.config.cacheBust) {
      if (patternlab.config.debug) {
        console.log('setting cacheBuster value for frontend assets.');
      }
      patternlab.cacheBuster = new Date().getTime();
    } else {
      patternlab.cacheBuster = 0;
    }
  }

  function listStarterkits() {
    var starterkit_manager = new sm(patternlab.config);
    return starterkit_manager.list_starterkits();
  }

  function loadStarterKit(starterkitName, clean) {
    var starterkit_manager = new sm(patternlab.config);
    starterkit_manager.load_starterkit(starterkitName, clean);
  }

  function buildPatterns(deletePatternDir) {
    try {
      patternlab.data = buildPatternData(paths.source.data, fs);
    } catch (ex) {
      plutils.logRed('missing or malformed' + paths.source.data + 'data.json  Pattern Lab may not work without this file.');
      patternlab.data = {};
    }
    try {
      patternlab.listitems = fs.readJSONSync(path.resolve(paths.source.data, 'listitems.json'));
    } catch (ex) {
      plutils.logRed('missing or malformed' + paths.source.data + 'listitems.json  Pattern Lab may not work without this file.');
      patternlab.listitems = {};
    }
    try {
      patternlab.header = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'partials', 'general-header.mustache'), 'utf8');
      patternlab.footer = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'partials', 'general-footer.mustache'), 'utf8');
      patternlab.patternSection = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'partials', 'patternSection.mustache'), 'utf8');
      patternlab.patternSectionSubType = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'partials', 'patternSectionSubtype.mustache'), 'utf8');
      patternlab.viewAll = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'viewall.mustache'), 'utf8');
    } catch (ex) {
      console.log(ex);
      plutils.logRed('\nERROR: missing an essential file from ' + paths.source.patternlabFiles + '. Pattern Lab won\'t work without this file.\n');
      process.exit(1);
    }
    patternlab.patterns = [];
    patternlab.subtypePatterns = {};
    patternlab.partials = {};
    patternlab.data.link = {};

    setCacheBust();

    var pattern_assembler = new pa(),
      pattern_exporter = new pe(),
      lineage_hunter = new lh(),
      patterns_dir = paths.source.patterns;

    pattern_assembler.combine_listItems(patternlab);

    // diveSync once to perform iterative populating of patternlab object
    processAllPatternsIterative(pattern_assembler, patterns_dir, patternlab);

    //diveSync again to recursively include partials, filling out the
    //extendedTemplate property of the patternlab.patterns elements
    processAllPatternsRecursive(pattern_assembler, patterns_dir, patternlab);

    //set user defined head and foot if they exist
    try {
      patternlab.userHead = fs.readFileSync(path.resolve(paths.source.meta, '_00-head.mustache'), 'utf8');
    }
    catch (ex) {
      plutils.logRed('\nWARNING: Could not find the user-editable header template, currently configured to be at ' + path.join(config.paths.source.meta, '_00-head.mustache') + '. Your configured path may be incorrect (check paths.source.meta in your config file), the file may have been deleted, or it may have been left in the wrong place during a migration or update.\n');
      if (patternlab.config.debug) { console.log(ex); }
      process.exit(1);
    }
    try {
      patternlab.userFoot = fs.readFileSync(path.resolve(paths.source.meta, '_01-foot.mustache'), 'utf8');
    }
    catch (ex) {
      plutils.logRed('\nWARNING: Could not find the user-editable footer template, currently configured to be at ' + path.join(config.paths.source.meta, '_01-foot.mustache') + '. Your configured path may be incorrect (check paths.source.meta in your config file), the file may have been deleted, or it may have been left in the wrong place during a migration or update.\n');
      if (patternlab.config.debug) { console.log(ex); }
      process.exit(1);
    }

    //now that all the main patterns are known, look for any links that might be within data and expand them
    //we need to do this before expanding patterns & partials into extendedTemplates, otherwise we could lose the data -> partial reference
    pattern_assembler.parse_data_links(patternlab);

    //cascade any patternStates
    lineage_hunter.cascade_pattern_states(patternlab);

    //delete the contents of config.patterns.public before writing
    if (deletePatternDir) {
      fs.removeSync(paths.public.patterns);
      fs.emptyDirSync(paths.public.patterns);
    }

    //set pattern-specific header if necessary
    var head;
    if (patternlab.userHead) {
      head = patternlab.userHead;
    } else {
      head = patternlab.header;
    }

    //set the pattern-specific header by compiling the general-header with data, and then adding it to the meta header
    patternlab.data.patternLabHead = pattern_assembler.renderPattern(patternlab.header, {
      cacheBuster: patternlab.cacheBuster
    });

    //render all patterns last, so lineageR works
    patternlab.patterns.forEach(function (pattern) {

      if (!pattern.isPattern) {
        return false;
      }

      pattern.header = head;

      //todo move this into lineage_hunter
      pattern.patternLineages = pattern.lineage;
      pattern.patternLineageExists = pattern.lineage.length > 0;
      pattern.patternLineagesR = pattern.lineageR;
      pattern.patternLineageRExists = pattern.lineageR.length > 0;
      pattern.patternLineageEExists = pattern.patternLineageExists || pattern.patternLineageRExists;

      //render the pattern, but first consolidate any data we may have
      var allData;
      try {
        allData = JSON5.parse(JSON5.stringify(patternlab.data));
      } catch (err) {
        console.log('There was an error parsing JSON for ' + pattern.relPath);
        console.log(err);
      }
      allData = plutils.mergeData(allData, pattern.jsonFileData);
      allData.cacheBuster = patternlab.cacheBuster;

      var headHTML = pattern_assembler.renderPattern(pattern.header, allData);

      //render the extendedTemplate with all data
      pattern.patternPartialCode = pattern_assembler.renderPattern(pattern, allData);

      //todo see if this is still needed
      //pattern.patternPartialCodeE = entity_encoder.encode(pattern.patternPartialCode);

      // stringify this data for individual pattern rendering and use on the styleguide
      // see if patternData really needs these other duped values
      pattern.patternData = JSON.stringify({
        cssEnabled: false,
        patternLineageExists: pattern.patternLineageExists,
        patternLineages: pattern.patternLineages,
        lineage: pattern.patternLineages,
        patternLineageRExists: pattern.patternLineageRExists,
        patternLineagesR: pattern.patternLineagesR,
        lineageR: pattern.patternLineagesR,
        patternLineageEExists: pattern.patternLineageExists || pattern.patternLineageRExists,
        patternDesc: pattern.patternDescExists ? pattern.patternDesc : '',
        patternBreadcrumb:
          pattern.patternGroup === pattern.patternSubGroup ?
          {
            patternType: pattern.patternGroup
          } : {
            patternType: pattern.patternGroup,
            patternSubtype: pattern.patternSubGroup
          },
        patternExtension: pattern.fileExtension.substr(1), //remove the dot because styleguide asset default adds it for us
        patternName: pattern.patternName,
        patternPartial: pattern.patternPartial,
        patternState: pattern.patternState,
        extraOutput: {}
      });

      //set the pattern-specific footer by compiling the general-footer with data, and then adding it to the meta footer
      var footerPartial = pattern_assembler.renderPattern(patternlab.footer, {
        isPattern: pattern.isPattern,
        patternData: pattern.patternData,
        cacheBuster: patternlab.cacheBuster
      });

      var footerHTML = pattern_assembler.renderPattern(patternlab.userFoot, {
        patternLabFoot : footerPartial
      });

      //default the output suffixes if not present
      var outputFileSuffixes = {
        rendered: '',
        rawTemplate: '',
        markupOnly: '.markup-only'
      }
      outputFileSuffixes = _.extend(outputFileSuffixes, patternlab.config.outputFileSuffixes);

      //write the compiled template to the public patterns directory
      var patternPage = headHTML + pattern.patternPartialCode + footerHTML;
      fs.outputFileSync(paths.public.patterns + pattern.patternLink.replace('.html', outputFileSuffixes.rendered + '.html'), patternPage);

      //write the mustache file too
      fs.outputFileSync(paths.public.patterns + pattern.patternLink.replace('.html', outputFileSuffixes.rawTemplate + pattern.fileExtension), pattern.template);

      //write the encoded version too
      fs.outputFileSync(paths.public.patterns + pattern.patternLink.replace('.html', outputFileSuffixes.markupOnly + '.html'), pattern.patternPartialCode);

      return true;
    });

    //export patterns if necessary
    pattern_exporter.export_patterns(patternlab);
  }

  return {
    version: function () {
      return getVersion();
    },
    build: function (callback, deletePatternDir) {
      buildPatterns(deletePatternDir);
      new ui().buildFrontend(patternlab);
      printDebug();
      callback();
    },
    help: function () {
      help();
    },
    patternsonly: function (callback, deletePatternDir) {
      buildPatterns(deletePatternDir);
      printDebug();
      callback();
    },
    liststarterkits: function () {
      return listStarterkits();
    },
    loadstarterkit: function (starterkitName, clean) {
      loadStarterKit(starterkitName, clean);
    }
  };
};

// export these free functions so they're available without calling the exported
// function, for use in reducing code dupe in unit tests. At least, until we
// have a better way to do this
patternlab_engine.build_pattern_data = buildPatternData;
patternlab_engine.process_all_patterns_iterative = processAllPatternsIterative;
patternlab_engine.process_all_patterns_recursive = processAllPatternsRecursive;

module.exports = patternlab_engine;
<|endoftext|>


<commit_before>import { Matrix4 } from '../math/Matrix4';
import { FloatType, RGBAFormat } from '../constants';
import { DataTexture } from '../textures/DataTexture';
import { _Math } from '../math/Math';

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 * @author michael guerrero / http://realitymeltdown.com
 * @author ikerr / http://verold.com
 */

function Skeleton( bones, boneInverses, useVertexTexture ) {

	this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true;

	this.identityMatrix = new Matrix4();

	// copy the bone array

	bones = bones || [];

	this.bones = bones.slice( 0 );

	// create a bone texture or an array of floats

	if ( this.useVertexTexture ) {

		// layout (1 matrix = 4 pixels)
		//      RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
		//  with  8x8  pixel texture max   16 bones * 4 pixels =  (8 * 8)
		//       16x16 pixel texture max   64 bones * 4 pixels = (16 * 16)
		//       32x32 pixel texture max  256 bones * 4 pixels = (32 * 32)
		//       64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)

		var size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix
		size = _Math.nextPowerOfTwo( Math.ceil( size ) );
		size = Math.max( size, 4 );

		this.boneTextureWidth = size;
		this.boneTextureHeight = size;

		this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel
		this.boneTexture = new DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, RGBAFormat, FloatType );

	} else {

		this.boneMatrices = new Float32Array( 16 * this.bones.length );

	}

	// use the supplied bone inverses or calculate the inverses

	if ( boneInverses === undefined ) {

		this.calculateInverses();

	} else {

		if ( this.bones.length === boneInverses.length ) {

			this.boneInverses = boneInverses.slice( 0 );

		} else {

			console.warn( 'THREE.Skeleton bonInverses is the wrong length.' );

			this.boneInverses = [];

			for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

				this.boneInverses.push( new Matrix4() );

			}

		}

	}

}

Object.assign( Skeleton.prototype, {

	calculateInverses: function () {

		this.boneInverses = [];

		for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

			var inverse = new Matrix4();

			if ( this.bones[ b ] ) {

				inverse.getInverse( this.bones[ b ].matrixWorld );

			}

			this.boneInverses.push( inverse );

		}

	},

	pose: function () {

		var bone;

		// recover the bind-time world matrices

		for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

			bone = this.bones[ b ];

			if ( bone ) {

				bone.matrixWorld.getInverse( this.boneInverses[ b ] );

			}

		}

		// compute the local matrices, positions, rotations and scales

		for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

			bone = this.bones[ b ];

			if ( bone ) {

				if ( bone.parent && bone.parent.isBone ) {

					bone.matrix.getInverse( bone.parent.matrixWorld );
					bone.matrix.multiply( bone.matrixWorld );

				} else {

					bone.matrix.copy( bone.matrixWorld );

				}

				bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );

			}

		}

	},

	update: ( function () {

		var offsetMatrix = new Matrix4();

		return function update() {

			// flatten bone matrices to array

			for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

				// compute the offset between the current and the original transform

				var matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix;

				offsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] );
				offsetMatrix.toArray( this.boneMatrices, b * 16 );

			}

			if ( this.useVertexTexture ) {

				this.boneTexture.needsUpdate = true;

			}

		};

	} )(),

	clone: function () {

		return new Skeleton( this.bones, this.boneInverses, this.useVertexTexture );

	}

} );

export { Skeleton };
<commit_msg>Fix typo in Skeleton<commit_after>import { Matrix4 } from '../math/Matrix4';
import { FloatType, RGBAFormat } from '../constants';
import { DataTexture } from '../textures/DataTexture';
import { _Math } from '../math/Math';

/**
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 * @author michael guerrero / http://realitymeltdown.com
 * @author ikerr / http://verold.com
 */

function Skeleton( bones, boneInverses, useVertexTexture ) {

	this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true;

	this.identityMatrix = new Matrix4();

	// copy the bone array

	bones = bones || [];

	this.bones = bones.slice( 0 );

	// create a bone texture or an array of floats

	if ( this.useVertexTexture ) {

		// layout (1 matrix = 4 pixels)
		//      RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
		//  with  8x8  pixel texture max   16 bones * 4 pixels =  (8 * 8)
		//       16x16 pixel texture max   64 bones * 4 pixels = (16 * 16)
		//       32x32 pixel texture max  256 bones * 4 pixels = (32 * 32)
		//       64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)

		var size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix
		size = _Math.nextPowerOfTwo( Math.ceil( size ) );
		size = Math.max( size, 4 );

		this.boneTextureWidth = size;
		this.boneTextureHeight = size;

		this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel
		this.boneTexture = new DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, RGBAFormat, FloatType );

	} else {

		this.boneMatrices = new Float32Array( 16 * this.bones.length );

	}

	// use the supplied bone inverses or calculate the inverses

	if ( boneInverses === undefined ) {

		this.calculateInverses();

	} else {

		if ( this.bones.length === boneInverses.length ) {

			this.boneInverses = boneInverses.slice( 0 );

		} else {

			console.warn( 'THREE.Skeleton boneInverses is the wrong length.' );

			this.boneInverses = [];

			for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

				this.boneInverses.push( new Matrix4() );

			}

		}

	}

}

Object.assign( Skeleton.prototype, {

	calculateInverses: function () {

		this.boneInverses = [];

		for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

			var inverse = new Matrix4();

			if ( this.bones[ b ] ) {

				inverse.getInverse( this.bones[ b ].matrixWorld );

			}

			this.boneInverses.push( inverse );

		}

	},

	pose: function () {

		var bone;

		// recover the bind-time world matrices

		for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

			bone = this.bones[ b ];

			if ( bone ) {

				bone.matrixWorld.getInverse( this.boneInverses[ b ] );

			}

		}

		// compute the local matrices, positions, rotations and scales

		for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

			bone = this.bones[ b ];

			if ( bone ) {

				if ( bone.parent && bone.parent.isBone ) {

					bone.matrix.getInverse( bone.parent.matrixWorld );
					bone.matrix.multiply( bone.matrixWorld );

				} else {

					bone.matrix.copy( bone.matrixWorld );

				}

				bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );

			}

		}

	},

	update: ( function () {

		var offsetMatrix = new Matrix4();

		return function update() {

			// flatten bone matrices to array

			for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {

				// compute the offset between the current and the original transform

				var matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix;

				offsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] );
				offsetMatrix.toArray( this.boneMatrices, b * 16 );

			}

			if ( this.useVertexTexture ) {

				this.boneTexture.needsUpdate = true;

			}

		};

	} )(),

	clone: function () {

		return new Skeleton( this.bones, this.boneInverses, this.useVertexTexture );

	}

} );

export { Skeleton };
<|endoftext|>


<commit_before>/*! Palindrom
 * https://github.com/Palindrom/Palindrom
 * (c) 2017 Joachim Wester
 * MIT license
 */

import PalindromNetworkChannel from './palindrom-network-channel';
import { applyPatch, validate } from 'fast-json-patch';
import JSONPatcherProxy from 'jsonpatcherproxy';
import { JSONPatchQueueSynchronous, JSONPatchQueue } from 'json-patch-queue';
import JSONPatchOT from 'json-patch-ot';
import JSONPatchOTAgent from 'json-patch-ot-agent';
import { PalindromConnectionError } from './palindrom-errors';
import Reconnector from './reconnector';
import { Heartbeat, NoHeartbeat } from './heartbeat';
import NoQueue from './noqueue';

/* this variable is bumped automatically when you call npm version */
const palindromVersion = '6.0.1';

if (typeof global === 'undefined') {
    if (typeof window !== 'undefined') {
        /* incase neither window nor global existed, e.g React Native */
        var global = window;
    } else {
        var global = {};
    }
}

/**
 * Defines a connection to a remote PATCH server, serves an object that is persistent between browser and server.
 * @param {Object} [options] map of arguments. See README.md for description
 */
export default class Palindrom {
    /**
     * Palindrom version
     */
    static get version() {
        return palindromVersion;
    }
    constructor(options) {
        /**
         * Palindrom instance version
         */
        this.version = palindromVersion;

        if (typeof options !== 'object') {
            throw new TypeError(
                'Palindrom constructor requires an object argument.'
            );
        }
        if (!options.remoteUrl) {
            throw new TypeError('remoteUrl is required');
        }

        if (options.callback) {
            console.warn(
                'options.callback is deprecated. Please use `onStateReset` instead'
            );
        }

        this.debug = options.debug != undefined ? options.debug : true;

        this.isObserving = false;

        function noop() {}

        this.onLocalChange = options.onLocalChange || noop;
        this.onRemoteChange = options.onRemoteChange || noop;
        this.onStateReset = options.onStateReset || options.callback || noop;
        this.filterLocalChange =
            options.filterLocalChange || (operation => operation);

        this.onPatchReceived = options.onPatchReceived || noop;
        this.onPatchSent = options.onPatchSent || noop;
        this.onSocketStateChanged = options.onSocketStateChanged || noop;
        this.onConnectionError = options.onConnectionError || noop;
        this.retransmissionThreshold = options.retransmissionThreshold || 3;
        this.onReconnectionCountdown = options.onReconnectionCountdown || noop;
        this.onReconnectionEnd = options.onReconnectionEnd || noop;
        this.onSocketOpened = options.onSocketOpened || noop;
        this.onIncomingPatchValidationError =
            options.onIncomingPatchValidationError || noop;
        this.onOutgoingPatchValidationError =
            options.onOutgoingPatchValidationError || noop;
        this.onError = options.onError || noop;

        this.reconnector = new Reconnector(
            () => makeReconnection(this),
            this.onReconnectionCountdown,
            this.onReconnectionEnd
        );

        this.retransmissionThreshold = options.retransmissionThreshold || 3;

        this.reconnector = new Reconnector(
            () => this._connectToRemote(JSON.stringify(this.queue.pending)),
            this.onReconnectionCountdown,
            this.onReconnectionEnd
        );

        if (options.pingIntervalS) {
            const intervalMs = options.pingIntervalS * 1000;
            this.heartbeat = new Heartbeat(
                this.ping.bind(this),
                this.handleConnectionError.bind(this),
                intervalMs,
                intervalMs
            );
        } else {
            this.heartbeat = new NoHeartbeat();
        }

        this.network = new PalindromNetworkChannel(
            this, // palindrom instance TODO: to be removed, used for error reporting
            options.remoteUrl,
            options.useWebSocket || false, // useWebSocket
            this.handleRemoteChange.bind(this), //onReceive
            this.onPatchSent.bind(this), //onSend,
            this.handleConnectionError.bind(this),
            this.onSocketOpened.bind(this),
            this.handleFatalError.bind(this), //onFatalError,
            this.onSocketStateChanged.bind(this) //onStateChange
        );
        /**
         * how many OT operations are there in each patch 0, 1 or 2
         */
        this.OTPatchIndexOffset = 0;
        // choose queuing engine
        if (options.localVersionPath) {
            if (!options.remoteVersionPath) {
                this.OTPatchIndexOffset = 1;
                // just versioning
                this.queue = new JSONPatchQueueSynchronous(
                    this.obj,
                    options.localVersionPath,
                    this.validateAndApplySequence.bind(this),
                    options.purity
                );
            } else {
                this.OTPatchIndexOffset = 2;
                // double versioning or OT
                if (options.ot) {
                    this.queue = new JSONPatchOTAgent(
                        this.obj,
                        JSONPatchOT.transform,
                        [options.localVersionPath, options.remoteVersionPath],
                        this.validateAndApplySequence.bind(this),
                        options.purity
                    );
                } else {
                    this.queue = new JSONPatchQueue(
                        this.obj,
                        [options.localVersionPath, options.remoteVersionPath],
                        this.validateAndApplySequence.bind(this),
                        options.purity
                    ); // full or noop OT
                }
            }
        } else {
            // no queue - just api
            this.queue = new NoQueue(
                this.obj,
                this.validateAndApplySequence.bind(this)
            );
        }
        this._connectToRemote();
    }
    async _connectToRemote(reconnectionPendingData = null) {
        this.heartbeat.stop();
        const json = await this.network._establish(reconnectionPendingData);
        this.reconnector.stopReconnecting();

        if (this.debug) {
            this.remoteObj = JSON.parse(JSON.stringify(json));
        }

        this.queue.reset(json);
        this.heartbeat.start();
    }
    get useWebSocket() {
        return this.network.useWebSocket;
    }
    set useWebSocket(newValue) {
        this.network.useWebSocket = newValue;
    }

    ping() {
        this._sendPatches([]); // sends empty message to server
    }

    _sendPatches(patches) {
        const txt = JSON.stringify(patches);
        this.unobserve();
        this.heartbeat.notifySend();
        this.network.send(txt);
        this.observe();
    }
    /**
     * Closes the Palindrom session probably
     */
    closeConnection() {
        this.network.closeConnection();
    }

    prepareProxifiedObject(obj) {
        if (!obj) {
            obj = {};
        }
        /* wrap a new object with a proxy observer */
        this.jsonPatcherProxy = new JSONPatcherProxy(obj);

        const proxifiedObj = this.jsonPatcherProxy.observe(false, operation => {
            const filtered = this.filterLocalChange(operation);
            // totally ignore falsy (didn't pass the filter) JSON Patch operations
            filtered && this.handleLocalChange(filtered);
        });

        /* make it read-only and expose it as `obj` */
        Object.defineProperty(this, 'obj', {
            get() {
                return proxifiedObj;
            },
            set() {
                throw new Error('palindrom.obj is readonly');
            },
            /* so that we can redefine it */
            configurable: true
        });
        /* JSONPatcherProxy default state is observing */
        this.isObserving = true;
    }

    observe() {
        this.jsonPatcherProxy && this.jsonPatcherProxy.resume();
        this.isObserving = true;
    }

    unobserve() {
        this.jsonPatcherProxy && this.jsonPatcherProxy.pause();
        this.isObserving = false;
    }

    handleLocalChange(operation) {
        // it's a single operation, we need to check only it's value
        operation.value &&
            findRangeErrors(
                operation.value,
                this.onOutgoingPatchValidationError,
                operation.path
            );

        const patches = [operation];
        if (this.debug) {
            this.validateSequence(this.remoteObj, patches);
        }

        this._sendPatches(this.queue.send(patches));
        this.onLocalChange(patches);
    }

    validateAndApplySequence(tree, sequence) {
        try {
            // we don't want this changes to generate patches since they originate from server, not client
            this.unobserve();
            const results = applyPatch(tree, sequence, this.debug);
            // notifications have to happen only where observe has been re-enabled
            // otherwise some listener might produce changes that would go unnoticed
            this.observe();
            // the state was fully replaced
            if (results.newDocument !== tree) {
                // object was reset, proxify it again
                this.prepareProxifiedObject(results.newDocument);

                this.queue.obj = this.obj;

                // validate json response
                findRangeErrors(this.obj, this.onIncomingPatchValidationError);
                this.onStateReset(this.obj);
            }
            this.onRemoteChange(sequence, results);
        } catch (error) {
            if (this.debug) {
                this.onIncomingPatchValidationError(error);
                return;
            } else {
                throw error;
            }
        }
        return this.obj;
    }

    validateSequence(tree, sequence) {
        const error = validate(sequence, tree);
        if (error) {
            this.onOutgoingPatchValidationError(error);
        }
    }

    /**
     * Handle an error which is probably caused by random disconnection
     */
    handleConnectionError() {
        this.heartbeat.stop();
        this.reconnector.triggerReconnection();
        this.onConnectionError();
    }

    /**
     * Handle an error which probably won't go away on itself (basically forward upstream)
     * @param {PalindromConnectionError} palindromError
     */
    handleFatalError(palindromError) {
        this.heartbeat.stop();
        this.reconnector.stopReconnecting();
        this.onConnectionError(palindromError);
    }

    reconnectNow() {
        this.reconnector.reconnectNow();
    }

    handleRemoteChange(data, url, method) {
        this.onPatchReceived(data, url, method);

        this.heartbeat.notifyReceive();
        const patches = data || []; // fault tolerance - empty response string should be treated as empty patch array

        validateNumericsRangesInPatch(
            patches,
            this.onIncomingPatchValidationError,
            this.OTPatchIndexOffset
        );

        if (patches.length === 0) {
            // ping message
            return;
        }

        // apply only if we're still watching
        if (!this.isObserving) {
            return;
        }
        this.queue.receive(patches);
        if (
            this.queue.pending &&
            this.queue.pending.length &&
            this.queue.pending.length > this.retransmissionThreshold
        ) {
            // remote counterpart probably failed to receive one of earlier messages, because it has been receiving
            // (but not acknowledging messages for some time
            this.queue.pending.forEach(this._sendPatches, this);
        }

        if (this.debug) {
            this.remoteObj = JSON.parse(JSON.stringify(this.obj));
        }
    }
}

/**
 * Iterates a JSON-Patch, traversing every patch value looking for out-of-range numbers
 * @param {JSONPatch} patch patch to check
 * @param {Function} errorHandler the error handler callback
 * @param {*} startFrom the index where iteration starts
 */
function validateNumericsRangesInPatch(patch, errorHandler, startFrom) {
    for (let i = startFrom, len = patch.length; i < len; i++) {
        findRangeErrors(patch[i].value, errorHandler, patch[i].path);
    }
}

/**
 * Traverses/checks value looking for out-of-range numbers, throws a RangeError if it finds any
 * @param {*} val value
 * @param {Function} errorHandler
 */
function findRangeErrors(val, errorHandler, variablePath = '') {
    const type = typeof val;
    if (type == 'object') {
        for (const key in val) {
            if (val.hasOwnProperty(key)) {
                findRangeErrors(
                    val[key],
                    errorHandler,
                    variablePath + '/' + key
                );
            }
        }
    } else if (
        type === 'number' &&
        (val > Number.MAX_SAFE_INTEGER || val < Number.MIN_SAFE_INTEGER)
    ) {
        errorHandler(
            new RangeError(
                `A number that is either bigger than Number.MAX_INTEGER_VALUE or smaller than Number.MIN_INTEGER_VALUE has been encountered in a patch, value is: ${val}, variable path is: ${variablePath}`
            )
        );
    }
}
<commit_msg>Remove reconnection pending data redundant stringifying<commit_after>/*! Palindrom
 * https://github.com/Palindrom/Palindrom
 * (c) 2017 Joachim Wester
 * MIT license
 */

import PalindromNetworkChannel from './palindrom-network-channel';
import { applyPatch, validate } from 'fast-json-patch';
import JSONPatcherProxy from 'jsonpatcherproxy';
import { JSONPatchQueueSynchronous, JSONPatchQueue } from 'json-patch-queue';
import JSONPatchOT from 'json-patch-ot';
import JSONPatchOTAgent from 'json-patch-ot-agent';
import { PalindromConnectionError } from './palindrom-errors';
import Reconnector from './reconnector';
import { Heartbeat, NoHeartbeat } from './heartbeat';
import NoQueue from './noqueue';

/* this variable is bumped automatically when you call npm version */
const palindromVersion = '6.0.1';

if (typeof global === 'undefined') {
    if (typeof window !== 'undefined') {
        /* incase neither window nor global existed, e.g React Native */
        var global = window;
    } else {
        var global = {};
    }
}

/**
 * Defines a connection to a remote PATCH server, serves an object that is persistent between browser and server.
 * @param {Object} [options] map of arguments. See README.md for description
 */
export default class Palindrom {
    /**
     * Palindrom version
     */
    static get version() {
        return palindromVersion;
    }
    constructor(options) {
        /**
         * Palindrom instance version
         */
        this.version = palindromVersion;

        if (typeof options !== 'object') {
            throw new TypeError(
                'Palindrom constructor requires an object argument.'
            );
        }
        if (!options.remoteUrl) {
            throw new TypeError('remoteUrl is required');
        }

        if (options.callback) {
            console.warn(
                'options.callback is deprecated. Please use `onStateReset` instead'
            );
        }

        this.debug = options.debug != undefined ? options.debug : true;

        this.isObserving = false;

        function noop() {}

        this.onLocalChange = options.onLocalChange || noop;
        this.onRemoteChange = options.onRemoteChange || noop;
        this.onStateReset = options.onStateReset || options.callback || noop;
        this.filterLocalChange =
            options.filterLocalChange || (operation => operation);

        this.onPatchReceived = options.onPatchReceived || noop;
        this.onPatchSent = options.onPatchSent || noop;
        this.onSocketStateChanged = options.onSocketStateChanged || noop;
        this.onConnectionError = options.onConnectionError || noop;
        this.retransmissionThreshold = options.retransmissionThreshold || 3;
        this.onReconnectionCountdown = options.onReconnectionCountdown || noop;
        this.onReconnectionEnd = options.onReconnectionEnd || noop;
        this.onSocketOpened = options.onSocketOpened || noop;
        this.onIncomingPatchValidationError =
            options.onIncomingPatchValidationError || noop;
        this.onOutgoingPatchValidationError =
            options.onOutgoingPatchValidationError || noop;
        this.onError = options.onError || noop;

        this.reconnector = new Reconnector(
            () => makeReconnection(this),
            this.onReconnectionCountdown,
            this.onReconnectionEnd
        );

        this.retransmissionThreshold = options.retransmissionThreshold || 3;

        this.reconnector = new Reconnector(
            () => this._connectToRemote(this.queue.pending),
            this.onReconnectionCountdown,
            this.onReconnectionEnd
        );

        if (options.pingIntervalS) {
            const intervalMs = options.pingIntervalS * 1000;
            this.heartbeat = new Heartbeat(
                this.ping.bind(this),
                this.handleConnectionError.bind(this),
                intervalMs,
                intervalMs
            );
        } else {
            this.heartbeat = new NoHeartbeat();
        }

        this.network = new PalindromNetworkChannel(
            this, // palindrom instance TODO: to be removed, used for error reporting
            options.remoteUrl,
            options.useWebSocket || false, // useWebSocket
            this.handleRemoteChange.bind(this), //onReceive
            this.onPatchSent.bind(this), //onSend,
            this.handleConnectionError.bind(this),
            this.onSocketOpened.bind(this),
            this.handleFatalError.bind(this), //onFatalError,
            this.onSocketStateChanged.bind(this) //onStateChange
        );
        /**
         * how many OT operations are there in each patch 0, 1 or 2
         */
        this.OTPatchIndexOffset = 0;
        // choose queuing engine
        if (options.localVersionPath) {
            if (!options.remoteVersionPath) {
                this.OTPatchIndexOffset = 1;
                // just versioning
                this.queue = new JSONPatchQueueSynchronous(
                    this.obj,
                    options.localVersionPath,
                    this.validateAndApplySequence.bind(this),
                    options.purity
                );
            } else {
                this.OTPatchIndexOffset = 2;
                // double versioning or OT
                if (options.ot) {
                    this.queue = new JSONPatchOTAgent(
                        this.obj,
                        JSONPatchOT.transform,
                        [options.localVersionPath, options.remoteVersionPath],
                        this.validateAndApplySequence.bind(this),
                        options.purity
                    );
                } else {
                    this.queue = new JSONPatchQueue(
                        this.obj,
                        [options.localVersionPath, options.remoteVersionPath],
                        this.validateAndApplySequence.bind(this),
                        options.purity
                    ); // full or noop OT
                }
            }
        } else {
            // no queue - just api
            this.queue = new NoQueue(
                this.obj,
                this.validateAndApplySequence.bind(this)
            );
        }
        this._connectToRemote();
    }
    async _connectToRemote(reconnectionPendingData = null) {
        this.heartbeat.stop();
        const json = await this.network._establish(reconnectionPendingData);
        this.reconnector.stopReconnecting();

        if (this.debug) {
            this.remoteObj = JSON.parse(JSON.stringify(json));
        }

        this.queue.reset(json);
        this.heartbeat.start();
    }
    get useWebSocket() {
        return this.network.useWebSocket;
    }
    set useWebSocket(newValue) {
        this.network.useWebSocket = newValue;
    }

    ping() {
        this._sendPatches([]); // sends empty message to server
    }

    _sendPatches(patches) {
        const txt = JSON.stringify(patches);
        this.unobserve();
        this.heartbeat.notifySend();
        this.network.send(txt);
        this.observe();
    }
    /**
     * Closes the Palindrom session probably
     */
    closeConnection() {
        this.network.closeConnection();
    }

    prepareProxifiedObject(obj) {
        if (!obj) {
            obj = {};
        }
        /* wrap a new object with a proxy observer */
        this.jsonPatcherProxy = new JSONPatcherProxy(obj);

        const proxifiedObj = this.jsonPatcherProxy.observe(false, operation => {
            const filtered = this.filterLocalChange(operation);
            // totally ignore falsy (didn't pass the filter) JSON Patch operations
            filtered && this.handleLocalChange(filtered);
        });

        /* make it read-only and expose it as `obj` */
        Object.defineProperty(this, 'obj', {
            get() {
                return proxifiedObj;
            },
            set() {
                throw new Error('palindrom.obj is readonly');
            },
            /* so that we can redefine it */
            configurable: true
        });
        /* JSONPatcherProxy default state is observing */
        this.isObserving = true;
    }

    observe() {
        this.jsonPatcherProxy && this.jsonPatcherProxy.resume();
        this.isObserving = true;
    }

    unobserve() {
        this.jsonPatcherProxy && this.jsonPatcherProxy.pause();
        this.isObserving = false;
    }

    handleLocalChange(operation) {
        // it's a single operation, we need to check only it's value
        operation.value &&
            findRangeErrors(
                operation.value,
                this.onOutgoingPatchValidationError,
                operation.path
            );

        const patches = [operation];
        if (this.debug) {
            this.validateSequence(this.remoteObj, patches);
        }

        this._sendPatches(this.queue.send(patches));
        this.onLocalChange(patches);
    }

    validateAndApplySequence(tree, sequence) {
        try {
            // we don't want this changes to generate patches since they originate from server, not client
            this.unobserve();
            const results = applyPatch(tree, sequence, this.debug);
            // notifications have to happen only where observe has been re-enabled
            // otherwise some listener might produce changes that would go unnoticed
            this.observe();
            // the state was fully replaced
            if (results.newDocument !== tree) {
                // object was reset, proxify it again
                this.prepareProxifiedObject(results.newDocument);

                this.queue.obj = this.obj;

                // validate json response
                findRangeErrors(this.obj, this.onIncomingPatchValidationError);
                this.onStateReset(this.obj);
            }
            this.onRemoteChange(sequence, results);
        } catch (error) {
            if (this.debug) {
                this.onIncomingPatchValidationError(error);
                return;
            } else {
                throw error;
            }
        }
        return this.obj;
    }

    validateSequence(tree, sequence) {
        const error = validate(sequence, tree);
        if (error) {
            this.onOutgoingPatchValidationError(error);
        }
    }

    /**
     * Handle an error which is probably caused by random disconnection
     */
    handleConnectionError() {
        this.heartbeat.stop();
        this.reconnector.triggerReconnection();
        this.onConnectionError();
    }

    /**
     * Handle an error which probably won't go away on itself (basically forward upstream)
     * @param {PalindromConnectionError} palindromError
     */
    handleFatalError(palindromError) {
        this.heartbeat.stop();
        this.reconnector.stopReconnecting();
        this.onConnectionError(palindromError);
    }

    reconnectNow() {
        this.reconnector.reconnectNow();
    }

    handleRemoteChange(data, url, method) {
        this.onPatchReceived(data, url, method);

        this.heartbeat.notifyReceive();
        const patches = data || []; // fault tolerance - empty response string should be treated as empty patch array

        validateNumericsRangesInPatch(
            patches,
            this.onIncomingPatchValidationError,
            this.OTPatchIndexOffset
        );

        if (patches.length === 0) {
            // ping message
            return;
        }

        // apply only if we're still watching
        if (!this.isObserving) {
            return;
        }
        this.queue.receive(patches);
        if (
            this.queue.pending &&
            this.queue.pending.length &&
            this.queue.pending.length > this.retransmissionThreshold
        ) {
            // remote counterpart probably failed to receive one of earlier messages, because it has been receiving
            // (but not acknowledging messages for some time
            this.queue.pending.forEach(this._sendPatches, this);
        }

        if (this.debug) {
            this.remoteObj = JSON.parse(JSON.stringify(this.obj));
        }
    }
}

/**
 * Iterates a JSON-Patch, traversing every patch value looking for out-of-range numbers
 * @param {JSONPatch} patch patch to check
 * @param {Function} errorHandler the error handler callback
 * @param {*} startFrom the index where iteration starts
 */
function validateNumericsRangesInPatch(patch, errorHandler, startFrom) {
    for (let i = startFrom, len = patch.length; i < len; i++) {
        findRangeErrors(patch[i].value, errorHandler, patch[i].path);
    }
}

/**
 * Traverses/checks value looking for out-of-range numbers, throws a RangeError if it finds any
 * @param {*} val value
 * @param {Function} errorHandler
 */
function findRangeErrors(val, errorHandler, variablePath = '') {
    const type = typeof val;
    if (type == 'object') {
        for (const key in val) {
            if (val.hasOwnProperty(key)) {
                findRangeErrors(
                    val[key],
                    errorHandler,
                    variablePath + '/' + key
                );
            }
        }
    } else if (
        type === 'number' &&
        (val > Number.MAX_SAFE_INTEGER || val < Number.MIN_SAFE_INTEGER)
    ) {
        errorHandler(
            new RangeError(
                `A number that is either bigger than Number.MAX_INTEGER_VALUE or smaller than Number.MIN_INTEGER_VALUE has been encountered in a patch, value is: ${val}, variable path is: ${variablePath}`
            )
        );
    }
}
<|endoftext|>