<commit_before>// Convert an element into a 3D laptop, moving its contents into the screen.

class Laptop {
  constructor(elem, index, dummy = false) {
    this.elem = elem;
    this.index = index;
    this.dummy = dummy;

    this._translateX = this._translateY = this._translateZ = 0;
    this._rotateX = this._rotateY = this._rotateZ = 0;
    this._lidAngle = 90;

    this.elem.classList.add('laptop3d');
    if (this.dummy) this.elem.classList.add('dummy');
    if (typeof this.index !== 'undefined') this.elem.setAttribute('data-laptop3d-index', this.index);

    const children = [...this.elem.childNodes];
    this.elem.innerHTML = `

    `;
    // Record some common elements as properties
    ['wrapper', 'base', 'lid', 'screen'].forEach((name) => {
      this[name] = this.elem.getElementsByClassName(name)[0];
    });
    // Add all former children to the new screen element
    children.forEach(child => this.screen.appendChild(child));

    // Transform
    this.elem.style.transform = `translateX(50vw) translateX(-50%) rotateX(80deg) rotateZ(45deg) translateX(${30 * this.index}vw)`;

    // Lift up a bit on hover
    if (!this.dummy) {
      this.elem.addEventListener('mouseenter', () => { this.rotateZ = -90; });
      this.elem.addEventListener('mouseleave', () => { this.rotateZ = 0; });
    }

    this._applyTransform();
  }

  _applyTransform() {
    this.wrapper.style.transform = [
      `rotateX(${this._rotateX})`,
      `rotateY(${this._rotateY})`,
      `rotateZ(${this._rotateZ})`,
      `translateX(${this._translateX})`,
      `translateY(${this._translateY})`,
      `translateZ(${this._translateZ})`,
    ].join(' ');
    this.lid.style.transform = `translateY(-33.333333vw) rotateX(${-180 + this._lidAngle}deg)`;
  }

  // Translation

  get translateX() { return this._translateX; }
  get translateY() { return this._translateY; }
  get translateZ() { return this._translateZ; }

  set translateX(val) { this._translateX = val; this._applyTransform(); }
  set translateY(val) { this._translateY = val; this._applyTransform(); }
  set translateZ(val) { this._translateZ = val; this._applyTransform(); }

  // Rotation
  get rotateX() { return this._rotateX; }
  get rotateY() { return this._rotateY; }
  get rotateZ() { return this._rotateZ; }

  _setRotate(axis, val) {
    if (!['X', 'Y', 'Z'].includes(axis)) throw new Error('Axis must be one of X Y or Z'); // val must be XYZ
    const prop = `_rotate${axis}`; // Property that we're setting
    if (typeof val === 'string' && val.endsWith('deg')) this[prop] = val; // Don't change if the value is already a string ending in 'deg'
    else this[prop] = `${val}deg`; // Otherwise add the 'deg' suffix
    this._applyTransform();
  }
  set rotateX(val) { this._setRotate('X', val); }
  set rotateY(val) { this._setRotate('Y', val); }
  set rotateZ(val) { this._setRotate('Z', val); }

  // Lid
  get lidAngle() { return this._lidAngle; }
  set lidAngle(val) { this._lidAngle = val; this._applyTransform(); }

}

class LaptopCarousel {
  constructor(container, laptops) {
    this.container = container;
    this.laptops = laptops;
    // Sort by index
    this.laptops.sort((a, b) => a.index - b.index);
    // Check that there are no overlapping indices
    const indices = this.laptops.map(l => l.index);
    if (indices.length !== new Set(indices).size) throw new Error('LaptopCarousel indices must be unique');
    // Record this as the carousel for each laptop
    laptops.forEach((l) => { l.carousel = this; });
    // Build map of laptops by index
    this.laptopsByIndex = {};
    laptops.forEach((l) => { this.laptopsByIndex[l.index] = l; });
  }

  // All indices represented
  get indices() { return this.laptops.map(l => l.index); }
  // Minimum index represented
  get minIndex() { return Math.min(...this.indices); }
  // Maximum index represented
  get maxIndex() { return Math.max(...this.indices); }

  }

  // Maximum index represented
  get maxIndex() {
    return Math.max(...this.laptops.map(l => l.index));
  }

  scroll(progress) {
    this.progress = progress;
  }
}

// Set up laptop scene
document.addEventListener('DOMContentLoaded', () => {
  // Convert all elements with the class 'laptop3d' into laptops
  const laptopsContainer = document.getElementsByClassName('laptops-container')[0];
  const laptopElems = [...laptopsContainer.getElementsByClassName('laptop3d')];
  const laptops = laptopElems.map((l, i) => new Laptop(l, i));
  // Add 10 dummy laptops to the beginning
  const dummyLaptops = new Array(10)
    .fill(0)
    .map(() => document.createElement('div'))
    .map(l => laptopsContainer.appendChild(l))
    .map((l, i) => new Laptop(l, -(i + 1), true));

  window.carousel = new LaptopCarousel(laptopsContainer, laptops.concat(dummyLaptops));
});
<commit_msg>Oops (clean up)<commit_after>// Convert an element into a 3D laptop, moving its contents into the screen.

class Laptop {
  constructor(elem, index, dummy = false) {
    this.elem = elem;
    this.index = index;
    this.dummy = dummy;

    this._translateX = this._translateY = this._translateZ = 0;
    this._rotateX = this._rotateY = this._rotateZ = 0;
    this._lidAngle = 90;

    this.elem.classList.add('laptop3d');
    if (this.dummy) this.elem.classList.add('dummy');
    if (typeof this.index !== 'undefined') this.elem.setAttribute('data-laptop3d-index', this.index);

    const children = [...this.elem.childNodes];
    this.elem.innerHTML = `

    `;
    // Record some common elements as properties
    ['wrapper', 'base', 'lid', 'screen'].forEach((name) => {
      this[name] = this.elem.getElementsByClassName(name)[0];
    });
    // Add all former children to the new screen element
    children.forEach(child => this.screen.appendChild(child));

    // Transform
    this.elem.style.transform = `translateX(50vw) translateX(-50%) rotateX(80deg) rotateZ(45deg) translateX(${30 * this.index}vw)`;

    // Lift up a bit on hover
    if (!this.dummy) {
      this.elem.addEventListener('mouseenter', () => { this.rotateZ = -90; });
      this.elem.addEventListener('mouseleave', () => { this.rotateZ = 0; });
    }

    this._applyTransform();
  }

  _applyTransform() {
    this.wrapper.style.transform = [
      `rotateX(${this._rotateX})`,
      `rotateY(${this._rotateY})`,
      `rotateZ(${this._rotateZ})`,
      `translateX(${this._translateX})`,
      `translateY(${this._translateY})`,
      `translateZ(${this._translateZ})`,
    ].join(' ');
    this.lid.style.transform = `translateY(-33.333333vw) rotateX(${-180 + this._lidAngle}deg)`;
  }

  // Translation

  get translateX() { return this._translateX; }
  get translateY() { return this._translateY; }
  get translateZ() { return this._translateZ; }

  set translateX(val) { this._translateX = val; this._applyTransform(); }
  set translateY(val) { this._translateY = val; this._applyTransform(); }
  set translateZ(val) { this._translateZ = val; this._applyTransform(); }

  // Rotation
  get rotateX() { return this._rotateX; }
  get rotateY() { return this._rotateY; }
  get rotateZ() { return this._rotateZ; }

  _setRotate(axis, val) {
    if (!['X', 'Y', 'Z'].includes(axis)) throw new Error('Axis must be one of X Y or Z'); // val must be XYZ
    const prop = `_rotate${axis}`; // Property that we're setting
    if (typeof val === 'string' && val.endsWith('deg')) this[prop] = val; // Don't change if the value is already a string ending in 'deg'
    else this[prop] = `${val}deg`; // Otherwise add the 'deg' suffix
    this._applyTransform();
  }
  set rotateX(val) { this._setRotate('X', val); }
  set rotateY(val) { this._setRotate('Y', val); }
  set rotateZ(val) { this._setRotate('Z', val); }

  // Lid
  get lidAngle() { return this._lidAngle; }
  set lidAngle(val) { this._lidAngle = val; this._applyTransform(); }

}

class LaptopCarousel {
  constructor(container, laptops) {
    this.container = container;
    this.laptops = laptops;
    // Sort by index
    this.laptops.sort((a, b) => a.index - b.index);
    // Check that there are no overlapping indices
    const indices = this.laptops.map(l => l.index);
    if (indices.length !== new Set(indices).size) throw new Error('LaptopCarousel indices must be unique');
    // Record this as the carousel for each laptop
    laptops.forEach((l) => { l.carousel = this; });
    // Build map of laptops by index
    this.laptopsByIndex = {};
    laptops.forEach((l) => { this.laptopsByIndex[l.index] = l; });
  }

  // All indices represented
  get indices() { return this.laptops.map(l => l.index); }
  // Minimum index represented
  get minIndex() { return Math.min(...this.indices); }
  // Maximum index represented
  get maxIndex() { return Math.max(...this.indices); }

  scroll(progress) {
    this.progress = progress;
  }
}

// Set up laptop scene
document.addEventListener('DOMContentLoaded', () => {
  // Convert all elements with the class 'laptop3d' into laptops
  const laptopsContainer = document.getElementsByClassName('laptops-container')[0];
  const laptopElems = [...laptopsContainer.getElementsByClassName('laptop3d')];
  const laptops = laptopElems.map((l, i) => new Laptop(l, i));
  // Add 10 dummy laptops to the beginning
  const dummyLaptops = new Array(10)
    .fill(0)
    .map(() => document.createElement('div'))
    .map(l => laptopsContainer.appendChild(l))
    .map((l, i) => new Laptop(l, -(i + 1), true));

  window.carousel = new LaptopCarousel(laptopsContainer, laptops.concat(dummyLaptops));
});
<|endoftext|>


<commit_before>// Convert an element into a 3D laptop, moving its contents into the screen.

class Laptop {
  constructor(elem, index, dummy = false) {
    this.elem = elem;
    this.index = index;
    this.dummy = dummy;

    this._translateX = this._translateY = this._translateZ = 0;
    this._rotateX = '80deg'; this._rotateY = 0; this._rotateZ = '45deg';

    this.elem.classList.add('laptop3d');
    if (this.dummy) this.elem.classList.add('dummy');
    if (typeof this.index !== 'undefined') this.elem.setAttribute('data-laptop3d-index', this.index);

    const children = [...this.elem.childNodes];
    this.elem.innerHTML = `

    `;
    // Record some common elements as properties
    ['base', 'lid', 'screen'].forEach((name) => {
      this[name] = this.elem.getElementsByClassName(name)[0];
    });
    // Add all former children to the new screen element
    children.forEach(child => this.screen.appendChild(child));

    // Transform
    this._translateX = `${30 * this.index}vw`;

    // Lift up a bit on hover
    if (!this.dummy) {
      this.elem.addEventListener('mouseenter', () => { this.translateZ = '1vw'; });
      this.elem.addEventListener('mouseleave', () => { this.translateZ = 0; });
    }

    this._applyTransform();
  }

  // Allow getting and setting transformation properties individually
  _applyTransform() {
    this.elem.style.transform = [
      `rotateX(${this._rotateX})`,
      `rotateY(${this._rotateY})`,
      `rotateZ(${this._rotateZ})`,
      `translateX(${this._translateX})`,
      `translateY(${this._translateY})`,
      `translateZ(${this._translateZ})`,
    ].join(' ');
  }

  get translateX() { return this._translateX; }
  get translateY() { return this._translateY; }
  get translateZ() { return this._translateZ; }
  get rotateX() { return this._rotateX; }
  get rotateY() { return this._rotateY; }
  get rotateZ() { return this._rotateZ; }

  set translateX(val) { this._translateX = val; this._applyTransform(); }
  set translateY(val) { this._translateY = val; this._applyTransform(); }
  set translateZ(val) { this._translateZ = val; this._applyTransform(); }

  _setRotate(axis, val) {
    if (!['X', 'Y', 'Z'].includes(axis)) throw new Error('Axis must be one of X Y or Z'); // val must be XYZ
    const prop = `_rotate${axis}`; // Property that we're setting
    if (typeof val === 'string' && val.endsWith('deg')) this[prop] = val; // Don't change if the value is already a string ending in 'deg'
    else this[prop] = `${val}deg`; // Otherwise add the 'deg' suffix
    this._applyTransform();
  }
  set rotateX(val) { this._setRotate('X', val); }
  set rotateY(val) { this._setRotate('Y', val); }
  set rotateZ(val) { this._setRotate('Z', val); }
}

class LaptopCarousel {
  constructor(container, laptops) {
    this.container = container;
    this.laptops = laptops;
    // Sort by index
    this.laptops.sort((a, b) => a.index - b.index);
    // Check that there are no overlapping indices
    const indices = this.laptops.map(l => l.index);
    if (indices.length !== new Set(indices).size) throw new Error('LaptopCarousel indices must be unique');
    // Build map of laptops by index
    this.laptopsByIndex = {};
    laptops.forEach((l) => { this.laptopsByIndex[l.index] = l; });
  }

  scroll(progress) {
    this.progress = progress;
  }
}

// Set up laptop scene
document.addEventListener('DOMContentLoaded', () => {
  // Convert all elements with the class 'laptop3d' into laptops
  const laptopsContainer = document.getElementsByClassName('laptops-container')[0];
  const laptopElems = [...laptopsContainer.getElementsByClassName('laptop3d')];
  const laptops = laptopElems.map((l, i) => new Laptop(l, i));
  // Add 10 dummy laptops to the beginning
  const dummyLaptops = new Array(10)
    .fill(0)
    .map(() => document.createElement('div'))
    .map(l => laptopsContainer.appendChild(l))
    .map((l, i) => new Laptop(l, -(i + 1), true));

  window.carousel = new LaptopCarousel(laptopsContainer, laptops.concat(dummyLaptops));
});
<commit_msg>Horizontally center first laptop<commit_after>// Convert an element into a 3D laptop, moving its contents into the screen.

class Laptop {
  constructor(elem, index, dummy = false) {
    this.elem = elem;
    this.index = index;
    this.dummy = dummy;

    this._translateX = this._translateY = this._translateZ = 0;
    this._rotateX = '80deg'; this._rotateY = 0; this._rotateZ = '45deg';

    this.elem.classList.add('laptop3d');
    if (this.dummy) this.elem.classList.add('dummy');
    if (typeof this.index !== 'undefined') this.elem.setAttribute('data-laptop3d-index', this.index);

    const children = [...this.elem.childNodes];
    this.elem.innerHTML = `

    `;
    // Record some common elements as properties
    ['base', 'lid', 'screen'].forEach((name) => {
      this[name] = this.elem.getElementsByClassName(name)[0];
    });
    // Add all former children to the new screen element
    children.forEach(child => this.screen.appendChild(child));

    // Transform
    this._translateX = `${30 * this.index}vw`;

    // Lift up a bit on hover
    if (!this.dummy) {
      this.elem.addEventListener('mouseenter', () => { this.translateZ = '1vw'; });
      this.elem.addEventListener('mouseleave', () => { this.translateZ = 0; });
    }

    this._applyTransform();
  }

  // Allow getting and setting transformation properties individually
  _applyTransform() {
    this.elem.style.transform = [
      'translateX(50vw) translateX(-50%)',
      `rotateX(${this._rotateX})`,
      `rotateY(${this._rotateY})`,
      `rotateZ(${this._rotateZ})`,
      `translateX(${this._translateX})`,
      `translateY(${this._translateY})`,
      `translateZ(${this._translateZ})`,
    ].join(' ');
  }

  get translateX() { return this._translateX; }
  get translateY() { return this._translateY; }
  get translateZ() { return this._translateZ; }
  get rotateX() { return this._rotateX; }
  get rotateY() { return this._rotateY; }
  get rotateZ() { return this._rotateZ; }

  set translateX(val) { this._translateX = val; this._applyTransform(); }
  set translateY(val) { this._translateY = val; this._applyTransform(); }
  set translateZ(val) { this._translateZ = val; this._applyTransform(); }

  _setRotate(axis, val) {
    if (!['X', 'Y', 'Z'].includes(axis)) throw new Error('Axis must be one of X Y or Z'); // val must be XYZ
    const prop = `_rotate${axis}`; // Property that we're setting
    if (typeof val === 'string' && val.endsWith('deg')) this[prop] = val; // Don't change if the value is already a string ending in 'deg'
    else this[prop] = `${val}deg`; // Otherwise add the 'deg' suffix
    this._applyTransform();
  }
  set rotateX(val) { this._setRotate('X', val); }
  set rotateY(val) { this._setRotate('Y', val); }
  set rotateZ(val) { this._setRotate('Z', val); }
}

class LaptopCarousel {
  constructor(container, laptops) {
    this.container = container;
    this.laptops = laptops;
    // Sort by index
    this.laptops.sort((a, b) => a.index - b.index);
    // Check that there are no overlapping indices
    const indices = this.laptops.map(l => l.index);
    if (indices.length !== new Set(indices).size) throw new Error('LaptopCarousel indices must be unique');
    // Build map of laptops by index
    this.laptopsByIndex = {};
    laptops.forEach((l) => { this.laptopsByIndex[l.index] = l; });
  }

  scroll(progress) {
    this.progress = progress;
  }
}

// Set up laptop scene
document.addEventListener('DOMContentLoaded', () => {
  // Convert all elements with the class 'laptop3d' into laptops
  const laptopsContainer = document.getElementsByClassName('laptops-container')[0];
  const laptopElems = [...laptopsContainer.getElementsByClassName('laptop3d')];
  const laptops = laptopElems.map((l, i) => new Laptop(l, i));
  // Add 10 dummy laptops to the beginning
  const dummyLaptops = new Array(10)
    .fill(0)
    .map(() => document.createElement('div'))
    .map(l => laptopsContainer.appendChild(l))
    .map((l, i) => new Laptop(l, -(i + 1), true));

  window.carousel = new LaptopCarousel(laptopsContainer, laptops.concat(dummyLaptops));
});
<|endoftext|>


<commit_before>var parseString = function(string) {
	if(typeof string !== 'string') {
		return null;
	}

	return string.split(";");
};

var parseArray = function(array) {
	if(typeof array !== 'object' || Object.prototype.toString.call(array) !== '[object Array]') {
		return null;
	}
	var stringImploded = '';

	var length = array.length;
	for (var i = 0; i < length; i++) {
		if(typeof array[i] !== 'string' || array[i].indexOf(";")  > -1) {
			throw "Error : " + typeof array[i] + array[i].indexOf(";");
		}
		stringImploded += i > 0 ? ';' : '';
		stringImploded += array[i];
	}
	return stringImploded;
};

exports.parseString = parseString;
exports.parseArray 	= parseArray;
<commit_msg>[DOC] the one where whitespaces were added<commit_after>var parseString = function(string) {
	if (typeof string !== 'string') {
		return null;
	}

	return string.split(";");
};

var parseArray = function(array) {
	if (typeof array !== 'object' || Object.prototype.toString.call(array) !== '[object Array]') {
		return null;
	}
	var stringImploded = '';

	var length = array.length;
	for (var i = 0; i < length; i++) {
		if (typeof array[i] !== 'string' || array[i].indexOf(";")  > -1) {
			throw "Error : " + typeof array[i] + array[i].indexOf(";");
		}
		stringImploded += i > 0 ? ';' : '';
		stringImploded += array[i];
	}
	return stringImploded;
};

exports.parseString = parseString;
exports.parseArray 	= parseArray;
<|endoftext|>


<commit_before><commit_msg>Added sorting to generate-md.js<commit_after><|endoftext|>


<commit_before>var FirebaseRef = require('../settings').FirebaseRef;
var subscribeRef = FirebaseRef.child('persons');

var Subscribe = {
    name: String,
    email: String,
    phone: String,
    address: String,
    all: function () {
        return FirebaseRef.child('persons.json');
    },
    get: function () {
        // Filter by email
    },
    save: function (data) {
        return subscribeRef.push(data);
    }
};

module.exports = Subscribe;
<commit_msg>Subscribe model<commit_after>var FirebaseRef = require('../settings').FirebaseRef;
var subscribeRef = FirebaseRef.child('persons');

var Subscribe = {
    name: String,
    email: String,
    phone: String,
    address: String,
    all: function () {
        return subscribeRef;
    },
    get: function () {
        // Filter by email
    },
    save: function (data) {
        return subscribeRef.push(data);
    }
};

module.exports = Subscribe;
<|endoftext|>


<commit_before>var mongoose     = require('mongoose');
var Schema       = mongoose.Schema;

var Objectid = mongoose.Schema.Types.ObjectId;
var Mixed = mongoose.Schema.Types.Mixed;

var TagSchema   = new Schema({
	name: { type: String, unique: true, index: true, set: toLower },
	type: { type: String, index: true }
});

TagSchema.set("_perms", {
	admin: "crud",
	user: "cr",
	all: "r"
});

function toLower (v) {
	return v.toLowerCase();
}

module.exports = mongoose.model('Tag', TagSchema);<commit_msg>Allow all users to add tags<commit_after>var mongoose     = require('mongoose');
var Schema       = mongoose.Schema;

var Objectid = mongoose.Schema.Types.ObjectId;
var Mixed = mongoose.Schema.Types.Mixed;

var TagSchema   = new Schema({
	name: { type: String, unique: true, index: true, set: toLower },
	type: { type: String, index: true }
});

TagSchema.set("_perms", {
	admin: "crud",
	user: "cr",
	all: "cr"
});

function toLower (v) {
	return v.toLowerCase();
}

module.exports = mongoose.model('Tag', TagSchema);<|endoftext|>


<commit_before><commit_msg>Removed extraneous assertion<commit_after><|endoftext|>


<commit_before><commit_msg>Fixed bug in javascript<commit_after><|endoftext|>


<commit_before>var wrench = nodeRequire('wrench');
var Path = nodeRequire('path');
var os = nodeRequire('os');
var fs = nodeRequire('fs');
var $ = require('jquery');
var util = require('util');

module.exports = {
  newProject: function() {
    //copy the empty project folder to a temporary directory
    var emptyProject = 'mode_assets/p5/empty_project';
    var tempProject = Path.join(os.tmpdir(), 'p5' + Date.now(), 'Untitled');
    wrench.mkdirSyncRecursive(tempProject);
    wrench.copyDirSyncRecursive(emptyProject, tempProject, {
      excludeHiddenUnix: true,
      inflateSymlinks: true,
      forceDelete: true
    });

    this.projectPath = tempProject;

    //open the project and file
    var self = this;
    this.loadProject(tempProject, function(){
      self.openFile(Path.join(tempProject, 'sketch.js'));
      gui.Window.get().show();
    });
  },

  exportProject: function() {
    console.log('hello');
  },

  saveAs: function(path) {
    //save all files
    this.saveAll();

    //copy the folder
    wrench.copyDirSyncRecursive(this.projectPath, path);

    //change file paths
    this.files.forEach(function(file) {
      file.path = Path.join(path, file.name);
    });

    this.$broadcast('save-project-as', path);

    this.projectPath = path;
    //this.$broadcast('open-project', path);
    this.temp = false;
  },

  run: function() {
    var self = this;
    this.saveAll();

    if (this.outputWindow) {
      this.outputWindow.reloadIgnoringCache();
      this.outputWindow.show();
      this.outputWindow.focus();
    } else {
      gui.App.clearCache();
      startServer(this.projectPath, this, function(url) {
        self.outputWindow = self.newWindow(url, {show: true, toolbar: true, 'inject-js-start': 'js/debug-console.js'});
        self.outputWindow.on("close", function(){
          this.hide();
        });

      });
    }
  },

};

var running = false;
var url = '';

function startServer(path, app, callback) {
  if (running === false) {
    var portscanner = nodeRequire('portscanner');
    portscanner.findAPortNotInUse(3000, 4000, '127.0.0.1', function(error, port) {
      var static = nodeRequire('node-static');
      var server = nodeRequire('http').createServer(handler);
      var io = nodeRequire('socket.io')(server);
      var file = new static.Server(path);

      server.listen(port, function(){
        running = true;
        url = 'http://localhost:' + port;
        callback(url);
      });

      function handler(request, response) {
        request.addListener('end', function () {
          file.serve(request, response);
        }).resume();
      }

      io.on('connection', function (socket) {
        socket.on('console', function (data) {
          app.debugOut(data.msg, data.num, data.type);
        });
      });
    });

  } else {
    callback(url);
  }

}
<commit_msg>really close output window<commit_after>var wrench = nodeRequire('wrench');
var Path = nodeRequire('path');
var os = nodeRequire('os');
var fs = nodeRequire('fs');
var $ = require('jquery');
var util = require('util');

module.exports = {
  newProject: function() {
    //copy the empty project folder to a temporary directory
    var emptyProject = 'mode_assets/p5/empty_project';
    var tempProject = Path.join(os.tmpdir(), 'p5' + Date.now(), 'Untitled');
    wrench.mkdirSyncRecursive(tempProject);
    wrench.copyDirSyncRecursive(emptyProject, tempProject, {
      excludeHiddenUnix: true,
      inflateSymlinks: true,
      forceDelete: true
    });

    this.projectPath = tempProject;

    //open the project and file
    var self = this;
    this.loadProject(tempProject, function(){
      self.openFile(Path.join(tempProject, 'sketch.js'));
      gui.Window.get().show();
    });
  },

  exportProject: function() {
    console.log('hello');
  },

  saveAs: function(path) {
    //save all files
    this.saveAll();

    //copy the folder
    wrench.copyDirSyncRecursive(this.projectPath, path);

    //change file paths
    this.files.forEach(function(file) {
      file.path = Path.join(path, file.name);
    });

    this.$broadcast('save-project-as', path);

    this.projectPath = path;
    //this.$broadcast('open-project', path);
    this.temp = false;
  },

  run: function() {
    var self = this;
    this.saveAll();

    if (this.outputWindow) {
      this.outputWindow.reloadIgnoringCache();
      this.outputWindow.show();
      this.outputWindow.focus();
    } else {
      gui.App.clearCache();
      startServer(this.projectPath, this, function(url) {
        self.outputWindow = self.newWindow(url, {show: true, toolbar: true, 'inject-js-start': 'js/debug-console.js'});
        self.outputWindow.on("close", function(){
          self.outputWindow = null;
          this.close(true);
          //this.hide();
        });

      });
    }
  },

};

var running = false;
var url = '';

function startServer(path, app, callback) {
  if (running === false) {
    var portscanner = nodeRequire('portscanner');
    portscanner.findAPortNotInUse(3000, 4000, '127.0.0.1', function(error, port) {
      var static = nodeRequire('node-static');
      var server = nodeRequire('http').createServer(handler);
      var io = nodeRequire('socket.io')(server);
      var file = new static.Server(path);

      server.listen(port, function(){
        running = true;
        url = 'http://localhost:' + port;
        callback(url);
      });

      function handler(request, response) {
        request.addListener('end', function () {
          file.serve(request, response);
        }).resume();
      }

      io.on('connection', function (socket) {
        socket.on('console', function (data) {
          app.debugOut(data.msg, data.num, data.type);
        });
      });
    });

  } else {
    callback(url);
  }

}
<|endoftext|>


<commit_before><commit_msg>Replace $.parents with $.closest<commit_after><|endoftext|>


<commit_before><commit_msg>Add a finish() method to the editor which is called after the editing completes by submit or cancel. None of the built in editors use the method.<commit_after><|endoftext|>


<commit_before><commit_msg>Update maps_lib.js<commit_after><|endoftext|>


<commit_before><commit_msg>poloniex error handles<commit_after><|endoftext|>


<commit_before>var config;
var configPath;
var roles;
var electronRequire;
var ipcRenderer;
var remote;
var presentationMode;
var appMode;

if (typeof process === 'object') {
  appMode = 'app';
} else {
  appMode = 'browser';
}

if (appMode === 'app') {

  remote = require('electron').remote;

  config = remote.getGlobal('config');
  configPath = remote.getGlobal('appConfigPath');
  roles = remote.getGlobal('roles');

  if (config) {

    // preserve newlines, etc - use valid JSON
    config = config.replace(/\\n/g, "\\n")
      .replace(/\\'/g, "\\'")
      .replace(/\\"/g, '\\"')
      .replace(/\\&/g, "\\&")
      .replace(/\\r/g, "\\r")
      .replace(/\\t/g, "\\t")
      .replace(/\\b/g, "\\b")
      .replace(/\\f/g, "\\f");

    // remove non-printable and other non-valid JSON chars
    config = config.replace(/[\u0000-\u0019]+/g,"");

    // Convert to JavaScript Object
    config = JSON.parse(config);

    // Set global property to use in stores
    presentationMode = 'online';

    // preserve newlines, etc - use valid JSON
    roles = roles.replace(/\\n/g, "\\n")
      .replace(/\\'/g, "\\'")
      .replace(/\\"/g, '\\"')
      .replace(/\\&/g, "\\&")
      .replace(/\\r/g, "\\r")
      .replace(/\\t/g, "\\t")
      .replace(/\\b/g, "\\b")
      .replace(/\\f/g, "\\f");

    // remove non-printable and other non-valid JSON chars
    roles = roles.replace(/[\u0000-\u0019]+/g,"");

    // Convert to JavaScript Object
    roles = JSON.parse(roles);
  } else {

    // Set global property to use in stores
    presentationMode = 'offline';
  }

  // Use for non browserify requires
  electronRequire = require;

  // Use to communicate with Electron
  ipcRenderer = require('electron').ipcRenderer;
}
<commit_msg>Added lodash to packagedapp setup<commit_after>var config;
var configPath;
var roles;
var electronRequire;
var ipcRenderer;
var remote;
var presentationMode;
var appMode;
var _;

if (typeof process === 'object') {
  appMode = 'app';
} else {
  appMode = 'browser';
}

if (appMode === 'app') {

  remote = require('electron').remote;
  _ = require('lodash');

  config = remote.getGlobal('config');
  configPath = remote.getGlobal('appConfigPath');
  roles = remote.getGlobal('roles');

  if (config) {

    // preserve newlines, etc - use valid JSON
    config = config.replace(/\\n/g, "\\n")
      .replace(/\\'/g, "\\'")
      .replace(/\\"/g, '\\"')
      .replace(/\\&/g, "\\&")
      .replace(/\\r/g, "\\r")
      .replace(/\\t/g, "\\t")
      .replace(/\\b/g, "\\b")
      .replace(/\\f/g, "\\f");

    // remove non-printable and other non-valid JSON chars
    config = config.replace(/[\u0000-\u0019]+/g,"");

    // Convert to JavaScript Object
    config = JSON.parse(config);

    // Set global property to use in stores
    presentationMode = 'online';

    // preserve newlines, etc - use valid JSON
    roles = roles.replace(/\\n/g, "\\n")
      .replace(/\\'/g, "\\'")
      .replace(/\\"/g, '\\"')
      .replace(/\\&/g, "\\&")
      .replace(/\\r/g, "\\r")
      .replace(/\\t/g, "\\t")
      .replace(/\\b/g, "\\b")
      .replace(/\\f/g, "\\f");

    // remove non-printable and other non-valid JSON chars
    roles = roles.replace(/[\u0000-\u0019]+/g,"");

    // Convert to JavaScript Object
    roles = JSON.parse(roles);
  } else {

    // Set global property to use in stores
    presentationMode = 'offline';
  }

  // Use for non browserify requires
  electronRequire = require;

  // Use to communicate with Electron
  ipcRenderer = require('electron').ipcRenderer;
}
<|endoftext|>


<commit_before><commit_msg>Update datadog.js<commit_after><|endoftext|>


<commit_before><commit_msg>Support custom receiverProgress<commit_after><|endoftext|>


<commit_before><commit_msg>extract cleanup<commit_after><|endoftext|>


<commit_before><commit_msg>closePullRequest function<commit_after><|endoftext|>


<commit_before>'use babel'

/* @flow */

import { Range, Point } from 'atom'
import type Buffers from './buffers'
import type { Linter$Message } from './types'

export function map<TValue, TResult>(iterable: Array<TValue> | Set<TValue>, callback: ((param: TValue) => TResult)): Array<TResult> {
  const toReturn = []
  for (const entry of iterable) {
    toReturn.push(callback(entry))
  }
  return toReturn
}

export function visitMessage(message: Linter$Message): Promise {
  return atom.workspace.open(message.filePath).then(function() {
    if (message.range) {
      const textEditor = atom.workspace.getActiveTextEditor()
      textEditor.setCursorBufferPosition(textEditor)
    }
  })
}

export function getBuffersMap(buffers: Buffers): { buffersMap: Object, filePaths: Set<string> } {
  const buffersMap = {}
  const filePaths = new Set()
  for (const buffer of buffers.getBuffers()) {
    const filePath = buffer.getBuffer().getPath()
    buffersMap[filePath] = {
      buffer,
      added: [],
      removed: []
    }
    filePaths.add(filePath)
  }
  return { buffersMap, filePaths }
}

export function getMessageRange(message: Linter$Message): Range {
  return Array.isArray(message.range) ? Range.fromObject(message.range) : message.range
}
export function getMessageClass(message: Linter$Message): string {
  return `${message.class || ''} ${message.type.toLowerCase()}`
}

export function getMessagesOnPoint(messages: Set<Linter$Message>, filePath: string, cursorPosition: Point): Set<Linter$Message> {
  const filtered = new Set()
  const range = new Range(cursorPosition, cursorPosition)
  for (const message of messages) {
    if (message.filePath === filePath && message.range && range.intersectsWith(Range.fromObject(message.range))) {
      filtered.add(message)
    }
  }
  return filtered
}
<commit_msg>:new: Add message sorting helper<commit_after>'use babel'

/* @flow */

import { Range, Point } from 'atom'
import type Buffers from './buffers'
import type { Linter$Message } from './types'

export function map<TValue, TResult>(iterable: Array<TValue> | Set<TValue>, callback: ((param: TValue) => TResult)): Array<TResult> {
  const toReturn = []
  for (const entry of iterable) {
    toReturn.push(callback(entry))
  }
  return toReturn
}

export function visitMessage(message: Linter$Message): Promise {
  return atom.workspace.open(message.filePath).then(function() {
    if (message.range) {
      const textEditor = atom.workspace.getActiveTextEditor()
      textEditor.setCursorBufferPosition(textEditor)
    }
  })
}

export function getBuffersMap(buffers: Buffers): { buffersMap: Object, filePaths: Set<string> } {
  const buffersMap = {}
  const filePaths = new Set()
  for (const buffer of buffers.getBuffers()) {
    const filePath = buffer.getBuffer().getPath()
    buffersMap[filePath] = {
      buffer,
      added: [],
      removed: []
    }
    filePaths.add(filePath)
  }
  return { buffersMap, filePaths }
}

export function getMessageRange(message: Linter$Message): Range {
  return Array.isArray(message.range) ? Range.fromObject(message.range) : message.range
}
export function getMessageClass(message: Linter$Message): string {
  return `${message.class || ''} ${message.type.toLowerCase()}`
}

export function getMessagesOnPoint(messages: Set<Linter$Message>, filePath: string, cursorPosition: Point): Set<Linter$Message> {
  const filtered = new Set()
  const range = new Range(cursorPosition, cursorPosition)
  for (const message of messages) {
    if (message.filePath === filePath && message.range && range.intersectsWith(Range.fromObject(message.range))) {
      filtered.add(message)
    }
  }
  return filtered
}

export function sortMessages(messages: Array<Linter$Message>): Array<Linter$Message> {
  return messages.sort(function(a, b) {
    if (a.filePath !== b.filePath) {
      return -1
    }
    if (!a.range || b.range) {
      return -1
    }
    return getMessageRange(a).compare(b)
  })
}
<|endoftext|>


<commit_before><commit_msg>Add message handler<commit_after><|endoftext|>


<commit_before>var async = require('async');
/**
* Diffing tool instance
* @const
*/
var DEFAULT_DIFFER = require('looks-same');

/**
* Module for file system interaction
* @const
*/
var DEFAULT_FS = require('fs');

/**
* Root directory of the screenshots
* @type {String}
* @const
* @default
*/
var DEFAULT_ROOT_DIRECTORY = 'visual-tests';

/**
* @param browser - Instance of some browser
* @param {Object} [options]
* @param [options.differ] - A diffing tool instance
* @param [options.fs] - A module to interact with the file system
* @param {String} [options.rootDirectory='visual-tests'] - The directory
*     where the screenshots will be saved
* @constructor
*/
function Mugshot(browser, options) {
  if (browser === undefined) {
    throw new Error('No browser instance was provided');
  }

  this._browser = browser;

  if (arguments.length >= 2 &&
      (typeof options !== 'object' || options instanceof Array)) {
    throw new Error('options is not an obejct');
  }

  options = options || {};
  this._options = {};

  this._options.differ = options.differ || DEFAULT_DIFFER;
  this._options.fs = options.fs || DEFAULT_FS;
  this._options.rootDirectory = options.rootDirectory || DEFAULT_ROOT_DIRECTORY;
}

/**
* @param {Object} captureItem - Details about what will be captured
* @param {String} [captureItem.selector] - A html or css selector
* @param {String} caputreItem.name - A name for the screenshot
*/
Mugshot.prototype.capture = function(captureItem, cb) {
  var fs = this._options.fs,
      screenshot = this._browser.takeScreenshot(),
      baseline = null;

  fs.exists(captureItem.name, function(err, exists) {
    if (!exists) {
      fs.writeFile(captureItem.name, screenshot, 'base64', function(err) {

      });
    }
    else {
      fs.readFile(captureItem.name, 'base64', function(err, data) {
        baseline = data;
      });
    }
  });
}

module.exports = Mugshot;
<commit_msg>remove inutile require<commit_after>/**
* Diffing tool instance
* @const
*/
var DEFAULT_DIFFER = require('looks-same');

/**
* Module for file system interaction
* @const
*/
var DEFAULT_FS = require('fs');

/**
* Root directory of the screenshots
* @type {String}
* @const
* @default
*/
var DEFAULT_ROOT_DIRECTORY = 'visual-tests';

/**
* @param browser - Instance of some browser
* @param {Object} [options]
* @param [options.differ] - A diffing tool instance
* @param [options.fs] - A module to interact with the file system
* @param {String} [options.rootDirectory='visual-tests'] - The directory
*     where the screenshots will be saved
* @constructor
*/
function Mugshot(browser, options) {
  if (browser === undefined) {
    throw new Error('No browser instance was provided');
  }

  this._browser = browser;

  if (arguments.length >= 2 &&
      (typeof options !== 'object' || options instanceof Array)) {
    throw new Error('options is not an obejct');
  }

  options = options || {};
  this._options = {};

  this._options.differ = options.differ || DEFAULT_DIFFER;
  this._options.fs = options.fs || DEFAULT_FS;
  this._options.rootDirectory = options.rootDirectory || DEFAULT_ROOT_DIRECTORY;
}

/**
* @param {Object} captureItem - Details about what will be captured
* @param {String} [captureItem.selector] - A html or css selector
* @param {String} caputreItem.name - A name for the screenshot
*/
Mugshot.prototype.capture = function(captureItem, cb) {
  var fs = this._options.fs,
      screenshot = this._browser.takeScreenshot(),
      baseline = null;

  fs.exists(captureItem.name, function(err, exists) {
    if (!exists) {
      fs.writeFile(captureItem.name, screenshot, 'base64', function(err) {

      });
    }
    else {
      fs.readFile(captureItem.name, 'base64', function(err, data) {
        baseline = data;
      });
    }
  });
}

module.exports = Mugshot;
<|endoftext|>


<commit_before>'use strict';

const nj = require('../bower_components/numjs/dist/numjs')
const _ = require('underscore')

const arrayUtil = require('./array_util')

// https://github.com/numpy/numpy/blob/v1.10.1/numpy/lib/function_base.py#L1116-L1175
function diff(a, n, axis) {
  // default to
  n = n === undefined ? 1 : n
  if (n === 0) {
    return a
  }
  if (n < 0) {
    throw new Error('order must be non-negative but got ' + n)
  }

  let nd = a.shape.length
  let slice1 = _.map(_.range(nd), el => [null])
  let slice2 = _.map(_.range(nd), el => [null])
  // default to last axis
  axis = axis === undefined ? nd - 1 : axis
  slice1[axis] = 1
  slice2[axis] = [null, -1]
  if (n > 1) {
    return diff(a.slice(...slice1).subtract(a.slice(...slice2), n - 1, axis))
  }
  else {
    return a.slice(...slice1).subtract(a.slice(...slice2))
  }
}

function sum(a, axis) {
  if (axis === undefined) {
    return a.flatten().sum()
  }

  const nd = a.shape.length
  const axisLength = a.shape[axis]
  const sliceShape = a.shape.slice()
  sliceShape.splice(axis, 1)

  if (sliceShape.length === 0) {
    // get cumulative sum of array (splice to discard initial 0)
    return nj.array(arrayUtil.scanLeft(0, a.tolist(), (prev, curr) => prev + curr).slice(1))
  }
  else {
    let slice = _.map(_.range(nd), el => [null, null, null])

    let sumSlice = nj.zeros(sliceShape)
    // LOOP INVARIANT: result is the cum sum up to i on the axis
    for (let i = 0; i < axisLength; i++) {
      // slice array at i on the given axis
      slice[axis] = [i, i + 1]
      const row = a.slice(...slice).reshape(...sliceShape)
      sumSlice = sumSlice.add(row)
    }
    return sumSlice
  }
}

// TODO test for array rank > 2
function cumsum(a, axis) {
  if (axis === undefined) {
    return cumsum(a.flatten(), 0)
  }

  const nd = a.shape.length
  const axisLength = a.shape[axis]
  const sliceShape = a.shape.slice()
  sliceShape.splice(axis, 1)

  if (sliceShape.length === 0) {
    // get cumulative sum of array (splice to discard initial 0)
    return nj.array(arrayUtil.scanLeft(0, a.tolist(), (prev, curr) => prev + curr).slice(1))
  }
  else {
    let slice = _.map(_.range(nd), el => [null, null, null])

    const result = []
    let sumSlice = nj.zeros(sliceShape)
    // LOOP INVARIANT: result is the cum sum up to i on the axis
    for (let i = 0; i < axisLength; i++) {
      // slice array at i on the given axis
      slice[axis] = [i, i + 1]
      const row = a.slice(...slice).reshape(...sliceShape)
      sumSlice = sumSlice.add(row)
      // add the sum to the result array
      result.push(sumSlice.tolist())
    }
    const axes = _.range(0, a.shape.length)
    axes[0] = axis
    axes[axis] = 0
    return nj.array(result).transpose(axes)
  }
}

// http://stackoverflow.com/questions/22697936/binary-search-in-javascript
function searchsorted(a, v) {
  let m = 0;
  let n = a.shape[0] - 1
  while (m <= n) {
    const k = (n + m) >> 1
    const cmp = v - a.get(k)
    if (cmp > 0) {
      m = k + 1
    }
    else if (cmp < 0) {
      n = k - 1
    }
    else {
      return k
    }
  }
  return m
}

function vectorize(a, fun) {
  return nj.array(_.map(a.flatten().tolist(), fun)).reshape(...a.shape)
}

// lowerOffset is negative
function getNeighbors(a, r, c, lowerOffset, upperOffset, includeSelf) {
  const clipRow = _.partial(clip, 0, a.shape[0] - 1)
  const clipColumn = _.partial(clip, 0, a.shape[1] - 1)

  if (includeSelf) {
    const rowSlice = [clipRow(r + lowerOffset), clipRow(r + upperOffset) + 1]
    const columnSlice = [clipColumn(c + lowerOffset), clipColumn(c + upperOffset) + 1]
    const neighbors = a.slice(rowSlice, columnSlice).flatten().tolist()
    return nj.array(neighbors)
  }
  else {
    // get slices for upper, left, right, and lower partitions
    const upperRowSlice = [clipRow(r + lowerOffset), r]
    const upperColumnSlice = [clipColumn(c + lowerOffset), clipColumn(c + upperOffset) + 1]

    const leftRowSlice = [r, r + 1]
    const leftColumnSlice = [clipColumn(c + lowerOffset), c]

    const rightRowSlice = [r, r + 1]
    const rightColumnSlice = [c + 1, clipColumn(c + upperOffset) + 1]

    const lowerRowSlice = [r + 1, clipRow(r + upperOffset) + 1]
    const lowerColumnSlice = [clipColumn(c + lowerOffset), clipColumn(c + upperOffset) + 1]

    const rowSlices = [upperRowSlice, leftRowSlice, rightRowSlice, lowerRowSlice]
    const columnSlices = [upperColumnSlice, leftColumnSlice, rightColumnSlice, lowerColumnSlice]

    const neighborGroups = arrayUtil.flatMap(_.zip(rowSlices, columnSlices), ([rowSlice, columnSlice]) => a.slice(rowSlice, columnSlice).flatten().tolist())
    const neighbors = arrayUtil.flatten(neighborGroups)
    return nj.array(neighbors)
  }
}

function sort(a) {
  const arr = a.flatten().tolist()
  arr.sort()
  return nj.array(arr)
}

function percentile(a, q) {
  const sorted = sort(a.flatten())
  const rank = q / 100 * (sorted.shape[0] + 1) - 1
  if (Number.isInteger(rank)) {
    if (sorted.get(rank) === undefined) {
      return null
    }
    else {
      return sorted.get(rank)
    }
  }
  else {
    const IR = Math.floor(rank)
    const FR = rank - IR
    const lower = sorted.get(IR)
    const upper = sorted.get(IR + 1)
    if (lower === undefined && upper === undefined) {
      return null
    }
    else if (lower === undefined) {
      return upper
    }
    else if (upper === undefined) {
      return lower
    }
    else {
      const interpolated = FR * (upper - lower) + lower
      return interpolated
    }
  }
}

const l2Norm = arr => Math.sqrt(vectorize(arr, x => Math.pow(x, 2)).sum())

const distance = (a1, a2) => l2Norm(a1.subtract(a2)) / (l2Norm(a1) + l2Norm(a2))

module.exports = {
  diff,
  sum,
  cumsum,
  searchsorted,
  vectorize,
  getNeighbors,
  sort,
  percentile,
  l2Norm,
  distance
}

function clip(start, end, value) {
  if (value < start) {
    return start
  }
  else if (value > end) {
    return end
  }
  else {
    return value
  }
}

<commit_msg>added comment to show partitions for getNeighbors<commit_after>'use strict';

const nj = require('../bower_components/numjs/dist/numjs')
const _ = require('underscore')

const arrayUtil = require('./array_util')

// https://github.com/numpy/numpy/blob/v1.10.1/numpy/lib/function_base.py#L1116-L1175
function diff(a, n, axis) {
  // default to
  n = n === undefined ? 1 : n
  if (n === 0) {
    return a
  }
  if (n < 0) {
    throw new Error('order must be non-negative but got ' + n)
  }

  let nd = a.shape.length
  let slice1 = _.map(_.range(nd), el => [null])
  let slice2 = _.map(_.range(nd), el => [null])
  // default to last axis
  axis = axis === undefined ? nd - 1 : axis
  slice1[axis] = 1
  slice2[axis] = [null, -1]
  if (n > 1) {
    return diff(a.slice(...slice1).subtract(a.slice(...slice2), n - 1, axis))
  }
  else {
    return a.slice(...slice1).subtract(a.slice(...slice2))
  }
}

function sum(a, axis) {
  if (axis === undefined) {
    return a.flatten().sum()
  }

  const nd = a.shape.length
  const axisLength = a.shape[axis]
  const sliceShape = a.shape.slice()
  sliceShape.splice(axis, 1)

  if (sliceShape.length === 0) {
    // get cumulative sum of array (splice to discard initial 0)
    return nj.array(arrayUtil.scanLeft(0, a.tolist(), (prev, curr) => prev + curr).slice(1))
  }
  else {
    let slice = _.map(_.range(nd), el => [null, null, null])

    let sumSlice = nj.zeros(sliceShape)
    // LOOP INVARIANT: result is the cum sum up to i on the axis
    for (let i = 0; i < axisLength; i++) {
      // slice array at i on the given axis
      slice[axis] = [i, i + 1]
      const row = a.slice(...slice).reshape(...sliceShape)
      sumSlice = sumSlice.add(row)
    }
    return sumSlice
  }
}

// TODO test for array rank > 2
function cumsum(a, axis) {
  if (axis === undefined) {
    return cumsum(a.flatten(), 0)
  }

  const nd = a.shape.length
  const axisLength = a.shape[axis]
  const sliceShape = a.shape.slice()
  sliceShape.splice(axis, 1)

  if (sliceShape.length === 0) {
    // get cumulative sum of array (splice to discard initial 0)
    return nj.array(arrayUtil.scanLeft(0, a.tolist(), (prev, curr) => prev + curr).slice(1))
  }
  else {
    let slice = _.map(_.range(nd), el => [null, null, null])

    const result = []
    let sumSlice = nj.zeros(sliceShape)
    // LOOP INVARIANT: result is the cum sum up to i on the axis
    for (let i = 0; i < axisLength; i++) {
      // slice array at i on the given axis
      slice[axis] = [i, i + 1]
      const row = a.slice(...slice).reshape(...sliceShape)
      sumSlice = sumSlice.add(row)
      // add the sum to the result array
      result.push(sumSlice.tolist())
    }
    const axes = _.range(0, a.shape.length)
    axes[0] = axis
    axes[axis] = 0
    return nj.array(result).transpose(axes)
  }
}

// http://stackoverflow.com/questions/22697936/binary-search-in-javascript
function searchsorted(a, v) {
  let m = 0;
  let n = a.shape[0] - 1
  while (m <= n) {
    const k = (n + m) >> 1
    const cmp = v - a.get(k)
    if (cmp > 0) {
      m = k + 1
    }
    else if (cmp < 0) {
      n = k - 1
    }
    else {
      return k
    }
  }
  return m
}

function vectorize(a, fun) {
  return nj.array(_.map(a.flatten().tolist(), fun)).reshape(...a.shape)
}

// lowerOffset is negative
function getNeighbors(a, r, c, lowerOffset, upperOffset, includeSelf) {
  const clipRow = _.partial(clip, 0, a.shape[0] - 1)
  const clipColumn = _.partial(clip, 0, a.shape[1] - 1)

  if (includeSelf) {
    const rowSlice = [clipRow(r + lowerOffset), clipRow(r + upperOffset) + 1]
    const columnSlice = [clipColumn(c + lowerOffset), clipColumn(c + upperOffset) + 1]
    const neighbors = a.slice(rowSlice, columnSlice).flatten().tolist()
    return nj.array(neighbors)
  }
  else {
    // get slices for upper, left, right, and lower partitions without SELF
    /*  [     UPPER       ]
     *  [LEFT] SELF [RIGHT]
     *  [     LOWER       ]
     */
    const upperRowSlice = [clipRow(r + lowerOffset), r]
    const upperColumnSlice = [clipColumn(c + lowerOffset), clipColumn(c + upperOffset) + 1]

    const leftRowSlice = [r, r + 1]
    const leftColumnSlice = [clipColumn(c + lowerOffset), c]

    const rightRowSlice = [r, r + 1]
    const rightColumnSlice = [c + 1, clipColumn(c + upperOffset) + 1]

    const lowerRowSlice = [r + 1, clipRow(r + upperOffset) + 1]
    const lowerColumnSlice = [clipColumn(c + lowerOffset), clipColumn(c + upperOffset) + 1]

    const rowSlices = [upperRowSlice, leftRowSlice, rightRowSlice, lowerRowSlice]
    const columnSlices = [upperColumnSlice, leftColumnSlice, rightColumnSlice, lowerColumnSlice]

    const neighborGroups = arrayUtil.flatMap(_.zip(rowSlices, columnSlices), ([rowSlice, columnSlice]) => a.slice(rowSlice, columnSlice).flatten().tolist())
    const neighbors = arrayUtil.flatten(neighborGroups)
    return nj.array(neighbors)
  }
}

function sort(a) {
  const arr = a.flatten().tolist()
  arr.sort()
  return nj.array(arr)
}

function percentile(a, q) {
  const sorted = sort(a.flatten())
  const rank = q / 100 * (sorted.shape[0] + 1) - 1
  if (Number.isInteger(rank)) {
    if (sorted.get(rank) === undefined) {
      return null
    }
    else {
      return sorted.get(rank)
    }
  }
  else {
    const IR = Math.floor(rank)
    const FR = rank - IR
    const lower = sorted.get(IR)
    const upper = sorted.get(IR + 1)
    if (lower === undefined && upper === undefined) {
      return null
    }
    else if (lower === undefined) {
      return upper
    }
    else if (upper === undefined) {
      return lower
    }
    else {
      const interpolated = FR * (upper - lower) + lower
      return interpolated
    }
  }
}

const l2Norm = arr => Math.sqrt(vectorize(arr, x => Math.pow(x, 2)).sum())

const distance = (a1, a2) => l2Norm(a1.subtract(a2)) / (l2Norm(a1) + l2Norm(a2))

module.exports = {
  diff,
  sum,
  cumsum,
  searchsorted,
  vectorize,
  getNeighbors,
  sort,
  percentile,
  l2Norm,
  distance
}

function clip(start, end, value) {
  if (value < start) {
    return start
  }
  else if (value > end) {
    return end
  }
  else {
    return value
  }
}

<|endoftext|>


<commit_before><commit_msg>bump version<commit_after><|endoftext|>


<commit_before>// CREDIT: https://github.com/e14n/webfinger

var Step = require("step"),
    dns = require("dns"),
    http = require("http"),
    https = require("https"),
    url = require("url"),
    querystring = require("querystring")
    webfinger = require("webfinger");

var request = function(module, options, parsers, callback) {

    var types = [], prop;

    for (prop in parsers) {
        if (parsers.hasOwnProperty(prop)) {
            types.push(prop);
        }
    }

    var req = module.request(options, function(res) {

        var body = "";

        res.setEncoding('utf8');

        res.on('data', function (chunk) {
            body = body + chunk;
        });

        res.on("error", function(err) {
            callback(err, null);
        });

        res.on("end", function() {

            var ct, matched, parser, newopts;

            if (res.statusCode > 300 && res.statusCode < 400 && res.headers.location) {

                newopts = url.parse(res.headers.location);

                // Don't redirect if it's not allowed

                if (options.httpsOnly && newopts.protocol != "https:") {
                    callback(new Error("Refusing to redirect to non-HTTPS url: " + res.headers.location), null);
                    return;
                }

                newopts.httpsOnly = options.httpsOnly;

                request(((newopts.protocol == "https:") ? https : http), newopts, parsers, callback);
                return;

            } else if (res.statusCode !== 200) {
                callback(new Error("Bad response code: " + res.statusCode + ":" + body), null);
                return;
            }

            if (!res.headers["content-type"]) {
                callback(new Error("No Content-Type header"), null);
                return;
            }

            ct = res.headers["content-type"];

            matched = types.filter(function(type) { return (ct.substr(0, type.length) == type); });

            if (matched.length == 0) {
                callback(new Error("Content-Type '"+ct+"' does not match any expected types: "+types.join(",")), null);
                return;
            }

            parser = parsers[matched];

            parser(body, callback);
        });
    });

    req.on('error', function(err) {
        callback(err, null);
    });

    req.end();
};

var httpsWebfist = function(hostname, resource, rel, callback) {

    var params,
        qs,
        options;

    params = {
        resource: resource
    };

    if (rel) {
        params.rel = rel;
    }

    qs = querystring.stringify(params),

    options = {
        hostname: hostname,
        port: 443,
        path: "/.well-known/webfinger?" + qs,
        method: "GET",
        httpsOnly: true
    };

    request(https, options, {"application/json": webfinger.jrd, "application/jrd+json": webfinger.jrd}, callback);
};

var webfist = function(resource, rel, options, callback) {

    var server;

    // Options parameter is optional

    if (!callback) {
        callback = options;
        options = {};
    }

    // Rel parameter is optional

    if (!callback) {
        callback = rel;
        rel = null;
    }

    // Prefix it with acct: if it looks like a bare webfinger

    if (resource.indexOf(":") === -1) {
        if (resource.indexOf("@") !== -1) {
            resource = "acct:" + resource;
        }
    }

    server = url.parse(options.server || 'http://webfist.org');

    Step(
        function() {
            httpsWebfist(server.hostname, resource, rel, this);
        },
        function(err, jrd) {
            if (!err) {
                // It worked; return the jrd
                callback(null, jrd);
                return;
            }
            if (options.webfingerOnly) {
                throw new Error("Unable to find webfinger");
            }
            lrdd(resource, options, this);
        },
        callback
    );

};

exports.webfist = webfist;
<commit_msg>Fetch delegation link.<commit_after>// CREDIT: https://github.com/e14n/webfinger

var Step = require("step"),
    dns = require("dns"),
    http = require("http"),
    https = require("https"),
    url = require("url"),
    querystring = require("querystring")
    webfinger = require("webfinger");

var request = function(module, options, parsers, callback) {

    var types = [], prop;

    for (prop in parsers) {
        if (parsers.hasOwnProperty(prop)) {
            types.push(prop);
        }
    }

    var req = module.request(options, function(res) {

        var body = "";

        res.setEncoding('utf8');

        res.on('data', function (chunk) {
            body = body + chunk;
        });

        res.on("error", function(err) {
            callback(err, null);
        });

        res.on("end", function() {

            var ct, matched, parser, newopts;

            if (res.statusCode > 300 && res.statusCode < 400 && res.headers.location) {

                newopts = url.parse(res.headers.location);

                // Don't redirect if it's not allowed

                if (options.httpsOnly && newopts.protocol != "https:") {
                    callback(new Error("Refusing to redirect to non-HTTPS url: " + res.headers.location), null);
                    return;
                }

                newopts.httpsOnly = options.httpsOnly;

                request(((newopts.protocol == "https:") ? https : http), newopts, parsers, callback);
                return;

            } else if (res.statusCode !== 200) {
                callback(new Error("Bad response code: " + res.statusCode + ":" + body), null);
                return;
            }

            if (!res.headers["content-type"]) {
                callback(new Error("No Content-Type header"), null);
                return;
            }

            ct = res.headers["content-type"];

            matched = types.filter(function(type) { return (ct.substr(0, type.length) == type); });

            if (matched.length == 0) {
                callback(new Error("Content-Type '"+ct+"' does not match any expected types: "+types.join(",")), null);
                return;
            }

            parser = parsers[matched];

            parser(body, callback);
        });
    });

    req.on('error', function(err) {
        callback(err, null);
    });

    req.end();
};

var lookup = function(server, resource, rel, httpsOnly, callback) {

    var parsed,
        params,
        qs,
        options;

    parsed = url.parse(server);

    if ((parsed.protocol !== "https:") && httpsOnly) {
        callback(new Error("Refusing to use insecure WebFist server: " + server), null);
    }

    params = {
        resource: resource
    };

    if (rel) {
        params.rel = rel;
    }

    qs = querystring.stringify(params),

    options = {
        hostname: parsed.hostname,
        port: parsed.port,
        path: "/.well-known/webfinger?" + qs,
        method: "GET",
        httpsOnly: httpsOnly
    };

    request(((parsed.protocol == "https:") ? https : http), options, {"application/json": webfinger.jrd, "application/jrd+json": webfinger.jrd}, callback);
};

var webfist = function(resource, rel, options, callback) {

    // Options parameter is optional

    if (!callback) {
        callback = options;
        options = {};
    }

    // Rel parameter is optional

    if (!callback) {
        callback = rel;
        rel = null;
    }

    // Prefix it with acct: if it looks like a bare webfinger

    if (resource.indexOf(":") === -1) {
        if (resource.indexOf("@") !== -1) {
            resource = "acct:" + resource;
        }
    }

    Step(
        function() {
            lookup(options.server || 'http://webfist.org/', resource, rel, options.httpsOnly, this);
        },
        function(err, jrd) {
            var delegations, newopts;
            if (err) throw err;
            if (!jrd.hasOwnProperty("links")) {
                throw new Error("No links in WebFist JRD");
            }

            // First, get the WebFist delegation links
            delegations = jrd.links.filter(function(link) {
                return (link.hasOwnProperty("rel") &&
                        link.rel == "http://webfist.org/spec/rel" &&
                        link.hasOwnProperty("href"));
            });

            if (!delegations || delegations.length === 0) {
                throw new Error("No delegation links in WebFist JRD");
            }

            // Fetch the real resource descriptor
            newopts = url.parse(delegations[0].href);

            if ((newopts.protocol !== "https:") && options.httpsOnly) {
                callback(new Error("Refusing to fetch non-HTTPS delegation: " + delegations[0].href), null);
            }

            newopts.httpsOnly = options.httpsOnly;

            request(((newopts.protocol == "https:") ? https : http), newopts, {"application/json": webfinger.jrd, "application/jrd+json": webfinger.jrd}, this);
        },
        callback
    );
};

exports.webfist = webfist;
<|endoftext|>


<commit_before>import {ZERO_POINT, compare, traverse} from './point-helpers'

export default class LineIterator {
  constructor (tree) {
    this.tree = tree
  }

  reset () {
    this.leftAncestor = null
    this.leftAncestorRow = -1
    this.leftAncestorBufferEnd = ZERO_POINT
    this.leftAncestorStack = []
    this.leftAncestorRowStack = [-1]
    this.leftAncestorBufferEndStack = [ZERO_POINT]
    this.currentScreenRow = -1
    this.setCurrentNode(this.tree.root)
  }

  findNode (row) {
    this.reset()

    if (!this.currentNode) return null

    while (true) {
      if (row < this.currentScreenRow) {
        if (this.currentNode.left) {
          this.descendLeft()
        } else {
          return null
        }
      } else if (row === this.currentScreenRow) {
        return this.currentNode
      } else { // row > this.currentScreenRow
        if (this.currentNode.right) {
          this.descendRight()
        } else {
          return null
        }
      }
    }
  }

  seekToScreenPosition (targetPosition) {
    this.findNode(targetPosition.row)
  }

  seekToBufferPosition (targetPosition) {
    this.reset()

    if (!this.currentNode) return null

    while (true) {
      if (compare(targetPosition, this.currentLineBufferStart) <= 0) {
        if (this.currentNode.left) {
          this.descendLeft()
        } else {
          break
        }
      } else {
        if (compare(targetPosition, this.currentLineBufferEnd) <= 0) {
          break
        } else if (this.currentNode.right) {
          this.descendRight()
        } else {
          break
        }
      }
    }
  }

  moveToSuccessor () {
    if (!this.currentNode) return false

    if (this.currentNode.right) {
      this.descendRight()
      while (this.currentNode.left) {
        this.descendLeft()
      }
      return true
    } else {
      while (this.currentNode.parent && this.currentNode.parent.right === this.currentNode) {
        this.ascend()
      }
      this.ascend()

      return this.currentNode != null
    }
  }

  getScreenRow () {
    return this.currentScreenRow
  }

  getScreenLineLength () {
    return this.currentNode.screenExtent
  }

  getBufferStart () {
    return this.currentLineBufferStart
  }

  getBufferEnd () {
    return this.currentLineBufferEnd
  }

  getTokens (node) {
    return this.currentNode ? this.currentNode.tokens : null
  }

  getScreenPositionWithMaxLineLength () {
    this.reset()

    if (!this.currentNode) return null

    let maxScreenExtent = this.currentNode.maxScreenExtent
    while (true) {
      if (this.currentNode.screenExtent === maxScreenExtent) {
        return {row: this.currentScreenRow, column: maxScreenExtent}
      } else if (this.currentNode.left && this.currentNode.left.maxScreenExtent === maxScreenExtent) {
        this.descendLeft()
      } else {
        this.descendRight()
      }
    }
  }

  setCurrentNode (node) {
    this.currentNode = node
    if (this.currentNode) {
      this.currentScreenRow = this.leftAncestorRow + this.currentNode.getLeftSubtreeRowCount() + 1
      this.currentLineBufferStart = traverse(this.leftAncestorBufferEnd, this.currentNode.getLeftSubtreeBufferExtent())
      this.currentLineBufferEnd = traverse(this.currentLineBufferStart, this.currentNode.bufferExtent)
    }
  }

  descendLeft () {
    this.pushToAncestorStacks()
    this.setCurrentNode(this.currentNode.left)
  }

  descendRight () {
    this.pushToAncestorStacks()
    this.leftAncestor = this.currentNode
    this.leftAncestorRow = this.currentScreenRow
    this.leftAncestorBufferEnd = this.currentLineBufferEnd
    this.setCurrentNode(this.currentNode.right)
  }

  ascend () {
    this.leftAncestor = this.leftAncestorStack.pop()
    this.leftAncestorRow = this.leftAncestorRowStack.pop()
    this.leftAncestorBufferEnd = this.leftAncestorBufferEndStack.pop()
    this.setCurrentNode(this.currentNode.parent)
  }

  pushToAncestorStacks () {
    this.leftAncestorStack.push(this.leftAncestor)
    this.leftAncestorRowStack.push(this.leftAncestorRow)
    this.leftAncestorBufferEndStack.push(this.leftAncestorBufferEnd)
  }
}
<commit_msg>Initialize LineIterator to an empty line when index is empty<commit_after>import {ZERO_POINT, compare, traverse} from './point-helpers'

export default class LineIterator {
  constructor (tree) {
    this.tree = tree
  }

  reset () {
    this.leftAncestor = null
    this.leftAncestorRow = -1
    this.leftAncestorBufferEnd = ZERO_POINT
    this.leftAncestorStack = []
    this.leftAncestorRowStack = [-1]
    this.leftAncestorBufferEndStack = [ZERO_POINT]
    this.currentScreenRow = 0
    this.currentLineBufferStart = ZERO_POINT
    this.currentLineBufferEnd = ZERO_POINT
    this.setCurrentNode(this.tree.root)
  }

  findNode (row) {
    this.reset()

    if (!this.currentNode) return null

    while (true) {
      if (row < this.currentScreenRow) {
        if (this.currentNode.left) {
          this.descendLeft()
        } else {
          return null
        }
      } else if (row === this.currentScreenRow) {
        return this.currentNode
      } else { // row > this.currentScreenRow
        if (this.currentNode.right) {
          this.descendRight()
        } else {
          return null
        }
      }
    }
  }

  seekToScreenPosition (targetPosition) {
    this.findNode(targetPosition.row)
  }

  seekToBufferPosition (targetPosition) {
    this.reset()

    if (!this.currentNode) return null

    while (true) {
      if (compare(targetPosition, this.currentLineBufferStart) <= 0) {
        if (this.currentNode.left) {
          this.descendLeft()
        } else {
          break
        }
      } else {
        if (compare(targetPosition, this.currentLineBufferEnd) <= 0) {
          break
        } else if (this.currentNode.right) {
          this.descendRight()
        } else {
          break
        }
      }
    }
  }

  moveToSuccessor () {
    if (!this.currentNode) return false

    if (this.currentNode.right) {
      this.descendRight()
      while (this.currentNode.left) {
        this.descendLeft()
      }
      return true
    } else {
      while (this.currentNode.parent && this.currentNode.parent.right === this.currentNode) {
        this.ascend()
      }
      this.ascend()

      return this.currentNode != null
    }
  }

  getScreenRow () {
    return this.currentScreenRow
  }

  getScreenLineLength () {
    return this.currentNode.screenExtent
  }

  getBufferStart () {
    return this.currentLineBufferStart
  }

  getBufferEnd () {
    return this.currentLineBufferEnd
  }

  getTokens (node) {
    return this.currentNode ? this.currentNode.tokens : null
  }

  getScreenPositionWithMaxLineLength () {
    this.reset()

    if (!this.currentNode) return null

    let maxScreenExtent = this.currentNode.maxScreenExtent
    while (true) {
      if (this.currentNode.screenExtent === maxScreenExtent) {
        return {row: this.currentScreenRow, column: maxScreenExtent}
      } else if (this.currentNode.left && this.currentNode.left.maxScreenExtent === maxScreenExtent) {
        this.descendLeft()
      } else {
        this.descendRight()
      }
    }
  }

  setCurrentNode (node) {
    this.currentNode = node
    if (this.currentNode) {
      this.currentScreenRow = this.leftAncestorRow + this.currentNode.getLeftSubtreeRowCount() + 1
      this.currentLineBufferStart = traverse(this.leftAncestorBufferEnd, this.currentNode.getLeftSubtreeBufferExtent())
      this.currentLineBufferEnd = traverse(this.currentLineBufferStart, this.currentNode.bufferExtent)
    }
  }

  descendLeft () {
    this.pushToAncestorStacks()
    this.setCurrentNode(this.currentNode.left)
  }

  descendRight () {
    this.pushToAncestorStacks()
    this.leftAncestor = this.currentNode
    this.leftAncestorRow = this.currentScreenRow
    this.leftAncestorBufferEnd = this.currentLineBufferEnd
    this.setCurrentNode(this.currentNode.right)
  }

  ascend () {
    this.leftAncestor = this.leftAncestorStack.pop()
    this.leftAncestorRow = this.leftAncestorRowStack.pop()
    this.leftAncestorBufferEnd = this.leftAncestorBufferEndStack.pop()
    this.setCurrentNode(this.currentNode.parent)
  }

  pushToAncestorStacks () {
    this.leftAncestorStack.push(this.leftAncestor)
    this.leftAncestorRowStack.push(this.leftAncestorRow)
    this.leftAncestorBufferEndStack.push(this.leftAncestorBufferEnd)
  }
}
<|endoftext|>


<commit_before>import PropTypes from 'prop-types';
import React from 'react';
import {
  View,
  StyleSheet,
  TouchableHighlight,
  TouchableOpacity,
  Platform,
  Switch,
  TextInput,
} from 'react-native';
import Avatar from '../avatar/Avatar';
import Badge from '../badge/badge';
import Icon from '../icons/Icon';
import Text from '../text/Text';
import colors from '../config/colors';
import fonts from '../config/fonts';
import normalize from '../helpers/normalizeText';
import ViewPropTypes from '../config/ViewPropTypes';

const ListItem = props => {
  const {
    onPress,
    title,
    leftIcon,
    rightIcon,
    leftIconOnPress,
    leftIconOnLongPress,
    leftIconUnderlayColor,
    leftIconContainerStyle,
    avatarStyle,
    avatarContainerStyle,
    avatarOverlayContainerStyle,
    underlayColor,
    subtitle,
    subtitleStyle,
    containerStyle,
    wrapperStyle,
    titleNumberOfLines,
    titleStyle,
    titleContainerStyle,
    hideChevron,
    chevronColor,
    roundAvatar,
    component,
    fontFamily,
    rightTitle,
    rightTitleContainerStyle,
    rightTitleStyle,
    rightTitleNumberOfLines,
    subtitleContainerStyle,
    subtitleNumberOfLines,
    badge,
    label,
    onLongPress,
    switchButton,
    onSwitch,
    switchDisabled,
    switchOnTintColor,
    switchThumbTintColor,
    switchTintColor,
    switched,
    textInput,
    textInputAutoCapitalize,
    textInputAutoCorrect,
    textInputAutoFocus,
    textInputEditable,
    textInputKeyboardType,
    textInputMaxLength,
    textInputMultiline,
    textInputOnChangeText,
    textInputOnFocus,
    textInputOnBlur,
    textInputSelectTextOnFocus,
    textInputReturnKeyType,
    textInputValue,
    textInputSecure,
    textInputStyle,
    textInputContainerStyle,
    onPressRightIcon,
    ...attributes
  } = props;

  let { avatar } = props;

  let Component = onPress || onLongPress ? TouchableHighlight : View;
  let LeftIconWrapper =
    leftIconOnPress || leftIconOnLongPress ? TouchableHighlight : View;
  if (component) {
    Component = component;
  }
  if (typeof avatar === 'string') {
    avatar = { uri: avatar };
  }
  return (
    <Component
      onLongPress={onLongPress}
      onPress={onPress}
      underlayColor={underlayColor}
      style={[styles.container, containerStyle && containerStyle]}
      {...attributes}
    >
      <View style={[styles.wrapper, wrapperStyle && wrapperStyle]}>
        {React.isValidElement(leftIcon)
          ? leftIcon
          : leftIcon &&
            leftIcon.name &&
            <LeftIconWrapper
              onLongPress={leftIconOnLongPress}
              onPress={leftIconOnPress}
              underlayColor={leftIconUnderlayColor}
              style={[
                styles.iconStyle,
                { flex: rightTitle && rightTitle !== '' ? 0.3 : 0.15 },
                leftIconContainerStyle && leftIconContainerStyle,
              ]}
            >
              <View>
                <Icon
                  type={leftIcon.type}
                  iconStyle={[styles.icon, leftIcon.style && leftIcon.style]}
                  name={leftIcon.name}
                  color={leftIcon.color || colors.grey4}
                  size={leftIcon.size || 24}
                />
              </View>
            </LeftIconWrapper>}
        {avatar &&
          <View style={styles.avatar}>
            {React.isValidElement(avatar)
              ? avatar
              : <Avatar
                  avatarStyle={avatarStyle && avatarStyle}
                  containerStyle={avatarContainerStyle && avatarContainerStyle}
                  overlayContainerStyle={
                    avatarOverlayContainerStyle && avatarOverlayContainerStyle
                  }
                  rounded={roundAvatar}
                  source={avatar}
                />}
          </View>}
        <View style={styles.titleSubtitleContainer}>
          <View style={titleContainerStyle}>
            {title && (typeof title === 'string' || typeof title === 'number')
              ? <Text
                  numberOfLines={titleNumberOfLines}
                  style={[
                    styles.title,
                    !leftIcon && { marginLeft: 10 },
                    titleStyle && titleStyle,
                    fontFamily && { fontFamily },
                  ]}
                >
                  {title}
                </Text>
              : <View>
                  {title}
                </View>}
          </View>
          <View style={subtitleContainerStyle}>
            {subtitle &&
            (typeof subtitle === 'string' || typeof subtitle === 'number')
              ? <Text
                  numberOfLines={subtitleNumberOfLines}
                  style={[
                    styles.subtitle,
                    !leftIcon && { marginLeft: 10 },
                    subtitleStyle && subtitleStyle,
                    fontFamily && { fontFamily },
                  ]}
                >
                  {subtitle}
                </Text>
              : <View>
                  {subtitle}
                </View>}
          </View>
        </View>
        {rightTitle &&
          rightTitle !== '' &&
          !textInput &&
          <View style={[styles.rightTitleContainer, rightTitleContainerStyle]}>
            <Text
              numberOfLines={rightTitleNumberOfLines}
              style={[styles.rightTitleStyle, rightTitleStyle]}
            >
              {rightTitle}
            </Text>
          </View>}
        {textInput &&
          <View style={[styles.rightTitleContainer, textInputContainerStyle]}>
            <TextInput
              style={[styles.textInputStyle, textInputStyle]}
              defaultValue={rightTitle}
              value={textInputValue}
              autoCapitalize={textInputAutoCapitalize}
              autoCorrect={textInputAutoCorrect}
              autoFocus={textInputAutoFocus}
              editable={textInputEditable}
              keyboardType={textInputKeyboardType}
              maxLength={textInputMaxLength}
              multiline={textInputMultiline}
              onChangeText={textInputOnChangeText}
              onFocus={textInputOnFocus}
              onBlur={textInputOnBlur}
              secureTextEntry={textInputSecure}
              selectTextOnFocus={textInputSelectTextOnFocus}
              returnKeyType={textInputReturnKeyType}
            />
          </View>}
        {badge && !rightTitle && <Badge {...badge} />}
        {!hideChevron &&
          (React.isValidElement(rightIcon)
            ? rightIcon
            : <TouchableOpacity
                onPress={onPressRightIcon}
                disabled={!onPressRightIcon}
                style={styles.chevronContainer}
              >
                <Icon
                  type={rightIcon.type}
                  iconStyle={rightIcon.style}
                  size={28}
                  name={rightIcon.name || 'chevron-right'}
                  color={rightIcon.color || chevronColor}
                />
              </TouchableOpacity>)}
        {switchButton &&
          hideChevron &&
          <View style={styles.switchContainer}>
            <Switch
              onValueChange={onSwitch}
              disabled={switchDisabled}
              onTintColor={switchOnTintColor}
              thumbTintColor={switchThumbTintColor}
              tintColor={switchTintColor}
              value={switched}
            />
          </View>}
        {label && label}
      </View>
    </Component>
  );
};

ListItem.defaultProps = {
  underlayColor: 'white',
  leftIconUnderlayColor: 'white',
  chevronColor: colors.grey4,
  rightIcon: { name: 'chevron-right' },
  hideChevron: false,
  roundAvatar: false,
  switchButton: false,
  textInputEditable: true,
  titleNumberOfLines: 1,
  subtitleNumberOfLines: 1,
  rightTitleNumberOfLines: 1,
};

ListItem.propTypes = {
  title: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.object,
  ]),
  avatar: PropTypes.any,
  icon: PropTypes.any,
  onPress: PropTypes.func,
  rightIcon: PropTypes.oneOfType([PropTypes.element, PropTypes.object]),
  underlayColor: PropTypes.string,
  subtitle: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.object,
  ]),
  subtitleStyle: PropTypes.any,
  subtitleNumberOfLines: PropTypes.number,
  containerStyle: PropTypes.any,
  wrapperStyle: PropTypes.any,
  titleStyle: PropTypes.any,
  titleContainerStyle: PropTypes.any,
  titleNumberOfLines: PropTypes.number,
  hideChevron: PropTypes.bool,
  chevronColor: PropTypes.string,
  roundAvatar: PropTypes.bool,
  badge: PropTypes.any,
  switchButton: PropTypes.bool,
  onSwitch: PropTypes.func,
  switchDisabled: PropTypes.bool,
  switchOnTintColor: PropTypes.string,
  switchThumbTintColor: PropTypes.string,
  switchTintColor: PropTypes.string,
  switched: PropTypes.bool,
  textInput: PropTypes.bool,
  textInputAutoCapitalize: PropTypes.bool,
  textInputAutoCorrect: PropTypes.bool,
  textInputAutoFocus: PropTypes.bool,
  textInputEditable: PropTypes.bool,
  textInputKeyboardType: PropTypes.oneOf([
    'default',
    'email-address',
    'numeric',
    'phone-pad',
    'ascii-capable',
    'numbers-and-punctuation',
    'url',
    'number-pad',
    'name-phone-pad',
    'decimal-pad',
    'twitter',
    'web-search',
  ]),
  textInputMaxLength: PropTypes.number,
  textInputMultiline: PropTypes.bool,
  textInputOnChangeText: PropTypes.func,
  textInputOnFocus: PropTypes.func,
  textInputOnBlur: PropTypes.func,
  textInputSelectTextOnFocus: PropTypes.bool,
  textInputReturnKeyType: PropTypes.string,
  textInputValue: PropTypes.string,
  textInputSecure: PropTypes.bool,
  textInputStyle: PropTypes.any,
  textInputContainerStyle: PropTypes.any,
  component: PropTypes.any,
  fontFamily: PropTypes.string,
  rightTitle: PropTypes.string,
  rightTitleContainerStyle: ViewPropTypes.style,
  rightTitleStyle: Text.propTypes.style,
  rightTitleNumberOfLines: PropTypes.number,
  subtitleContainerStyle: ViewPropTypes.style,
  label: PropTypes.any,
  onLongPress: PropTypes.func,
  leftIcon: PropTypes.oneOfType([PropTypes.element, PropTypes.object]),
  leftIconOnPress: PropTypes.func,
  leftIconOnLongPress: PropTypes.func,
  leftIconUnderlayColor: PropTypes.string,
  leftIconContainerStyle: ViewPropTypes.style,
  avatarStyle: ViewPropTypes.style,
  avatarContainerStyle: ViewPropTypes.style,
  avatarOverlayContainerStyle: ViewPropTypes.style,
  onPressRightIcon: PropTypes.func,
};

const styles = StyleSheet.create({
  avatar: {
    width: 34,
    height: 34,
  },
  container: {
    paddingTop: 10,
    paddingRight: 10,
    paddingBottom: 10,
    borderBottomColor: colors.greyOutline,
    borderBottomWidth: 1,
    backgroundColor: 'transparent',
  },
  wrapper: {
    flexDirection: 'row',
    marginLeft: 10,
  },
  iconStyle: {
    justifyContent: 'center',
    alignItems: 'center',
  },
  icon: {
    marginRight: 8,
  },
  title: {
    fontSize: normalize(14),
    color: colors.grey1,
  },
  subtitle: {
    color: colors.grey3,
    fontSize: normalize(12),
    marginTop: 1,
    ...Platform.select({
      ios: {
        fontWeight: '600',
      },
      android: {
        ...fonts.android.bold,
      },
    }),
  },
  titleSubtitleContainer: {
    justifyContent: 'center',
    flex: 1,
  },
  chevronContainer: {
    flex: 0.15,
    alignItems: 'flex-end',
    justifyContent: 'center',
  },
  switchContainer: {
    flex: 0.15,
    alignItems: 'flex-end',
    justifyContent: 'center',
    marginRight: 5,
  },
  rightTitleContainer: {
    flex: 1,
    alignItems: 'flex-end',
    justifyContent: 'center',
  },
  rightTitleStyle: {
    marginRight: 5,
    color: colors.grey4,
  },
  textInputStyle: {
    height: 20,
    textAlign: 'right',
  },
});

export default ListItem;
<commit_msg>Don't throw error if ListItem title, subtitle is empty string. Fixes #431<commit_after>import PropTypes from 'prop-types';
import React from 'react';
import {
  View,
  StyleSheet,
  TouchableHighlight,
  TouchableOpacity,
  Platform,
  Switch,
  TextInput,
} from 'react-native';
import Avatar from '../avatar/Avatar';
import Badge from '../badge/badge';
import Icon from '../icons/Icon';
import Text from '../text/Text';
import colors from '../config/colors';
import fonts from '../config/fonts';
import normalize from '../helpers/normalizeText';
import ViewPropTypes from '../config/ViewPropTypes';

const ListItem = props => {
  const {
    onPress,
    title,
    leftIcon,
    rightIcon,
    leftIconOnPress,
    leftIconOnLongPress,
    leftIconUnderlayColor,
    leftIconContainerStyle,
    avatarStyle,
    avatarContainerStyle,
    avatarOverlayContainerStyle,
    underlayColor,
    subtitle,
    subtitleStyle,
    containerStyle,
    wrapperStyle,
    titleNumberOfLines,
    titleStyle,
    titleContainerStyle,
    hideChevron,
    chevronColor,
    roundAvatar,
    component,
    fontFamily,
    rightTitle,
    rightTitleContainerStyle,
    rightTitleStyle,
    rightTitleNumberOfLines,
    subtitleContainerStyle,
    subtitleNumberOfLines,
    badge,
    label,
    onLongPress,
    switchButton,
    onSwitch,
    switchDisabled,
    switchOnTintColor,
    switchThumbTintColor,
    switchTintColor,
    switched,
    textInput,
    textInputAutoCapitalize,
    textInputAutoCorrect,
    textInputAutoFocus,
    textInputEditable,
    textInputKeyboardType,
    textInputMaxLength,
    textInputMultiline,
    textInputOnChangeText,
    textInputOnFocus,
    textInputOnBlur,
    textInputSelectTextOnFocus,
    textInputReturnKeyType,
    textInputValue,
    textInputSecure,
    textInputStyle,
    textInputContainerStyle,
    onPressRightIcon,
    ...attributes
  } = props;

  let { avatar } = props;

  let Component = onPress || onLongPress ? TouchableHighlight : View;
  let LeftIconWrapper = leftIconOnPress || leftIconOnLongPress
    ? TouchableHighlight
    : View;
  if (component) {
    Component = component;
  }
  if (typeof avatar === 'string') {
    avatar = { uri: avatar };
  }
  return (
    <Component
      onLongPress={onLongPress}
      onPress={onPress}
      underlayColor={underlayColor}
      style={[styles.container, containerStyle && containerStyle]}
      {...attributes}
    >
      <View style={[styles.wrapper, wrapperStyle && wrapperStyle]}>
        {React.isValidElement(leftIcon)
          ? leftIcon
          : leftIcon &&
              leftIcon.name &&
              <LeftIconWrapper
                onLongPress={leftIconOnLongPress}
                onPress={leftIconOnPress}
                underlayColor={leftIconUnderlayColor}
                style={[
                  styles.iconStyle,
                  { flex: rightTitle && rightTitle !== '' ? 0.3 : 0.15 },
                  leftIconContainerStyle && leftIconContainerStyle,
                ]}
              >
                <View>
                  <Icon
                    type={leftIcon.type}
                    iconStyle={[styles.icon, leftIcon.style && leftIcon.style]}
                    name={leftIcon.name}
                    color={leftIcon.color || colors.grey4}
                    size={leftIcon.size || 24}
                  />
                </View>
              </LeftIconWrapper>}
        {avatar &&
          <View style={styles.avatar}>
            {React.isValidElement(avatar)
              ? avatar
              : <Avatar
                  avatarStyle={avatarStyle && avatarStyle}
                  containerStyle={avatarContainerStyle && avatarContainerStyle}
                  overlayContainerStyle={
                    avatarOverlayContainerStyle && avatarOverlayContainerStyle
                  }
                  rounded={roundAvatar}
                  source={avatar}
                />}
          </View>}
        <View style={styles.titleSubtitleContainer}>
          <View style={titleContainerStyle}>
            {title !== null &&
              (typeof title === 'string' || typeof title === 'number')
              ? <Text
                  numberOfLines={titleNumberOfLines}
                  style={[
                    styles.title,
                    !leftIcon && { marginLeft: 10 },
                    titleStyle && titleStyle,
                    fontFamily && { fontFamily },
                  ]}
                >
                  {title}
                </Text>
              : <View>
                  {title}
                </View>}
          </View>
          <View style={subtitleContainerStyle}>
            {subtitle !== null &&
              (typeof subtitle === 'string' || typeof subtitle === 'number')
              ? <Text
                  numberOfLines={subtitleNumberOfLines}
                  style={[
                    styles.subtitle,
                    !leftIcon && { marginLeft: 10 },
                    subtitleStyle && subtitleStyle,
                    fontFamily && { fontFamily },
                  ]}
                >
                  {subtitle}
                </Text>
              : <View>
                  {subtitle}
                </View>}
          </View>
        </View>
        {rightTitle &&
          rightTitle !== '' &&
          !textInput &&
          <View style={[styles.rightTitleContainer, rightTitleContainerStyle]}>
            <Text
              numberOfLines={rightTitleNumberOfLines}
              style={[styles.rightTitleStyle, rightTitleStyle]}
            >
              {rightTitle}
            </Text>
          </View>}
        {textInput &&
          <View style={[styles.rightTitleContainer, textInputContainerStyle]}>
            <TextInput
              style={[styles.textInputStyle, textInputStyle]}
              defaultValue={rightTitle}
              value={textInputValue}
              autoCapitalize={textInputAutoCapitalize}
              autoCorrect={textInputAutoCorrect}
              autoFocus={textInputAutoFocus}
              editable={textInputEditable}
              keyboardType={textInputKeyboardType}
              maxLength={textInputMaxLength}
              multiline={textInputMultiline}
              onChangeText={textInputOnChangeText}
              onFocus={textInputOnFocus}
              onBlur={textInputOnBlur}
              secureTextEntry={textInputSecure}
              selectTextOnFocus={textInputSelectTextOnFocus}
              returnKeyType={textInputReturnKeyType}
            />
          </View>}
        {badge && !rightTitle && <Badge {...badge} />}
        {!hideChevron &&
          (React.isValidElement(rightIcon)
            ? rightIcon
            : <TouchableOpacity
                onPress={onPressRightIcon}
                disabled={!onPressRightIcon}
                style={styles.chevronContainer}
              >
                <Icon
                  type={rightIcon.type}
                  iconStyle={rightIcon.style}
                  size={28}
                  name={rightIcon.name || 'chevron-right'}
                  color={rightIcon.color || chevronColor}
                />
              </TouchableOpacity>)}
        {switchButton &&
          hideChevron &&
          <View style={styles.switchContainer}>
            <Switch
              onValueChange={onSwitch}
              disabled={switchDisabled}
              onTintColor={switchOnTintColor}
              thumbTintColor={switchThumbTintColor}
              tintColor={switchTintColor}
              value={switched}
            />
          </View>}
        {label && label}
      </View>
    </Component>
  );
};

ListItem.defaultProps = {
  underlayColor: 'white',
  leftIconUnderlayColor: 'white',
  chevronColor: colors.grey4,
  rightIcon: { name: 'chevron-right' },
  hideChevron: false,
  roundAvatar: false,
  switchButton: false,
  textInputEditable: true,
  titleNumberOfLines: 1,
  subtitleNumberOfLines: 1,
  rightTitleNumberOfLines: 1,
};

ListItem.propTypes = {
  title: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.object,
  ]),
  avatar: PropTypes.any,
  icon: PropTypes.any,
  onPress: PropTypes.func,
  rightIcon: PropTypes.oneOfType([PropTypes.element, PropTypes.object]),
  underlayColor: PropTypes.string,
  subtitle: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.object,
  ]),
  subtitleStyle: PropTypes.any,
  subtitleNumberOfLines: PropTypes.number,
  containerStyle: PropTypes.any,
  wrapperStyle: PropTypes.any,
  titleStyle: PropTypes.any,
  titleContainerStyle: PropTypes.any,
  titleNumberOfLines: PropTypes.number,
  hideChevron: PropTypes.bool,
  chevronColor: PropTypes.string,
  roundAvatar: PropTypes.bool,
  badge: PropTypes.any,
  switchButton: PropTypes.bool,
  onSwitch: PropTypes.func,
  switchDisabled: PropTypes.bool,
  switchOnTintColor: PropTypes.string,
  switchThumbTintColor: PropTypes.string,
  switchTintColor: PropTypes.string,
  switched: PropTypes.bool,
  textInput: PropTypes.bool,
  textInputAutoCapitalize: PropTypes.bool,
  textInputAutoCorrect: PropTypes.bool,
  textInputAutoFocus: PropTypes.bool,
  textInputEditable: PropTypes.bool,
  textInputKeyboardType: PropTypes.oneOf([
    'default',
    'email-address',
    'numeric',
    'phone-pad',
    'ascii-capable',
    'numbers-and-punctuation',
    'url',
    'number-pad',
    'name-phone-pad',
    'decimal-pad',
    'twitter',
    'web-search',
  ]),
  textInputMaxLength: PropTypes.number,
  textInputMultiline: PropTypes.bool,
  textInputOnChangeText: PropTypes.func,
  textInputOnFocus: PropTypes.func,
  textInputOnBlur: PropTypes.func,
  textInputSelectTextOnFocus: PropTypes.bool,
  textInputReturnKeyType: PropTypes.string,
  textInputValue: PropTypes.string,
  textInputSecure: PropTypes.bool,
  textInputStyle: PropTypes.any,
  textInputContainerStyle: PropTypes.any,
  component: PropTypes.any,
  fontFamily: PropTypes.string,
  rightTitle: PropTypes.string,
  rightTitleContainerStyle: ViewPropTypes.style,
  rightTitleStyle: Text.propTypes.style,
  rightTitleNumberOfLines: PropTypes.number,
  subtitleContainerStyle: ViewPropTypes.style,
  label: PropTypes.any,
  onLongPress: PropTypes.func,
  leftIcon: PropTypes.oneOfType([PropTypes.element, PropTypes.object]),
  leftIconOnPress: PropTypes.func,
  leftIconOnLongPress: PropTypes.func,
  leftIconUnderlayColor: PropTypes.string,
  leftIconContainerStyle: ViewPropTypes.style,
  avatarStyle: ViewPropTypes.style,
  avatarContainerStyle: ViewPropTypes.style,
  avatarOverlayContainerStyle: ViewPropTypes.style,
  onPressRightIcon: PropTypes.func,
};

const styles = StyleSheet.create({
  avatar: {
    width: 34,
    height: 34,
  },
  container: {
    paddingTop: 10,
    paddingRight: 10,
    paddingBottom: 10,
    borderBottomColor: colors.greyOutline,
    borderBottomWidth: 1,
    backgroundColor: 'transparent',
  },
  wrapper: {
    flexDirection: 'row',
    marginLeft: 10,
  },
  iconStyle: {
    justifyContent: 'center',
    alignItems: 'center',
  },
  icon: {
    marginRight: 8,
  },
  title: {
    fontSize: normalize(14),
    color: colors.grey1,
  },
  subtitle: {
    color: colors.grey3,
    fontSize: normalize(12),
    marginTop: 1,
    ...Platform.select({
      ios: {
        fontWeight: '600',
      },
      android: {
        ...fonts.android.bold,
      },
    }),
  },
  titleSubtitleContainer: {
    justifyContent: 'center',
    flex: 1,
  },
  chevronContainer: {
    flex: 0.15,
    alignItems: 'flex-end',
    justifyContent: 'center',
  },
  switchContainer: {
    flex: 0.15,
    alignItems: 'flex-end',
    justifyContent: 'center',
    marginRight: 5,
  },
  rightTitleContainer: {
    flex: 1,
    alignItems: 'flex-end',
    justifyContent: 'center',
  },
  rightTitleStyle: {
    marginRight: 5,
    color: colors.grey4,
  },
  textInputStyle: {
    height: 20,
    textAlign: 'right',
  },
});

export default ListItem;
<|endoftext|>