<commit_before>/*
 * GazeJS - An implementation of the JavaScript bindings for Tobii Gaze SDK.
 * https://github.com/jiahansu/GazeJS
 *
 * Copyright (c) 2013-2013, Jia-Han Su (https://github.com/jiahansu)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Olivier Chafik nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY JIA-HAN SU AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

var my = require("myclass"), bridjs = require("bridjs"),
        log4js = require("log4js"), log = log4js.getLogger("TobiiGazeImpl"),
        TobiiGaze = require("./gaze"),
        ErrorCodes = require("./error_codes"),
        DataTypes = require("./data_types"),
        GazeException = require("../gaze_exception"),
        CallbackTypes = require("./callback_types"),
        gaze = new TobiiGaze(), Status = require("../status"),
        NANO_TO_SECONDS = (1.0 / (1000 * 1000 * 1000));

module.exports = my.Class(Status,{
    constructor: function() {
        var self = this;

        this.eyeTracker = null;
        //this.screenBounds = null;//new DataTypes.Rect();
        this.status = module.exports.IDLE;
        this.releaseAfterStopped = false;
        this.listener = null;
        this.gazeStartSeconds = 0;
        this.onStopTrackingCallback = bridjs.newCallback(CallbackTypes.AsyncCallback, function(errorCode, userData) {
            self.checkError(errorCode);
            self.onStopTracking();
        });
        this.onDisconnectCallback = bridjs.newCallback(CallbackTypes.AsyncBasicCallback, function(userData) {
            self.onDisconnect();
        });
        this.onErrorCallback = bridjs.newCallback(CallbackTypes.AsyncCallback, function(errorCode, userData) {
            var message = gaze.getErrorMessage(errorCode);

            log.error("OnError: " + gaze.getErrorMessage(errorCode));
            self.onError(message);
        });
        this.onConnectCallback = bridjs.newCallback(CallbackTypes.AsyncCallback, function(errorCode, userData) {
            self.checkError(errorCode);

            self.onConnect();
        });
        this.onDeviceInfoCallback = bridjs.newCallback(CallbackTypes.AsyncDeviceInfoCallback, function(deviceInfo, errorCode, userData) {
            self.checkError(errorCode);

            log.debug("OnDeviceInof, serial number = " + bridjs.toString(deviceInfo.serialNumber));
        });

        this.onStartTrackingCallback = bridjs.newCallback(CallbackTypes.AsyncCallback, function(errorCode, userData) {
            self.checkError(errorCode);
            self.onStart();
        });

        this.onGazeDataCallback = bridjs.newCallback(CallbackTypes.Listener, function(gazeData, extensions, userData) {
            var left = gazeData.left.gazePointOnDisplayNormalized,
                    right = gazeData.right.gazePointOnDisplayNormalized,
                    status = gazeData.trackingStatus, leftEye, rightEye,
                    center = {x:0, y:0}, count = 0;;

            if ((status === DataTypes.Status.TRACKING_STATUS_BOTH_EYES_TRACKED ||
                    status === DataTypes.Status.TRACKING_STATUS_ONLY_LEFT_EYE_TRACKED ||
                    status === DataTypes.Status.TRACKING_STATUS_ONE_EYE_TRACKED_PROBABLY_LEFT) &&
                    left.x!==undefined && left.y!==undefined) {
                leftEye = {x: left.x /* self.screenBounds.right*/, y: left.y /** self.screenBounds.bottom*/};
                center.x+=leftEye.x;
                center.y+=leftEye.y;
                ++count;
            }

            if ((status === DataTypes.Status.TRACKING_STATUS_BOTH_EYES_TRACKED ||
                    status === DataTypes.Status.TRACKING_STATUS_ONLY_RIGHT_EYE_TRACKED ||
                    status === DataTypes.Status.TRACKING_STATUS_ONE_EYE_TRACKED_PROBABLY_RIGHT)
                    && right.x!==undefined && right.y!==undefined) {
                rightEye = {x: right.x /* self.screenBounds.right*/, y: right.y /* self.screenBounds.bottom*/};
                center.x += rightEye.x;
                center.y+=rightEye.y;
                ++count;
            }
            if(count>=1){
                center.x /= count;
                center.y /=count;
            }else{
                center = undefined;
            }
            self.onGazeData({left:leftEye, right:rightEye, prefered:center,
                timeSeconds: self.getTrackingTimeSeconds()});
        });
    },
    getTrackingTimeSeconds:function(){
        return this.timeSeconds()-this.gazeStartSeconds;
    },
    timeSeconds:function(){
      var time = process.hrtime();

      return time[0] + (time[1] * NANO_TO_SECONDS);
    },
    setListener:function(listener){
      this.listener = listener;
    },
    warn:function(e){
      log.warn(e);

      if(e.stack){
          log.warn(e.stack);
      }
    },
    onError: function(message) {
        var self = this;

        if (this.listener && typeof (this.listener.onError) === "function") {
            try {
                this.listener.onError(new GazeException(message));
            } catch (e) {
                this.warn(e);
            }
        }
        this.status = module.exports.ERROR;
        setTimeout(function() {
            self.stop();
        }, 0);
    },
    onGazeData:function(gazeData){
        if(this.listener && typeof(this.listener.onGazeData)==="function"){
            try{
                this.listener.onGazeData(gazeData);
            }catch(e){
                this.warn(e);
            }
        }
    },
    onStart:function(){
         this.status = module.exports.STARTED;
         this.gazeStartSeconds = this.timeSeconds();
         log.debug("OnStart");

         if(this.listener && typeof(this.listener.onStart)==="function"){
            try{
                this.listener.onStart();
            }catch(e){
                this.warn(e);
            }
        }
    },
    onConnect: function() {
        log.info("OnConnect");

        gaze.getDeviceInfoAsync(this.eyeTracker, this.onDeviceInfoCallback, null);
        gaze.startTrackingAsync(this.eyeTracker, this.onStartTrackingCallback, this.onGazeDataCallback, null);
    },
    onDisconnect: function() {
        log.debug("onDisconnection");
        gaze.breakEventLoop(bridjs.byPointer(this.eyeTracker));
        this.status = module.exports.STOPPED;

        if(this.listener && typeof(this.listener.onStop)==="function"){
            try{
                this.listener.onStop();
            }catch(e){
                this.warn(e);
            }
        }

        if (this.releaseAfterStopped) {
            this.releaseAfterStopped = false;
            this.release();
        }
    },
    checkError: function(errorCode) {
        var value;

        if (typeof (errorCode) === "number") {
            value = errorCode;
        } else {
            value = errorCode.get();
        }

        if (value !== ErrorCodes.SUCCESS) {
            var message = tobiiGaze.getErrorMessage(value);

            this.onError(message);

            throw new GazeException("Gaze error :" + message);
        }
    },
    init: function() {
        if (this.status === module.exports.IDLE) {
            var errorCode = new bridjs.NativeValue.uint32(),
                    modelUrl = new Buffer(DataTypes.Constants.DEVICE_INFO_MAX_MODEL_LENGTH),
                    screenBounds = new DataTypes.Rect();

            //config.init(bridjs.byPointer(errorCode));
            //this.checkError(errorCode);

            gaze.getConnectedEyeTracker(modelUrl, DataTypes.Constants.DEVICE_INFO_MAX_MODEL_LENGTH,
                bridjs.byPointer(errorCode));
            this.checkError(errorCode);

            log.debug("Tobii EyeTracker Model name: " + bridjs.toString(modelUrl));
            log.debug("Tobii Gaze SDK version: " + gaze.getVersion());

            //config.getScreenBoundsPixels(modelUrl, bridjs.byPointer(screenBounds),
                    //bridjs.byPointer(errorCode));
            //this.checkError(errorCode);

            //this.screenBounds = {left: screenBounds.left, right: screenBounds.right,
             //   top:screenBounds.top, bottom: screenBounds.bottom};

            this.eyeTracker = gaze.create(modelUrl, bridjs.byPointer(errorCode));
            this.checkError(errorCode);

            gaze.setLogging("tobii_gaze_impl_log.txt", DataTypes.LogLevel.OFF, bridjs.byPointer(errorCode));
            this.checkError(errorCode);

            this.status = module.exports.INITED;
        } else {
            throw new GazeException("Illegal status to init tracker: " + this.status);
        }
    },
    start: function() {
        if (this.status === module.exports.INITED || this.status === module.exports.STOPPED) {
            var eventLoopErrorCode = new bridjs.NativeValue.uint32(),
                    self = this;
            this.status = module.exports.STARTING;
            log.debug("runEventLoop++");
            bridjs.async(gaze).runEventLoop(bridjs.byPointer(this.eyeTracker),
                    bridjs.byPointer(eventLoopErrorCode), function() {
                self.checkError(eventLoopErrorCode);
                log.debug("gaze.runEventLoop() returned");
            });
            log.debug("runEventLoop--");
            /*Delay execution to workaround strange crash issue*/
            setTimeout(function() {
                gaze.registerError(bridjs.byPointer(self.eyeTracker), self.onErrorCallback, null);
                gaze.connectAsync(bridjs.byPointer(self.eyeTracker), self.onConnectCallback, null);
            }, 16);

        } else {
            throw new GazeException("Illegal status to start tracker: " + this.status);
        }
    },
    onStopTracking: function() {
        gaze.disconnectAsync(this.eyeTracker, this.onDisconnectCallback, null);
        log.debug("OnStop");
    },
    stop: function() {
        if (this.status === module.exports.STARTED) {
            this.status = module.exports.STOPPING;
            gaze.stopTrackingAsync(this.eyeTracker, this.onStopTrackingCallback, null);
        }else{
            throw new GazeException("Illegal status to stop tracker: " + this.status);
        }
    },
    release: function() {
        if (this.status === module.exports.STOPPED ||
                this.status === module.exports.STARTED ||
                this.status === module.exports.INITED ||
                this.status === module.exports.ERROR) {
            if (this.status === module.exports.STARTED) {
                this.releaseAfterStopped = true;
                this.stop();
            } else {
                log.info("Release eyeTracker: " + this.eyeTracker);
                this.releaseAfterStopped = false;
                if (this.eyeTracker) {
                    gaze.destroy(bridjs.byPointer(this.eyeTracker));
                    this.eyeTracker = null;
                }
                //config.free();
                this.status = module.exports.IDLE;

                log.debug("Release EyeTracker done");
            }
        } else {
            throw new GazeException("Illegal status to release tracker: " + this.status);
        }
    },

    getLibraryVersion:function(){
        gaze.getVersion();
    },

    getModelName:function(){
        if (this.status !== module.exports.IDLE) {
            var modelUrl = new Buffer(DataTypes.Constants.DEVICE_INFO_MAX_MODEL_LENGTH);
            var errorCode = new bridjs.NativeValue.uint32();

            gaze.getConnectedEyeTracker(modelUrl, DataTypes.Constants.DEVICE_INFO_MAX_MODEL_LENGTH,
                bridjs.byPointer(errorCode));
            this.checkError(errorCode);

            return bridjs.toString(modelUrl);
        }else{
            throw new GazeException("Please init tracker before getModelName(), status = "+this.status);
        }
    },

    getStatus:function(){
        return this.status;
    }
});<commit_msg>Allow invocation of stop() after error<commit_after>/*
 * GazeJS - An implementation of the JavaScript bindings for Tobii Gaze SDK.
 * https://github.com/jiahansu/GazeJS
 *
 * Copyright (c) 2013-2013, Jia-Han Su (https://github.com/jiahansu)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Olivier Chafik nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY JIA-HAN SU AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

var my = require("myclass"), bridjs = require("bridjs"),
    log4js = require("log4js"), log = log4js.getLogger("TobiiGazeImpl"),
    TobiiGaze = require("./gaze"),
    ErrorCodes = require("./error_codes"),
    DataTypes = require("./data_types"),
    GazeException = require("../gaze_exception"),
    CallbackTypes = require("./callback_types"),
    gaze = new TobiiGaze(), Status = require("../status"),
    NANO_TO_SECONDS = (1.0 / (1000 * 1000 * 1000));

module.exports = my.Class(Status, {
    constructor: function () {
        var self = this;

        this.eyeTracker = null;
        //this.screenBounds = null;//new DataTypes.Rect();
        this.status = module.exports.IDLE;
        this.releaseAfterStopped = false;
        this.listener = null;
        this.gazeStartSeconds = 0;
        this.onStopTrackingCallback = bridjs.newCallback(CallbackTypes.AsyncCallback, function (errorCode, userData) {
            self.checkError(errorCode);
            self.onStopTracking();
        });
        this.onDisconnectCallback = bridjs.newCallback(CallbackTypes.AsyncBasicCallback, function (userData) {
            self.onDisconnect();
        });
        this.onErrorCallback = bridjs.newCallback(CallbackTypes.AsyncCallback, function (errorCode, userData) {
            var message = gaze.getErrorMessage(errorCode);

            log.error("OnError: " + gaze.getErrorMessage(errorCode));
            self.onError(message);
        });
        this.onConnectCallback = bridjs.newCallback(CallbackTypes.AsyncCallback, function (errorCode, userData) {
            self.checkError(errorCode);

            self.onConnect();
        });
        this.onDeviceInfoCallback = bridjs.newCallback(CallbackTypes.AsyncDeviceInfoCallback, function (deviceInfo, errorCode, userData) {
            self.checkError(errorCode);

            log.debug("OnDeviceInof, serial number = " + bridjs.toString(deviceInfo.serialNumber));
        });

        this.onStartTrackingCallback = bridjs.newCallback(CallbackTypes.AsyncCallback, function (errorCode, userData) {
            self.checkError(errorCode);
            self.onStart();
        });

        this.onGazeDataCallback = bridjs.newCallback(CallbackTypes.Listener, function (gazeData, extensions, userData) {
            var left = gazeData.left.gazePointOnDisplayNormalized,
                right = gazeData.right.gazePointOnDisplayNormalized,
                status = gazeData.trackingStatus, leftEye, rightEye,
                center = {x: 0, y: 0}, count = 0;
            ;

            if ((status === DataTypes.Status.TRACKING_STATUS_BOTH_EYES_TRACKED ||
                status === DataTypes.Status.TRACKING_STATUS_ONLY_LEFT_EYE_TRACKED ||
                status === DataTypes.Status.TRACKING_STATUS_ONE_EYE_TRACKED_PROBABLY_LEFT) &&
                left.x !== undefined && left.y !== undefined) {
                leftEye = {x: left.x /* self.screenBounds.right*/, y: left.y /** self.screenBounds.bottom*/};
                center.x += leftEye.x;
                center.y += leftEye.y;
                ++count;
            }

            if ((status === DataTypes.Status.TRACKING_STATUS_BOTH_EYES_TRACKED ||
                status === DataTypes.Status.TRACKING_STATUS_ONLY_RIGHT_EYE_TRACKED ||
                status === DataTypes.Status.TRACKING_STATUS_ONE_EYE_TRACKED_PROBABLY_RIGHT)
                && right.x !== undefined && right.y !== undefined) {
                rightEye = {x: right.x /* self.screenBounds.right*/, y: right.y /* self.screenBounds.bottom*/};
                center.x += rightEye.x;
                center.y += rightEye.y;
                ++count;
            }
            if (count >= 1) {
                center.x /= count;
                center.y /= count;
            } else {
                center = undefined;
            }
            self.onGazeData({
                left: leftEye, right: rightEye, prefered: center,
                timeSeconds: self.getTrackingTimeSeconds()
            });
        });
    },
    getTrackingTimeSeconds: function () {
        return this.timeSeconds() - this.gazeStartSeconds;
    },
    timeSeconds: function () {
        var time = process.hrtime();

        return time[0] + (time[1] * NANO_TO_SECONDS);
    },
    setListener: function (listener) {
        this.listener = listener;
    },
    warn: function (e) {
        log.warn(e);

        if (e.stack) {
            log.warn(e.stack);
        }
    },
    onError: function (message) {
        var self = this;

        if (this.listener && typeof (this.listener.onError) === "function") {
            try {
                this.listener.onError(new GazeException(message));
            } catch (e) {
                this.warn(e);
            }
        }
        this.status = module.exports.ERROR;
        setTimeout(function () {
            self.stop();
        }, 0);
    },
    onGazeData: function (gazeData) {
        if (this.listener && typeof(this.listener.onGazeData) === "function") {
            try {
                this.listener.onGazeData(gazeData);
            } catch (e) {
                this.warn(e);
            }
        }
    },
    onStart: function () {
        this.status = module.exports.STARTED;
        this.gazeStartSeconds = this.timeSeconds();
        log.debug("OnStart");

        if (this.listener && typeof(this.listener.onStart) === "function") {
            try {
                this.listener.onStart();
            } catch (e) {
                this.warn(e);
            }
        }
    },
    onConnect: function () {
        log.info("OnConnect");

        gaze.getDeviceInfoAsync(this.eyeTracker, this.onDeviceInfoCallback, null);
        gaze.startTrackingAsync(this.eyeTracker, this.onStartTrackingCallback, this.onGazeDataCallback, null);
    },
    onDisconnect: function () {
        log.debug("onDisconnection");
        gaze.breakEventLoop(bridjs.byPointer(this.eyeTracker));
        this.status = module.exports.STOPPED;

        if (this.listener && typeof(this.listener.onStop) === "function") {
            try {
                this.listener.onStop();
            } catch (e) {
                this.warn(e);
            }
        }

        if (this.releaseAfterStopped) {
            this.releaseAfterStopped = false;
            this.release();
        }
    },
    checkError: function (errorCode) {
        var value;

        if (typeof (errorCode) === "number") {
            value = errorCode;
        } else {
            value = errorCode.get();
        }

        if (value !== ErrorCodes.SUCCESS) {
            var message = tobiiGaze.getErrorMessage(value);

            this.onError(message);

            throw new GazeException("Gaze error :" + message);
        }
    },
    init: function () {
        if (this.status === module.exports.IDLE) {
            var errorCode = new bridjs.NativeValue.uint32(),
                modelUrl = new Buffer(DataTypes.Constants.DEVICE_INFO_MAX_MODEL_LENGTH),
                screenBounds = new DataTypes.Rect();

            //config.init(bridjs.byPointer(errorCode));
            //this.checkError(errorCode);

            gaze.getConnectedEyeTracker(modelUrl, DataTypes.Constants.DEVICE_INFO_MAX_MODEL_LENGTH,
                bridjs.byPointer(errorCode));
            this.checkError(errorCode);

            log.debug("Tobii EyeTracker Model name: " + bridjs.toString(modelUrl));
            log.debug("Tobii Gaze SDK version: " + gaze.getVersion());

            //config.getScreenBoundsPixels(modelUrl, bridjs.byPointer(screenBounds),
            //bridjs.byPointer(errorCode));
            //this.checkError(errorCode);

            //this.screenBounds = {left: screenBounds.left, right: screenBounds.right,
            //   top:screenBounds.top, bottom: screenBounds.bottom};

            this.eyeTracker = gaze.create(modelUrl, bridjs.byPointer(errorCode));
            this.checkError(errorCode);

            gaze.setLogging("tobii_gaze_impl_log.txt", DataTypes.LogLevel.OFF, bridjs.byPointer(errorCode));
            this.checkError(errorCode);

            this.status = module.exports.INITED;
        } else {
            throw new GazeException("Illegal status to init tracker: " + this.status);
        }
    },
    start: function () {
        if (this.status === module.exports.INITED || this.status === module.exports.STOPPED) {
            var eventLoopErrorCode = new bridjs.NativeValue.uint32(),
                self = this;
            this.status = module.exports.STARTING;
            log.debug("runEventLoop++");
            bridjs.async(gaze).runEventLoop(bridjs.byPointer(this.eyeTracker),
                bridjs.byPointer(eventLoopErrorCode), function () {
                    self.checkError(eventLoopErrorCode);
                    log.debug("gaze.runEventLoop() returned");
                });
            log.debug("runEventLoop--");
            /*Delay execution to workaround strange crash issue*/
            setTimeout(function () {
                gaze.registerError(bridjs.byPointer(self.eyeTracker), self.onErrorCallback, null);
                gaze.connectAsync(bridjs.byPointer(self.eyeTracker), self.onConnectCallback, null);
            }, 16);

        } else {
            throw new GazeException("Illegal status to start tracker: " + this.status);
        }
    },
    onStopTracking: function () {
        gaze.disconnectAsync(this.eyeTracker, this.onDisconnectCallback, null);
        log.debug("OnStop");
    },
    stop: function () {
        if (this.status === module.exports.STARTED || this.status === module.exports.ERROR) {
            this.status = module.exports.STOPPING;
            gaze.stopTrackingAsync(this.eyeTracker, this.onStopTrackingCallback, null);
        } else {
            throw new GazeException("Illegal status to stop tracker: " + this.status);
        }
    },
    release: function () {
        if (this.status === module.exports.STOPPED ||
            this.status === module.exports.STARTED ||
            this.status === module.exports.INITED ||
            this.status === module.exports.ERROR) {
            if (this.status === module.exports.STARTED) {
                this.releaseAfterStopped = true;
                this.stop();
            } else {
                log.info("Release eyeTracker: " + this.eyeTracker);
                this.releaseAfterStopped = false;
                if (this.eyeTracker) {
                    gaze.destroy(bridjs.byPointer(this.eyeTracker));
                    this.eyeTracker = null;
                }
                //config.free();
                this.status = module.exports.IDLE;

                log.debug("Release EyeTracker done");
            }
        } else {
            throw new GazeException("Illegal status to release tracker: " + this.status);
        }
    },

    getLibraryVersion: function () {
        gaze.getVersion();
    },

    getModelName: function () {
        if (this.status !== module.exports.IDLE) {
            var modelUrl = new Buffer(DataTypes.Constants.DEVICE_INFO_MAX_MODEL_LENGTH);
            var errorCode = new bridjs.NativeValue.uint32();

            gaze.getConnectedEyeTracker(modelUrl, DataTypes.Constants.DEVICE_INFO_MAX_MODEL_LENGTH,
                bridjs.byPointer(errorCode));
            this.checkError(errorCode);

            return bridjs.toString(modelUrl);
        } else {
            throw new GazeException("Please init tracker before getModelName(), status = " + this.status);
        }
    },

    getStatus: function () {
        return this.status;
    }
});<|endoftext|>


<commit_before>// @flow

import Spinner from '@atlaskit/spinner';

import React, { Component } from 'react';
import type { Dispatch } from 'redux';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import URL from 'url';

import {
    RemoteControl,
    setupScreenSharingForWindow,
    setupAlwaysOnTopRender,
    initPopupsConfigurationRender,
    setupWiFiStats
} from 'jitsi-meet-electron-utils';

import config from '../../config';
import { setEmail, setName } from '../../settings';

import { LoadingIndicator, Wrapper } from '../styled';
import { getExternalApiURL } from '../../utils';

type Props = {

    /**
     * Redux dispatch.
     */
    dispatch: Dispatch<*>;

    /**
     * React Router location object.
     */
    location: Object;

    /**
     * Avatar URL.
     */
    _avatarURL: string;

    /**
     * Email of user.
     */
    _email: string;

    /**
     * Name of user.
     */
    _name: string;

    /**
     * Default Jitsi Server URL.
     */
    _serverURL: string;

    /**
     * Start with Audio Muted.
     */
    _startWithAudioMuted: boolean;

    /**
     * Start with Video Muted.
     */
    _startWithVideoMuted: boolean;
};

type State = {

    /**
     * If the conference is loading or not.
     */
    isLoading: boolean;
};

/**
 * Conference component.
 */
class Conference extends Component<Props, State> {
    /**
     * Reference to the element of this component.
     */
    _ref: Object;

    /**
     * External API object.
     */
    _api: Object;

    /**
     * Initializes a new {@code Conference} instance.
     *
     * @inheritdoc
     */
    constructor() {
        super();

        // External API will load an instance of babel-polyfill. Hence we
        // should remove existing babel-polyfill instance.
        delete global._babelPolyfill;

        this.state = {
            isLoading: true
        };

        this._ref = React.createRef();

        this._onIframeLoad = this._onIframeLoad.bind(this);
    }

    /**
     * Attach the script to this component.
     *
     * @returns {void}
     */
    componentDidMount() {
        const parentNode = this._ref.current;
        const room = this.props.location.state.room;
        const serverURL = this.props.location.state.serverURL
            || this.props._serverURL
            || config.defaultServerURL;

        const script = document.createElement('script');

        script.async = true;
        script.onload = () => this._onScriptLoad(parentNode, room, serverURL);
        script.onerror = (event: Event) =>
            this._navigateToHome(event, room, serverURL);
        script.src = getExternalApiURL(serverURL);

        this._ref.current.appendChild(script);
    }

    /**
     * Keep profile settings in sync with Conference.
     *
     * @param {Props} prevProps - Component's prop values before update.
     * @returns {void}
     */
    componentDidUpdate(prevProps) {
        const { props } = this;

        if (props._avatarURL !== prevProps._avatarURL) {
            this._setAvatarURL(props._avatarURL);
        }
        if (props._email !== prevProps._email) {
            this._setEmail(props._email);
        }
        if (props._name !== prevProps._name) {
            this._setName(props._name);
        }
    }

    /**
     * Remove conference on unmounting.
     *
     * @returns {void}
     */
    componentWillUnmount() {
        if (this._api) {
            this._api.dispose();
        }
    }

    /**
     * Implements React's {@link Component#render()}.
     *
     * @returns {ReactElement}
     */
    render() {
        return (
            <Wrapper innerRef = { this._ref }>
                { this._maybeRenderLoadingIndicator() }
            </Wrapper>
        );
    }

    /**
     * It renders a loading indicator, if appropriate.
     *
     * @returns {?ReactElement}
     */
    _maybeRenderLoadingIndicator() {
        if (this.state.isLoading) {
            return (
                <LoadingIndicator>
                    <Spinner size = 'large' />
                </LoadingIndicator>
            );
        }
    }

    /**
     * Navigates to home screen (Welcome).
     *
     * @param {Event} event - Event by which the function is called.
     * @param {string} room - Room name.
     * @param {string} serverURL - Server URL.
     * @returns {void}
     */
    _navigateToHome(event: Event, room: ?string, serverURL: ?string) {
        this.props.dispatch(push('/', {
            error: event.type === 'error',
            room,
            serverURL
        }));
    }

    /**
     * When the script is loaded create the iframe element in this component
     * and attach utils from jitsi-meet-electron-utils.
     *
     * @param {Object} parentNode - Node to which iframe has to be attached.
     * @param {string} roomName - Conference room name to be joined.
     * @param {string} serverURL - Jitsi Meet server url.
     * @returns {void}
     */
    _onScriptLoad(parentNode: Object, roomName: string, serverURL: string) {
        const JitsiMeetExternalAPI = window.JitsiMeetExternalAPI;

        const { host } = URL.parse(serverURL);

        const configOverwrite = {
            startWithAudioMuted: this.props._startWithAudioMuted,
            startWithVideoMuted: this.props._startWithVideoMuted
        };

        this._api = new JitsiMeetExternalAPI(host, {
            configOverwrite,
            onload: this._onIframeLoad,
            parentNode,
            roomName
        });
        initPopupsConfigurationRender(this._api);

        const iframe = this._api.getIFrame();

        setupScreenSharingForWindow(iframe);
        new RemoteControl(iframe); // eslint-disable-line no-new
        setupAlwaysOnTopRender(this._api);
        setupWiFiStats(iframe);

        this._api.on('readyToClose', (event: Event) =>
            this._navigateToHome(event));
        this._api.on('videoConferenceJoined',
            (conferenceInfo: Object) =>
                this._onVideoConferenceJoined(conferenceInfo));
    }

    /**
     * Updates redux state's user name from conference.
     *
     * @param {Object} params - Returned object from event.
     * @param {string} id - Local Participant ID.
     * @returns {void}
     */
    _onDisplayNameChange(params: Object, id: string) {
        if (params.id === id) {
            this.props.dispatch(setName(params.displayname));
        }
    }

    /**
     * Updates redux state's email from conference.
     *
     * @param {Object} params - Returned object from event.
     * @param {string} id - Local Participant ID.
     * @returns {void}
     */
    _onEmailChange(params: Object, id: string) {
        if (params.id === id) {
            this.props.dispatch(setEmail(params.email));
        }
    }

    _onIframeLoad: (*) => void;

    /**
     * Sets state of loading to false when iframe has completely loaded.
     *
     * @returns {void}
     */
    _onIframeLoad() {
        this.setState({
            isLoading: false
        });
    }

    /**
     * Saves conference info on joining it.
     *
     * @param {Object} conferenceInfo - Contains information about the current
     * conference.
     * @returns {void}
     */
    _onVideoConferenceJoined(conferenceInfo: Object) {
        setupDragAreas(this._api.getIFrame());

        this._setAvatarURL(this.props._avatarURL);
        this._setEmail(this.props._email);
        this._setName(this.props._name);

        const { id } = conferenceInfo;

        this._api.on('displayNameChange',
            (params: Object) => this._onDisplayNameChange(params, id));
        this._api.on('emailChange',
            (params: Object) => this._onEmailChange(params, id));
    }

    /**
     * Set Avatar URL from settings to conference.
     *
     * @param {string} avatarURL - Avatar URL.
     * @returns {void}
     */
    _setAvatarURL(avatarURL: string) {
        this._api.executeCommand('avatarUrl', avatarURL);
    }

    /**
     * Set email from settings to conference.
     *
     * @param {string} email - Email of user.
     * @returns {void}
     */
    _setEmail(email: string) {
        this._api.executeCommand('email', email);
    }

    /**
     * Set name from settings to conference.
     *
     * @param {string} name - Name of user.
     * @returns {void}
     */
    _setName(name: string) {
        this._api.executeCommand('displayName', name);
    }

}

/**
 * Inject some style into the iframe so everything except the filmstrip, chat,
 * buttons or any input is draggable.
 *
 * @param {Object} iframe - Reference to the iframe where the drag areas will
 * be set.
 * @returns {void}
 */
function setupDragAreas(iframe) {
    const injectStyle = document.createElement('style');

    injectStyle.type = 'text/css';
    injectStyle.textContent
        = 'body { -webkit-app-region: drag; }'
        + 'button, input { -webkit-app-region: no-drag }'
        + '#chatconversation, .filmstrip { -webkit-app-region: no-drag; }';
    iframe.contentDocument.head.appendChild(injectStyle);
}

/**
 * Maps (parts of) the redux state to the React props.
 *
 * @param {Object} state - The redux state.
 * @returns {{
 *     _avatarURL: string,
 *     _email: string,
 *     _name: string,
 *     _serverURL: string,
 *     _startWithAudioMuted: boolean,
 *     _startWithVideoMuted: boolean
 * }}
 */
function _mapStateToProps(state: Object) {
    return {
        _avatarURL: state.settings.avatarURL,
        _email: state.settings.email,
        _name: state.settings.name,
        _serverURL: state.settings.serverURL,
        _startWithAudioMuted: state.settings.startWithAudioMuted,
        _startWithVideoMuted: state.settings.startWithVideoMuted
    };
}

export default connect(_mapStateToProps)(Conference);
<commit_msg>Fix: Made host parsing compatible for servers deployed in subdirectory<commit_after>// @flow

import Spinner from '@atlaskit/spinner';

import React, { Component } from 'react';
import type { Dispatch } from 'redux';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';

import {
    RemoteControl,
    setupScreenSharingForWindow,
    setupAlwaysOnTopRender,
    initPopupsConfigurationRender,
    setupWiFiStats
} from 'jitsi-meet-electron-utils';

import config from '../../config';
import { setEmail, setName } from '../../settings';

import { LoadingIndicator, Wrapper } from '../styled';
import { getExternalApiURL } from '../../utils';

type Props = {

    /**
     * Redux dispatch.
     */
    dispatch: Dispatch<*>;

    /**
     * React Router location object.
     */
    location: Object;

    /**
     * Avatar URL.
     */
    _avatarURL: string;

    /**
     * Email of user.
     */
    _email: string;

    /**
     * Name of user.
     */
    _name: string;

    /**
     * Default Jitsi Server URL.
     */
    _serverURL: string;

    /**
     * Start with Audio Muted.
     */
    _startWithAudioMuted: boolean;

    /**
     * Start with Video Muted.
     */
    _startWithVideoMuted: boolean;
};

type State = {

    /**
     * If the conference is loading or not.
     */
    isLoading: boolean;
};

/**
 * Conference component.
 */
class Conference extends Component<Props, State> {
    /**
     * Reference to the element of this component.
     */
    _ref: Object;

    /**
     * External API object.
     */
    _api: Object;

    /**
     * Initializes a new {@code Conference} instance.
     *
     * @inheritdoc
     */
    constructor() {
        super();

        // External API will load an instance of babel-polyfill. Hence we
        // should remove existing babel-polyfill instance.
        delete global._babelPolyfill;

        this.state = {
            isLoading: true
        };

        this._ref = React.createRef();

        this._onIframeLoad = this._onIframeLoad.bind(this);
    }

    /**
     * Attach the script to this component.
     *
     * @returns {void}
     */
    componentDidMount() {
        const parentNode = this._ref.current;
        const room = this.props.location.state.room;
        const serverURL = this.props.location.state.serverURL
            || this.props._serverURL
            || config.defaultServerURL;

        const script = document.createElement('script');

        script.async = true;
        script.onload = () => this._onScriptLoad(parentNode, room, serverURL);
        script.onerror = (event: Event) =>
            this._navigateToHome(event, room, serverURL);
        script.src = getExternalApiURL(serverURL);

        this._ref.current.appendChild(script);
    }

    /**
     * Keep profile settings in sync with Conference.
     *
     * @param {Props} prevProps - Component's prop values before update.
     * @returns {void}
     */
    componentDidUpdate(prevProps) {
        const { props } = this;

        if (props._avatarURL !== prevProps._avatarURL) {
            this._setAvatarURL(props._avatarURL);
        }
        if (props._email !== prevProps._email) {
            this._setEmail(props._email);
        }
        if (props._name !== prevProps._name) {
            this._setName(props._name);
        }
    }

    /**
     * Remove conference on unmounting.
     *
     * @returns {void}
     */
    componentWillUnmount() {
        if (this._api) {
            this._api.dispose();
        }
    }

    /**
     * Implements React's {@link Component#render()}.
     *
     * @returns {ReactElement}
     */
    render() {
        return (
            <Wrapper innerRef = { this._ref }>
                { this._maybeRenderLoadingIndicator() }
            </Wrapper>
        );
    }

    /**
     * It renders a loading indicator, if appropriate.
     *
     * @returns {?ReactElement}
     */
    _maybeRenderLoadingIndicator() {
        if (this.state.isLoading) {
            return (
                <LoadingIndicator>
                    <Spinner size = 'large' />
                </LoadingIndicator>
            );
        }
    }

    /**
     * Navigates to home screen (Welcome).
     *
     * @param {Event} event - Event by which the function is called.
     * @param {string} room - Room name.
     * @param {string} serverURL - Server URL.
     * @returns {void}
     */
    _navigateToHome(event: Event, room: ?string, serverURL: ?string) {
        this.props.dispatch(push('/', {
            error: event.type === 'error',
            room,
            serverURL
        }));
    }

    /**
     * When the script is loaded create the iframe element in this component
     * and attach utils from jitsi-meet-electron-utils.
     *
     * @param {Object} parentNode - Node to which iframe has to be attached.
     * @param {string} roomName - Conference room name to be joined.
     * @param {string} serverURL - Jitsi Meet server url.
     * @returns {void}
     */
    _onScriptLoad(parentNode: Object, roomName: string, serverURL: string) {
        const JitsiMeetExternalAPI = window.JitsiMeetExternalAPI;

        const host = serverURL.replace(/https?:\/\//, '');

        const configOverwrite = {
            startWithAudioMuted: this.props._startWithAudioMuted,
            startWithVideoMuted: this.props._startWithVideoMuted
        };

        this._api = new JitsiMeetExternalAPI(host, {
            configOverwrite,
            onload: this._onIframeLoad,
            parentNode,
            roomName
        });
        initPopupsConfigurationRender(this._api);

        const iframe = this._api.getIFrame();

        setupScreenSharingForWindow(iframe);
        new RemoteControl(iframe); // eslint-disable-line no-new
        setupAlwaysOnTopRender(this._api);
        setupWiFiStats(iframe);

        this._api.on('readyToClose', (event: Event) =>
            this._navigateToHome(event));
        this._api.on('videoConferenceJoined',
            (conferenceInfo: Object) =>
                this._onVideoConferenceJoined(conferenceInfo));
    }

    /**
     * Updates redux state's user name from conference.
     *
     * @param {Object} params - Returned object from event.
     * @param {string} id - Local Participant ID.
     * @returns {void}
     */
    _onDisplayNameChange(params: Object, id: string) {
        if (params.id === id) {
            this.props.dispatch(setName(params.displayname));
        }
    }

    /**
     * Updates redux state's email from conference.
     *
     * @param {Object} params - Returned object from event.
     * @param {string} id - Local Participant ID.
     * @returns {void}
     */
    _onEmailChange(params: Object, id: string) {
        if (params.id === id) {
            this.props.dispatch(setEmail(params.email));
        }
    }

    _onIframeLoad: (*) => void;

    /**
     * Sets state of loading to false when iframe has completely loaded.
     *
     * @returns {void}
     */
    _onIframeLoad() {
        this.setState({
            isLoading: false
        });
    }

    /**
     * Saves conference info on joining it.
     *
     * @param {Object} conferenceInfo - Contains information about the current
     * conference.
     * @returns {void}
     */
    _onVideoConferenceJoined(conferenceInfo: Object) {
        setupDragAreas(this._api.getIFrame());

        this._setAvatarURL(this.props._avatarURL);
        this._setEmail(this.props._email);
        this._setName(this.props._name);

        const { id } = conferenceInfo;

        this._api.on('displayNameChange',
            (params: Object) => this._onDisplayNameChange(params, id));
        this._api.on('emailChange',
            (params: Object) => this._onEmailChange(params, id));
    }

    /**
     * Set Avatar URL from settings to conference.
     *
     * @param {string} avatarURL - Avatar URL.
     * @returns {void}
     */
    _setAvatarURL(avatarURL: string) {
        this._api.executeCommand('avatarUrl', avatarURL);
    }

    /**
     * Set email from settings to conference.
     *
     * @param {string} email - Email of user.
     * @returns {void}
     */
    _setEmail(email: string) {
        this._api.executeCommand('email', email);
    }

    /**
     * Set name from settings to conference.
     *
     * @param {string} name - Name of user.
     * @returns {void}
     */
    _setName(name: string) {
        this._api.executeCommand('displayName', name);
    }

}

/**
 * Inject some style into the iframe so everything except the filmstrip, chat,
 * buttons or any input is draggable.
 *
 * @param {Object} iframe - Reference to the iframe where the drag areas will
 * be set.
 * @returns {void}
 */
function setupDragAreas(iframe) {
    const injectStyle = document.createElement('style');

    injectStyle.type = 'text/css';
    injectStyle.textContent
        = 'body { -webkit-app-region: drag; }'
        + 'button, input { -webkit-app-region: no-drag }'
        + '#chatconversation, .filmstrip { -webkit-app-region: no-drag; }';
    iframe.contentDocument.head.appendChild(injectStyle);
}

/**
 * Maps (parts of) the redux state to the React props.
 *
 * @param {Object} state - The redux state.
 * @returns {{
 *     _avatarURL: string,
 *     _email: string,
 *     _name: string,
 *     _serverURL: string,
 *     _startWithAudioMuted: boolean,
 *     _startWithVideoMuted: boolean
 * }}
 */
function _mapStateToProps(state: Object) {
    return {
        _avatarURL: state.settings.avatarURL,
        _email: state.settings.email,
        _name: state.settings.name,
        _serverURL: state.settings.serverURL,
        _startWithAudioMuted: state.settings.startWithAudioMuted,
        _startWithVideoMuted: state.settings.startWithVideoMuted
    };
}

export default connect(_mapStateToProps)(Conference);
<|endoftext|>


<commit_before>'use strict';

var inherits = require('inherits');

var $ = require('bitcore').util.preconditions;

var Script = require('bitcore').Script;
var Transaction = require('bitcore').Transaction;
var _ = require('bitcore').deps._;

/**
 * A commitment transaction (also referred to as Lock transaction).
 *
 * @constructor
 * @param {Object} opts
 * @param {Array.<string>} opts.publicKeys
 * @param {string|bitcore.Network} opts.network - livenet by default
 */
function Commitment(opts) {
  $.checkArgument(opts.publicKeys && opts.publicKeys.length === 2, 'Must provide exactly two public keys');
  Transaction.call(this, opts.transaction);

  this.network = opts.network || 'livenet';
  this.publicKeys = opts.publicKeys;
  this.outscript = Script.buildMultisigOut(this.publicKeys, 2);
  this.address = this.outscript.toScriptHashOut().toAddress();
  this.to(this.address, this.inputAmount);

  Object.defineProperty(this, 'amount', {
    configurable: false,
    get: function() {
      return this.inputAmount;
    }
  });
}
inherits(Commitment, Transaction);

Commitment.prototype.toObject = function() {
  var transaction = Transaction.prototype.toObject.apply(this);
  return {
    transaction: transaction,
    publicKeys: _.map(this.publicKeys, function(publicKey) {
      return publicKey.toString();
    }),
    network: this.network.toString(),
  };
};

/**
 * @return {bitcore.Address}
 */
Commitment.prototype.getAddress = function() {
  return this.address;
};

module.exports = Commitment;
<commit_msg>revert to change<commit_after>'use strict';

var inherits = require('inherits');

var $ = require('bitcore').util.preconditions;

var Script = require('bitcore').Script;
var Transaction = require('bitcore').Transaction;
var _ = require('bitcore').deps._;

/**
 * A commitment transaction (also referred to as Lock transaction).
 *
 * @constructor
 * @param {Object} opts
 * @param {Array.<string>} opts.publicKeys
 * @param {string|bitcore.Network} opts.network - livenet by default
 */
function Commitment(opts) {
  $.checkArgument(opts.publicKeys && opts.publicKeys.length === 2, 'Must provide exactly two public keys');
  Transaction.call(this, opts.transaction);

  this.network = opts.network || 'livenet';
  this.publicKeys = opts.publicKeys;
  this.outscript = Script.buildMultisigOut(this.publicKeys, 2);
  this.address = this.outscript.toScriptHashOut().toAddress();
  this.change(this.address);

  Object.defineProperty(this, 'amount', {
    configurable: false,
    get: function() {
      return this.inputAmount;
    }
  });
}
inherits(Commitment, Transaction);

Commitment.prototype.toObject = function() {
  var transaction = Transaction.prototype.toObject.apply(this);
  return {
    transaction: transaction,
    publicKeys: _.map(this.publicKeys, function(publicKey) {
      return publicKey.toString();
    }),
    network: this.network.toString(),
  };
};

/**
 * @return {bitcore.Address}
 */
Commitment.prototype.getAddress = function() {
  return this.address;
};

module.exports = Commitment;
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { connect } from 'react-redux'
import Loader from 'react-loader';
import Navbar from "../../components/Navbar.react"
import InputURL from "../../components/inputURL/"
import EntityItem from "../../components/EntityItem.react"

const inputKey = 'homeResult';
const homepageUrlSearchForm = {
  display: 'block',
  margin: 'auto',
  marginTop: '50px',
  paddingLeft: '20px',
  paddingRight: '20px'
}

import { getFirehose } from "../actions/index"

class Home extends Component {

  componentWillMount() {
    const { dispatch } = this.props;
    dispatch(getFirehose())
  }

  render() {
    const { node, isURL, firehoseResult, dispatch } = this.props;

    const connections = false?
    firehoseResult.map(function(edge, i){
      return (

          <EntityItem
            entity={edge.nodeFrom}
            user={edge.user}
          />
          <EntityItem
            entity={edge.nodeTo}
            user={edge.user}
          />

)
    }):<Loader top="100px"/>;

    return (

        <Navbar />

              <InputURL
                placeholder="Enter a URL to search"
                hasSearchButton={true}
                receivedSearchResult={this._onSearchResult}
                id={inputKey}/>

Recently Made Connections:

              {connections}

    );
  }

  _changeMessage(i){
    this.setState({
      messageIndex: i
    })
  }
}

function mapStateToProps(state) {
  const { firehoseResult, inputURLResult} = state

  let object = { firehoseResult }

  if (  inputURLResult && inputURLResult[inputKey] ){
    const { node, isURL } = inputURLResult[inputKey];
    Object.assign(object, { node, isURL });
  }

  return object
}

export default connect(mapStateToProps)(Home)
<commit_msg>opps killing hard coded value.<commit_after>import React, { Component } from 'react'
import { connect } from 'react-redux'
import Loader from 'react-loader';
import Navbar from "../../components/Navbar.react"
import InputURL from "../../components/inputURL/"
import EntityItem from "../../components/EntityItem.react"

const inputKey = 'homeResult';
const homepageUrlSearchForm = {
  display: 'block',
  margin: 'auto',
  marginTop: '50px',
  paddingLeft: '20px',
  paddingRight: '20px'
}

import { getFirehose } from "../actions/index"

class Home extends Component {

  componentWillMount() {
    const { dispatch } = this.props;
    dispatch(getFirehose())
  }

  render() {
    const { node, isURL, firehoseResult, dispatch } = this.props;

    const connections = firehoseResult?
    firehoseResult.map(function(edge, i){
      return (

          <EntityItem
            entity={edge.nodeFrom}
            user={edge.user}
          />
          <EntityItem
            entity={edge.nodeTo}
            user={edge.user}
          />

)
    }):<Loader top="100px"/>;

    return (

        <Navbar />

              <InputURL
                placeholder="Enter a URL to search"
                hasSearchButton={true}
                receivedSearchResult={this._onSearchResult}
                id={inputKey}/>

Recently Made Connections:

              {connections}

    );
  }

  _changeMessage(i){
    this.setState({
      messageIndex: i
    })
  }
}

function mapStateToProps(state) {
  const { firehoseResult, inputURLResult} = state

  let object = { firehoseResult }

  if (  inputURLResult && inputURLResult[inputKey] ){
    const { node, isURL } = inputURLResult[inputKey];
    Object.assign(object, { node, isURL });
  }

  return object
}

export default connect(mapStateToProps)(Home)
<|endoftext|>


<commit_before>/*
 * SimpleJS v0.0.1
 *
 * Copyright (c) 2012 Tyler O'Brien
 *
 * 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.
 * */

/*
 * AJAX fallback for IE6.
 * Might not work for IE5 and earlier.
 * */
if (typeof XMLHttpRequest === 'undefined') {
	var XMLHttpRequest = function() {
		return new ActiveXObject('Microsoft.XMLHTTP');
	};
	XMLHttpRequest.prototype.isActiveX = true;
} else {
	XMLHttpRequest.prototype.isActiveX = false;
}

/*
 * send_s() returns Nothing
 * Input: Object
    * A "safe" version of XMLHttpRequest.send().
    * Is compatible with both ActiveX-based AJAX and otherwise.
    * */
XMLHttpRequest.prototype.send_s = function(args) {
	if (typeof args === 'undefined' || args === null) {
		if (this.isActiveX) this.send();
		else this.send(null);
	} else if ('method' in args && 'queryString' in args && args.method === 'POST') {
		this.send(args.queryString);
	} else {
		this.send_s();
	}
}

/*
 * decodeQueryString() returns Object
 * Input: Nothing
    * Converts the string to an Object that represents a query string.
    * Examples of valid formats:
       * ?id=42&email=foo@bar.com&type=helloworld
	   * &id=42&foo&name=John+Doe
	   * foo&bar
    * */
String.prototype.decodeQueryString = function() {
	var buffer;
	var queryString = this.replace('+', ' ');
	var regex = /[?&]?([^&=]+)=?([^&]+)?/g;
	var result = {};

	while (buffer = regex.exec(queryString)) {
		result[decodeURIComponent(buffer[1])] = decodeURIComponent(buffer[2]);
	}

	return result;
};

var Simple = {
	AJAX: function(args) {
		var ajaxRequest = new Simple.AJAXRequest(args);

		ajaxRequest.http.open(ajaxRequest.method, ajaxRequest.urlToOpen, true);
		ajaxRequest.http.setRequestHeader('Content-type', ajaxRequest.contentType+'; charset='+ajaxRequest.charset);

		if (ajaxRequest.method === 'POST') {
			ajaxRequest.http.setRequestHeader('Content-length', ajaxRequest.queryString.length);
			ajaxRequest.http.setRequestHeader('Connection', 'close');
		}

		ajaxRequest.http.onreadystatechange = function(){
			switch (ajaxRequest.http.readyState) {
				case 1:
					ajaxRequest.timeBegin = new Date().getTime();
					Simple.AJAXHandler.CallIfExists(ajaxRequest.onConnect);
				break;
				case 2:
					Simple.AJAXHandler.CallIfExists(ajaxRequest.onRequest);
				break;
				case 3:
					Simple.AJAXHandler.CallIfExists(ajaxRequest.onProcess);
				break;
				case 4:
					if (typeof ajaxRequest.timeout !== 'undefined') {
						clearTimeout(ajaxRequest.timeout);
					}

					ajaxRequest.timeEnd = new Date().getTime();
					ajaxRequest.timeDifference = (ajaxRequest.timeEnd - ajaxRequest.timeBegin);

					switch (ajaxRequest.http.status) {
						case 200:
							Simple.AJAXHandler.CallIfExists(ajaxRequest.onSuccess, ajaxRequest.http.responseText, ajaxRequest.timeDifference);
						break;
						case 404:
							Simple.AJAXHandler.CallIfExists(ajaxRequest.onNotFound, ajaxRequest.http.responseText, ajaxRequest.timeDifference);
						default:
							Simple.AJAXHandler.CallIfExists(ajaxRequest.onError, ajaxRequest.http.status, ajaxRequest.timeDifference);
						break;
					}
				break;
			}
		};

		/*
		 * Add a new timeout if one is given.
		 * The time is assumed to be milliseconds.
		 * */
		if ('timeout' in args && args['timeout'] === true) {
			ajaxRequest.timeout = setTimeout(function() {
				ajaxRequest.http.abort();
				Simple.AJAXHandler.CallIfExists(ajaxRequest.onTimeout);
			}, args['timeout']);
		}

		ajaxRequest.http.send_s(ajaxRequest);
	},

	/*
	 * AJAXHandler
	 * This object contains boilerplate functions that help organise the code of Simple AJAX.
	 * These probably won't need to be used outside of the AjaxRequest constructor function.
	 * Note:
		* These functions are also where the default values are assigned.
	 * */
	AJAXHandler: {
		/*
		 * CallIfExists() returns Nothing
		 * Input: Function, Mixed, Mixed
			* Takes a callback, and up to two optional parameters.
			* Depending on the number of parameters given will make one of three different calls.
			* */
		CallIfExists: function(callback, param1, param2) {
			if (typeof callback === 'function') {
				if (typeof param2 !== 'undefined') callback(param1, param2);
				else if (typeof param1 !== 'undefined') callback(param1);
				else callback();
			}
		},

		/*
		 * GetCarset() returns String
		 * Input: String
			* Takes a passed object, assumed String.
			* If NULL or UNDEFINED is passed then a default value is returned.
			* Otherwise the passed value is returned back.
			* */
		GetCharset: function(charset) {
			return (typeof charset === 'string') ? charset : 'utf-8';
		},

		/*
		 * GetContentType() returns String
		 * Input: String
			* See GetCharset().
			* */
		GetContentType: function(contentType) {
			return (typeof contentType === 'string') ? contentType : 'application/x-www-form-urlencoded';
		},

		/*
		 * GetMethod() returns String
		 * Input: String
			* See GetCharset().
			* */
		GetMethod: function(method) {
			return (typeof method === 'string') ? method : 'GET';
		},

		/*
		 * GetQueryString() returns String
		 * Input: Object
		 * Takes an object of (key=>value) pairs and converts them to a query string.
		 * For example:
			* The object {a:1,b:2,c:3} would become "a=1&b=2&c=3".
			* Note that the question mark is not appended to the beginning.
		 * */
		GetQueryString: function(data) {
			var output = '';

			if (typeof data !== 'undefined') {
				var output = '';

				for (var key in data) {
					output = (output + key +'='+ data[key] + '&');
				}

				// Trim off the extra ampersand.
				output = output.substring(0, output.length-1);
			}

			return output;
		},

		/*
		 * GetUrl() returns String
		 * Input: String
			* See GetCharset().
			* */
		GetUrl: function(url) {
			return (typeof url === 'string') ? url : '/';
		},

		/*
		 * GetUrlToOpen() returns String
		 * Input: String, String, String
			* Returns the value that will be passed to the XMLHttpRequest.open() function.
			* If the method is a GET it will be the entire URL, as well as the query string.
			* If the method is a POST then it will only be the query string.
			* */
		GetUrlToOpen: function(url, queryString, method) {
			return (method === 'POST') ? url : (url + '?' + queryString);
		}
	},

	AJAXRequest: function(args) {
		this.charset = Simple.AJAXHandler.GetCharset(args['charset']);
		this.contentType = Simple.AJAXHandler.GetContentType(args['contentType']);
		this.http = new XMLHttpRequest();
		this.method = Simple.AJAXHandler.GetMethod(args['method']);
		this.onConnect = args['onConnect'];
		this.onError = args['onError'];
		this.onNotFound = args['onNotFound'];
		this.onProcess = args['onProcess'];
		this.onRequest = args['onRequest'];
		this.onSuccess = args['onSuccess'];
		this.onTimeout = args['onTimeout'];
		this.queryString = Simple.AJAXHandler.GetQueryString(args['data']);
		this.timeBegin = 0;
		this.timeDifference = 0;
		this.timeEnd = 0;
		this.timeout = null;
		this.url = Simple.AJAXHandler.GetUrl(args['url']);
		this.urlToOpen = Simple.AJAXHandler.GetUrlToOpen(this.url, this.queryString, this.method);
	},

	Cookie: {
		data: {},

		DoUpdateData: function() {
			this.data = {};

			var arr = document.cookie.split('; ');
			var buffer = null;
			var cookie = null;
			var regex = /([^=]+)=(.*)/;

			Simple.Each(arr, function(){
				cookie = regex.exec(this);
				Simple.Cookie.data[escape(cookie[1])] = escape(cookie[2]);
			});
		},

		Get: function(name) {
			if (this.data === null) {
				this.DoUpdateData();
			}
			return Simple.Cookie.data[name];
		},

		Set: function(name, value, expiration) {
			document.cookie = (name+'='+value+';') + (expiration ? ' expires=0;' : '');
			this.DoUpdateData();
		}
	},

	/*
	 * Each() returns Nothing
	 * Input: Array|Object, Function
	    *
	    * */
	Each: function (haystack, callback) {
		if (typeof haystack !== 'undefined' && haystack !== null) {
			var iterator = {
				i: null,
				parent: haystack,
				value: null
			};
			if (haystack.forEach !== undefined) {
				var end = haystack.length;
				for (var i = 0; i < end; i++) {
					iterator.value = haystack[i];
					if (callback.call(iterator.value, iterator) === false) {
						break;
					}
				}
			} else {
				for (iterator.i in haystack) {
					iterator.value = haystack[iterator.i];
					if (callback.call(iterator.value, iterator) === false) {
						break;
					}
				}
			}
		}
	},

	/*
	 * Equals() returns Boolean
	 * Input: Mixed, Mixed
	    * Compares each element of both passed objects, checking for strict equality.
	    * */
	Equals: function(first, second) {
		var result = true;

		Simple.Each(first, function(itr) {
			if (itr.value !== second[itr.index]) {
				return result = false;
			}
		});

		return result;
	},

	/*
	 * Exists() returns Mixed
	 * Input: Mixed, Mixed, Boolean
	    *
	    * */
	Exists: function(value, override, doReturnBoolean) {
		var output;

		if (typeof value !== 'undefined') {
			output = value;
		} else if (typeof doReturnBoolean !== 'undefined' && doReturnBoolean === true) {
			output = false;
		} else {
			output = override;
		}

		return output;
	},

	DOM: {
		callbacks: [], // The array of each callback function to be called when the DOM is ready.
		isReady: false, // This boolean is used to ensure that DOM.OnReady is only called once.

		/*
		 * OnDOMContentLoaded() returns Nothing
		 * Input: Nothing
		    * The function called by the event listeners.
		    * Because of the legacy event listener this may be called twice.
		    * */
		OnDOMContentLoaded: function() {
			if (typeof document.addEventListener !== 'undefined') {
				document.removeEventListener('DOMContentLoaded', Simple.DOM.OnDOMContentLoaded, false);
				Simple.DOM.OnReady();
			} else if (typeof document.attachEvent !== 'undefined' && document.readyState === 'complete' && document.body !== null) {
				document.detachEvent('onreadystatechange', Simple.DOM.OnDOMContentLoaded);
				Simple.DOM.OnReady();
			}
		},

		/*
		 * OnReady() returns Nothing
		 * Input: Nothing
		    * The function called when the DOM has finished loading/is ready.
		    * Uses a boolean to prevent multiple calls because it may be called twice by
		    * the event listener and legacy event listener.
		    * */
		OnReady: function() {
			if (Simple.DOM.isReady === false) {
				if (Simple.DOM.callbacks.length > 0) {
					Simple.Each(Simple.DOM.callbacks, function(){
						this.call(null);
					});
				}
				Simple.DOM.isReady = true;
			}
		},

		/*
		 * WhenReady() returns Nothing
		 * Input: Function
		    * Adds the passed callback to the array of callbacks that are called when
		    * the DOM is ready.
		    * */
		WhenReady: function(callback) {
			if (Simple.DOM.isReady === false) {
				Simple.DOM.callbacks.push(callback);
			}
		}
	},

	GET: {
		data: document.location.search.decodeQueryString(),

		/*
		 * exists() returns Boolean
		 * Input: String
		 * */
		exists: function(index) {
			return (typeof index === 'string' && index in this.data);
		},

		/*
		 * find() returns Mixed
		 * Input: String
		 * */
		find: function(index) {
			if (this.exists(index)) {
				return this.data[index];
			}
		}
	}
};

Simple.Cookie.DoUpdateData();

if (typeof document.addEventListener !== 'undefined') {
	document.addEventListener('DOMContentLoaded', Simple.DOM.OnDOMContentLoaded, false);
	window.addEventListener('load', Simple.DOM.OnReady, false);
} else if (typeof document.attachEvent !== 'undefined') {
	document.attachEvent('onreadystatechange', Simple.DOM.OnDOMContentLoaded);
	window.attachEvent('onload', Simple.DOM.OnReady, false);
} else {
	window.onload = Simple.DOM.OnReady;
}<commit_msg>Adjusted comments.<commit_after>/*
 * SimpleJS v0.0.1
 *
 * Copyright (c) 2012 Tyler O'Brien
 *
 * 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.
 * */

/*
 * AJAX fallback for IE6.
 * Might not work for IE5 and earlier.
 * */
if (typeof XMLHttpRequest === 'undefined') {
	var XMLHttpRequest = function() {
		return new ActiveXObject('Microsoft.XMLHTTP');
	};
	XMLHttpRequest.prototype.isActiveX = true;
} else {
	XMLHttpRequest.prototype.isActiveX = false;
}

/*
 * send_s() returns Nothing
 * Input: Object
    * A "safe" version of XMLHttpRequest.send().
    * Is compatible with both ActiveX-based AJAX and otherwise.
    * */
XMLHttpRequest.prototype.send_s = function(args) {
	if (typeof args === 'undefined' || args === null) {
		if (this.isActiveX) this.send();
		else this.send(null);
	} else if ('method' in args && 'queryString' in args && args.method === 'POST') {
		this.send(args.queryString);
	} else {
		this.send_s();
	}
}

/*
 * decodeQueryString() returns Object
 * Input: Nothing
    * Converts the string to an Object that represents a query string.
    * Examples of valid formats:
       * ?id=42&email=foo@bar.com&type=helloworld
	   * &id=42&foo&name=John+Doe
	   * foo&bar
    * */
String.prototype.decodeQueryString = function() {
	var buffer;
	var queryString = this.replace('+', ' ');
	var regex = /[?&]?([^&=]+)=?([^&]+)?/g;
	var result = {};

	while (buffer = regex.exec(queryString)) {
		result[decodeURIComponent(buffer[1])] = decodeURIComponent(buffer[2]);
	}

	return result;
};

var Simple = {
	AJAX: function(args) {
		var ajaxRequest = new Simple.AJAXRequest(args);

		ajaxRequest.http.open(ajaxRequest.method, ajaxRequest.urlToOpen, true);
		ajaxRequest.http.setRequestHeader('Content-type', ajaxRequest.contentType+'; charset='+ajaxRequest.charset);

		if (ajaxRequest.method === 'POST') {
			ajaxRequest.http.setRequestHeader('Content-length', ajaxRequest.queryString.length);
			ajaxRequest.http.setRequestHeader('Connection', 'close');
		}

		ajaxRequest.http.onreadystatechange = function(){
			switch (ajaxRequest.http.readyState) {
				case 1:
					ajaxRequest.timeBegin = new Date().getTime();
					Simple.AJAXHandler.CallIfExists(ajaxRequest.onConnect);
				break;
				case 2:
					Simple.AJAXHandler.CallIfExists(ajaxRequest.onRequest);
				break;
				case 3:
					Simple.AJAXHandler.CallIfExists(ajaxRequest.onProcess);
				break;
				case 4:
					if (typeof ajaxRequest.timeout !== 'undefined') {
						clearTimeout(ajaxRequest.timeout);
					}

					ajaxRequest.timeEnd = new Date().getTime();
					ajaxRequest.timeDifference = (ajaxRequest.timeEnd - ajaxRequest.timeBegin);

					switch (ajaxRequest.http.status) {
						case 200:
							Simple.AJAXHandler.CallIfExists(ajaxRequest.onSuccess, ajaxRequest.http.responseText, ajaxRequest.timeDifference);
						break;
						case 404:
							Simple.AJAXHandler.CallIfExists(ajaxRequest.onNotFound, ajaxRequest.http.responseText, ajaxRequest.timeDifference);
						default:
							Simple.AJAXHandler.CallIfExists(ajaxRequest.onError, ajaxRequest.http.status, ajaxRequest.timeDifference);
						break;
					}
				break;
			}
		};

		/*
		 * Add a new timeout if one is given.
		 * The time is assumed to be milliseconds.
		 * */
		if ('timeout' in args && args['timeout'] === true) {
			ajaxRequest.timeout = setTimeout(function() {
				ajaxRequest.http.abort();
				Simple.AJAXHandler.CallIfExists(ajaxRequest.onTimeout);
			}, args['timeout']);
		}

		ajaxRequest.http.send_s(ajaxRequest);
	},

	/*
	 * AJAXHandler
	 * This object contains boilerplate functions that help organise the code of Simple AJAX.
	 * These probably won't need to be used outside of the AjaxRequest constructor function.
	 * Note:
		* These functions are also where the default values are assigned.
	 * */
	AJAXHandler: {
		/*
		 * CallIfExists() returns Nothing
		 * Input: Function, Mixed, Mixed
			* Takes a callback, and up to two optional parameters.
			* Depending on the number of parameters given will make one of three different calls.
			* */
		CallIfExists: function(callback, param1, param2) {
			if (typeof callback === 'function') {
				if (typeof param2 !== 'undefined') callback(param1, param2);
				else if (typeof param1 !== 'undefined') callback(param1);
				else callback();
			}
		},

		/*
		 * GetCarset() returns String
		 * Input: String
		 * */
		GetCharset: function(charset) {
			return (typeof charset === 'string') ? charset : 'utf-8';
		},

		/*
		 * GetContentType() returns String
		 * Input: String
		 */
		GetContentType: function(contentType) {
			return (typeof contentType === 'string') ? contentType : 'application/x-www-form-urlencoded';
		},

		/*
		 * GetMethod() returns String
		 * Input: String
		 */
		GetMethod: function(method) {
			return (typeof method === 'string') ? method : 'GET';
		},

		/*
		 * GetQueryString() returns String
		 * Input: Object
		 * Takes an object of (key=>value) pairs and converts them to a query string.
		 * For example:
			* The object {a:1,b:2,c:3} would become "a=1&b=2&c=3".
			* Note that the question mark is not appended to the beginning.
		 * */
		GetQueryString: function(data) {
			var output = '';

			if (typeof data !== 'undefined') {
				var output = '';

				for (var key in data) {
					output = (output + key +'='+ data[key] + '&');
				}

				// Trim off the extra ampersand.
				output = output.substring(0, output.length-1);
			}

			return output;
		},

		/*
		 * GetUrl() returns String
		 * Input: String
		 */
		GetUrl: function(url) {
			return (typeof url === 'string') ? url : '/';
		},

		/*
		 * GetUrlToOpen() returns String
		 * Input: String, String, String
			* Returns the value that will be passed to the XMLHttpRequest.open() function.
			* If the method is a GET it will be the entire URL, as well as the query string.
			* If the method is a POST then it will only be the query string.
			* */
		GetUrlToOpen: function(url, queryString, method) {
			return (method === 'POST') ? url : (url + '?' + queryString);
		}
	},

	AJAXRequest: function(args) {
		this.charset = Simple.AJAXHandler.GetCharset(args['charset']);
		this.contentType = Simple.AJAXHandler.GetContentType(args['contentType']);
		this.http = new XMLHttpRequest();
		this.method = Simple.AJAXHandler.GetMethod(args['method']);
		this.onConnect = args['onConnect'];
		this.onError = args['onError'];
		this.onNotFound = args['onNotFound'];
		this.onProcess = args['onProcess'];
		this.onRequest = args['onRequest'];
		this.onSuccess = args['onSuccess'];
		this.onTimeout = args['onTimeout'];
		this.queryString = Simple.AJAXHandler.GetQueryString(args['data']);
		this.timeBegin = 0;
		this.timeDifference = 0;
		this.timeEnd = 0;
		this.timeout = null;
		this.url = Simple.AJAXHandler.GetUrl(args['url']);
		this.urlToOpen = Simple.AJAXHandler.GetUrlToOpen(this.url, this.queryString, this.method);
	},

	Cookie: {
		data: {},

		DoUpdateData: function() {
			this.data = {};

			var arr = document.cookie.split('; ');
			var buffer = null;
			var cookie = null;
			var regex = /([^=]+)=(.*)/;

			Simple.Each(arr, function(){
				cookie = regex.exec(this);
				Simple.Cookie.data[escape(cookie[1])] = escape(cookie[2]);
			});
		},

		Get: function(name) {
			if (this.data === null) {
				this.DoUpdateData();
			}
			return Simple.Cookie.data[name];
		},

		Set: function(name, value, expiration) {
			document.cookie = (name+'='+value+';') + (expiration ? ' expires=0;' : '');
			this.DoUpdateData();
		}
	},

	/*
	 * Each() returns Nothing
	 * Input: Array|Object, Function
	    *
	    * */
	Each: function (haystack, callback) {
		if (typeof haystack !== 'undefined' && haystack !== null) {
			var iterator = {
				i: null,
				parent: haystack,
				value: null
			};
			if (haystack.forEach !== undefined) {
				var end = haystack.length;
				for (var i = 0; i < end; i++) {
					iterator.value = haystack[i];
					if (callback.call(iterator.value, iterator) === false) {
						break;
					}
				}
			} else {
				for (iterator.i in haystack) {
					iterator.value = haystack[iterator.i];
					if (callback.call(iterator.value, iterator) === false) {
						break;
					}
				}
			}
		}
	},

	/*
	 * Equals() returns Boolean
	 * Input: Mixed, Mixed
	    * Compares each element of both passed objects, checking for strict equality.
	    * */
	Equals: function(first, second) {
		var result = true;

		Simple.Each(first, function(itr) {
			if (itr.value !== second[itr.index]) {
				return result = false;
			}
		});

		return result;
	},

	/*
	 * Exists() returns Mixed
	 * Input: Mixed, Mixed, Boolean
	    *
	    * */
	Exists: function(value, override, doReturnBoolean) {
		var output;

		if (typeof value !== 'undefined') {
			output = value;
		} else if (typeof doReturnBoolean !== 'undefined' && doReturnBoolean === true) {
			output = false;
		} else {
			output = override;
		}

		return output;
	},

	DOM: {
		callbacks: [], // The array of each callback function to be called when the DOM is ready.
		isReady: false, // This boolean is used to ensure that DOM.OnReady is only called once.

		/*
		 * OnDOMContentLoaded() returns Nothing
		 * Input: Nothing
		    * The function called by the event listeners.
		    * Because of the legacy event listener this may be called twice.
		    * */
		OnDOMContentLoaded: function() {
			if (typeof document.addEventListener !== 'undefined') {
				document.removeEventListener('DOMContentLoaded', Simple.DOM.OnDOMContentLoaded, false);
				Simple.DOM.OnReady();
			} else if (typeof document.attachEvent !== 'undefined' && document.readyState === 'complete' && document.body !== null) {
				document.detachEvent('onreadystatechange', Simple.DOM.OnDOMContentLoaded);
				Simple.DOM.OnReady();
			}
		},

		/*
		 * OnReady() returns Nothing
		 * Input: Nothing
		    * The function called when the DOM has finished loading/is ready.
		    * Uses a boolean to prevent multiple calls because it may be called twice by
		    * the event listener and legacy event listener.
		    * */
		OnReady: function() {
			if (Simple.DOM.isReady === false) {
				if (Simple.DOM.callbacks.length > 0) {
					Simple.Each(Simple.DOM.callbacks, function(){
						this.call(null);
					});
				}
				Simple.DOM.isReady = true;
			}
		},

		/*
		 * WhenReady() returns Nothing
		 * Input: Function
		    * Adds the passed callback to the array of callbacks that are called when
		    * the DOM is ready.
		    * */
		WhenReady: function(callback) {
			if (Simple.DOM.isReady === false) {
				Simple.DOM.callbacks.push(callback);
			}
		}
	},

	GET: {
		data: document.location.search.decodeQueryString(),

		/*
		 * exists() returns Boolean
		 * Input: String
		 * */
		exists: function(index) {
			return (typeof index === 'string' && index in this.data);
		},

		/*
		 * find() returns Mixed
		 * Input: String
		 * */
		find: function(index) {
			if (this.exists(index)) {
				return this.data[index];
			}
		}
	}
};

Simple.Cookie.DoUpdateData();

if (typeof document.addEventListener !== 'undefined') {
	document.addEventListener('DOMContentLoaded', Simple.DOM.OnDOMContentLoaded, false);
	window.addEventListener('load', Simple.DOM.OnReady, false);
} else if (typeof document.attachEvent !== 'undefined') {
	document.attachEvent('onreadystatechange', Simple.DOM.OnDOMContentLoaded);
	window.attachEvent('onload', Simple.DOM.OnReady, false);
} else {
	window.onload = Simple.DOM.OnReady;
}<|endoftext|>


<commit_before>

//Initialize Map and bind filter button
//TODO:
//Add event handlers for map zoom/move
$(document).ready(function () {
    document.querySelector("google-map").addEventListener('api-load', function(e) {
      map.init();
  });
	$("#tButton").click(function() {
		st = "Thu, 01 Jan 1970 05:00:00 GMT";
		end = "Sat, 01 Jan 2050 05:00:00 GMT";
		radius = 10;
		tags = [];

		if($('#startTimePicker').data("DateTimePicker").date() != null){
		st = $('#startTimePicker').data("DateTimePicker").date().toDate().toUTCString();
		}

		if($('#endTimePicker').data("DateTimePicker").date() != null){
		end = $('#endTimePicker').data("DateTimePicker").date().toDate().toUTCString();
		}

		if( $('#radius').val() != ""){
			radius = $('#radius').val();
		}

		temp = $('#tags').val();
		if(temp.length != ""){
		temp = temp.replace(/ /g,'');
		temp = temp.toLowerCase();
		tags = temp.split(',');
		}
		filterBy(st, end, radius,tags);
	})
});

//Map Object to hold map parameters
//and will be used for map event handling
var map = {
    mapElement: null,
    map: null,
    markers: null,
    zoom: null,
    leftBound: null,
    rightBound: null,
    bottomBound: null,
    topBound: null,

    init: function() {
        map.mapElement = document.querySelector("google-map");
        map.map = map.mapElement.map;
        map.zoom = map.map.getZoom();
        map.markers = Array.prototype.slice.call(document.querySelectorAll("google-map-marker"));
        for (var i = 0; i < map.markers.length; i++) {
            console.log(map.markers[i]);
        }

    },

    updateBounds: function() {
        map.leftBound = map.map.getBounds.getSouthWest().lng();
        map.bottomBound = map.map.getBounds.getSouthWest().lat();
        map.rightBound = map.map.getBounds.getNorthEast().lng();
        map.topBound = map.map.getBounds.getNorthEast().lat();
    },

    move: function() {
        map.updateBounds();
        //future will call filterBy
    },
    click: function() {
        map.updateBounds();
        //future will call filterBy
    }
};

//filters the markers displayed on the map
//currently only by time/radius
function filterBy(startTime, endTime, rad) {
    //AJAX CALL
    $.getJSON($SCRIPT_ROOT + '/filter', {
        //set fields to send
        start: startTime,
        end: endTime,
        radius: rad,
        tags: JSON.stringify(tags)
      },
      //CALLBACK FUNCTION
      function(data) {
        //remove all markers currently on the map
        //but that were not found in the database query
        //by setting their map reference to null
        for(var i = 0; i < map.markers.length; i++) {
            if(isIn(map.markers[i], "id", data, "_id") == null) {
                map.markers[i].marker.setMap(null);
            }
        }

        //for each marker returned by the database query
        for(var i = 0; i < data.length; i++) {
            console.log(data);
            temp = new Date(data[i].start_date.$date);
            console.log(temp);

            //if the marker is already in map.markers
            //set the markers reference to the map
            temp = isIn(data[i], "_id", map.markers, "id");
            if(temp != null) {
                temp.marker.setMap(map.map);
            }
            //else create a new marker and add it to the map/list of markers
            else {
            	console.log("SHOULDN'T BE HERE");
                console.log(data[i]);
                var m = document.createElement('google-map-marker');
                m.id = data[i]._id;

                m.longitude = data[i].location.loc.coordinates[0];
                m.latitude = data[i].location.loc.coordinates[1];
                m.title = data[i].title;
                var h3 = document.createElement("h3");
                var a = document.createElement("a");
                a.href = "/event/" + data[i]._id;
                a.innerText = data[i].title;
                h3.appendChild(a);
                m.appendChild(h3);
                var p1 = document.createElement("p");
                p1.innerText = data[i].description;
                m.appendChild(p1);
                var p2 = document.createElement("p");

                //TODO:
                //Fix the dates so they are formatted correctly
                var sd  = new Date(data[i].start_date.$date);
                var ed = new Date(data[i].end_date.$date);
                p2.innerText = sd + " -- " + ed;
                m.appendChild(p2);

                var p3 = document.createElement("p");
                p3.innerText = data[i].location.address;
                m.appendChild(p3);
                console.log(m);
                console.log(m.latitute);
                map.mapElement.appendChild(m);
                map.markers.push(m);
                //m.marker.setMap(map.map);
            }
        }
				seperateMarkers();
      });

}

//function to check if and item exists in
//a list by checking a specific attribute
//used by filterBy()
function isIn(m, mAttr, l, lAttr) {
    for(var i = 0; i < l.length; i++) {
        if(l[i][lAttr].trim() == m[mAttr].trim()) {
            return l[i];
        }
    }
    return null;
}
<commit_msg>filter bug checking<commit_after>

//Initialize Map and bind filter button
//TODO:
//Add event handlers for map zoom/move
$(document).ready(function () {
    document.querySelector("google-map").addEventListener('api-load', function(e) {
      map.init();
  });
	$("#tButton").click(function() {
		st = "Thu, 01 Jan 1970 05:00:00 GMT";
		end = "Sat, 01 Jan 2050 05:00:00 GMT";
		radius = 10;
		tags = [];

		if($('#startTimePicker').data("DateTimePicker").date() != null){
		st = $('#startTimePicker').data("DateTimePicker").date().toDate().toUTCString();
		}

		if($('#endTimePicker').data("DateTimePicker").date() != null){
		end = $('#endTimePicker').data("DateTimePicker").date().toDate().toUTCString();
		}

		if( $('#radius').val() != ""){
			radius = $('#radius').val();
		}

		temp = $('#tags').val();
		if(temp.length != ""){
		temp = temp.replace(/ /g,'');
		temp = temp.toLowerCase();
		tags = temp.split(',');
		}
		filterBy(st, end, radius,tags);
	})
});

//Map Object to hold map parameters
//and will be used for map event handling
var map = {
    mapElement: null,
    map: null,
    markers: null,
    zoom: null,
    leftBound: null,
    rightBound: null,
    bottomBound: null,
    topBound: null,

    init: function() {
        map.mapElement = document.querySelector("google-map");
        map.map = map.mapElement.map;
        map.zoom = map.map.getZoom();
        map.markers = Array.prototype.slice.call(document.querySelectorAll("google-map-marker"));
        for (var i = 0; i < map.markers.length; i++) {
            console.log(map.markers[i]);
        }

    },

    updateBounds: function() {
        map.leftBound = map.map.getBounds.getSouthWest().lng();
        map.bottomBound = map.map.getBounds.getSouthWest().lat();
        map.rightBound = map.map.getBounds.getNorthEast().lng();
        map.topBound = map.map.getBounds.getNorthEast().lat();
    },

    move: function() {
        map.updateBounds();
        //future will call filterBy
    },
    click: function() {
        map.updateBounds();
        //future will call filterBy
    }
};

//filters the markers displayed on the map
//currently only by time/radius
function filterBy(startTime, endTime, rad) {
    //AJAX CALL
    $.getJSON($SCRIPT_ROOT + '/filter', {
        //set fields to send
        start: startTime,
        end: endTime,
        radius: rad,
        tags: JSON.stringify(tags)
      },
      //CALLBACK FUNCTION
      function(data) {
        //remove all markers currently on the map
        //but that were not found in the database query
        //by setting their map reference to null
        for(var i = 0; i < map.markers.length; i++) {
            if(isIn(map.markers[i], "id", data, "_id") == null) {
                map.markers[i].marker.setMap(null);
            }
        }

        //for each marker returned by the database query
        for(var i = 0; i < data.length; i++) {
            temp = new Date(data[i].start_date.$date);

            //if the marker is already in map.markers
            //set the markers reference to the map
            temp = isIn(data[i], "_id", map.markers, "id");
            if(temp != null) {
                temp.marker.setMap(map.map);
            }
            //else create a new marker and add it to the map/list of markers
            else {
            	console.log("SHOULDN'T BE HERE");
                console.log(data[i]);
                console.log("map markers");
                for(var i = 0; i < map.markers.length; i++) {
                	console.log(map.markers[i]);
                }
                console.log("end map markers");
                var m = document.createElement('google-map-marker');
                m.id = data[i]._id;

                m.longitude = data[i].location.loc.coordinates[0];
                m.latitude = data[i].location.loc.coordinates[1];
                m.title = data[i].title;
                var h3 = document.createElement("h3");
                var a = document.createElement("a");
                a.href = "/event/" + data[i]._id;
                a.innerText = data[i].title;
                h3.appendChild(a);
                m.appendChild(h3);
                var p1 = document.createElement("p");
                p1.innerText = data[i].description;
                m.appendChild(p1);
                var p2 = document.createElement("p");

                //TODO:
                //Fix the dates so they are formatted correctly
                var sd  = new Date(data[i].start_date.$date);
                var ed = new Date(data[i].end_date.$date);
                p2.innerText = sd + " -- " + ed;
                m.appendChild(p2);

                var p3 = document.createElement("p");
                p3.innerText = data[i].location.address;
                m.appendChild(p3);
                map.mapElement.appendChild(m);
                map.markers.push(m);
                //m.marker.setMap(map.map);
            }
        }
				seperateMarkers();
      });

}

//function to check if and item exists in
//a list by checking a specific attribute
//used by filterBy()
function isIn(m, mAttr, l, lAttr) {
    for(var i = 0; i < l.length; i++) {
        if(l[i][lAttr].trim() == m[mAttr].trim()) {
            return l[i];
        }
    }
    return null;
}
<|endoftext|>