<commit_before>
$(function(){
	//abstraction wrapper around extension api, stolen from batarang :)
	var chromeExtension= {
		sendRequest: function (requestName, cb) {
			chrome.extension.sendRequest({
			script: requestName,
			tab: chrome.devtools.inspectedWindow.tabId
			}, cb || function () {});
		},

		eval: function (fn, args, cb) {
			// with two args
			if (!cb && typeof args === 'function') {
				cb = args;
				args = {};
			} else if (!args) {
				args = {};
			}
			chrome.devtools.inspectedWindow.eval('(' +
				fn.toString() +
				'(window, ' +
				JSON.stringify(args) +
				'));', cb);
		},
		watchRefresh: function (cb) {
			var port = chrome.extension.connect();
			port.postMessage({
				action: 'register',
				inspectedTabId: chrome.devtools.inspectedWindow.tabId
			});
			port.onMessage.addListener(function(msg) {
				if (msg === 'refresh' && cb) {
					cb();
				}
			});
			port.onDisconnect.addListener(function (a) {
				console.log(a);
			});
		}
	};
	var attachLoggingExtender=function(globalWindowObj){
		try{

			//require js support
			var ko = window.ko;
			if( !ko){
				if(typeof window.require === 'function') {
					try{
						ko = require('ko');
					} catch(e) { /*ingore */ }
					if(!ko){
						try{
							ko = require('knockout');
						} catch(e) { /*ingore */ }
					}
				}
				if(!ko) {
					return ;
				}
			}

			//create the extender in the context of the page
			ko.extenders.ChromeExtensionLogChange = function(target, option) {
				target.subscribe(function(newValue) {
					console.debug(option, newValue);
					console.markTimeline(option+" changed (ko)");
				});
				return target;
			};

			//crazy code that will loop all nodes an get all the knockout binded viewmodels on a page
			var viewModels=[];
			var items = document.getElementsByTagName("*");
			for (var i = 0; i < items.length; i++) {
				try{
					var theVm=ko.contextFor(items[i]).$data;
					var isAlreadyInArray=false;
					for(var j=0;j<viewModels.length;j++)
						if(viewModels[j]==theVm)
							isAlreadyInArray=true;
					if(!isAlreadyInArray)
						viewModels.push(theVm);
				}
				catch(toBeIgnoredExc){}
			}

			if(!viewModels.length){
				return;
			}
			//add extender to each observable/array/computed that will log changes
			for(var k=0;k<viewModels.length;k++){
				var tempVm=viewModels[k];
				for (var vmProperty in tempVm) {
					try{
						if (!tempVm.hasOwnProperty(vmProperty))
							continue;
						if(tempVm[vmProperty]===null || tempVm[vmProperty]===undefined)
							continue;
						if(!ko.isSubscribable(tempVm[vmProperty]))
							continue;
						tempVm[vmProperty].extend({ChromeExtensionLogChange: vmProperty});
					}
					catch(unableToExtendException){
						console.log("Unable to extend the viewmodel",vmProperty,tempVm);
					}
				}
			}
		}
		catch(err){
			console.error(err);
		}
	};

	var chromeExtensionEvalCallback=function(promise){
		//disable the button so you can only attach the extender once
		$("#enableTracing").text("Tracing enabled").attr("disabled","disabled");
	};

	$("#enableTracing").click(function(){
		chromeExtension.eval(attachLoggingExtender,true,chromeExtensionEvalCallback);
	});
	chromeExtension.watchRefresh(function(){
		$("#enableTracing").text("Enable Tracing").removeAttr("disabled");
	});

});<commit_msg>indent sub viewmodel changes<commit_after>
$(function(){
	//abstraction wrapper around extension api, stolen from batarang :)
	var chromeExtension= {
		sendRequest: function (requestName, cb) {
			chrome.extension.sendRequest({
			script: requestName,
			tab: chrome.devtools.inspectedWindow.tabId
			}, cb || function () {});
		},

		eval: function (fn, args, cb) {
			// with two args
			if (!cb && typeof args === 'function') {
				cb = args;
				args = {};
			} else if (!args) {
				args = {};
			}
			chrome.devtools.inspectedWindow.eval('(' +
				fn.toString() +
				'(window, ' +
				JSON.stringify(args) +
				'));', cb);
		},
		watchRefresh: function (cb) {
			var port = chrome.extension.connect();
			port.postMessage({
				action: 'register',
				inspectedTabId: chrome.devtools.inspectedWindow.tabId
			});
			port.onMessage.addListener(function(msg) {
				if (msg === 'refresh' && cb) {
					cb();
				}
			});
			port.onDisconnect.addListener(function (a) {
				console.log(a);
			});
		}
	};
	var attachLoggingExtender=function(globalWindowObj){
		try{

			//require js support
			var ko = window.ko;
			if( !ko){
				if(typeof window.require === 'function') {
					try{
						ko = require('ko');
					} catch(e) { /*ingore */ }
					if(!ko){
						try{
							ko = require('knockout');
						} catch(e) { /*ingore */ }
					}
				}
				if(!ko) {
					return ;
				}
			}

			//create the extender in the context of the page
			var chromeExtensionLogChangeFun=function(target, option) {
				var indent="   ";
				var total="";
				for(var i=0;i<option.nestingLevel;i++){
					total+=indent;
				}

				target.subscribe(function(newValue) {
					console.debug(total,option.propName, newValue);
					console.markTimeline(option.propName+" changed (ko)");
				});
				return target;
			};
			ko.extenders.ChromeExtensionLogChange = chromeExtensionLogChangeFun;

			//crazy code that will loop all nodes an get all the knockout binded viewmodels on a page
			var viewModels=[];
			var items = document.getElementsByTagName("*");
			for (var i = 0; i < items.length; i++) {
				try{
					var theContextFor=ko.contextFor(items[i]);
					var theVm=theContextFor.$data;
					var theNestingLevel=theContextFor.$parents.length;
					var isAlreadyInArray=false;
					for(var j=0;j<viewModels.length;j++)
						if(viewModels[j].viewmodel==theVm)
							isAlreadyInArray=true;
					if(!isAlreadyInArray)
						viewModels.push({viewmodel:theVm,level:theNestingLevel});
				}
				catch(toBeIgnoredExc){}
			}

			if(!viewModels.length){
				return;
			}
			//add extender to each observable/array/computed that will log changes
			for(var k=0;k<viewModels.length;k++){
				var tempVm=viewModels[k].viewmodel;
				var nestingLevel=viewModels[k].level;
				for (var vmProperty in tempVm) {
					try{
						if (!tempVm.hasOwnProperty(vmProperty))
							continue;
						if(tempVm[vmProperty]===null || tempVm[vmProperty]===undefined)
							continue;
						if(!ko.isSubscribable(tempVm[vmProperty]))
							continue;
						tempVm[vmProperty].extend({ChromeExtensionLogChange: {propName:vmProperty,nestingLevel:nestingLevel}});
					}
					catch(unableToExtendException){
						console.log("Unable to extend the viewmodel",vmProperty,tempVm);
					}
				}
			}
		}
		catch(err){
			console.error(err);
		}
	};

	var chromeExtensionEvalCallback=function(promise){
		//disable the button so you can only attach the extender once
		$("#enableTracing").text("Tracing enabled").attr("disabled","disabled");
	};

	$("#enableTracing").click(function(){
		chromeExtension.eval(attachLoggingExtender,true,chromeExtensionEvalCallback);
	});
	chromeExtension.watchRefresh(function(){
		$("#enableTracing").text("Enable Tracing").removeAttr("disabled");
	});

});<|endoftext|>


<commit_before>const flatten = require('flatten')
const Set     = require('es6-set')

function normalizeRoot(root) {
	if(!root) return document
	if(typeof(root) == 'string') return $(root)
	return root
}

function $(selector, root) {
	root = normalizeRoot(root)
	return wrapNode(root.querySelector(selector))
}

$.all = function $$(selector, root) {
	root = normalizeRoot(root)
	return [].slice.call(root.querySelectorAll(selector)).map(function(node) {
		return wrapNode(node)
	})
}

$.wrap = function(node) {
	if(Array.isArray(node)) {
		return [].slice.call(root.querySelectorAll(selector)).map(function(node) {
			return wrapNode(node)
		})
	} else {
		return wrapNode(node)
	}
}

function wrapNode(node) {
	node.find = function(sel) {
		return $(sel, node)
	}
	node.findAll = function(sel) {
		return $.all(sel, node)
	}
	return node
}

module.exports = $

window.$ = $<commit_msg>Fix $.wrap for nodelists<commit_after>const flatten = require('flatten')
const Set     = require('es6-set')

function normalizeRoot(root) {
	if(!root) return document
	if(typeof(root) == 'string') return $(root)
	return root
}

function $(selector, root) {
	root = normalizeRoot(root)
	return wrapNode(root.querySelector(selector))
}

$.all = function $$(selector, root) {
	root = normalizeRoot(root)
	return [].slice.call(root.querySelectorAll(selector)).map(function(node) {
		return wrapNode(node)
	})
}

$.wrap = function(node) {
	if(typeof(node.length) == 'number') {
		return [].slice.call(node).map(function(node) {
			return wrapNode(node)
		})
	} else {
		return wrapNode(node)
	}
}

function wrapNode(node) {
	node.find = function(sel) {
		return $(sel, node)
	}
	node.findAll = function(sel) {
		return $.all(sel, node)
	}
	return node
}

module.exports = $

window.$ = $<|endoftext|>


<commit_before>import 'accordion/src/accordion.js';

(function() {
    "use strict";

    document.querySelectorAll('.accordion').forEach(function(item) {
        let accordion = new Accordion(item, {
            onToggle: function(target){
                // Remove IDs from content folds so the browser doesn't jump around when opening an accordion item
                document.querySelectorAll('.accordion li a').forEach(function (item) {
                    item.removeAttribute('id');
                });

                // Only allow one accordion item open at time
                target.accordion.folds.forEach(fold => {
                    if(fold !== target) {
                        fold.open = false;
                        fold.el.firstElementChild.setAttribute('aria-expanded', 'false');
                    }
                });

                // Force the focus on the element they opened
                target.el.firstElementChild.focus();

                // Allow the content to be shown if its open or hide it when closed
                target.content.classList.toggle('hidden')

                // Set accessible state of expanded
                target.el.firstElementChild.setAttribute('aria-expanded', 'true');

                // Update the browsers hash so if the url is copied it will deep link properly
                window.location.hash = target.heading.hash.substr(1);
            },
            enabledClass: 'enabled',
            noAria: true,
            noTransforms: true
        });

        // Hide all accordion content from the start so content inside it isn't part of the tabindex
        item.querySelectorAll('.content').forEach(function(item) {
            item.classList.add('hidden');
        });

        // Apply accessibility attributes
        item.querySelectorAll('li a:first-child').forEach(function(item) {
            item.setAttribute('role', 'button');
            item.setAttribute('aria-expanded', 'false');
        });

        // See if the hash is within this accordion so we can open it
        if(window.location.hash != '') {
            accordion.folds.forEach(function (fold) {
                if(fold.heading.getAttribute('id') == window.location.hash.substr(1)) {
                    window.setTimeout(function () {
                        fold.open = true;
                    }, 500);
                }
            });
        }
    });

    // Apply the required content fold afterwards to simplify the html
    document.querySelectorAll('ul.accordion > li').forEach(function(item) {
        item.querySelector('div').classList.add('fold');
    });
})();
<commit_msg>adding +/- span to accordion button if it doesnt exist<commit_after>import 'accordion/src/accordion.js';

(function() {
    "use strict";

    document.querySelectorAll('.accordion').forEach(function(item) {
        let accordion = new Accordion(item, {
            onToggle: function(target){
                // Remove IDs from content folds so the browser doesn't jump around when opening an accordion item
                document.querySelectorAll('.accordion li a').forEach(function (item) {
                    item.removeAttribute('id');
                });

                // Only allow one accordion item open at time
                target.accordion.folds.forEach(fold => {
                    if(fold !== target) {
                        fold.open = false;
                        fold.el.firstElementChild.setAttribute('aria-expanded', 'false');
                    }
                });

                // Force the focus on the element they opened
                target.el.firstElementChild.focus();

                // Allow the content to be shown if its open or hide it when closed
                target.content.classList.toggle('hidden')

                // Set accessible state of expanded
                target.el.firstElementChild.setAttribute('aria-expanded', 'true');

                // Update the browsers hash so if the url is copied it will deep link properly
                window.location.hash = target.heading.hash.substr(1);
            },
            enabledClass: 'enabled',
            noAria: true,
            noTransforms: true
        });

        // Hide all accordion content from the start so content inside it isn't part of the tabindex
        item.querySelectorAll('.content').forEach(function(item) {
            item.classList.add('hidden');
        });

        // Apply accessibility attributes
        item.querySelectorAll('li a:first-child').forEach(function(item) {
            item.setAttribute('role', 'button');
            item.setAttribute('aria-expanded', 'false');

            // Adds +/- span if there isn't one already
            if (!item.querySelector('span')) {
                item.insertAdjacentHTML('afterbegin', `<span aria-hidden="true"></span>`);
            }
        });

        // See if the hash is within this accordion so we can open it
        if(window.location.hash != '') {
            accordion.folds.forEach(function (fold) {
                if(fold.heading.getAttribute('id') == window.location.hash.substr(1)) {
                    window.setTimeout(function () {
                        fold.open = true;
                    }, 500);
                }
            });
        }
    });

    // Apply the required content fold afterwards to simplify the html
    document.querySelectorAll('ul.accordion > li').forEach(function(item) {
        item.querySelector('div').classList.add('fold');
    });
})();
<|endoftext|>


<commit_before>'use strict'

const libob = require('libobject');
const Parser = require('./Parser');

module.exports = (scope, event_iri, session = {role: '*'}, callback) => {

    let event = scope.cache.get(event_iri);
    if (event) {
        return event.ready(callback);
    }

    event = libob.queue((error, handler, done) => {

        if (error) {
            scope.cache.del(event_iri);
            return done(error);
        }

        let type, handler_iri;
        for (handler_iri in event.seq) {
            handler = event.seq[handler_iri];
            type = typeof handler.D === 'string' ? 'D' : (typeof handler.S === 'string' ? 'S' : null);
            type && getMethodRef(event_iri, handler, type, handler.D || handler.S, done);
        }

        scope.cache.set(event_iri, {
            seq: event.seq,
            end: event.end,
            err: event.err,
            ready: fn => fn(null, event)
        });

        done(null, event);

    }, callback);

    event._c = 0;
    event.seq = {};
    event.get = handler_iri => event.seq[handler_iri] = event.seq[handler_iri] || {};
    event.set = (handler_iri, err, instance) => {

        if (err) {
            return event.done(err);
        }

        if (!instance) {
            return ++event._c;
        }

        !err && (event.get(handler_iri).I = instance);
        --event._c === 0 && event._p && event.done();
    };

    event.fin = () => {
        event._p = true;
        event._c === 0 && event.done();
    };

    scope.cache.set(event_iri, event);

    scope.read(event_iri, session).on('error', event.done).
    pipe(Parser(scope, event, session)).on('error', event.done);
};

function getMethodRef (event_iri, handler, type, method, done) {
    if (!(handler[type] = libob.path(method, handler.I))) {
        return done(new Error('Flow.event "' + event_iri + '": Method "' + method + '" on instance "' + handler.I._name + '" not found.'));
    }
}
<commit_msg>overwrite event loader with cache object<commit_after>'use strict'

const libob = require('libobject');
const Parser = require('./Parser');

module.exports = (scope, event_iri, session = {role: '*'}, callback) => {

    let event = scope.cache.get(event_iri);
    if (event) {
        return event.ready(callback);
    }

    event = libob.queue((error, handler, done) => {

        if (error) {
            scope.cache.del(event_iri);
            return done(error);
        }

        let type, handler_iri;
        for (handler_iri in event.seq) {
            handler = event.seq[handler_iri];
            type = typeof handler.D === 'string' ? 'D' : (typeof handler.S === 'string' ? 'S' : null);
            type && getMethodRef(event_iri, handler, type, handler.D || handler.S, done);
        }

        event = {
            seq: event.seq,
            end: event.end,
            err: event.err,
            ready: fn => fn(null, event)
        };

        scope.cache.set(event_iri, event);

        done(null, event);

    }, callback);

    event._c = 0;
    event.seq = {};
    event.get = handler_iri => event.seq[handler_iri] = event.seq[handler_iri] || {};
    event.set = (handler_iri, err, instance) => {

        if (err) {
            return event.done(err);
        }

        if (!instance) {
            return ++event._c;
        }

        !err && (event.get(handler_iri).I = instance);
        --event._c === 0 && event._p && event.done();
    };

    event.fin = () => {
        event._p = true;
        event._c === 0 && event.done();
    };

    scope.cache.set(event_iri, event);

    scope.read(event_iri, session).on('error', event.done).
    pipe(Parser(scope, event, session)).on('error', event.done);
};

function getMethodRef (event_iri, handler, type, method, done) {
    if (!(handler[type] = libob.path(method, handler.I))) {
        return done(new Error('Flow.event "' + event_iri + '": Method "' + method + '" on instance "' + handler.I._name + '" not found.'));
    }
}
<|endoftext|>


<commit_before>//Focus.reference.builder.loadListByName('papas').then(function(data){Focus.dispatcher.dispatch({action: {type: "update",data: {papas: data}}})})

const refStoreGetter = require('focus-core').reference.getStore;
const builtInActionReferenceLoader = require('focus-core').reference.builtInAction;
const isEmpty = require('lodash/lang/isEmpty');
const referenceMixin = {
    /** @inheritdoc */
    /*  getDefaultProps: function getReferenceDefaultProps(){
    return {*/
    /**
    * Array which contains all the reference lists.
    * If the referenceNames are set into the object, they are set into the default props.
    * @type {Array}
    */
    /*  referenceNames: this.referenceNames || []
    };
    },*/
    getInitialState(){
        return {reference: {}};
    },
    /**
    * Build actions associated to the reference.
    */
    _buildReferenceActions(){
        this.action = this.action || {};
        this.action.loadReference = builtInActionReferenceLoader(this.referenceNames);
    },
    _loadReference(){
        return this.action.loadReference();
    },
    /**
    * Build the reference names and set the store into the application.
    */
    _buildReferenceStoreConfig(){
        //Get the store for references.
        const referenceStore = refStoreGetter();

        //If the reference store is empty don't do anything.
        if(isEmpty(this.referenceNames)){
            return;
        }
        this.stores = this.stores || [];
        //Set as referencestore the referencestore of the application.
        this.stores.push({
            store: referenceStore,
            properties: this.referenceNames
        });
    },
    /**
    * Build store and actions related to the reference.
    */
    _buildReference(){
        this._buildReferenceStoreConfig();
        this._buildReferenceActions();
    },
    /** @inheritdoc */
    componentWillMount(){
        this.referenceNames = this.props.referenceNames || this.referenceNames;
        this._buildReference();
    }
};

module.exports = referenceMixin;
<commit_msg>[reference] Create a new object action in the form to avoid shared reference between forms. Fix #731 .<commit_after>//Focus.reference.builder.loadListByName('papas').then(function(data){Focus.dispatcher.dispatch({action: {type: "update",data: {papas: data}}})})

const refStoreGetter = require('focus-core').reference.getStore;
const builtInActionReferenceLoader = require('focus-core').reference.builtInAction;
const isEmpty = require('lodash/lang/isEmpty');
const referenceMixin = {
    /** @inheritdoc */
    /*  getDefaultProps: function getReferenceDefaultProps(){
    return {*/
    /**
    * Array which contains all the reference lists.
    * If the referenceNames are set into the object, they are set into the default props.
    * @type {Array}
    */
    /*  referenceNames: this.referenceNames || []
    };
    },*/
    getInitialState(){
        return {reference: {}};
    },
    /**
    * Build actions associated to the reference.
    */
    _buildReferenceActions(){
        this.action = {
            loadReference: builtInActionReferenceLoader(this.referenceNames),
            ...this.action
        };
    },
    _loadReference(){
        return this.action.loadReference();
    },
    /**
    * Build the reference names and set the store into the application.
    */
    _buildReferenceStoreConfig(){
        //Get the store for references.
        const referenceStore = refStoreGetter();

        //If the reference store is empty don't do anything.
        if(isEmpty(this.referenceNames)){
            return;
        }
        this.stores = this.stores || [];
        //Set as referencestore the referencestore of the application.
        this.stores.push({
            store: referenceStore,
            properties: this.referenceNames
        });
    },
    /**
    * Build store and actions related to the reference.
    */
    _buildReference(){
        this._buildReferenceStoreConfig();
        this._buildReferenceActions();
    },
    /** @inheritdoc */
    componentWillMount(){
        this.referenceNames = this.props.referenceNames || this.referenceNames;
        this._buildReference();
    }
};

module.exports = referenceMixin;
<|endoftext|>


<commit_before>import React from 'react'
import { StyleSheet, TouchableOpacity, View, Platform } from 'react-native'
import Text from '../text/Text'
import fonts from '../config/fonts'
import colors from '../config/colors'
import FAIcon from 'react-native-vector-icons/FontAwesome'
import getIconType from '../helpers/getIconType'

let styles = {}

const CheckBox = ({component, checked, iconRight, title, center, right, containerStyle, textStyle, onPress, onLongPress, onIconPress, onLongIconPress, checkedIcon, uncheckedIcon, iconType, checkedColor, uncheckedColor, checkedTitle, fontFamily}) => {
  let Icon = FAIcon
  if (iconType) {
    Icon = getIconType(iconType)
  }
  const Component = component || TouchableOpacity
  let iconName = uncheckedIcon
  if (checked) {
    iconName = checkedIcon
  }
  return (
    <Component
      onLongPress={onLongPress}
      onPress={onPress}
      style={[
        styles.container,
        containerStyle && containerStyle
      ]}>
      <View style={[
        styles.wrapper,
      ]}>
        {
          !iconRight && (
            <Icon
              color={checked ? checkedColor : uncheckedColor}
              name={iconName}
              size={24}
              onLongPress={onLongIconPress}
              onPress={onIconPress} />
          )
        }
        <Text style={[
          styles.text,
          textStyle && textStyle,
          fontFamily && {fontFamily}
        ]}>
          {checked ? checkedTitle || title : title}
        </Text>
        {
          iconRight && (
            <Icon
              color={checked ? checkedColor : uncheckedColor}
              name={iconName}
              size={24} />
          )
        }
      </View>
    </Component>
  )
}

CheckBox.defaultProps = {
  checked: false,
  iconRight: false,
  right: false,
  center: false,
  checkedColor: 'green',
  uncheckedColor: '#bfbfbf',
  checkedIcon: 'check-square-o',
  uncheckedIcon: 'square-o'
}

// CheckBox.propTypes = {
//   component, checked, iconRight, title, center, containerStyle, textStyle, onPress, checkedIcon, uncheckedIcon, iconType, checkedColor, uncheckedColor, checkedTitle
// }

styles = StyleSheet.create({
  wrapper: {
    flexDirection: 'row',
    alignItems: 'center'
  },
  text: {
    marginLeft: 10,
    marginRight: 10,
    color: colors.grey1,
    ...Platform.select({
      ios: {
        fontWeight: 'bold'
      },
      android: {
        fontFamily: fonts.android.bold
      }
    })
  }
})

export default CheckBox
<commit_msg>update Checkbox.js<commit_after>import React from 'react'
import { StyleSheet, TouchableOpacity, View, Platform } from 'react-native'
import Text from '../text/Text'
import fonts from '../config/fonts'
import colors from '../config/colors'
import FAIcon from 'react-native-vector-icons/FontAwesome'
import getIconType from '../helpers/getIconType'

let styles = {}

const CheckBox = ({component, checked, iconRight, title, center, right, containerStyle, textStyle, onPress, onLongPress, onIconPress, onLongIconPress, checkedIcon, uncheckedIcon, iconType, checkedColor, uncheckedColor, checkedTitle, fontFamily}) => {
  let Icon = FAIcon
  if (iconType) {
    Icon = getIconType(iconType)
  }
  const Component = component || TouchableOpacity
  let iconName = uncheckedIcon
  if (checked) {
    iconName = checkedIcon
  }
  return (
    <Component
      onLongPress={onLongPress}
      onPress={onPress}
      style={[
        styles.container,
        containerStyle && containerStyle
      ]}>
      <View style={[
        styles.wrapper,
      ]}>
        {
          !iconRight && (
            <Icon
              color={checked ? checkedColor : uncheckedColor}
              name={iconName}
              size={24}
              onLongPress={onLongIconPress}
              onPress={onIconPress} />
          )
        }
        <Text style={[
          styles.text,
          textStyle && textStyle,
          fontFamily && {fontFamily}
        ]}>
          {checked ? checkedTitle || title : title}
        </Text>
        {
          iconRight && (
            <Icon
              color={checked ? checkedColor : uncheckedColor}
              name={iconName}
              size={24} />
          )
        }
      </View>
    </Component>
  )
}

CheckBox.defaultProps = {
  checked: false,
  iconRight: false,
  right: false,
  center: false,
  checkedColor: 'green',
  uncheckedColor: '#bfbfbf',
  checkedIcon: 'check-square-o',
  uncheckedIcon: 'square-o'
}

// CheckBox.propTypes = {
//   component, checked, iconRight, title, center, containerStyle, textStyle, onPress, checkedIcon, uncheckedIcon, iconType, checkedColor, uncheckedColor, checkedTitle
// }

styles = StyleSheet.create({
  wrapper: {
    flexDirection: 'row',
    alignItems: 'center'
  },
  container: {
    margin: 5,
    marginLeft: 10,
    marginRight: 10,
    backgroundColor: '#fafafa',
    borderColor: '#ededed',
    borderWidth: 1,
    padding: 10,
    borderRadius: 3
  },
  text: {
    marginLeft: 10,
    marginRight: 10,
    color: colors.grey1,
    ...Platform.select({
      ios: {
        fontWeight: 'bold'
      },
      android: {
        fontFamily: fonts.android.bold
      }
    })
  }
})

export default CheckBox
<|endoftext|>


<commit_before>'use strict'

const Logger = require('./util/logger')
const logger = Logger.global.chain('[jirascope]')

/**
 * Provides an understanding of jira issues and their network.
 *
 * @param {Object} jiraClient - The client to use to talk to JIRA
 * @param {Object?} dataStore - The data store to use
 * @param {Object} options - Options to customise behaviour
 * @param {string} options.query - The initial query to use
 * @param {string[]} options.followStatusCategories - An array of status categories to follow
 * @param {string[]} options.followLinkTypes - An array of link types to follow
 *
 * @property {Object} issues - issues keyed by key
 */
class Jirascope {
  constructor (jiraClient, dataStore, options) {
    this.jiraClient = jiraClient
    this.dataStore = dataStore
    this.options = options
    this.issues = {}
    this.orphans = []
    this.graphs = []
  }

  async populate () {
    if (this.dataStore) {
      this.issues = await this.dataStore.readData('issues')
    }
    if (!this.issues) {
      await this.fetch()
    }
    this.analyse()
  }

  async fetch () {
    const issues = {}
    logger.info(`fetching initial issues`)
    let newIssues = await this.jiraClient.getIssuesByQuery(this.options.query, 1000)

    while (newIssues.length > 0) {
      newIssues.forEach((newIssue) => {
        issues[newIssue.key] = newIssue
        logger.trace(`${newIssue.key} found`)
      })

      let missingIssues = {}
      logger.info(`reviewing issue links`)
      newIssues.forEach((newIssue) => {
        newIssue.links = newIssue.links.filter((link) => { return this.options.followLinkTypes.includes(link.type) })
        if (newIssue.links.length === 0) {
          logger.trace(`${newIssue.key} - no links`)
        } else if (!this.options.followStatusCategories.includes(newIssue.statusCategory)) {
          logger.trace(`${newIssue.key} - skipping due to status category of '${newIssue.statusCategory}'`)
        } else {
          logger.trace(`${newIssue.key} - evaluating links`)
          newIssue.links.forEach((link) => {
            if (!issues[link.dstKey]) {
              missingIssues[link.dstKey] = link.dstKey
              logger.trace(`${link.srcKey} ${link.label} ${link.dstKey} - ${link.dstKey} not yet fetched`)
            } else {
              logger.trace(`${link.srcKey} ${link.label} ${link.dstKey} - ${link.dstKey} already fetched`)
            }
          })
        }
      })
      let lookups = Object.keys(missingIssues)
      if (lookups.length > 0) {
        logger.info(`fetching linked issues`)
        newIssues = await this.jiraClient.getIssuesByKey(lookups)
      } else {
        newIssues = []
      }
    }
    this.issues = issues
  }

  analyse () {
    const orphans = []
    const graphs = []
    const roots = []
    const leaves = []
    const issues = Object.assign({}, this.issues)
    while (Object.keys(issues).length !== 0) {
      Logger.global.trace(`issues left to consider: ${Object.keys(issues).length}`)
      const stack = Object.keys(issues).splice(0, 1) // seed the stack
      if (stack.length !== 0) {
        const graph = {
          nodes: [],
          edges: []
        }
        Logger.global.trace(`starting a new graph with ${stack}`)
        while (stack.length !== 0) {
          const key = stack.pop()
          Logger.global.trace(`considering ${key}, remaining stack is ${stack}`)
          const issue = issues[key]
          if (issue) {
            graph.nodes.push(issue)
            delete issues[key]
            issue.root = true
            issue.leaf = true
            issue.links.forEach((link) => {
              if (this.issues[link.srcKey] && this.issues[link.dstKey]) { // only include edges that we have issues for
                if (link.direction === 'inward') {
                  issue.leaf = false
                  graph.edges.push(link)
                  stack.unshift(link.dstKey)
                }
                if (link.direction === 'outward') {
                  issue.root = false
                }
              }
            })
            if (issue.root) {
              roots.push(issue)
            }
            if (issue.leaf) {
              leaves.push(issue)
            }
          }
        }
        if (graph.nodes.length === 1) {
          orphans.push(graph.nodes[0])
        } else {
          graphs.push(graph)
        }
      }
    }
    this.orphans = orphans
    this.graphs = graphs
    this.roots = roots
    this.leaves = leaves
  }

  async store () {
    if (this.dataStore) {
      await this.dataStore.writeData('issues', this.issues)
      await this.dataStore.writeData('orphans', this.orphans)
      await this.dataStore.writeData('graphs', this.graphs)
      await this.dataStore.writeData('roots', this.roots)
      await this.dataStore.writeData('leaves', this.leaves)
    }
  }

  async cleanup () {
    this.issues = {}
    if (this.dataStore) {
      await this.dataStore.deleteData('issues')
    }
  }
}

exports = module.exports = Jirascope
<commit_msg>only store keys for roots, leaves and orphans detection<commit_after>'use strict'

const Logger = require('./util/logger')
const logger = Logger.global.chain('[jirascope]')

/**
 * Provides an understanding of jira issues and their network.
 *
 * @param {Object} jiraClient - The client to use to talk to JIRA
 * @param {Object?} dataStore - The data store to use
 * @param {Object} options - Options to customise behaviour
 * @param {string} options.query - The initial query to use
 * @param {string[]} options.followStatusCategories - An array of status categories to follow
 * @param {string[]} options.followLinkTypes - An array of link types to follow
 *
 * @property {Object} issues - issues keyed by key
 */
class Jirascope {
  constructor (jiraClient, dataStore, options) {
    this.jiraClient = jiraClient
    this.dataStore = dataStore
    this.options = options
    this.issues = {}
    this.orphans = []
    this.graphs = []
  }

  async populate () {
    if (this.dataStore) {
      this.issues = await this.dataStore.readData('issues')
    }
    if (!this.issues) {
      await this.fetch()
    }
    this.analyse()
  }

  async fetch () {
    const issues = {}
    logger.info(`fetching initial issues`)
    let newIssues = await this.jiraClient.getIssuesByQuery(this.options.query, 1000)

    while (newIssues.length > 0) {
      newIssues.forEach((newIssue) => {
        issues[newIssue.key] = newIssue
        logger.trace(`${newIssue.key} found`)
      })

      let missingIssues = {}
      logger.info(`reviewing issue links`)
      newIssues.forEach((newIssue) => {
        newIssue.links = newIssue.links.filter((link) => { return this.options.followLinkTypes.includes(link.type) })
        if (newIssue.links.length === 0) {
          logger.trace(`${newIssue.key} - no links`)
        } else if (!this.options.followStatusCategories.includes(newIssue.statusCategory)) {
          logger.trace(`${newIssue.key} - skipping due to status category of '${newIssue.statusCategory}'`)
        } else {
          logger.trace(`${newIssue.key} - evaluating links`)
          newIssue.links.forEach((link) => {
            if (!issues[link.dstKey]) {
              missingIssues[link.dstKey] = link.dstKey
              logger.trace(`${link.srcKey} ${link.label} ${link.dstKey} - ${link.dstKey} not yet fetched`)
            } else {
              logger.trace(`${link.srcKey} ${link.label} ${link.dstKey} - ${link.dstKey} already fetched`)
            }
          })
        }
      })
      let lookups = Object.keys(missingIssues)
      if (lookups.length > 0) {
        logger.info(`fetching linked issues`)
        newIssues = await this.jiraClient.getIssuesByKey(lookups)
      } else {
        newIssues = []
      }
    }
    this.issues = issues
  }

  analyse () {
    const orphans = []
    const graphs = []
    const roots = []
    const leaves = []
    const issues = Object.assign({}, this.issues)
    while (Object.keys(issues).length !== 0) {
      Logger.global.trace(`issues left to consider: ${Object.keys(issues).length}`)
      const stack = Object.keys(issues).splice(0, 1) // seed the stack
      if (stack.length !== 0) {
        const graph = {
          nodes: [],
          edges: []
        }
        Logger.global.trace(`starting a new graph with ${stack}`)
        while (stack.length !== 0) {
          const key = stack.pop()
          Logger.global.trace(`considering ${key}, remaining stack is ${stack}`)
          const issue = issues[key]
          if (issue) {
            graph.nodes.push(issue)
            delete issues[key]
            issue.root = true
            issue.leaf = true
            issue.links.forEach((link) => {
              if (this.issues[link.srcKey] && this.issues[link.dstKey]) { // only include edges that we have issues for
                if (link.direction === 'inward') {
                  issue.leaf = false
                  graph.edges.push(link)
                  stack.unshift(link.dstKey)
                }
                if (link.direction === 'outward') {
                  issue.root = false
                }
              }
            })
            if (issue.root) {
              roots.push(issue.key)
            }
            if (issue.leaf) {
              leaves.push(issue.key)
            }
          }
        }
        if (graph.nodes.length === 1) {
          orphans.push(graph.nodes[0].key)
        } else {
          graphs.push(graph)
        }
      }
    }
    this.orphans = orphans
    this.graphs = graphs
    this.roots = roots
    this.leaves = leaves
  }

  async store () {
    if (this.dataStore) {
      await this.dataStore.writeData('issues', this.issues)
      await this.dataStore.writeData('orphans', this.orphans)
      await this.dataStore.writeData('graphs', this.graphs)
      await this.dataStore.writeData('roots', this.roots)
      await this.dataStore.writeData('leaves', this.leaves)
    }
  }

  async cleanup () {
    this.issues = {}
    if (this.dataStore) {
      await this.dataStore.deleteData('issues')
    }
  }
}

exports = module.exports = Jirascope
<|endoftext|>


<commit_before>import React from 'react';
import classNames from 'classnames';
import { connect } from 'react-redux';
import { find, get, union, sortBy, groupBy, concat, debounce } from 'lodash';

import { NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT } from '../../constants/limits';
import { TABLE_ROW_FOCUS_DEBOUNCE_INTERVAL } from '../../constants/timer';

import ShowMore from '../show-more';
import NodeDetailsTableRow from './node-details-table-row';
import NodeDetailsTableHeaders from './node-details-table-headers';
import { ipToPaddedString } from '../../utils/string-utils';
import { moveElement, insertElement } from '../../utils/array-utils';
import { getSerializedTimeTravelTimestamp } from '../../utils/web-api-utils';
import {
  isIP, isNumber, defaultSortDesc, getTableColumnsStyles
} from '../../utils/node-details-utils';

function getDefaultSortedBy(columns, nodes) {
  // default sorter specified by columns
  const defaultSortColumn = find(columns, {defaultSort: true});
  if (defaultSortColumn) {
    return defaultSortColumn.id;
  }
  // otherwise choose first metric
  const firstNodeWithMetrics = find(nodes, n => get(n, ['metrics', 0]));
  if (firstNodeWithMetrics) {
    return get(firstNodeWithMetrics, ['metrics', 0, 'id']);
  }

  return 'label';
}

function maybeToLower(value) {
  if (!value || !value.toLowerCase) {
    return value;
  }
  return value.toLowerCase();
}

function getNodeValue(node, header) {
  const fieldId = header && header.id;
  if (fieldId !== null) {
    let field = union(node.metrics, node.metadata).find(f => f.id === fieldId);

    if (field) {
      if (isIP(header)) {
        // Format the IPs so that they are sorted numerically.
        return ipToPaddedString(field.value);
      } else if (isNumber(header)) {
        return parseFloat(field.value);
      }
      return field.value;
    }

    if (node.parents) {
      field = node.parents.find(f => f.topologyId === fieldId);
      if (field) {
        return field.label;
      }
    }

    if (node[fieldId] !== undefined && node[fieldId] !== null) {
      return node[fieldId];
    }
  }

  return null;
}

function getValueForSortedBy(sortedByHeader) {
  return node => maybeToLower(getNodeValue(node, sortedByHeader));
}

function getMetaDataSorters(nodes) {
  // returns an array of sorters that will take a node
  return get(nodes, [0, 'metadata'], []).map((field, index) => (node) => {
    const nodeMetadataField = node.metadata && node.metadata[index];
    if (nodeMetadataField) {
      if (isNumber(nodeMetadataField)) {
        return parseFloat(nodeMetadataField.value);
      }
      return nodeMetadataField.value;
    }
    return null;
  });
}

function sortNodes(nodes, getValue, sortedDesc) {
  const sortedNodes = sortBy(
    nodes,
    getValue,
    getMetaDataSorters(nodes)
  );
  if (sortedDesc) {
    sortedNodes.reverse();
  }
  return sortedNodes;
}

function getSortedNodes(nodes, sortedByHeader, sortedDesc) {
  const getValue = getValueForSortedBy(sortedByHeader);
  const withAndWithoutValues = groupBy(nodes, (n) => {
    const v = getValue(n);
    return v !== null && v !== undefined ? 'withValues' : 'withoutValues';
  });
  const withValues = sortNodes(withAndWithoutValues.withValues, getValue, sortedDesc);
  const withoutValues = sortNodes(withAndWithoutValues.withoutValues, getValue, sortedDesc);

  return concat(withValues, withoutValues);
}

// By inserting this fake invisible row into the table, with the help of
// some CSS trickery, we make the inner scrollable content of the table
// have a minimal height. That prevents auto-scroll under a focus if the
// number of table rows shrinks.
function minHeightConstraint(height = 0) {
  return
;
}

class NodeDetailsTable extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      limit: props.limit || NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT,
      sortedDesc: this.props.sortedDesc,
      sortedBy: this.props.sortedBy
    };
    this.focusState = {};

    this.updateSorted = this.updateSorted.bind(this);
    this.handleLimitClick = this.handleLimitClick.bind(this);
    this.onMouseLeaveRow = this.onMouseLeaveRow.bind(this);
    this.onMouseEnterRow = this.onMouseEnterRow.bind(this);
    this.saveTableContentRef = this.saveTableContentRef.bind(this);
    // Use debouncing to prevent event flooding when e.g. crossing fast with mouse cursor
    // over the whole table. That would be expensive as each focus causes table to rerender.
    this.debouncedFocusRow = debounce(this.focusRow, TABLE_ROW_FOCUS_DEBOUNCE_INTERVAL);
    this.debouncedBlurRow = debounce(this.blurRow, TABLE_ROW_FOCUS_DEBOUNCE_INTERVAL);
  }

  updateSorted(sortedBy, sortedDesc) {
    this.setState({ sortedBy, sortedDesc });
    this.props.onSortChange(sortedBy, sortedDesc);
  }

  handleLimitClick() {
    const limit = this.state.limit ? 0 : NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT;
    this.setState({ limit });
  }

  focusRow(rowIndex, node) {
    // Remember the focused row index, the node that was focused and
    // the table content height so that we can keep the node row fixed
    // without auto-scrolling happening.
    // NOTE: It would be ideal to modify the real component state here,
    // but that would cause whole table to rerender, which becomes to
    // expensive with the current implementation if the table consists
    // of 1000+ nodes.
    this.focusState = {
      focusedNode: node,
      focusedRowIndex: rowIndex,
      tableContentMinHeightConstraint: this.tableContent.scrollHeight,
    };
  }

  blurRow() {
    // Reset the focus state
    this.focusState = {};
  }

  onMouseEnterRow(rowIndex, node) {
    this.debouncedBlurRow.cancel();
    this.debouncedFocusRow(rowIndex, node);
  }

  onMouseLeaveRow() {
    this.debouncedFocusRow.cancel();
    this.debouncedBlurRow();
  }

  saveTableContentRef(ref) {
    this.tableContent = ref;
  }

  getColumnHeaders() {
    const columns = this.props.columns || [];
    return [{id: 'label', label: this.props.label}].concat(columns);
  }

  render() {
    const { nodeIdKey, columns, topologyId, onClickRow,
      onMouseEnter, onMouseLeave, timestamp } = this.props;

    const sortedBy = this.state.sortedBy || getDefaultSortedBy(columns, this.props.nodes);
    const sortedByHeader = this.getColumnHeaders().find(h => h.id === sortedBy);
    const sortedDesc = (this.state.sortedDesc === null) ?
      defaultSortDesc(sortedByHeader) : this.state.sortedDesc;

    let nodes = getSortedNodes(this.props.nodes, sortedByHeader, sortedDesc);

    const { focusedNode, focusedRowIndex, tableContentMinHeightConstraint } = this.focusState;
    if (Number.isInteger(focusedRowIndex) && focusedRowIndex < nodes.length) {
      const nodeRowIndex = nodes.findIndex(node => node.id === focusedNode.id);
      if (nodeRowIndex >= 0) {
        // If the focused node still exists in the table, we move it
        // to the hovered row, keeping the rest of the table sorted.
        nodes = moveElement(nodes, nodeRowIndex, focusedRowIndex);
      } else {
        // Otherwise we insert the dead focused node there, pretending
        // it's still alive. That enables the users to read off all the
        // info they want and perhaps even open the details panel. Also,
        // only if we do this, we can guarantee that mouse hover will
        // always freeze the table row until we focus out.
        nodes = insertElement(nodes, focusedRowIndex, focusedNode);
      }
    }

    const limited = nodes && this.state.limit > 0 && nodes.length > this.state.limit;
    const expanded = this.state.limit === 0;
    const notShown = nodes.length - this.state.limit;
    if (nodes && limited) {
      nodes = nodes.slice(0, this.state.limit);
    }

    const className = classNames('node-details-table-wrapper-wrapper', this.props.className);
    const headers = this.getColumnHeaders();
    const styles = getTableColumnsStyles(headers);

    return (

              {this.props.nodes && this.props.nodes.length > 0 && <NodeDetailsTableHeaders
                headers={headers}
                sortedBy={sortedBy}
                sortedDesc={sortedDesc}
                onClick={this.updateSorted}
              />}

              {nodes && nodes.map((node, index) => (
                <NodeDetailsTableRow
                  key={node.id}
                  renderIdCell={this.props.renderIdCell}
                  selected={this.props.selectedNodeId === node.id}
                  node={node}
                  index={index}
                  nodeIdKey={nodeIdKey}
                  colStyles={styles}
                  columns={columns}
                  onClick={onClickRow}
                  onMouseEnter={this.onMouseEnterRow}
                  onMouseLeave={this.onMouseLeaveRow}
                  timestamp={timestamp}
                  topologyId={topologyId} />
              ))}
              {minHeightConstraint(tableContentMinHeightConstraint)}

          <ShowMore
            handleClick={this.handleLimitClick}
            collection={nodes}
            expanded={expanded}
            notShown={notShown} />

    );
  }
}

NodeDetailsTable.defaultProps = {
  nodeIdKey: 'id',  // key to identify a node in a row (used for topology links)
  onSortChange: () => {},
  sortedDesc: null,
  sortedBy: null,
};

function mapStateToProps(state) {
  return {
    timestamp: getSerializedTimeTravelTimestamp(state),
  };
}

export default connect(mapStateToProps)(NodeDetailsTable);
<commit_msg>Show table overflow only if limit exceeded by 2+<commit_after>import React from 'react';
import classNames from 'classnames';
import { connect } from 'react-redux';
import { find, get, union, sortBy, groupBy, concat, debounce } from 'lodash';

import { NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT } from '../../constants/limits';
import { TABLE_ROW_FOCUS_DEBOUNCE_INTERVAL } from '../../constants/timer';

import ShowMore from '../show-more';
import NodeDetailsTableRow from './node-details-table-row';
import NodeDetailsTableHeaders from './node-details-table-headers';
import { ipToPaddedString } from '../../utils/string-utils';
import { moveElement, insertElement } from '../../utils/array-utils';
import { getSerializedTimeTravelTimestamp } from '../../utils/web-api-utils';
import {
  isIP, isNumber, defaultSortDesc, getTableColumnsStyles
} from '../../utils/node-details-utils';

function getDefaultSortedBy(columns, nodes) {
  // default sorter specified by columns
  const defaultSortColumn = find(columns, {defaultSort: true});
  if (defaultSortColumn) {
    return defaultSortColumn.id;
  }
  // otherwise choose first metric
  const firstNodeWithMetrics = find(nodes, n => get(n, ['metrics', 0]));
  if (firstNodeWithMetrics) {
    return get(firstNodeWithMetrics, ['metrics', 0, 'id']);
  }

  return 'label';
}

function maybeToLower(value) {
  if (!value || !value.toLowerCase) {
    return value;
  }
  return value.toLowerCase();
}

function getNodeValue(node, header) {
  const fieldId = header && header.id;
  if (fieldId !== null) {
    let field = union(node.metrics, node.metadata).find(f => f.id === fieldId);

    if (field) {
      if (isIP(header)) {
        // Format the IPs so that they are sorted numerically.
        return ipToPaddedString(field.value);
      } else if (isNumber(header)) {
        return parseFloat(field.value);
      }
      return field.value;
    }

    if (node.parents) {
      field = node.parents.find(f => f.topologyId === fieldId);
      if (field) {
        return field.label;
      }
    }

    if (node[fieldId] !== undefined && node[fieldId] !== null) {
      return node[fieldId];
    }
  }

  return null;
}

function getValueForSortedBy(sortedByHeader) {
  return node => maybeToLower(getNodeValue(node, sortedByHeader));
}

function getMetaDataSorters(nodes) {
  // returns an array of sorters that will take a node
  return get(nodes, [0, 'metadata'], []).map((field, index) => (node) => {
    const nodeMetadataField = node.metadata && node.metadata[index];
    if (nodeMetadataField) {
      if (isNumber(nodeMetadataField)) {
        return parseFloat(nodeMetadataField.value);
      }
      return nodeMetadataField.value;
    }
    return null;
  });
}

function sortNodes(nodes, getValue, sortedDesc) {
  const sortedNodes = sortBy(
    nodes,
    getValue,
    getMetaDataSorters(nodes)
  );
  if (sortedDesc) {
    sortedNodes.reverse();
  }
  return sortedNodes;
}

function getSortedNodes(nodes, sortedByHeader, sortedDesc) {
  const getValue = getValueForSortedBy(sortedByHeader);
  const withAndWithoutValues = groupBy(nodes, (n) => {
    const v = getValue(n);
    return v !== null && v !== undefined ? 'withValues' : 'withoutValues';
  });
  const withValues = sortNodes(withAndWithoutValues.withValues, getValue, sortedDesc);
  const withoutValues = sortNodes(withAndWithoutValues.withoutValues, getValue, sortedDesc);

  return concat(withValues, withoutValues);
}

// By inserting this fake invisible row into the table, with the help of
// some CSS trickery, we make the inner scrollable content of the table
// have a minimal height. That prevents auto-scroll under a focus if the
// number of table rows shrinks.
function minHeightConstraint(height = 0) {
  return
;
}

class NodeDetailsTable extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      limit: props.limit,
      sortedDesc: this.props.sortedDesc,
      sortedBy: this.props.sortedBy
    };
    this.focusState = {};

    this.updateSorted = this.updateSorted.bind(this);
    this.handleLimitClick = this.handleLimitClick.bind(this);
    this.onMouseLeaveRow = this.onMouseLeaveRow.bind(this);
    this.onMouseEnterRow = this.onMouseEnterRow.bind(this);
    this.saveTableContentRef = this.saveTableContentRef.bind(this);
    // Use debouncing to prevent event flooding when e.g. crossing fast with mouse cursor
    // over the whole table. That would be expensive as each focus causes table to rerender.
    this.debouncedFocusRow = debounce(this.focusRow, TABLE_ROW_FOCUS_DEBOUNCE_INTERVAL);
    this.debouncedBlurRow = debounce(this.blurRow, TABLE_ROW_FOCUS_DEBOUNCE_INTERVAL);
  }

  updateSorted(sortedBy, sortedDesc) {
    this.setState({ sortedBy, sortedDesc });
    this.props.onSortChange(sortedBy, sortedDesc);
  }

  handleLimitClick() {
    const limit = this.state.limit ? 0 : this.props.limit;
    this.setState({ limit });
  }

  focusRow(rowIndex, node) {
    // Remember the focused row index, the node that was focused and
    // the table content height so that we can keep the node row fixed
    // without auto-scrolling happening.
    // NOTE: It would be ideal to modify the real component state here,
    // but that would cause whole table to rerender, which becomes to
    // expensive with the current implementation if the table consists
    // of 1000+ nodes.
    this.focusState = {
      focusedNode: node,
      focusedRowIndex: rowIndex,
      tableContentMinHeightConstraint: this.tableContent.scrollHeight,
    };
  }

  blurRow() {
    // Reset the focus state
    this.focusState = {};
  }

  onMouseEnterRow(rowIndex, node) {
    this.debouncedBlurRow.cancel();
    this.debouncedFocusRow(rowIndex, node);
  }

  onMouseLeaveRow() {
    this.debouncedFocusRow.cancel();
    this.debouncedBlurRow();
  }

  saveTableContentRef(ref) {
    this.tableContent = ref;
  }

  getColumnHeaders() {
    const columns = this.props.columns || [];
    return [{id: 'label', label: this.props.label}].concat(columns);
  }

  render() {
    const { nodeIdKey, columns, topologyId, onClickRow,
      onMouseEnter, onMouseLeave, timestamp } = this.props;

    const sortedBy = this.state.sortedBy || getDefaultSortedBy(columns, this.props.nodes);
    const sortedByHeader = this.getColumnHeaders().find(h => h.id === sortedBy);
    const sortedDesc = (this.state.sortedDesc === null) ?
      defaultSortDesc(sortedByHeader) : this.state.sortedDesc;

    let nodes = getSortedNodes(this.props.nodes, sortedByHeader, sortedDesc);

    const { focusedNode, focusedRowIndex, tableContentMinHeightConstraint } = this.focusState;
    if (Number.isInteger(focusedRowIndex) && focusedRowIndex < nodes.length) {
      const nodeRowIndex = nodes.findIndex(node => node.id === focusedNode.id);
      if (nodeRowIndex >= 0) {
        // If the focused node still exists in the table, we move it
        // to the hovered row, keeping the rest of the table sorted.
        nodes = moveElement(nodes, nodeRowIndex, focusedRowIndex);
      } else {
        // Otherwise we insert the dead focused node there, pretending
        // it's still alive. That enables the users to read off all the
        // info they want and perhaps even open the details panel. Also,
        // only if we do this, we can guarantee that mouse hover will
        // always freeze the table row until we focus out.
        nodes = insertElement(nodes, focusedRowIndex, focusedNode);
      }
    }

    // If we are 1 over the limit, we still show the row. We never display
    // "+1" but only "+2" and up.
    const limit = this.state.limit > 0 && nodes.length === this.state.limit + 1
      ? nodes.length
      : this.state.limit;
    const limited = nodes && limit > 0 && nodes.length > limit;
    const expanded = limit === 0;
    const notShown = nodes.length - limit;
    if (nodes && limited) {
      nodes = nodes.slice(0, limit);
    }

    const className = classNames('node-details-table-wrapper-wrapper', this.props.className);
    const headers = this.getColumnHeaders();
    const styles = getTableColumnsStyles(headers);

    return (

              {this.props.nodes && this.props.nodes.length > 0 && <NodeDetailsTableHeaders
                headers={headers}
                sortedBy={sortedBy}
                sortedDesc={sortedDesc}
                onClick={this.updateSorted}
              />}

              {nodes && nodes.map((node, index) => (
                <NodeDetailsTableRow
                  key={node.id}
                  renderIdCell={this.props.renderIdCell}
                  selected={this.props.selectedNodeId === node.id}
                  node={node}
                  index={index}
                  nodeIdKey={nodeIdKey}
                  colStyles={styles}
                  columns={columns}
                  onClick={onClickRow}
                  onMouseEnter={this.onMouseEnterRow}
                  onMouseLeave={this.onMouseLeaveRow}
                  timestamp={timestamp}
                  topologyId={topologyId} />
              ))}
              {minHeightConstraint(tableContentMinHeightConstraint)}

          <ShowMore
            handleClick={this.handleLimitClick}
            collection={nodes}
            expanded={expanded}
            notShown={notShown} />

    );
  }
}

NodeDetailsTable.defaultProps = {
  nodeIdKey: 'id',  // key to identify a node in a row (used for topology links)
  limit: NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT,
  onSortChange: () => {},
  sortedDesc: null,
  sortedBy: null,
};

function mapStateToProps(state) {
  return {
    timestamp: getSerializedTimeTravelTimestamp(state),
  };
}

export default connect(mapStateToProps)(NodeDetailsTable);
<|endoftext|>


<commit_before>map_style = [
    {
        "featureType": "water",
        "stylers": [
            {
                "visibility": "on"
            },
            {
                "color": "#acbcc9"
            }
        ]
    },
    {
        "featureType": "landscape",
        "stylers": [
            {
                "color": "#f2e5d4"
            }
        ]
    },
    {
        "featureType": "road.highway",
        "elementType": "geometry",
        "stylers": [
            {
                "color": "#c5c6c6"
            }
        ]
    },
    {
        "featureType": "road.arterial",
        "elementType": "geometry",
        "stylers": [
            {
                "color": "#e4d7c6"
            }
        ]
    },
    {
        "featureType": "road.local",
        "elementType": "geometry",
        "stylers": [
            {
                "color": "#fbfaf7"
            }
        ]
    },
    {
        "featureType": "poi.park",
        "elementType": "geometry",
        "stylers": [
            {
                "color": "#c5dac6"
            }
        ]
    },
    {
        "featureType": "administrative",
        "stylers": [
            {
                "visibility": "on"
            },
            {
                "lightness": 33
            }
        ]
    },
    {
        "featureType": "road"
    },
    {
        "featureType": "poi.park",
        "elementType": "labels",
        "stylers": [
            {
                "visibility": "on"
            },
            {
                "lightness": 20
            }
        ]
    },
    {},
    {
        "featureType": "road",
        "stylers": [
            {
                "lightness": 20
            }
        ]
    }
];

/*$.get( "/happylocation", function(data) {
    var Montreal = new google.maps.LatLng(45.5500, -73.5500);

    map = new google.maps.Map(document.getElementById('map-canvas'), {
        center: Montreal,
        zoom: 18,
        mapTypeId: google.maps.MapTypeId.TERRAIN,
        styles: map_style
    });
});*/

var Montreal = new google.maps.LatLng(45.5500, -73.5500);

map = new google.maps.Map(document.getElementById('map-canvas'), {
  center: Montreal,
  zoom: 18,
  mapTypeId: google.maps.MapTypeId.TERRAIN,
  styles: map_style
});

// AJAX to get map data
$.ajax({
    url: '/data',
    type: 'get',
    success: function(data) {
        var heatMapData = [];
        for (var i in data) {
            console.log(data[i][0] +", "+ data[i][1]+"," + data[i][2]);
            heatMapData.push( { location: new google.maps.LatLng(data[i][0], data[i][1]), weight: data[i][2] } );
            //makeMarker(JSONdata[i]);
        }

        var heatmap = new google.maps.visualization.HeatmapLayer({
            data: heatMapData
        });

        heatmap.setMap(map);
    },
    error: function(xhr, desc, err) {
        console.log(xhr);
        console.log("Details: " + desc + "\nError:" + err);
    }
});

/*
function makeMarker(x){
	var coord = new google.maps.LatLng(x[0],x[1]);
	var contentString = '
'+
	      '
'+
	      '
'+
	      '
Uluru
'+
	      '
'+
	      '
Uluru, also referred to as Ayers Rock, is a large ' +
	      'sandstone rock formation in the southern part of the '+
	      'Northern Territory, central Australia. It lies 335 km (208 mi) '+
	      'south west of the nearest large town, Alice Springs; 450 km '+
	      '(280 mi) by road. Kata Tjuta and Uluru are the two major '+
	      'features of the Uluru - Kata Tjuta National Park. Uluru is '+
	      'sacred to the Pitjantjatjara and Yankunytjatjara, the '+
	      'Aboriginal people of the area. It has many springs, waterholes, '+
	      'rock caves and ancient paintings. Uluru is listed as a World '+
	      'Heritage Site.
'+
	      '
Attribution: Uluru, '+
	      'http://en.wikipedia.org/w/index.php?title=Uluru '+
	      '(last visited June 22, 2009).
'+
	      '
'+
	      '
';
	var infowindow = new google.maps.InfoWindow({
      		content: contentString
  	});
	var marker = new google.maps.Marker({
		position: coord,
      		map: map,
      		title: 'Uluru (Ayers Rock)'
  	});
	google.maps.event.addListener(marker, 'click', function() {
    		infowindow.open(map,marker);
  	});
}
*/
<commit_msg>Console printing.<commit_after>map_style = [
    {
        "featureType": "water",
        "stylers": [
            {
                "visibility": "on"
            },
            {
                "color": "#acbcc9"
            }
        ]
    },
    {
        "featureType": "landscape",
        "stylers": [
            {
                "color": "#f2e5d4"
            }
        ]
    },
    {
        "featureType": "road.highway",
        "elementType": "geometry",
        "stylers": [
            {
                "color": "#c5c6c6"
            }
        ]
    },
    {
        "featureType": "road.arterial",
        "elementType": "geometry",
        "stylers": [
            {
                "color": "#e4d7c6"
            }
        ]
    },
    {
        "featureType": "road.local",
        "elementType": "geometry",
        "stylers": [
            {
                "color": "#fbfaf7"
            }
        ]
    },
    {
        "featureType": "poi.park",
        "elementType": "geometry",
        "stylers": [
            {
                "color": "#c5dac6"
            }
        ]
    },
    {
        "featureType": "administrative",
        "stylers": [
            {
                "visibility": "on"
            },
            {
                "lightness": 33
            }
        ]
    },
    {
        "featureType": "road"
    },
    {
        "featureType": "poi.park",
        "elementType": "labels",
        "stylers": [
            {
                "visibility": "on"
            },
            {
                "lightness": 20
            }
        ]
    },
    {},
    {
        "featureType": "road",
        "stylers": [
            {
                "lightness": 20
            }
        ]
    }
];

/*$.get( "/happylocation", function(data) {
    var Montreal = new google.maps.LatLng(45.5500, -73.5500);

    map = new google.maps.Map(document.getElementById('map-canvas'), {
        center: Montreal,
        zoom: 18,
        mapTypeId: google.maps.MapTypeId.TERRAIN,
        styles: map_style
    });
});*/

var Montreal = new google.maps.LatLng(45.5500, -73.5500);

map = new google.maps.Map(document.getElementById('map-canvas'), {
  center: Montreal,
  zoom: 18,
  mapTypeId: google.maps.MapTypeId.TERRAIN,
  styles: map_style
});

// AJAX to get map data
$.ajax({
    url: '/data',
    type: 'get',
    success: function(data) {
        console.log(data);
        var heatMapData = [];
        for (var i in data) {
            heatMapData.push( { location: new google.maps.LatLng(data[i][0], data[i][1]), weight: data[i][2] } );
            //makeMarker(JSONdata[i]);
        }

        var heatmap = new google.maps.visualization.HeatmapLayer({
            data: heatMapData
        });

        heatmap.setMap(map);
    },
    error: function(xhr, desc, err) {
        console.log(xhr);
        console.log("Details: " + desc + "\nError:" + err);
    }
});

/*
function makeMarker(x){
	var coord = new google.maps.LatLng(x[0],x[1]);
	var contentString = '
'+
	      '
'+
	      '
'+
	      '
Uluru
'+
	      '
'+
	      '
Uluru, also referred to as Ayers Rock, is a large ' +
	      'sandstone rock formation in the southern part of the '+
	      'Northern Territory, central Australia. It lies 335 km (208 mi) '+
	      'south west of the nearest large town, Alice Springs; 450 km '+
	      '(280 mi) by road. Kata Tjuta and Uluru are the two major '+
	      'features of the Uluru - Kata Tjuta National Park. Uluru is '+
	      'sacred to the Pitjantjatjara and Yankunytjatjara, the '+
	      'Aboriginal people of the area. It has many springs, waterholes, '+
	      'rock caves and ancient paintings. Uluru is listed as a World '+
	      'Heritage Site.
'+
	      '
Attribution: Uluru, '+
	      'http://en.wikipedia.org/w/index.php?title=Uluru '+
	      '(last visited June 22, 2009).
'+
	      '
'+
	      '
';
	var infowindow = new google.maps.InfoWindow({
      		content: contentString
  	});
	var marker = new google.maps.Marker({
		position: coord,
      		map: map,
      		title: 'Uluru (Ayers Rock)'
  	});
	google.maps.event.addListener(marker, 'click', function() {
    		infowindow.open(map,marker);
  	});
}
*/
<|endoftext|>


<commit_before>/*
 * Currently, dismantler has to be in target room already.
 *
 */

module.exports ={
    run : function(creep){
        var dismantleFlags = creep.room.find(FIND_FLAGS,{filter: (f) => /dismantle/.test(f.name)});
        var numFlags = dismantleFlags.length;
        var target = undefined
        for(i=1,i<=numFlags,i++){
            var myFlag = 'dismantle' + i;
            var structsAtPlace = Game.flags[myFlag].pos.lookFor(LOOK_STRUCTURES);
            if(structsAtPlace.length > 0){
                target = structsAtPlace[0];
                break;
            }
        }
        if(target != undefined){
            if(creep.dismantle(target) == ERR_NOT_IN_RANGE){
                creep.moveTo(target);
            }
        }
    }
}
<commit_msg>minor syntax<commit_after>/*
 * Currently, dismantler has to be in target room already.
 *
 */

module.exports ={
    run : function(creep){
        var dismantleFlags = creep.room.find(FIND_FLAGS,{filter: (f) => /dismantle/.test(f.name)});
        var numFlags = dismantleFlags.length;
        var target = undefined;
        for(i=1 ; i<=numFlags ; i++){
            var myFlag = 'dismantle' + i;
            var structsAtPlace = Game.flags[myFlag].pos.lookFor(LOOK_STRUCTURES);
            if(structsAtPlace.length > 0){
                target = structsAtPlace[0];
                break;
            }
        }
        if(target != undefined){
            if(creep.dismantle(target) == ERR_NOT_IN_RANGE){
                creep.moveTo(target);
            }
        }
    }
}
<|endoftext|>


<commit_before>/**
	_moon.VideoFeedback_ is a protected kind used inside of _moon.VideoPlayer_, to provide feedback informations
	of video contorls and status.
*/
enyo.kind({
	name: "moon.VideoFeedback",
	kind: "enyo.Control",
	classes: "moon-video-player-feedback hidden",
	published: {
		//* Timeout duration for disapearing feedback information (in milliseconds)
		autoTimeoutMS: 	2000,
		imagePath: 		"$lib/moonstone/images/",
		jumpBackImg: 	"icon-jumpback.png",
		rewindImg: 		"icon-rewind.png",
		playImg: 		"icon-play.png",
		pauseImg: 		"icon-pause.png",
		fastForwardImg: "icon-fastforward.png",
		jumpForwardImg: "icon-jumpforward.png"
	},
	//* @protected
	showingFeedback: false,
	_autoTimer: null,
	components: [
		{classes: "moon-video-feedback-wrapper", components: [
			{name: "leftIcon",  classes: "moon-video-feedback-icon-left",  allowHtml: true, content: " ", showing: false},
			{name: "feedText",  classes: "moon-video-feedback-text"},
			{name: "rightIcon", classes: "moon-video-feedback-icon-right", allowHtml: true, content: " ", showing: false}
		]}
	],

	//* @public

	feedback: function(inMessage, inParams, inPersistShowing, inLeftSrc, inRightSrc) {
		var customMessage = false;
		inMessage = inMessage || "";
		inParams = inParams || {};

		switch (inMessage) {
			case "Play":
				inRightSrc = enyo.path.rewrite(this.imagePath + this.playImg);
				break;

			case "Pause":
				inRightSrc = enyo.path.rewrite(this.imagePath + this.pauseImg);
				break;

			case "Rewind":
				inMessage = inParams.playbackRate + "x";
				inLeftSrc = enyo.path.rewrite(this.imagePath + this.rewindImg);
				break;

			case "Fastforward":
				inMessage = inParams.playbackRate + "x";
				inRightSrc = enyo.path.rewrite(this.imagePath + this.fastForwardImg);
				break;

			case "JumpBackward":
				inMessage = inParams.jumpSize + " sec";
				inLeftSrc = enyo.path.rewrite(this.imagePath + this.jumpBackImg);
				break;

			case "JumpForward":
				inMessage = inParams.jumpSize + " sec";
				inRightSrc = enyo.path.rewrite(this.imagePath + this.jumpForwardImg);
				break;

			// If the user sends in a custom message, block other messages until it's hidden
			default:
				customMessage = true;
				this.showingFeedback = true;
				break;
		}

		// Don't show feedback if we are showing custom feedback already, unless this is a new custom message
		if (!customMessage && this.showingFeedback) {
			return;
		}

		// Set content as _inMessage_
		this.$.feedText.setContent(inMessage);

		// Show output controls
		this.showFeedback();

		// Show icons as appropriate
		this.updateIcons(inLeftSrc, inRightSrc);

		//* Don't setup hide timer if _inPersistShowing_ is true
		if (inPersistShowing) {
			this.resetAutoTimer();
		} else {
			this.setAutoTimer();
		}
	},

	//* Show this control
	showFeedback: function() {
		this.removeClass("hidden");
	},
	//* Hide this control and set _this.showingFeedback_ to _false_
	hideFeedback: function() {
		this.addClass("hidden");
		this.showingFeedback = false;
	},

	//* @protected

	//* Start job that will hide this control
	setAutoTimer: function() {
		this.log("SETTING TIMER");
		this.hideJob = enyo.job(this.id + "hide", this.bindSafely("hideFeedback"), this.getAutoTimeoutMS());
	},
	//* Clear job that will hide this control
	resetAutoTimer: function() {
		enyo.job.stop(this.id + "hide");
	},
	//* Show/hide icons and set sources
	updateIcons: function(inLeftSrc, inRightSrc) {
		if (inLeftSrc) {
			this.$.leftIcon.show();
			this.$.leftIcon.applyStyle("background-image", "url(" + inLeftSrc + ")");
		} else {
			this.$.leftIcon.hide();
		}

		if (inRightSrc) {
			this.$.rightIcon.show();
			this.$.rightIcon.applyStyle("background-image", "url(" + inRightSrc + ")");
		} else {
			this.$.rightIcon.hide();
		}
	}
});
<commit_msg>Pulled debug log.<commit_after>/**
	_moon.VideoFeedback_ is a protected kind used inside of _moon.VideoPlayer_, to provide feedback informations
	of video contorls and status.
*/
enyo.kind({
	name: "moon.VideoFeedback",
	kind: "enyo.Control",
	classes: "moon-video-player-feedback hidden",
	published: {
		//* Timeout duration for disapearing feedback information (in milliseconds)
		autoTimeoutMS: 	2000,
		imagePath: 		"$lib/moonstone/images/",
		jumpBackImg: 	"icon-jumpback.png",
		rewindImg: 		"icon-rewind.png",
		playImg: 		"icon-play.png",
		pauseImg: 		"icon-pause.png",
		fastForwardImg: "icon-fastforward.png",
		jumpForwardImg: "icon-jumpforward.png"
	},
	//* @protected
	showingFeedback: false,
	_autoTimer: null,
	components: [
		{classes: "moon-video-feedback-wrapper", components: [
			{name: "leftIcon",  classes: "moon-video-feedback-icon-left",  allowHtml: true, content: " ", showing: false},
			{name: "feedText",  classes: "moon-video-feedback-text"},
			{name: "rightIcon", classes: "moon-video-feedback-icon-right", allowHtml: true, content: " ", showing: false}
		]}
	],

	//* @public

	feedback: function(inMessage, inParams, inPersistShowing, inLeftSrc, inRightSrc) {
		var customMessage = false;
		inMessage = inMessage || "";
		inParams = inParams || {};

		switch (inMessage) {
			case "Play":
				inRightSrc = enyo.path.rewrite(this.imagePath + this.playImg);
				break;

			case "Pause":
				inRightSrc = enyo.path.rewrite(this.imagePath + this.pauseImg);
				break;

			case "Rewind":
				inMessage = inParams.playbackRate + "x";
				inLeftSrc = enyo.path.rewrite(this.imagePath + this.rewindImg);
				break;

			case "Fastforward":
				inMessage = inParams.playbackRate + "x";
				inRightSrc = enyo.path.rewrite(this.imagePath + this.fastForwardImg);
				break;

			case "JumpBackward":
				inMessage = inParams.jumpSize + " sec";
				inLeftSrc = enyo.path.rewrite(this.imagePath + this.jumpBackImg);
				break;

			case "JumpForward":
				inMessage = inParams.jumpSize + " sec";
				inRightSrc = enyo.path.rewrite(this.imagePath + this.jumpForwardImg);
				break;

			// If the user sends in a custom message, block other messages until it's hidden
			default:
				customMessage = true;
				this.showingFeedback = true;
				break;
		}

		// Don't show feedback if we are showing custom feedback already, unless this is a new custom message
		if (!customMessage && this.showingFeedback) {
			return;
		}

		// Set content as _inMessage_
		this.$.feedText.setContent(inMessage);

		// Show output controls
		this.showFeedback();

		// Show icons as appropriate
		this.updateIcons(inLeftSrc, inRightSrc);

		//* Don't setup hide timer if _inPersistShowing_ is true
		if (inPersistShowing) {
			this.resetAutoTimer();
		} else {
			this.setAutoTimer();
		}
	},

	//* Show this control
	showFeedback: function() {
		this.removeClass("hidden");
	},
	//* Hide this control and set _this.showingFeedback_ to _false_
	hideFeedback: function() {
		this.addClass("hidden");
		this.showingFeedback = false;
	},

	//* @protected

	//* Start job that will hide this control
	setAutoTimer: function() {
		this.hideJob = enyo.job(this.id + "hide", this.bindSafely("hideFeedback"), this.getAutoTimeoutMS());
	},
	//* Clear job that will hide this control
	resetAutoTimer: function() {
		enyo.job.stop(this.id + "hide");
	},
	//* Show/hide icons and set sources
	updateIcons: function(inLeftSrc, inRightSrc) {
		if (inLeftSrc) {
			this.$.leftIcon.show();
			this.$.leftIcon.applyStyle("background-image", "url(" + inLeftSrc + ")");
		} else {
			this.$.leftIcon.hide();
		}

		if (inRightSrc) {
			this.$.rightIcon.show();
			this.$.rightIcon.applyStyle("background-image", "url(" + inRightSrc + ")");
		} else {
			this.$.rightIcon.hide();
		}
	}
});
<|endoftext|>


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

/**
 * @fileoverview Node JS script that starts a test server for running tests.
 */
var fsMod = require('fs');
var pathMod = require('path');
var nopt = /** @type {!Function} */ (require('nopt'));
var mkdir = /** @type {!Function} */ (require('mkdirp').sync);
var rmdir = /** @type {!Function} */ (require('rimraf').sync);
var glob = /** @type {!Function} */ (require('glob').sync);
var fork = /** @type {!Function} */ (require('child_process').fork);
var exec = /** @type {!Function} */ (require('child_process').exec);
var createServer =
    /** @type {!Function} */ (require('http-server').createServer);

/** @typedef {{Dir: !Function}} @private */
var TempType_;
var temp = /** @type {TempType_} */ (require('temporary'));

var stdin = process.stdin;
var stdout = process.stdout;

/** @typedef {{listen: !Function, close: !Function}} @private */
var HTTPServerType_;

/** @type {HTTPServerType_} */
var server;

// Command line options.
var knownOpts = {
  'library': pathMod,
  'target': String,
  'port': [Number, null]
};
var args = nopt(knownOpts);
if (!args.hasOwnProperty('library') || !args.hasOwnProperty('target')) {
  stdout.write('Lovefield test server\r\n');
  stdout.write('Usage:\r\n');
  stdout.write('  --library Closure library location\r\n');
  stdout.write('  --target <perf|tests> Which test set to run\r\n');
  stdout.write('  --port [number] Port number to use, default to 4000\r\n');
  process.exit(1);
}

// Creates a temp directory.
var dir = new temp.Dir();
var tempPath = pathMod.resolve(dir.path);
var origPath = process.cwd();
stdout.write('Serving path is: ' + tempPath + '\r\n');
process.chdir(tempPath);
fsMod.mkdirSync('lovefield');
fsMod.mkdirSync('html');

/** @const {!Array.<string>} */
var SYMLINKS = ['lib', 'perf', 'testing', 'tests'];
createSymLinks();

// Create HR schema for tests
var spacPath = pathMod.resolve(pathMod.join(__dirname, '../spac/spac.js'));
var spac = fork(
    spacPath,
    [
      '--schema=' +
     pathMod.resolve(pathMod.join(__dirname, '../testing/hr_schema.yaml')),
      '--namespace=hr.db',
      '--outputdir=' + pathMod.resolve(pathMod.join(tempPath, 'html'))
    ]);

spac.on('close', function(code) {
  if (code == 0) {
    // Creates deps.js
    var writerPath = pathMod.resolve('closure/bin/build/depswriter.py');
    var command =
        'python ' + writerPath +
        '  --root_with_prefix="' +
        pathMod.resolve(pathMod.join(__dirname, '..')) +
        ' ../../lovefield"  --root_with_prefix="html ../../html" > deps.js';
    exec(command, function(error, cout, cerr) {
      createTestFiles();
      var port = args.port || 4000;
      server = /** @type {HTTPServerType_} */ (createServer());
      server.listen(port);
      stdout.write('Server started at port ' + port + '\r\n');
      waitCtrlC();
    });
  } else {
    stdout.write('ERROR: unable to generate code from schema\r\n');
    cleanUp();
    process.exit(1);
  }
});

/** Creates symbolic links to Closure and Lovefield */
function createSymLinks() {
  fsMod.symlinkSync(
      pathMod.resolve(pathMod.join(args.library, 'closure')),
      pathMod.join(tempPath, 'closure'),
      'junction');
  SYMLINKS.forEach(function(link) {
    fsMod.symlinkSync(
        pathMod.resolve(pathMod.join(__dirname, '../' + link)),
        pathMod.join(tempPath, 'lovefield/' + link),
        'junction');
  });
}

/** Removes previously created symbolic links */
function removeSymLinks() {
  fsMod.unlinkSync('closure');
  SYMLINKS.forEach(function(link) {
    fsMod.unlinkSync('lovefield/' + link);
  });
}

/** Creates stub HTML for test files */
function createTestFiles() {
  var testFiles = glob('lovefield/' + args.target + '/**/*_test.js');
  stdout.write('Generating ' + testFiles.length + ' test files ... ');
  var files = testFiles.map(function(name, index) {
    if (index % 10 == 0) {
      stdout.write(index + ' ');
    }
    return createTestFile(name);
  });

  var title = 'Lovefield ' + args.target;
  var links = files.map(function(file) {
    return '    ' + file.slice(5) + '
';
  });
  var contents =
      '\n' +
      '  \n' +
      '    <title>' + title + '</title>\n' +
      '  \n' +
      '  \n' +
      '
' + title + '
\n' +
      links.join('\n') +
      '\n  \n' +
      '\n';
  fsMod.writeFileSync('index.html', contents);
  stdout.write('\nTest files generated. Starting server ...\n');
}

/**
 * @param {string} script Path of the script, e.g. lovefield/tests/foo_test.js.
 * @return {string} Generated file path.
 */
function createTestFile(script) {
  var target = 'html/' + script.slice(10, -2) + 'html';
  var level = target.match(/\//g).length;
  var prefix = new Array(level).join('../') + '../';
  var contents =
      '\n' +
      '  \n' +
      '    <title>' + pathMod.basename(target).slice(0, -5) + '</title>\n' +
      '    \n' +
      '    \n' +
      '  \n' +
      '  \n' +
      '    \n' +
      '    \n' +
      '  \n' +
      '\n';
  mkdir(pathMod.dirname(target));
  fsMod.writeFileSync(target, contents);
  return target;
}

/** Waits until user press Ctrl-C */
function waitCtrlC() {
  // Wait until Ctrl-C is pressed.
  stdin.setRawMode(true);
  stdin.resume();
  stdin.setEncoding('utf8');
  stdout.write('Press Ctrl-C to stop server ...\r\n');
  stdin.on('data', function(key) {
    if (key == '\u0003') {
      stdout.write('Stopping server ...\r\n');
      server.close();
      cleanUp();
      process.exit(0);
    }

    // Write key to stdout as usual.
    stdout.write(key);
  });
}

/** Removes temp folder */
function cleanUp() {
  stdout.write('Removing temp folder ...\r\n');
  removeSymLinks();
  process.chdir(origPath);
  rmdir(tempPath);
}
<commit_msg>Add doctype and meta charset for generated HTML in run_test_server.js. Change line break from \n to \r\n for easier inspection on Windows. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=77952427<commit_after>/**
 * @license
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Node JS script that starts a test server for running tests.
 */
var fsMod = require('fs');
var pathMod = require('path');
var nopt = /** @type {!Function} */ (require('nopt'));
var mkdir = /** @type {!Function} */ (require('mkdirp').sync);
var rmdir = /** @type {!Function} */ (require('rimraf').sync);
var glob = /** @type {!Function} */ (require('glob').sync);
var fork = /** @type {!Function} */ (require('child_process').fork);
var exec = /** @type {!Function} */ (require('child_process').exec);
var createServer =
    /** @type {!Function} */ (require('http-server').createServer);

/** @typedef {{Dir: !Function}} @private */
var TempType_;
var temp = /** @type {TempType_} */ (require('temporary'));

var stdin = process.stdin;
var stdout = process.stdout;

/** @typedef {{listen: !Function, close: !Function}} @private */
var HTTPServerType_;

/** @type {HTTPServerType_} */
var server;

// Command line options.
var knownOpts = {
  'library': pathMod,
  'target': String,
  'port': [Number, null]
};
var args = nopt(knownOpts);
if (!args.hasOwnProperty('library') || !args.hasOwnProperty('target')) {
  stdout.write('Lovefield test server\r\n');
  stdout.write('Usage:\r\n');
  stdout.write('  --library Closure library location\r\n');
  stdout.write('  --target <perf|tests> Which test set to run\r\n');
  stdout.write('  --port [number] Port number to use, default to 4000\r\n');
  process.exit(1);
}

// Creates a temp directory.
var dir = new temp.Dir();
var tempPath = pathMod.resolve(dir.path);
var origPath = process.cwd();
stdout.write('Serving path is: ' + tempPath + '\r\n');
process.chdir(tempPath);
fsMod.mkdirSync('lovefield');
fsMod.mkdirSync('html');

/** @const {!Array.<string>} */
var SYMLINKS = ['lib', 'perf', 'testing', 'tests'];
createSymLinks();

// Create HR schema for tests
var spacPath = pathMod.resolve(pathMod.join(__dirname, '../spac/spac.js'));
var spac = fork(
    spacPath,
    [
      '--schema=' +
     pathMod.resolve(pathMod.join(__dirname, '../testing/hr_schema.yaml')),
      '--namespace=hr.db',
      '--outputdir=' + pathMod.resolve(pathMod.join(tempPath, 'html'))
    ]);

spac.on('close', function(code) {
  if (code == 0) {
    // Creates deps.js
    var writerPath = pathMod.resolve('closure/bin/build/depswriter.py');
    var command =
        'python ' + writerPath +
        '  --root_with_prefix="' +
        pathMod.resolve(pathMod.join(__dirname, '..')) +
        ' ../../lovefield"  --root_with_prefix="html ../../html" > deps.js';
    exec(command, function(error, cout, cerr) {
      createTestFiles();
      var port = args.port || 4000;
      server = /** @type {HTTPServerType_} */ (createServer());
      server.listen(port);
      stdout.write('Server started at port ' + port + '\r\n');
      waitCtrlC();
    });
  } else {
    stdout.write('ERROR: unable to generate code from schema\r\n');
    cleanUp();
    process.exit(1);
  }
});

/** Creates symbolic links to Closure and Lovefield */
function createSymLinks() {
  fsMod.symlinkSync(
      pathMod.resolve(pathMod.join(args.library, 'closure')),
      pathMod.join(tempPath, 'closure'),
      'junction');
  SYMLINKS.forEach(function(link) {
    fsMod.symlinkSync(
        pathMod.resolve(pathMod.join(__dirname, '../' + link)),
        pathMod.join(tempPath, 'lovefield/' + link),
        'junction');
  });
}

/** Removes previously created symbolic links */
function removeSymLinks() {
  fsMod.unlinkSync('closure');
  SYMLINKS.forEach(function(link) {
    fsMod.unlinkSync('lovefield/' + link);
  });
}

/** Creates stub HTML for test files */
function createTestFiles() {
  var testFiles = glob('lovefield/' + args.target + '/**/*_test.js');
  stdout.write('Generating ' + testFiles.length + ' test files ... ');
  var files = testFiles.map(function(name, index) {
    if (index % 10 == 0) {
      stdout.write(index + ' ');
    }
    return createTestFile(name);
  });

  var title = 'Lovefield ' + args.target;
  var links = files.map(function(file) {
    return '    ' + file.slice(5) + '
';
  });
  var contents =
      '<!DOCTYPE html>\r\n' +
      '\r\n' +
      '  \r\n' +
      '    <meta charset="utf-8" />\r\n' +
      '    <title>' + title + '</title>\r\n' +
      '  \r\n' +
      '  \r\n' +
      '
' + title + '
\r\n' +
      links.join('\r\n') +
      '\r\n  \r\n' +
      '\r\n';
  fsMod.writeFileSync('index.html', contents);
  stdout.write('\nTest files generated. Starting server ...\n');
}

/**
 * @param {string} script Path of the script, e.g. lovefield/tests/foo_test.js.
 * @return {string} Generated file path.
 */
function createTestFile(script) {
  var target = 'html/' + script.slice(10, -2) + 'html';
  var level = target.match(/\//g).length;
  var prefix = new Array(level).join('../') + '../';
  var contents =
      '<!DOCTYPE html>\r\n' +
      '\r\n' +
      '  \r\n' +
      '    <meta charset="utf-8" />\r\n' +
      '    <title>' + pathMod.basename(target).slice(0, -5) + '</title>\r\n' +
      '    \r\n' +
      '    \r\n' +
      '  \r\n' +
      '  \r\n' +
      '    \r\n' +
      '    \r\n' +
      '  \r\n' +
      '\r\n';
  mkdir(pathMod.dirname(target));
  fsMod.writeFileSync(target, contents);
  return target;
}

/** Waits until user press Ctrl-C */
function waitCtrlC() {
  // Wait until Ctrl-C is pressed.
  stdin.setRawMode(true);
  stdin.resume();
  stdin.setEncoding('utf8');
  stdout.write('Press Ctrl-C to stop server ...\r\n');
  stdin.on('data', function(key) {
    if (key == '\u0003') {
      stdout.write('Stopping server ...\r\n');
      server.close();
      cleanUp();
      process.exit(0);
    }

    // Write key to stdout as usual.
    stdout.write(key);
  });
}

/** Removes temp folder */
function cleanUp() {
  stdout.write('Removing temp folder ...\r\n');
  removeSymLinks();
  process.chdir(origPath);
  rmdir(tempPath);
}
<|endoftext|>


<commit_before>/*
	parse.js
	Reads the incoming message and chooses the appropriate response
*/

const login = require("facebook-chat-api");
const cool = require('cool-ascii-faces');
const http = require('http');
const Firebase = require("firebase");
const cows = require('cows');
const url = require('url');
const Client = require('node-rest-client').Client;

var db = new Firebase(process.env.DANK_SINATRA_FIREBASE);
var message_reqs = db.child("Requests");
var usersDB = db.child("users");
var chatsDB = db.child("chats");

// All commands go here
var choices = {
	help: /\\help/,

	greet: /Dank/,

	weather: /\\weather/,
	date: /\\date/,

	insult: /\\insult/,

	cool: /\\face/,
	cow: /\\cow/,
	senate: /\\senate/
};

/*
	TODO: Simulate conversation. Use IDs and DB
*/
function parse(api, message){
	var response = '';

	// Add child for the threadID and append message there
	chatsDB.child(message.threadID).set(message);
	usersDB.child(message.senderID).set(message);

	if (choices.help.test(message.body)){
		response = "Type '\\help' for a list of commands.\n";
		response += "\\weather (ZIP code): Send the current weather in the given ZIP code.\n";
		response += "\\date: Send the current date.\n";
		response += "\\face: Send a cool ascii face.\n";
		response += "\\cow: Send an ascii cow.\n";
		response += "\\senate: send a fact about the United States Senate."

		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	else if (choices.cool.test(message.body)){
		response = cool();

		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	else if (choices.weather.test(message.body)){

		var zip_code = message.body.replace(choices.weather,"");
		zip_code = zip_code.trim();
		console.log(zip_code);

		http.get('http://api.wunderground.com/api/'+process.env.WEATHER_API_KEY+'/conditions/q/' + zip_code + '.json',function(res){
			var body = '';
			var temp = '';
			var status = '';
			var city = '';

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

			res.on('error', function(error){
				console.error(error.message);
				api.sendMessage("Invalid argument!",message.threadID);
			});

			res.on('end', function(){
				var weather_data = JSON.parse(body);
				console.log(weather_data);

				if (!weather_data.response.error){
					temp = weather_data.current_observation.temp_f;
					status = weather_data.current_observation.weather;
					city = weather_data.current_observation.display_location.city;

					response += "The current temperature in " + city + " is " + temp + ".\n";
					response += "The weather is " + status + ".";

					message_reqs.push(message);
					console.dir("Sending " + response);
					api.sendMessage(response, message.threadID);
				}
				else{
					response = JSON.stringify(weather_data.response.error);
					api.sendMessage(response,message.threadID);
				}
			});
		});
	}

	else if (choices.date.test(message.body)){
		//var date = new Date();
		response = "The date is " + Date() + ".";
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	else if (choices.cow.test(message.body)){
		response = cows()[Math.floor(Math.random()*418)];
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	else if (choices.insult.test(message.body)){
		response = "Fuck you " + message.senderName + "!";
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	else if (choices.senate.test(message.body)){

		var client = new Client();
		var nyt_url = url.format({
			protocol: 'http',
			host: 'api.nytimes.com',
			pathname: '/svc/politics/v3/us/legislative/congress/113/senate/members.json',
			query: {
				'api-key': process.env.NYT_CONGRESS
			}
		});
		client.get(nyt_url, function(data, response) {
			// Sort by total votes
			data.results[0].members.sort(function(a, b){
				return a.total_votes - b.total_votes;
			});
			//console.log(data.results[0].members[0]);
			response = "The senator with the fewest total votes cast is ";
			response += data.results[0].members[0].first_name + ' ' + data.results[0].members[0].last_name;
			response += " with " + data.results[0].members[0].total_votes + " total votes.";

			message_reqs.push(message);
			console.log("Sending " + response);
			api.sendMessage(response, message.threadID);

		});

	}
}

module.exports.parse = parse;
<commit_msg>Added greet function<commit_after>/*
	parse.js
	Reads the incoming message and chooses the appropriate response
*/

const login = require("facebook-chat-api");
const cool = require('cool-ascii-faces');
const http = require('http');
const Firebase = require("firebase");
const cows = require('cows');
const url = require('url');
const Client = require('node-rest-client').Client;

var db = new Firebase(process.env.DANK_SINATRA_FIREBASE);
var message_reqs = db.child("Requests");
var usersDB = db.child("users");
var chatsDB = db.child("chats");

// All commands go here
var choices = {
	help: /\\help/,

	greet: /\\howdy/,
	magic8: /\\magic8/,

	weather: /\\weather/,
	date: /\\date/,

	insult: /\\insult/,

	cool: /\\face/,
	cow: /\\cow/,
	senate: /\\senate/
};

/*
	TODO:
	1. Simulate conversation. Use IDs and DB
	2. Give a random greeting
	2. Magic 8 ball
*/
function parse(api, message){
	var response = '';

	// Add child for the threadID and append message there
	chatsDB.child(message.threadID).set(message);
	usersDB.child(message.senderID).set(message);

	if (choices.help.test(message.body)){
		response = "Type '\\help' for a list of commands.\n";
		response += "\\howdy: Send a greeting.\n";
		response += "\\weather (ZIP code): Send the current weather in the given ZIP code.\n";
		response += "\\date: Send the current date.\n";
		response += "\\face: Send a cool ascii face.\n";
		response += "\\cow: Send an ascii cow.\n";
		response += "\\senate: send a fact about the United States Senate."

		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	else if (choices.cool.test(message.body)){
		response = cool();

		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	else if (choices.weather.test(message.body)){

		var zip_code = message.body.replace(choices.weather,"");
		zip_code = zip_code.trim();
		console.log(zip_code);

		http.get('http://api.wunderground.com/api/'+process.env.WEATHER_API_KEY+'/conditions/q/' + zip_code + '.json',function(res){
			var body = '';
			var temp = '';
			var status = '';
			var city = '';

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

			res.on('error', function(error){
				console.error(error.message);
				api.sendMessage("Invalid argument!",message.threadID);
			});

			res.on('end', function(){
				var weather_data = JSON.parse(body);
				console.log(weather_data);

				if (!weather_data.response.error){
					temp = weather_data.current_observation.temp_f;
					status = weather_data.current_observation.weather;
					city = weather_data.current_observation.display_location.city;

					response += "The current temperature in " + city + " is " + temp + ".\n";
					response += "The weather is " + status + ".";

					message_reqs.push(message);
					console.dir("Sending " + response);
					api.sendMessage(response, message.threadID);
				}
				else{
					response = JSON.stringify(weather_data.response.error);
					api.sendMessage(response,message.threadID);
				}
			});
		});
	}

	else if (choices.date.test(message.body)){
		//var date = new Date();
		response = "The date is " + Date() + ".";
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	else if (choices.cow.test(message.body)){
		response = cows()[Math.floor(Math.random()*418)];
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	else if (choices.insult.test(message.body)){
		response = "Fuck you " + message.senderName + "!";
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	else if (choices.senate.test(message.body)){

		var client = new Client();
		var nyt_url = url.format({
			protocol: 'http',
			host: 'api.nytimes.com',
			pathname: '/svc/politics/v3/us/legislative/congress/113/senate/members.json',
			query: {
				'api-key': process.env.NYT_CONGRESS
			}
		});
		client.get(nyt_url, function(data, response) {
			// Sort by total votes
			data.results[0].members.sort(function(a, b){
				return a.total_votes - b.total_votes;
			});
			//console.log(data.results[0].members[0]);
			response = "The senator with the fewest total votes cast is ";
			response += data.results[0].members[0].first_name + ' ' + data.results[0].members[0].last_name;
			response += " with " + data.results[0].members[0].total_votes + " total votes.";

			message_reqs.push(message);
			console.log("Sending " + response);
			api.sendMessage(response, message.threadID);

		});
	}

	else if (choices.greet.test(message.body)){

		// Choose randomly from array of greetings

		response = "Howdy, " + message.senderName + "!";
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}
}

module.exports.parse = parse;
<|endoftext|>