<commit_before>/* -*- Mode: js; js-indent-level: 2; -*- */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Mozilla Source Map.
 *
 * The Initial Developer of the Original Code is Mozilla.
 * Portions created by the Initial Developer are Copyright (C) 2011
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Nick Fitzgerald <nfitzgerald@mozilla.com> (original author)
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */
define(function (require, exports, module) {

  var assert = require('assert');
  var ArraySet = require('source-map/array-set').ArraySet;

  function makeTestSet() {
    var set = new ArraySet();
    for (var i = 0; i < 100; i++) {
      set.add(String(i));
    }
    return set;
  }

  exports['test .has() membership'] = function () {
    var set = makeTestSet();
    for (var i = 0; i < 100; i++) {
      assert.ok(set.has(String(i)));
    }
  };

  exports['test .indexOf() elements'] = function () {
    var set = makeTestSet();
    for (var i = 0; i < 100; i++) {
      assert.strictEqual(set.indexOf(String(i)), i);
    }
  };

  exports['test .at() indexing'] = function () {
    var set = makeTestSet();
    for (var i = 0; i < 100; i++) {
      assert.strictEqual(set.at(i), String(i));
    }
  };

  exports['test creating from an array'] = function () {
    var set = ArraySet.fromArray(['foo', 'bar', 'baz', 'quux']);

    assert.ok(set.has('foo'));
    assert.ok(set.has('bar'));
    assert.ok(set.has('baz'));
    assert.ok(set.has('quux'));

    assert.strictEqual(set.indexOf('foo'), 0);
    assert.strictEqual(set.indexOf('bar'), 1);
    assert.strictEqual(set.indexOf('baz'), 2);
    assert.strictEqual(set.indexOf('quux'), 3);

    assert.strictEqual(set.at(0), 'foo');
    assert.strictEqual(set.at(1), 'bar');
    assert.strictEqual(set.at(2), 'baz');
    assert.strictEqual(set.at(3), 'quux');
  };

});
<commit_msg>Let's make sure it doesn't fail on `hasOwnProperty`<commit_after>/* -*- Mode: js; js-indent-level: 2; -*- */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Mozilla Source Map.
 *
 * The Initial Developer of the Original Code is Mozilla.
 * Portions created by the Initial Developer are Copyright (C) 2011
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Nick Fitzgerald <nfitzgerald@mozilla.com> (original author)
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */
define(function (require, exports, module) {

  var assert = require('assert');
  var ArraySet = require('source-map/array-set').ArraySet;

  function makeTestSet() {
    var set = new ArraySet();
    for (var i = 0; i < 100; i++) {
      set.add(String(i));
    }
    return set;
  }

  exports['test .has() membership'] = function () {
    var set = makeTestSet();
    for (var i = 0; i < 100; i++) {
      assert.ok(set.has(String(i)));
    }
  };

  exports['test .indexOf() elements'] = function () {
    var set = makeTestSet();
    for (var i = 0; i < 100; i++) {
      assert.strictEqual(set.indexOf(String(i)), i);
    }
  };

  exports['test .at() indexing'] = function () {
    var set = makeTestSet();
    for (var i = 0; i < 100; i++) {
      assert.strictEqual(set.at(i), String(i));
    }
  };

  exports['test creating from an array'] = function () {
    var set = ArraySet.fromArray(['foo', 'bar', 'baz', 'quux', 'hasOwnProperty']);

    assert.ok(set.has('foo'));
    assert.ok(set.has('bar'));
    assert.ok(set.has('baz'));
    assert.ok(set.has('quux'));
    assert.ok(set.has('hasOwnProperty'));

    assert.strictEqual(set.indexOf('foo'), 0);
    assert.strictEqual(set.indexOf('bar'), 1);
    assert.strictEqual(set.indexOf('baz'), 2);
    assert.strictEqual(set.indexOf('quux'), 3);

    assert.strictEqual(set.at(0), 'foo');
    assert.strictEqual(set.at(1), 'bar');
    assert.strictEqual(set.at(2), 'baz');
    assert.strictEqual(set.at(3), 'quux');
  };

});
<|endoftext|>


<commit_before>var should = require('chai').should();
var fs = require('fs');

var stripdata = require('../bin/stripdata.js');

describe('stripdata', function() {

	beforeEach(function() {
		resetOptions();
	});

	describe('general functionality', function() {

		it('should not modify data when no options', function(done) {
			var inputData = readInputTestFile();

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();
				inputData.should.deep.equal(outputData);
				deleteFilesCreated();

				done();
			});
		});

		it('should remove the model name for a specific model', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.stripModels = ['Model A'];

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				outputData[0].deviceId.should.deep.equal('smbg device-456456');
				outputData[1].deviceId.should.deep.equal('Model B-defdef');
				outputData[2].deviceId.should.deep.equal('Model C-654654');
				outputData[3].deviceId.should.deep.equal('basal device-cbacba');
				outputData[4].deviceId.should.deep.equal('Model B-fedfed');
				deleteFilesCreated();

				done();
			});
		});

		it('should remove the model for muliple specified models', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.stripModels = ['Model A', 'Model B'];

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				outputData[0].deviceId.should.deep.equal('smbg device-456456');
				outputData[1].deviceId.should.deep.equal('cbg device-defdef');
				outputData[2].deviceId.should.deep.equal('Model C-654654');
				outputData[3].deviceId.should.deep.equal('basal device-cbacba');
				outputData[4].deviceId.should.deep.equal('deviceEvent device-fedfed');
				deleteFilesCreated();

				done();
			});
		});

		it('should remove the serial number for a given model', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.stripSNs = ['Model A'];

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				outputData[0].deviceId.should.deep.equal('Model A-Serial Number');
				outputData[1].deviceId.should.deep.equal('Model B-defdef');
				outputData[2].deviceId.should.deep.equal('Model C-654654');
				outputData[3].deviceId.should.deep.equal('Model A-Serial Number');
				outputData[4].deviceId.should.deep.equal('Model B-fedfed');
				deleteFilesCreated();

				done();
			});
		});

		it('should not remove the serial number for multiple specified models', function(done) {

		});

		it('should strip all models and serial numbers');
		it('should strip all models and serial numbers except the model for the given model');
		it('should strip all models and serial numbers except the serial number for the given model');
		it('should remove the given data type');
		it('should remove all data types');
		it('should remove all data types except for the given data type');
		it('should hash all of the ID types');
		it('should remove the source field');

	})

	describe('#splitDeviceId()', function() {

		it('should split a deviceId at the \'-\'', function() {
			var splitId = stripdata.splitDeviceId('Model A-123456789');
			splitId.should.be.a('array');
			splitId.should.have.length(2);
			splitId.should.deep.equal(['Model A', '123456789']);
		});

		it('should split a deviceId at the \'_\'', function() {
			var splitId = stripdata.splitDeviceId('Model B_987654321');
			splitId.should.be.a('array');
			splitId.should.have.length(2);
			splitId.should.deep.equal(['Model B', '987654321']);
		});

		it('should split a deviceId with multiple \'-\' in the model', function() {
			var splitId = stripdata.splitDeviceId('Model-C-Version-Z-12341234');
			splitId.should.be.a('array');
			splitId.should.have.length(2);
			splitId.should.deep.equal(['Model-C-Version-Z', '12341234']);
		});

	});

	describe('#hashIDsForData()', function() {

		it('should not hash Ids if option not selected', function() {
			stripdata.program.hashIDs = false;
			var data = readInputTestFile();
			for (var i in data) {
				var chunk = {val: data[i]};
				var expectGroup = data[i]._groupId;
				var expectUpload = data[i].uploadId;
				stripdata.hashIDsForData(chunk);
				should.exist(chunk.val._groupId);
				should.not.exist(chunk.val.hash_groupId);
				chunk.val._groupId.should.equal(expectGroup);
				should.exist(chunk.val.uploadId);
				should.not.exist(chunk.val.hash_uploadId);
				chunk.val.uploadId.should.equal(expectUpload);
			}
		});

		it('should hash all Ids if option is selected', function() {
			stripdata.program.hashIDs = true;
			var data = readInputTestFile();
			for (var i in data) {
				var chunk = {val: data[i]};
				var expectGroup = data[i]._groupId;
				var expectUpload = data[i].uploadId;
				stripdata.hashIDsForData(chunk);
				should.not.exist(chunk.val._groupId);
				should.exist(chunk.val.hash_groupId);
				chunk.val.hash_groupId.should.not.equal(expectGroup);
				should.not.exist(chunk.val.uploadId);
				should.exist(chunk.val.hash_uploadId);
				chunk.val.hash_uploadId.should.not.equal(expectUpload);
			}
		});

	});
});

function resetOptions() {
	stripdata.program.input = 'test/testdata.json';
	stripdata.program.output = 'test/testdataout.json';
	stripdata.program.stripModels = [];
	stripdata.program.stripSNs = [];
	stripdata.program.leaveModels = [];
	stripdata.program.stripAll = false;
	stripdata.program.removeTypes = [];
	stripdata.program.leaveTypes = [];
	stripdata.program.removeAll = false;
	stripdata.program.hashIDs = false;
	stripdata.program.removeSource = false;
	stripdata.program.verbose = false;
}

function readInputTestFile() {
	var input = fs.readFileSync('test/testdata.json', {encoding: 'utf8'});
	return JSON.parse(input);
}

function readOutputTestFile() {
	var output = fs.readFileSync('test/testdataout.json', {encoding: 'utf8'});
	return JSON.parse(output);
}

function deleteFilesCreated() {
	const execSync = require('child_process').execSync;
	execSync('rm test/testdataout.json');
}<commit_msg>Finished tests for stripdata<commit_after>var should = require('chai').should();
var fs = require('fs');

var stripdata = require('../bin/stripdata.js');

describe('stripdata', function() {

	beforeEach(function() {
		resetOptions();
	});

	describe('general functionality', function() {

		it('should not modify data when no options', function(done) {
			var inputData = readInputTestFile();

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();
				inputData.should.deep.equal(outputData);
				deleteFilesCreated();

				done();
			});
		});

		it('should remove the model name for a specific model', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.stripModels = ['Model A'];

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				outputData[0].deviceId.should.deep.equal('smbg device-456456');
				outputData[1].deviceId.should.deep.equal('Model B-defdef');
				outputData[2].deviceId.should.deep.equal('Model C-654654');
				outputData[3].deviceId.should.deep.equal('basal device-cbacba');
				outputData[4].deviceId.should.deep.equal('Model B-fedfed');
				deleteFilesCreated();

				done();
			});
		});

		it('should remove the model for muliple specified models', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.stripModels = ['Model A', 'Model B'];

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				outputData[0].deviceId.should.deep.equal('smbg device-456456');
				outputData[1].deviceId.should.deep.equal('cbg device-defdef');
				outputData[2].deviceId.should.deep.equal('Model C-654654');
				outputData[3].deviceId.should.deep.equal('basal device-cbacba');
				outputData[4].deviceId.should.deep.equal('deviceEvent device-fedfed');
				deleteFilesCreated();

				done();
			});
		});

		it('should remove the serial number for a given model', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.stripSNs = ['Model A'];

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				outputData[0].deviceId.should.deep.equal('Model A-Serial Number');
				outputData[1].deviceId.should.deep.equal('Model B-defdef');
				outputData[2].deviceId.should.deep.equal('Model C-654654');
				outputData[3].deviceId.should.deep.equal('Model A-Serial Number');
				outputData[4].deviceId.should.deep.equal('Model B-fedfed');
				deleteFilesCreated();

				done();
			});
		});

		it('should not remove the serial number for multiple specified models', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.stripSNs = ['Model A', 'Model B'];

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				outputData[0].deviceId.should.deep.equal('Model A-Serial Number');
				outputData[1].deviceId.should.deep.equal('Model B-Serial Number');
				outputData[2].deviceId.should.deep.equal('Model C-654654');
				outputData[3].deviceId.should.deep.equal('Model A-Serial Number');
				outputData[4].deviceId.should.deep.equal('Model B-Serial Number');
				deleteFilesCreated();

				done();
			});
		});

		it('should remove the model and serial number for the specified model', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.stripModels = ['Model A'];
			stripdata.program.stripSNs = ['Model A'];

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				outputData[0].deviceId.should.deep.equal('smbg device-Serial Number');
				outputData[1].deviceId.should.deep.equal('Model B-defdef');
				outputData[2].deviceId.should.deep.equal('Model C-654654');
				outputData[3].deviceId.should.deep.equal('basal device-Serial Number');
				outputData[4].deviceId.should.deep.equal('Model B-fedfed');
				deleteFilesCreated();

				done();
			});
		});

		it('should strip all models and serial numbers', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.stripAll = true;

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				outputData[0].deviceId.should.deep.equal('smbg device-Serial Number');
				outputData[1].deviceId.should.deep.equal('cbg device-Serial Number');
				outputData[2].deviceId.should.deep.equal('bolus device-Serial Number');
				outputData[3].deviceId.should.deep.equal('basal device-Serial Number');
				outputData[4].deviceId.should.deep.equal('deviceEvent device-Serial Number');
				deleteFilesCreated();

				done();
			});
		});

		it('should strip all models and serial numbers except the model for the given model', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.stripAll = true;
			stripdata.program.leaveModels = ['Model A'];

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				outputData[0].deviceId.should.deep.equal('Model A-Serial Number');
				outputData[1].deviceId.should.deep.equal('cbg device-Serial Number');
				outputData[2].deviceId.should.deep.equal('bolus device-Serial Number');
				outputData[3].deviceId.should.deep.equal('Model A-Serial Number');
				outputData[4].deviceId.should.deep.equal('deviceEvent device-Serial Number');
				deleteFilesCreated();

				done();
			});
		});

		it('should strip all models and serial numbers except the serial number for the given model', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.stripAll = true;
			stripdata.program.leaveSNs = ['Model A'];

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				outputData[0].deviceId.should.deep.equal('smbg device-456456');
				outputData[1].deviceId.should.deep.equal('cbg device-Serial Number');
				outputData[2].deviceId.should.deep.equal('bolus device-Serial Number');
				outputData[3].deviceId.should.deep.equal('basal device-cbacba');
				outputData[4].deviceId.should.deep.equal('deviceEvent device-Serial Number');
				deleteFilesCreated();

				done();
			});
		});

		it('should remove the given data type', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.removeTypes = ['cbg'];

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				outputData.length.should.deep.equal(4);
				outputData[0].deviceId.should.deep.equal('Model A-456456');
				outputData[1].deviceId.should.deep.equal('Model C-654654');
				outputData[2].deviceId.should.deep.equal('Model A-cbacba');
				outputData[3].deviceId.should.deep.equal('Model B-fedfed');
				deleteFilesCreated();

				done();
			});
		});

		it('should remove all data types', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.removeAll = true;

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				outputData.length.should.deep.equal(0);
				deleteFilesCreated();

				done();
			});
		});

		it('should remove all data types except for the given data type', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.removeAll = true;
			stripdata.program.leaveTypes = ['cbg'];

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				outputData.length.should.deep.equal(1);
				outputData[0].deviceId.should.deep.equal('Model B-defdef');
				deleteFilesCreated();

				done();
			});
		});

		it('should hash all of the ID types if option is selected', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.hashIDs = true;

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				for (var i in outputData) {
					var expectGroup = inputData[i]._groupId;
					var expectUpload = inputData[i].uploadId;
					should.not.exist(outputData[i]._groupId);
					should.exist(outputData[i].hash_groupId);
					outputData[i].hash_groupId.should.not.equal(expectGroup);
					should.not.exist(outputData[i].uploadId);
					should.exist(outputData[i].hash_uploadId);
					outputData[i].hash_uploadId.should.not.equal(expectUpload);
				}
				deleteFilesCreated();

				done();
			});
		});

		it('should not hash all of the ID types if option is not selected', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.hashIDs = false;

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				for (var i in outputData) {
					var expectGroup = inputData[i]._groupId;
					var expectUpload = inputData[i].uploadId;
					should.exist(outputData[i]._groupId);
					should.not.exist(outputData[i].hash_groupId);
					outputData[i]._groupId.should.equal(expectGroup);
					should.exist(outputData[i].uploadId);
					should.not.exist(outputData[i].hash_uploadId);
					outputData[i].uploadId.should.equal(expectUpload);
				}
				deleteFilesCreated();

				done();
			});
		});

		it('should remove the source field if option is selected', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.removeSource = true;

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				for (var i in outputData) {
					should.not.exist(outputData[i].source);
				}
				deleteFilesCreated();

				done();
			});
		});

		it('should not remove the source field if option is not selected', function(done) {
			var inputData = readInputTestFile();

			stripdata.program.removeSource = false;

			stripdata.performDataStripping(function() {
				var outputData = readOutputTestFile();

				for (var i in outputData) {
					should.exist(outputData[i].source);
				}
				deleteFilesCreated();

				done();
			});
		});

	})

	describe('#splitDeviceId()', function() {

		it('should split a deviceId at the \'-\'', function() {
			var splitId = stripdata.splitDeviceId('Model A-123456789');
			splitId.should.be.a('array');
			splitId.should.have.length(2);
			splitId.should.deep.equal(['Model A', '123456789']);
		});

		it('should split a deviceId at the \'_\'', function() {
			var splitId = stripdata.splitDeviceId('Model B_987654321');
			splitId.should.be.a('array');
			splitId.should.have.length(2);
			splitId.should.deep.equal(['Model B', '987654321']);
		});

		it('should split a deviceId with multiple \'-\' in the model', function() {
			var splitId = stripdata.splitDeviceId('Model-C-Version-Z-12341234');
			splitId.should.be.a('array');
			splitId.should.have.length(2);
			splitId.should.deep.equal(['Model-C-Version-Z', '12341234']);
		});

	});

	describe('#hashIDsForData()', function() {

		it('should not hash Ids if option not selected', function() {
			stripdata.program.hashIDs = false;
			var data = readInputTestFile();
			for (var i in data) {
				var chunk = {val: data[i]};
				var expectGroup = data[i]._groupId;
				var expectUpload = data[i].uploadId;
				stripdata.hashIDsForData(chunk);
				should.exist(chunk.val._groupId);
				should.not.exist(chunk.val.hash_groupId);
				chunk.val._groupId.should.equal(expectGroup);
				should.exist(chunk.val.uploadId);
				should.not.exist(chunk.val.hash_uploadId);
				chunk.val.uploadId.should.equal(expectUpload);
			}
		});

		it('should hash all Ids if option is selected', function() {
			stripdata.program.hashIDs = true;
			var data = readInputTestFile();
			for (var i in data) {
				var chunk = {val: data[i]};
				var expectGroup = data[i]._groupId;
				var expectUpload = data[i].uploadId;
				stripdata.hashIDsForData(chunk);
				should.not.exist(chunk.val._groupId);
				should.exist(chunk.val.hash_groupId);
				chunk.val.hash_groupId.should.not.equal(expectGroup);
				should.not.exist(chunk.val.uploadId);
				should.exist(chunk.val.hash_uploadId);
				chunk.val.hash_uploadId.should.not.equal(expectUpload);
			}
		});

	});
});

function resetOptions() {
	stripdata.program.input = 'test/testdata.json';
	stripdata.program.output = 'test/testdataout.json';
	stripdata.program.stripModels = [];
	stripdata.program.stripSNs = [];
	stripdata.program.leaveModels = [];
	stripdata.program.stripAll = false;
	stripdata.program.removeTypes = [];
	stripdata.program.leaveTypes = [];
	stripdata.program.removeAll = false;
	stripdata.program.hashIDs = false;
	stripdata.program.removeSource = false;
	stripdata.program.verbose = false;
}

function readInputTestFile() {
	var input = fs.readFileSync('test/testdata.json', {encoding: 'utf8'});
	return JSON.parse(input);
}

function readOutputTestFile() {
	var output = fs.readFileSync('test/testdataout.json', {encoding: 'utf8'});
	return JSON.parse(output);
}

function deleteFilesCreated() {
	const execSync = require('child_process').execSync;
	execSync('rm test/testdataout.json');
}<|endoftext|>


<commit_before>/**
* Contains information about a single contact.
* @constructor
* @param {DOMString} id unique identifier
* @param {DOMString} displayName
* @param {ContactName} name
* @param {DOMString} nickname
* @param {Array.<ContactField>} phoneNumbers array of phone numbers
* @param {Array.<ContactField>} emails array of email addresses
* @param {Array.<ContactAddress>} addresses array of addresses
* @param {Array.<ContactField>} ims instant messaging user ids
* @param {Array.<ContactOrganization>} organizations
* @param {DOMString} birthday contact's birthday
* @param {DOMString} note user notes about contact
* @param {Array.<ContactField>} photos
* @param {Array.<ContactField>} categories
* @param {Array.<ContactField>} urls contact's web sites
*/
var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
    ims, organizations, birthday, note, photos, categories, urls) {
    this.id = id || null;
    this.rawId = null;
    this.displayName = displayName || null;
    this.name = name || null; // ContactName
    this.nickname = nickname || null;
    this.phoneNumbers = phoneNumbers || []; // ContactField[]
    this.emails = emails || []; // ContactField[]
    this.addresses = addresses || []; // ContactAddress[]
    this.ims = ims || []; // ContactField[]
    this.organizations = organizations || []; // ContactOrganization[]
    this.birthday = birthday || null;
    this.note = note || null;
    this.photos = photos || []; // ContactField[]
    this.categories = categories || []; // ContactField[]
    this.urls = urls || []; // ContactField[]
};

module.exports = Contact;
<commit_msg>added phonegap contact methods<commit_after>var exec = require('phonegap/exec'),
    ContactError = require('phonegap/plugin/ContactError'),
    utils = require('phonegap/utils');

/**
* Contains information about a single contact.
* @constructor
* @param {DOMString} id unique identifier
* @param {DOMString} displayName
* @param {ContactName} name
* @param {DOMString} nickname
* @param {Array.<ContactField>} phoneNumbers array of phone numbers
* @param {Array.<ContactField>} emails array of email addresses
* @param {Array.<ContactAddress>} addresses array of addresses
* @param {Array.<ContactField>} ims instant messaging user ids
* @param {Array.<ContactOrganization>} organizations
* @param {DOMString} birthday contact's birthday
* @param {DOMString} note user notes about contact
* @param {Array.<ContactField>} photos
* @param {Array.<ContactField>} categories
* @param {Array.<ContactField>} urls contact's web sites
*/
var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
    ims, organizations, birthday, note, photos, categories, urls) {
    this.id = id || null;
    this.rawId = null;
    this.displayName = displayName || null;
    this.name = name || null; // ContactName
    this.nickname = nickname || null;
    this.phoneNumbers = phoneNumbers || []; // ContactField[]
    this.emails = emails || []; // ContactField[]
    this.addresses = addresses || []; // ContactAddress[]
    this.ims = ims || []; // ContactField[]
    this.organizations = organizations || []; // ContactOrganization[]
    this.birthday = birthday || null;
    this.note = note || null;
    this.photos = photos || []; // ContactField[]
    this.categories = categories || []; // ContactField[]
    this.urls = urls || []; // ContactField[]
};

/**
* Removes contact from device storage.
* @param successCB success callback
* @param errorCB error callback
*/
Contact.prototype.remove = function(successCB, errorCB) {
    if (this.id === null) {
        var errorObj = new ContactError(ContactError.UNKNOWN_ERROR);
        errorCB(errorObj);
    }
    else {
        exec(successCB, errorCB, "Contacts", "remove", [this.id]);
    }
};

/**
* Creates a deep copy of this Contact.
* With the contact ID set to null.
* @return copy of this Contact
*/
Contact.prototype.clone = function() {
    var clonedContact = utils.clone(this);
    var i;
    clonedContact.id = null;
    clonedContact.rawId = null;
    // Loop through and clear out any id's in phones, emails, etc.
    if (clonedContact.phoneNumbers) {
        for (i = 0; i < clonedContact.phoneNumbers.length; i++) {
            clonedContact.phoneNumbers[i].id = null;
        }
    }
    if (clonedContact.emails) {
        for (i = 0; i < clonedContact.emails.length; i++) {
            clonedContact.emails[i].id = null;
        }
    }
    if (clonedContact.addresses) {
        for (i = 0; i < clonedContact.addresses.length; i++) {
            clonedContact.addresses[i].id = null;
        }
    }
    if (clonedContact.ims) {
        for (i = 0; i < clonedContact.ims.length; i++) {
            clonedContact.ims[i].id = null;
        }
    }
    if (clonedContact.organizations) {
        for (i = 0; i < clonedContact.organizations.length; i++) {
            clonedContact.organizations[i].id = null;
        }
    }
    if (clonedContact.tags) {
        for (i = 0; i < clonedContact.tags.length; i++) {
            clonedContact.tags[i].id = null;
        }
    }
    if (clonedContact.photos) {
        for (i = 0; i < clonedContact.photos.length; i++) {
            clonedContact.photos[i].id = null;
        }
    }
    if (clonedContact.urls) {
        for (i = 0; i < clonedContact.urls.length; i++) {
            clonedContact.urls[i].id = null;
        }
    }
    return clonedContact;
};

/**
* Persists contact to device storage.
* @param successCB success callback
* @param errorCB error callback
*/
Contact.prototype.save = function(successCB, errorCB) {
    exec(successCB, errorCB, "Contacts", "save", [this]);
};

module.exports = Contact;
<|endoftext|>


<commit_before>const config = require("./config");
const systemapi = require("./systemapi");
const system = require("sdk/system");
const _ = require('underscore');

systemapi.setup();

exports["testerror"] = function(assert, done) {
    systemapi.exec(function(res) {
	assert.ok(res.error !== undefined,
		  "unknown method returns error");
	assert.ok(res.error.type === "nosuchmethod",
		  "unknown method returns correct error");
	done();
    }, { method : 'foo'});
};

exports["testpinglocal"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log("test doPing",res);
	assert.ok(!res.error, "doPing no error");
	assert.ok(res.result.count === 1, "doPing count");
	assert.ok(res.result.rtt.length === 1, "doPing results");
	done();
    }, { method : 'doPing', params: ['localhost', { count : 1 }]});
};

exports["testpingbcast"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log("test doPing",res);
	assert.ok(!res.error, "doPing no error");
	if (doneflag)
	    done();
    }, { method : 'doPing',
	 params: ['10.254.2.255',{ count : 2, interval : 1, bcast : true }]});
    //'192.168.1.255',
};

exports["testpingerror"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	assert.ok(res.error, "doPing got error");
	assert.ok(res.error.type === "missingparams",
		  "doPing got correct error");
	done();
    }, { method : 'doPing', params: []});
};

exports["testpingttl"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log("test doPing with ttl",res);
	assert.ok(!res.error, "doPing no error");
	assert.ok(res.result.count === 1, "doPing count == 1");
	assert.ok(res.result.time_exceeded_from,
		  "doPing got time exceeded from " +
		  res.result.time_exceeded_from);
	done();
    }, { method : 'doPing', params: [config.MSERVER_FR,
				     { count : 1, ttl : 1, timeout : 1}]});
};

exports["testtraceroute"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log("test doTraceroute",res);
	assert.ok(!res.error, "doTraceroute no error");
	assert.ok(res.result.hops[0], "doTraceroute got results");
	assert.ok(res.result.hops[0].address == '127.0.0.1',
		  "doTraceroute results valid");
	done();
    }, { method : 'doTraceroute', params: ['localhost']});
};

exports["testtraceroutelong"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log("test doTraceroute",res);
	assert.ok(!res.error, "doTraceroute no error");
	assert.ok(res.result.hops.length>0, "doTraceroute got results");
	done();
    }, { method : 'doTraceroute', params: ['www.google.com', {
	count : 1, waittime : 1
    }]});
};

exports["testgetos"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	assert.ok(res === require('sdk/system').platform,
		  "getOS: " + res);
	done();
    }, { method : 'getOS', params: []});
};

exports["testgethostname"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error && res.result, "getHostname: " + res.result);
	done();
    }, { method : 'getHostname'});
};

exports["testgetarp"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getArp no error");
	assert.ok(_.keys(res.result).length>0, "getArp has results");
	done();
    }, { method : 'getArpCache'});
};

exports["testnslookup"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "nslookup no error");
	done();
    }, { method : 'nslookup', params : ['muse.inria.fr']});
};

exports["testgetroute"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getRoutingTable no error");
	assert.ok(!_.isEmpty(res.result.routes), "getRoutingTable has results");
	assert.ok(res.result.defaultroute,
		  "getRoutingTable found default route");
	done();
    }, { method : 'getRoutingTable'});
};

exports["testgetns"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getNameservers no error");
	assert.ok(res.result.nameservers.length > 0, "getNameservers got results");
	done();
    }, { method : 'getNameservers'});
};

exports["testgetifaces"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getActiveInterfaces no error");
	assert.ok(_.keys(res.result).length>0, "getActiveInterfaces found some interfaces");
	done();
    }, { method : 'getActiveInterfaces'});
};

exports["testifacestats"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getIfaceStats no error");
	assert.ok(_.keys(res.result).length>0, "getIfaceStats found some interfaces");
	done();
    }, { method : 'getIfaceStats'});
};

exports["testgetwifi"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	if (!res.error && res.result.bssid) {
	    assert.ok(res.result.bssid,"getActiveWifiInterface bssid " + res.result.bssid);

	    systemapi.exec(function(res2, doneflag) {
		console.log(res2);
		assert.ok(!res2.error, "getWifiSignal no error");
		assert.ok(res2.result.signal,"getWifiSignal " + res2.result.signal);

		systemapi.exec(function(res3, doneflag) {
		    console.log(res3);
		    assert.ok(!res3.error, "getWifiNetworks no error");
		    assert.ok(res3.result.length > 0,"getWifiNetworks found networks");
		    done();

		}, { method : 'getWifiNetworks'});

	    }, { method : 'getWifiSignal'});

	} else {
	    assert.ok(res!==undefined, "getActiveWifiInterface no wifi or offline");
	    done();
	}
    }, { method : 'getActiveWifiInterface'});
};

exports["testmem"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	if (system.platform !== 'darwin' && system.platform !== 'winnt') {
	    assert.ok(!res.error && res.result.memfree > 0, "getMemInfo");
	} else {
	    assert.ok(res.error, "getMemInfo");
	}
	done();
    }, { method : 'getMemInfo'});
};

exports["testsysinfo"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	if (system.platform === 'winnt') {
	    assert.ok(!res.error && res.result.memfree > 0, "getSysInfo");
	} else {
		// not available
	    assert.ok(res.error, "getSysInfo not available");
	}
	done();
    }, { method : 'getSysInfo'});
};

exports["testload"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getLoad no error");
	if (system.platform !== 'winnt') assert.ok(res.result.tasks.total > 0, "getLoad found tasks");
	if (system.platform !== 'winnt') assert.ok(res.result.loadavg.onemin > 0, "getLoad found loadavg");
	if (system.platform !== 'winnt') assert.ok(res.result.cpu.user > 0, "getLoad found cpu");
	if (system.platform !== 'winnt') assert.ok(res.result.memory.total > 0, "getLoad found memory");
	done();
    }, { method : 'getLoad'});
};

exports["testbmem"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getBrowserMemoryUsage no error");
	assert.ok(res.result.mem > 0, "getBrowserMemoryUsage got result");
	done();
    }, { method : 'getBrowserMemoryUsage'});
};

exports["testproxy"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getProxy no error");
	done();
    }, { method : 'getProxyInfo', params : [config.API_URL]});
};

exports["testpromise"] = function(assert, done) {
    const { all } = require('sdk/core/promise');
    all([
	systemapi.execp({ method : 'getBrowserMemoryUsage'}),
	systemapi.execp({ method : 'getLoad'}),
	systemapi.execp({ method : 'getNameservers'}),
    ]).then(function (results) {
	// success function
	console.log(JSON.stringify(results, null, 4));
	assert.ok(results.length == 3, "got all results");
	done();
    }, function (reason) {
	assert.ok(reason, "error " + reason);
	done();
    });
};

require("sdk/test").run(exports);

<commit_msg>test update<commit_after>const config = require("./config");
const systemapi = require("./systemapi");
const system = require("sdk/system");
const _ = require('underscore');

systemapi.setup();

exports["testerror"] = function(assert, done) {
    systemapi.exec(function(res) {
	assert.ok(res.error !== undefined,
		  "unknown method returns error");
	assert.ok(res.error.type === "nosuchmethod",
		  "unknown method returns correct error");
	done();
    }, { method : 'foo'});
};

exports["testpinglocal"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log("test doPing",res);
	assert.ok(!res.error, "doPing no error");
	assert.ok(res.result.count === 1, "doPing count");
	assert.ok(res.result.rtt.length === 1, "doPing results");
	done();
    }, { method : 'doPing', params: ['localhost', { count : 1 }]});
};

exports["testpingbcast"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log("test doPing",res);
	assert.ok(!res.error, "doPing no error");
	if (doneflag)
	    done();
    }, { method : 'doPing',
	 params: ['192.168.1.255',{ count : 2, interval : 1, bcast : true }]});
};

exports["testpingerror"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	assert.ok(res.error, "doPing got error");
	assert.ok(res.error.type === "missingparams",
		  "doPing got correct error");
	done();
    }, { method : 'doPing', params: []});
};

exports["testpingttl"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log("test doPing with ttl",res);
	assert.ok(!res.error, "doPing no error");
	assert.ok(res.result.count === 1, "doPing count == 1");
	assert.ok(res.result.time_exceeded_from,
		  "doPing got time exceeded from " +
		  res.result.time_exceeded_from);
	done();
    }, { method : 'doPing', params: [config.MSERVER_FR,
				     { count : 1, ttl : 1, timeout : 1}]});
};

exports["testpingttl3"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log("test doPing with ttl",res);
	assert.ok(!res.error, "doPing no error");
	assert.ok(res.result.count === 1, "doPing count == 1");
	assert.ok(res.result.time_exceeded_from,
		  "doPing got time exceeded from " +
		  res.result.time_exceeded_from);
	done();
    }, { method : 'doPing', params: [config.MSERVER_FR,
				     { count : 1, ttl : 3, timeout : 1}]});
};

exports["testtraceroute"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log("test doTraceroute",res);
	assert.ok(!res.error, "doTraceroute no error");
	assert.ok(res.result.hops[0], "doTraceroute got results");
	assert.ok(res.result.hops[0].address == '127.0.0.1',
		  "doTraceroute results valid");
	done();
    }, { method : 'doTraceroute', params: ['localhost']});
};

exports["testtraceroutelong"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log("test doTraceroute",res);
	assert.ok(!res.error, "doTraceroute no error");
	assert.ok(res.result.hops.length>0, "doTraceroute got results");
	done();
    }, { method : 'doTraceroute', params: ['www.google.com', {
	count : 1, waittime : 1
    }]});
};

exports["testgetos"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	assert.ok(res === require('sdk/system').platform,
		  "getOS: " + res);
	done();
    }, { method : 'getOS', params: []});
};

exports["testgethostname"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error && res.result, "getHostname: " + res.result);
	done();
    }, { method : 'getHostname'});
};

exports["testgetarp"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getArp no error");
	assert.ok(_.keys(res.result).length>0, "getArp has results");
	done();
    }, { method : 'getArpCache'});
};

exports["testnslookup"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "nslookup no error");
	done();
    }, { method : 'nslookup', params : ['muse.inria.fr']});
};

exports["testgetroute"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getRoutingTable no error");
	assert.ok(!_.isEmpty(res.result.routes), "getRoutingTable has results");
	assert.ok(res.result.defaultroute,
		  "getRoutingTable found default route");
	done();
    }, { method : 'getRoutingTable'});
};

exports["testgetns"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getNameservers no error");
	assert.ok(res.result.nameservers.length > 0, "getNameservers got results");
	done();
    }, { method : 'getNameservers'});
};

exports["testgetifaces"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getActiveInterfaces no error");
	assert.ok(_.keys(res.result).length>0, "getActiveInterfaces found some interfaces");
	done();
    }, { method : 'getActiveInterfaces'});
};

exports["testifacestats"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getIfaceStats no error");
	assert.ok(_.keys(res.result).length>0, "getIfaceStats found some interfaces");
	done();
    }, { method : 'getIfaceStats'});
};

exports["testgetwifi"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	if (!res.error && res.result.bssid) {
	    assert.ok(res.result.bssid,"getActiveWifiInterface bssid " + res.result.bssid);

	    systemapi.exec(function(res2, doneflag) {
		console.log(res2);
		assert.ok(!res2.error, "getWifiSignal no error");
		assert.ok(res2.result.signal,"getWifiSignal " + res2.result.signal);

		systemapi.exec(function(res3, doneflag) {
		    console.log(res3);
		    assert.ok(!res3.error, "getWifiNetworks no error");
		    assert.ok(res3.result.length > 0,"getWifiNetworks found networks");
		    done();

		}, { method : 'getWifiNetworks'});

	    }, { method : 'getWifiSignal'});

	} else {
	    assert.ok(res!==undefined, "getActiveWifiInterface no wifi or offline");
	    done();
	}
    }, { method : 'getActiveWifiInterface'});
};

exports["testmem"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	if (system.platform !== 'darwin' && system.platform !== 'winnt') {
	    assert.ok(!res.error && res.result.memfree > 0, "getMemInfo");
	} else {
	    assert.ok(res.error, "getMemInfo");
	}
	done();
    }, { method : 'getMemInfo'});
};

exports["testsysinfo"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	if (system.platform === 'winnt') {
	    assert.ok(!res.error && res.result.memfree > 0, "getSysInfo");
	} else {
		// not available
	    assert.ok(res.error, "getSysInfo not available");
	}
	done();
    }, { method : 'getSysInfo'});
};

exports["testload"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getLoad no error");
	if (system.platform !== 'winnt') assert.ok(res.result.tasks.total > 0, "getLoad found tasks");
	if (system.platform !== 'winnt') assert.ok(res.result.loadavg.onemin > 0, "getLoad found loadavg");
	if (system.platform !== 'winnt') assert.ok(res.result.cpu.user > 0, "getLoad found cpu");
	if (system.platform !== 'winnt') assert.ok(res.result.memory.total > 0, "getLoad found memory");
	done();
    }, { method : 'getLoad'});
};

exports["testbmem"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getBrowserMemoryUsage no error");
	assert.ok(res.result.mem > 0, "getBrowserMemoryUsage got result");
	done();
    }, { method : 'getBrowserMemoryUsage'});
};

exports["testproxy"] = function(assert, done) {
    systemapi.exec(function(res, doneflag) {
	console.log(res);
	assert.ok(!res.error, "getProxy no error");
	done();
    }, { method : 'getProxyInfo', params : [config.API_URL]});
};

exports["testpromise"] = function(assert, done) {
    const { all } = require('sdk/core/promise');
    all([
	systemapi.execp({ method : 'getBrowserMemoryUsage'}),
	systemapi.execp({ method : 'getLoad'}),
	systemapi.execp({ method : 'getNameservers'}),
    ]).then(function (results) {
	// success function
	console.log(JSON.stringify(results, null, 4));
	assert.ok(results.length == 3, "got all results");
	done();
    }, function (reason) {
	assert.ok(reason, "error " + reason);
	done();
    });
};

require("sdk/test").run(exports);

<|endoftext|>


<commit_before>var stanzas = require('../stanza/avatar');

module.exports = function (client) {
    client.disco.addFeature('urn:xmpp:avatar:metadata+notify');

    client.on('pubsubEvent', function (msg) {
        if (!msg.event._extensions.updated) return;
        if (msg.event.updated.node !== 'urn:xmpp:avatar:metadata') return;

        client.emit('avatar', {
            jid: msg.from,
            avatars: msg.updated.published[0].avatars
        });
    });

    client.publishAvatar = function (id, data, cb) {
        client.publish(null, 'urn:xmpp:avatar:data', {
            id: id,
            avatarData: data
        }, cb);
    };

    client.useAvatars = function (info, cb) {
        client.publish(null, 'urn:xmpp:avatar:metadata', {
            id: 'current',
            avatars: info
        }, cb);
    };
};
<commit_msg>Fix retrieving avatars.<commit_after>var stanzas = require('../stanza/avatar');

module.exports = function (client) {
    client.disco.addFeature('urn:xmpp:avatar:metadata+notify');

    client.on('pubsubEvent', function (msg) {
        if (!msg.event._extensions.updated) return;
        if (msg.event.updated.node !== 'urn:xmpp:avatar:metadata') return;

        client.emit('avatar', {
            jid: msg.from,
            avatars: msg.event.updated.published[0].avatars
        });
    });

    client.publishAvatar = function (id, data, cb) {
        client.publish(null, 'urn:xmpp:avatar:data', {
            id: id,
            avatarData: data
        }, cb);
    };

    client.useAvatars = function (info, cb) {
        client.publish(null, 'urn:xmpp:avatar:metadata', {
            id: 'current',
            avatars: info
        }, cb);
    };

    client.getAvatar = function (jid, id, cb) {
        client.getItem(jid, 'urn:xmpp:avatar:data', id, cb);
    };
};
<|endoftext|>


<commit_before>
import { wait, initArrays, compareUsers, Y, flushSome, flushAll } from 'yjs/tests-lib/helper.js'
import { test, proxyConsole } from 'cutest'
import Chance from 'chance'

proxyConsole()

var database = { name: 'memory' }
var connector = { name: 'test', url: 'http://localhost:1234' }

var _uniqueNumber = 0
function getUniqueNumber () {
  return _uniqueNumber++
}

var arrayTransactions = [
  function insert (t, user, chance) {
    var uniqueNumber = getUniqueNumber()
    var content = []
    var len = chance.integer({ min: 1, max: 4 })
    for (var i = 0; i < len; i++) {
      content.push(uniqueNumber)
    }
    var pos = chance.integer({ min: 0, max: user.share.array.length })
    user.share.array.insert(pos, content)
  },
  /*
  function insertTypeArray (t, user, chance) {
    var pos = chance.integer({ min: 0, max: user.share.array.length })
    user.share.array.insert(pos, [Y.Array])
    var array2 = user.share.array.get(pos)
    array2.insert(0, [1, 2, 3, 4])
  },
  */
  function insertTypeMap (t, user, chance) {
    var pos = chance.integer({ min: 0, max: user.share.array.length })
    user.share.array.insert(pos, [Y.Map])
    var map = user.share.array.get(pos)
    map.set('someprop', 42)
    map.set('someprop', 43)
    map.set('someprop', 44)
  },
  function _delete (t, user, chance) {
    var length = user.share.array._content.length
    if (length > 0) {
      var pos = chance.integer({ min: 0, max: length - 1 })
      var delLength = chance.integer({ min: 1, max: Math.min(2, length - pos) })
      if (user.share.array._content[pos].type != null) {
        if (chance.bool()) {
          var type = user.share.array.get(pos)
          if (type instanceof Y.Array.typeDefinition.class) {
            if (type._content.length > 0) {
              pos = chance.integer({ min: 0, max: type._content.length - 1 })
              delLength = chance.integer({ min: 0, max: Math.min(2, type._content.length - pos) })
              type.delete(pos, delLength)
            }
          } else {
            type.delete('someprop')
          }
        } else {
          user.share.array.delete(pos, delLength)
        }
      } else {
        user.share.array.delete(pos, delLength)
      }
    }
  }
]

async function applyRandomTests (t, iterations) {
  const chance = new Chance(t.getSeed() * 1000000000)
  var { users } = await initArrays(t, { users: 5, connector: connector, db: database, chance: chance })
  for (var i = 0; i < iterations; i++) {
    if (chance.bool({likelihood: 10})) {
      // 10% chance to disconnect/reconnect a user
      // we make sure that the first users always is connected
      let user = chance.pickone(users.slice(1))
      if (user.connector.isSynced) {
        if (users.filter(u => u.connector.isSynced).length > 1) {
          // make sure that at least one user remains in the room
          await user.disconnect()
          if (users[0].connector.testRoom == null) {
            await wait(100)
          }
        }
      } else {
        await user.reconnect()
        if (users[0].connector.testRoom == null) {
          await wait(100)
        }
        await new Promise(function (resolve) {
          user.connector.whenSynced(resolve)
        })
      }
    } else if (chance.bool({likelihood: 5})) {
      // 20%*!prev chance to flush all & garbagecollect
      // TODO: We do not gc all users as this does not work yet
      // await garbageCollectUsers(t, users)
      await flushAll(t, users)
      await flushAll(t, users)
      await wait(500)
      await users[0].db.emptyGarbageCollector()
      await flushAll(t, users)
      await wait(500)
      await flushAll(t, users)
    } else if (chance.bool({likelihood: 10})) {
      // 20%*!prev chance to flush some operations
      await flushSome(t, users)
    }
    let user = chance.pickone(users)
    var test = chance.pickone(arrayTransactions)
    test(t, user, chance)
  }
  await compareUsers(t, users)
}

test('y-array: Random tests (42)', async function random42 (t) {
  await applyRandomTests(t, 42)
})

test('y-array: Random tests (43)', async function random43 (t) {
  await applyRandomTests(t, 43)
})

test('y-array: Random tests (44)', async function random44 (t) {
  await applyRandomTests(t, 44)
})

test('y-array: Random tests (45)', async function random45 (t) {
  await applyRandomTests(t, 45)
})

test('y-array: Random tests (46)', async function random46 (t) {
  await applyRandomTests(t, 46)
})

test('y-array: Random tests (47)', async function random47 (t) {
  await applyRandomTests(t, 47)
})

test('y-array: Random tests (200)', async function random200 (t) {
  await applyRandomTests(t, 200)
})

test('y-array: Random tests (300)', async function random300 (t) {
  await applyRandomTests(t, 300)
})

test('y-array: Random tests (400)', async function random400 (t) {
  await applyRandomTests(t, 400)
})

test('y-array: Random tests (500)', async function random500 (t) {
  await applyRandomTests(t, 500)
})
<commit_msg>remove some unnecessary wait statements<commit_after>
import { wait, initArrays, compareUsers, Y, flushSome, flushAll } from 'yjs/tests-lib/helper.js'
import { test, proxyConsole } from 'cutest'
import Chance from 'chance'

proxyConsole()

var database = { name: 'memory' }
var connector = { name: 'test', url: 'http://localhost:1234' }

var _uniqueNumber = 0
function getUniqueNumber () {
  return _uniqueNumber++
}

var arrayTransactions = [
  function insert (t, user, chance) {
    var uniqueNumber = getUniqueNumber()
    var content = []
    var len = chance.integer({ min: 1, max: 4 })
    for (var i = 0; i < len; i++) {
      content.push(uniqueNumber)
    }
    var pos = chance.integer({ min: 0, max: user.share.array.length })
    user.share.array.insert(pos, content)
  },
  /*
  function insertTypeArray (t, user, chance) {
    var pos = chance.integer({ min: 0, max: user.share.array.length })
    user.share.array.insert(pos, [Y.Array])
    var array2 = user.share.array.get(pos)
    array2.insert(0, [1, 2, 3, 4])
  },
  */
  function insertTypeMap (t, user, chance) {
    var pos = chance.integer({ min: 0, max: user.share.array.length })
    user.share.array.insert(pos, [Y.Map])
    var map = user.share.array.get(pos)
    map.set('someprop', 42)
    map.set('someprop', 43)
    map.set('someprop', 44)
  },
  function _delete (t, user, chance) {
    var length = user.share.array._content.length
    if (length > 0) {
      var pos = chance.integer({ min: 0, max: length - 1 })
      var delLength = chance.integer({ min: 1, max: Math.min(2, length - pos) })
      if (user.share.array._content[pos].type != null) {
        if (chance.bool()) {
          var type = user.share.array.get(pos)
          if (type instanceof Y.Array.typeDefinition.class) {
            if (type._content.length > 0) {
              pos = chance.integer({ min: 0, max: type._content.length - 1 })
              delLength = chance.integer({ min: 0, max: Math.min(2, type._content.length - pos) })
              type.delete(pos, delLength)
            }
          } else {
            type.delete('someprop')
          }
        } else {
          user.share.array.delete(pos, delLength)
        }
      } else {
        user.share.array.delete(pos, delLength)
      }
    }
  }
]

async function applyRandomTests (t, iterations) {
  const chance = new Chance(t.getSeed() * 1000000000)
  var { users } = await initArrays(t, { users: 5, connector: connector, db: database, chance: chance })
  for (var i = 0; i < iterations; i++) {
    if (chance.bool({likelihood: 10})) {
      // 10% chance to disconnect/reconnect a user
      // we make sure that the first users always is connected
      let user = chance.pickone(users.slice(1))
      if (user.connector.isSynced) {
        if (users.filter(u => u.connector.isSynced).length > 1) {
          // make sure that at least one user remains in the room
          await user.disconnect()
          if (users[0].connector.testRoom == null) {
            await wait(100)
          }
        }
      } else {
        await user.reconnect()
        if (users[0].connector.testRoom == null) {
          await wait(100)
        }
        await new Promise(function (resolve) {
          user.connector.whenSynced(resolve)
        })
      }
    } else if (chance.bool({likelihood: 5})) {
      // 20%*!prev chance to flush all & garbagecollect
      // TODO: We do not gc all users as this does not work yet
      // await garbageCollectUsers(t, users)
      await flushAll(t, users)
      await users[0].db.emptyGarbageCollector()
      await flushAll(t, users)
    } else if (chance.bool({likelihood: 10})) {
      // 20%*!prev chance to flush some operations
      await flushSome(t, users)
    }
    let user = chance.pickone(users)
    var test = chance.pickone(arrayTransactions)
    test(t, user, chance)
  }
  await compareUsers(t, users)
}

test('y-array: Random tests (42)', async function random42 (t) {
  await applyRandomTests(t, 42)
})

test('y-array: Random tests (43)', async function random43 (t) {
  await applyRandomTests(t, 43)
})

test('y-array: Random tests (44)', async function random44 (t) {
  await applyRandomTests(t, 44)
})

test('y-array: Random tests (45)', async function random45 (t) {
  await applyRandomTests(t, 45)
})

test('y-array: Random tests (46)', async function random46 (t) {
  await applyRandomTests(t, 46)
})

test('y-array: Random tests (47)', async function random47 (t) {
  await applyRandomTests(t, 47)
})

/*

test('y-array: Random tests (200)', async function random200 (t) {
  await applyRandomTests(t, 200)
})

test('y-array: Random tests (300)', async function random300 (t) {
  await applyRandomTests(t, 300)
})

test('y-array: Random tests (400)', async function random400 (t) {
  await applyRandomTests(t, 400)
})

test('y-array: Random tests (500)', async function random500 (t) {
  await applyRandomTests(t, 500)
})
*/
<|endoftext|>


<commit_before>const Vec3 = require('vec3').Vec3
const assert = require('assert')
const Painting = require('../painting')
const Location = require('../location')

const { OctahedronIterator } = require('../iterators')

module.exports = inject

const paintingFaceToVec = [
  new Vec3(0, 0, -1),
  new Vec3(-1, 0, 0),
  new Vec3(0, 0, 1),
  new Vec3(1, 0, 0)
]

function inject (bot, { version }) {
  const nbt = require('prismarine-nbt')
  const Block = require('prismarine-block')(version)
  const Chunk = require('prismarine-chunk')(version)
  const ChatMessage = require('../chat_message')(version)
  let columns = {}
  const signs = {}
  const paintingsByPos = {}
  const paintingsById = {}

  const blockEntities = new Map()

  function addPainting (painting) {
    paintingsById[painting.id] = painting
    paintingsByPos[painting.position] = painting
  }

  function deletePainting (painting) {
    delete paintingsById[painting.id]
    delete paintingsByPos[painting.position]
  }

  function addBlockEntity (nbtData) {
    const blockEntity = nbt.simplify(nbtData)
    const absolutePoint = new Vec3(blockEntity.x, blockEntity.y, blockEntity.z)
    const loc = new Location(absolutePoint)

    // Handle signs
    if (blockEntity.id === 'minecraft:sign' || blockEntity.id === 'Sign') {
      const prepareJson = (i) => {
        const data = blockEntity[`Text${i}`]

        if (data === '') return ''

        const json = JSON.parse(data)
        if (!('text' in json)) return ''

        json.text = json.text.replace(/^"|"$/g, '')
        return json
      }

      blockEntity.Text1 = new ChatMessage(prepareJson(1))
      blockEntity.Text2 = new ChatMessage(prepareJson(2))
      blockEntity.Text3 = new ChatMessage(prepareJson(3))
      blockEntity.Text4 = new ChatMessage(prepareJson(4))

      signs[loc.floored] = [
        blockEntity.Text1.toString(),
        blockEntity.Text2.toString(),
        blockEntity.Text3.toString(),
        blockEntity.Text4.toString()
      ].join('\n')
    }

    blockEntities[loc.floored] = blockEntity
  }

  function delColumn (chunkX, chunkY) {
    const columnCorner = new Vec3(chunkX * 16, 0, chunkY * 16)
    const key = columnKeyXZ(columnCorner.x, columnCorner.z)
    delete columns[key]
    bot.emit('chunkColumnUnload', columnCorner)
  }

  function addColumn (args) {
    const columnCorner = new Vec3(args.x * 16, 0, args.z * 16)
    const key = columnKeyXZ(columnCorner.x, columnCorner.z)
    if (!args.bitMap) {
      // stop storing the chunk column
      delColumn(args.x, args.z)
      return
    }
    let column = columns[key]
    if (!column) columns[key] = column = new Chunk()

    try {
      column.load(args.data, args.bitMap, args.skyLightSent)
      if (args.biomes !== undefined) {
        column.loadBiomes(args.biomes)
      }
    } catch (e) {
      bot.emit('error', e)
      return
    }

    bot.emit('chunkColumnLoad', columnCorner)
  }

  function getMatchingFunction (matching) {
    if (typeof (matching) !== 'function') {
      if (!Array.isArray(matching)) {
        matching = [matching]
      }
      return isMatchingType
    }
    return matching

    function isMatchingType (block) {
      return block === null ? false : matching.indexOf(block.type) >= 0
    }
  }

  function isBlockInSection (section, matcher) {
    if (!section) return false // section is empty, skip it (yay!)
    // If the chunk use a palette we can speed up the search by first
    // checking the palette which usually contains less than 20 ids
    // vs checking the 4096 block of the section. If we don't have a
    // match in the palette, we can skip this section.
    if (section.palette) {
      for (const stateId of section.palette) {
        if (matcher(Block.fromStateId(stateId, 0))) {
          return true // the block is in the palette
        }
      }
      return false // skip
    }
    return true // global palette, the block might be in there
  }

  bot.findBlocks = (options) => {
    const matcher = getMatchingFunction(options.matching)
    const point = options.point || bot.entity.position
    let start = point.floored()
    const maxDistance = Math.ceil((options.maxDistance || 16) / 16)
    const minCount = options.minCount || 1
    const blocks = []
    start = new Vec3(Math.floor(start.x / 16), Math.floor(start.y / 16), Math.floor(start.z / 16))
    const it = new OctahedronIterator(start, maxDistance)
    // the octahedron iterator can sometime go through the same section again
    // we use a set to keep track of visited sections
    const visitedSections = new Set()
    let startedLayer = 0
    let next = start
    while (next) {
      const column = columns[columnKeyXZ(next.x * 16, next.z * 16)]
      if (next.y >= 0 && next.y < 16 && column && !visitedSections.has(next.toString())) {
        const section = column.sections[next.y]
        if (isBlockInSection(section, matcher)) {
          const cursor = new Vec3(0, 0, 0)
          for (cursor.x = next.x * 16; cursor.x < next.x * 16 + 16; cursor.x++) {
            for (cursor.y = next.y * 16; cursor.y < next.y * 16 + 16; cursor.y++) {
              for (cursor.z = next.z * 16; cursor.z < next.z * 16 + 16; cursor.z++) {
                const found = bot.blockAt(cursor, false)
                if (matcher(found)) blocks.push(cursor.clone())
              }
            }
          }
        }
        visitedSections.add(next.toString())
      }
      // If we started a layer, we have to finish it otherwise we might miss closer blocks
      if (startedLayer !== it.apothem && blocks.length >= minCount) {
        break
      }
      startedLayer = it.apothem
      next = it.next()
    }
    blocks.sort((a, b) => {
      return a.distanceTo(point) - b.distanceTo(point)
    })
    return blocks
  }

  function findBlock (options) {
    const blocks = bot.findBlocks(options)
    if (blocks.length === 0) return null
    return bot.blockAt(blocks[0])
  }

  function posInChunk (pos) {
    pos = pos.floored()
    pos.x &= 15
    pos.y &= 255
    pos.z &= 15
    return pos
  }

  function blockAt (absolutePoint, extraInfos = true) {
    const loc = new Location(absolutePoint)
    const key = columnKeyXZ(loc.chunkCorner.x, loc.chunkCorner.z)

    const column = columns[key]
    // null column means chunk not loaded
    if (!column) return null

    const block = column.getBlock(posInChunk(absolutePoint))
    block.position = loc.floored
    if (extraInfos) {
      block.signText = signs[loc.floored]
      block.painting = paintingsByPos[loc.floored]
      block.blockEntity = blockEntities[loc.floored]
    }

    return block
  }

  function blockIsNotEmpty (pos) {
    const block = bot.blockAt(pos)
    return block !== null && block.boundingBox !== 'empty'
  }

  // maybe this should be moved to math.js instead?
  function visiblePosition (a, b) {
    let v = b.minus(a)
    const t = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)
    v = v.scaled(1 / t)
    v = v.scaled(1 / 5)
    const u = t * 5
    let na
    for (let i = 1; i < u; i++) {
      na = a.plus(v)
      // check that blocks don't inhabit the same position
      if (!na.floored().equals(a.floored())) {
        // check block is not transparent
        if (blockIsNotEmpty(na)) return false
      }
      a = na
    }
    return true
  }

  // if passed in block is within line of sight to the bot, returns true
  // also works on anything with a position value
  function canSeeBlock (block) {
    // this emits a ray from the center of the bots body to the block
    if (visiblePosition(bot.entity.position.offset(0, bot.entity.height * 0.5, 0), block.position)) {
      return true
    }
    return false
  }

  function chunkColumn (x, z) {
    const key = columnKeyXZ(x, z)
    return columns[key]
  }

  function emitBlockUpdate (oldBlock, newBlock) {
    bot.emit('blockUpdate', oldBlock, newBlock)
    const position = oldBlock ? oldBlock.position
      : (newBlock ? newBlock.position : null)
    if (position) bot.emit(`blockUpdate:${newBlock.position}`, oldBlock, newBlock)
  }

  bot._client.on('unload_chunk', (packet) => {
    delColumn(packet.x, packet.z)
  })

  function updateBlockState (point, stateId) {
    const oldBlock = blockAt(point)
    const loc = new Location(point)
    const key = columnKeyXZ(loc.chunkCorner.x, loc.chunkCorner.z)
    const column = columns[key]
    // sometimes minecraft server sends us block updates before it sends
    // us the column that the block is in. ignore this.
    if (!column) return
    column.setBlockStateId(posInChunk(point), stateId)

    const newBlock = blockAt(point)
    if (oldBlock.type !== newBlock.type) {
      delete blockEntities[loc.floored]
      delete signs[loc.floored]

      const painting = paintingsByPos[loc.floored]
      if (painting) deletePainting(painting)
    }

    emitBlockUpdate(oldBlock, newBlock)
  }

  bot._client.on('update_light', (packet) => {
    const key = columnKeyXZ(packet.chunkX, packet.chunkZ)
    let column = columns[key]

    if (!column) columns[key] = column = new Chunk()

    column.loadLight(packet.data, packet.skyLightMask, packet.blockLightMask, packet.emptySkyLightMask, packet.emptyBlockLightMask)
  })

  bot._client.on('map_chunk', (packet) => {
    addColumn({
      x: packet.x,
      z: packet.z,
      bitMap: packet.bitMap,
      heightmaps: packet.heightmaps,
      biomes: packet.biomes,
      skyLightSent: bot.game.dimension === 'overworld',
      groundUp: packet.groundUp,
      data: packet.chunkData
    })

    if (typeof packet.blockEntities !== 'undefined') {
      for (const nbtData of packet.blockEntities) {
        addBlockEntity(nbtData)
      }
    }
  })

  bot._client.on('map_chunk_bulk', (packet) => {
    let offset = 0
    let meta
    let i
    let size
    for (i = 0; i < packet.meta.length; ++i) {
      meta = packet.meta[i]
      size = (8192 + (packet.skyLightSent ? 2048 : 0)) *
        onesInShort(meta.bitMap) + // block ids
        2048 * onesInShort(meta.bitMap) + // (two bytes per block id)
        256 // biomes
      addColumn({
        x: meta.x,
        z: meta.z,
        bitMap: meta.bitMap,
        heightmaps: packet.heightmaps,
        skyLightSent: packet.skyLightSent,
        groundUp: true,
        data: packet.data.slice(offset, offset + size)
      })
      offset += size
    }

    assert.strictEqual(offset, packet.data.length)
  })

  bot._client.on('multi_block_change', (packet) => {
    // multi block change
    for (let i = 0; i < packet.records.length; ++i) {
      const record = packet.records[i]

      const blockZ = (record.horizontalPos & 0x0f)
      const blockX = (record.horizontalPos >> 4) & 0x0f

      const pt = new Vec3(packet.chunkX * 16 + blockX, record.y, packet.chunkZ * 16 + blockZ)
      updateBlockState(pt, record.blockId)
    }
  })

  bot._client.on('block_change', (packet) => {
    const pt = new Vec3(packet.location.x, packet.location.y, packet.location.z)
    updateBlockState(pt, packet.type)
  })

  bot._client.on('explosion', (packet) => {
    // explosion
    const p = new Vec3(packet.x, packet.y, packet.z)
    packet.affectedBlockOffsets.forEach((offset) => {
      const pt = p.offset(offset.x, offset.y, offset.z)
      updateBlockState(pt, 0)
    })
  })

  bot._client.on('spawn_entity_painting', (packet) => {
    const pos = new Vec3(packet.location.x, packet.location.y, packet.location.z)
    const painting = new Painting(packet.entityId,
      pos, packet.title, paintingFaceToVec[packet.direction])
    addPainting(painting)
  })

  bot._client.on('entity_destroy', (packet) => {
    // destroy entity
    packet.entityIds.forEach((id) => {
      const painting = paintingsById[id]
      if (painting) deletePainting(painting)
    })
  })

  bot._client.on('update_sign', (packet) => {
    const pos = new Vec3(packet.location.x, packet.location.y, packet.location.z)
    const oldBlock = blockAt(pos)

    const prepareString = (i) => {
      let text = packet[`text${i}`]

      if (text === 'null' || text === '') {
        text = '""'
      }

      const json = JSON.parse(text)
      if (json.text) {
        json.text = json.text.replace(/^"|"$/g, '')
      }

      return new ChatMessage(json)
    }

    signs[pos] = [
      prepareString(1),
      prepareString(2),
      prepareString(3),
      prepareString(4)
    ].join('\n')

    emitBlockUpdate(oldBlock, blockAt(pos))
  })

  bot._client.on('tile_entity_data', (packet) => {
    addBlockEntity(packet.nbtData)
  })

  bot.updateSign = (block, text) => {
    const lines = text.split('\n')
    if (lines.length > 4) {
      bot.emit('error', new Error('too many lines for sign text'))
      return
    }
    for (let i = 0; i < lines.length; ++i) {
      if (lines[i].length > 15) {
        bot.emit('error', new Error('signs have max line length 15'))
        return
      }
    }

    bot._client.write('update_sign', {
      location: block.position,
      text1: JSON.stringify(lines[0]),
      text2: JSON.stringify(lines[1]),
      text3: JSON.stringify(lines[2]),
      text4: JSON.stringify(lines[3])
    })
  }

  // if we get a respawn packet and the dimension is changed,
  // unload all chunks from memory.
  let dimension
  bot._client.on('login', (packet) => {
    dimension = packet.dimension
  })
  bot._client.on('respawn', (packet) => {
    if (dimension === packet.dimension) return
    dimension = packet.dimension
    columns = {}
  })

  bot.findBlock = findBlock
  bot.canSeeBlock = canSeeBlock
  bot.blockAt = blockAt
  bot._chunkColumn = chunkColumn
  bot._updateBlockState = updateBlockState
  bot._columns = columns
  bot._blockEntities = blockEntities
}

function columnKeyXZ (x, z) {
  return `${x},${z}`
}

function onesInShort (n) {
  n = n & 0xffff
  let count = 0
  for (let i = 0; i < 16; ++i) {
    count = ((1 << i) & n) ? count + 1 : count
  }
  return count
}
<commit_msg>Fix #1052<commit_after>const Vec3 = require('vec3').Vec3
const assert = require('assert')
const Painting = require('../painting')
const Location = require('../location')

const { OctahedronIterator } = require('../iterators')

module.exports = inject

const paintingFaceToVec = [
  new Vec3(0, 0, -1),
  new Vec3(-1, 0, 0),
  new Vec3(0, 0, 1),
  new Vec3(1, 0, 0)
]

function inject (bot, { version }) {
  const nbt = require('prismarine-nbt')
  const Block = require('prismarine-block')(version)
  const Chunk = require('prismarine-chunk')(version)
  const ChatMessage = require('../chat_message')(version)
  let columns = {}
  const signs = {}
  const paintingsByPos = {}
  const paintingsById = {}

  const blockEntities = new Map()

  function addPainting (painting) {
    paintingsById[painting.id] = painting
    paintingsByPos[painting.position] = painting
  }

  function deletePainting (painting) {
    delete paintingsById[painting.id]
    delete paintingsByPos[painting.position]
  }

  function addBlockEntity (nbtData) {
    const blockEntity = nbt.simplify(nbtData)
    const absolutePoint = new Vec3(blockEntity.x, blockEntity.y, blockEntity.z)
    const loc = new Location(absolutePoint)

    // Handle signs
    if (blockEntity.id === 'minecraft:sign' || blockEntity.id === 'Sign') {
      const prepareJson = (i) => {
        const data = blockEntity[`Text${i}`]

        if (data === null || data === '') return ''

        const json = JSON.parse(data)
        if (!('text' in json)) return ''

        json.text = json.text.replace(/^"|"$/g, '')
        return json
      }

      blockEntity.Text1 = new ChatMessage(prepareJson(1))
      blockEntity.Text2 = new ChatMessage(prepareJson(2))
      blockEntity.Text3 = new ChatMessage(prepareJson(3))
      blockEntity.Text4 = new ChatMessage(prepareJson(4))

      signs[loc.floored] = [
        blockEntity.Text1.toString(),
        blockEntity.Text2.toString(),
        blockEntity.Text3.toString(),
        blockEntity.Text4.toString()
      ].join('\n')
    }

    blockEntities[loc.floored] = blockEntity
  }

  function delColumn (chunkX, chunkY) {
    const columnCorner = new Vec3(chunkX * 16, 0, chunkY * 16)
    const key = columnKeyXZ(columnCorner.x, columnCorner.z)
    delete columns[key]
    bot.emit('chunkColumnUnload', columnCorner)
  }

  function addColumn (args) {
    const columnCorner = new Vec3(args.x * 16, 0, args.z * 16)
    const key = columnKeyXZ(columnCorner.x, columnCorner.z)
    if (!args.bitMap) {
      // stop storing the chunk column
      delColumn(args.x, args.z)
      return
    }
    let column = columns[key]
    if (!column) columns[key] = column = new Chunk()

    try {
      column.load(args.data, args.bitMap, args.skyLightSent)
      if (args.biomes !== undefined) {
        column.loadBiomes(args.biomes)
      }
    } catch (e) {
      bot.emit('error', e)
      return
    }

    bot.emit('chunkColumnLoad', columnCorner)
  }

  function getMatchingFunction (matching) {
    if (typeof (matching) !== 'function') {
      if (!Array.isArray(matching)) {
        matching = [matching]
      }
      return isMatchingType
    }
    return matching

    function isMatchingType (block) {
      return block === null ? false : matching.indexOf(block.type) >= 0
    }
  }

  function isBlockInSection (section, matcher) {
    if (!section) return false // section is empty, skip it (yay!)
    // If the chunk use a palette we can speed up the search by first
    // checking the palette which usually contains less than 20 ids
    // vs checking the 4096 block of the section. If we don't have a
    // match in the palette, we can skip this section.
    if (section.palette) {
      for (const stateId of section.palette) {
        if (matcher(Block.fromStateId(stateId, 0))) {
          return true // the block is in the palette
        }
      }
      return false // skip
    }
    return true // global palette, the block might be in there
  }

  bot.findBlocks = (options) => {
    const matcher = getMatchingFunction(options.matching)
    const point = options.point || bot.entity.position
    let start = point.floored()
    const maxDistance = Math.ceil((options.maxDistance || 16) / 16)
    const minCount = options.minCount || 1
    const blocks = []
    start = new Vec3(Math.floor(start.x / 16), Math.floor(start.y / 16), Math.floor(start.z / 16))
    const it = new OctahedronIterator(start, maxDistance)
    // the octahedron iterator can sometime go through the same section again
    // we use a set to keep track of visited sections
    const visitedSections = new Set()
    let startedLayer = 0
    let next = start
    while (next) {
      const column = columns[columnKeyXZ(next.x * 16, next.z * 16)]
      if (next.y >= 0 && next.y < 16 && column && !visitedSections.has(next.toString())) {
        const section = column.sections[next.y]
        if (isBlockInSection(section, matcher)) {
          const cursor = new Vec3(0, 0, 0)
          for (cursor.x = next.x * 16; cursor.x < next.x * 16 + 16; cursor.x++) {
            for (cursor.y = next.y * 16; cursor.y < next.y * 16 + 16; cursor.y++) {
              for (cursor.z = next.z * 16; cursor.z < next.z * 16 + 16; cursor.z++) {
                const found = bot.blockAt(cursor, false)
                if (matcher(found)) blocks.push(cursor.clone())
              }
            }
          }
        }
        visitedSections.add(next.toString())
      }
      // If we started a layer, we have to finish it otherwise we might miss closer blocks
      if (startedLayer !== it.apothem && blocks.length >= minCount) {
        break
      }
      startedLayer = it.apothem
      next = it.next()
    }
    blocks.sort((a, b) => {
      return a.distanceTo(point) - b.distanceTo(point)
    })
    return blocks
  }

  function findBlock (options) {
    const blocks = bot.findBlocks(options)
    if (blocks.length === 0) return null
    return bot.blockAt(blocks[0])
  }

  function posInChunk (pos) {
    pos = pos.floored()
    pos.x &= 15
    pos.y &= 255
    pos.z &= 15
    return pos
  }

  function blockAt (absolutePoint, extraInfos = true) {
    const loc = new Location(absolutePoint)
    const key = columnKeyXZ(loc.chunkCorner.x, loc.chunkCorner.z)

    const column = columns[key]
    // null column means chunk not loaded
    if (!column) return null

    const block = column.getBlock(posInChunk(absolutePoint))
    block.position = loc.floored
    if (extraInfos) {
      block.signText = signs[loc.floored]
      block.painting = paintingsByPos[loc.floored]
      block.blockEntity = blockEntities[loc.floored]
    }

    return block
  }

  function blockIsNotEmpty (pos) {
    const block = bot.blockAt(pos)
    return block !== null && block.boundingBox !== 'empty'
  }

  // maybe this should be moved to math.js instead?
  function visiblePosition (a, b) {
    let v = b.minus(a)
    const t = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)
    v = v.scaled(1 / t)
    v = v.scaled(1 / 5)
    const u = t * 5
    let na
    for (let i = 1; i < u; i++) {
      na = a.plus(v)
      // check that blocks don't inhabit the same position
      if (!na.floored().equals(a.floored())) {
        // check block is not transparent
        if (blockIsNotEmpty(na)) return false
      }
      a = na
    }
    return true
  }

  // if passed in block is within line of sight to the bot, returns true
  // also works on anything with a position value
  function canSeeBlock (block) {
    // this emits a ray from the center of the bots body to the block
    if (visiblePosition(bot.entity.position.offset(0, bot.entity.height * 0.5, 0), block.position)) {
      return true
    }
    return false
  }

  function chunkColumn (x, z) {
    const key = columnKeyXZ(x, z)
    return columns[key]
  }

  function emitBlockUpdate (oldBlock, newBlock) {
    bot.emit('blockUpdate', oldBlock, newBlock)
    const position = oldBlock ? oldBlock.position
      : (newBlock ? newBlock.position : null)
    if (position) bot.emit(`blockUpdate:${newBlock.position}`, oldBlock, newBlock)
  }

  bot._client.on('unload_chunk', (packet) => {
    delColumn(packet.x, packet.z)
  })

  function updateBlockState (point, stateId) {
    const oldBlock = blockAt(point)
    const loc = new Location(point)
    const key = columnKeyXZ(loc.chunkCorner.x, loc.chunkCorner.z)
    const column = columns[key]
    // sometimes minecraft server sends us block updates before it sends
    // us the column that the block is in. ignore this.
    if (!column) return
    column.setBlockStateId(posInChunk(point), stateId)

    const newBlock = blockAt(point)
    if (oldBlock.type !== newBlock.type) {
      delete blockEntities[loc.floored]
      delete signs[loc.floored]

      const painting = paintingsByPos[loc.floored]
      if (painting) deletePainting(painting)
    }

    emitBlockUpdate(oldBlock, newBlock)
  }

  bot._client.on('update_light', (packet) => {
    const key = columnKeyXZ(packet.chunkX, packet.chunkZ)
    let column = columns[key]

    if (!column) columns[key] = column = new Chunk()

    column.loadLight(packet.data, packet.skyLightMask, packet.blockLightMask, packet.emptySkyLightMask, packet.emptyBlockLightMask)
  })

  bot._client.on('map_chunk', (packet) => {
    addColumn({
      x: packet.x,
      z: packet.z,
      bitMap: packet.bitMap,
      heightmaps: packet.heightmaps,
      biomes: packet.biomes,
      skyLightSent: bot.game.dimension === 'overworld',
      groundUp: packet.groundUp,
      data: packet.chunkData
    })

    if (typeof packet.blockEntities !== 'undefined') {
      for (const nbtData of packet.blockEntities) {
        addBlockEntity(nbtData)
      }
    }
  })

  bot._client.on('map_chunk_bulk', (packet) => {
    let offset = 0
    let meta
    let i
    let size
    for (i = 0; i < packet.meta.length; ++i) {
      meta = packet.meta[i]
      size = (8192 + (packet.skyLightSent ? 2048 : 0)) *
        onesInShort(meta.bitMap) + // block ids
        2048 * onesInShort(meta.bitMap) + // (two bytes per block id)
        256 // biomes
      addColumn({
        x: meta.x,
        z: meta.z,
        bitMap: meta.bitMap,
        heightmaps: packet.heightmaps,
        skyLightSent: packet.skyLightSent,
        groundUp: true,
        data: packet.data.slice(offset, offset + size)
      })
      offset += size
    }

    assert.strictEqual(offset, packet.data.length)
  })

  bot._client.on('multi_block_change', (packet) => {
    // multi block change
    for (let i = 0; i < packet.records.length; ++i) {
      const record = packet.records[i]

      const blockZ = (record.horizontalPos & 0x0f)
      const blockX = (record.horizontalPos >> 4) & 0x0f

      const pt = new Vec3(packet.chunkX * 16 + blockX, record.y, packet.chunkZ * 16 + blockZ)
      updateBlockState(pt, record.blockId)
    }
  })

  bot._client.on('block_change', (packet) => {
    const pt = new Vec3(packet.location.x, packet.location.y, packet.location.z)
    updateBlockState(pt, packet.type)
  })

  bot._client.on('explosion', (packet) => {
    // explosion
    const p = new Vec3(packet.x, packet.y, packet.z)
    packet.affectedBlockOffsets.forEach((offset) => {
      const pt = p.offset(offset.x, offset.y, offset.z)
      updateBlockState(pt, 0)
    })
  })

  bot._client.on('spawn_entity_painting', (packet) => {
    const pos = new Vec3(packet.location.x, packet.location.y, packet.location.z)
    const painting = new Painting(packet.entityId,
      pos, packet.title, paintingFaceToVec[packet.direction])
    addPainting(painting)
  })

  bot._client.on('entity_destroy', (packet) => {
    // destroy entity
    packet.entityIds.forEach((id) => {
      const painting = paintingsById[id]
      if (painting) deletePainting(painting)
    })
  })

  bot._client.on('update_sign', (packet) => {
    const pos = new Vec3(packet.location.x, packet.location.y, packet.location.z)
    const oldBlock = blockAt(pos)

    const prepareString = (i) => {
      let text = packet[`text${i}`]

      if (text === 'null' || text === '') {
        text = '""'
      }

      const json = JSON.parse(text)
      if (json.text) {
        json.text = json.text.replace(/^"|"$/g, '')
      }

      return new ChatMessage(json)
    }

    signs[pos] = [
      prepareString(1),
      prepareString(2),
      prepareString(3),
      prepareString(4)
    ].join('\n')

    emitBlockUpdate(oldBlock, blockAt(pos))
  })

  bot._client.on('tile_entity_data', (packet) => {
    addBlockEntity(packet.nbtData)
  })

  bot.updateSign = (block, text) => {
    const lines = text.split('\n')
    if (lines.length > 4) {
      bot.emit('error', new Error('too many lines for sign text'))
      return
    }
    for (let i = 0; i < lines.length; ++i) {
      if (lines[i].length > 15) {
        bot.emit('error', new Error('signs have max line length 15'))
        return
      }
    }

    bot._client.write('update_sign', {
      location: block.position,
      text1: JSON.stringify(lines[0]),
      text2: JSON.stringify(lines[1]),
      text3: JSON.stringify(lines[2]),
      text4: JSON.stringify(lines[3])
    })
  }

  // if we get a respawn packet and the dimension is changed,
  // unload all chunks from memory.
  let dimension
  bot._client.on('login', (packet) => {
    dimension = packet.dimension
  })
  bot._client.on('respawn', (packet) => {
    if (dimension === packet.dimension) return
    dimension = packet.dimension
    columns = {}
  })

  bot.findBlock = findBlock
  bot.canSeeBlock = canSeeBlock
  bot.blockAt = blockAt
  bot._chunkColumn = chunkColumn
  bot._updateBlockState = updateBlockState
  bot._columns = columns
  bot._blockEntities = blockEntities
}

function columnKeyXZ (x, z) {
  return `${x},${z}`
}

function onesInShort (n) {
  n = n & 0xffff
  let count = 0
  for (let i = 0; i < 16; ++i) {
    count = ((1 << i) & n) ? count + 1 : count
  }
  return count
}
<|endoftext|>


<commit_before>
var fs = require('fs'),
    path = require('path'),
    exec = require('child_process').exec;

module.exports = function(settings){
    // Validation
    if(!settings.shell){
        throw new Error('No shell provided');
    }
    var shell = settings.shell;
    // Default settings
    settings.workspace = settings.workspace || shell.project_dir;
    if(!settings.workspace){
        throw new Error('No workspace provided');
    }
    // Register commands
    var coffee;
    shell.on('exit', function() {
        if (shell.isShell && !settings.detach && coffee) {
            coffee.kill();
        }
    });
    function enrichFiles(files){
        if(!settings.workspace){
            return;
        }
        return files.split(' ').map(function(file){
            if(file.substr(0,1) !== '/'){
                file = '/'+file;
            }
            if(file.substr(-1,1)!=='/' && fs.statSync(file).isDirectory()){
                file += '/';
            }
            return file;
        }).join(' ');
    };
    shell.cmd('coffee start', 'Start CoffeeScript', function(req, res, next) {
        var args = [];
        var detached = !shell.isShell || settings.detach;
        var pipeStdout = settings.stdout && !detached;
        var pipeStderr = settings.stderr && !detached;
        // Before compiling, concatenate all scripts together in the
        // order they were passed, and write them into the specified
        // file. Useful for building large projects.
        if(settings.join){
            args.push('-j');
            args.push(enrichFiles(settings.join));
        }
        // Watch the modification times of the coffee-scripts,
        // recompiling as soon as a change occurs.
        args.push('-w');
        // If the jsl (JavaScript Lint) command is installed, use it
        // to check the compilation of a CoffeeScript file. (Handy
        // in conjunction with --watch)
        if(settings.lint){
            args.push('-l');
        }
        // Load a library before compiling or executing your script.
        // Can be used to hook in to the compiler (to add Growl
        // notifications, for example).
        if(settings.require){
            args.push('-r');
            args.push(settings.require);
        }
        // Compile the JavaScript without the top-level function
        // safety wrapper. (Used for CoffeeScript as a Node.js module.)
        args.push('-b');
        /* Not sure if this apply to wath mode
        // The node executable has some useful options you can set,
        // such as --debug and --max-stack-size. Use this flag to
        // forward options directly to Node.js.
        if(settings.nodejs){
            args.push('--nodejs');
            args.push(settings.nodejs);
        }
        */
        // Write out all compiled JavaScript files into the specified
        // directory. Use in conjunction with --compile or --watch.
        if(!settings.output && path.existsSync(settings.workspace+'/lib')){
            settings.output = settings.workspace+'/lib/';
        }
        if(settings.output){
            args.push('-o');
            args.push(enrichFiles(settings.output));
        }
        // Compile a .coffee script into a .js JavaScript file
        // of the same name.
        if(!settings.compile && path.existsSync(settings.workspace+'/src')){
            settings.compile = settings.workspace+'/src/';
        }
        if(settings.compile){
            args.push('-c');
            args.push(enrichFiles(settings.compile));
        }
        if(!pipeStdout){
            args.push('>');
            args.push(settings.stdout);
        }
        if(!pipeStderr){
            args.push('2>');
            args.push(settings.stderr);
        }
        args.unshift('coffee');
        coffee = exec(args.join(' '));
        if(pipeStdout){
            coffee.stdout.pipe(
                typeof settings.stdout === 'string'
                ? fs.createWriteStream(settings.stdout)
                : settings.stdout
            );
        }
        if(pipeStderr){
            coffee.stderr.pipe(
                typeof settings.stderr === 'string'
                ? fs.createWriteStream(settings.stderr)
                : settings.stderr
            );
        }
        if(detached){
            var pidfile = settings.pidfile || '/tmp/coffee.pid';
            fs.writeFileSync(pidfile,''+coffee.pid);
        }
        // Give a chance to coffee to startup
        setTimeout(function(){
            if(coffee){
                res.cyan('CoffeeScript started').ln();
            }
            res.prompt();
        },500);
    });
    shell.cmd('coffee stop', 'Stop CoffeeScript', function(req, res, next) {
        if(!shell.isShell || settings.detach || !coffee){
            var pidfile = settings.pidfile || '/tmp/coffee.pid';
            var pid = fs.readFileSync(pidfile);
            var cmds = [];
            cmds.push('for i in `ps -ef| awk \'$3 == \''+pid+'\' { print $2 }\'` ; do kill $i ; done');
            cmds.push('kill '+pid);
            return exec(cmds.join(' && '))
            .on('exit', function(code){
                code === 0
                ? res.cyan('coffee successfully stoped')
                : res.red('Error while stoping coffee');
                fs.unlinkSync(pidfile);
                res.prompt();
            });
        }else if (coffee) {
            coffee.on('exit', function(code) {
                coffee = null;
                res.cyan('CoffeeScript successfully stopped');
                res.prompt();
            });
            coffee.kill();
        } else {
            res.prompt();
        }
    });
}

<commit_msg>Comment auto compilation from "src" to "lib"<commit_after>
var fs = require('fs'),
    path = require('path'),
    exec = require('child_process').exec;

module.exports = function(settings){
    // Validation
    if(!settings.shell){
        throw new Error('No shell provided');
    }
    var shell = settings.shell;
    // Default settings
    settings.workspace = settings.workspace || shell.project_dir;
    if(!settings.workspace){
        throw new Error('No workspace provided');
    }
    // Register commands
    var coffee;
    shell.on('exit', function() {
        if (shell.isShell && !settings.detach && coffee) {
            coffee.kill();
        }
    });
    // Sanitize a list of files separated by spaces
    function enrichFiles(files){
        if(!settings.workspace){
            return;
        }
        return files.split(' ').map(function(file){
            if(file.substr(0,1) !== '/'){
                file = '/'+file;
            }
            if(file.substr(-1,1)!=='/' && fs.statSync(file).isDirectory()){
                file += '/';
            }
            return file;
        }).join(' ');
    };
    shell.cmd('coffee start', 'Start CoffeeScript', function(req, res, next) {
        var args = [];
        var detached = !shell.isShell || settings.detach;
        var pipeStdout = settings.stdout && !detached;
        var pipeStderr = settings.stderr && !detached;
        // Before compiling, concatenate all scripts together in the
        // order they were passed, and write them into the specified
        // file. Useful for building large projects.
        if(settings.join){
            args.push('-j');
            args.push(enrichFiles(settings.join));
        }
        // Watch the modification times of the coffee-scripts,
        // recompiling as soon as a change occurs.
        args.push('-w');
        // If the jsl (JavaScript Lint) command is installed, use it
        // to check the compilation of a CoffeeScript file. (Handy
        // in conjunction with --watch)
        if(settings.lint){
            args.push('-l');
        }
        // Load a library before compiling or executing your script.
        // Can be used to hook in to the compiler (to add Growl
        // notifications, for example).
        if(settings.require){
            args.push('-r');
            args.push(settings.require);
        }
        // Compile the JavaScript without the top-level function
        // safety wrapper. (Used for CoffeeScript as a Node.js module.)
        args.push('-b');
        /* Not sure if this apply to wath mode
        // The node executable has some useful options you can set,
        // such as --debug and --max-stack-size. Use this flag to
        // forward options directly to Node.js.
        if(settings.nodejs){
            args.push('--nodejs');
            args.push(settings.nodejs);
        }
        */
        // Write out all compiled JavaScript files into the specified
        // directory. Use in conjunction with --compile or --watch.
        // if(!settings.output && path.existsSync(settings.workspace+'/lib')){
        //     settings.output = settings.workspace+'/lib/';
        // }
        if(settings.output){
            args.push('-o');
            args.push(enrichFiles(settings.output));
        }
        // Compile a .coffee script into a .js JavaScript file
        // of the same name.
        // if(!settings.compile && path.existsSync(settings.workspace+'/src')){
        //     settings.compile = settings.workspace+'/src/';
        // }
        if(!settings.compile){
            settings.compile = settings.workspace;
        }
        if(settings.compile){
            args.push('-c');
            args.push(enrichFiles(settings.compile));
        }
        if(!pipeStdout){
            args.push('>');
            args.push(settings.stdout || '/dev/null');
        }
        if(!pipeStderr){
            args.push('2>');
            args.push(settings.stderr || '/dev/null');
        }
        args.unshift('coffee');
        coffee = exec(args.join(' '));
        if(pipeStdout){
            coffee.stdout.pipe(
                typeof settings.stdout === 'string'
                ? fs.createWriteStream(settings.stdout)
                : settings.stdout
            );
        }
        if(pipeStderr){
            coffee.stderr.pipe(
                typeof settings.stderr === 'string'
                ? fs.createWriteStream(settings.stderr)
                : settings.stderr
            );
        }
        if(detached){
            var pidfile = settings.pidfile || '/tmp/coffee.pid';
            fs.writeFileSync(pidfile,''+coffee.pid);
        }
        // Give a chance to coffee to startup
        setTimeout(function(){
            if(coffee){
                res.cyan('CoffeeScript started').ln();
            }
            res.prompt();
        },500);
    });
    shell.cmd('coffee stop', 'Stop CoffeeScript', function(req, res, next) {
        if(!shell.isShell || settings.detach || !coffee){
            var pidfile = settings.pidfile || '/tmp/coffee.pid';
            var pid = fs.readFileSync(pidfile);
            var cmds = [];
            cmds.push('for i in `ps -ef| awk \'$3 == \''+pid+'\' { print $2 }\'` ; do kill $i ; done');
            cmds.push('kill '+pid);
            return exec(cmds.join(' && '))
            .on('exit', function(code){
                code === 0
                ? res.cyan('coffee successfully stoped')
                : res.red('Error while stoping coffee');
                fs.unlinkSync(pidfile);
                res.prompt();
            });
        }else if (coffee) {
            coffee.on('exit', function(code) {
                coffee = null;
                res.cyan('CoffeeScript successfully stopped');
                res.prompt();
            });
            coffee.kill();
        } else {
            res.prompt();
        }
    });
}

<|endoftext|>