<commit_before>window.requestAnimFrame = function(){
    return (
            window.requestAnimationFrame       ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame    ||
            window.oRequestAnimationFrame      ||
            window.msRequestAnimationFrame     ||
            function(/* function */ callback){
                window.setTimeout(callback, 1000 / 60);
            }
        );
}();

(function (global, document) {

  // Whiteboard -- a class that hooks into an element and handles input
  // it can also receive draw events and write to it
  //
  // WhiteboardClient -- connects to server and will send and receive messages. manages the whole communication thing
  // MessageBus -- brokers communication between  Whiteboard and WhiteboardClient.

  var MessageBus = function() {
    this.subscribers = {};
  };

  MessageBus.prototype.subscribe = function( messageType, handler ) {
    if ( typeof this.subscribers[messageType] === 'undefined' ) {
      this.subscribers[messageType] = [];
    }

    this.subscribers[messageType].push(handler);

    return this;
  };

  MessageBus.prototype.broadcast = function( messageType, message ) {
    var subscribers = this.subscribers[messageType];

    // if there's no subscribers
    if ( typeof subscribers === 'undefined' || subscribers.length === 0 ) {
      // console.log( 'not able to broadcast ' + messageType + ' because of no subscribers' );
      return;
    }

    for( subscriber in subscribers ) {
      // console.log({"broadcasting to": subscribers[subscriber], "message": message});
      subscribers[subscriber]( messageType, message );
    }
  }

  var WhiteboardClient = function( host, messageBus ) {
    this.messageBus = messageBus
                        .subscribe( 'draw', this.receiveDraw.bind(this) );
                        // .subscribe( 'update', this, this.receiveUpdate.bind(this) );

    this.connect( host );
  };

  WhiteboardClient.prototype.connect = function( host ) {
    var messageBus = this.messageBus;

    this.ws = new WebSocket( host );

    // handle the connection to the server
    // request the user list
    this.ws.onopen = function() {
      console.log('connected websocket!')
      this.requestUserList();
    }.bind(this);

    this.ws.onclose = function() { console.log('lost connection to websocket!') };

    // handle receiving a message.
    this.ws.onmessage = function(msg) {
      var data = JSON.parse(msg.data),
          event = data.event,
          payload = data.payload;

      switch (event) {
      case "user_list":
        this.messageBus.broadcast('receive_user_list', payload);
        break;

      case "draw":
        this.messageBus.broadcast('receive_draw', payload);
        break;

      case "pen_up":
        this.messageBus.broadcast('receive_pen_up', payload);
        break;

      case "user_join":
        this.messageBus.broadcast('receive_user_join', payload);
        break;

      case "user_part":
        this.messageBus.broadcast('receive_user_part', payload);
        break;

      default:
        console.log("got unknown packet type: " + event);
      }
    }.bind(this);
  };

  WhiteboardClient.prototype.requestUserList = function() {
    this.send( 'user_list', {} );
  }

  WhiteboardClient.prototype.send = function( event, payload) {
    delete payload.pointer;

    var packet = {
      event: event,
      payload: payload
    };

    this.ws.send( JSON.stringify(packet) );

    return this;
  };

  // received a draw event from the local whiteboard
  WhiteboardClient.prototype.receiveDraw = function( messageType, message ) {
    // console.log({ 'type': messageType, 'got message': message });

    this.sendDraw( message );
  };

  // send a draw message back up to the server
  WhiteboardClient.prototype.sendDraw = function( message ) {
    this.send( 'draw', message );

    return this;
  };

  var Whiteboard = function( host, element ) {
    this.whiteboard = element;
    this.messageBus = new MessageBus()
                            .subscribe( 'receive_draw',   this.handleUpdate.bind(this) )
                            .subscribe( 'receive_pen_up', this.handlePenUp.bind(this) );
                            // .subscribe( 'set_penColor',   this.handleSetPenColor.bind(this) )
                            // .subscribe( 'set_penWidth',   this.handleSetPenWidth.bind(this) );

    this.client = new WhiteboardClient( host, this.messageBus );

    // default sizing ( 2x larger than 1080 )
    this.defaultWidth = 1920 * 2;
    this.defaultHeight = 1080 * 2;

    // initialize offscreen context
    this.image = this.createImage( this.defaultWidth, this.defaultHeight );
    this.imageCtx = this.image.getContext('2d');
    this.whiteboardCtx = this.whiteboard.getContext('2d');

    this.zoomRatio = 0.5; // 50% zoom

    // the x/y of the view's upper-left corner compared to the main image
    this.scrollX = 0;
    this.scrollY = 0;

    // initialize some of our state
    this.penWidth = 4;
    this.penColor = "FF0000";

    // local state of the pen
    // (used for tracking the difference between mousedrag and mousemove)
    this.penDown = false;

    // store where each user's pen is (for connecting lines)
    this.penStatuses = {}; // hash keyed by userId

    // some initialization functions
    this.resizeWhiteboard();
    this.initializeListeners();
  };

  Whiteboard.prototype.createImage = function( width, height ) {
    var buffer = document.createElement('canvas'),
        ctx = buffer.getContext('2d');

    buffer.width = width;
    buffer.height = height;

    // fill with white
    ctx.fillStyle = '#ffffff';
    ctx.fillRect(0, 0, width, height);

    return buffer;
  }

  Whiteboard.prototype.resizeWhiteboard = function() {
    // resize the canvas a bit
    var body = document.getElementsByTagName('body')[0],
        fullsizeWidth = body.offsetWidth,
        fullsizeHeight = window.innerHeight;

    this.whiteboard.width = fullsizeWidth;
    this.whiteboard.height = fullsizeHeight;
  };

  Whiteboard.prototype.handle = function( eventName, callback ) {
    this.whiteboard.addEventListener( eventName, callback, false );
  };

  // hook into all the event handlers
  Whiteboard.prototype.initializeListeners = function() {
    // touch
    this.handle( 'touchstart', this.handleTouchStart.bind(this) );
    this.handle( 'touchend',   this.handleTouchEnd.bind(this)   );
    this.handle( 'touchmove',  this.handleTouchMove.bind(this)  );

    // mouse
    this.handle( 'mousedown',  this.handleMouseDown.bind(this)  );
    this.handle( 'mouseup',    this.handleMouseUp.bind(this)    );
    this.handle( 'mousemove',  this.handleMouseMove.bind(this)  );

    this.handle( 'mousewheel', function(event) {
      event.preventDefault();

      var dx = event.wheelDeltaX,
          dy = event.wheelDeltaY,
          inverted = event.webkitDirectionInvertedFromDevice;

      this.scroll( dx, dy, inverted );
    }.bind(this))
  };

  Whiteboard.prototype.scroll = function( dx, dy, is_inverted ) {
    if (is_inverted) {
      dx = -dx;
      dy = -dy;
    }

    this.scrollX -= dx;
    this.scrollY -= dy;

    if (this.scrollX < 0) {
      this.scrollX = 0;
    } else if ( this.scrollX > this.image.width - this.whiteboard.width ) {
      this.scrollX = this.image.width - this.whiteboard.width;
    }

    if (this.scrollY < 0) {
      this.scrollY = 0;
    } else if ( this.scrollY > this.image.height - this.whiteboard.height ) {
      this.scrollY = this.image.height - this.whiteboard.height;
    }

    this.redraw();
  };

  Whiteboard.prototype.redraw = function() {
    window.requestAnimFrame(function() {
      this.whiteboardCtx.drawImage(
        this.image,
        this.scrollX,
        this.scrollY,
        this.whiteboard.width,
        this.whiteboard.height,
        0,
        0,
        this.whiteboard.width,
        this.whiteboard.height
      );
    }.bind(this));
  };

  Whiteboard.prototype.handleTouchStart = function( event ) {
    event.preventDefault();

    var touch = event.changedTouches[0];

    this.sendDrawEvent( 'touch', touch.clientX, touch.clientY );
  };

  Whiteboard.prototype.handleTouchEnd = function( event ) {
    event.preventDefault();

    this.penDown = false;

    this.client.send( 'pen_up', {} );
  };

  Whiteboard.prototype.handleTouchMove = function( event ) {
    event.preventDefault();

    var touch = event.changedTouches[0];

    this.sendDrawEvent( 'touch', touch.clientX, touch.clientY );
  };

  Whiteboard.prototype.handleMouseDown = function( event ) {
    event.preventDefault();

    this.penDown = true;

    var x = event.clientX,
        y = event.clientY;

    this.sendDrawEvent( 'mouse', x, y );
  };

  Whiteboard.prototype.handleMouseUp = function( event ) {
    event.preventDefault();

    this.penDown = false;
    this.client.send( 'pen_up', {} );

  };

  Whiteboard.prototype.handleMouseMove = function( event ) {
    event.preventDefault();

    // if the mouse isn't down, it's not a drag event.
    if ( ! this.penDown ) { return; }

    var x = event.clientX,
        y = event.clientY;

    this.sendDrawEvent( 'mouse', x, y );
  };

  Whiteboard.prototype.sendDrawEvent = function( pointer, x, y ) {
    this.messageBus.broadcast( 'draw', {
      pointer: pointer,
      x: x + this.scrollX,
      y: y + this.scrollY,
      penWidth: this.penWidth,
      penColor: this.penColor
    } );
  };

  Whiteboard.prototype.handleUpdate = function( messageType, message ) {
    var ctx         = this.imageCtx,
        last        = this.penStatuses[message.userId],
        userId      = message.userId.replace(/[^a-z0-9]/ig, ''),
        userEle     = document.getElementById(userId);
        onscreenCtx = this.whiteboardCtx;

    // set background on this user
    userEle.style.backgroundColor = "#" + message.penColor;

    ctx.fillStyle = "#" + message.penColor;
    // ctx.fillRect( message.x, message.y, 2, 2 );

    ctx.beginPath();
    if ( last ) {
      ctx.moveTo(last.x, last.y);
      ctx.lineTo(message.x, message.y);
      ctx.lineWidth = message.penWidth;
      ctx.strokeStyle = "#" + message.penColor;
      ctx.stroke();
    }

    ctx.arc(message.x, message.y, message.penWidth / 2, 0,2*Math.PI, false);
    ctx.fill();

    this.penStatuses[message.userId] = { x: message.x, y: message.y };

    // render offscreen image to onscreen canvas
    this.redraw();
  };

  Whiteboard.prototype.handlePenUp = function( messageType, message ) {
    var userId = message.userId
        userEleId = message.userId.replace(/[^a-z0-9]/ig, ''),
        userEle = document.getElementById(userEleId);

    userEle.style.backgroundColor = "transparent";

    delete this.penStatuses[userId];
  };

  global.MessageBus = MessageBus;
  global.WhiteboardClient = WhiteboardClient;
  global.Whiteboard = Whiteboard;

  global.whiteboard = new Whiteboard( 'ws://' + window.location.host + '/websocket' + window.location.search, document.getElementById('whiteboard') );

  global.whiteboard.messageBus.subscribe( 'receive_user_list', function( _event, users ) {
    console.log({got_user_list: users});

    var i, user;

    for ( i in users ) {
      user = users[i];
      addUser( user );
    }
  })
  .subscribe( 'receive_user_join', function( _event, userInfo ) {
    addUser(userInfo);
  })
  .subscribe( 'receive_user_part', function( _event, userInfo) {
    removeUser(userInfo);
  });

  function addUser( user ) {
    var user_list_ele = document.getElementById('user-list'),
        userId = user.userId.replace(/[^a-z0-9]/ig, '');

    user_list_ele.innerHTML += '
' + user.nick + '
';
  }

  function removeUser( user ) {
    var userListEle = document.getElementById('user-list'),
        userId = user.userId.replace(/[^a-z0-9]/ig, ''),
        userEle = document.getElementById(userId);

    userListEle.removeChild( userEle );
  }

  var control_toggle_btn = document.getElementById('hideshow'),
      tools_ele = document.getElementById('form');

  control_toggle_btn.addEventListener( 'click', function() {
    if ( this.innerHTML == 'X' ) {
      this.innerHTML = '>';
      tools_ele.style.display = 'none';
    } else {
      this.innerHTML = 'X';
      tools_ele.style.display = 'block';
    }
  });

  // TODO: rewrite all this shit here. leverage some messageBus goodness.
  document.getElementById('pen-width-input').addEventListener( 'input', function() {
    var value = this.value;

    value = parseInt(value);

    if ( value > 0 ) {
      global.whiteboard.penWidth = value;
    }
  });

  document.getElementById('pen-color-input').addEventListener( 'input', function() {
    var value = this.value;

    if ( value.match(/^[a-f0-9]{6}/i) ) {
      global.whiteboard.penColor = value;
    }
  });

})(window, document);
<commit_msg>default value for is_inverted in scroll function<commit_after>window.requestAnimFrame = function(){
    return (
            window.requestAnimationFrame       ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame    ||
            window.oRequestAnimationFrame      ||
            window.msRequestAnimationFrame     ||
            function(/* function */ callback){
                window.setTimeout(callback, 1000 / 60);
            }
        );
}();

(function (global, document) {

  // Whiteboard -- a class that hooks into an element and handles input
  // it can also receive draw events and write to it
  //
  // WhiteboardClient -- connects to server and will send and receive messages. manages the whole communication thing
  // MessageBus -- brokers communication between  Whiteboard and WhiteboardClient.

  var MessageBus = function() {
    this.subscribers = {};
  };

  MessageBus.prototype.subscribe = function( messageType, handler ) {
    if ( typeof this.subscribers[messageType] === 'undefined' ) {
      this.subscribers[messageType] = [];
    }

    this.subscribers[messageType].push(handler);

    return this;
  };

  MessageBus.prototype.broadcast = function( messageType, message ) {
    var subscribers = this.subscribers[messageType];

    // if there's no subscribers
    if ( typeof subscribers === 'undefined' || subscribers.length === 0 ) {
      // console.log( 'not able to broadcast ' + messageType + ' because of no subscribers' );
      return;
    }

    for( subscriber in subscribers ) {
      // console.log({"broadcasting to": subscribers[subscriber], "message": message});
      subscribers[subscriber]( messageType, message );
    }
  }

  var WhiteboardClient = function( host, messageBus ) {
    this.messageBus = messageBus
                        .subscribe( 'draw', this.receiveDraw.bind(this) );
                        // .subscribe( 'update', this, this.receiveUpdate.bind(this) );

    this.connect( host );
  };

  WhiteboardClient.prototype.connect = function( host ) {
    var messageBus = this.messageBus;

    this.ws = new WebSocket( host );

    // handle the connection to the server
    // request the user list
    this.ws.onopen = function() {
      console.log('connected websocket!')
      this.requestUserList();
    }.bind(this);

    this.ws.onclose = function() { console.log('lost connection to websocket!') };

    // handle receiving a message.
    this.ws.onmessage = function(msg) {
      var data = JSON.parse(msg.data),
          event = data.event,
          payload = data.payload;

      switch (event) {
      case "user_list":
        this.messageBus.broadcast('receive_user_list', payload);
        break;

      case "draw":
        this.messageBus.broadcast('receive_draw', payload);
        break;

      case "pen_up":
        this.messageBus.broadcast('receive_pen_up', payload);
        break;

      case "user_join":
        this.messageBus.broadcast('receive_user_join', payload);
        break;

      case "user_part":
        this.messageBus.broadcast('receive_user_part', payload);
        break;

      default:
        console.log("got unknown packet type: " + event);
      }
    }.bind(this);
  };

  WhiteboardClient.prototype.requestUserList = function() {
    this.send( 'user_list', {} );
  }

  WhiteboardClient.prototype.send = function( event, payload) {
    delete payload.pointer;

    var packet = {
      event: event,
      payload: payload
    };

    this.ws.send( JSON.stringify(packet) );

    return this;
  };

  // received a draw event from the local whiteboard
  WhiteboardClient.prototype.receiveDraw = function( messageType, message ) {
    // console.log({ 'type': messageType, 'got message': message });

    this.sendDraw( message );
  };

  // send a draw message back up to the server
  WhiteboardClient.prototype.sendDraw = function( message ) {
    this.send( 'draw', message );

    return this;
  };

  var Whiteboard = function( host, element ) {
    this.whiteboard = element;
    this.messageBus = new MessageBus()
                            .subscribe( 'receive_draw',   this.handleUpdate.bind(this) )
                            .subscribe( 'receive_pen_up', this.handlePenUp.bind(this) );
                            // .subscribe( 'set_penColor',   this.handleSetPenColor.bind(this) )
                            // .subscribe( 'set_penWidth',   this.handleSetPenWidth.bind(this) );

    this.client = new WhiteboardClient( host, this.messageBus );

    // default sizing ( 2x larger than 1080 )
    this.defaultWidth = 1920 * 2;
    this.defaultHeight = 1080 * 2;

    // initialize offscreen context
    this.image = this.createImage( this.defaultWidth, this.defaultHeight );
    this.imageCtx = this.image.getContext('2d');
    this.whiteboardCtx = this.whiteboard.getContext('2d');

    this.zoomRatio = 0.5; // 50% zoom

    // the x/y of the view's upper-left corner compared to the main image
    this.scrollX = 0;
    this.scrollY = 0;

    // initialize some of our state
    this.penWidth = 4;
    this.penColor = "FF0000";

    // local state of the pen
    // (used for tracking the difference between mousedrag and mousemove)
    this.penDown = false;

    // store where each user's pen is (for connecting lines)
    this.penStatuses = {}; // hash keyed by userId

    // some initialization functions
    this.resizeWhiteboard();
    this.initializeListeners();
  };

  Whiteboard.prototype.createImage = function( width, height ) {
    var buffer = document.createElement('canvas'),
        ctx = buffer.getContext('2d');

    buffer.width = width;
    buffer.height = height;

    // fill with white
    ctx.fillStyle = '#ffffff';
    ctx.fillRect(0, 0, width, height);

    return buffer;
  }

  Whiteboard.prototype.resizeWhiteboard = function() {
    // resize the canvas a bit
    var body = document.getElementsByTagName('body')[0],
        fullsizeWidth = body.offsetWidth,
        fullsizeHeight = window.innerHeight;

    this.whiteboard.width = fullsizeWidth;
    this.whiteboard.height = fullsizeHeight;
  };

  Whiteboard.prototype.handle = function( eventName, callback ) {
    this.whiteboard.addEventListener( eventName, callback, false );
  };

  // hook into all the event handlers
  Whiteboard.prototype.initializeListeners = function() {
    // touch
    this.handle( 'touchstart', this.handleTouchStart.bind(this) );
    this.handle( 'touchend',   this.handleTouchEnd.bind(this)   );
    this.handle( 'touchmove',  this.handleTouchMove.bind(this)  );

    // mouse
    this.handle( 'mousedown',  this.handleMouseDown.bind(this)  );
    this.handle( 'mouseup',    this.handleMouseUp.bind(this)    );
    this.handle( 'mousemove',  this.handleMouseMove.bind(this)  );

    this.handle( 'mousewheel', function(event) {
      event.preventDefault();

      var dx = event.wheelDeltaX,
          dy = event.wheelDeltaY,
          inverted = event.webkitDirectionInvertedFromDevice;

      this.scroll( dx, dy, inverted );
    }.bind(this))
  };

  Whiteboard.prototype.scroll = function( dx, dy, is_inverted ) {
    if ( typeof is_inverted === 'undefined' ) { is_inverted = false; }

    if (is_inverted) {
      dx = -dx;
      dy = -dy;
    }

    this.scrollX -= dx;
    this.scrollY -= dy;

    if (this.scrollX < 0) {
      this.scrollX = 0;
    } else if ( this.scrollX > this.image.width - this.whiteboard.width ) {
      this.scrollX = this.image.width - this.whiteboard.width;
    }

    if (this.scrollY < 0) {
      this.scrollY = 0;
    } else if ( this.scrollY > this.image.height - this.whiteboard.height ) {
      this.scrollY = this.image.height - this.whiteboard.height;
    }

    this.redraw();
  };

  Whiteboard.prototype.redraw = function() {
    window.requestAnimFrame(function() {
      this.whiteboardCtx.drawImage(
        this.image,
        this.scrollX,
        this.scrollY,
        this.whiteboard.width,
        this.whiteboard.height,
        0,
        0,
        this.whiteboard.width,
        this.whiteboard.height
      );
    }.bind(this));
  };

  Whiteboard.prototype.handleTouchStart = function( event ) {
    event.preventDefault();

    var touch = event.changedTouches[0];

    this.sendDrawEvent( 'touch', touch.clientX, touch.clientY );
  };

  Whiteboard.prototype.handleTouchEnd = function( event ) {
    event.preventDefault();

    this.penDown = false;

    this.client.send( 'pen_up', {} );
  };

  Whiteboard.prototype.handleTouchMove = function( event ) {
    event.preventDefault();

    var touch = event.changedTouches[0];

    this.sendDrawEvent( 'touch', touch.clientX, touch.clientY );
  };

  Whiteboard.prototype.handleMouseDown = function( event ) {
    event.preventDefault();

    this.penDown = true;

    var x = event.clientX,
        y = event.clientY;

    this.sendDrawEvent( 'mouse', x, y );
  };

  Whiteboard.prototype.handleMouseUp = function( event ) {
    event.preventDefault();

    this.penDown = false;
    this.client.send( 'pen_up', {} );

  };

  Whiteboard.prototype.handleMouseMove = function( event ) {
    event.preventDefault();

    // if the mouse isn't down, it's not a drag event.
    if ( ! this.penDown ) { return; }

    var x = event.clientX,
        y = event.clientY;

    this.sendDrawEvent( 'mouse', x, y );
  };

  Whiteboard.prototype.sendDrawEvent = function( pointer, x, y ) {
    this.messageBus.broadcast( 'draw', {
      pointer: pointer,
      x: x + this.scrollX,
      y: y + this.scrollY,
      penWidth: this.penWidth,
      penColor: this.penColor
    } );
  };

  Whiteboard.prototype.handleUpdate = function( messageType, message ) {
    var ctx         = this.imageCtx,
        last        = this.penStatuses[message.userId],
        userId      = message.userId.replace(/[^a-z0-9]/ig, ''),
        userEle     = document.getElementById(userId);
        onscreenCtx = this.whiteboardCtx;

    // set background on this user
    userEle.style.backgroundColor = "#" + message.penColor;

    ctx.fillStyle = "#" + message.penColor;
    // ctx.fillRect( message.x, message.y, 2, 2 );

    ctx.beginPath();
    if ( last ) {
      ctx.moveTo(last.x, last.y);
      ctx.lineTo(message.x, message.y);
      ctx.lineWidth = message.penWidth;
      ctx.strokeStyle = "#" + message.penColor;
      ctx.stroke();
    }

    ctx.arc(message.x, message.y, message.penWidth / 2, 0,2*Math.PI, false);
    ctx.fill();

    this.penStatuses[message.userId] = { x: message.x, y: message.y };

    // render offscreen image to onscreen canvas
    this.redraw();
  };

  Whiteboard.prototype.handlePenUp = function( messageType, message ) {
    var userId = message.userId
        userEleId = message.userId.replace(/[^a-z0-9]/ig, ''),
        userEle = document.getElementById(userEleId);

    userEle.style.backgroundColor = "transparent";

    delete this.penStatuses[userId];
  };

  global.MessageBus = MessageBus;
  global.WhiteboardClient = WhiteboardClient;
  global.Whiteboard = Whiteboard;

  global.whiteboard = new Whiteboard( 'ws://' + window.location.host + '/websocket' + window.location.search, document.getElementById('whiteboard') );

  global.whiteboard.messageBus.subscribe( 'receive_user_list', function( _event, users ) {
    console.log({got_user_list: users});

    var i, user;

    for ( i in users ) {
      user = users[i];
      addUser( user );
    }
  })
  .subscribe( 'receive_user_join', function( _event, userInfo ) {
    addUser(userInfo);
  })
  .subscribe( 'receive_user_part', function( _event, userInfo) {
    removeUser(userInfo);
  });

  function addUser( user ) {
    var user_list_ele = document.getElementById('user-list'),
        userId = user.userId.replace(/[^a-z0-9]/ig, '');

    user_list_ele.innerHTML += '
' + user.nick + '
';
  }

  function removeUser( user ) {
    var userListEle = document.getElementById('user-list'),
        userId = user.userId.replace(/[^a-z0-9]/ig, ''),
        userEle = document.getElementById(userId);

    userListEle.removeChild( userEle );
  }

  var control_toggle_btn = document.getElementById('hideshow'),
      tools_ele = document.getElementById('form');

  control_toggle_btn.addEventListener( 'click', function() {
    if ( this.innerHTML == 'X' ) {
      this.innerHTML = '>';
      tools_ele.style.display = 'none';
    } else {
      this.innerHTML = 'X';
      tools_ele.style.display = 'block';
    }
  });

  // TODO: rewrite all this shit here. leverage some messageBus goodness.
  document.getElementById('pen-width-input').addEventListener( 'input', function() {
    var value = this.value;

    value = parseInt(value);

    if ( value > 0 ) {
      global.whiteboard.penWidth = value;
    }
  });

  document.getElementById('pen-color-input').addEventListener( 'input', function() {
    var value = this.value;

    if ( value.match(/^[a-f0-9]{6}/i) ) {
      global.whiteboard.penColor = value;
    }
  });

})(window, document);
<|endoftext|>


<commit_before>/**
 * Copyright 2015 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * The entry point for AMP Runtime (v0.js) when AMP Runtime = AMP Doc.
 */

// src/polyfills.js must be the first import.
import './polyfills';

import {Services} from './services';
import {TickLabel} from './enums';
import {adoptWithMultidocDeps} from './runtime';
import {cssText as ampDocCss} from '../build/ampdoc.css';
import {cssText as ampSharedCss} from '../build/ampshared.css';
import {fontStylesheetTimeout} from './font-stylesheet-timeout';
import {getMode} from './mode';
import {
  installAmpdocServices,
  installBuiltinElements,
  installRuntimeServices,
} from './service/core-services';
import {installAutoLightboxExtension} from './auto-lightbox';
import {installDocService} from './service/ampdoc-impl';
import {installErrorReporting} from './error';
import {installPerformanceService} from './service/performance-impl';
import {installPlatformService} from './service/platform-impl';
import {installPullToRefreshBlocker} from './pull-to-refresh';
import {installStandaloneExtension} from './standalone';
import {
  installStylesForDoc,
  makeBodyVisible,
  makeBodyVisibleRecovery,
} from './style-installer';
import {internalRuntimeVersion} from './internal-version';
import {maybeTrackImpression} from './impression';
import {maybeValidate} from './validator-integration';
import {preconnectToOrigin} from './preconnect';
import {startupChunk} from './chunk';
import {stubElementsForDoc} from './service/custom-element-registry';

/**
 * self.IS_AMP_ALT (is AMP alternative binary) is undefined by default in the
 * main v0.js since it is the "main" js.
 * This global boolean is set by alternative binaries like amp-inabox and
 * amp-shadow which has their own bootstrapping sequence.
 * With how single pass works these alternative binaries cannot be generated
 * easily because we can only do a "single pass" so we treat these alternative
 * main binaries as "extensions" and we concatenate their code with the main
 * v0.js code.
 * @type {boolean|undefined}
 */
const shouldMainBootstrapRun = !self.IS_AMP_ALT;

/**
 * Execute the bootstrap
 * @param {!./service/ampdoc-impl.AmpDoc} ampdoc
 * @param {!./service/performance-impl.Performance} perf
 */
function bootstrap(ampdoc, perf) {
  startupChunk(self.document, function services() {
    // Core services.
    installRuntimeServices(self);
    installAmpdocServices(ampdoc);
    // We need the core services (viewer/resources) to start instrumenting
    perf.coreServicesAvailable();
    maybeTrackImpression(self);
  });
  startupChunk(self.document, function adoptWindow() {
    adoptWithMultidocDeps(self);
  });
  startupChunk(self.document, function builtins() {
    // Builtins.
    installBuiltinElements(self);
  });
  startupChunk(self.document, function stub() {
    // Pre-stub already known elements.
    stubElementsForDoc(ampdoc);
  });
  startupChunk(
    self.document,
    function final() {
      if (!IS_SXG) {
        installPullToRefreshBlocker(self);
      }
      installAutoLightboxExtension(ampdoc);
      installStandaloneExtension(ampdoc);
      maybeValidate(self);
      makeBodyVisible(self.document);
      preconnectToOrigin(self.document);
    },
    /* makes the body visible */ true
  );
  startupChunk(self.document, function finalTick() {
    perf.tick(TickLabel.END_INSTALL_STYLES);
    Services.resourcesForDoc(ampdoc).ampInitComplete();
    // TODO(erwinm): move invocation of the `flush` method when we have the
    // new ticks in place to batch the ticks properly.
    perf.flush();
  });
}

if (shouldMainBootstrapRun) {
  // Store the originalHash as early as possible. Trying to debug:
  // https://github.com/ampproject/amphtml/issues/6070
  if (self.location) {
    self.location.originalHash = self.location.hash;
  }

  /** @type {!./service/ampdoc-impl.AmpDocService} */
  let ampdocService;
  // We must under all circumstances call makeBodyVisible.
  // It is much better to have AMP tags not rendered than having
  // a completely blank page.
  try {
    // Should happen first.
    installErrorReporting(self); // Also calls makeBodyVisibleRecovery on errors.

    // Declare that this runtime will support a single root doc. Should happen
    // as early as possible.
    installDocService(self, /* isSingleDoc */ true);
    ampdocService = Services.ampdocServiceFor(self);
  } catch (e) {
    // In case of an error call this.
    makeBodyVisibleRecovery(self.document);
    throw e;
  }
  startupChunk(self.document, function initial() {
    /** @const {!./service/ampdoc-impl.AmpDoc} */
    const ampdoc = ampdocService.getAmpDoc(self.document);
    installPlatformService(self);
    installPerformanceService(self);
    /** @const {!./service/performance-impl.Performance} */
    const perf = Services.performanceFor(self);
    if (
      self.document.documentElement.hasAttribute('i-amphtml-no-boilerplate')
    ) {
      perf.addEnabledExperiment('no-boilerplate');
    }
    if (IS_ESM) {
      perf.addEnabledExperiment('esm');
    }
    fontStylesheetTimeout(self);
    perf.tick(TickLabel.INSTALL_STYLES);
    if (IS_ESM) {
      bootstrap(ampdoc, perf);
    } else {
      installStylesForDoc(
        ampdoc,
        ampDocCss + ampSharedCss,
        () => bootstrap(ampdoc, perf),
        /* opt_isRuntimeCss */ true,
        /* opt_ext */ 'amp-runtime'
      );
    }
  });

  // Output a message to the console and add an attribute to the <html>
  // tag to give some information that can be used in error reports.
  // (At least by sophisticated users).
  if (self.console) {
    (console.info || console.log).call(
      console,
      `Powered by AMP ⚡ HTML – Version ${internalRuntimeVersion()}`,
      self.location.href
    );
  }
  // This code is eleminated in prod build through a babel transformer.
  if (getMode().localDev) {
    self.document.documentElement.setAttribute('esm', IS_ESM ? 1 : 0);
  }
  self.document.documentElement.setAttribute(
    'amp-version',
    internalRuntimeVersion()
  );
}
<commit_msg>amp.js: remove reference to single-pass (#32007)<commit_after>/**
 * Copyright 2015 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * The entry point for AMP Runtime (v0.js) when AMP Runtime = AMP Doc.
 */

// src/polyfills.js must be the first import.
import './polyfills';

import {Services} from './services';
import {TickLabel} from './enums';
import {adoptWithMultidocDeps} from './runtime';
import {cssText as ampDocCss} from '../build/ampdoc.css';
import {cssText as ampSharedCss} from '../build/ampshared.css';
import {fontStylesheetTimeout} from './font-stylesheet-timeout';
import {getMode} from './mode';
import {
  installAmpdocServices,
  installBuiltinElements,
  installRuntimeServices,
} from './service/core-services';
import {installAutoLightboxExtension} from './auto-lightbox';
import {installDocService} from './service/ampdoc-impl';
import {installErrorReporting} from './error';
import {installPerformanceService} from './service/performance-impl';
import {installPlatformService} from './service/platform-impl';
import {installPullToRefreshBlocker} from './pull-to-refresh';
import {installStandaloneExtension} from './standalone';
import {
  installStylesForDoc,
  makeBodyVisible,
  makeBodyVisibleRecovery,
} from './style-installer';
import {internalRuntimeVersion} from './internal-version';
import {maybeTrackImpression} from './impression';
import {maybeValidate} from './validator-integration';
import {preconnectToOrigin} from './preconnect';
import {startupChunk} from './chunk';
import {stubElementsForDoc} from './service/custom-element-registry';

/**
 * self.IS_AMP_ALT (is AMP alternative binary) is undefined by default in the
 * main v0.js since it is the "main" js.
 * This global boolean is set by alternative binaries like amp-inabox and
 * amp-shadow which has their own bootstrapping sequence.
 * @type {boolean|undefined}
 */
const shouldMainBootstrapRun = !self.IS_AMP_ALT;

/**
 * Execute the bootstrap
 * @param {!./service/ampdoc-impl.AmpDoc} ampdoc
 * @param {!./service/performance-impl.Performance} perf
 */
function bootstrap(ampdoc, perf) {
  startupChunk(self.document, function services() {
    // Core services.
    installRuntimeServices(self);
    installAmpdocServices(ampdoc);
    // We need the core services (viewer/resources) to start instrumenting
    perf.coreServicesAvailable();
    maybeTrackImpression(self);
  });
  startupChunk(self.document, function adoptWindow() {
    adoptWithMultidocDeps(self);
  });
  startupChunk(self.document, function builtins() {
    // Builtins.
    installBuiltinElements(self);
  });
  startupChunk(self.document, function stub() {
    // Pre-stub already known elements.
    stubElementsForDoc(ampdoc);
  });
  startupChunk(
    self.document,
    function final() {
      if (!IS_SXG) {
        installPullToRefreshBlocker(self);
      }
      installAutoLightboxExtension(ampdoc);
      installStandaloneExtension(ampdoc);
      maybeValidate(self);
      makeBodyVisible(self.document);
      preconnectToOrigin(self.document);
    },
    /* makes the body visible */ true
  );
  startupChunk(self.document, function finalTick() {
    perf.tick(TickLabel.END_INSTALL_STYLES);
    Services.resourcesForDoc(ampdoc).ampInitComplete();
    // TODO(erwinm): move invocation of the `flush` method when we have the
    // new ticks in place to batch the ticks properly.
    perf.flush();
  });
}

if (shouldMainBootstrapRun) {
  // Store the originalHash as early as possible. Trying to debug:
  // https://github.com/ampproject/amphtml/issues/6070
  if (self.location) {
    self.location.originalHash = self.location.hash;
  }

  /** @type {!./service/ampdoc-impl.AmpDocService} */
  let ampdocService;
  // We must under all circumstances call makeBodyVisible.
  // It is much better to have AMP tags not rendered than having
  // a completely blank page.
  try {
    // Should happen first.
    installErrorReporting(self); // Also calls makeBodyVisibleRecovery on errors.

    // Declare that this runtime will support a single root doc. Should happen
    // as early as possible.
    installDocService(self, /* isSingleDoc */ true);
    ampdocService = Services.ampdocServiceFor(self);
  } catch (e) {
    // In case of an error call this.
    makeBodyVisibleRecovery(self.document);
    throw e;
  }
  startupChunk(self.document, function initial() {
    /** @const {!./service/ampdoc-impl.AmpDoc} */
    const ampdoc = ampdocService.getAmpDoc(self.document);
    installPlatformService(self);
    installPerformanceService(self);
    /** @const {!./service/performance-impl.Performance} */
    const perf = Services.performanceFor(self);
    if (
      self.document.documentElement.hasAttribute('i-amphtml-no-boilerplate')
    ) {
      perf.addEnabledExperiment('no-boilerplate');
    }
    if (IS_ESM) {
      perf.addEnabledExperiment('esm');
    }
    fontStylesheetTimeout(self);
    perf.tick(TickLabel.INSTALL_STYLES);
    if (IS_ESM) {
      bootstrap(ampdoc, perf);
    } else {
      installStylesForDoc(
        ampdoc,
        ampDocCss + ampSharedCss,
        () => bootstrap(ampdoc, perf),
        /* opt_isRuntimeCss */ true,
        /* opt_ext */ 'amp-runtime'
      );
    }
  });

  // Output a message to the console and add an attribute to the <html>
  // tag to give some information that can be used in error reports.
  // (At least by sophisticated users).
  if (self.console) {
    (console.info || console.log).call(
      console,
      `Powered by AMP ⚡ HTML – Version ${internalRuntimeVersion()}`,
      self.location.href
    );
  }
  // This code is eleminated in prod build through a babel transformer.
  if (getMode().localDev) {
    self.document.documentElement.setAttribute('esm', IS_ESM ? 1 : 0);
  }
  self.document.documentElement.setAttribute(
    'amp-version',
    internalRuntimeVersion()
  );
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

var React = require('React');
var Site = require('Site');
var center = require('center');

var apps = [
  {
    name: 'Beetroot',
    icon: 'http://is1.mzstatic.com/image/pf/us/r30/Purple5/v4/66/fd/dd/66fddd70-f848-4fc5-43ee-4d52197ccab8/pr_source.png',
    link: 'https://itunes.apple.com/us/app/beetroot/id1016159001?ls=1&mt=8',
    author: 'Alex Duckmanton',
  },
  {
    name: 'Discord',
    icon: 'http://a5.mzstatic.com/us/r30/Purple5/v4/c1/2f/4c/c12f4cba-1d9a-f6bf-2240-04085d3470ec/icon175x175.jpeg',
    link:  'https://itunes.apple.com/us/app/discord-chat-for-gamers/id985746746?mt=8',
    author: 'Hammer & Chisel',
  },
  {
    name: 'Discovery VR',
    icon: 'http://a2.mzstatic.com/us/r30/Purple6/v4/d1/d5/f4/d1d5f437-9f6b-b5aa-5fe7-47bd19f934bf/icon175x175.png',
    link:  'https://itunes.apple.com/us/app/discovery-vr/id1030815031?mt=8',
    author: 'Discovery Communications',
  },
  {
    name: 'DropBot',
    icon: 'http://a2.mzstatic.com/us/r30/Purple69/v4/fb/df/73/fbdf73e0-22d2-c936-3115-1defa195acba/icon175x175.png',
    link:  'https://itunes.apple.com/us/app/dropbot-phone-replacement/id1000855694?mt=8',
    author: 'Peach Labs',
  },
  {
    name: 'Exponent',
    icon: 'http://a4.mzstatic.com/us/r30/Purple2/v4/3a/d3/c9/3ad3c96c-5e14-f988-4bdd-0fdc95efd140/icon175x175.png',
    link:  'https://itunes.apple.com/ca/app/exponent/id982107779?mt=8',
    author: 'Charlie Cheever & James Ide',
  },
  {
    name: 'F8',
    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple5/v4/bf/d9/50/bfd9504e-a1bd-67c5-b50b-24e97016dae9/pr_source.jpg',
    link: 'https://itunes.apple.com/us/app/f8/id853467066?mt=8',
    author: 'Facebook',
  },
  {
    name: 'Facebook Groups',
    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple69/v4/57/f8/4c/57f84c0c-793d-5f9a-95ee-c212d0369e37/mzl.ugjwfhzx.png',
    link: 'https://itunes.apple.com/us/app/facebook-groups/id931735837?mt=8',
    author: 'Facebook',
  },
  {
    name: 'Facebook Adverts Manager - Android',
    icon: 'https://lh3.googleusercontent.com/ODKlFYm7BaNiLMEEDO2b4DOCU-hmS1-Fg3_x_lLUaJZ0ssFsxciSoX1dYERaWDJuEs8=w300',
    link: 'https://play.google.com/store/apps/details?id=com.facebook.adsmanager',
    author: 'Facebook',
  },
  {
    name: 'Facebook Ads Manager - iOS',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple5/v4/9e/16/86/9e1686ef-cc55-805a-c977-538ddb5e6832/mzl.gqbhwitj.png',
    link: 'https://itunes.apple.com/us/app/facebook-ads-manager/id964397083?mt=8',
    author: 'Facebook',
  },
  {
    name: 'HSK Level 1 Chinese Flashcards',
    icon: 'http://is2.mzstatic.com/image/pf/us/r30/Purple1/v4/b2/4f/3a/b24f3ae3-2597-cc70-1040-731b425a5904/mzl.amxdcktl.jpg',
    link: 'https://itunes.apple.com/us/app/hsk-level-1-chinese-flashcards/id936639994',
    author: 'HS Schaaf',
  },
  {
    name: 'Leanpub',
    icon: 'http://a2.mzstatic.com/us/r30/Purple6/v4/9f/4a/6f/9f4a6f8c-8951-ed89-4083-74ace23df9ef/icon350x350.jpeg',
    link: 'https://itunes.apple.com/us/app/leanpub/id913517110?ls=1&mt=8',
    author: 'Leanpub',
  },
  {
    name: 'Lrn',
    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple1/v4/41/a9/e9/41a9e9b6-7801-aef7-2400-2eca14923321/mzl.adyswxad.png',
    link: 'https://itunes.apple.com/us/app/lrn-learn-to-code-at-your/id1019622677',
    author: 'Lrn Labs, Inc',
  },
  {
    name: 'Lumpen Radio',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple1/v4/46/43/00/464300b1-fae3-9640-d4a2-0eb050ea3ff2/mzl.xjjawige.png',
    link: 'https://itunes.apple.com/us/app/lumpen-radio/id1002193127?mt=8',
    author: 'Joshua Habdas',
  },
  {
    name: 'MinTrain',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple5/v4/51/51/68/51516875-1323-3100-31a8-cd1853d9a2c0/mzl.gozwmstp.png',
    link: 'https://itunes.apple.com/us/app/mintrain/id1015739031?mt=8',
    author: 'Peter Cottle',
  },
  {
    name: 'Mr. Dapper',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple4/v4/e8/3f/7c/e83f7cb3-2602-f8e8-de9a-ce0a775a4a14/mzl.hmdjhfai.png',
    link: 'https://itunes.apple.com/us/app/mr.-dapper-men-fashion-app/id989735184?ls=1&mt=8',
    author: 'wei ping woon',
  },
  {
    name: 'Ncredible',
    icon: 'http://a3.mzstatic.com/us/r30/Purple2/v4/a9/00/74/a9007400-7ccf-df10-553b-3b6cb67f3f5f/icon350x350.png',
    link: 'https://itunes.apple.com/ca/app/ncredible/id1019662810?mt=8',
    author: 'NBC News Digital, LLC',
  },
  {
    name: 'Night Light',
    icon: 'http://is3.mzstatic.com/image/pf/us/r30/Purple7/v4/5f/50/5f/5f505fe5-0a30-6bbf-6ed9-81ef09351aba/mzl.lkeqxyeo.png',
    link: 'https://itunes.apple.com/gb/app/night-light-feeding-light/id1016843582?mt=8',
    author: 'Tian Yuan',
  },
  {
    name: 'ReactTo36',
    icon: 'http://is2.mzstatic.com/image/pf/us/r30/Purple5/v4/e3/c8/79/e3c87934-70c6-4974-f20d-4adcfc68d71d/mzl.wevtbbkq.png',
    link: 'https://itunes.apple.com/us/app/reactto36/id989009293?mt=8',
    author: 'Jonathan Solichin',
  },
  {
    name: 'RN Playground',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple1/v4/20/ec/8e/20ec8eb8-9e12-6686-cd16-7ac9e3ef1d52/mzl.ngvuoybx.png',
    link: 'https://itunes.apple.com/us/app/react-native-playground/id1002032944?mt=8',
    author: 'Joshua Sierles',
  },
  {
    name: 'Start - medication manager for depression',
    icon: 'http://a1.mzstatic.com/us/r30/Purple49/v4/de/9b/6f/de9b6fe8-84ea-7a12-ba2c-0a6d6c7b10b0/icon175x175.png',
    link: 'https://itunes.apple.com/us/app/start-medication-manager-for/id1012099928?mt=8',
    author: 'Iodine Inc.',
  },
  {
    name: 'SG Toto 4d',
    icon: 'http://a4.mzstatic.com/us/r30/Purple7/v4/d2/bc/46/d2bc4696-84d6-9681-a49f-7f660d6b04a7/icon175x175.jpeg',
    link: 'https://itunes.apple.com/us/app/sg-toto-4d/id1006371481?mt=8',
    author: 'Steve Ng'
  },
  {
    name: 'Tabtor Parent',
    icon: 'http://a1.mzstatic.com/us/r30/Purple4/v4/80/50/9d/80509d05-18f4-a0b8-0cbb-9ba927d04477/icon175x175.jpeg',
    link: 'https://itunes.apple.com/us/app/tabtor-math/id1018651199?utm_source=ParentAppLP',
    author: 'PrazAs Learning Inc.',
  },
  {
    name: 'Tong Xing Wang',
    icon: 'http://a3.mzstatic.com/us/r30/Purple1/v4/7d/52/a7/7d52a71f-9532-82a5-b92f-87076624fdb2/icon175x175.jpeg',
    link: 'https://itunes.apple.com/cn/app/tong-xing-wang/id914254459?mt=8',
    author: 'Ho Yin Tsun Eugene',
  },
  {
    name: 'Yoloci',
    icon: 'http://a5.mzstatic.com/eu/r30/Purple7/v4/fa/e5/26/fae52635-b97c-bd53-2ade-89e2a4326745/icon175x175.jpeg',
    link: 'https://itunes.apple.com/de/app/yoloci/id991323225?mt=8',
    author: 'Yonduva GmbH (@PhilippKrone)',
  },
  {
    name: 'youmeyou',
    icon: 'http://is1.mzstatic.com/image/pf/us/r30/Purple7/v4/7c/42/30/7c423042-8945-7733-8af3-1523468706a8/mzl.qlecxphf.png',
    link: 'https://itunes.apple.com/us/app/youmeyou/id949540333?mt=8',
    author: 'youmeyou, LLC',
  },
  {
    name: 'Spero for Cancer',
    icon: 'https://s3-us-west-1.amazonaws.com/cancerspot/site_images/Spero1024.png',
    link: 'https://geo.itunes.apple.com/us/app/spero-for-cancer/id1033923573?mt=8',
    author: 'Spero.io',
  },
];

var showcase = React.createClass({
  render: function() {
    return (
      <Site section="showcase" title="Showcase">

Apps using React Native

              Here is a list of apps using React Native. Submit a pull request on GitHub to list your app.

          {
            apps.map((app, i) => {
              return (

{app.name}

By {app.author}

              );
            })
          }

      </Site>
    );
  }
});

module.exports = showcase;
<commit_msg>Alphabetize list.<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

var React = require('React');
var Site = require('Site');
var center = require('center');

var apps = [
  {
    name: 'Beetroot',
    icon: 'http://is1.mzstatic.com/image/pf/us/r30/Purple5/v4/66/fd/dd/66fddd70-f848-4fc5-43ee-4d52197ccab8/pr_source.png',
    link: 'https://itunes.apple.com/us/app/beetroot/id1016159001?ls=1&mt=8',
    author: 'Alex Duckmanton',
  },
  {
    name: 'Discord',
    icon: 'http://a5.mzstatic.com/us/r30/Purple5/v4/c1/2f/4c/c12f4cba-1d9a-f6bf-2240-04085d3470ec/icon175x175.jpeg',
    link:  'https://itunes.apple.com/us/app/discord-chat-for-gamers/id985746746?mt=8',
    author: 'Hammer & Chisel',
  },
  {
    name: 'Discovery VR',
    icon: 'http://a2.mzstatic.com/us/r30/Purple6/v4/d1/d5/f4/d1d5f437-9f6b-b5aa-5fe7-47bd19f934bf/icon175x175.png',
    link:  'https://itunes.apple.com/us/app/discovery-vr/id1030815031?mt=8',
    author: 'Discovery Communications',
  },
  {
    name: 'DropBot',
    icon: 'http://a2.mzstatic.com/us/r30/Purple69/v4/fb/df/73/fbdf73e0-22d2-c936-3115-1defa195acba/icon175x175.png',
    link:  'https://itunes.apple.com/us/app/dropbot-phone-replacement/id1000855694?mt=8',
    author: 'Peach Labs',
  },
  {
    name: 'Exponent',
    icon: 'http://a4.mzstatic.com/us/r30/Purple2/v4/3a/d3/c9/3ad3c96c-5e14-f988-4bdd-0fdc95efd140/icon175x175.png',
    link:  'https://itunes.apple.com/ca/app/exponent/id982107779?mt=8',
    author: 'Charlie Cheever & James Ide',
  },
  {
    name: 'F8',
    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple5/v4/bf/d9/50/bfd9504e-a1bd-67c5-b50b-24e97016dae9/pr_source.jpg',
    link: 'https://itunes.apple.com/us/app/f8/id853467066?mt=8',
    author: 'Facebook',
  },
  {
    name: 'Facebook Groups',
    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple69/v4/57/f8/4c/57f84c0c-793d-5f9a-95ee-c212d0369e37/mzl.ugjwfhzx.png',
    link: 'https://itunes.apple.com/us/app/facebook-groups/id931735837?mt=8',
    author: 'Facebook',
  },
  {
    name: 'Facebook Adverts Manager - Android',
    icon: 'https://lh3.googleusercontent.com/ODKlFYm7BaNiLMEEDO2b4DOCU-hmS1-Fg3_x_lLUaJZ0ssFsxciSoX1dYERaWDJuEs8=w300',
    link: 'https://play.google.com/store/apps/details?id=com.facebook.adsmanager',
    author: 'Facebook',
  },
  {
    name: 'Facebook Ads Manager - iOS',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple5/v4/9e/16/86/9e1686ef-cc55-805a-c977-538ddb5e6832/mzl.gqbhwitj.png',
    link: 'https://itunes.apple.com/us/app/facebook-ads-manager/id964397083?mt=8',
    author: 'Facebook',
  },
  {
    name: 'HSK Level 1 Chinese Flashcards',
    icon: 'http://is2.mzstatic.com/image/pf/us/r30/Purple1/v4/b2/4f/3a/b24f3ae3-2597-cc70-1040-731b425a5904/mzl.amxdcktl.jpg',
    link: 'https://itunes.apple.com/us/app/hsk-level-1-chinese-flashcards/id936639994',
    author: 'HS Schaaf',
  },
  {
    name: 'Leanpub',
    icon: 'http://a2.mzstatic.com/us/r30/Purple6/v4/9f/4a/6f/9f4a6f8c-8951-ed89-4083-74ace23df9ef/icon350x350.jpeg',
    link: 'https://itunes.apple.com/us/app/leanpub/id913517110?ls=1&mt=8',
    author: 'Leanpub',
  },
  {
    name: 'Lrn',
    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple1/v4/41/a9/e9/41a9e9b6-7801-aef7-2400-2eca14923321/mzl.adyswxad.png',
    link: 'https://itunes.apple.com/us/app/lrn-learn-to-code-at-your/id1019622677',
    author: 'Lrn Labs, Inc',
  },
  {
    name: 'Lumpen Radio',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple1/v4/46/43/00/464300b1-fae3-9640-d4a2-0eb050ea3ff2/mzl.xjjawige.png',
    link: 'https://itunes.apple.com/us/app/lumpen-radio/id1002193127?mt=8',
    author: 'Joshua Habdas',
  },
  {
    name: 'MinTrain',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple5/v4/51/51/68/51516875-1323-3100-31a8-cd1853d9a2c0/mzl.gozwmstp.png',
    link: 'https://itunes.apple.com/us/app/mintrain/id1015739031?mt=8',
    author: 'Peter Cottle',
  },
  {
    name: 'Mr. Dapper',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple4/v4/e8/3f/7c/e83f7cb3-2602-f8e8-de9a-ce0a775a4a14/mzl.hmdjhfai.png',
    link: 'https://itunes.apple.com/us/app/mr.-dapper-men-fashion-app/id989735184?ls=1&mt=8',
    author: 'wei ping woon',
  },
  {
    name: 'Ncredible',
    icon: 'http://a3.mzstatic.com/us/r30/Purple2/v4/a9/00/74/a9007400-7ccf-df10-553b-3b6cb67f3f5f/icon350x350.png',
    link: 'https://itunes.apple.com/ca/app/ncredible/id1019662810?mt=8',
    author: 'NBC News Digital, LLC',
  },
  {
    name: 'Night Light',
    icon: 'http://is3.mzstatic.com/image/pf/us/r30/Purple7/v4/5f/50/5f/5f505fe5-0a30-6bbf-6ed9-81ef09351aba/mzl.lkeqxyeo.png',
    link: 'https://itunes.apple.com/gb/app/night-light-feeding-light/id1016843582?mt=8',
    author: 'Tian Yuan',
  },
  {
    name: 'ReactTo36',
    icon: 'http://is2.mzstatic.com/image/pf/us/r30/Purple5/v4/e3/c8/79/e3c87934-70c6-4974-f20d-4adcfc68d71d/mzl.wevtbbkq.png',
    link: 'https://itunes.apple.com/us/app/reactto36/id989009293?mt=8',
    author: 'Jonathan Solichin',
  },
  {
    name: 'RN Playground',
    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple1/v4/20/ec/8e/20ec8eb8-9e12-6686-cd16-7ac9e3ef1d52/mzl.ngvuoybx.png',
    link: 'https://itunes.apple.com/us/app/react-native-playground/id1002032944?mt=8',
    author: 'Joshua Sierles',
  },
  {
    name: 'SG Toto 4d',
    icon: 'http://a4.mzstatic.com/us/r30/Purple7/v4/d2/bc/46/d2bc4696-84d6-9681-a49f-7f660d6b04a7/icon175x175.jpeg',
    link: 'https://itunes.apple.com/us/app/sg-toto-4d/id1006371481?mt=8',
    author: 'Steve Ng'
  },
  {
    name: 'Spero for Cancer',
    icon: 'https://s3-us-west-1.amazonaws.com/cancerspot/site_images/Spero1024.png',
    link: 'https://geo.itunes.apple.com/us/app/spero-for-cancer/id1033923573?mt=8',
    author: 'Spero.io',
  },
  {
    name: 'Start - medication manager for depression',
    icon: 'http://a1.mzstatic.com/us/r30/Purple49/v4/de/9b/6f/de9b6fe8-84ea-7a12-ba2c-0a6d6c7b10b0/icon175x175.png',
    link: 'https://itunes.apple.com/us/app/start-medication-manager-for/id1012099928?mt=8',
    author: 'Iodine Inc.',
  },
  {
    name: 'Tabtor Parent',
    icon: 'http://a1.mzstatic.com/us/r30/Purple4/v4/80/50/9d/80509d05-18f4-a0b8-0cbb-9ba927d04477/icon175x175.jpeg',
    link: 'https://itunes.apple.com/us/app/tabtor-math/id1018651199?utm_source=ParentAppLP',
    author: 'PrazAs Learning Inc.',
  },
  {
    name: 'Tong Xing Wang',
    icon: 'http://a3.mzstatic.com/us/r30/Purple1/v4/7d/52/a7/7d52a71f-9532-82a5-b92f-87076624fdb2/icon175x175.jpeg',
    link: 'https://itunes.apple.com/cn/app/tong-xing-wang/id914254459?mt=8',
    author: 'Ho Yin Tsun Eugene',
  },
  {
    name: 'Yoloci',
    icon: 'http://a5.mzstatic.com/eu/r30/Purple7/v4/fa/e5/26/fae52635-b97c-bd53-2ade-89e2a4326745/icon175x175.jpeg',
    link: 'https://itunes.apple.com/de/app/yoloci/id991323225?mt=8',
    author: 'Yonduva GmbH (@PhilippKrone)',
  },
  {
    name: 'youmeyou',
    icon: 'http://is1.mzstatic.com/image/pf/us/r30/Purple7/v4/7c/42/30/7c423042-8945-7733-8af3-1523468706a8/mzl.qlecxphf.png',
    link: 'https://itunes.apple.com/us/app/youmeyou/id949540333?mt=8',
    author: 'youmeyou, LLC',
  },
];

var showcase = React.createClass({
  render: function() {
    return (
      <Site section="showcase" title="Showcase">

Apps using React Native

              Here is a list of apps using React Native. Submit a pull request on GitHub to list your app.

          {
            apps.map((app, i) => {
              return (

{app.name}

By {app.author}

              );
            })
          }

      </Site>
    );
  }
});

module.exports = showcase;
<|endoftext|>


<commit_before>var events = require('events'),
	cheerio = require('cheerio'),
	util = require('util');

function MicroParser(schema, options) {
	var _self = this;
	events.EventEmitter.call(this);
	// test for schema and true object
	if (schema === undefined || Object.prototype.toString.call(schema) !== "[object Object]" || Object.keys(schema).length <= 0) {
		throw new Error("A schema Object is required!");
	}
	this.schema = schema;

	this.loadData = function (data) {
		if (data === undefined || data === '') {
			throw new Error("Data was empty or undefined");
		}
		this.data = data;
		this.$ = cheerio.load(this.data);
	};

	this.parseName = function () {
		var $ = this.$,
			nodes,
			name;
		if (_self.schema.name.id !== undefined) {
			name = $('#' + _self.schema.name.id).text();
		} else {
			$('.' + _self.schema.name.class).children().each(function (idx, elm) {
				if ($(this).attr('itemprop') === _self.schema.name.itemprop) {
					name = $(this).text();
				}
			});
		}
		return name;
	};

	this.parseIngredients = function () {
		var $ = this.$;
		var ingredients = [];
		$('#' + _self.schema.ingredients.id).each(function (idx, elem) {
			var ingredient = {};
			$(this).children().find('span').each(function (idx2, elem2) {
				if ($(this).hasClass(_self.schema.ingredients.name.class)) {
					ingredient['ingredient'] = $(this).text();
				}
				if ($(this).hasClass(_self.schema.ingredients.amount.class)) {
					ingredient['amount'] = $(this).text();
				}
			});
			ingredients.push(ingredient);
		});
		return ingredients;
	};

	this.parseDescription = function () {
		var $ = this.$,
			description,
			elm;
		if (_self.schema.description.id !== undefined) {
			description = $('#' + _self.schema.description.id).text();
		} else {
			elm = $('.' + _self.schema.description.class);
			if (elm.attr('itemprop') === _self.schema.description.itemprop) {

			}
		}

		return description;
	};

	this.parseDirections = function () {
		var $ = this.$,
			directions = [],
			elm;
		if (_self.schema.directions.id !== undefined) {
			elm = $('#' + _self.schema.directions.id);
		} else {
			elm = $('.' + _self.schema.directions.class);
		}

		elm.find(_self.schema.directions.elm).children().each(function (idx, elm2) {
			directions.push($(this).text());
		});
		return directions;
	};
}

// Inherit the EventEmitter prototype
util.inherits(MicroParser, events.EventEmitter);
module.exports = MicroParser;
<commit_msg>updating parsing directions to include better support for foodnetwork<commit_after>var events = require('events'),
	cheerio = require('cheerio'),
	util = require('util');

function MicroParser(schema, options) {
	var _self = this;
	events.EventEmitter.call(this);
	// test for schema and true object
	if (schema === undefined || Object.prototype.toString.call(schema) !== "[object Object]" || Object.keys(schema).length <= 0) {
		throw new Error("A schema Object is required!");
	}
	this.schema = schema;

	this.loadData = function (data) {
		if (data === undefined || data === '') {
			throw new Error("Data was empty or undefined");
		}
		this.data = data;
		this.$ = cheerio.load(this.data);
	};

	this.parseName = function () {
		var $ = this.$,
			nodes,
			name;
		if (_self.schema.name.id !== undefined) {
			name = $('#' + _self.schema.name.id).text();
		} else {
			$('.' + _self.schema.name.class).children().each(function (idx, elm) {
				if ($(this).attr('itemprop') === _self.schema.name.itemprop) {
					name = $(this).text();
				}
			});
		}
		return name;
	};

	this.parseIngredients = function () {
		var $ = this.$;
		var ingredients = [];
		$('#' + _self.schema.ingredients.id).each(function (idx, elem) {
			var ingredient = {};
			$(this).children().find('span').each(function (idx2, elem2) {
				if ($(this).hasClass(_self.schema.ingredients.name.class)) {
					ingredient['ingredient'] = $(this).text();
				}
				if ($(this).hasClass(_self.schema.ingredients.amount.class)) {
					ingredient['amount'] = $(this).text();
				}
			});
			ingredients.push(ingredient);
		});
		return ingredients;
	};

	this.parseDescription = function () {
		var $ = this.$,
			description,
			elm;
		if (_self.schema.description.id !== undefined) {
			description = $('#' + _self.schema.description.id).text();
		} else {
			elm = $('.' + _self.schema.description.class);
			if (elm.attr('itemprop') === _self.schema.description.itemprop) {

			}
		}

		return description;
	};

	this.parseDirections = function () {
		var $ = this.$,
			directions = [],
			elm;
		if (_self.schema.directions.id !== undefined) {
			elm = $('#' + _self.schema.directions.id);
		} else {
			elm = $('.' + _self.schema.directions.class);
		}

		elm.find(_self.schema.directions.direction.elm).each(function (idx, elm2) {
			directions.push($(this).text());
		});
		return directions;
	};
}

// Inherit the EventEmitter prototype
util.inherits(MicroParser, events.EventEmitter);
module.exports = MicroParser;
<|endoftext|>


<commit_before>//

exports.config =
{
	seleniumAddress: 'http://localhost:4444/wd/hub',
	specs: ['public/modules/users/tests/authentication.signup.spec.test.js'],

	baseUrl: 'http://localhost:3000/'
}

//, 'public/modules/users/tests/spec.signin.test.js','public/modules/decks/tests/protractor.spec.test.js'<commit_msg>re-added other tests to conf file<commit_after>//

exports.config =
{
	seleniumAddress: 'http://localhost:4444/wd/hub',
	specs: ['public/modules/users/tests/authentication.signup.spec.test.js', 'public/modules/users/tests/spec.signin.test.js','public/modules/decks/tests/protractor.spec.test.js'],

	baseUrl: 'http://localhost:3000/'
}

//<|endoftext|>


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

var Promise = require('es6-promise').Promise;
var mkdirp = require('mkdirp');
var ncp = require('ncp');
var webpack = require('webpack');
var webpackConfig = require('./webpack.coffee').build;

exports.buildDevIndex = function(config) {
  process.env.NODE_ENV = 'dev';

  return new Promise(function(resolve, reject) {
    webpackConfig(config).then(function(c) {
      webpack(c, function(err) {
        if(err) {
          return reject(err);
        }

        var cwd = process.cwd();
        var renderPage = require(_path.join(cwd, './.antwar/build/bundleStaticPage.js'));

        fs.writeFileSync(
          _path.join(cwd, './.antwar/build/index.html'),
          renderPage('/antwar_devindex', null)
        );

        ncp('./assets', _path.join(cwd, './.antwar/build/assets'));

        resolve();
      });
    }).catch(function(err) {
      reject(err);
    });
  });
};

exports.build = function(config) {
  process.env.NODE_ENV = 'production';

  return new Promise(function(resolve, reject) {
    var output = config.output;

    if(!output) {
      return reject(new Error('Missing output directory'));
    }

    webpackConfig(config).then(function(c) {
      webpack(c, function(err) {
        if(err) {
          return reject(err);
        }

        var cwd = process.cwd();
        var params = {
          cwd: cwd,
          renderPage: require(_path.join(cwd, './.antwar/build/bundleStaticPage.js')),
          allPaths: require(_path.join(cwd, './.antwar/build/paths.js')),
          output: _path.join(cwd, output),
        };
        writeAssets(params);
        writePages(params);
        writeIndex(params);
        writePosts(params);

        // TODO: this should be pushed to a plugin
        //var rss = require(_path.join(cwd, './.antwar/build/bundleStaticRss.js'));
        //fs.writeFileSync(_path.join(process.cwd(), output, 'atom.xml'), rss(renderPage));

        resolve();
      });
    });
  });
};

function writeAssets(o) {
  var assets = _path.join(o.output, 'assets');
  var mainPath = './.antwar/build/main.css';

  mkdirp.sync(assets);

  ncp(_path.join(o.cwd, './assets'), assets);

  if(fs.existsSync(mainPath)) {
    fs.writeFileSync(
      _path.join(assets, 'main.css'),
      fs.readFileSync(mainPath)
    );
  }
}

function writePages(o) {
  Object.keys(o.allPaths).forEach(function(path) {
    if(path !== 'posts') {
      var publicPath = o.output;

      if(path === '/') {
        path = '';
      }
      else {
        publicPath = _path.join(o.output, path);

        mkdirp.sync(publicPath);
      }

      fs.writeFileSync(
        _path.join(publicPath, 'index.html'),

        o.renderPage('/' + path, null)
      );
    }
  });
}

function writeIndex(o) {
  mkdirp.sync(_path.join(o.output, 'blog'));

  fs.writeFileSync(
    _path.join(o.output,  'blog', 'index.html'),

    o.renderPage('/blog', null)
  );
}

function writePosts(o) {
  Object.keys(o.allPaths.posts).forEach(function(post) {
    var p = _path.join(o.output, 'blog', post);

    mkdirp.sync(p);

    fs.writeFileSync(
      _path.join(p, 'index.html'),

      o.renderPage('/blog/' + post)
    );
  });
}
<commit_msg>Invoke `allPaths` correctly<commit_after>'use strict';
var fs = require('fs');
var _path = require('path');

var Promise = require('es6-promise').Promise;
var mkdirp = require('mkdirp');
var ncp = require('ncp');
var webpack = require('webpack');
var webpackConfig = require('./webpack.coffee').build;

exports.buildDevIndex = function(config) {
  process.env.NODE_ENV = 'dev';

  return new Promise(function(resolve, reject) {
    webpackConfig(config).then(function(c) {
      webpack(c, function(err) {
        if(err) {
          return reject(err);
        }

        var cwd = process.cwd();
        var renderPage = require(_path.join(cwd, './.antwar/build/bundleStaticPage.js'));

        fs.writeFileSync(
          _path.join(cwd, './.antwar/build/index.html'),
          renderPage('/antwar_devindex', null)
        );

        ncp('./assets', _path.join(cwd, './.antwar/build/assets'));

        resolve();
      });
    }).catch(function(err) {
      reject(err);
    });
  });
};

exports.build = function(config) {
  process.env.NODE_ENV = 'production';

  return new Promise(function(resolve, reject) {
    var output = config.output;

    if(!output) {
      return reject(new Error('Missing output directory'));
    }

    webpackConfig(config).then(function(c) {
      webpack(c, function(err) {
        if(err) {
          return reject(err);
        }

        var cwd = process.cwd();
        var params = {
          cwd: cwd,
          renderPage: require(_path.join(cwd, './.antwar/build/bundleStaticPage.js')),
          allPaths: require(_path.join(cwd, './.antwar/build/paths.js'))(),
          output: _path.join(cwd, output),
        };
        writeAssets(params);
        writePages(params);
        writeIndex(params);
        writePosts(params);

        // TODO: this should be pushed to a plugin
        //var rss = require(_path.join(cwd, './.antwar/build/bundleStaticRss.js'));
        //fs.writeFileSync(_path.join(process.cwd(), output, 'atom.xml'), rss(renderPage));

        resolve();
      });
    });
  });
};

function writeAssets(o) {
  var assets = _path.join(o.output, 'assets');
  var mainPath = './.antwar/build/main.css';

  mkdirp.sync(assets);

  ncp(_path.join(o.cwd, './assets'), assets);

  if(fs.existsSync(mainPath)) {
    fs.writeFileSync(
      _path.join(assets, 'main.css'),
      fs.readFileSync(mainPath)
    );
  }
}

function writePages(o) {
  Object.keys(o.allPaths).forEach(function(path) {
    if(path !== 'posts') {
      var publicPath = o.output;

      if(path === '/') {
        path = '';
      }
      else {
        publicPath = _path.join(o.output, path);

        mkdirp.sync(publicPath);
      }

      fs.writeFileSync(
        _path.join(publicPath, 'index.html'),

        o.renderPage('/' + path, null)
      );
    }
  });
}

function writeIndex(o) {
  mkdirp.sync(_path.join(o.output, 'blog'));

  fs.writeFileSync(
    _path.join(o.output,  'blog', 'index.html'),

    o.renderPage('/blog', null)
  );
}

function writePosts(o) {
  Object.keys(o.allPaths.posts).forEach(function(post) {
    var p = _path.join(o.output, 'blog', post);

    mkdirp.sync(p);

    fs.writeFileSync(
      _path.join(p, 'index.html'),

      o.renderPage('/blog/' + post)
    );
  });
}
<|endoftext|>


<commit_before>module.exports = {
  plugins: {
    sauce: {
      disabled: true,
      browsers: [
        'mac/chrome',
        'mac/firefox',
        'mac/safari',
        'ios/safari',
        'android/chrome',
        'windows 10/internet explorer',
        'windows 10/MicrosoftEdge',
      ]
    }
  }
};
<commit_msg>fix correct iPhone platform name for sauce tests<commit_after>module.exports = {
  plugins: {
    sauce: {
      disabled: true,
      browsers: [
        'mac/chrome',
        'mac/firefox',
        'mac/safari',
        'any/iPhone',
        'android/chrome',
        'windows 10/internet explorer',
        'windows 10/MicrosoftEdge',
      ]
    }
  }
};
<|endoftext|>


<commit_before>'use strict';
/* jshint camelcase:false */

var corbel = require('../../../dist/corbel.js'),
    chai = require('chai'),
    sinon = require('sinon'),
    expect = chai.expect;

describe('With custom domain we can', function() {

    var sandbox = sinon.sandbox.create();

    var CONFIG = {
        clientId: 'clientId',
        clientSecret: 'clientSecret',
        scopes: ['corbel-qa:client'],
        urlBase: 'https://{{module}}-corbel.io/'
    };

    var RESOURCE_COLLECTION_URL = CONFIG.urlBase.replace('{{module}}', 'resources') + '{{domain}}/resource/{{resource}}' ;

    var corbelDriver, corbelRequestStub;

    beforeEach(function() {
        corbelDriver = corbel.getDriver(CONFIG);
        corbelRequestStub = sandbox.stub(corbel.request, 'send');
        corbelRequestStub.returns(Promise.resolve());
    });

    afterEach(function() {
        sandbox.restore();
    });

    it('add a custom domain value', function() {
        var resource = 'resource:entity';
        var customDomain = 'oneTestDomain';

        var url = RESOURCE_COLLECTION_URL.replace('{{resource}}', resource).replace('{{domain}}', customDomain);
        expect(corbelDriver.domain(customDomain).resources.collection(resource).getURL()).to.be.equal(url);
    });

    it('does not persist the value on the configuration for consecutive calls', function(done){
        var resource = 'resource:entity';
        var customDomain = 'oneTestDomainTwo';

        var urlWithDomain = RESOURCE_COLLECTION_URL.replace('{{resource}}', resource).replace('{{domain}}', customDomain);
        var urlWithoutDomain = RESOURCE_COLLECTION_URL.replace('{{resource}}', resource).replace('{{domain}}', 'unauthenticated');

        expect(corbelDriver.domain(customDomain).resources.collection(resource).getURL()).to.be.equal(urlWithDomain);

        corbelDriver.domain(customDomain).resources.collection(resource)
            .get()
            .then(function(){
                expect(corbelDriver.resources.collection(resource).getURL()).to.be.equal(urlWithoutDomain);
            })
            .should.notify(done);
    });
});
<commit_msg>(domain) webfs unit test<commit_after>'use strict';
/* jshint camelcase:false */

var corbel = require('../../../dist/corbel.js'),
    chai = require('chai'),
    sinon = require('sinon'),
    expect = chai.expect;

describe('With custom domain we can', function() {

    var sandbox = sinon.sandbox.create();

    var CONFIG = {
        clientId: 'clientId',
        clientSecret: 'clientSecret',
        scopes: ['corbel-qa:client'],
        urlBase: 'https://{{module}}-corbel.io/'
    };

    var RESOURCE_COLLECTION_URL = CONFIG.urlBase.replace('{{module}}', 'resources') + '{{domain}}/resource/{{resource}}' ;
    var WEBFS_URL = CONFIG.urlBase.replace('{{module}}', 'webfs') + '{{domain}}/{{resource}}' ;

    var corbelDriver, corbelRequestStub;

    beforeEach(function() {
        corbelDriver = corbel.getDriver(CONFIG);
        corbelRequestStub = sandbox.stub(corbel.request, 'send');
        corbelRequestStub.returns(Promise.resolve());
    });

    afterEach(function() {
        sandbox.restore();
    });

    it('add a custom domain value', function() {
        var resource = 'resource:entity';
        var customDomain = 'oneTestDomain';

        var url = RESOURCE_COLLECTION_URL.replace('{{resource}}', resource).replace('{{domain}}', customDomain);
        expect(corbelDriver.domain(customDomain).resources.collection(resource).getURL()).to.be.equal(url);
    });

    it('does not persist the value on resources configuration for consecutive calls', function(done){
        var resource = 'resource:entity';
        var customDomain = 'oneTestDomainTwo';

        var urlWithDomain = RESOURCE_COLLECTION_URL.replace('{{resource}}', resource).replace('{{domain}}', customDomain);
        var urlWithoutDomain = RESOURCE_COLLECTION_URL.replace('{{resource}}', resource).replace('{{domain}}', 'unauthenticated');

        expect(corbelDriver.domain(customDomain).resources.collection(resource).getURL()).to.be.equal(urlWithDomain);

        corbelDriver.domain(customDomain).resources.collection(resource)
            .get()
            .then(function(){
                expect(corbelDriver.resources.collection(resource).getURL()).to.be.equal(urlWithoutDomain);
            })
            .should.notify(done);
    });

    it('does not persist the value on webfs configuration for consecutive calls', function(done){
        var resource = 'index.html';
        var customDomain = 'oneTestDomainTwo';

        var urlWithDomain = WEBFS_URL.replace('{{resource}}', resource).replace('{{domain}}', customDomain);
        var urlWithoutDomain = WEBFS_URL.replace('{{resource}}', resource).replace('{{domain}}', 'unauthenticated');

        expect(corbelDriver.domain(customDomain).webfs.webfs(resource)._buildUri(resource)).to.be.equal(urlWithDomain);

        corbelDriver.domain(customDomain).webfs.webfs(resource).get()
            .then(function(){
                expect(corbelDriver.webfs.webfs(resource)._buildUri(resource)).to.be.equal(urlWithoutDomain);
            })
            .should.notify(done);
    });
});
<|endoftext|>


<commit_before>/*
 *
 *  Gis.js is released under the MIT license, which should be retained when including, utilising or developing Gis.js in any environment.
 *
 *  Original Creator: James Gould © 2017
 *
 *  ----------> UNDER ACTIVE DEVELOPMENT. FEATURES, BUG FIXES AND REFACTORING WILL OCCUR NIGH ON DAILY. <----------
 *
 */

/**
 * Utility functions for working with GIS data. Do not export, use internally.
 */
var Utils = {

    /**
     * Checks if the input validates to a float datatype.
     */
    isFloat: (value) => {
        return value === +n && n !== (n|0);
    },

}

/**
 * Contains utility functions for working with GIS data.
 *
 */
var Gis = {

    /**
     * Point object
     */
    Point: (latitude, longitude) => {
        var point = {
            x: latitude,
            y: longitude
        };

        return point;
    },

    /**
     * Validates a (latitude, longitude) pair as being a valid float, and within the expected range of each respective value.
     */
    ValidLatLng: (latitude, longitude, callback) => {
        if(!Utils.isFloat(latitude) || !Utils.isFloat(longitude)) {
            if(typeof callback === undefined) {
                return false;
            } else {
                var err = new Error("Latitude/longitude pair is of an invalid datatype");
                return callback(err);
            }
        }
        return (latitude >= -90 && latitude <= 90) && (longitude >= -180 && longitude <= 180);
    },

    /**
     * Validates if a Point object is valid.
     */
    ValidPoint: (point) => {
        if(typeof point !== Gis.Point) { // hmm, breaks if custom Point obj with x, y props. This is just bad but it's the weekend, lets go crazy ¯\_(ツ)_/¯
            return false;
        } else {
            return Gis.ValidLatLng(point.x, point.y);
        }
    },

    /**
     * Determines if a given (latitude, longitude) pair is within a given polygon. Currently only works will an array of Point objects.
     */
    PointInPolygon: (latitude, longitude, polygon) => {

    }

}

/*
 * Export only Gis, do not release any local objects or functions (extracted or otherwise) used.
 */
module.exports = Gis;<commit_msg>Removed a pointess callback.<commit_after>/*
 *
 *  Gis.js is released under the MIT license, which should be retained when including, utilising or developing Gis.js in any environment.
 *
 *  Original Creator: James Gould © 2017
 *
 *  ----------> UNDER ACTIVE DEVELOPMENT. FEATURES, BUG FIXES AND REFACTORING WILL OCCUR NIGH ON DAILY. <----------
 *
 */

/**
 * Utility functions for working with GIS data. Do not export, use internally.
 */
var Utils = {

    /**
     * Checks if the input validates to a float datatype.
     */
    isFloat: (value) => {
        return value === +n && n !== (n|0);
    },

}

/**
 * Contains utility functions for working with GIS data.
 *
 */
var Gis = {

    /**
     * Point object
     */
    Point: (latitude, longitude) => {
        var point = {
            x: latitude,
            y: longitude
        };

        return point;
    },

    /**
     * Validates a (latitude, longitude) pair as being a valid float, and within the expected range of each respective value.
     */
    ValidLatLng: (latitude, longitude) => {
        if(!Utils.isFloat(latitude) || !Utils.isFloat(longitude)) {
                return false;
        }
        return (latitude >= -90 && latitude <= 90) && (longitude >= -180 && longitude <= 180);
    },

    /**
     * Validates if a Point object is valid.
     */
    ValidPoint: (point) => {
        if(typeof point !== Gis.Point) { // hmm, breaks if custom Point obj with x, y props. This is just bad but it's the weekend, lets go crazy ¯\_(ツ)_/¯
            return false;
        } else {
            return Gis.ValidLatLng(point.x, point.y);
        }
    },

    /**
     * Determines if a given (latitude, longitude) pair is within a given polygon. Currently only works will an array of Point objects.
     */
    PointInPolygon: (latitude, longitude, polygon) => {

    }

}

/*
 * Export only Gis, do not release any local objects or functions (extracted or otherwise) used.
 */
module.exports = Gis;<|endoftext|>


<commit_before>'use babel';

/* @flow */
import * as fs from 'fs';
import * as path from 'path';
import _ from 'lodash';
import os from 'os';
import { BufferedProcess } from 'atom';

export function run(textEditor) {
  console.log('run function call', textEditor);
  return new Promise((resolve) => {
    console.log('run promise create', textEditor);
    let processOutput = '';
    const fileName = textEditor.getPath();
    let outputFilePath = fileName;
    const projectPath = atom.project.relativizePath(fileName)[0];
    let cwd = projectPath;
    if (!(cwd)) {
      cwd = path.dirname(fileName);
    }
    const fileModified = textEditor.isModified();
    if (fileModified) {
      const outputDir = `${atom.getConfigDirPath()}/tester-mocha`;
      if (!fs.existsSync(outputDir)) {
        fs.mkdir(outputDir);
      }
      outputFilePath = `${outputDir}/${path.basename(fileName)}`;
      fs.writeFileSync(outputFilePath, textEditor.getText());
      console.log('WRITE TEMP FILE', outputFilePath, textEditor.getText());
    }
    function parseReporterOutput(outputString) {
      let consoleOutput = '';
      const messages = [];
      _.forEach(_.split(outputString, os.EOL), (line) => {
        console.log('HANDLE OUTPUT', line);
        try {
          const outputEvent = JSON.parse(line);
          messages.push(outputEvent);
        } catch (e) {
          console.log('ERROR JSON', e);
          consoleOutput += line.toString() + os.EOL;
        }
      });
      return { messages, consoleOutput };
    }
    const args = ['--reporter', `${atom.packages.resolvePackagePath('tester-mocha')}/lib/mocha-reporter.js`, '--colors', outputFilePath];
    const options = { cwd };
    const mochaBinary = atom.config.get('tester-mocha.binaryPath');
    const command = mochaBinary != null ? mochaBinary : `${atom.packages.resolvePackagePath('tester-mocha')}/node_modules/.bin/mocha`;
    const stdout = data => processOutput += data;
    const stderr = data => processOutput += data;
    const exit = (code) => {
      console.log('OUTPUT', processOutput, code);
      return resolve(parseReporterOutput(processOutput));
    };
    const process = new BufferedProcess({ command, args, options, stdout, stderr, exit });

    process.onWillThrowError((errorObject) => {
      atom.notifications.addError('Tester is unable to locate the mocha command. Please ensure process.env.PATH can access mocha.');
      console.error('Tester Mocha: ', errorObject);
    });
  });
}
<commit_msg>refactoring<commit_after>'use babel';

/* @flow */
import * as fs from 'fs';
import * as path from 'path';
import _ from 'lodash';
import os from 'os';
import { BufferedProcess } from 'atom';

export function run(textEditor) {
  console.log('run function call', textEditor);
  return new Promise((resolve) => {
    console.log('run promise create', textEditor);
    let processOutput = '';
    const fileName = textEditor.getPath();
    let outputFilePath = fileName;
    const projectPath = atom.project.relativizePath(fileName)[0];
    let cwd = projectPath;
    if (!(cwd)) {
      cwd = path.dirname(fileName);
    }
    const fileModified = textEditor.isModified();
    if (fileModified) {
      const outputDir = `${atom.getConfigDirPath()}/tester-mocha`;
      if (!fs.existsSync(outputDir)) {
        fs.mkdir(outputDir);
      }
      outputFilePath = `${outputDir}/${path.basename(fileName)}`;
      fs.writeFileSync(outputFilePath, textEditor.getText());
      console.log('WRITE TEMP FILE', outputFilePath, textEditor.getText());
    }
    function parseReporterOutput(outputString) {
      let output = '';
      const messages = [];
      _.forEach(_.split(outputString, os.EOL), (line) => {
        console.log('HANDLE OUTPUT', line);
        try {
          const outputEvent = JSON.parse(line);
          messages.push(outputEvent);
        } catch (e) {
          console.log('ERROR JSON', e);
          output += line.toString() + os.EOL;
        }
      });
      return { messages, output };
    }
    const args = ['--reporter', `${atom.packages.resolvePackagePath('tester-mocha')}/lib/mocha-reporter.js`, '--colors', outputFilePath];
    const options = { cwd };
    const mochaBinary = atom.config.get('tester-mocha.binaryPath');
    const command = mochaBinary != null ? mochaBinary : `${atom.packages.resolvePackagePath('tester-mocha')}/node_modules/.bin/mocha`;
    const stdout = data => processOutput += data;
    const stderr = data => processOutput += data;
    const exit = (code) => {
      console.log('OUTPUT', processOutput, code);
      return resolve(parseReporterOutput(processOutput));
    };
    const process = new BufferedProcess({ command, args, options, stdout, stderr, exit });

    process.onWillThrowError((errorObject) => {
      atom.notifications.addError('Tester is unable to locate the mocha command. Please ensure process.env.PATH can access mocha.');
      console.error('Tester Mocha: ', errorObject);
    });
  });
}
<|endoftext|>