<commit_before>/**
 * Base class for creating other shapes.
 * Each custom shape must extends from this class.
 *
 * @since 1.0.0
 * @version 1.0.0
 * @example
 * import Shape from 'kittik-shape-basic';
 *
 * export default class Rectangle extends Shape {
 *   render(cursor) {
 *     // Implement your logic here for rendering the shape
 *   }
 * }
 */
export default class Shape {
  /**
   * @constructor
   * @param {Object} [options]
   * @param {String} [options.text] Text that will be rendered in the shape
   * @param {Number} [options.width] Shape width
   * @param {Number} [options.height] Shape height
   * @param {Number} [options.x] Absolute coordinate X
   * @param {Number} [options.y] Absolute coordinate Y
   * @param {String} [options.background] Background color from {@link COLORS}
   * @param {String} [options.foreground] Foreground color from {@link COLORS}
   * @param {String} [options.align] Set if shape is need to be aligned
   * @param {Object} [options.animation] Animation options for this shape
   */
  constructor(options = {}) {
    this._options = options;

    this.setText(options.text);
    this.setWidth(options.width);
    this.setHeight(options.height);
    this.setPosition(options.x, options.y);
    this.setAlign(options.align);
    this.setBackground(options.background);
    this.setForeground(options.foreground);
    this.setAnimation(options.animation);
  }

  /**
   * Get option value.
   *
   * @param {String} path Path can be set with dot-notation
   * @returns {*}
   */
  get(path) {
    return path.split('.').reduce((obj, key) => obj[key], this._options);
  }

  /**
   * Set new option value.
   *
   * @param {String} path Path can be set with dot-notation
   * @param {*} value Value that need to be written to the options object
   * @returns {Shape}
   */
  set(path, value) {
    let obj = this._options;
    let tags = path.split('.');
    let len = tags.length - 1;

    for (let i = 0; i < len; i++) {
      if (typeof obj[tags[i]] === 'undefined') obj[tags[i]] = {};
      obj = obj[tags[i]];
    }

    obj[tags[len]] = value;

    return this;
  }

  /**
   * Get text content from this shape.
   *
   * @returns {String}
   */
  getText() {
    return this.get('text');
  }

  /**
   * Set new text content to this shape.
   *
   * @param {String} [text=''] New text
   * @returns {Shape}
   */
  setText(text = '') {
    this.set('text', text);
    return this;
  }

  /**
   * Get shape width.
   *
   * @returns {Number}
   */
  getWidth() {
    return this.get('width');
  }

  /**
   * Set new shape width.
   *
   * @param {Number} [width=15] Shape width
   * @returns {Shape}
   */
  setWidth(width = 15) {
    this.set('width', width);
    return this;
  }

  /**
   * Get shape height.
   *
   * @returns {Number}
   */
  getHeight() {
    return this.get('height');
  }

  /**
   * Set new shape height.
   *
   * @param {Number} [height=5] Shape height
   * @returns {Shape}
   */
  setHeight(height = 5) {
    this.set('height', height);
    return this;
  }

  /**
   * Get current position of shape.
   *
   * @returns {{x: Number, y: Number}}
   */
  getPosition() {
    return {x: this.get('x'), y: this.get('y')};
  }

  /**
   * Set new shape position.
   *
   * @param {Number} [x=10] Absolute coordinate X
   * @param {Number} [y=10] Absolute coordinate Y
   * @returns {Shape}
   */
  setPosition(x = 10, y = 10) {
    this.set('x', x);
    this.set('y', y);
    return this;
  }

  /**
   * Get align property from this shape.
   *
   * @returns {String}
   */
  getAlign() {
    return this.get('align');
  }

  /**
   * Set align to this shape.
   *
   * @param {String} align
   * @returns {Shape}
   */
  setAlign(align) {
    this.set('align', align);
    return this;
  }

  /**
   * Check if this shape must be aligned.
   *
   * @returns {Boolean}
   */
  isAligned() {
    return !!this.get('align');
  }

  /**
   * Get background color.
   *
   * @returns {String}
   */
  getBackground() {
    return this.get('background');
  }

  /**
   * Set new background color.
   *
   * @param {String} background Background color from {@link COLORS}
   * @returns {Shape}
   */
  setBackground(background) {
    this.set('background', background);
    return this;
  }

  /**
   * Get foreground color.
   *
   * @returns {String}
   */
  getForeground() {
    return this.get('foreground');
  }

  /**
   * Set new foreground color.
   *
   * @param {String} foreground Foreground color from {@link COLORS}
   * @returns {Shape}
   */
  setForeground(foreground) {
    this.set('foreground', foreground);
    return this;
  }

  /**
   * Get animation options from this shape.
   *
   * @returns {Object}
   */
  getAnimation() {
    return this.get('animation');
  }

  /**
   * Set animation options to the shape.
   *
   * @param {Object} animation
   * @param {String} animation.name Animation name
   * @returns {Shape}
   */
  setAnimation(animation) {
    this.set('animation', animation);
    return this;
  }

  /**
   * Check if this shape is animated.
   *
   * @returns {Boolean}
   */
  isAnimated() {
    return !!this.get('animation');
  }

  /**
   * Base render method that must be implemented in childes.
   *
   * @abstract
   * @param {Cursor} cursor Cursor instance which you can use for render the shape
   * @throws {Error} Throws error if method will not be overridden
   */
  render(cursor) {
    throw new Error('render() method must be implemented');
  }

  /**
   * Returns Object representation of the shape.
   * This representation consists of all options fields.
   *
   * @returns {{name: String, options: {text: String, width: Number, height: Number, x: Number, y: Number, background: String, foreground: String, animation: Object}}}
   */
  toObject() {
    return {
      name: this.constructor.name,
      options: {
        text: this.getText(),
        width: this.getWidth(),
        height: this.getHeight(),
        x: this.getPosition().x,
        y: this.getPosition().y,
        background: this.getBackground(),
        foreground: this.getForeground(),
        animation: this.getAnimation()
      }
    };
  }

  /**
   * Returns JSON representation of the shape.
   *
   * @returns {String}
   */
  toJSON() {
    return JSON.stringify(this.toObject());
  }

  /**
   * Wrapper around `new Shape()`.
   *
   * @static
   * @param {*} args
   * @returns {Shape}
   */
  static create(...args) {
    return new this(...args);
  }

  /**
   * Creates new Shape instance from Object representation.
   *
   * @static
   * @param {Object} obj Object that you got from {@link Shape.toObject}
   * @returns {Shape}
   */
  static fromObject(obj) {
    if (!obj.name || !obj.options) throw new Error('It looks like it is not an Object representation of the shape');
    if (obj.name !== this.name) throw new Error(`${obj.name} is not an Object representation of the ${this.name}`);

    return this.create(obj.options);
  }

  /**
   * Creates new Shape instance from JSON representation.
   *
   * @static
   * @param {String} json JSON string that you got from {@link Shape.toJSON}
   * @returns {Shape}
   */
  static fromJSON(json) {
    let obj = JSON.parse(json);
    return this.fromObject(obj);
  }
}
<commit_msg>refactor(shape): Split align to separate X and Y coordinates<commit_after>/**
 * Base class for creating other shapes.
 * Each custom shape must extends from this class.
 *
 * @since 1.0.0
 * @example
 * import Shape from 'kittik-shape-basic';
 *
 * export default class Rectangle extends Shape {
 *   render(cursor) {
 *     // Implement your logic here for rendering the shape
 *   }
 * }
 */
export default class Shape {
  /**
   * @constructor
   * @param {Object} [options]
   * @param {String} [options.text] Text that will be rendered in the shape
   * @param {Number} [options.width] Shape width
   * @param {Number} [options.height] Shape height
   * @param {Number} [options.x] Absolute coordinate X
   * @param {Number} [options.y] Absolute coordinate Y
   * @param {String} [options.align] Set if shape is need to be aligned
   * @param {String} [options.background] Background color from {@link COLORS}
   * @param {String} [options.foreground] Foreground color from {@link COLORS}
   * @param {Object} [options.animation] Animation options for this shape
   */
  constructor(options = {}) {
    this._options = options;

    this.setText(options.text);
    this.setWidth(options.width);
    this.setHeight(options.height);
    this.setPosition(options.x, options.y);
    this.setAlignX(options.alignX);
    this.setAlignY(options.alignY);
    this.setBackground(options.background);
    this.setForeground(options.foreground);
    this.setAnimation(options.animation);
  }

  /**
   * Get option value.
   *
   * @param {String} path Path can be set with dot-notation
   * @returns {*}
   */
  get(path) {
    return path.split('.').reduce((obj, key) => obj[key], this._options);
  }

  /**
   * Set new option value.
   *
   * @param {String} path Path can be set with dot-notation
   * @param {*} value Value that need to be written to the options object
   * @returns {Shape}
   */
  set(path, value) {
    let obj = this._options;
    let tags = path.split('.');
    let len = tags.length - 1;

    for (let i = 0; i < len; i++) {
      if (typeof obj[tags[i]] === 'undefined') obj[tags[i]] = {};
      obj = obj[tags[i]];
    }

    obj[tags[len]] = value;

    return this;
  }

  /**
   * Get text content from this shape.
   *
   * @returns {String}
   */
  getText() {
    return this.get('text');
  }

  /**
   * Set new text content to this shape.
   *
   * @param {String} [text=''] New text
   * @returns {Shape}
   */
  setText(text = '') {
    return this.set('text', text);
  }

  /**
   * Get shape width.
   *
   * @returns {Number}
   */
  getWidth() {
    return this.get('width');
  }

  /**
   * Set new shape width.
   *
   * @param {Number} [width=15] Shape width
   * @returns {Shape}
   */
  setWidth(width = 15) {
    return this.set('width', width);
  }

  /**
   * Get shape height.
   *
   * @returns {Number}
   */
  getHeight() {
    return this.get('height');
  }

  /**
   * Set new shape height.
   *
   * @param {Number} [height=5] Shape height
   * @returns {Shape}
   */
  setHeight(height = 5) {
    return this.set('height', height);
  }

  /**
   * Get current position of shape.
   *
   * @returns {{x: Number, y: Number}}
   */
  getPosition() {
    return {x: this.get('x'), y: this.get('y')};
  }

  /**
   * Set new shape position.
   *
   * @param {Number} [x=10] Absolute coordinate X
   * @param {Number} [y=10] Absolute coordinate Y
   * @returns {Shape}
   */
  setPosition(x = 10, y = 10) {
    return this.set('x', x).set('y', y);
  }

  /**
   * Get align property within X coordinates.
   *
   * @returns {String}
   */
  getAlignX() {
    return this.get('alignX');
  }

  /**
   * Set align property within X coordinates.
   *
   * @param {String} align Can be left, center or right
   * @returns {Shape}
   */
  setAlignX(align) {
    return this.set('alignX', align);
  }

  /**
   * Get align property within Y coordinates.
   *
   * @returns {String}
   */
  getAlignY() {
    return this.get('alignY');
  }

  /**
   * Set align property within Y coordinates.
   *
   * @param {String} align Can be top, middle or bottom
   * @returns {Shape}
   */
  setAlignY(align) {
    return this.set('alignY', align);
  }

  /**
   * Check if this shape must be aligned.
   *
   * @returns {Boolean}
   */
  isAligned() {
    return !!this.getAlignX() || !!this.getAlignY();
  }

  /**
   * Get background color.
   *
   * @returns {String}
   */
  getBackground() {
    return this.get('background');
  }

  /**
   * Set new background color.
   *
   * @param {String} background Background color from {@link COLORS}
   * @returns {Shape}
   */
  setBackground(background) {
    return this.set('background', background);
  }

  /**
   * Get foreground color.
   *
   * @returns {String}
   */
  getForeground() {
    return this.get('foreground');
  }

  /**
   * Set new foreground color.
   *
   * @param {String} foreground Foreground color from {@link COLORS}
   * @returns {Shape}
   */
  setForeground(foreground) {
    return this.set('foreground', foreground);
  }

  /**
   * Get animation options from this shape.
   *
   * @returns {Object}
   */
  getAnimation() {
    return this.get('animation');
  }

  /**
   * Set animation options to the shape.
   *
   * @param {Object} animation
   * @param {String} animation.name Animation name
   * @returns {Shape}
   */
  setAnimation(animation) {
    this.set('animation', animation);
    return this;
  }

  /**
   * Check if this shape is animated.
   *
   * @returns {Boolean}
   */
  isAnimated() {
    return !!this.get('animation');
  }

  /**
   * Base render method that must be implemented in childes.
   *
   * @abstract
   * @param {Cursor} cursor Cursor instance which you can use for render the shape
   * @throws {Error} Throws error if method will not be overridden
   */
  render(cursor) {
    throw new Error('render() method must be implemented');
  }

  /**
   * Returns Object representation of the shape.
   * This representation consists of all options fields.
   *
   * @returns {{name: String, options: {text: String, width: Number, height: Number, x: Number, y: Number, background: String, foreground: String, animation: Object}}}
   */
  toObject() {
    return {
      name: this.constructor.name,
      options: {
        text: this.getText(),
        width: this.getWidth(),
        height: this.getHeight(),
        x: this.getPosition().x,
        y: this.getPosition().y,
        alignX: this.getAlignX(),
        alignY: this.getAlignY(),
        background: this.getBackground(),
        foreground: this.getForeground(),
        animation: this.getAnimation()
      }
    };
  }

  /**
   * Returns JSON representation of the shape.
   *
   * @returns {String}
   */
  toJSON() {
    return JSON.stringify(this.toObject());
  }

  /**
   * Wrapper around `new Shape()`.
   *
   * @static
   * @param {*} args
   * @returns {Shape}
   */
  static create(...args) {
    return new this(...args);
  }

  /**
   * Creates new Shape instance from Object representation.
   *
   * @static
   * @param {Object} obj Object that you got from {@link Shape.toObject}
   * @returns {Shape}
   */
  static fromObject(obj) {
    if (!obj.name || !obj.options) throw new Error('It looks like it is not an Object representation of the shape');
    if (obj.name !== this.name) throw new Error(`${obj.name} is not an Object representation of the ${this.name}`);

    return this.create(obj.options);
  }

  /**
   * Creates new Shape instance from JSON representation.
   *
   * @static
   * @param {String} json JSON string that you got from {@link Shape.toJSON}
   * @returns {Shape}
   */
  static fromJSON(json) {
    let obj = JSON.parse(json);
    return this.fromObject(obj);
  }
}
<|endoftext|>


<commit_before>// @flow

import {Platform, Alert, Linking} from 'react-native'
import RNCalendarEvents from 'react-native-calendar-events'
import type {EventType} from './types'

export function addToCalendar(event: EventType): Promise<boolean> {
  return RNCalendarEvents.authorizationStatus()
    .then(authStatus => {
      if (authStatus !== 'authorized') {
        return requestCalendarAccess()
      }
      return true
    })
    .then(status => {
      if (!status) {
        return false
      }
      return saveEventToCalendar(event)
    })
    .catch(err => {
      alert(err)
      return false
    })
}

async function saveEventToCalendar(event: EventType): Promise<boolean> {
  try {
    await RNCalendarEvents.saveEvent(event.title, {
      location: event.location,
      startDate: event.startTime.toISOString(),
      endDate: event.endTime.toISOString(),
    })
    return true
  } catch (err) {
    return false
  }
}

function promptSettings(): any {
  if (Platform.OS === 'ios') {
    return Alert.alert(
      'Enable Calendar Access',
      'Please enable calendar access in device settings.',
      [
        {text: 'OK', onPress: () => console.log('OK Pressed'), style: 'cancel'},
        {text: 'Settings', onPress: () => Linking.openURL('app-settings:')},
      ],
    )
  }
}

async function requestCalendarAccess(): Promise<boolean> {
  let status = null
  try {
    status = await RNCalendarEvents.authorizeEventStore()
  } catch (err) {
    return false
  }

  if (status !== 'authorized') {
    return promptSettings()
  }

  return true
}
<commit_msg>Change wording to match text in ios plist<commit_after>// @flow

import {Platform, Alert, Linking} from 'react-native'
import RNCalendarEvents from 'react-native-calendar-events'
import type {EventType} from './types'

export function addToCalendar(event: EventType): Promise<boolean> {
  return RNCalendarEvents.authorizationStatus()
    .then(authStatus => {
      if (authStatus !== 'authorized') {
        return requestCalendarAccess()
      }
      return true
    })
    .then(status => {
      if (!status) {
        return false
      }
      return saveEventToCalendar(event)
    })
    .catch(err => {
      alert(err)
      return false
    })
}

async function saveEventToCalendar(event: EventType): Promise<boolean> {
  try {
    await RNCalendarEvents.saveEvent(event.title, {
      location: event.location,
      startDate: event.startTime.toISOString(),
      endDate: event.endTime.toISOString(),
    })
    return true
  } catch (err) {
    return false
  }
}

function promptSettings(): any {
  if (Platform.OS === 'ios') {
    // Note: remember to change this text in the iOS plist, too.
    return Alert.alert(
      '"All About Olaf" Would Like to Access Your Calendar',
      `We use your calendar to add events to your calendar so that you remember
       what you wanted to attend.`,
      [
        {text: 'Don\'t Allow', onPress: () => console.log('cancel pressed'), style: 'cancel'},
        {text: 'Settings', onPress: () => Linking.openURL('app-settings:')},
      ],
    )
  }
}

async function requestCalendarAccess(): Promise<boolean> {
  let status = null
  try {
    status = await RNCalendarEvents.authorizeEventStore()
  } catch (err) {
    return false
  }

  if (status !== 'authorized') {
    return promptSettings()
  }

  return true
}
<|endoftext|>


<commit_before>var canvas;
var colorId;
var mode;

function setup(){
  canvas = createCanvas(500, 500);
  colorId = P5JsUtils.COLOR_ID_GREEN;
  background(50);
  mode = 'random';
  drawColorTiles();
}

function keyTyped(){
  switch (key) {
    case 'p':
      saveCanvas(canvas, 'screenshot', 'png');
      break;
    case 'r':
      colorId = P5JsUtils.COLOR_ID_RED;
      drawColorTiles();
      break;
    case 'o':
      colorId = P5JsUtils.COLOR_ID_ORANGE;
      drawColorTiles();
      break;
    case 'y':
      colorId = P5JsUtils.COLOR_ID_YELLOW;
      drawColorTiles();
      break;
    case 'g':
      colorId = P5JsUtils.COLOR_ID_GREEN;
      drawColorTiles();
      break;
    case 'b':
      colorId = P5JsUtils.COLOR_ID_BLUE;
      drawColorTiles();
      break;
    case 'v':
      colorId = P5JsUtils.COLOR_ID_VIOLET;
      drawColorTiles();
      break;
    case 'm':
      toggleMode();
      drawColorTiles();
      break;
  }
}

function toggleMode(){
  if (mode == 'random') {
    mode = 'scales';
  } else {
    mode = 'random';
  }
}

function drawColorTiles(){
  let cellWidth = 20;
  let margin = 20;
  let numRows = (width  - 2 * margin) / cellWidth;
  let numCols = (height - 2 * margin) / cellWidth;

  noStroke();
  for (let i = 0; i < numCols; i++){
    for (let j = 0; j < numRows; j++){
      fillColorFor(j, i);
      rect(margin + i * cellWidth, margin + j * cellWidth, cellWidth, cellWidth);
    }
  }
}

function fillColorFor(row, col){
  if (mode == 'random') {
    fill(P5JsUtils.getRandomColorByID(colorId));
  }
}
<commit_msg>p5js/scales - random_colors - Add simple debugging of color at mouse pos<commit_after>var canvas;
var colorId;
var mode;

function setup(){
  canvas = createCanvas(500, 500);
  colorId = P5JsUtils.COLOR_ID_GREEN;
  background(50);
  mode = 'random';
  drawColorTiles();
}

function mousePressed(){
  console.log(get(mouseX, mouseY));
}

function keyTyped(){
  switch (key) {
    case 'p':
      saveCanvas(canvas, 'screenshot', 'png');
      break;
    case 'r':
      colorId = P5JsUtils.COLOR_ID_RED;
      drawColorTiles();
      break;
    case 'o':
      colorId = P5JsUtils.COLOR_ID_ORANGE;
      drawColorTiles();
      break;
    case 'y':
      colorId = P5JsUtils.COLOR_ID_YELLOW;
      drawColorTiles();
      break;
    case 'g':
      colorId = P5JsUtils.COLOR_ID_GREEN;
      drawColorTiles();
      break;
    case 'b':
      colorId = P5JsUtils.COLOR_ID_BLUE;
      drawColorTiles();
      break;
    case 'v':
      colorId = P5JsUtils.COLOR_ID_VIOLET;
      drawColorTiles();
      break;
    case 'm':
      toggleMode();
      drawColorTiles();
      break;
  }
}

function toggleMode(){
  if (mode == 'random') {
    mode = 'scales';
  } else {
    mode = 'random';
  }
}

function drawColorTiles(){
  let cellWidth = 20;
  let margin = 20;
  let numRows = (width  - 2 * margin) / cellWidth;
  let numCols = (height - 2 * margin) / cellWidth;

  noStroke();
  for (let i = 0; i < numCols; i++){
    for (let j = 0; j < numRows; j++){
      fillColorFor(j, i);
      rect(margin + i * cellWidth, margin + j * cellWidth, cellWidth, cellWidth);
    }
  }
}

function fillColorFor(row, col){
  if (mode == 'random') {
    fill(P5JsUtils.getRandomColorByID(colorId));
  }
}
<|endoftext|>


<commit_before>console.log('lalala');
//TODO do not polute the global workspace... eventually!

function picnames(){
  var pics = [
    "http://24.media.tumblr.com/682996b5152ede515195f86383f8a45c/tumblr_mthme5lImD1rvuefeo1_500.jpg",
    "http://31.media.tumblr.com/e543774937d26fdb2ffe51598b38614b/tumblr_mthmikLD101rvuefeo1_500.jpg",
    "http://31.media.tumblr.com/19500610594070f5c9aa99f227740f09/tumblr_mtg15cakQF1rvuefeo1_500.jpg",
    "http://31.media.tumblr.com/0452d659390c63e79f7cb505e81c4478/tumblr_mt8j6imlDo1rvuefeo1_500.jpg",
    "http://24.media.tumblr.com/51a2157e649c4d7a83f4d1a4d6e86062/tumblr_mst2992s291rvuefeo1_500.jpg"
    ];
  return pics;
}

$('#item0').attr("src", picnames()[0]);
$('#item1').attr("src", picnames()[1]);
$('#item2').attr("src", picnames()[2]);
$('#item3').attr("src", picnames()[3]);
$('#item4').attr("src", picnames()[4]);

$('.carousel').carousel({
    interval: 2000
});
<commit_msg>adds compatibility messages<commit_after>console.log('lalala');
//TODO do not polute the global workspace... eventually!

function picnames(){
  var pics = [
    "http://24.media.tumblr.com/682996b5152ede515195f86383f8a45c/tumblr_mthme5lImD1rvuefeo1_500.jpg",
    "http://31.media.tumblr.com/e543774937d26fdb2ffe51598b38614b/tumblr_mthmikLD101rvuefeo1_500.jpg",
    "http://31.media.tumblr.com/19500610594070f5c9aa99f227740f09/tumblr_mtg15cakQF1rvuefeo1_500.jpg",
    "http://31.media.tumblr.com/0452d659390c63e79f7cb505e81c4478/tumblr_mt8j6imlDo1rvuefeo1_500.jpg",
    "http://24.media.tumblr.com/51a2157e649c4d7a83f4d1a4d6e86062/tumblr_mst2992s291rvuefeo1_500.jpg"
    ];
  return pics;
};

$('#item0').attr("src", picnames()[0]);
$('#item1').attr("src", picnames()[1]);
$('#item2').attr("src", picnames()[2]);
$('#item3').attr("src", picnames()[3]);
$('#item4').attr("src", picnames()[4]);

$('.carousel').carousel({
    interval: 2000
});

var cMess1 ='You are going to be alone for the rest of your life';
var cMess2 ='buy another pet, you are gonna need it';
var cMess3 ='message 3 is for somehtine else';
var cMess4 ='message 4 is also for something else';
var cMess5 ='default message';

var compatMessages = [];
compatMessages.push(cMess1);
compatMessages.push(cMess2);
compatMessages.push(cMess3);
compatMessages.push(cMess4);
compatMessages.push(cMess5);

function changeCompatMessage(messageNumber){
  $('#compatibility').text(compatMessages[messageNumber]);
}
//default message
$('#compatibility').text(compatMessages[4]);
<|endoftext|>


<commit_before>var tessel = require('tessel');

var climatelib = require('climate-si7020');
var bleLib = require('ble-ble113a')
var packetGen = require('bleadvertise');

var climate = climatelib.use(tessel.port['B']);
var ble = bleLib.use(tessel.port['A']);

ble.on('ready', function(err) {
	if (err) {
		return console.log(err);
	}
	console.log('Connected to ble113a.');
	ble.setAdvertisingData(packetGen.serialize({completeName: "Tessel BLE113A Module"}), function(err) {
		if (err) {
			return console.log(err);
		}
		ble.startAdvertising();
	})
});

ble.on('connect', function() {
	console.log("We have a BLE connection to master.");

	setInterval(function(){
		climate.readHumidity(function(err, humid){
			climate.readTemperature('f', function(err, temp){
				ble.writeLocalValue(0, new Buffer(temp.toFixed(4)));
				ble.writeLocalValue(1, new Buffer(humid.toFixed(4)));
			});
		});
	}, 1000);
});

//Climate event handling, primarily logging
climate.on('ready', function() {
	console.log('Connected to climate-si7020');
});

climate.on('error', function(err) {
	console.log('error connecting module', err);
});

//Bluetooth event handling, primarily logging
ble.on('disconnect', function() {
	console.log('Disconnected from central device')
  // Stop our interval
  clearInterval(interval);
  // Start advertising again
  ble.startAdvertising();
});

ble.on('startAdvertising', function(){
	console.log('Started advertising as BLE peripheral device')
});

ble.on('stopAdvertising', function(){
	console.log('Stopped advertising')
});

<commit_msg>Switches module loading to use tesselate<commit_after>var tessel = require('tessel');
var packetGen = require('bleadvertise');

// Load and immediately run tesselate module
require('tesselate')({
  modules: {
    A: ['ble-ble113a', 'ble'],
    B: ['climate-si7020', 'climate']
  },
  development: true              // enable development logging, useful for debugging
}, function(tessel, modules){
  var ble = modules.ble;
  var climate = modules.climate;

    console.log('Connected to modules.');
    ble.setAdvertisingData(packetGen.serialize({completeName: "Tessel BLE113A Module"}), function(err) {
      if (err) {
        return console.log(err);
      }
      ble.startAdvertising();
    })

  ble.on('connect', function() {
    console.log("We have a BLE connection to master.");

    setInterval(function(){
      climate.readHumidity(function(err, humid){
        climate.readTemperature('f', function(err, temp){
          ble.writeLocalValue(0, new Buffer(temp.toFixed(4)));
          ble.writeLocalValue(1, new Buffer(humid.toFixed(4)));
        });
      });
    }, 1000);
  });

  //Bluetooth event handling, primarily logging
  ble.on('disconnect', function() {
    console.log('Disconnected from central device')
    // Stop our interval
    clearInterval(interval);
    // Start advertising again
    ble.startAdvertising();
  });

  ble.on('startAdvertising', function(){
    console.log('Started advertising as BLE peripheral device')
  });

  ble.on('stopAdvertising', function(){
    console.log('Stopped advertising')
  });
});<|endoftext|>


<commit_before>import { Animation } from '../../animation/Animation.js';
import { linear } from '../../animation/Easing.js';
import { Class } from '../../core/Core.js';
import { limit } from '../../core/Math.js';
import { appendChildren, setStyle } from '../../dom/Element.js';
import { ViewEventsController } from '../ViewEventsController.js';
import { ScrollView } from './ScrollView.js';
import { TouchScrollView } from './TouchScrollView.js';

import /* {
    nextFrame,
    nextLoop,
    observes,
    on,
    property,
    queue,
} from */ '../../foundation/Decorators.js';

const PanZoomView = Class({
    Name: 'PanZoomView',

    Extends: TouchScrollView,

    showScrollbarX: true,
    showScrollbarY: false,

    init: function (mixin) {
        PanZoomView.parent.init.call(this, mixin);

        this.scaleAnimation = new Animation({
            object: this,
            property: 'scale',
            duration: 200,
        });

        this.scale = 1;

        this._tCount = 0;
        this._tScale = 1;
        this._tDist = 0;
        this._tX = 0;
        this._tY = 0;
        this._posX = 0;
        this._posY = 0;
        this._scrollParent = null;
    },

    setListeners: function () {
        const layer = this.get('layer');
        if (this.get('isInDocument')) {
            layer.addEventListener('load', this, true);
            layer.addEventListener('webkitTransitionEnd', this, true);
            layer.addEventListener('transitionend', this, true);
        } else {
            layer.removeEventListener('load', this, true);
            layer.removeEventListener('webkitTransitionEnd', this, true);
            layer.removeEventListener('transitionend', this, true);
        }
    }.observes('isInDocument'),

    parentViewDidResize() {
        if (this.get('isInDocument')) {
            this.contentDidResize();
        }
        return PanZoomView.parent.parentViewDidResize.call(this);
    },

    // Needs to be in the next next frame after the next event loop so the
    // browser has definitely drawn the loaded image and we get the proper
    // resized dimensions. Why, I'm not quite sure but just nextLoop no longer
    // seems to be enough.
    contentDidResize: function () {
        this.computedPropertyDidChange('scrollWidth').computedPropertyDidChange(
            'scrollHeight',
        );
        const minScale = this.get('minScale');
        if (this.get('scale') < minScale) {
            this.set('scale', minScale);
        }
        const scrollLeft = this.get('scrollLeft');
        const scrollTop = this.get('scrollTop');
        if (
            scrollLeft > this.get('maxScrollX') ||
            scrollTop > this.get('maxScrollY')
        ) {
            // This will clamp them to allowed values
            this.scrollTo(scrollLeft, scrollTop, false);
        }
    }
        .nextLoop()
        .nextFrame()
        .on('load', 'webkitTransitionEnd', 'transitionend'),

    positioning: 'relative',

    layout: function () {
        const scale = this.get('scale');
        return {
            height:
                this.get('isInDocument') && scale !== 1
                    ? this.get('scrollHeight') * scale
                    : 'auto',
        };
    }.property('scrollHeight', 'scale'),

    scrollWidth: function () {
        return this._scrollContents.firstChild.offsetWidth;
    }.property('isInDocument'),

    scrollHeight: function () {
        return this._scrollContents.firstChild.offsetHeight;
    }.property('isInDocument'),

    _setAllowBounce: function () {
        this.allowBounce =
            !!this.get('maxScrollX') ||
            this.get('scale') < this.get('minScale');
    }.on('touchstart'),
    _setAllowBounce2: function () {
        this.allowBounce = true;
    }.observes('scale'),

    maxScrollX: function () {
        const scale = this.get('scale');
        const pxWidth = this.get('pxWidth');
        const scrollWidth = this.get('scrollWidth');
        return this.get('showScrollbarX')
            ? Math.max(0, scale * scrollWidth - pxWidth)
            : 0;
    }.property('scale', 'scrollWidth', 'pxWidth'),

    maxScrollY: function () {
        const scale = this.get('scale');
        const pxHeight = this.get('pxHeight');
        const scrollHeight = this.get('scrollHeight');
        return this.get('showScrollbarY')
            ? Math.max(0, scale * scrollHeight - pxHeight)
            : 0;
    }.property('scale', 'scrollHeight', 'pxHeight'),

    minScale: function () {
        return this.get('isInDocument')
            ? Math.min(this.get('pxWidth') / this.get('scrollWidth'), 1)
            : 1;
    }.property('pxWidth', 'scrollWidth'),

    maxScale: 3,

    setInitialScale: function () {
        this.set('scale', this.get('minScale'));
    }
        .queue('after')
        .observes('isInDocument'),

    // Draw scale

    draw(layer) {
        const render = PanZoomView.parent.draw.call(this, layer);
        const scrollContents = render[0];
        appendChildren(scrollContents, this.contents);
        setStyle(scrollContents, '-webkit-transform-origin', '0 0');
        setStyle(scrollContents, 'transform-origin', '0 0');
        return render;
    },

    zoomNeedsRedraw: function () {
        this.propertyNeedsRedraw(this, 'scroll');
    }.observes('scale'),

    redrawScroll() {
        const x = this.get('scrollLeft');
        const y = this.get('scrollTop');
        const scale = this.get('scale');
        setStyle(
            this._scrollContents,
            'transform',
            'translate3d(' +
                -x +
                'px,' +
                -y +
                'px,0)' +
                'scale(' +
                scale +
                ') ',
        );
    },

    // Zoom with pinch

    countTouches: function (event) {
        const touches = event.touches;
        const oldTouchCount = this._tCount;
        const newTouchCount = (this._tCount = touches.length);
        const scrollAnimation = this.get('scrollAnimation');
        if (oldTouchCount !== 2 && newTouchCount === 2) {
            this.scaleAnimation.stop();

            // Take over from scroll handlers.
            scrollAnimation._trackingId = null;
            scrollAnimation._isDragging = false;
            scrollAnimation._positions.length = 0;
            scrollAnimation._times.length = 0;
            ViewEventsController.removeEventTarget(scrollAnimation);

            const touchA = touches[0];
            const touchB = touches[1];
            const aX = touchA.screenX;
            const aY = touchA.screenY;
            const bX = touchB.screenX;
            const bY = touchB.screenY;

            const scale = this.get('scale');

            // Distance between touches
            let x = aX - bX;
            let y = aY - bY;

            this._tScale = scale;
            this._tDist = Math.sqrt(x * x + y * y);

            // Find position of centre point between touches
            x = (aX + bX) / 2;
            y = (aY + bY) / 2;

            // Adjust so that it is offset from the top left of the content
            // area as ( 0, 0 ) instead of the screen.
            const position = this.get('layer').getBoundingClientRect();
            let posX = position.left;
            let posY = position.top;
            x -= posX;
            y -= posY;

            const scrollParent =
                this.get('positioning') === 'relative'
                    ? this.getParent(ScrollView)
                    : null;
            if (scrollParent) {
                posX += scrollParent.get('scrollLeft');
                posY += scrollParent.get('scrollTop');
            }

            x += this.get('scrollLeft');
            y += this.get('scrollTop');

            // Now apply the current scale factor to get the coordinates as if
            // scale === 1.
            x /= scale;
            y /= scale;

            this._tX = x;
            this._tY = y;
            this._posX = posX;
            this._posY = posY;
            this._scrollParent = scrollParent;
        } else if (oldTouchCount === 2 && newTouchCount !== 2) {
            this._scrollParent = null;

            // Either continue scrolling, or animate back to min/max bounds.
            if (newTouchCount === 1) {
                scrollAnimation.onTouchStart(event);
                scrollAnimation._isDragging = true;
                scrollAnimation._enableScrollX = true;
            } else {
                scrollAnimation._velocityX = 0;
                scrollAnimation._velocityY = 0;
                scrollAnimation._lastFrameTime = 0;
                scrollAnimation.animate(null, 60000, linear);
            }

            // Animate back to allowed scale.
            this.scaleAnimation.animate(
                limit(
                    this.get('scale'),
                    this.get('minScale'),
                    this.get('maxScale'),
                ),
            );
        }
    }.on('touchstart', 'touchend'),

    zoom: function (event) {
        // It seems some platforms (iOS 9, Firefox Mobile) fire a touchmove
        // event without a corresponding touchstart/end event (or at least,
        // it's out of order). So must double check here to make sure we
        // actually have the number of touches we think we do.
        this.countTouches(event);

        if (this._tCount === 2) {
            // We are handling this; don't scroll parent view.
            event.preventDefault();
            event.stopPropagation();

            const touches = event.touches;
            const touchA = touches[0];
            const touchB = touches[1];
            const aX = touchA.screenX;
            const aY = touchA.screenY;
            const bX = touchB.screenX;
            const bY = touchB.screenY;
            const scrollParent = this._scrollParent;

            // Calculate new scale from distance between touches
            let x = aX - bX;
            let y = aY - bY;
            const distance = Math.sqrt(x * x + y * y);

            const minScale = this.get('minScale');
            const maxScale = this.get('maxScale');
            let scale = (distance / this._tDist) * this._tScale;
            scale =
                scale < minScale / 2
                    ? minScale / 2
                    : scale > maxScale
                    ? maxScale
                    : scale;

            // Find position of current centre point between touches
            x = (aX + bX) / 2;
            y = (aY + bY) / 2;

            // Find where on the screen the original centre point is
            let origX = this._tX * scale - this.get('scrollLeft') + this._posX;
            let origY = this._tY * scale - this.get('scrollTop') + this._posY;

            if (scrollParent) {
                origX -= scrollParent.get('scrollLeft');
                origY -= scrollParent.get('scrollTop');
            }

            // Work out how far we have to scroll to make the part of the doc
            // originally in the centre, still in the centre
            const deltaX = origX - x;
            const deltaY = origY - y;

            if (deltaX) {
                if (
                    scrollParent &&
                    scale >= minScale &&
                    scrollParent.get('showScrollbarX')
                ) {
                    scrollParent.scrollBy(deltaX, 0);
                } else {
                    this.increment('scrollLeft', deltaX);
                }
            }
            if (deltaY) {
                if (
                    scrollParent &&
                    scale >= minScale &&
                    scrollParent.get('showScrollbarY')
                ) {
                    scrollParent.scrollBy(0, deltaY);
                } else {
                    this.increment('scrollTop', deltaY);
                }
            }
            this.set('scale', scale);
        }
    }.on('touchmove'),
});

export { PanZoomView };
<commit_msg>Better measurement of PanZoomView scroll dimensions<commit_after>import { Animation } from '../../animation/Animation.js';
import { linear } from '../../animation/Easing.js';
import { Class } from '../../core/Core.js';
import { limit } from '../../core/Math.js';
import { appendChildren, setStyle } from '../../dom/Element.js';
import { ViewEventsController } from '../ViewEventsController.js';
import { ScrollView } from './ScrollView.js';
import { TouchScrollView } from './TouchScrollView.js';

import /* {
    nextFrame,
    nextLoop,
    observes,
    on,
    property,
    queue,
} from */ '../../foundation/Decorators.js';

const PanZoomView = Class({
    Name: 'PanZoomView',

    Extends: TouchScrollView,

    showScrollbarX: true,
    showScrollbarY: false,

    init: function (mixin) {
        PanZoomView.parent.init.call(this, mixin);

        this.scaleAnimation = new Animation({
            object: this,
            property: 'scale',
            duration: 200,
        });

        this.scale = 1;

        this._tCount = 0;
        this._tScale = 1;
        this._tDist = 0;
        this._tX = 0;
        this._tY = 0;
        this._posX = 0;
        this._posY = 0;
        this._scrollParent = null;
    },

    setListeners: function () {
        const layer = this.get('layer');
        if (this.get('isInDocument')) {
            layer.addEventListener('load', this, true);
            layer.addEventListener('webkitTransitionEnd', this, true);
            layer.addEventListener('transitionend', this, true);
        } else {
            layer.removeEventListener('load', this, true);
            layer.removeEventListener('webkitTransitionEnd', this, true);
            layer.removeEventListener('transitionend', this, true);
        }
    }.observes('isInDocument'),

    parentViewDidResize() {
        if (this.get('isInDocument')) {
            this.contentDidResize();
        }
        return PanZoomView.parent.parentViewDidResize.call(this);
    },

    // Needs to be in the next next frame after the next event loop so the
    // browser has definitely drawn the loaded image and we get the proper
    // resized dimensions. Why, I'm not quite sure but just nextLoop no longer
    // seems to be enough.
    contentDidResize: function () {
        this.computedPropertyDidChange('scrollWidth').computedPropertyDidChange(
            'scrollHeight',
        );
        const minScale = this.get('minScale');
        if (this.get('scale') < minScale) {
            this.set('scale', minScale);
        }
        const scrollLeft = this.get('scrollLeft');
        const scrollTop = this.get('scrollTop');
        if (
            scrollLeft > this.get('maxScrollX') ||
            scrollTop > this.get('maxScrollY')
        ) {
            // This will clamp them to allowed values
            this.scrollTo(scrollLeft, scrollTop, false);
        }
    }
        .nextLoop()
        .nextFrame()
        .on('load', 'webkitTransitionEnd', 'transitionend'),

    positioning: 'relative',

    layout: function () {
        const scale = this.get('scale');
        return {
            height:
                this.get('isInDocument') && scale !== 1
                    ? this.get('scrollHeight') * scale
                    : 'auto',
        };
    }.property('scrollHeight', 'scale'),

    scrollWidth: function () {
        return this._scrollContents.scrollWidth;
    }.property('isInDocument'),

    scrollHeight: function () {
        return this._scrollContents.scrollHeight;
    }.property('isInDocument'),

    _setAllowBounce: function () {
        this.allowBounce =
            !!this.get('maxScrollX') ||
            this.get('scale') < this.get('minScale');
    }.on('touchstart'),
    _setAllowBounce2: function () {
        this.allowBounce = true;
    }.observes('scale'),

    maxScrollX: function () {
        const scale = this.get('scale');
        const pxWidth = this.get('pxWidth');
        const scrollWidth = this.get('scrollWidth');
        return this.get('showScrollbarX')
            ? Math.max(0, scale * scrollWidth - pxWidth)
            : 0;
    }.property('scale', 'scrollWidth', 'pxWidth'),

    maxScrollY: function () {
        const scale = this.get('scale');
        const pxHeight = this.get('pxHeight');
        const scrollHeight = this.get('scrollHeight');
        return this.get('showScrollbarY')
            ? Math.max(0, scale * scrollHeight - pxHeight)
            : 0;
    }.property('scale', 'scrollHeight', 'pxHeight'),

    minScale: function () {
        return this.get('isInDocument')
            ? Math.min(this.get('pxWidth') / this.get('scrollWidth'), 1)
            : 1;
    }.property('pxWidth', 'scrollWidth'),

    maxScale: 3,

    setInitialScale: function () {
        this.set('scale', this.get('minScale'));
    }
        .queue('after')
        .observes('isInDocument'),

    // Draw scale

    draw(layer) {
        const render = PanZoomView.parent.draw.call(this, layer);
        const scrollContents = render[0];
        appendChildren(scrollContents, this.contents);
        setStyle(scrollContents, '-webkit-transform-origin', '0 0');
        setStyle(scrollContents, 'transform-origin', '0 0');
        return render;
    },

    zoomNeedsRedraw: function () {
        this.propertyNeedsRedraw(this, 'scroll');
    }.observes('scale'),

    redrawScroll() {
        const x = this.get('scrollLeft');
        const y = this.get('scrollTop');
        const scale = this.get('scale');
        setStyle(
            this._scrollContents,
            'transform',
            'translate3d(' +
                -x +
                'px,' +
                -y +
                'px,0)' +
                'scale(' +
                scale +
                ') ',
        );
    },

    // Zoom with pinch

    countTouches: function (event) {
        const touches = event.touches;
        const oldTouchCount = this._tCount;
        const newTouchCount = (this._tCount = touches.length);
        const scrollAnimation = this.get('scrollAnimation');
        if (oldTouchCount !== 2 && newTouchCount === 2) {
            this.scaleAnimation.stop();

            // Take over from scroll handlers.
            scrollAnimation._trackingId = null;
            scrollAnimation._isDragging = false;
            scrollAnimation._positions.length = 0;
            scrollAnimation._times.length = 0;
            ViewEventsController.removeEventTarget(scrollAnimation);

            const touchA = touches[0];
            const touchB = touches[1];
            const aX = touchA.screenX;
            const aY = touchA.screenY;
            const bX = touchB.screenX;
            const bY = touchB.screenY;

            const scale = this.get('scale');

            // Distance between touches
            let x = aX - bX;
            let y = aY - bY;

            this._tScale = scale;
            this._tDist = Math.sqrt(x * x + y * y);

            // Find position of centre point between touches
            x = (aX + bX) / 2;
            y = (aY + bY) / 2;

            // Adjust so that it is offset from the top left of the content
            // area as ( 0, 0 ) instead of the screen.
            const position = this.get('layer').getBoundingClientRect();
            let posX = position.left;
            let posY = position.top;
            x -= posX;
            y -= posY;

            const scrollParent =
                this.get('positioning') === 'relative'
                    ? this.getParent(ScrollView)
                    : null;
            if (scrollParent) {
                posX += scrollParent.get('scrollLeft');
                posY += scrollParent.get('scrollTop');
            }

            x += this.get('scrollLeft');
            y += this.get('scrollTop');

            // Now apply the current scale factor to get the coordinates as if
            // scale === 1.
            x /= scale;
            y /= scale;

            this._tX = x;
            this._tY = y;
            this._posX = posX;
            this._posY = posY;
            this._scrollParent = scrollParent;
        } else if (oldTouchCount === 2 && newTouchCount !== 2) {
            this._scrollParent = null;

            // Either continue scrolling, or animate back to min/max bounds.
            if (newTouchCount === 1) {
                scrollAnimation.onTouchStart(event);
                scrollAnimation._isDragging = true;
                scrollAnimation._enableScrollX = true;
            } else {
                scrollAnimation._velocityX = 0;
                scrollAnimation._velocityY = 0;
                scrollAnimation._lastFrameTime = 0;
                scrollAnimation.animate(null, 60000, linear);
            }

            // Animate back to allowed scale.
            this.scaleAnimation.animate(
                limit(
                    this.get('scale'),
                    this.get('minScale'),
                    this.get('maxScale'),
                ),
            );
        }
    }.on('touchstart', 'touchend'),

    zoom: function (event) {
        // It seems some platforms (iOS 9, Firefox Mobile) fire a touchmove
        // event without a corresponding touchstart/end event (or at least,
        // it's out of order). So must double check here to make sure we
        // actually have the number of touches we think we do.
        this.countTouches(event);

        if (this._tCount === 2) {
            // We are handling this; don't scroll parent view.
            event.preventDefault();
            event.stopPropagation();

            const touches = event.touches;
            const touchA = touches[0];
            const touchB = touches[1];
            const aX = touchA.screenX;
            const aY = touchA.screenY;
            const bX = touchB.screenX;
            const bY = touchB.screenY;
            const scrollParent = this._scrollParent;

            // Calculate new scale from distance between touches
            let x = aX - bX;
            let y = aY - bY;
            const distance = Math.sqrt(x * x + y * y);

            const minScale = this.get('minScale');
            const maxScale = this.get('maxScale');
            let scale = (distance / this._tDist) * this._tScale;
            scale =
                scale < minScale / 2
                    ? minScale / 2
                    : scale > maxScale
                    ? maxScale
                    : scale;

            // Find position of current centre point between touches
            x = (aX + bX) / 2;
            y = (aY + bY) / 2;

            // Find where on the screen the original centre point is
            let origX = this._tX * scale - this.get('scrollLeft') + this._posX;
            let origY = this._tY * scale - this.get('scrollTop') + this._posY;

            if (scrollParent) {
                origX -= scrollParent.get('scrollLeft');
                origY -= scrollParent.get('scrollTop');
            }

            // Work out how far we have to scroll to make the part of the doc
            // originally in the centre, still in the centre
            const deltaX = origX - x;
            const deltaY = origY - y;

            if (deltaX) {
                if (
                    scrollParent &&
                    scale >= minScale &&
                    scrollParent.get('showScrollbarX')
                ) {
                    scrollParent.scrollBy(deltaX, 0);
                } else {
                    this.increment('scrollLeft', deltaX);
                }
            }
            if (deltaY) {
                if (
                    scrollParent &&
                    scale >= minScale &&
                    scrollParent.get('showScrollbarY')
                ) {
                    scrollParent.scrollBy(0, deltaY);
                } else {
                    this.increment('scrollTop', deltaY);
                }
            }
            this.set('scale', scale);
        }
    }.on('touchmove'),
});

export { PanZoomView };
<|endoftext|>


<commit_before>import Inferno   from 'inferno'
import Component from 'inferno-component'
import styled    from 'styled-components'
import { bind }  from 'decko'

import { Indicator } from './indicator'
import { Dots, Dot } from './steps'
import {
  Container,
  Line,
  Thumb,
  Track
} from './parts'

export class Slider extends Component {
  state = {
    focus: false,
    keyFocus: false,
  }

  // Helper functions
  vise = (min, value, max) =>
    Math.min(Math.max(min, value), max)

  capitalize = (string) =>
    string.charAt(0).toUpperCase() + string.slice(1)

  getPercentage = (max) => max / (this.props.step || this.props.max)

  split = (max, parts) => max / parts

  componentWillMount() {
    document.body.addEventListener(
      'mousemove',
      this.handleMouseMove,
      { passive: true }
    )
    document.body.addEventListener(
      'mouseup',
      this.handleMouseUp,
      { passive: true }
    )
  }

  componentWillUnmount() {
    document.body.removeEventListener(
      'mousemove',
      this.handleMouseMove,
      { passive: true }
    )
    document.body.removeEventListener(
      'mouseup',
      this.handleMouseUp,
      { passive: true }
    )
  }

  @bind
  moveSlider({ clientX }) {
    const { offsetLeft, clientWidth } = this.slider
    const { max } = this.props
    const percentage = (clientX - offsetLeft) / clientWidth

    const progress = this.vise(0, percentage, 1) * max

    this.emit('change', progress)
  }

  emit(type, value) {
    const eventName = 'on' + this.capitalize(type)
    if(typeof this.props[eventName] == 'function') {
      this.props[eventName](value)
    }
  }

  @bind
  handleMouseDown(e) {
    // Set the state and emit the focus event
    this.setState({ focus: true })
    this.emit('focus')

    this.moveSlider(e)
  }

  @bind
  handleMouseUp(e) {
    // Set the state and emit the blur event
    this.setState({ focus: false })
    this.emit('blur')
  }

  @bind
  handleMouseMove(e) {
    if(this.state.focus) this.moveSlider(e)
  }

  @bind
  handleFocus() {
    this.setState({ keyFocus: true })
  }

  @bind
  handleKeyDown({ keyCode }) {
    const { vise } = this
    let { value, max } = this.props
    let { keyFocus } = this.state

    const percentage = this.getPercentage(max)

    switch (keyCode) {

      // Forward: increment of 1
      case 38:
      case 39:
        if(keyFocus) {
          const _value = vise(0, value + percentage, max)
          this.emit('change', _value)
        }
      break

      // Backwards: decrease of 1
      case 40:
      case 37:
        if(keyFocus) {
          const _value = vise(0, value - percentage, max)
          this.emit('change', _value)
        }
      break
      default:
      break
    }
  }

  render({ steps, ...props}) {
    const {
      handleMouseDown,
      handleMouseUp,
      handleMouseMove,
      handleKeyDown,
      handleFocus
    } = this
    const { focus, keyFocus } = this.state
    const dots = []

    if(steps) {
      const stepValue = this.split(props.max, steps)

      for (let i = 0; i < steps; i++) {
        dots.push(<Dot style={{ left: stepValue * i + '%'  }} id={i} />)
      }
    }

    return(
      <Container
        {...props}
        onMouseDown={handleMouseDown}
        onKeyDown={handleKeyDown}
        onFocus={handleFocus}
        innerRef={e => this.slider = e}
        tabIndex={props.disabled ? -1 : 0}
        focus={focus}
      >

        {/* Thumb */}
        <Thumb
          {...props}
          focus={focus}
          style={{left: (props.value / props.max) * 100 + '%'}}
        />

        {/** Dots for stepped slider */}
        {steps && props.discrete &&
          <Dots {...props}>
            {dots}
            <Dot style='left: 100%' />
          </Dots>
        }

        {/*Main Line*/}
        <Line disabled={props.disabled} />

        {/* Track */}
        <Track
          disabled={props.disabled}
          style={{width: (props.value / props.max) * 100 + '%'}}
        />

        <Indicator {...props} focus={focus || keyFocus} />
      </Container>
    )
  }
}
<commit_msg>:bug: Fixed step progress with keyboard events<commit_after>import Inferno   from 'inferno'
import Component from 'inferno-component'
import styled    from 'styled-components'
import { bind }  from 'decko'

import { Indicator } from './indicator'
import { Dots, Dot } from './steps'
import {
  Container,
  Line,
  Thumb,
  Track
} from './parts'

export class Slider extends Component {
  state = {
    focus: false,
    keyFocus: false,
  }

  // Helper functions
  vise = (min, value, max) =>
    Math.min(Math.max(min, value), max)

  capitalize = (string) =>
    string.charAt(0).toUpperCase() + string.slice(1)

  getPercentage = (max) => max / (this.props.steps || this.props.max)

  split = (max, parts) => max / parts

  componentWillMount() {
    document.body.addEventListener(
      'mousemove',
      this.handleMouseMove,
      { passive: true }
    )
    document.body.addEventListener(
      'mouseup',
      this.handleMouseUp,
      { passive: true }
    )
  }

  componentWillUnmount() {
    document.body.removeEventListener(
      'mousemove',
      this.handleMouseMove,
      { passive: true }
    )
    document.body.removeEventListener(
      'mouseup',
      this.handleMouseUp,
      { passive: true }
    )
  }

  @bind
  moveSlider({ clientX }) {
    const { offsetLeft, clientWidth } = this.slider
    const { max } = this.props
    const percentage = (clientX - offsetLeft) / clientWidth

    const progress = this.vise(0, percentage, 1) * max

    this.emit('change', progress)
  }

  emit(type, value) {
    const eventName = 'on' + this.capitalize(type)
    if(typeof this.props[eventName] == 'function') {
      this.props[eventName](value)
    }
  }

  @bind
  handleMouseDown(e) {
    // Set the state and emit the focus event
    this.setState({ focus: true })
    this.emit('focus')

    this.moveSlider(e)
  }

  @bind
  handleMouseUp(e) {
    // Set the state and emit the blur event
    this.setState({ focus: false })
    this.emit('blur')
  }

  @bind
  handleMouseMove(e) {
    if(this.state.focus) this.moveSlider(e)
  }

  @bind
  handleFocus() {
    this.setState({ keyFocus: true })
  }

  @bind
  handleKeyDown({ keyCode }) {
    const { vise } = this
    let { value, max } = this.props
    let { keyFocus } = this.state

    const percentage = this.getPercentage(max)

    switch (keyCode) {

      // Forward: increment of 1
      case 38:
      case 39:
        if(keyFocus) {
          const _value = vise(0, value + percentage, max)
          this.emit('change', _value)
        }
      break

      // Backwards: decrease of 1
      case 40:
      case 37:
        if(keyFocus) {
          const _value = vise(0, value - percentage, max)
          this.emit('change', _value)
        }
      break
      default:
      break
    }
  }

  render({ steps, ...props}) {
    const {
      handleMouseDown,
      handleMouseUp,
      handleMouseMove,
      handleKeyDown,
      handleFocus
    } = this
    const { focus, keyFocus } = this.state
    const dots = []

    if(steps) {
      const stepValue = this.split(props.max, steps)

      for (let i = 0; i < steps; i++) {
        dots.push(<Dot style={{ left: stepValue * i + '%'  }} id={i} />)
      }
    }

    return(
      <Container
        {...props}
        onMouseDown={handleMouseDown}
        onKeyDown={handleKeyDown}
        onFocus={handleFocus}
        innerRef={e => this.slider = e}
        tabIndex={props.disabled ? -1 : 0}
        focus={focus}
      >

        {/* Thumb */}
        <Thumb
          {...props}
          focus={focus}
          style={{left: (props.value / props.max) * 100 + '%'}}
        />

        {/** Dots for stepped slider */}
        {steps && props.discrete &&
          <Dots {...props}>
            {dots}
            <Dot style='left: 100%' />
          </Dots>
        }

        {/*Main Line*/}
        <Line disabled={props.disabled} />

        {/* Track */}
        <Track
          disabled={props.disabled}
          style={{width: (props.value / props.max) * 100 + '%'}}
        />

        <Indicator {...props} focus={focus || keyFocus} />
      </Container>
    )
  }
}
<|endoftext|>


<commit_before>//(function(){
//  var name = 'one';
//  window.onload(){
//    console.log(name);
//  };
//  name  = 'two';
// })();

// when an inner function has no local variables, and itself is only availble to the parent function it is, so it can access it's parent's variables
function init(){
  var name = 'George';
  function displayName(){
    console.log(name);
  }
  displayName();
}
init();

// displayName() inner function was returned from outter function before being executed.
// the local variabls within a function only exist for the duration of that function's execution. the following function shouldn't work normally.
// a closure is a special kind of object that combines 2 things: a funciton, and the environment which the function was created.
// the environment consists of any local variables that were in-scope at the time the closure was created.
// in this case, myFunc() incoporates both displayName() and name string when the closure, myFunc() was created.
function makeFunc(){
  var name = 'George';
  function displayName(){
    console.log(name);
  }
  return displayName;
}

var myFunc = makeFunc();
myFunc();

<commit_msg>updated closure.js<commit_after>(function(){
  var name = 'one';
  window.onload(){
    console.log(name);
  };
  name  = 'two';
})();

// closures are functions that refer to independent(free) variables. In other words, the funciton defined in the colsure 'remembers' the enviroment in which it was created.
// when an inner function has no local variables, and itself is only availble to the parent function it is, so it can access it's parent's variables
// lexcial scoping
function init(){
  var name = 'George';
  function displayName(){
    console.log(name);
  }
  displayName();
}
init();

// displayName() inner function was returned from outter function before being executed.
// the local variabls within a function only exist for the duration of that function's execution. the following function shouldn't work normally.
// a closure is a special kind of object that combines 2 things: a funciton, and the environment which the function was created.
// the environment consists of any local variables that were in-scope at the time the closure was created.
// in this case, myFunc() incoporates both displayName() and name string when the closure, myFunc() was created.
function makeFunc(){
  var name = 'George';
  function displayName(){
    console.log(name);
  }
  return displayName;
}

var myFunc = makeFunc();
myFunc();

// Based on my understanding, the way to init are colsures are assigning functinos to values.
function makeAdder(x){
  return function(y){
    return x + y;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);

console.log(add5(2));
console.log(add10(2));

function add(x){
  return function(y){
    return function(z){
      return function(a){
        return x + y + z + a;
      };
    };
  };
}

var add = add(1);
var addy = add(2);
var addz = addy(3);
console.log(addz(6));

var counter = (function(){
  var privateCounter = 0;
  function changeBy(val){
    privateCounter += val;
  }
 return {
  increment: function(){
    changeBy(1);
  },
  decrement: function(){
    changeBy(-1);
  },
  value:function(){
    return privateCounter;
  }
 };
})();

console.log(counter.value());
counter.increment();
console.log(counter.value());
counter.increment();
console.log(counter.value());
counter.decrement();
console.log(counter.value());

// notice how each of the two maintains it's independence from each other. It's envoriment during the call of the makeCounter() function is different each time. The closure variable privateCounter contains a different instance each time.
var makeCounter = function(){
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function(){
       changeBy(1);
    },
    decrement: function(){
      changeBy(-1);
    },
    value: function(){
     return privateCounter;
   }
  };
};

var counter1 = makeCounter();
var counter2 = makeCounter();

console.log(counter1.value());
counter1.increment();
counter1.increment();
console.log(counter1.value());
counter1.decrement();
console.log(counter1.value());
console.log(counter2.value());

<|endoftext|>


<commit_before>const {HotModuleReplacementPlugin, NoErrorsPlugin} = require('webpack')

// Modules requires for hot reloading in development
const hotModules = [
  'react-hot-loader/patch',
  'eventsource-polyfill',
  'webpack-hot-middleware/client',
]

/**
 * Add HMR settings to Webpack configuration
 * @param {Object} config Configuration to modify
 * @return {void}
 */
module.exports = config => {
  // Add plugins for hot module code
  config.plugins = [
    ...config.plugins,
    new HotModuleReplacementPlugin(),
    new NoErrorsPlugin(),
  ]

  // Add hot module code to entries
  config.entry = Object.keys(config.entry)
    .filter(key => Array.isArray(config.entry[key]))
    .reduce((previous, key) => Object.assign(previous, {
      [key]: [...hotModules, ...config.entry[key]],
    }), {})
}
<commit_msg>s/NoErrorsPlugin/NoEmitOnErrorsPlugin<commit_after>const {HotModuleReplacementPlugin, NoEmitOnErrorsPlugin} = require('webpack')

// Modules requires for hot reloading in development
const hotModules = [
  'react-hot-loader/patch',
  'eventsource-polyfill',
  'webpack-hot-middleware/client',
]

/**
 * Add HMR settings to Webpack configuration
 * @param {Object} config Configuration to modify
 * @return {void}
 */
module.exports = config => {
  // Add plugins for hot module code
  config.plugins = [
    ...config.plugins,
    new HotModuleReplacementPlugin(),
    new NoEmitOnErrorsPlugin(),
  ]

  // Add hot module code to entries
  config.entry = Object.keys(config.entry)
    .filter(key => Array.isArray(config.entry[key]))
    .reduce((previous, key) => Object.assign(previous, {
      [key]: [...hotModules, ...config.entry[key]],
    }), {})
}
<|endoftext|>


<commit_before>// @flow

import React from 'react'
import {Text, View, StyleSheet, TouchableOpacity, Platform} from 'react-native'
import {parseTerm} from '../../../lib/course-search'
import type {CourseType} from '../../../lib/course-search'
import {Cell, TableView, Section} from 'react-native-tableview-simple'
import {FormattedLine} from './formatted-line'
import Icon from 'react-native-vector-icons/Ionicons'
import * as c from '../../components/colors'
import type {TopLevelViewPropsType} from '../../types'

type TermType = {
	title: string,
	data: Array<CourseType>,
}

type Props = TopLevelViewPropsType & {
	terms: Array<{title: string, data: Array<CourseType>}>,
}

export class CourseSearchTableView extends React.PureComponent<Props> {
	onPress = (course: CourseType) => {
		this.props.navigation.navigate('CourseDetailView', {course: course})
	}

	renderCells = (term: TermType) => {
		const cells = term.data.map(course => (
			<TouchableOpacity
				key={course.clbid}
				onPress={() => {
					this.onPress(course)
				}}
			>
				<CourseCell course={course} />
			</TouchableOpacity>
		))
		return cells
	}

	renderSection = (term: TermType) => {
		let cells = this.renderCells(term)
		let termHeader = parseTerm(term.title)
		return (
			<Section key={term.title} header={termHeader}>
				{cells}
			</Section>
		)
	}

	render() {
		// console.log(this.props.terms)
		const sections = this.props.terms.map(term => this.renderSection(term))
		return <TableView>{sections}</TableView>
	}
}

const CourseCell = props => {
	const iconPlatform = Platform.OS === 'ios' ? 'ios' : 'md'
	const icon = `${iconPlatform}-arrow-forward`
	return (
		<Cell
			{...props}
			cellContentView={
				<View style={styles.cellContainer}>
					<View style={styles.cellContent}>
						<View>
							<Text style={styles.cellHeader}>{props.course.name}</Text>
							<Text style={styles.cellSubTitle}>
								{props.course.departments[0]} {props.course.number}
								{props.course.section}
							</Text>
							{props.course.times && (
								<Text>
									<FormattedLine items={props.course.times} />
								</Text>
							)}
							{props.course.instructors && (
								<Text>
									<FormattedLine items={props.course.instructors} />
								</Text>
							)}
							{props.course.gereqs && (
								<Text>
									<FormattedLine items={props.course.gereqs} />
								</Text>
							)}
						</View>
					</View>
					<View style={styles.arrowContainer}>
						<Icon name={icon} style={styles.arrow} />
					</View>
				</View>
			}
		/>
	)
}

const styles = StyleSheet.create({
	cellContainer: {
		padding: 5,
		flex: 1,
		flexDirection: 'row',
	},
	cellContent: {
		flex: 0.98,
	},
	arrow: {
		fontSize: 30,
		color: c.iosGray,
	},
	arrowContainer: {
		justifyContent: 'center',
	},
	cellHeader: {
		fontSize: 25,
	},
	cellSubTitle: {
		fontSize: 18,
	},
})
<commit_msg>remove unused results components<commit_after><|endoftext|>


<commit_before>// @flow

import yargs from "yargs";
// @todo remove that and use project config
import phenomic from "@phenomic/core";

yargs.command(
  "start",
  "start your project (server / development mode)",
  {},
  () => phenomic.start()
);

yargs.command(
  "build",
  "build your project (static / production mode)",
  {},
  () => phenomic.build()
);

export default () => {
  yargs.parse(process.argv);
};
<commit_msg>✨ `@phenomic/cli`: add preview command<commit_after>// @flow

import yargs from "yargs";
// @todo remove that and use project config
import phenomic from "@phenomic/core";

yargs.command(
  "start",
  "start your project (server / development mode)",
  {},
  () => phenomic.start()
);

yargs.command(
  "build",
  "build your project (static / production mode)",
  {},
  () => phenomic.build()
);

yargs.command(
  "preview",
  "build & serve your project (static / production mode)",
  {},
  () => phenomic.preview()
);

export default () => {
  yargs.parse(process.argv);
};
<|endoftext|>


<commit_before>/**
 * @copyright 2015, Prometheus Research, LLC
 */

import React, {PropTypes}   from 'react';
import Value                from './Value';
import Input                from './Input';
import ErrorList            from './ErrorList';
import Component            from './Component';

function renderLabel(label, schema) {
  return label && {label};
}

function renderErrorList(formValue) {
  return <ErrorList formValue={formValue} />;
}

export default class Field extends Component {

  static propTypes = {
    ...Component.propTypes,
    label: PropTypes.string,
    children: PropTypes.element,
    renderLabel: PropTypes.func,
    renderErrorList: PropTypes.func
  };

  static defaultProps = {
    children: <Input type="text" />,
    renderLabel,
    renderErrorList
  };

  constructor(props) {
    super(props);
    this.state = {dirty: false};
  }

  render() {
    let {children, renderLabel, renderErrorList} = this.props;
    let {dirty} = this.state;
    let {schema, value, errors, params} = this.formValue;
    let showErrors = dirty || params.forceShowErrors;
    children = React.cloneElement(
      React.Children.only(children),
      {value, onChange: this.onChange});
    let label = this.props.label || schema.label;
    return (

        {renderLabel(label, schema)}
        {children}
        {showErrors && renderErrorList(this.formValue)}

    );
  }

  onBlur = () => {
    this.setState({dirty: true});
  }

  onChange = (e) => {
    let value;
    if (e && e.target && e.target.value !== undefined) {
      e.stopPropagation();
      value = e.target.value;
      if (value === '') {
        value = undefined;
      }
    } else {
      value = e;
    }
    this.setState({dirty: true});
    this.props.formValue.set(value);
  }
}
<commit_msg><Field />: fixes for new Value API<commit_after>/**
 * @copyright 2015, Prometheus Research, LLC
 */

import React, {PropTypes}   from 'react';
import Value                from './Value';
import Input                from './Input';
import ErrorList            from './ErrorList';
import Component            from './Component';

function renderLabel(label, schema) {
  return label && {label};
}

function renderErrorList(formValue) {
  return <ErrorList formValue={formValue} />;
}

export default class Field extends Component {

  static propTypes = {
    ...Component.propTypes,
    label: PropTypes.string,
    children: PropTypes.element,
    renderLabel: PropTypes.func,
    renderErrorList: PropTypes.func
  };

  static defaultProps = {
    children: <Input type="text" />,
    renderLabel,
    renderErrorList
  };

  constructor(props) {
    super(props);
    this.state = {dirty: false};
  }

  render() {
    let {children, renderLabel, renderErrorList} = this.props;
    let {dirty} = this.state;
    let {schema, value, errors, params} = this.formValue;
    let showErrors = dirty || params.forceShowErrors;
    children = React.cloneElement(
      React.Children.only(children),
      {value, onChange: this.onChange});
    let label = this.props.label || schema.label;
    return (

        {renderLabel(label, schema)}
        {children}
        {showErrors && renderErrorList(this.formValue)}

    );
  }

  onBlur = () => {
    this.setState({dirty: true});
  }

  onChange = (e) => {
    let value;
    if (e && e.target && e.target.value !== undefined) {
      e.stopPropagation();
      value = e.target.value;
      if (value === '') {
        value = undefined;
      }
    } else {
      value = e;
    }
    this.setState({dirty: true});
    this.props.formValue.update(value);
  }
}
<|endoftext|>


<commit_before>var Component = UIComponent;

// `id` arguments to this class MUST be non-empty strings
_UI.List = Component.extend({
  typeName: 'List',
  _items: null, // OrderedDict of id -> Component
  _else: null, // Component
  constructed: function () {
    this._items = new OrderedDict;
  },
  addItemBefore: function (id, compType, data, beforeId) {
    var self = this;

    var comp = compType(function () {
      this.dataDep.depend();
      return this._data;
    }, {
      _data: data,
      dataDep: new Deps.Dependency
    });
    self._items.putBefore(id, comp, beforeId);

    if (self.stage === Component.BUILT) {
      if (self._else) {
        self._else.remove();
        self._else = null;
      }

      self.insertBefore(
        comp, beforeId ? self._items.get(beforeId) : null);
    }
  },
  removeItem: function (id) {
    var comp = this._items.remove(id);

    if (this.stage === Component.BUILT) {
      comp.remove();
      if (this._items.empty()) {
        this._else = this.elseContent();
        if (this._else)
          this.append(this._else);
      }
    }
  },
  moveItemBefore: function (id, beforeId) {
    var comp = this._items.get(id);
    this._items.moveBefore(id, beforeId);

    if (this.stage === Component.BUILT) {
      comp.detach();
      this.insertBefore(
        comp, beforeId ? this._items.get(beforeId) : null);
    }
  },
  getItem: function (id) {
    return this._items.get(id) || null;
  },
  setItemData: function (id, newData) {
    var comp = this.getItem(id);
    if (! comp)
      throw new Error("No such item: " + id);
    // Do a `===` check even though it's weak
    if (newData !== comp._data) {
      comp._data = newData;
      comp.dataDep.changed();
    }
  },
  numItems: function () {
    return this._items.size();
  },
  render: function (buf) {
    // This component reactively rebuilds when any dependencies
    // here are invalidated.
    //
    // The "item" methods cannot be called from here; they assume
    // they are not operating during the build, but either
    // before or after it.

    var self = this;
    if (self._items.empty()) {
      buf(self._else = self.elseContent());
    } else {
      self._items.forEach(function (comp) {
        buf(comp);
      });
    }
  },
  _findStartComponent: function () {
    return this._items.firstValue();
  },
  _findEndComponent: function () {
    return this._items.lastValue();
  },
  // Replace the data in this list with a different dataset,
  // reusing components with matching ids, moving them if
  // necessary.
  // The caller supplies a sequence of (id, data) : (String, any)
  // pairs using the `add` method of the returned object, and then
  // calls `end`.
  beginReplace: function () {
    var self = this;

    var items = self._items;
    var ptr = items.first();
    var seenIds = {};
    var counter = 1;
    // uniquify IDs by adding a few random characters and
    // a counter.
    var rand = Random.id().slice(0,4);
    return {
      // here only, id may be null
      add: function (id, compType, data) {
        var origId = id;
        while ((! id) || seenIds.hasOwnProperty(id))
          id = (origId || '') + rand + (counter++);
        seenIds[id] = true;

        // Now we know `id` is unique among new items,
        // but it may match an old item at or after
        // the location of `ptr`
        if (ptr === id) {
          // XXX we don't deal the case where compType is different
          // from the original compType.
          self.setItemData(id, data);
          ptr = items.next(ptr);
        } else if (items.has(id)) {
          self.moveItemBefore(id, ptr);
          self.setItemData(id, data);
        } else {
          self.addItemBefore(id, compType, data, ptr);
        }
      },
      end: function () {
        // delete everything at or after ptr
        while (ptr) {
          var next = items.next(ptr);
          self.removeItem(ptr);
          ptr = next;
        }
      }
    };
  }
});

_UI.Each = Component.extend({
  typeName: 'Each',
  List: _UI.List,
  _oldData: null,
  init: function () {
    var self = this;
    self._list = self.List({
      elseContent: function (/**/) {
        return self.elseContent.apply(self, arguments);
      }
    });
    // add outside of the rebuild cycle
    self.add(self._list);
  },
  _getId: function (value) { // override this
    if (value == null) {
      return null;
    } else if (value._id == null) {
      if (typeof value === 'object')
        // value is some object without `_id`.  oh well.
        return null;
      else
        // value is a string or number, say
        return String(value);
    } else {
      if (typeof value._id === 'object')
        return null;
      else
        return String(value._id);
    }
  },
  render: function (buf) {
    var self = this;
    var list = self._list;

    var newData = self.data();
    // Do a `===` check even though it's weak
    if (newData !== self._oldData) {
      self._oldData = newData;

      var replacer = list.beginReplace();

      if (! newData) {
        // nothing to do
      } else if (typeof newData.length === 'number' &&
                 typeof newData.splice === 'function') {
        // looks like an array
        var array = newData;

        for (var i=0, N=array.length; i<N; i++) {
          var x = array[i];
          replacer.add(self._getId(x), self.content, x);
        }

      } else if (newData.observe) {
        var cursor = newData;

        // we assume that `observe` will only call `addedAt` (and
        // not other callbacks) before returning (which is specced),
        // and further that these calls will be in document order
        // (which isn't).
        cursor.observe({
          _no_indices: true,
          addedAt: function (doc, i, beforeId) {
            var id = Meteor.idStringify(doc._id);
            if (replacer)
              replacer.add(id, self.content, doc);
            else
              list.addItemBefore(id, self.content, doc,
                                 beforeId && Meteor.idStringify(beforeId));
          },
          removed: function (doc) {
            list.removeItem(Meteor.idStringify(doc._id));
          },
          movedTo: function (doc, i, j, beforeId) {
            list.moveItemBefore(Meteor.idStringify(doc._id),
                                beforeId && Meteor.idStringify(beforeId));
          },
          changed: function (newDoc) {
            list.setItemData(Meteor.idStringify(newDoc._id), newDoc);
          }
        });
      } else {
        for (var k in newData)
          replacer.add(k, self.content, newData[k]);
      }

      replacer.end();
      replacer = null; // so cursor.observe callbacks stop using it
    }

    buf(list);
  }
});
<commit_msg>document limitations and move on<commit_after>var Component = UIComponent;

// `id` arguments to this class MUST be non-empty strings
_UI.List = Component.extend({
  typeName: 'List',
  _items: null, // OrderedDict of id -> Component
  _else: null, // Component
  constructed: function () {
    this._items = new OrderedDict;
  },
  addItemBefore: function (id, compType, data, beforeId) {
    var self = this;

    var comp = compType(function () {
      this.dataDep.depend();
      return this._data;
    }, {
      _data: data,
      dataDep: new Deps.Dependency
    });
    self._items.putBefore(id, comp, beforeId);

    if (self.stage === Component.BUILT) {
      if (self._else) {
        self._else.remove();
        self._else = null;
      }

      self.insertBefore(
        comp, beforeId ? self._items.get(beforeId) : null);
    }
  },
  removeItem: function (id) {
    var comp = this._items.remove(id);

    if (this.stage === Component.BUILT) {
      comp.remove();
      if (this._items.empty()) {
        this._else = this.elseContent();
        if (this._else)
          this.append(this._else);
      }
    }
  },
  moveItemBefore: function (id, beforeId) {
    var comp = this._items.get(id);
    this._items.moveBefore(id, beforeId);

    if (this.stage === Component.BUILT) {
      comp.detach();
      this.insertBefore(
        comp, beforeId ? this._items.get(beforeId) : null);
    }
  },
  getItem: function (id) {
    return this._items.get(id) || null;
  },
  setItemData: function (id, newData) {
    var comp = this.getItem(id);
    if (! comp)
      throw new Error("No such item: " + id);
    // Do a `===` check even though it's weak
    if (newData !== comp._data) {
      comp._data = newData;
      comp.dataDep.changed();
    }
  },
  numItems: function () {
    return this._items.size();
  },
  render: function (buf) {
    // This component reactively rebuilds when any dependencies
    // here are invalidated.
    //
    // The "item" methods cannot be called from here; they assume
    // they are not operating during the build, but either
    // before or after it.

    var self = this;
    if (self._items.empty()) {
      buf(self._else = self.elseContent());
    } else {
      self._items.forEach(function (comp) {
        buf(comp);
      });
    }
  },
  _findStartComponent: function () {
    return this._items.firstValue();
  },
  _findEndComponent: function () {
    return this._items.lastValue();
  },
  // Replace the data in this list with a different dataset,
  // reusing components with matching ids, moving them if
  // necessary.
  // The caller supplies a sequence of (id, data) : (String, any)
  // pairs using the `add` method of the returned object, and then
  // calls `end`.
  beginReplace: function () {
    var self = this;

    var items = self._items;
    var ptr = items.first();
    var seenIds = {};
    var counter = 1;
    // uniquify IDs by adding a few random characters and
    // a counter.
    var rand = Random.id().slice(0,4);
    return {
      // here only, id may be null
      add: function (id, compType, data) {
        var origId = id;
        while ((! id) || seenIds.hasOwnProperty(id))
          id = (origId || '') + rand + (counter++);
        seenIds[id] = true;

        // Now we know `id` is unique among new items,
        // but it may match an old item at or after
        // the location of `ptr`.
        //
        // We use the strategy of moving an existing component
        // into the appropriate place if one exists, otherwise
        // inserting one.  This is efficient if, say, a new document
        // is inserted at the top or bottom, removed from the bottom,
        // or moved to the top.  It's inefficient if a document is
        // removed from the top or moved to the bottom, because we
        // will perform `N-1` "moves".
        //
        // In summary, we don't generate efficient moves the way
        // least-common-subsequence would, be we do reuse existing
        // components and move them to the right place.
        if (ptr === id) {
          // XXX we don't deal the case where compType is different
          // from the original compType.
          self.setItemData(id, data);
          ptr = items.next(ptr);
        } else if (items.has(id)) {
          self.moveItemBefore(id, ptr);
          self.setItemData(id, data);
        } else {
          self.addItemBefore(id, compType, data, ptr);
        }
      },
      end: function () {
        // delete everything at or after ptr
        while (ptr) {
          var next = items.next(ptr);
          self.removeItem(ptr);
          ptr = next;
        }
      }
    };
  }
});

_UI.Each = Component.extend({
  typeName: 'Each',
  List: _UI.List,
  _oldData: null,
  init: function () {
    var self = this;
    self._list = self.List({
      elseContent: function (/**/) {
        return self.elseContent.apply(self, arguments);
      }
    });
    // add outside of the rebuild cycle
    self.add(self._list);
  },
  _getId: function (value) { // override this
    if (value == null) {
      return null;
    } else if (value._id == null) {
      if (typeof value === 'object')
        // value is some object without `_id`.  oh well.
        return null;
      else
        // value is a string or number, say
        return String(value);
    } else {
      if (typeof value._id === 'object')
        return null;
      else
        return String(value._id);
    }
  },
  render: function (buf) {
    var self = this;
    var list = self._list;

    var newData = self.data();
    // Do a `===` check even though it's weak
    if (newData !== self._oldData) {
      self._oldData = newData;

      var replacer = list.beginReplace();

      if (! newData) {
        // nothing to do
      } else if (typeof newData.length === 'number' &&
                 typeof newData.splice === 'function') {
        // looks like an array
        var array = newData;

        for (var i=0, N=array.length; i<N; i++) {
          var x = array[i];
          replacer.add(self._getId(x), self.content, x);
        }

      } else if (newData.observe) {
        var cursor = newData;

        // we assume that `observe` will only call `addedAt` (and
        // not other callbacks) before returning (which is specced),
        // and further that these calls will be in document order
        // (which isn't).
        cursor.observe({
          _no_indices: true,
          addedAt: function (doc, i, beforeId) {
            var id = Meteor.idStringify(doc._id);
            if (replacer)
              replacer.add(id, self.content, doc);
            else
              list.addItemBefore(id, self.content, doc,
                                 beforeId && Meteor.idStringify(beforeId));
          },
          removed: function (doc) {
            list.removeItem(Meteor.idStringify(doc._id));
          },
          movedTo: function (doc, i, j, beforeId) {
            list.moveItemBefore(Meteor.idStringify(doc._id),
                                beforeId && Meteor.idStringify(beforeId));
          },
          changed: function (newDoc) {
            list.setItemData(Meteor.idStringify(newDoc._id), newDoc);
          }
        });
      } else {
        for (var k in newData)
          replacer.add(k, self.content, newData[k]);
      }

      replacer.end();
      replacer = null; // so cursor.observe callbacks stop using it
    }

    buf(list);
  }
});
<|endoftext|>


<commit_before>var MessageStream = require('message-stream')
var net = require('net')
var argv = require('optimist').argv
var EventEmitter = require('events').EventEmitter

// port needed for connection
var port = argv.port || 2503
var myIp = require('my-local-ip')()
var host = argv.host || myIp
var serverPort = argv.server || 2503

// id needed for per client identity
var id = myIp + ':' + serverPort

// name purely for pretty-ness
var name = argv.name || 'Anonymous'

function Chat(id, name) {
    // Each node needs a messages thing
    var chat = new EventEmitter()

    // keep track of history
    var history = chat.history = []
    var clock = chat.clock = {}

    // We should be able to send messages locally
    chat.send = function (text) {
        chat.emit('message', {
            text: text,
            name: name,
            id: id,
            time: Date.now()
        })
    }

    // Create a stream for sending and receiving messages
    // When we receieve a message from the stream we should
    // call .receive
    // When we have a message emmitted we should queue it
    // unless we emitted it ourselves to avoid an infinite loop
    // This means we should always pass along the stream to
    // receive
    chat.createStream = function () {
        var stream = MessageStream(function (message) {
            // Handle history messages
            if (typeof message.since === "number") {
                console.log(message.id + ' requests messages since:', message.since)
                history.forEach(function (e) {
                    if(e.time > message.since) {
                        stream.queue(e)
                    }
                })
            // otherwise receive the message
            } else {
                chat.receive(message, stream)
            }
        })

        // on message send down stream
        chat.on('message', function (message, source) {
            if (source !== stream) {
                stream.queue(message)
            }
        })

        // send the history receival handshake
        stream.queue({ since: chat.latest(), id: id })

        return stream
    }

    // we should be able to receive messages from a network
    chat.receive = function (message, source) {
        chat.emit('message', message, source)
    }

    // on message store in history & print
    chat.on('message', function (message) {
        // check to see whether message already handled
        if (clock[message.id] == null || clock[message.id] < message.time) {
            // update clock
            clock[message.id] = message.time

            chat.history.push(message)
            console.log(message.name + ' > ' + message.text)
        }
    })

    //get the lastest message we know.
    chat.latest = function () {
        return history.reduce(function (max, e) {
            return max.time > e.time ? max : e
        }, {time: 0}).time
    }

    return chat
}

var chat = Chat(id, name)
process.stdin.on('data', function (text) {
    chat.send(String(text))
})

//if (argv.server) {
    var server = net.createServer(function (stream) {
        stream.pipe(chat.createStream()).pipe(stream)
    })

    server.listen(argv.server || 2503)
    console.log('Started server on port', port)
//} else {
    // connection logic in function for retries
    ;(function connect () {
        var hosts = Object.keys(chat.clock).map(function (e) {
          var p = e.split(':')
          return {host: p[0], port: p[1]}
        }).filter(function (e) {
          return serverPort != e.port || myIp != e.host
        })

        var random = hosts[~~(Math.random() * hosts.length)]
            || {host: host, port: port}

        console.log('Attempt connection to:', random, chat.clock)

        if(random.host == myIp && random.port == serverPort) {
           console.log('do not connect to self')
           return reconnect()
        }

        var client = net.connect(random.port, random.host, function () {
            client.pipe(chat.createStream()).pipe(client)
            console.log('Connected to server on port', port)
            setTimeout(function() {
              client.end()
            }, 5000)
        })

        // retry on end or error
        client.on('error', reconnect)
        client.on('close', reconnect)

        function reconnect () {
            if(client) client.removeAllListeners()
            setTimeout(function () {
                connect()
            }, 1000)
        }
    })()
//}
<commit_msg>refactored<commit_after>var MessageStream = require('message-stream')
var net = require('net')
var argv = require('optimist').argv
var EventEmitter = require('events').EventEmitter

// port needed for connection
var seedPort = argv.port || 2503
var myIp = require('my-local-ip')()
var seedHost = argv.host || myIp
var serverPort = argv.server || 2503

// id needed for per client identity
var id = myIp + ':' + serverPort

// name purely for pretty-ness
var name = argv.name || 'Anonymous'

function Chat(id, name) {
    // Each node needs a messages thing
    var chat = new EventEmitter()
    chat.setMaxListeners(Infinity)

    // keep track of history
    var history = chat.history = []
    var clock = chat.clock = {}

    // We should be able to send messages locally
    chat.send = function (text) {
        chat.emit('message', {
            text: text,
            name: name,
            id: id,
            time: Date.now()
        })
    }

    // Create a stream for sending and receiving messages
    // When we receieve a message from the stream we should
    // call .receive
    // When we have a message emmitted we should queue it
    // unless we emitted it ourselves to avoid an infinite loop
    // This means we should always pass along the stream to
    // receive
    chat.createStream = function () {
        var stream = MessageStream(function (message) {
            // Handle history messages
            if (typeof message.since === "number") {
                console.log(message.id + ' requests messages since:', message.since)
                history.forEach(function (e) {
                    if(e.time > message.since) {
                        stream.queue(e)
                    }
                })
            // otherwise receive the message
            } else {
                chat.receive(message, stream)
            }
        })

        // on message send down stream
        chat.on('message', function (message, source) {
            if (source !== stream) {
                stream.queue(message)
            }
        })

        // send the history receival handshake
        stream.queue({ since: chat.latest(), id: id })

        return stream
    }

    // we should be able to receive messages from a network
    chat.receive = function (message, source) {
        chat.emit('message', message, source)
    }

    // on message store in history & print
    chat.on('message', function (message) {
        // check to see whether message already handled
        if (clock[message.id] == null || clock[message.id] < message.time) {
            // update clock
            clock[message.id] = message.time

            chat.history.push(message)
            console.log(message.name + ' > ' + message.text)
        }
    })

    //get the lastest message we know.
    chat.latest = function () {
        return history.reduce(function (max, e) {
            return max.time > e.time ? max : e
        }, {time: 0}).time
    }

    return chat
}

var chat = Chat(id, name)
process.stdin.on('data', function (text) {
    chat.send(String(text))
})

//if (argv.server) {
    var server = net.createServer(function (stream) {
        stream.pipe(chat.createStream()).pipe(stream)
    })

    server.listen(serverPort)
    console.log('Started server on port', serverPort)
//} else {
    // connection logic in function for retries
    ;(function connect () {
        var hosts = Object.keys(chat.clock).map(function (e) {
          var p = e.split(':')
          return {host: p[0], port: p[1]}
        }).filter(function (e) {
          return serverPort != e.port || myIp != e.host
        })

        var random = hosts[~~(Math.random() * hosts.length)]
            || {host: seedHost, port: seedPort}

        console.log('Attempt connection to:', random)

        if(random.host == myIp && random.port == serverPort) {
           console.log('do not connect to self')
           return reconnect()
        }

        var client = net.connect(random.port, random.host, function () {
            client.pipe(chat.createStream()).pipe(client)
            console.log('Connected to server on port', random.port)
            setTimeout(function() {
              client.end()
            }, 5000)
        })

        // retry on end or error
        client.on('error', reconnect)
        client.on('close', reconnect)

        function reconnect () {
            if(client) client.removeAllListeners()
            setTimeout(function () {
                connect()
            }, 1000)
        }
    })()
//}
<|endoftext|>