<commit_before>var solar = require('./solar');
var weather = require('./weather');

function getElev() {
  var ms = Math.round((+new Date()) / 1000);
  return solar.solar_elevation(ms, node.config.lat, node.config.long);
}

var node = new (require('./../lib/node'))();
node.start('outside', 'nature', function () {

  // solar
  var elev = getElev();
  node.addProperty('solar_elev', 'number', elev);
  node.addProperty('sun_is_set', 'number', elev < 6);

  setInterval(function () {
    elev = getElev();
    node.setProperty('solar_elev', elev);
    node.setProperty('sun_is_set', elev < 6);

    console.log(node.tag, 'Setting solar elevation to', elev);
  }, 60 * 1000);

  // weather
  node.addProperty('weather',  'string');
  node.addProperty('temp',     'number');
  node.addProperty('humidity', 'number');
  node.addProperty('clouds',   'number');
  node.addProperty('wind',     'number');

  var upWeather = function () {
    weather.fetch(node.config, function (json) {
      node.setProperty('weather',  json.weather[0].main);
      node.setProperty('temp',     json.main.temp);
      node.setProperty('humidity', json.main.humidity);
      node.setProperty('clouds',   json.clouds.all / 100);
      node.setProperty('wind',     json.wind.speed);

      console.log(node.tag, 'Weather information updated');
    });
  };

  setInterval(upWeather, 10 * 60 * 1000);
  upWeather();
});
<commit_msg>Lop a ton of decimal numbers off the sun's elevation<commit_after>var solar = require('./solar');
var weather = require('./weather');

function getElev() {
  var ms = Math.round((+new Date()) / 1000);
  return solar.solar_elevation(ms, node.config.lat, node.config.long);
}

var node = new (require('./../lib/node'))();
node.start('outside', 'nature', function () {

  // solar
  var elev = Math.round(getElev() * 10) / 10;
  node.addProperty('solar_elev', 'number', elev);
  node.addProperty('sun_is_set', 'number', elev < 6);

  setInterval(function () {
    elev = Math.round(getElev() * 10) / 10;
    node.setProperty('solar_elev', elev);
    node.setProperty('sun_is_set', elev < 6);

    console.log(node.tag, 'Setting solar elevation to', elev);
  }, 60 * 1000);

  // weather
  node.addProperty('weather',  'string');
  node.addProperty('temp',     'number');
  node.addProperty('humidity', 'number');
  node.addProperty('clouds',   'number');
  node.addProperty('wind',     'number');

  var upWeather = function () {
    weather.fetch(node.config, function (json) {
      node.setProperty('weather',  json.weather[0].main);
      node.setProperty('temp',     json.main.temp);
      node.setProperty('humidity', json.main.humidity);
      node.setProperty('clouds',   json.clouds.all / 100);
      node.setProperty('wind',     json.wind.speed);

      console.log(node.tag, 'Weather information updated');
    });
  };

  setInterval(upWeather, 10 * 60 * 1000);
  upWeather();
});
<|endoftext|>


<commit_before>/* ng-Lettering v1.0.0
 * https://github.com/patrickmarabeas/ng-Lettering.js
 *
 * Original jQuery project: https://github.com/davatron5000/Lettering.js
 *
 * Copyright 2013, Patrick Marabeas http://pulse-dev.com
 * Released under the MIT license
 * http://opensource.org/licenses/mit-license.php
 *
 * Date: 18/11/2013
 */

var module = angular.module( 'ngLettering', [] );

module.directive( 'lettering', [ function () {
	return {
		restrict: 'A',
		link: function( scope, element, attrs ) {

			var methods = {
				letters: function() {
					injector( element, '', 'char', '' );
				},
				words: function() {
					injector( element, ' ', 'word', ' ' );
				},
				lines: function() {
					var r = 'eefec303079ad17405c889e092e105b0';
					angular.element( element ).children( 'br' ).replaceWith( r );
					injector( element, r, 'line', '' );
				}
			};

			function injector( element, splitter, klass, after ) {
				var a = element[0].innerHTML.split( splitter );
				var inject = '';

				if( a.length ) {
					angular.forEach( a, function( item, i ) {
						inject += '' + item + '' + after;
					});
					while( element[0].hasChildNodes() ) {
						element[0].removeChild( element[0].firstChild );
					}
					element.append( inject );
				}
			}

			scope.method = attrs.lettering || 'letters';
			methods[scope.method]();
		}
	}
}]);<commit_msg>fixed name<commit_after>/* ng-Lettering.js v1.0.0
 * https://github.com/patrickmarabeas/ng-Lettering.js
 *
 * Original jQuery project: https://github.com/davatron5000/Lettering.js
 *
 * Copyright 2013, Patrick Marabeas http://pulse-dev.com
 * Released under the MIT license
 * http://opensource.org/licenses/mit-license.php
 *
 * Date: 18/11/2013
 */

var module = angular.module( 'ngLettering', [] );

module.directive( 'lettering', [ function () {
	return {
		restrict: 'A',
		link: function( scope, element, attrs ) {

			var methods = {
				letters: function() {
					injector( element, '', 'char', '' );
				},
				words: function() {
					injector( element, ' ', 'word', ' ' );
				},
				lines: function() {
					var r = 'eefec303079ad17405c889e092e105b0';
					angular.element( element ).children( 'br' ).replaceWith( r );
					injector( element, r, 'line', '' );
				}
			};

			function injector( element, splitter, klass, after ) {
				var a = element[0].innerHTML.split( splitter );
				var inject = '';

				if( a.length ) {
					angular.forEach( a, function( item, i ) {
						inject += '' + item + '' + after;
					});
					while( element[0].hasChildNodes() ) {
						element[0].removeChild( element[0].firstChild );
					}
					element.append( inject );
				}
			}

			scope.method = attrs.lettering || 'letters';
			methods[scope.method]();
		}
	}
}]);<|endoftext|>


<commit_before>/* Nite v1.0
 * A tiny library to create a night overlay over the map
 * Author: Rossen Georgiev @ https://github.com/rossengeorgiev
 * Requires: GMaps API 3
 */

var nite = {
    map: null,
    date: null,
    marker_sun: null,
    marker_shadow: null,
    marker_shadow_lite: null,
    shadow_radius: parseInt(6371 * Math.PI * 500),
    sun_position: null,

    init: function(map) {
        if(typeof google === 'undefined'
           || typeof google.maps === 'undefined') throw "Nite Overlay: no google.maps detected";

        this.map = map;
        this.refreshSunZenith();

        this.marker_shadow = new google.maps.Circle({
            map: this.map,
            center: this.getShadowPosition(),
            radius: this.shadow_radius,
            fillColor: "#000",
            fillOpacity: 0.1,
            strokeOpacity: 0,
            clickable: false,
            editable: false
        });

        this.marker_shadow_lite = new google.maps.Circle({
            map: this.map,
            center: this.getShadowPosition(),
            radius: this.shadow_radius * 0.96,
            fillColor: "#000",
            fillOpacity: 0.1,
            strokeOpacity: 0,
            clickable: false,
            editable: false
        });
    },
    getShadowPosition: function() {
        return new google.maps.LatLng(-this.sun_position.lat(), -this.sun_position.lng() + 180);
    },
    refresh: function() {
        if(!this.isVisible()) return;
        this.refreshSunZenith();
        this.marker_shadow.setCenter(this.getShadowPosition());
        this.marker_shadow_lite.setCenter(this.getShadowPosition());
    },
    refreshSunZenith: function() {
        var rad = 0.017453292519943295;

        // based on NOAA solar calculations
        var utc = new Date();
        if(this.date) { utc = new Date(this.date); }
        utc = new Date(utc.getTime() + utc.getTimezoneOffset() * 60000);
        var mins_past_midnight = (utc.getHours() * 60 + utc.getMinutes()) / 1440;
        var jd = 2415018.5 - ((new Date("01/01/1900 00:00:00 UTC")).getTime() - utc.getTime()) / 1000 / 60 / 60 / 24;
        var jc = (jd - 2451545)/36525;
        var mean_long_sun = (280.46646+jc*(36000.76983+jc*0.0003032)) % 360;
        var mean_anom_sun = 357.52911+jc*(35999.05029-0.0001537*jc);
        var sun_eq = Math.sin(rad*mean_anom_sun)*(1.914602-jc*(0.004817+0.000014*jc))+Math.sin(rad*2*mean_anom_sun)*(0.019993-0.000101*jc)+Math.sin(rad*3*mean_anom_sun)*0.000289;
        var sun_true_long = mean_long_sun + sun_eq;
        var sun_app_long = sun_true_long - 0.00569 - 0.00478*Math.sin(rad*125.04-1934.136*jc);
        var mean_obliq_ecliptic = 23+(26+((21.448-jc*(46.815+jc*(0.00059-jc*0.001813))))/60)/60;
        var obliq_corr = mean_obliq_ecliptic + 0.00256*Math.cos(rad*125.04-1934.136*jc);

        var lat = Math.asin(Math.sin(rad*obliq_corr)*Math.sin(rad*sun_app_long)) / rad;

        var eccent = 0.016708634-jc*(0.000042037+0.0000001267*jc);
        var y = Math.tan(rad*(obliq_corr/2))*Math.tan(rad*(obliq_corr/2));
        var rq_of_time = 4*((y*Math.sin(2*rad*mean_long_sun)-2*eccent*Math.sin(rad*mean_anom_sun)+4*eccent*y*Math.sin(rad*mean_anom_sun)*Math.cos(2*rad*mean_long_sun)-0.5*y*y*Math.sin(4*rad*mean_long_sun)-1.25*eccent*eccent*Math.sin(2*rad*mean_anom_sun))/rad);
        var true_solar_time = (mins_past_midnight*1440+rq_of_time) % 1440;
        var lng = (true_solar_time/4 < 0) ? true_solar_time/4 + 180 : true_solar_time/4 - 180;

        this.sun_position = new google.maps.LatLng(lat, lng);
    },
    setDate: function(date) {
        this.date = date;
        this.refresh();
    },
    setMap: function(map) {
        this.map = map;
    },
    show: function() {
        this.marker_shadow.setVisible(true);
        this.marker_shadow_lite.setVisible(true);
        this.refresh();
    },
    hide: function() {
        this.marker_shadow.setVisible(false);
        this.marker_shadow_lite.setVisible(false);
    },
    isVisible: function() {
        return this.marker_shadow.getVisible();
    }
}
<commit_msg>cleaned up whitespaces<commit_after>/* Nite v1.1
 * A tiny library to create a night overlay over the map
 * Author: Rossen Georgiev @ https://github.com/rossengeorgiev
 * Requires: GMaps API 3
 */

var nite = {
    map: null,
    date: null,
    marker_sun: null,
    marker_shadow: null,
    marker_shadow_lite: null,
    shadow_radius: parseInt(6371 * Math.PI * 500),
    sun_position: null,

    init: function(map) {
        if(typeof google === 'undefined'
           || typeof google.maps === 'undefined') throw "Nite Overlay: no google.maps detected";

        this.map = map;
        this.refreshSunZenith();

        this.marker_shadow = new google.maps.Circle({
            map: this.map,
            center: this.getShadowPosition(),
            radius: this.shadow_radius,
            fillColor: "#000",
            fillOpacity: 0.1,
            strokeOpacity: 0,
            clickable: false,
            editable: false
        });

        this.marker_shadow_lite = new google.maps.Circle({
            map: this.map,
            center: this.getShadowPosition(),
            radius: this.shadow_radius * 0.96,
            fillColor: "#000",
            fillOpacity: 0.1,
            strokeOpacity: 0,
            clickable: false,
            editable: false
        });
    },
    getShadowPosition: function() {
        return new google.maps.LatLng(-this.sun_position.lat(), -this.sun_position.lng() + 180);
    },
    refresh: function() {
        if(!this.isVisible()) return;
        this.refreshSunZenith();
        this.marker_shadow.setCenter(this.getShadowPosition());
        this.marker_shadow_lite.setCenter(this.getShadowPosition());
    },
    refreshSunZenith: function() {
        var rad = 0.017453292519943295;

        // based on NOAA solar calculations
        var utc = new Date();
        if(this.date) { utc = new Date(this.date); }
        utc = new Date(utc.getTime() + utc.getTimezoneOffset() * 60000);
        var mins_past_midnight = (utc.getHours() * 60 + utc.getMinutes()) / 1440;
        var jd = 2415018.5 - ((new Date("01/01/1900 00:00:00 UTC")).getTime() - utc.getTime()) / 1000 / 60 / 60 / 24;
        var jc = (jd - 2451545)/36525;
        var mean_long_sun = (280.46646+jc*(36000.76983+jc*0.0003032)) % 360;
        var mean_anom_sun = 357.52911+jc*(35999.05029-0.0001537*jc);
        var sun_eq = Math.sin(rad*mean_anom_sun)*(1.914602-jc*(0.004817+0.000014*jc))+Math.sin(rad*2*mean_anom_sun)*(0.019993-0.000101*jc)+Math.sin(rad*3*mean_anom_sun)*0.000289;
        var sun_true_long = mean_long_sun + sun_eq;
        var sun_app_long = sun_true_long - 0.00569 - 0.00478*Math.sin(rad*125.04-1934.136*jc);
        var mean_obliq_ecliptic = 23+(26+((21.448-jc*(46.815+jc*(0.00059-jc*0.001813))))/60)/60;
        var obliq_corr = mean_obliq_ecliptic + 0.00256*Math.cos(rad*125.04-1934.136*jc);

        var lat = Math.asin(Math.sin(rad*obliq_corr)*Math.sin(rad*sun_app_long)) / rad;

        var eccent = 0.016708634-jc*(0.000042037+0.0000001267*jc);
        var y = Math.tan(rad*(obliq_corr/2))*Math.tan(rad*(obliq_corr/2));
        var rq_of_time = 4*((y*Math.sin(2*rad*mean_long_sun)-2*eccent*Math.sin(rad*mean_anom_sun)+4*eccent*y*Math.sin(rad*mean_anom_sun)*Math.cos(2*rad*mean_long_sun)-0.5*y*y*Math.sin(4*rad*mean_long_sun)-1.25*eccent*eccent*Math.sin(2*rad*mean_anom_sun))/rad);
        var true_solar_time = (mins_past_midnight*1440+rq_of_time) % 1440;
        var lng = (true_solar_time/4 < 0) ? true_solar_time/4 + 180 : true_solar_time/4 - 180;

        this.sun_position = new google.maps.LatLng(lat, lng);
    },
    setDate: function(date) {
        this.date = date;
        this.refresh();
    },
    setMap: function(map) {
        this.map = map;
    },
    show: function() {
        this.marker_shadow.setVisible(true);
        this.marker_shadow_lite.setVisible(true);
        this.refresh();
    },
    hide: function() {
        this.marker_shadow.setVisible(false);
        this.marker_shadow_lite.setVisible(false);
    },
    isVisible: function() {
        return this.marker_shadow.getVisible();
    }
}
<|endoftext|>


<commit_before>/*
 Replace the array this.currentCommandArray with an array of commands for the arduino neopixel controller,
 and this will loop over them continuously.
 Set this.currentCommandArrayPoint to 0 to put it back at command 0.
 */

const webModel = require('./webModel');
const robotModel = require('./robotModel');
const webModelFunctions = require('./webModelFunctions');
const UsbDevice = require('./UsbDevice.js');
const SerialPort = require("serialport");
const howManySecondsSince = require('./howManySecondsSince');
const masterRelay = require('./MasterRelay');
const personalData = require('./personalData');

// Adjustable contants for the board:
const baudrate = 115200;
const retrySendDelay = 15;
const postSendDelay = 250;

class Arduino {
    /** @namespace personalData.relays.has_arduino */
    /** @namespace personalData.arduinoUniqueString */
    /** @namespace personalData.arduinoStringLocation */
    constructor(runFromCommandLine) {
        this.programIsBusy = false; // Prevent multiple instances from running at once in the same program
        this.arduinoReady = false;
        this.arduinoBusy = true;
        this.arduinoBusyStartTime = new Date();
        this.arduinoBusyTimeoutSeconds = 60;
        this.repeatTimeout = null;
        this.runFromCommandLine = runFromCommandLine;
        this.portObj = null;

        // Commands programmed into the arduino
        this.lightPattern = {
            colorWipe: 0,
            rainbow: 1,
            rainbowCycle: 2,
            theaterChase: 3,
            theaterChaseRainbow: 4,
            alternate: 5,
            fillSolid: 9
        };

        // Named pixels
        this.pixel = {
            LOOP_START: 33, // First LED on the top of the ring.
            LOOP_END: 119 // My last pixel has no green :(
        };

        this.currentCommandArrayPoint = 0;
        this.ledTestCommandArray = [
            // Clear the loop with a black wipe
            `${this.lightPattern.colorWipe},0,0,0,${this.pixel.LOOP_START},${this.pixel.LOOP_END},25`,
            // Start wipe in the middle of the loop
            `${this.lightPattern.colorWipe},255,255,255,100,${this.pixel.LOOP_END},25`,
            `${this.lightPattern.colorWipe},255,255,255,${this.pixel.LOOP_START},100,25`,
            // Wipe and clear small section in reverse order
            `${this.lightPattern.colorWipe},255,0,0,90,105,20`,
            `${this.lightPattern.colorWipe},0,0,0,105,90,20`,
            `${this.lightPattern.colorWipe},255,0,0,105,90,20`,
            `${this.lightPattern.colorWipe},0,0,0,90,105,20`,
            // Wipe and clear small section in same order
            `${this.lightPattern.colorWipe},255,0,0,90,105,20`,
            `${this.lightPattern.colorWipe},0,0,0,90,105,20`,
            `${this.lightPattern.colorWipe},255,0,0,105,90,20`,
            `${this.lightPattern.colorWipe},0,0,0,105,90,20`,
            // Theater Chase in a small section
            `${this.lightPattern.theaterChase},255,0,0,50,90,106,30`,
            // Clear loop with a black wipe
            `${this.lightPattern.colorWipe},0,0,0,${this.pixel.LOOP_START},${this.pixel.LOOP_END},25`,
            // Make some big color loops with escalating speed
            `${this.lightPattern.colorWipe},255,0,0,${this.pixel.LOOP_START},${this.pixel.LOOP_END},25`,
            `${this.lightPattern.colorWipe},0,255,0,${this.pixel.LOOP_START},${this.pixel.LOOP_END},15`,
            `${this.lightPattern.colorWipe},0,0,255,${this.pixel.LOOP_START},${this.pixel.LOOP_END},10`,
            `${this.lightPattern.rainbow},${this.pixel.LOOP_START},${this.pixel.LOOP_END},1`,
            `${this.lightPattern.rainbowCycle},${this.pixel.LOOP_START},${this.pixel.LOOP_END},1`,
            // Escalate the chase
            // NOTE: Use consecutive chases to evaluate update speed,
            // Is it taking too long for a new command to get to the board,
            // causing gaps in the animation, or is it fluid?
            `${this.lightPattern.theaterChase},170,170,170,50,${this.pixel.LOOP_START},${this.pixel.LOOP_END},5`,
            `${this.lightPattern.theaterChase},170,170,170,50,${this.pixel.LOOP_START},${this.pixel.LOOP_END},5`,
            `${this.lightPattern.theaterChase},170,170,170,50,${this.pixel.LOOP_START},${this.pixel.LOOP_END},5`,
            `${this.lightPattern.theaterChase},170,170,170,40,${this.pixel.LOOP_START},${this.pixel.LOOP_END},20`,
            `${this.lightPattern.theaterChase},170,170,170,30,${this.pixel.LOOP_START},${this.pixel.LOOP_END},30`,
            `${this.lightPattern.theaterChase},170,170,170,20,${this.pixel.LOOP_START},${this.pixel.LOOP_END},30`,
            // Reverse Chase
            `${this.lightPattern.theaterChase},170,170,170,15,${this.pixel.LOOP_END},${this.pixel.LOOP_START},40`,
            // Super fast!
            `${this.lightPattern.theaterChase},170,170,170,10,${this.pixel.LOOP_START},${this.pixel.LOOP_END},50`,
            `${this.lightPattern.theaterChase},170,170,170,5,${this.pixel.LOOP_START},${this.pixel.LOOP_END},55`,
            `${this.lightPattern.theaterChaseRainbow},50,${this.pixel.LOOP_START},${this.pixel.LOOP_END},256`,
        ];
        this.currentCommandArray = [];
    }

    static getPortName() {
        /** @namespace personalData.masterPowerRelayStringLocation */
        /** @namespace personalData.masterPowerRelayUniqueString */
        const arduinoDevice = new UsbDevice(personalData.arduinoUniqueString, personalData.arduinoStringLocation);
        return arduinoDevice.findDeviceName();
    }

    turnOnRelays() {
        return new Promise((resolve, reject) => {
            let delay = 0;
            if (personalData.useMasterPowerRelay && !webModel.masterRelayOn) {
                masterRelay('on');
                delay = 3000;
            }
            setTimeout(() => {
                let delayTwo = 0;
                if (personalData.relays.has_arduino && !webModel.relays.find(x => x.name === 'arduino')['relayOn']) {
                    robotModel.usbRelay.switchRelay(webModel.relays.find(x => x.name === 'arduino')['number'], 'on');
                    delayTwo = 2000;
                }
                if (personalData.relays.has_fiveVolt && !webModel.relays.find(x => x.name === 'fiveVolt')['relayOn']) {
                    robotModel.usbRelay.switchRelay(webModel.relays.find(x => x.name === 'fiveVolt')['number'], 'on');
                    delayTwo = 4000;
                }
                setTimeout(() => {
                    // TODO: This assumes both relays exist.
                    // TODO: Rely on results to continue instead of delay and fail.
                    if (webModel.relays.find(x => x.name === 'arduino')['relayOn'] && webModel.relays.find(x => x.name === 'fiveVolt')['relayOn']) {
                        resolve();
                    } else {
                        reject('Relays did not turn on.');
                    }
                }, delayTwo);
            }, delay);
        })
    }

    sendCommandToArduino() {
        if (this.repeatTimeout) {
            clearTimeout(this.repeatTimeout);
        }
        if (!this.arduinoReady || (this.arduinoBusy && howManySecondsSince(this.arduinoBusyStartTime) < this.arduinoBusyTimeoutSeconds)) {
            this.repeatTimeout = setTimeout(() => {
                this.sendCommandToArduino();
            }, retrySendDelay);
        } else {
            this.arduinoBusy = false;
            this.arduinoBusyStartTime = new Date();
            if (this.runFromCommandLine) {
                console.log(`${this.currentCommandArray[this.currentCommandArrayPoint]}->`);
            }
            this.portObj.write(`${this.currentCommandArray[this.currentCommandArrayPoint]}\n`, (err) => { // Argument Options: err, result
                if (err) {
                    console.log(`Write ERROR: ${err}`);
                }
                if (this.currentCommandArrayPoint < this.currentCommandArray.length - 1) {
                    this.currentCommandArrayPoint++;
                } else {
                    this.currentCommandArrayPoint = 0;
                }
                this.repeatTimeout = setTimeout(() => {
                    this.sendCommandToArduino();
                }, postSendDelay);
            });
        }
    }

    init() {
        // See Camera.js for example
        let inputStream = '';
        const inputArray = [];
        this.currentCommandArray = this.ledTestCommandArray;
        if (!this.programIsBusy) {
            webModelFunctions.update('neoPixelsOn', true);
            this.programIsBusy = true;
            this.turnOnRelays()
                .then(() => {
                    return Arduino.getPortName()
                })
                .then((port) => {
                    this.currentCommandArrayPoint = 0;

                    // var wrapUp = (runFromCommandLine, error) => {
                    //     if (runFromCommandLine && error) {
                    //         console.error('Failed to write to port: ' + error);
                    //         process.exit(1);
                    //     }
                    //     this.programIsBusy = false;
                    // };

                    this.portObj = new SerialPort(port, {
                        baudRate: baudrate,
                        autoOpen: false
                    });

                    this.portObj.on('data', (data) => {
                        // The "buffer" has to be converted into a string.
                        // console.log(String(data));
                        inputStream += String(data);
                        // Serial Port uses \r\n to separate lines of input.
                        if (inputStream.indexOf('\r\n') > -1) {
                            inputArray.push(inputStream.split('\r\n'));
                            inputStream = '';
                            let output = inputArray.shift();
                            if (this.runFromCommandLine) {
                                console.log(`<-${output[0]}`);
                            }
                            if (output[0] === 'BUSY') {
                                this.arduinoBusy = true;
                                this.arduinoBusyStartTime = new Date();
                            }
                            if (output[0] === 'READY') {
                                if (this.repeatTimeout) {
                                    clearTimeout(this.repeatTimeout);
                                }
                                this.repeatTimeout = setTimeout(() => {
                                    this.sendCommandToArduino();
                                }, postSendDelay);
                                this.arduinoBusy = false;
                                this.arduinoReady = true;
                            }
                            if (output[0] === 'DONE') {
                                if (this.repeatTimeout) {
                                    clearTimeout(this.repeatTimeout);
                                }
                                this.repeatTimeout = setTimeout(() => {
                                    this.sendCommandToArduino();
                                }, retrySendDelay);
                                this.arduinoBusy = false;
                            }
                        }
                    });

                    this.portObj.open((error) => {
                        if (error) {
                            console.log('Arduino Connection Error: ' + error);
                        } else {
                            this.repeatTimeout = setTimeout(() => {
                                this.sendCommandToArduino();
                            }, retrySendDelay);
                        }
                    });
                })
                .catch(error => {
                    console.log(`Arduino Error: ${error}`);
                    webModelFunctions.update('neoPixelsOn', false);
                    this.programIsBusy = false;
                });
        }
    }

    pause() {
        this.arduinoReady = false;
        if (this.repeatTimeout) {
            clearTimeout(this.repeatTimeout);
        }
    }

    waitUntilNotBusy(callback) {
        setTimeout(() => {
            if (!this.arduinoBusy) {
                callback();
            } else {
                setTimeout(() => {
                    this.waitUntilNotBusy(callback);
                }, 1000);
            }
        }, 1000);
    }

    lightsOut() {
        this.currentCommandArrayPoint = 0;
        this.currentCommandArray = [
            `${this.lightPattern.fillSolid},0,0,0,${this.pixel.LOOP_END}`
        ];
        setTimeout(() => {
            // Give it time to send the new command at least once.
            this.pause();
            if (this.portObj) {
                this.portObj.close();
            }
            this.programIsBusy = false;
            webModelFunctions.update('neoPixelsOn', false);
        }, 5000);
    }
}
module.exports = Arduino;
if (require.main === module) {
    // Run the function if this is called directly instead of required as a module.
    const Arduino = require('./Arduino');
    const arduino = new Arduino(true);
    arduino.init();
    // Test sending custom pattern lists:
    // setTimeout(()=> {
    //     arduino.currentCommandArray = [
    //         `${arduino.lightPattern.colorWipe},255,0,0,${arduino.pixel.LOOP_START},${arduino.pixel.LOOP_END},10`,
    //         `${arduino.lightPattern.colorWipe},0,255,0,${arduino.pixel.LOOP_END},${arduino.pixel.LOOP_START},10`,
    //         `${arduino.lightPattern.colorWipe},0,0,255,${arduino.pixel.LOOP_START},${arduino.pixel.LOOP_END},10`
    //     ];
    //     arduino.currentCommandArrayPoint = 0;
    //     console.log('Now it should be different.');
    //     setTimeout(()=>{
    //         arduino.currentCommandArray = arduino.ledTestCommandArray;
    //         arduino.currentCommandArrayPoint = 0;
    //         console.log('Now back to the test pattern');
    //     }, 30000);
    // }, 20000);

    // Test pausing:
    // setTimeout(()=> {
    //     arduino.pause();
    //     console.log('Lights should cease shortly.');
    // }, 30000);

    // Test shutting off lights:
    //setTimeout(()=> {
    //    console.log('Lights should go out and stay out shortly.');
    //    arduino.lightsOut();
    //}, 30000);
}
<commit_msg>Deal with unexpected port closure on Arduino serial connection.<commit_after>/*
 Replace the array this.currentCommandArray with an array of commands for the arduino neopixel controller,
 and this will loop over them continuously.
 Set this.currentCommandArrayPoint to 0 to put it back at command 0.
 */

const webModel = require('./webModel');
const robotModel = require('./robotModel');
const webModelFunctions = require('./webModelFunctions');
const UsbDevice = require('./UsbDevice.js');
const SerialPort = require("serialport");
const howManySecondsSince = require('./howManySecondsSince');
const masterRelay = require('./MasterRelay');
const personalData = require('./personalData');

// Adjustable contants for the board:
const baudrate = 115200;
const retrySendDelay = 15;
const postSendDelay = 250;

class Arduino {
    /** @namespace personalData.relays.has_arduino */
    /** @namespace personalData.arduinoUniqueString */
    /** @namespace personalData.arduinoStringLocation */
    constructor(runFromCommandLine) {
        this.programIsBusy = false; // Prevent multiple instances from running at once in the same program
        this.arduinoReady = false;
        this.arduinoBusy = true;
        this.arduinoBusyStartTime = new Date();
        this.arduinoBusyTimeoutSeconds = 60;
        this.repeatTimeout = null;
        this.runFromCommandLine = runFromCommandLine;
        this.portObj = null;

        // Commands programmed into the arduino
        this.lightPattern = {
            colorWipe: 0,
            rainbow: 1,
            rainbowCycle: 2,
            theaterChase: 3,
            theaterChaseRainbow: 4,
            alternate: 5,
            fillSolid: 9
        };

        // Named pixels
        this.pixel = {
            LOOP_START: 33, // First LED on the top of the ring.
            LOOP_END: 119 // My last pixel has no green :(
        };

        this.currentCommandArrayPoint = 0;
        this.ledTestCommandArray = [
            // Clear the loop with a black wipe
            `${this.lightPattern.colorWipe},0,0,0,${this.pixel.LOOP_START},${this.pixel.LOOP_END},25`,
            // Start wipe in the middle of the loop
            `${this.lightPattern.colorWipe},255,255,255,100,${this.pixel.LOOP_END},25`,
            `${this.lightPattern.colorWipe},255,255,255,${this.pixel.LOOP_START},100,25`,
            // Wipe and clear small section in reverse order
            `${this.lightPattern.colorWipe},255,0,0,90,105,20`,
            `${this.lightPattern.colorWipe},0,0,0,105,90,20`,
            `${this.lightPattern.colorWipe},255,0,0,105,90,20`,
            `${this.lightPattern.colorWipe},0,0,0,90,105,20`,
            // Wipe and clear small section in same order
            `${this.lightPattern.colorWipe},255,0,0,90,105,20`,
            `${this.lightPattern.colorWipe},0,0,0,90,105,20`,
            `${this.lightPattern.colorWipe},255,0,0,105,90,20`,
            `${this.lightPattern.colorWipe},0,0,0,105,90,20`,
            // Theater Chase in a small section
            `${this.lightPattern.theaterChase},255,0,0,50,90,106,30`,
            // Clear loop with a black wipe
            `${this.lightPattern.colorWipe},0,0,0,${this.pixel.LOOP_START},${this.pixel.LOOP_END},25`,
            // Make some big color loops with escalating speed
            `${this.lightPattern.colorWipe},255,0,0,${this.pixel.LOOP_START},${this.pixel.LOOP_END},25`,
            `${this.lightPattern.colorWipe},0,255,0,${this.pixel.LOOP_START},${this.pixel.LOOP_END},15`,
            `${this.lightPattern.colorWipe},0,0,255,${this.pixel.LOOP_START},${this.pixel.LOOP_END},10`,
            `${this.lightPattern.rainbow},${this.pixel.LOOP_START},${this.pixel.LOOP_END},1`,
            `${this.lightPattern.rainbowCycle},${this.pixel.LOOP_START},${this.pixel.LOOP_END},1`,
            // Escalate the chase
            // NOTE: Use consecutive chases to evaluate update speed,
            // Is it taking too long for a new command to get to the board,
            // causing gaps in the animation, or is it fluid?
            `${this.lightPattern.theaterChase},170,170,170,50,${this.pixel.LOOP_START},${this.pixel.LOOP_END},5`,
            `${this.lightPattern.theaterChase},170,170,170,50,${this.pixel.LOOP_START},${this.pixel.LOOP_END},5`,
            `${this.lightPattern.theaterChase},170,170,170,50,${this.pixel.LOOP_START},${this.pixel.LOOP_END},5`,
            `${this.lightPattern.theaterChase},170,170,170,40,${this.pixel.LOOP_START},${this.pixel.LOOP_END},20`,
            `${this.lightPattern.theaterChase},170,170,170,30,${this.pixel.LOOP_START},${this.pixel.LOOP_END},30`,
            `${this.lightPattern.theaterChase},170,170,170,20,${this.pixel.LOOP_START},${this.pixel.LOOP_END},30`,
            // Reverse Chase
            `${this.lightPattern.theaterChase},170,170,170,15,${this.pixel.LOOP_END},${this.pixel.LOOP_START},40`,
            // Super fast!
            `${this.lightPattern.theaterChase},170,170,170,10,${this.pixel.LOOP_START},${this.pixel.LOOP_END},50`,
            `${this.lightPattern.theaterChase},170,170,170,5,${this.pixel.LOOP_START},${this.pixel.LOOP_END},55`,
            `${this.lightPattern.theaterChaseRainbow},50,${this.pixel.LOOP_START},${this.pixel.LOOP_END},256`,
        ];
        this.currentCommandArray = [];
    }

    static getPortName() {
        /** @namespace personalData.masterPowerRelayStringLocation */
        /** @namespace personalData.masterPowerRelayUniqueString */
        const arduinoDevice = new UsbDevice(personalData.arduinoUniqueString, personalData.arduinoStringLocation);
        return arduinoDevice.findDeviceName();
    }

    turnOnRelays() {
        return new Promise((resolve, reject) => {
            let delay = 0;
            if (personalData.useMasterPowerRelay && !webModel.masterRelayOn) {
                masterRelay('on');
                delay = 3000;
            }
            setTimeout(() => {
                let delayTwo = 0;
                if (personalData.relays.has_arduino && !webModel.relays.find(x => x.name === 'arduino')['relayOn']) {
                    robotModel.usbRelay.switchRelay(webModel.relays.find(x => x.name === 'arduino')['number'], 'on');
                    delayTwo = 2000;
                }
                if (personalData.relays.has_fiveVolt && !webModel.relays.find(x => x.name === 'fiveVolt')['relayOn']) {
                    robotModel.usbRelay.switchRelay(webModel.relays.find(x => x.name === 'fiveVolt')['number'], 'on');
                    delayTwo = 4000;
                }
                setTimeout(() => {
                    // TODO: This assumes both relays exist.
                    // TODO: Rely on results to continue instead of delay and fail.
                    if (webModel.relays.find(x => x.name === 'arduino')['relayOn'] && webModel.relays.find(x => x.name === 'fiveVolt')['relayOn']) {
                        resolve();
                    } else {
                        reject('Relays did not turn on.');
                    }
                }, delayTwo);
            }, delay);
        })
    }

    sendCommandToArduino() {
        if (this.repeatTimeout) {
            clearTimeout(this.repeatTimeout);
        }
        if (!this.arduinoReady || (this.arduinoBusy && howManySecondsSince(this.arduinoBusyStartTime) < this.arduinoBusyTimeoutSeconds)) {
            this.repeatTimeout = setTimeout(() => {
                this.sendCommandToArduino();
            }, retrySendDelay);
        } else {
            this.arduinoBusy = false;
            this.arduinoBusyStartTime = new Date();
            if (this.runFromCommandLine) {
                console.log(`${this.currentCommandArray[this.currentCommandArrayPoint]}->`);
            }
            this.portObj.write(`${this.currentCommandArray[this.currentCommandArrayPoint]}\n`, (err) => { // Argument Options: err, result
                if (err) {
                    console.log(`Write ERROR: ${err}`);
                }
                if (this.currentCommandArrayPoint < this.currentCommandArray.length - 1) {
                    this.currentCommandArrayPoint++;
                } else {
                    this.currentCommandArrayPoint = 0;
                }
                this.repeatTimeout = setTimeout(() => {
                    this.sendCommandToArduino();
                }, postSendDelay);
            });
        }
    }

    init() {
        // See Camera.js for example
        let inputStream = '';
        const inputArray = [];
        this.currentCommandArray = this.ledTestCommandArray;
        if (!this.programIsBusy) {
            webModelFunctions.update('neoPixelsOn', true);
            this.programIsBusy = true;
            this.turnOnRelays()
                .then(() => {
                    return Arduino.getPortName()
                })
                .then((port) => {
                    this.currentCommandArrayPoint = 0;

                    // var wrapUp = (runFromCommandLine, error) => {
                    //     if (runFromCommandLine && error) {
                    //         console.error('Failed to write to port: ' + error);
                    //         process.exit(1);
                    //     }
                    //     this.programIsBusy = false;
                    // };

                    this.portObj = new SerialPort(port, {
                        baudRate: baudrate,
                        autoOpen: false
                    });

                    this.portObj.on('data', (data) => {
                        // The "buffer" has to be converted into a string.
                        // console.log(String(data));
                        inputStream += String(data);
                        // Serial Port uses \r\n to separate lines of input.
                        if (inputStream.indexOf('\r\n') > -1) {
                            inputArray.push(inputStream.split('\r\n'));
                            inputStream = '';
                            let output = inputArray.shift();
                            if (this.runFromCommandLine) {
                                console.log(`<-${output[0]}`);
                            }
                            if (output[0] === 'BUSY') {
                                this.arduinoBusy = true;
                                this.arduinoBusyStartTime = new Date();
                            }
                            if (output[0] === 'READY') {
                                if (this.repeatTimeout) {
                                    clearTimeout(this.repeatTimeout);
                                }
                                this.repeatTimeout = setTimeout(() => {
                                    this.sendCommandToArduino();
                                }, postSendDelay);
                                this.arduinoBusy = false;
                                this.arduinoReady = true;
                            }
                            if (output[0] === 'DONE') {
                                if (this.repeatTimeout) {
                                    clearTimeout(this.repeatTimeout);
                                }
                                this.repeatTimeout = setTimeout(() => {
                                    this.sendCommandToArduino();
                                }, retrySendDelay);
                                this.arduinoBusy = false;
                            }
                        }
                    });

                    this.portObj.on('close', () => {
                        this.pause();
                        this.portObj = null;
                        this.programIsBusy = false;
                        webModelFunctions.update('neoPixelsOn', false);
                    })

                    this.portObj.open((error) => {
                        if (error) {
                            console.log('Arduino Connection Error: ' + error);
                        } else {
                            this.repeatTimeout = setTimeout(() => {
                                this.sendCommandToArduino();
                            }, retrySendDelay);
                        }
                    });
                })
                .catch(error => {
                    console.log(`Arduino Error: ${error}`);
                    webModelFunctions.update('neoPixelsOn', false);
                    this.programIsBusy = false;
                });
        }
    }

    pause() {
        this.arduinoReady = false;
        if (this.repeatTimeout) {
            clearTimeout(this.repeatTimeout);
        }
    }

    waitUntilNotBusy(callback) {
        setTimeout(() => {
            if (!this.arduinoBusy) {
                callback();
            } else {
                setTimeout(() => {
                    this.waitUntilNotBusy(callback);
                }, 1000);
            }
        }, 1000);
    }

    lightsOut() {
        this.currentCommandArrayPoint = 0;
        this.currentCommandArray = [
            `${this.lightPattern.fillSolid},0,0,0,${this.pixel.LOOP_END}`
        ];
        setTimeout(() => {
            // Give it time to send the new command at least once.
            this.pause();
            if (this.portObj) {
              this.portObj.close();
            }
            this.programIsBusy = false;
            webModelFunctions.update('neoPixelsOn', false);
        }, 5000);
    }
}
module.exports = Arduino;
if (require.main === module) {
    // Run the function if this is called directly instead of required as a module.
    const Arduino = require('./Arduino');
    const arduino = new Arduino(true);
    arduino.init();
    // Test sending custom pattern lists:
    // setTimeout(()=> {
    //     arduino.currentCommandArray = [
    //         `${arduino.lightPattern.colorWipe},255,0,0,${arduino.pixel.LOOP_START},${arduino.pixel.LOOP_END},10`,
    //         `${arduino.lightPattern.colorWipe},0,255,0,${arduino.pixel.LOOP_END},${arduino.pixel.LOOP_START},10`,
    //         `${arduino.lightPattern.colorWipe},0,0,255,${arduino.pixel.LOOP_START},${arduino.pixel.LOOP_END},10`
    //     ];
    //     arduino.currentCommandArrayPoint = 0;
    //     console.log('Now it should be different.');
    //     setTimeout(()=>{
    //         arduino.currentCommandArray = arduino.ledTestCommandArray;
    //         arduino.currentCommandArrayPoint = 0;
    //         console.log('Now back to the test pattern');
    //     }, 30000);
    // }, 20000);

    // Test pausing:
    // setTimeout(()=> {
    //     arduino.pause();
    //     console.log('Lights should cease shortly.');
    // }, 30000);

    // Test shutting off lights:
    //setTimeout(()=> {
    //    console.log('Lights should go out and stay out shortly.');
    //    arduino.lightsOut();
    //}, 30000);
}
<|endoftext|>


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


<commit_before>
var NAME                = 0,
    DOT                 = 1,
    CHARACTER_CLASS     = 2,
    ORDERED_CHOICE      = 3,
    SEQUENCE            = 4,
    STRING_LITERAL      = 5,
    ZERO_OR_MORE        = 6,
    ONE_OR_MORE         = 7,
    OPTIONAL            = 8,
    NEGATIVE_LOOK_AHEAD = 9,
    POSITIVE_LOOK_AHEAD = 10,
    ERROR_NAME          = 11,
    ERROR_CHOICE        = 12;

var factories = [];

factories[STRING_LITERAL] = function(id, parent, state)
{
    return function(character)
    {
        var string = rules[id][1];

        if (string.charAt(state) === character)
        {
            if (state === string.length - 1)
                return parent;

            return parser(id, parent, state + 1);
        }

        return failure;
    }
}

factories[SEQUENCE] = function(id, parent, state)
{
    return function(character)
    {
        rule = rules[id];

        // If not the last one...
        if (state + 1 < rule.length - 1)
            parent = parser(id, parent, state + 1);

        return parser(rule[state + 1], parent)(character);
    }
}

factories[ORDERED_CHOICE] = function(id, parent, state)
{
    return function(character)
    {
        var rule = rules[id],
            index = 1,
            count = rule.length,
            parsers = [];

        for (; index < count; ++index)
            parsers = parsers.concat(parser(rule[index], parent)(character));

        return parsers;
    }
}

function success()
{
    console.log("success");
    return success;
}

function failure()
{
    console.log("failure");
    return failure;
}

function parser(id, parent, state)
{
    return factories[rules[id][0]](id, parent, state || 0);
}

function isNotFailure(parser)
{
    return parser !== failure;
}

function parse(parsers, character)
{
    var index = 0,
        count = parsers.length,
        results = [];

    for (; index < count; ++index)
        results = results.concat(parsers[index](character));

    return results.filter(isNotFailure);
}

var rules = [
                [SEQUENCE, 1, 2, 3],
                [STRING_LITERAL, "abc"],
                [STRING_LITERAL, "def"],
                [ORDERED_CHOICE, 1, 2]
            ];

var input = "abcdefddd",
    parsers = [parser(0, success)];

for (i = 0; i < input.length && parsers.length > 0; ++i)
    parsers = parse(parsers, input.charAt(i));

while (parsers.length > 0 && parsers[0] !== success)
    parsers = parse(parsers, null);

if (parsers.length > 0)
    console.log("success");
else
    console.log("failure");
<commit_msg>Added support for DOT and CHARACTER_CLASS to character based iteration parser.<commit_after>
var NAME                = 0,
    DOT                 = 1,
    CHARACTER_CLASS     = 2,
    ORDERED_CHOICE      = 3,
    SEQUENCE            = 4,
    STRING_LITERAL      = 5,
    ZERO_OR_MORE        = 6,
    ONE_OR_MORE         = 7,
    OPTIONAL            = 8,
    NEGATIVE_LOOK_AHEAD = 9,
    POSITIVE_LOOK_AHEAD = 10,
    ERROR_NAME          = 11,
    ERROR_CHOICE        = 12;

var factories = [];

factories[DOT] = function(id, parent, state)
{
    return function(character)
    {
        if (character !== null)
            return parent;

        return failure;
    }
}

factories[CHARACTER_CLASS] = function(id, parent, state)
{
    var rule = rules[id];

    if (typeof rule[1].valueOf() === "string")
        rule[1] = new RegExp(rule[1], "g");

    return function(character)
    {
        if (character.match(rule[1]))
            return parent;

        return failure;
    }
}

factories[STRING_LITERAL] = function(id, parent, state)
{
    return function(character)
    {
        var string = rules[id][1];

        if (string.charAt(state) === character)
        {
            if (state === string.length - 1)
                return parent;

            return parser(id, parent, state + 1);
        }

        return failure;
    }
}

factories[SEQUENCE] = function(id, parent, state)
{
    return function(character)
    {
        rule = rules[id];

        // If not the last one...
        if (state + 1 < rule.length - 1)
            parent = parser(id, parent, state + 1);

        return parser(rule[state + 1], parent)(character);
    }
}

factories[ORDERED_CHOICE] = function(id, parent, state)
{
    return function(character)
    {
        var rule = rules[id],
            index = 1,
            count = rule.length,
            parsers = [];

        for (; index < count; ++index)
            parsers = parsers.concat(parser(rule[index], parent)(character));

        return parsers;
    }
}

function success()
{
    console.log("success");
    return success;
}

function failure()
{
    console.log("failure");
    return failure;
}

function parser(id, parent, state)
{
    return factories[rules[id][0]](id, parent, state || 0);
}

function isNotFailure(parser)
{
    return parser !== failure;
}

function parse(parsers, character)
{
    var index = 0,
        count = parsers.length,
        results = [];

    for (; index < count; ++index)
        results = results.concat(parsers[index](character));

    return results.filter(isNotFailure);
}

var rules = [
                [SEQUENCE, 1, 2, 3, 4, 5],
                [STRING_LITERAL, "abc"],
                [STRING_LITERAL, "def"],
                [ORDERED_CHOICE, 1, 2],
                [DOT],
                [CHARACTER_CLASS, "[abc]"]
            ];

var input = "abcdefdeffe",
    parsers = [parser(0, success)];

for (i = 0; i < input.length && parsers.length > 0; ++i)
    parsers = parse(parsers, input.charAt(i));

while (parsers.length > 0 && parsers[0] !== success)
    parsers = parse(parsers, null);

if (parsers.length > 0)
    console.log("success");
else
    console.log("failure");
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var EventEmitter = require('./lib/event_emitter');
var stat = require('./lib/stat');
var inherits = require('util').inherits;

var errors = require('./errors');
var States = require('./reqres_states');

function TChannelOutResponse(id, options) {
    options = options || {};
    var self = this;
    EventEmitter.call(self);
    self.errorEvent = self.defineEvent('error');
    self.spanEvent = self.defineEvent('span');
    self.finishEvent = self.defineEvent('finish');

    self.channel = options.channel;
    self.inreq = options.inreq;
    self.logger = options.logger;
    self.random = options.random;
    self.timers = options.timers;

    self.start = 0;
    self.end = 0;
    self.state = States.Initial;
    self.id = id || 0;
    self.code = options.code || 0;
    self.tracing = options.tracing || null;
    self.headers = options.headers || {};
    self.checksumType = options.checksumType || 0;
    self.checksum = options.checksum || null;
    self.ok = self.code === 0;
    self.span = options.span || null;
    self.streamed = false;
    self._argstream = null;
    self.arg1 = null;
    self.arg2 = null;
    self.arg3 = null;

    self.codeString = null;
    self.message = null;
}

inherits(TChannelOutResponse, EventEmitter);

TChannelOutResponse.prototype.type = 'tchannel.outgoing-response';

TChannelOutResponse.prototype.extendLogInfo = function extendLogInfo(info) {
    var self = this;

    info.responseId = self.id;
    info.responseType = self.type;
    info.responseState = States.describe(self.state);
    info.responseOk = self.ok;
    info.responseCode = self.code;
    info.responseCodeString = self.codeString;
    info.responseErrorMessage = self.message;
    info.responseStart = self.start;
    info.responseEnd = self.end;
    info.responseHasArg3 = self.arg3 !== null && self.arg3 !== undefined;

    if (self.inreq) {
        info = self.inreq.extendLogInfo(info);
    }

    return info;
};

TChannelOutResponse.prototype._sendCallResponse = function _sendCallResponse(args, isLast) {
    var self = this;
    throw errors.UnimplementedMethod({
        className: self.constructor.name,
        methodName: '_sendCallResponse'
    });
};

TChannelOutResponse.prototype._sendCallResponseCont = function _sendCallResponseCont(args, isLast) {
    var self = this;
    throw errors.UnimplementedMethod({
        className: self.constructor.name,
        methodName: '_sendCallResponseCont'
    });
};

TChannelOutResponse.prototype._sendError = function _sendError(codeString, message) {
    var self = this;
    throw errors.UnimplementedMethod({
        className: self.constructor.name,
        methodName: '_sendError'
    });
};

TChannelOutResponse.prototype.sendParts = function sendParts(parts, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.sendCallResponseFrame(parts, isLast);
            break;
        case States.Streaming:
            self.sendCallResponseContFrame(parts, isLast);
            break;
        case States.Done:
            self.errorEvent.emit(self, errors.ResponseFrameState({
                attempted: 'arg parts',
                state: 'Done'
            }));
            break;
        case States.Error:
            // TODO: log warn
            break;
        default:
            self.channel.logger.error('TChannelOutResponse is in a wrong state', self.extendLogInfo({}));
            break;
    }
};

TChannelOutResponse.prototype.sendCallResponseFrame = function sendCallResponseFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.start = self.timers.now();
            self._sendCallResponse(args, isLast);
            if (self.span) {
                self.span.annotate('ss');
            }
            if (isLast) self.state = States.Done;
            else self.state = States.Streaming;
            break;
        case States.Streaming:
            self.errorEvent.emit(self, errors.ResponseFrameState({
                attempted: 'call response',
                state: 'Streaming'
            }));
            break;
        case States.Done:
        case States.Error:
            var arg2 = args[1] || '';
            var arg3 = args[2] || '';

            self.errorEvent.emit(self, errors.ResponseAlreadyDone({
                attempted: 'call response',
                state: self.state,
                method: 'sendCallResponseFrame',
                bufArg2: arg2.slice(0, 50),
                arg2: String(arg2).slice(0, 50),
                bufArg3: arg3.slice(0, 50),
                arg3: String(arg3).slice(0, 50)
            }));
    }
};

TChannelOutResponse.prototype.sendCallResponseContFrame = function sendCallResponseContFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.errorEvent.emit(self, errors.ResponseFrameState({
                attempted: 'call response continuation',
                state: 'Initial'
            }));
            break;
        case States.Streaming:
            self._sendCallResponseCont(args, isLast);
            if (isLast) self.state = States.Done;
            break;
        case States.Done:
        case States.Error:
            self.errorEvent.emit(self, errors.ResponseAlreadyDone({
                attempted: 'call response continuation',
                state: self.state,
                method: 'sendCallResponseContFrame'
            }));
    }
};

TChannelOutResponse.prototype.sendError = function sendError(codeString, message) {
    var self = this;

    if (self.inreq.connection && // because selfpeer/connection
        self.inreq.connection.closing) {
        self.logger.info('ignoring outresponse.sendError on a closed connection', {
            codeString: codeString,
            errorMessage: message
        });
        return;
    }

    if (self.state === States.Done || self.state === States.Error) {
        self.errorEvent.emit(self, errors.ResponseAlreadyDone({
            attempted: 'error frame',
            currentState: self.state,
            method: 'sendError',
            codeString: codeString,
            errMessage: message
        }));
    } else {
        if (self.span) {
            self.span.annotate('ss');
        }
        self.state = States.Error;

        self.codeString = codeString;
        self.message = message;
        self.channel.inboundCallsSystemErrorsStat.increment(1, {
            'calling-service': self.inreq.headers.cn,
            'service': self.inreq.serviceName,
            'endpoint': String(self.inreq.arg1),
            'type': self.codeString
        });
        self._sendError(codeString, message);
        self.emitFinish();
    }
};

TChannelOutResponse.prototype.emitFinish = function emitFinish() {
    var self = this;
    var now = self.timers.now();

    if (self.end) {
        self.logger.warn('out response double emitFinish', self.extendLogInfo({
            now: now
        }));
        return;
    }

    self.end = now;

    var latency = self.end - self.inreq.start;

    self.channel.emitFastStat(self.channel.buildStat(
        'tchannel.inbound.calls.latency',
        'timing',
        latency,
        new stat.InboundCallsLatencyTags(
            self.inreq.headers.cn,
            self.inreq.serviceName,
            self.inreq.endpoint
        )
    ));

    if (self.span) {
        self.spanEvent.emit(self, self.span);
    }

    self.finishEvent.emit(self);
};

TChannelOutResponse.prototype.setOk = function setOk(ok) {
    var self = this;
    if (self.state !== States.Initial) {
        self.errorEvent.emit(self, errors.ResponseAlreadyStarted({
            state: self.state,
            method: 'setOk',
            ok: ok
        }));
        return false;
    }
    self.ok = ok;
    self.code = ok ? 0 : 1; // TODO: too coupled to v2 specifics?
    return true;
};

TChannelOutResponse.prototype.sendOk = function sendOk(res1, res2) {
    var self = this;
    self.setOk(true);
    self.send(res1, res2);
};

TChannelOutResponse.prototype.sendNotOk = function sendNotOk(res1, res2) {
    var self = this;
    if (self.state === States.Error) {
        self.logger.error('cannot send application error, already sent error frame', self.extendLogInfo({
            res1: res1,
            res2: res2
        }));
    } else {
        self.setOk(false);
        self.send(res1, res2);
    }
};

TChannelOutResponse.prototype.send = function send(res1, res2) {
    var self = this;

    /* send calls after finish() should be swallowed */
    if (self.end) {
        var inreqErrClass = self.inreq &&
                            self.inreq.err &&
                            errors.classify(self.inreq.err);

        switch (inreqErrClass) {
            case 'Timeout':
                self.logger.info('OutResponse.send() after inreq timed out', self.extendLogInfo({}));
                break;
            default:
                self.logger.warn('OutResponse called send() after end', self.extendLogInfo({}));
        }
        return self;
    }

    self.arg2 = res1;
    self.arg3 = res2;

    if (self.ok) {
        self.channel.emitFastStat(self.channel.buildStat(
            'tchannel.inbound.calls.success',
            'counter',
            1,
            new stat.InboundCallsSuccessTags(
                self.inreq.headers.cn,
                self.inreq.serviceName,
                self.inreq.endpoint
            )
        ));
    } else {
        // TODO: add outResponse.setErrorType()
        self.channel.emitFastStat(self.channel.buildStat(
            'tchannel.inbound.calls.app-errors',
            'counter',
            1,
            new stat.InboundCallsAppErrorsTags(
                self.inreq.headers.cn,
                self.inreq.serviceName,
                self.inreq.endpoint,
                'unknown'
            )
        ));
    }

    // TODO: may be spam, consider dropping
    if (self.inreq.connection && // because selfpeer/connection
        self.inreq.connection.closing) {
        self.logger.info('ignoring outresponse.send on a closed connection', self.extendLogInfo({}));
    } else {
        self.sendCallResponseFrame([self.arg1, res1, res2], true);
    }

    self.emitFinish();

    return self;
};

module.exports = TChannelOutResponse;
<commit_msg>TChannelOutResponse: switch to req.callerName<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var EventEmitter = require('./lib/event_emitter');
var stat = require('./lib/stat');
var inherits = require('util').inherits;

var errors = require('./errors');
var States = require('./reqres_states');

function TChannelOutResponse(id, options) {
    options = options || {};
    var self = this;
    EventEmitter.call(self);
    self.errorEvent = self.defineEvent('error');
    self.spanEvent = self.defineEvent('span');
    self.finishEvent = self.defineEvent('finish');

    self.channel = options.channel;
    self.inreq = options.inreq;
    self.logger = options.logger;
    self.random = options.random;
    self.timers = options.timers;

    self.start = 0;
    self.end = 0;
    self.state = States.Initial;
    self.id = id || 0;
    self.code = options.code || 0;
    self.tracing = options.tracing || null;
    self.headers = options.headers || {};
    self.checksumType = options.checksumType || 0;
    self.checksum = options.checksum || null;
    self.ok = self.code === 0;
    self.span = options.span || null;
    self.streamed = false;
    self._argstream = null;
    self.arg1 = null;
    self.arg2 = null;
    self.arg3 = null;

    self.codeString = null;
    self.message = null;
}

inherits(TChannelOutResponse, EventEmitter);

TChannelOutResponse.prototype.type = 'tchannel.outgoing-response';

TChannelOutResponse.prototype.extendLogInfo = function extendLogInfo(info) {
    var self = this;

    info.responseId = self.id;
    info.responseType = self.type;
    info.responseState = States.describe(self.state);
    info.responseOk = self.ok;
    info.responseCode = self.code;
    info.responseCodeString = self.codeString;
    info.responseErrorMessage = self.message;
    info.responseStart = self.start;
    info.responseEnd = self.end;
    info.responseHasArg3 = self.arg3 !== null && self.arg3 !== undefined;

    if (self.inreq) {
        info = self.inreq.extendLogInfo(info);
    }

    return info;
};

TChannelOutResponse.prototype._sendCallResponse = function _sendCallResponse(args, isLast) {
    var self = this;
    throw errors.UnimplementedMethod({
        className: self.constructor.name,
        methodName: '_sendCallResponse'
    });
};

TChannelOutResponse.prototype._sendCallResponseCont = function _sendCallResponseCont(args, isLast) {
    var self = this;
    throw errors.UnimplementedMethod({
        className: self.constructor.name,
        methodName: '_sendCallResponseCont'
    });
};

TChannelOutResponse.prototype._sendError = function _sendError(codeString, message) {
    var self = this;
    throw errors.UnimplementedMethod({
        className: self.constructor.name,
        methodName: '_sendError'
    });
};

TChannelOutResponse.prototype.sendParts = function sendParts(parts, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.sendCallResponseFrame(parts, isLast);
            break;
        case States.Streaming:
            self.sendCallResponseContFrame(parts, isLast);
            break;
        case States.Done:
            self.errorEvent.emit(self, errors.ResponseFrameState({
                attempted: 'arg parts',
                state: 'Done'
            }));
            break;
        case States.Error:
            // TODO: log warn
            break;
        default:
            self.channel.logger.error('TChannelOutResponse is in a wrong state', self.extendLogInfo({}));
            break;
    }
};

TChannelOutResponse.prototype.sendCallResponseFrame = function sendCallResponseFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.start = self.timers.now();
            self._sendCallResponse(args, isLast);
            if (self.span) {
                self.span.annotate('ss');
            }
            if (isLast) self.state = States.Done;
            else self.state = States.Streaming;
            break;
        case States.Streaming:
            self.errorEvent.emit(self, errors.ResponseFrameState({
                attempted: 'call response',
                state: 'Streaming'
            }));
            break;
        case States.Done:
        case States.Error:
            var arg2 = args[1] || '';
            var arg3 = args[2] || '';

            self.errorEvent.emit(self, errors.ResponseAlreadyDone({
                attempted: 'call response',
                state: self.state,
                method: 'sendCallResponseFrame',
                bufArg2: arg2.slice(0, 50),
                arg2: String(arg2).slice(0, 50),
                bufArg3: arg3.slice(0, 50),
                arg3: String(arg3).slice(0, 50)
            }));
    }
};

TChannelOutResponse.prototype.sendCallResponseContFrame = function sendCallResponseContFrame(args, isLast) {
    var self = this;
    switch (self.state) {
        case States.Initial:
            self.errorEvent.emit(self, errors.ResponseFrameState({
                attempted: 'call response continuation',
                state: 'Initial'
            }));
            break;
        case States.Streaming:
            self._sendCallResponseCont(args, isLast);
            if (isLast) self.state = States.Done;
            break;
        case States.Done:
        case States.Error:
            self.errorEvent.emit(self, errors.ResponseAlreadyDone({
                attempted: 'call response continuation',
                state: self.state,
                method: 'sendCallResponseContFrame'
            }));
    }
};

TChannelOutResponse.prototype.sendError = function sendError(codeString, message) {
    var self = this;

    if (self.inreq.connection && // because selfpeer/connection
        self.inreq.connection.closing) {
        self.logger.info('ignoring outresponse.sendError on a closed connection', {
            codeString: codeString,
            errorMessage: message
        });
        return;
    }

    if (self.state === States.Done || self.state === States.Error) {
        self.errorEvent.emit(self, errors.ResponseAlreadyDone({
            attempted: 'error frame',
            currentState: self.state,
            method: 'sendError',
            codeString: codeString,
            errMessage: message
        }));
    } else {
        if (self.span) {
            self.span.annotate('ss');
        }
        self.state = States.Error;

        self.codeString = codeString;
        self.message = message;
        self.channel.inboundCallsSystemErrorsStat.increment(1, {
            'calling-service': self.inreq.callerName,
            'service': self.inreq.serviceName,
            'endpoint': String(self.inreq.arg1),
            'type': self.codeString
        });
        self._sendError(codeString, message);
        self.emitFinish();
    }
};

TChannelOutResponse.prototype.emitFinish = function emitFinish() {
    var self = this;
    var now = self.timers.now();

    if (self.end) {
        self.logger.warn('out response double emitFinish', self.extendLogInfo({
            now: now
        }));
        return;
    }

    self.end = now;

    var latency = self.end - self.inreq.start;

    self.channel.emitFastStat(self.channel.buildStat(
        'tchannel.inbound.calls.latency',
        'timing',
        latency,
        new stat.InboundCallsLatencyTags(
            self.inreq.callerName,
            self.inreq.serviceName,
            self.inreq.endpoint
        )
    ));

    if (self.span) {
        self.spanEvent.emit(self, self.span);
    }

    self.finishEvent.emit(self);
};

TChannelOutResponse.prototype.setOk = function setOk(ok) {
    var self = this;
    if (self.state !== States.Initial) {
        self.errorEvent.emit(self, errors.ResponseAlreadyStarted({
            state: self.state,
            method: 'setOk',
            ok: ok
        }));
        return false;
    }
    self.ok = ok;
    self.code = ok ? 0 : 1; // TODO: too coupled to v2 specifics?
    return true;
};

TChannelOutResponse.prototype.sendOk = function sendOk(res1, res2) {
    var self = this;
    self.setOk(true);
    self.send(res1, res2);
};

TChannelOutResponse.prototype.sendNotOk = function sendNotOk(res1, res2) {
    var self = this;
    if (self.state === States.Error) {
        self.logger.error('cannot send application error, already sent error frame', self.extendLogInfo({
            res1: res1,
            res2: res2
        }));
    } else {
        self.setOk(false);
        self.send(res1, res2);
    }
};

TChannelOutResponse.prototype.send = function send(res1, res2) {
    var self = this;

    /* send calls after finish() should be swallowed */
    if (self.end) {
        var inreqErrClass = self.inreq &&
                            self.inreq.err &&
                            errors.classify(self.inreq.err);

        switch (inreqErrClass) {
            case 'Timeout':
                self.logger.info('OutResponse.send() after inreq timed out', self.extendLogInfo({}));
                break;
            default:
                self.logger.warn('OutResponse called send() after end', self.extendLogInfo({}));
        }
        return self;
    }

    self.arg2 = res1;
    self.arg3 = res2;

    if (self.ok) {
        self.channel.emitFastStat(self.channel.buildStat(
            'tchannel.inbound.calls.success',
            'counter',
            1,
            new stat.InboundCallsSuccessTags(
                self.inreq.callerName,
                self.inreq.serviceName,
                self.inreq.endpoint
            )
        ));
    } else {
        // TODO: add outResponse.setErrorType()
        self.channel.emitFastStat(self.channel.buildStat(
            'tchannel.inbound.calls.app-errors',
            'counter',
            1,
            new stat.InboundCallsAppErrorsTags(
                self.inreq.callerName,
                self.inreq.serviceName,
                self.inreq.endpoint,
                'unknown'
            )
        ));
    }

    // TODO: may be spam, consider dropping
    if (self.inreq.connection && // because selfpeer/connection
        self.inreq.connection.closing) {
        self.logger.info('ignoring outresponse.send on a closed connection', self.extendLogInfo({}));
    } else {
        self.sendCallResponseFrame([self.arg1, res1, res2], true);
    }

    self.emitFinish();

    return self;
};

module.exports = TChannelOutResponse;
<|endoftext|>


<commit_before>var EditorUI = (function () {
    var EditorUI = {};

    EditorUI.index = function ( element ) {
        var parentEL = Polymer.dom(element).parentNode;
        var parentDOM = Polymer.dom(parentEL);
        var curChildEL = parentDOM.children.length > 0 ? parentDOM.children[0] : null;

        for ( var i = 0, len = parentDOM.children.length; i < len; ++i ) {
            if ( parentDOM.children[i] === element )
                return i;
        }

        return -1;
    };

    var _findInChildren = function ( element, elementToFind ) {
        var elementDOM = Polymer.dom(element);

        for ( var i = 0; i < elementDOM.children.length; ++i ) {
            var childEL = elementDOM.children[i];
            if ( childEL === elementToFind )
                return true;

            if ( Polymer.dom(childEL).children.length > 0 )
                if ( _findInChildren( childEL, elementToFind ) )
                    return true;
        }
        return false;
    };

    //
    EditorUI.find = function ( elements, elementToFind ) {
        if ( Array.isArray(elements) ||
             elements instanceof NodeList ||
             elements instanceof HTMLCollection )
        {
            for ( var i = 0; i < elements.length; ++i ) {
                var element = elements[i];
                if ( element === elementToFind )
                    return true;

                if ( _findInChildren ( element, elementToFind ) )
                    return true;
            }
            return false;
        }

        // if this is a single element
        if ( elements === elementToFind )
            return true;

        return _findInChildren( elements, elementToFind );
    };

    //
    EditorUI.getParentTabIndex = function ( element ) {
        var parent = Polymer.dom(element).parentNode;
        while ( parent ) {
            if ( parent.tabIndex !== null && parent.tabIndex !== undefined ) {
                return parent.tabIndex;
            }

            parent = Polymer.dom(parent).parentNode;
        }
        return 0;
    };

    //
    EditorUI.focusParent = function ( element ) {
        // NOTE: DO NOT use Polymer.dom(element).parentNode
        var parent = element.parentElement;
        while ( parent ) {
            if ( parent.tabIndex !== null &&
                 parent.tabIndex !== undefined &&
                 parent.tabIndex !== -1 ) {
                parent.focus();
                return;
            }
            parent = parent.parentElement;
        }
    };

    //
    EditorUI.getSelfOrAncient = function ( element, parentType ) {
        var parent = element;
        while ( parent ) {
            if ( parent instanceof parentType )
                return parent;

            parent = Polymer.dom(parent).parentNode;
        }
        return 0;
    };

    EditorUI.isSelfOrAncient = function ( element, ancientEL ) {
        var parent = element;
        while ( parent ) {
            if ( parent === ancientEL )
                return true;

            parent = Polymer.dom(parent).parentNode;
        }
        return false;
    };

    //
    EditorUI.getFirstFocusableChild = function ( element ) {
        if ( element.tabIndex !== null &&
             element.tabIndex !== undefined &&
             element.tabIndex !== -1
           )
        {
            return element;
        }

        var el = null;
        var elementDOM = Polymer.dom(element);
        for ( var i = 0; i < elementDOM.children.length; ++i ) {
            el = EditorUI.getFirstFocusableChild(elementDOM.children[i]);
            if ( el !== null )
                return el;
        }

        var rootDOM = Polymer.dom(element.root);
        if ( rootDOM ) {
            el = EditorUI.getFirstFocusableChild(rootDOM);
            if ( el !== null )
                return el;
        }

        return null;
    };

    var _cancelDrag = null;
    EditorUI.startDrag = function ( cursor, event, onMove, onEnd ) {
        EditorUI.addDragGhost(cursor);

        event.stopPropagation();

        var pressx = event.clientX, lastx = event.clientX;
        var pressy = event.clientY, lasty = event.clientY;
        var dx = 0, offsetx = 0;
        var dy = 0, offsety = 0;

        var mousemoveHandle = function(event) {
            event.stopPropagation();

            dx = event.clientX - lastx;
            dy = event.clientY - lasty;
            offsetx = event.clientX - pressx;
            offsety = event.clientY - pressy;

            lastx = event.clientX;
            lasty = event.clientY;

            onMove( event, dx, dy, offsetx, offsety );
        };

        var mouseupHandle = function(event) {
            event.stopPropagation();

            document.removeEventListener('mousemove', mousemoveHandle);
            document.removeEventListener('mouseup', mouseupHandle);

            EditorUI.removeDragGhost();

            dx = event.clientX - lastx;
            dy = event.clientY - lasty;
            offsetx = event.clientX - pressx;
            offsety = event.clientY - pressy;

            _cancelDrag = null;
            onEnd( event, dx, dy, offsetx, offsety);
        }.bind(this);

        _cancelDrag = function () {
            document.removeEventListener('mousemove', mousemoveHandle);
            document.removeEventListener('mouseup', mouseupHandle);

            EditorUI.removeDragGhost();
        };

        document.addEventListener ( 'mousemove', mousemoveHandle );
        document.addEventListener ( 'mouseup', mouseupHandle );
    };

    EditorUI.cancelDrag = function () {
        if ( _cancelDrag )
            _cancelDrag();
    };

    //
    var _dragGhost = null;
    EditorUI.addDragGhost = function ( cursor ) {
        // add drag-ghost
        if ( _dragGhost === null ) {
            _dragGhost = document.createElement('div');
            _dragGhost.classList.add('drag-ghost');
            _dragGhost.style.position = 'absolute';
            _dragGhost.style.zIndex = '999';
            _dragGhost.style.top = '0';
            _dragGhost.style.right = '0';
            _dragGhost.style.bottom = '0';
            _dragGhost.style.left = '0';
            _dragGhost.oncontextmenu = function() { return false; };
        }
        _dragGhost.style.cursor = cursor;
        document.body.appendChild(_dragGhost);

        return _dragGhost;
    };

    EditorUI.removeDragGhost = function () {
        if ( _dragGhost !== null ) {
            _dragGhost.style.cursor = 'auto';
            if ( _dragGhost.parentElement !== null ) {
                _dragGhost.parentElement.removeChild(_dragGhost);
            }
        }
    };

    //
    var _hitGhost = null;
    EditorUI.addHitGhost = function ( cursor, zindex, onhit ) {
        // add drag-ghost
        if ( _hitGhost === null ) {
            _hitGhost = document.createElement('div');
            _hitGhost.classList.add('hit-ghost');
            _hitGhost.style.position = 'absolute';
            _hitGhost.style.zIndex = zindex;
            _hitGhost.style.top = '0';
            _hitGhost.style.right = '0';
            _hitGhost.style.bottom = '0';
            _hitGhost.style.left = '0';
            // _hitGhost.style.background = 'rgba(0,0,0,0.2)';
            _hitGhost.oncontextmenu = function() { return false; };
        }

        _hitGhost.style.cursor = cursor;
        _hitGhost.addEventListener('mousedown', function (event) {
            event.preventDefault();
            event.stopPropagation();
            if ( onhit )
                onhit();
        });
        document.body.appendChild(_hitGhost);

        return _hitGhost;
    };

    EditorUI.removeHitGhost = function () {
        if ( _hitGhost !== null ) {
            _hitGhost.style.cursor = 'auto';
            if ( _hitGhost.parentElement !== null ) {
                _hitGhost.parentElement.removeChild(_hitGhost);
                _hitGhost.removeEventListener('mousedown');
            }
        }
    };

    //
    var _loadingMask = null;
    EditorUI.addLoadingMask = function ( options, onclick ) {
        // add drag-ghost
        if ( _loadingMask === null ) {
            _loadingMask = document.createElement('div');
            _loadingMask.classList.add('loading-mask');
            _loadingMask.style.position = 'absolute';
            _loadingMask.style.top = '0';
            _loadingMask.style.right = '0';
            _loadingMask.style.bottom = '0';
            _loadingMask.style.left = '0';
            _loadingMask.oncontextmenu = function() { return false; };
        }

        if ( options && typeof options.zindex === 'string' ) {
            _loadingMask.style.zIndex = options.zindex;
        }
        else {
            _loadingMask.style.zIndex = '999';
        }

        if ( options && typeof options.background === 'string' ) {
            _loadingMask.style.backgroundColor = options.background;
        }
        else {
            _loadingMask.style.backgroundColor = 'rgba(0,0,0,0.2)';
        }

        if ( options && typeof options.cursor === 'string' ) {
            _loadingMask.style.cursor = options.cursor;
        }
        else {
            _loadingMask.style.cursor = 'default';
        }

        _loadingMask.addEventListener('mousedown', function (event) {
            event.preventDefault();
            event.stopPropagation();
            if ( onclick )
                onclick();
        });

        document.body.appendChild(_loadingMask);

        return _loadingMask;
    };

    EditorUI.removeLoadingMask = function () {
        if ( _loadingMask !== null ) {
            _loadingMask.style.cursor = 'auto';
            if ( _loadingMask.parentElement !== null ) {
                _loadingMask.parentElement.removeChild(_loadingMask);
                _loadingMask.removeEventListener('mousedown');
            }
        }
    };

    function _createLayouts ( parentEL, infos, importList ) {
        for ( var i = 0; i < infos.length; ++i ) {
            var info = infos[i];

            var el;

            if ( info.type === 'dock' ) {
                el = new EditorUI.Dock();
            }
            else if ( info.type === 'panel' ) {
                el = new EditorUI.Panel();
            }

            if ( !el ) continue;

            if ( info.row !== undefined ) {
                el.row = info.row;
            }
            if ( info.width !== undefined ) {
                el.curWidth = info.width;
            }
            if ( info.height !== undefined ) {
                el.curHeight = info.height;
            }

            if ( info.docks ) {
                _createLayouts ( el, info.docks, importList );
            }
            else if ( info.panels ) {
                for ( var j = 0; j < info.panels.length; ++j ) {
                    importList.push( { dockEL: el, panelID: info.panels[j], active: j === info.active } );
                }
            }

            Polymer.dom(parentEL).appendChild(el);
        }
        parentEL._initResizers();
    }

    EditorUI.createLayout = function ( parentEL, layoutInfo ) {
        var importList = [];

        // if we have root, clear all children in it
        var rootEL = EditorUI.DockUtils.root;
        if ( rootEL ) {
            rootEL.remove();
            EditorUI.DockUtils.root = null;
        }

        rootEL = new EditorUI.Dock();
        rootEL.classList.add('fit');
        rootEL.setAttribute('no-collapse', '');

        if ( layoutInfo ) {
            if ( layoutInfo.row ) rootEL.setAttribute('row', '');
            _createLayouts( rootEL, layoutInfo.docks, importList );
        }

        Polymer.dom(parentEL).appendChild(rootEL);
        EditorUI.DockUtils.root = rootEL;

        return importList;
    };

    // binding helpers
    EditorUI.bind = function ( el1, value1, el2, value2 ) {
        el1.addEventListener( value1+'-changed', function ( event ) {
            el2.set( value2, event.detail.value );
        });
        el2.addEventListener( value2+'-changed', function ( event ) {
            el1.set( value1, event.detail.value );
        });
    };

    EditorUI.toHumanText = function ( text ) {
        var result = text.replace(/([A-Z])/g, ' $1').replace(/[-_]/g, ' ');

        // remove first white-space
        if ( result.charAt(0) === ' ' ) {
            result.slice(1);
        }

        // capitalize the first letter
        return result.charAt(0).toUpperCase() + result.slice(1);
    };

    return EditorUI;
})();
<commit_msg>fix focus child can not find children<commit_after>var EditorUI = (function () {
    var EditorUI = {};

    EditorUI.index = function ( element ) {
        var parentEL = Polymer.dom(element).parentNode;
        var parentDOM = Polymer.dom(parentEL);
        var curChildEL = parentDOM.children.length > 0 ? parentDOM.children[0] : null;

        for ( var i = 0, len = parentDOM.children.length; i < len; ++i ) {
            if ( parentDOM.children[i] === element )
                return i;
        }

        return -1;
    };

    var _findInChildren = function ( element, elementToFind ) {
        var elementDOM = Polymer.dom(element);

        for ( var i = 0; i < elementDOM.children.length; ++i ) {
            var childEL = elementDOM.children[i];
            if ( childEL === elementToFind )
                return true;

            if ( Polymer.dom(childEL).children.length > 0 )
                if ( _findInChildren( childEL, elementToFind ) )
                    return true;
        }
        return false;
    };

    //
    EditorUI.find = function ( elements, elementToFind ) {
        if ( Array.isArray(elements) ||
             elements instanceof NodeList ||
             elements instanceof HTMLCollection )
        {
            for ( var i = 0; i < elements.length; ++i ) {
                var element = elements[i];
                if ( element === elementToFind )
                    return true;

                if ( _findInChildren ( element, elementToFind ) )
                    return true;
            }
            return false;
        }

        // if this is a single element
        if ( elements === elementToFind )
            return true;

        return _findInChildren( elements, elementToFind );
    };

    //
    EditorUI.getParentTabIndex = function ( element ) {
        var parent = Polymer.dom(element).parentNode;
        while ( parent ) {
            if ( parent.tabIndex !== null && parent.tabIndex !== undefined ) {
                return parent.tabIndex;
            }

            parent = Polymer.dom(parent).parentNode;
        }
        return 0;
    };

    //
    EditorUI.focusParent = function ( element ) {
        // NOTE: DO NOT use Polymer.dom(element).parentNode
        var parent = element.parentElement;
        while ( parent ) {
            if ( parent.tabIndex !== null &&
                 parent.tabIndex !== undefined &&
                 parent.tabIndex !== -1 ) {
                parent.focus();
                return;
            }
            parent = parent.parentElement;
        }
    };

    //
    EditorUI.getSelfOrAncient = function ( element, parentType ) {
        var parent = element;
        while ( parent ) {
            if ( parent instanceof parentType )
                return parent;

            parent = Polymer.dom(parent).parentNode;
        }
        return 0;
    };

    EditorUI.isSelfOrAncient = function ( element, ancientEL ) {
        var parent = element;
        while ( parent ) {
            if ( parent === ancientEL )
                return true;

            parent = Polymer.dom(parent).parentNode;
        }
        return false;
    };

    //
    EditorUI.getFirstFocusableChild = function ( element ) {
        if ( element.tabIndex !== null &&
             element.tabIndex !== undefined &&
             element.tabIndex !== -1
           )
        {
            return element;
        }

        var el = null;
        // var elementDOM = Polymer.dom(element);
        var elementDOM = element;
        for ( var i = 0; i < elementDOM.children.length; ++i ) {
            el = EditorUI.getFirstFocusableChild(elementDOM.children[i]);
            if ( el !== null )
                return el;
        }

        // var rootDOM = Polymer.dom(element.root);
        // if ( rootDOM ) {
        //     el = EditorUI.getFirstFocusableChild(rootDOM);
        //     if ( el !== null )
        //         return el;
        // }

        return null;
    };

    var _cancelDrag = null;
    EditorUI.startDrag = function ( cursor, event, onMove, onEnd ) {
        EditorUI.addDragGhost(cursor);

        event.stopPropagation();

        var pressx = event.clientX, lastx = event.clientX;
        var pressy = event.clientY, lasty = event.clientY;
        var dx = 0, offsetx = 0;
        var dy = 0, offsety = 0;

        var mousemoveHandle = function(event) {
            event.stopPropagation();

            dx = event.clientX - lastx;
            dy = event.clientY - lasty;
            offsetx = event.clientX - pressx;
            offsety = event.clientY - pressy;

            lastx = event.clientX;
            lasty = event.clientY;

            onMove( event, dx, dy, offsetx, offsety );
        };

        var mouseupHandle = function(event) {
            event.stopPropagation();

            document.removeEventListener('mousemove', mousemoveHandle);
            document.removeEventListener('mouseup', mouseupHandle);

            EditorUI.removeDragGhost();

            dx = event.clientX - lastx;
            dy = event.clientY - lasty;
            offsetx = event.clientX - pressx;
            offsety = event.clientY - pressy;

            _cancelDrag = null;
            onEnd( event, dx, dy, offsetx, offsety);
        }.bind(this);

        _cancelDrag = function () {
            document.removeEventListener('mousemove', mousemoveHandle);
            document.removeEventListener('mouseup', mouseupHandle);

            EditorUI.removeDragGhost();
        };

        document.addEventListener ( 'mousemove', mousemoveHandle );
        document.addEventListener ( 'mouseup', mouseupHandle );
    };

    EditorUI.cancelDrag = function () {
        if ( _cancelDrag )
            _cancelDrag();
    };

    //
    var _dragGhost = null;
    EditorUI.addDragGhost = function ( cursor ) {
        // add drag-ghost
        if ( _dragGhost === null ) {
            _dragGhost = document.createElement('div');
            _dragGhost.classList.add('drag-ghost');
            _dragGhost.style.position = 'absolute';
            _dragGhost.style.zIndex = '999';
            _dragGhost.style.top = '0';
            _dragGhost.style.right = '0';
            _dragGhost.style.bottom = '0';
            _dragGhost.style.left = '0';
            _dragGhost.oncontextmenu = function() { return false; };
        }
        _dragGhost.style.cursor = cursor;
        document.body.appendChild(_dragGhost);

        return _dragGhost;
    };

    EditorUI.removeDragGhost = function () {
        if ( _dragGhost !== null ) {
            _dragGhost.style.cursor = 'auto';
            if ( _dragGhost.parentElement !== null ) {
                _dragGhost.parentElement.removeChild(_dragGhost);
            }
        }
    };

    //
    var _hitGhost = null;
    EditorUI.addHitGhost = function ( cursor, zindex, onhit ) {
        // add drag-ghost
        if ( _hitGhost === null ) {
            _hitGhost = document.createElement('div');
            _hitGhost.classList.add('hit-ghost');
            _hitGhost.style.position = 'absolute';
            _hitGhost.style.zIndex = zindex;
            _hitGhost.style.top = '0';
            _hitGhost.style.right = '0';
            _hitGhost.style.bottom = '0';
            _hitGhost.style.left = '0';
            // _hitGhost.style.background = 'rgba(0,0,0,0.2)';
            _hitGhost.oncontextmenu = function() { return false; };
        }

        _hitGhost.style.cursor = cursor;
        _hitGhost.addEventListener('mousedown', function (event) {
            event.preventDefault();
            event.stopPropagation();
            if ( onhit )
                onhit();
        });
        document.body.appendChild(_hitGhost);

        return _hitGhost;
    };

    EditorUI.removeHitGhost = function () {
        if ( _hitGhost !== null ) {
            _hitGhost.style.cursor = 'auto';
            if ( _hitGhost.parentElement !== null ) {
                _hitGhost.parentElement.removeChild(_hitGhost);
                _hitGhost.removeEventListener('mousedown');
            }
        }
    };

    //
    var _loadingMask = null;
    EditorUI.addLoadingMask = function ( options, onclick ) {
        // add drag-ghost
        if ( _loadingMask === null ) {
            _loadingMask = document.createElement('div');
            _loadingMask.classList.add('loading-mask');
            _loadingMask.style.position = 'absolute';
            _loadingMask.style.top = '0';
            _loadingMask.style.right = '0';
            _loadingMask.style.bottom = '0';
            _loadingMask.style.left = '0';
            _loadingMask.oncontextmenu = function() { return false; };
        }

        if ( options && typeof options.zindex === 'string' ) {
            _loadingMask.style.zIndex = options.zindex;
        }
        else {
            _loadingMask.style.zIndex = '999';
        }

        if ( options && typeof options.background === 'string' ) {
            _loadingMask.style.backgroundColor = options.background;
        }
        else {
            _loadingMask.style.backgroundColor = 'rgba(0,0,0,0.2)';
        }

        if ( options && typeof options.cursor === 'string' ) {
            _loadingMask.style.cursor = options.cursor;
        }
        else {
            _loadingMask.style.cursor = 'default';
        }

        _loadingMask.addEventListener('mousedown', function (event) {
            event.preventDefault();
            event.stopPropagation();
            if ( onclick )
                onclick();
        });

        document.body.appendChild(_loadingMask);

        return _loadingMask;
    };

    EditorUI.removeLoadingMask = function () {
        if ( _loadingMask !== null ) {
            _loadingMask.style.cursor = 'auto';
            if ( _loadingMask.parentElement !== null ) {
                _loadingMask.parentElement.removeChild(_loadingMask);
                _loadingMask.removeEventListener('mousedown');
            }
        }
    };

    function _createLayouts ( parentEL, infos, importList ) {
        for ( var i = 0; i < infos.length; ++i ) {
            var info = infos[i];

            var el;

            if ( info.type === 'dock' ) {
                el = new EditorUI.Dock();
            }
            else if ( info.type === 'panel' ) {
                el = new EditorUI.Panel();
            }

            if ( !el ) continue;

            if ( info.row !== undefined ) {
                el.row = info.row;
            }
            if ( info.width !== undefined ) {
                el.curWidth = info.width;
            }
            if ( info.height !== undefined ) {
                el.curHeight = info.height;
            }

            if ( info.docks ) {
                _createLayouts ( el, info.docks, importList );
            }
            else if ( info.panels ) {
                for ( var j = 0; j < info.panels.length; ++j ) {
                    importList.push( { dockEL: el, panelID: info.panels[j], active: j === info.active } );
                }
            }

            Polymer.dom(parentEL).appendChild(el);
        }
        parentEL._initResizers();
    }

    EditorUI.createLayout = function ( parentEL, layoutInfo ) {
        var importList = [];

        // if we have root, clear all children in it
        var rootEL = EditorUI.DockUtils.root;
        if ( rootEL ) {
            rootEL.remove();
            EditorUI.DockUtils.root = null;
        }

        rootEL = new EditorUI.Dock();
        rootEL.classList.add('fit');
        rootEL.setAttribute('no-collapse', '');

        if ( layoutInfo ) {
            if ( layoutInfo.row ) rootEL.setAttribute('row', '');
            _createLayouts( rootEL, layoutInfo.docks, importList );
        }

        Polymer.dom(parentEL).appendChild(rootEL);
        EditorUI.DockUtils.root = rootEL;

        return importList;
    };

    // binding helpers
    EditorUI.bind = function ( el1, value1, el2, value2 ) {
        el1.addEventListener( value1+'-changed', function ( event ) {
            el2.set( value2, event.detail.value );
        });
        el2.addEventListener( value2+'-changed', function ( event ) {
            el1.set( value1, event.detail.value );
        });
    };

    EditorUI.toHumanText = function ( text ) {
        var result = text.replace(/([A-Z])/g, ' $1').replace(/[-_]/g, ' ');

        // remove first white-space
        if ( result.charAt(0) === ' ' ) {
            result.slice(1);
        }

        // capitalize the first letter
        return result.charAt(0).toUpperCase() + result.slice(1);
    };

    return EditorUI;
})();
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import Head from 'next/head';
import Normalize from '../components/css/Normalize';
import BodyStyles from '../components/css/BodyStyles';

const Document = ({ children }) => (

      <title>Logan McAnsh</title>
      <meta charSet="utf-8" />
      <meta name="viewport" content="initial-scale=1.0, width=device-width" />
      <link rel="mask-icon" href="/static/images/website_icon.svg" color="#FC6C2B" />
      <link rel="shortcut icon" href="/static/images/favicon.png" />
      <Normalize />
      <BodyStyles />

    {children}

);

Document.propTypes = {
  children: PropTypes.node.isRequired
};

export default Document;
<commit_msg>apply it in layout.js<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import Head from 'next/head';
import Normalize from '../components/css/Normalize';
import BodyStyles from '../components/css/BodyStyles';

const Document = ({ children }) => (

      <title>Logan McAnsh</title>
      <meta charSet="utf-8" />
      <meta name="viewport" content="initial-scale=1.0, width=device-width" />
      <link rel="mask-icon" href="/static/images/website_icon.svg" color="#FC6C2B" />
      <link rel="shortcut icon" href="/static/images/favicon.png" />
      <Normalize />
      <BodyStyles />

    {children}