<commit_before>// $Id: tiki-jquery.js 16989 2009-02-27 19:37:11Z jonnybradley $
// JavaScript glue for JQuery (1.3.2) in TikiWiki (3.0)

var $jq = jQuery.noConflict();

$jq(document).ready( function() { // JQuery's DOM is ready event - before onload

	// override existing show/hide routines here
	show = function (foo,f,section) {
		if ($jq("#" + foo).hasClass("tabcontent")) {
			showJQ("#" + foo, jqueryTiki.effect_tabs, jqueryTiki.effect_tabs_speed, jqueryTiki.effect_tabs_direction);
		} else {
			showJQ("#" + foo, jqueryTiki.effect, jqueryTiki.effect_speed, jqueryTiki.effect_direction);
		}
		if (f) { setCookie(foo, "o", section); }
	};

	hide = function (foo,f, section) {
		if ($jq("#" + foo).hasClass("tabcontent")) {
			hideJQ("#" + foo, jqueryTiki.effect_tabs, jqueryTiki.effect_tabs_speed, jqueryTiki.effect_tabs_direction);
		} else {
			hideJQ("#" + foo, jqueryTiki.effect, jqueryTiki.effect_speed, jqueryTiki.effect_direction);
		}
		if (f) {
			var wasnot = getCookie(foo, section, 'x') == 'x';
			setCookie(foo, "c", section);
			if (wasnot) {
				history.go(0);	// ik!
			}
		}
	};

	// flip function... unfortunately didn't use show/hide (ay?)

	flip = function (foo,style) {
		if ($jq("#" + foo).css("display") == "none") {
			setSessionVar('show_' + escape(foo),'y');
			showJQ("#" + foo, jqueryTiki.effect, jqueryTiki.effect_speed, jqueryTiki.effect_direction);
		} else {
			setSessionVar('show_' + escape(foo), 'n');
			hideJQ("#" + foo, jqueryTiki.effect, jqueryTiki.effect_speed, jqueryTiki.effect_direction);
		}
	};

	/* toggle CSS (tableless) layout columns
	 * won't animate nicely - one TODO for 4.0
	toggleCols = function (id,zeromargin,maincol) {	// TODO (it properly!)
		var showit = 'show_' + escape(id);
		if (!zeromargin) zeromargin = '';
		if (!id) id = '';
		if (!maincol) maincol = 'col1';
		if (document.getElementById(id).style.display == "none") {
			//show(id);
	        $jq("#" + id).fadeIn();
		    if (zeromargin == 'left') {
		        $jq("#" + maincol).animate({"marginLeft": ""});
		        //$jq("#" + maincol).css("marginLeft", "");
		    } else {
		        $jq("#" + maincol).animate({"marginRight": ""});
		        //$jq("#" + maincol).css("marginRight", "");
		    }
			setCookie(showit,'y');
		} else {
	        $jq("#" + id).fadeOut();
		    if (zeromargin == 'left') {
		        $jq("#" + maincol).animate({"marginLeft": "0"});
		        //$jq("#" + maincol).css("marginLeft", "0");

		    } else {
		        $jq("#" + maincol).animate({"marginRight": "0"});
		        //$jq("#" + maincol).css("marginRight", "0");
		    }
			hide(id);
			setCookie(showit,'n');
		}
	}; */

	// handle JQ effects

	showJQ = function (selector, effect, speed, dir) {
		if (effect == 'none') {
			$jq(selector).show();
		} else if (effect == '' || effect == 'normal') {
			$jq(selector).show(speed);
		} else if (effect == 'slide') {
			$jq(selector).slideDown(speed);
		} else if (effect == 'fade') {
			$jq(selector).fadeIn(speed);
		} else if (effect.match(/(.*)_ui$/).length > 1) {
			$jq(selector).show(effect.match(/(.*)_ui$/)[1], {direction: dir }, speed);
		} else {
			$jq(selector).show();
		}
	};

	hideJQ = function (selector, effect, speed, dir) {
		if (effect == 'none') {
			$jq(selector).hide();
		} else if (effect == '' || effect == 'normal') {
			$jq(selector).hide(speed);
		} else if (effect == 'slide') {
			$jq(selector).slideUp(speed);
		} else if (effect == 'fade') {
			$jq(selector).fadeOut(speed);
		} else if (effect.match(/(.*)_ui$/).length > 1) {
			$jq(selector).hide(effect.match(/(.*)_ui$/)[1], {direction: dir }, speed);
		} else {
			$jq(selector).hide();
		}
	};

	// tooltip functions and setup
	if (jqueryTiki.tooltips) {	// apply "cluetips" to all .tips class anchors
		$jq('a.tips').cluetip({splitTitle: '|', showTitle: false, width: '150px', cluezIndex: 400});
		$jq('a.titletips').cluetip({splitTitle: '|', cluezIndex: 400});

		/* overrides for overlib tooltips
		 * another one TODO for 4.0?
		overlib = function(data) {
			$jq().mousemove(function(e) {
				$jq().cluetip({splitTitle: '|', showTitle: false, width: '150px', cluezIndex: 400, tracking: true});
				$jq().cluetipContents = data;
				$jq().cluetip.activate;
				// just doesn't appear...
			});

		};
		nd = function() {
			// remove the tooltip
			$jq().cluetip.inactivate;
			$jq().unbind("mousemove", e);
		};*/
	}

	// superfish setup (CSS menu effects)
	if (jqueryTiki.superfish) {
		$jq('ul.cssmenu_horiz').superfish({
			animation: {opacity:'show', height:'show'},	// fade-in and slide-down animation
			speed: 'fast'								// faster animation speed
		});
		$jq('ul.cssmenu_vert').superfish({
			animation: {opacity:'show', height:'show'},	// fade-in and slide-down animation
			speed: 'fast'								// faster animation speed
		});
	}

	// tablesorter setup (sortable tables?)
	if (jqueryTiki.tablesorter) {
		$jq('.sortable').tablesorter({
			widthFixed: true,							// ??
//			widgets: ['zebra'],							// stripes (coming soon)
			debug: true
		});
	}
});		// end $jq(document).ready

/* Autocomplete assistants */

function parseAutoJSON(data) {
	var parsed = [];
	return $jq.map(data, function(row) {
		return {
			data: row,
			value: row,
			result: row
		}
	});
}

<commit_msg>[FIX] Oops, debug flag left in on tablesorter<commit_after>// $Id: tiki-jquery.js 16989 2009-02-27 19:37:11Z jonnybradley $
// JavaScript glue for JQuery (1.3.2) in TikiWiki (3.0)

var $jq = jQuery.noConflict();

$jq(document).ready( function() { // JQuery's DOM is ready event - before onload

	// override existing show/hide routines here
	show = function (foo,f,section) {
		if ($jq("#" + foo).hasClass("tabcontent")) {
			showJQ("#" + foo, jqueryTiki.effect_tabs, jqueryTiki.effect_tabs_speed, jqueryTiki.effect_tabs_direction);
		} else {
			showJQ("#" + foo, jqueryTiki.effect, jqueryTiki.effect_speed, jqueryTiki.effect_direction);
		}
		if (f) { setCookie(foo, "o", section); }
	};

	hide = function (foo,f, section) {
		if ($jq("#" + foo).hasClass("tabcontent")) {
			hideJQ("#" + foo, jqueryTiki.effect_tabs, jqueryTiki.effect_tabs_speed, jqueryTiki.effect_tabs_direction);
		} else {
			hideJQ("#" + foo, jqueryTiki.effect, jqueryTiki.effect_speed, jqueryTiki.effect_direction);
		}
		if (f) {
			var wasnot = getCookie(foo, section, 'x') == 'x';
			setCookie(foo, "c", section);
			if (wasnot) {
				history.go(0);	// ik!
			}
		}
	};

	// flip function... unfortunately didn't use show/hide (ay?)

	flip = function (foo,style) {
		if ($jq("#" + foo).css("display") == "none") {
			setSessionVar('show_' + escape(foo),'y');
			showJQ("#" + foo, jqueryTiki.effect, jqueryTiki.effect_speed, jqueryTiki.effect_direction);
		} else {
			setSessionVar('show_' + escape(foo), 'n');
			hideJQ("#" + foo, jqueryTiki.effect, jqueryTiki.effect_speed, jqueryTiki.effect_direction);
		}
	};

	/* toggle CSS (tableless) layout columns
	 * won't animate nicely - one TODO for 4.0
	toggleCols = function (id,zeromargin,maincol) {	// TODO (it properly!)
		var showit = 'show_' + escape(id);
		if (!zeromargin) zeromargin = '';
		if (!id) id = '';
		if (!maincol) maincol = 'col1';
		if (document.getElementById(id).style.display == "none") {
			//show(id);
	        $jq("#" + id).fadeIn();
		    if (zeromargin == 'left') {
		        $jq("#" + maincol).animate({"marginLeft": ""});
		        //$jq("#" + maincol).css("marginLeft", "");
		    } else {
		        $jq("#" + maincol).animate({"marginRight": ""});
		        //$jq("#" + maincol).css("marginRight", "");
		    }
			setCookie(showit,'y');
		} else {
	        $jq("#" + id).fadeOut();
		    if (zeromargin == 'left') {
		        $jq("#" + maincol).animate({"marginLeft": "0"});
		        //$jq("#" + maincol).css("marginLeft", "0");

		    } else {
		        $jq("#" + maincol).animate({"marginRight": "0"});
		        //$jq("#" + maincol).css("marginRight", "0");
		    }
			hide(id);
			setCookie(showit,'n');
		}
	}; */

	// handle JQ effects

	showJQ = function (selector, effect, speed, dir) {
		if (effect == 'none') {
			$jq(selector).show();
		} else if (effect == '' || effect == 'normal') {
			$jq(selector).show(speed);
		} else if (effect == 'slide') {
			$jq(selector).slideDown(speed);
		} else if (effect == 'fade') {
			$jq(selector).fadeIn(speed);
		} else if (effect.match(/(.*)_ui$/).length > 1) {
			$jq(selector).show(effect.match(/(.*)_ui$/)[1], {direction: dir }, speed);
		} else {
			$jq(selector).show();
		}
	};

	hideJQ = function (selector, effect, speed, dir) {
		if (effect == 'none') {
			$jq(selector).hide();
		} else if (effect == '' || effect == 'normal') {
			$jq(selector).hide(speed);
		} else if (effect == 'slide') {
			$jq(selector).slideUp(speed);
		} else if (effect == 'fade') {
			$jq(selector).fadeOut(speed);
		} else if (effect.match(/(.*)_ui$/).length > 1) {
			$jq(selector).hide(effect.match(/(.*)_ui$/)[1], {direction: dir }, speed);
		} else {
			$jq(selector).hide();
		}
	};

	// tooltip functions and setup
	if (jqueryTiki.tooltips) {	// apply "cluetips" to all .tips class anchors
		$jq('a.tips').cluetip({splitTitle: '|', showTitle: false, width: '150px', cluezIndex: 400});
		$jq('a.titletips').cluetip({splitTitle: '|', cluezIndex: 400});

		/* overrides for overlib tooltips
		 * another one TODO for 4.0?
		overlib = function(data) {
			$jq().mousemove(function(e) {
				$jq().cluetip({splitTitle: '|', showTitle: false, width: '150px', cluezIndex: 400, tracking: true});
				$jq().cluetipContents = data;
				$jq().cluetip.activate;
				// just doesn't appear...
			});

		};
		nd = function() {
			// remove the tooltip
			$jq().cluetip.inactivate;
			$jq().unbind("mousemove", e);
		};*/
	}

	// superfish setup (CSS menu effects)
	if (jqueryTiki.superfish) {
		$jq('ul.cssmenu_horiz').superfish({
			animation: {opacity:'show', height:'show'},	// fade-in and slide-down animation
			speed: 'fast'								// faster animation speed
		});
		$jq('ul.cssmenu_vert').superfish({
			animation: {opacity:'show', height:'show'},	// fade-in and slide-down animation
			speed: 'fast'								// faster animation speed
		});
	}

	// tablesorter setup (sortable tables?)
	if (jqueryTiki.tablesorter) {
		$jq('.sortable').tablesorter({
			widthFixed: true							// ??
//			widgets: ['zebra'],							// stripes (coming soon)
		});
	}
});		// end $jq(document).ready

/* Autocomplete assistants */

function parseAutoJSON(data) {
	var parsed = [];
	return $jq.map(data, function(row) {
		return {
			data: row,
			value: row,
			result: row
		}
	});
}

<|endoftext|>


<commit_before>#!/usr/bin/env node

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

console.error([
  '\033[31mLooks like you installed react-native globally, maybe you meant react-native-cli?',
  'To fix the issue, run:\033[0m',
  'npm uninstall -g react-native',
  'npm install -g react-native-cli'
].join('\n'));

process.exit(1);
<commit_msg>Fix usage of react-native cli inside package.json scripts<commit_after>#!/usr/bin/env node

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

var script = process.argv[1];
var installedGlobally = script.indexOf('node_modules/.bin/react-native') === -1;

if (installedGlobally) {
  console.error([
    '\033[31mLooks like you installed react-native globally, maybe you meant react-native-cli?',
    'To fix the issue, run:\033[0m',
    'npm uninstall -g react-native',
    'npm install -g react-native-cli'
  ].join('\n'));
  process.exit(1);
} else {
  require('./cli').run();
}
<|endoftext|>


<commit_before>// $Id: tiki-jquery.js 16989 2009-02-27 19:37:11Z jonnybradley $
// JavaScript glue for JQuery (1.2.6) in TikiWiki (3.0)

var $jq = jQuery.noConflict();

$jq(document).ready( function() { // JQuery's DOM is ready event - before onload

	// override existing show/hide routines here
	show = function (foo,f,section) {
		if ($jq("#" + foo).hasClass("tabcontent")) {
			showJQ("#" + foo, jqueryTiki.effect_tabs, jqueryTiki.effect_tabs_speed, jqueryTiki.effect_tabs_direction);
		} else {
			showJQ("#" + foo, jqueryTiki.effect, jqueryTiki.effect_speed, jqueryTiki.effect_direction);
		}
		if (f) { setCookie(foo, "o", section); }
	}

	hide = function (foo,f, section) {
		if ($jq("#" + foo).hasClass("tabcontent")) {
			hideJQ("#" + foo, jqueryTiki.effect_tabs, jqueryTiki.effect_tabs_speed, jqueryTiki.effect_tabs_direction);
		} else {
			hideJQ("#" + foo, jqueryTiki.effect, jqueryTiki.effect_speed, jqueryTiki.effect_direction);
		}
		if (f) {
			var wasnot = getCookie(foo, section, 'x') == 'x';
			setCookie(foo, "c", section);
			if (wasnot) {
				history.go(0);	// ik!
			}
		}
	}

	// flip function... unfortunately didn't use show/hide (ay?)

	flip = function (foo,style) {
		if ($jq("#" + foo).css("display") == "none") {
			show(foo);
			setCookie('show_' + escape(foo),'y');
		} else {
			hide(foo);
			setCookie('show_' + escape(foo), 'n');
		}
	}

	/* toggle CSS (tableless) layout columns
	 * won't animate nicely - one for 4.0 :)
	 *
	toggleCols = function (id,zeromargin,maincol) {	// TODO (it properly!)
		var showit = 'show_' + escape(id);
		if (!zeromargin) zeromargin = '';
		if (!id) id = '';
		if (!maincol) maincol = 'col1';
		if (document.getElementById(id).style.display == "none") {
			//show(id);
	        $jq("#" + id).fadeIn();
		    if (zeromargin == 'left') {
		        $jq("#" + maincol).animate({"marginLeft": ""});
		        //$jq("#" + maincol).css("marginLeft", "");
		    } else {
		        $jq("#" + maincol).animate({"marginRight": ""});
		        //$jq("#" + maincol).css("marginRight", "");
		    }
			setCookie(showit,'y');
		} else {
	        $jq("#" + id).fadeOut();
		    if (zeromargin == 'left') {
		        $jq("#" + maincol).animate({"marginLeft": "0"});
		        //$jq("#" + maincol).css("marginLeft", "0");

		    } else {
		        $jq("#" + maincol).animate({"marginRight": "0"});
		        //$jq("#" + maincol).css("marginRight", "0");
		    }
			hide(id);
			setCookie(showit,'n');
		}
	} */

	// handle JQ effects

	showJQ = function (selector, effect, speed, dir) {
		if (effect == 'none') {
			$jq(selector).show();
		} else if (effect == '' || effect == 'normal') {
			$jq(selector).show(speed);
		} else if (effect == 'slide') {
			$jq(selector).slideDown(speed);
		} else if (effect == 'fade') {
			$jq(selector).fadeIn(speed);
		} else if (effect.match(/(.*)_ui$/).length > 1) {
			$jq(selector).show(effect.match(/(.*)_ui$/)[1], {direction: dir }, speed);
		} else {
			$jq(selector).show();
		}
	}

	hideJQ = function (selector, effect, speed, dir) {
		if (effect == 'none') {
			$jq(selector).hide();
		} else if (effect == '' || effect == 'normal') {
			$jq(selector).hide(speed);
		} else if (effect == 'slide') {
			$jq(selector).slideUp(speed);
		} else if (effect == 'fade') {
			$jq(selector).fadeOut(speed);
		} else if (effect.match(/(.*)_ui$/).length > 1) {
			$jq(selector).hide(effect.match(/(.*)_ui$/)[1], {direction: dir }, speed);
		} else {
			$jq(selector).hide();
		}
	}

	// tooltip functions and setup
	if (jqueryTiki.tooltips) {	// apply "cluetips" to all .tips class anchors
		$jq('a.tips').cluetip({splitTitle: '|', showTitle: false, width: '150px', cluezIndex: 400});
		$jq('a.titletips').cluetip({splitTitle: '|', cluezIndex: 400});
	}

	// superfish setup (CSS menu effects)
	if (jqueryTiki.superfish) {
		$jq('ul.cssmenu_horiz').superfish();
	}
});		// end $jq(document).ready

/* Autocomplete assistants */

function parseAutoJSON(data) {
	var parsed = [];
	return $jq.map(data, function(row) {
		return {
			data: row,
			value: row,
			result: row
		}
	});
}
<commit_msg>[MOD] Some trivial changes and (commented out) experiment to override overlib tooltips (left for later, to be removed before 3.0 release if not fixed, along with toggleCols() fn)<commit_after>// $Id: tiki-jquery.js 16989 2009-02-27 19:37:11Z jonnybradley $
// JavaScript glue for JQuery (1.3.2) in TikiWiki (3.0)

var $jq = jQuery.noConflict();

$jq(document).ready( function() { // JQuery's DOM is ready event - before onload

	// override existing show/hide routines here
	show = function (foo,f,section) {
		if ($jq("#" + foo).hasClass("tabcontent")) {
			showJQ("#" + foo, jqueryTiki.effect_tabs, jqueryTiki.effect_tabs_speed, jqueryTiki.effect_tabs_direction);
		} else {
			showJQ("#" + foo, jqueryTiki.effect, jqueryTiki.effect_speed, jqueryTiki.effect_direction);
		}
		if (f) { setCookie(foo, "o", section); }
	};

	hide = function (foo,f, section) {
		if ($jq("#" + foo).hasClass("tabcontent")) {
			hideJQ("#" + foo, jqueryTiki.effect_tabs, jqueryTiki.effect_tabs_speed, jqueryTiki.effect_tabs_direction);
		} else {
			hideJQ("#" + foo, jqueryTiki.effect, jqueryTiki.effect_speed, jqueryTiki.effect_direction);
		}
		if (f) {
			var wasnot = getCookie(foo, section, 'x') == 'x';
			setCookie(foo, "c", section);
			if (wasnot) {
				history.go(0);	// ik!
			}
		}
	};

	// flip function... unfortunately didn't use show/hide (ay?)

	flip = function (foo,style) {
		if ($jq("#" + foo).css("display") == "none") {
			show(foo);
			setCookie('show_' + escape(foo),'y');
		} else {
			hide(foo);
			setCookie('show_' + escape(foo), 'n');
		}
	};

	/* toggle CSS (tableless) layout columns
	 * won't animate nicely - one TODO for 4.0
	toggleCols = function (id,zeromargin,maincol) {	// TODO (it properly!)
		var showit = 'show_' + escape(id);
		if (!zeromargin) zeromargin = '';
		if (!id) id = '';
		if (!maincol) maincol = 'col1';
		if (document.getElementById(id).style.display == "none") {
			//show(id);
	        $jq("#" + id).fadeIn();
		    if (zeromargin == 'left') {
		        $jq("#" + maincol).animate({"marginLeft": ""});
		        //$jq("#" + maincol).css("marginLeft", "");
		    } else {
		        $jq("#" + maincol).animate({"marginRight": ""});
		        //$jq("#" + maincol).css("marginRight", "");
		    }
			setCookie(showit,'y');
		} else {
	        $jq("#" + id).fadeOut();
		    if (zeromargin == 'left') {
		        $jq("#" + maincol).animate({"marginLeft": "0"});
		        //$jq("#" + maincol).css("marginLeft", "0");

		    } else {
		        $jq("#" + maincol).animate({"marginRight": "0"});
		        //$jq("#" + maincol).css("marginRight", "0");
		    }
			hide(id);
			setCookie(showit,'n');
		}
	}; */

	// handle JQ effects

	showJQ = function (selector, effect, speed, dir) {
		if (effect == 'none') {
			$jq(selector).show();
		} else if (effect == '' || effect == 'normal') {
			$jq(selector).show(speed);
		} else if (effect == 'slide') {
			$jq(selector).slideDown(speed);
		} else if (effect == 'fade') {
			$jq(selector).fadeIn(speed);
		} else if (effect.match(/(.*)_ui$/).length > 1) {
			$jq(selector).show(effect.match(/(.*)_ui$/)[1], {direction: dir }, speed);
		} else {
			$jq(selector).show();
		}
	};

	hideJQ = function (selector, effect, speed, dir) {
		if (effect == 'none') {
			$jq(selector).hide();
		} else if (effect == '' || effect == 'normal') {
			$jq(selector).hide(speed);
		} else if (effect == 'slide') {
			$jq(selector).slideUp(speed);
		} else if (effect == 'fade') {
			$jq(selector).fadeOut(speed);
		} else if (effect.match(/(.*)_ui$/).length > 1) {
			$jq(selector).hide(effect.match(/(.*)_ui$/)[1], {direction: dir }, speed);
		} else {
			$jq(selector).hide();
		}
	};

	// tooltip functions and setup
	if (jqueryTiki.tooltips) {	// apply "cluetips" to all .tips class anchors
		$jq('a.tips').cluetip({splitTitle: '|', showTitle: false, width: '150px', cluezIndex: 400});
		$jq('a.titletips').cluetip({splitTitle: '|', cluezIndex: 400});

		/* overrides for overlib tooltips
		 * another one TODO for 4.0?
		overlib = function(data) {
			$jq().mousemove(function(e) {
				$jq().cluetip({splitTitle: '|', showTitle: false, width: '150px', cluezIndex: 400, tracking: true});
				$jq().cluetipContents = data;
				$jq().cluetip.activate;
				// just doesn't appear...
			});

		};
		nd = function() {
			// remove the tooltip
			$jq().cluetip.inactivate;
			$jq().unbind("mousemove", e);
		};*/
	}

	// superfish setup (CSS menu effects)
	if (jqueryTiki.superfish) {
		$jq('ul.cssmenu_horiz').superfish();
	}
});		// end $jq(document).ready

/* Autocomplete assistants */

function parseAutoJSON(data) {
	var parsed = [];
	return $jq.map(data, function(row) {
		return {
			data: row,
			value: row,
			result: row
		}
	});
}

<|endoftext|>


<commit_before>/**
 * @ngdoc service
 * @name Attr2Options
 * @description
 *   Converts tag attributes to options used by google api v3 objects, map, marker, polygon, circle, etc.
 */
/* global google */
(function() {
  'use strict';

  var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
  var MOZ_HACK_REGEXP = /^moz([A-Z])/;

  function camelCase(name) {
    return name.
      replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
        return offset ? letter.toUpperCase() : letter;
      }).
      replace(MOZ_HACK_REGEXP, 'Moz$1');
  }

  function JSONize(str) {
    try {       // if parsable already, return as it is
      JSON.parse(str);
      return str;
    } catch(e) { // if not parsable, change little
      return str
        // wrap keys without quote with valid double quote
        .replace(/([\$\w]+)\s*:/g, function(_, $1){return '"'+$1+'":'})
        // replacing single quote wrapped ones to double quote
        .replace(/'([^']+)'/g, function(_, $1){return '"'+$1+'"'})
    }
  }

  var Attr2Options = function($parse, $timeout, NavigatorGeolocation, GeoCoder) {

    /**
     * Returns the attributes of an element as hash
     * @memberof Attr2Options
     * @param {HTMLElement} el html element
     * @returns {Hash} attributes
     */
    var orgAttributes = function(el) {
      (el.length > 0) && (el = el[0]);
      var orgAttributes = {};
      for (var i=0; i<el.attributes.length; i++) {
        var attr = el.attributes[i];
        orgAttributes[attr.name] = attr.value;
      }
      return orgAttributes;
    };

    var toOptionValue = function(input, options) {
      var output, key=options.key, scope=options.scope;
      try { // 1. Number?
        var num = Number(input);
        if (isNaN(num)) {
          throw "Not a number";
        } else  {
          output = num;
        }
      } catch(err) {
        try { // 2.JSON?
          if (input.match(/^[\+\-]?[0-9\.]+,[ ]*\ ?[\+\-]?[0-9\.]+$/)) { // i.e "-1.0, 89.89"
            input = "["+input+"]";
          }
          output = JSON.parse(JSONize(input));
          if (output instanceof Array) {
            var t1stEl = output[0];
            if (t1stEl.constructor == Object) { // [{a:1}] : not lat/lng ones
            } else if (t1stEl.constructor == Array) { // [[1,2],[3,4]]
              output =  output.map(function(el) {
                return new google.maps.LatLng(el[0], el[1]);
              });
            } else if(!isNaN(parseFloat(t1stEl)) && isFinite(t1stEl)) {
              return new google.maps.LatLng(output[0], output[1]);
            }
          }
        } catch(err2) {
          // 3. Object Expression. i.e. LatLng(80,-49)
          if (input.match(/^[A-Z][a-zA-Z0-9]+\(.*\)$/)) {
            try {
              var exp = "new google.maps."+input;
              output = eval(exp); // TODO, still eval
            } catch(e) {
              output = input;
            }
          // 4. Object Expression. i.e. MayTypeId.HYBRID
          } else if (input.match(/^([A-Z][a-zA-Z0-9]+)\.([A-Z]+)$/)) {
            try {
              var matches = input.match(/^([A-Z][a-zA-Z0-9]+)\.([A-Z]+)$/);
              output = google.maps[matches[1]][matches[2]];
            } catch(e) {
              output = input;
            }
          // 5. Object Expression. i.e. HYBRID
          } else if (input.match(/^[A-Z]+$/)) {
            try {
              var capitalizedKey = key.charAt(0).toUpperCase() + key.slice(1);
              if (key.match(/temperatureUnit|windSpeedUnit|labelColor/)) {
                capitalizedKey = capitalizedKey.replace(/s$/,"");
                output = google.maps.weather[capitalizedKey][input];
              } else {
                output = google.maps[capitalizedKey][input];
              }
            } catch(e) {
              output = input;
            }
          } else {
            output = input;
          }
        } // catch(err2)
      } // catch(err)
      return output;
    };

    var getAttrsToObserve = function(attrs) {
      var attrsToObserve = [];
      if (attrs["ng-repeat"] || attrs.ngRepeat) {  // if element is created by ng-repeat, don't observe any
        void(0);
      } else {
        for (var attrName in attrs) {
          var attrValue = attrs[attrName];
          if (attrValue && attrValue.match(/\{\{.*\}\}/)) { // if attr value is {{..}}
            console.log('setting attribute to observe', attrName, camelCase(attrName), attrValue);
            attrsToObserve.push(camelCase(attrName));
          }
        }
      }
      return attrsToObserve;
    };

    /**
     * filters attributes by skipping angularjs methods $.. $$..
     * @memberof Attr2Options
     * @param {Hash} attrs tag attributes
     * @returns {Hash} filterd attributes
     */
    var filter = function(attrs) {
      var options = {};
      for(var key in attrs) {
        if (key.match(/^\$/) || key.match(/^ng[A-Z]/)) {
          void(0);
        } else {
          options[key] = attrs[key];
        }
      }
      return options;
    };

    /**
     * converts attributes hash to Google Maps API v3 options
     * ```
     *  . converts numbers to number
     *  . converts class-like string to google maps instance
     *    i.e. `LatLng(1,1)` to `new google.maps.LatLng(1,1)`
     *  . converts constant-like string to google maps constant
     *    i.e. `MapTypeId.HYBRID` to `google.maps.MapTypeId.HYBRID`
     *    i.e. `HYBRID"` to `google.maps.MapTypeId.HYBRID`
     * ```
     * @memberof Attr2Options
     * @param {Hash} attrs tag attributes
     * @param {scope} scope angularjs scope
     * @returns {Hash} options converted attributess
     */
    var getOptions = function(attrs, scope) {
      var options = {};
      for(var key in attrs) {
        if (attrs[key]) {
          if (key.match(/^on[A-Z]/)) { //skip events, i.e. on-click
            continue;
          } else if (key.match(/ControlOptions$/)) { // skip controlOptions
            continue;
          } else {
            options[key] = toOptionValue(attrs[key], {scope:scope, key: key});
          }
        } // if (attrs[key])
      } // for(var key in attrs)
      return options;
    };

    /**
     * converts attributes hash to scope-specific event function
     * @memberof Attr2Options
     * @param {scope} scope angularjs scope
     * @param {Hash} attrs tag attributes
     * @returns {Hash} events converted events
     */
    var getEvents = function(scope, attrs) {
      var events = {};
      var toLowercaseFunc = function($1){
        return "_"+$1.toLowerCase();
      };
      var eventFunc = function(attrValue) {
        var matches = attrValue.match(/([^\(]+)\(([^\)]*)\)/);
        var funcName = matches[1];
        var argsStr = matches[2].replace(/event[ ,]*/,'');  //remove string 'event'
        var argsExpr = $parse("["+argsStr+"]"); //for perf when triggering event
        return function(event) {
          var args = argsExpr(scope); //get args here to pass updated model values
          function index(obj,i) {return obj[i];}
          var f = funcName.split('.').reduce(index, scope);
          f && f.apply(this, [event].concat(args));
          $timeout( function() {
            scope.$apply();
          });
        };
      };

      for(var key in attrs) {
        if (attrs[key]) {
          if (!key.match(/^on[A-Z]/)) { //skip if not events
            continue;
          }

          //get event name as underscored. i.e. zoom_changed
          var eventName = key.replace(/^on/,'');
          eventName = eventName.charAt(0).toLowerCase() + eventName.slice(1);
          eventName = eventName.replace(/([A-Z])/g, toLowercaseFunc);

          var attrValue = attrs[key];
          events[eventName] = new eventFunc(attrValue);
        }
      }
      return events;
    };

    /**
     * control means map controls, i.e streetview, pan, etc, not a general control
     * @memberof Attr2Options
     * @param {Hash} filtered filtered tag attributes
     * @returns {Hash} Google Map options
     */
    var getControlOptions = function(filtered) {
      var controlOptions = {};
      if (typeof filtered != 'object') {
        return false;
      }

      for (var attr in filtered) {
        if (filtered[attr]) {
          if (!attr.match(/(.*)ControlOptions$/)) {
            continue; // if not controlOptions, skip it
          }

          //change invalid json to valid one, i.e. {foo:1} to {"foo": 1}
          var orgValue = filtered[attr];
          var newValue = orgValue.replace(/'/g, '"');
          newValue = newValue.replace(/([^"]+)|("[^"]+")/g, function($0, $1, $2) {
            if ($1) {
              return $1.replace(/([a-zA-Z0-9]+?):/g, '"$1":');
            } else {
              return $2;
            }
          });
          try {
            var options = JSON.parse(newValue);
            for (var key in options) { //assign the right values
              if (options[key]) {
                var value = options[key];
                if (typeof value === 'string') {
                  value = value.toUpperCase();
                } else if (key === "mapTypeIds") {
                  value = value.map( function(str) {
                    if (str.match(/^[A-Z]+$/)) { // if constant
                      return google.maps.MapTypeId[str.toUpperCase()];
                    } else { // else, custom map-type
                      return str;
                    }
                  });
                }

                if (key === "style") {
                  var str = attr.charAt(0).toUpperCase() + attr.slice(1);
                  var objName = str.replace(/Options$/,'')+"Style";
                  options[key] = google.maps[objName][value];
                } else if (key === "position") {
                  options[key] = google.maps.ControlPosition[value];
                } else {
                  options[key] = value;
                }
              }
            }
            controlOptions[attr] = options;
          } catch (e) {
            console.error('invald option for', attr, newValue, e, e.stack);
          }
        }
      } // for

      return controlOptions;
    };

    return {
      camelCase: camelCase,
      filter: filter,
      getOptions: getOptions,
      getEvents: getEvents,
      getControlOptions: getControlOptions,
      toOptionValue: toOptionValue,
      getAttrsToObserve: getAttrsToObserve,
      orgAttributes: orgAttributes
    }; // return

  };
  Attr2Options.$inject= ['$parse', '$timeout', 'NavigatorGeolocation', 'GeoCoder'];

  angular.module('ngMap').service('Attr2Options', Attr2Options);
})();
<commit_msg>(fix) Convert date in options hash to Date object   - Convert attributes with nested hashes to Google API options<commit_after>/**
 * @ngdoc service
 * @name Attr2Options
 * @description
 *   Converts tag attributes to options used by google api v3 objects, map, marker, polygon, circle, etc.
 */
/* global google */
(function() {
  'use strict';

  var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
  var MOZ_HACK_REGEXP = /^moz([A-Z])/;

  function camelCase(name) {
    return name.
      replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
        return offset ? letter.toUpperCase() : letter;
      }).
      replace(MOZ_HACK_REGEXP, 'Moz$1');
  }

  function JSONize(str) {
    try {       // if parsable already, return as it is
      JSON.parse(str);
      return str;
    } catch(e) { // if not parsable, change little
      return str
        // wrap keys without quote with valid double quote
        .replace(/([\$\w]+)\s*:/g, function(_, $1){return '"'+$1+'":'})
        // replacing single quote wrapped ones to double quote
        .replace(/'([^']+)'/g, function(_, $1){return '"'+$1+'"'})
    }
  }

  var Attr2Options = function($parse, $timeout, NavigatorGeolocation, GeoCoder) {

    /**
     * Returns the attributes of an element as hash
     * @memberof Attr2Options
     * @param {HTMLElement} el html element
     * @returns {Hash} attributes
     */
    var orgAttributes = function(el) {
      (el.length > 0) && (el = el[0]);
      var orgAttributes = {};
      for (var i=0; i<el.attributes.length; i++) {
        var attr = el.attributes[i];
        orgAttributes[attr.name] = attr.value;
      }
      return orgAttributes;
    };

    var toOptionValue = function(input, options) {
      var output, key=options.key, scope=options.scope;
      try { // 1. Number?
        var num = Number(input);
        if (isNaN(num)) {
          throw "Not a number";
        } else  {
          output = num;
        }
      } catch(err) {
        try { // 2.JSON?
          if (input.match(/^[\+\-]?[0-9\.]+,[ ]*\ ?[\+\-]?[0-9\.]+$/)) { // i.e "-1.0, 89.89"
            input = "["+input+"]";
          }
          output = JSON.parse(JSONize(input));
          if (output instanceof Array) {
            var t1stEl = output[0];
            if (t1stEl.constructor == Object) { // [{a:1}] : not lat/lng ones
            } else if (t1stEl.constructor == Array) { // [[1,2],[3,4]]
              output =  output.map(function(el) {
                return new google.maps.LatLng(el[0], el[1]);
              });
            } else if(!isNaN(parseFloat(t1stEl)) && isFinite(t1stEl)) {
              return new google.maps.LatLng(output[0], output[1]);
            }
          }
          else if (output === Object(output)) { // JSON is an object (not array or null)
            // check for nested hashes and convert to Google API options
            output = getOptions(output, options);
          }
        } catch(err2) {
          // 3. Object Expression. i.e. LatLng(80,-49)
          if (input.match(/^[A-Z][a-zA-Z0-9]+\(.*\)$/)) {
            try {
              var exp = "new google.maps."+input;
              output = eval(exp); // TODO, still eval
            } catch(e) {
              output = input;
            }
          // 4. Object Expression. i.e. MayTypeId.HYBRID
          } else if (input.match(/^([A-Z][a-zA-Z0-9]+)\.([A-Z]+)$/)) {
            try {
              var matches = input.match(/^([A-Z][a-zA-Z0-9]+)\.([A-Z]+)$/);
              output = google.maps[matches[1]][matches[2]];
            } catch(e) {
              output = input;
            }
          // 5. Object Expression. i.e. HYBRID
          } else if (input.match(/^[A-Z]+$/)) {
            try {
              var capitalizedKey = key.charAt(0).toUpperCase() + key.slice(1);
              if (key.match(/temperatureUnit|windSpeedUnit|labelColor/)) {
                capitalizedKey = capitalizedKey.replace(/s$/,"");
                output = google.maps.weather[capitalizedKey][input];
              } else {
                output = google.maps[capitalizedKey][input];
              }
            } catch(e) {
              output = input;
            }
          // 6. Date Object as ISO String i.e. "2015-08-12T06:12:40.858Z"
          } else if (input.match(/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/)) {
            try {
              output = new Date(input);
            } catch(e) {
              output = input;
            }
          } else {
            output = input;
          }
        } // catch(err2)
      } // catch(err)
      return output;
    };

    var getAttrsToObserve = function(attrs) {
      var attrsToObserve = [];
      if (attrs["ng-repeat"] || attrs.ngRepeat) {  // if element is created by ng-repeat, don't observe any
        void(0);
      } else {
        for (var attrName in attrs) {
          var attrValue = attrs[attrName];
          if (attrValue && attrValue.match(/\{\{.*\}\}/)) { // if attr value is {{..}}
            console.log('setting attribute to observe', attrName, camelCase(attrName), attrValue);
            attrsToObserve.push(camelCase(attrName));
          }
        }
      }
      return attrsToObserve;
    };

    /**
     * filters attributes by skipping angularjs methods $.. $$..
     * @memberof Attr2Options
     * @param {Hash} attrs tag attributes
     * @returns {Hash} filterd attributes
     */
    var filter = function(attrs) {
      var options = {};
      for(var key in attrs) {
        if (key.match(/^\$/) || key.match(/^ng[A-Z]/)) {
          void(0);
        } else {
          options[key] = attrs[key];
        }
      }
      return options;
    };

    /**
     * converts attributes hash to Google Maps API v3 options
     * ```
     *  . converts numbers to number
     *  . converts class-like string to google maps instance
     *    i.e. `LatLng(1,1)` to `new google.maps.LatLng(1,1)`
     *  . converts constant-like string to google maps constant
     *    i.e. `MapTypeId.HYBRID` to `google.maps.MapTypeId.HYBRID`
     *    i.e. `HYBRID"` to `google.maps.MapTypeId.HYBRID`
     * ```
     * @memberof Attr2Options
     * @param {Hash} attrs tag attributes
     * @param {scope} scope angularjs scope
     * @returns {Hash} options converted attributess
     */
    var getOptions = function(attrs, scope) {
      var options = {};
      for(var key in attrs) {
        if (attrs[key]) {
          if (key.match(/^on[A-Z]/)) { //skip events, i.e. on-click
            continue;
          } else if (key.match(/ControlOptions$/)) { // skip controlOptions
            continue;
          } else {
            // nested conversions need to be typechecked (non-strings are fully converted)
            if (typeof attrs[key] !== 'string') {
              options[key] = attrs[key];
            } else {
              options[key] = toOptionValue(attrs[key], {scope:scope, key: key});
            }
          }
        } // if (attrs[key])
      } // for(var key in attrs)
      return options;
    };

    /**
     * converts attributes hash to scope-specific event function
     * @memberof Attr2Options
     * @param {scope} scope angularjs scope
     * @param {Hash} attrs tag attributes
     * @returns {Hash} events converted events
     */
    var getEvents = function(scope, attrs) {
      var events = {};
      var toLowercaseFunc = function($1){
        return "_"+$1.toLowerCase();
      };
      var eventFunc = function(attrValue) {
        var matches = attrValue.match(/([^\(]+)\(([^\)]*)\)/);
        var funcName = matches[1];
        var argsStr = matches[2].replace(/event[ ,]*/,'');  //remove string 'event'
        var argsExpr = $parse("["+argsStr+"]"); //for perf when triggering event
        return function(event) {
          var args = argsExpr(scope); //get args here to pass updated model values
          function index(obj,i) {return obj[i];}
          var f = funcName.split('.').reduce(index, scope);
          f && f.apply(this, [event].concat(args));
          $timeout( function() {
            scope.$apply();
          });
        };
      };

      for(var key in attrs) {
        if (attrs[key]) {
          if (!key.match(/^on[A-Z]/)) { //skip if not events
            continue;
          }

          //get event name as underscored. i.e. zoom_changed
          var eventName = key.replace(/^on/,'');
          eventName = eventName.charAt(0).toLowerCase() + eventName.slice(1);
          eventName = eventName.replace(/([A-Z])/g, toLowercaseFunc);

          var attrValue = attrs[key];
          events[eventName] = new eventFunc(attrValue);
        }
      }
      return events;
    };

    /**
     * control means map controls, i.e streetview, pan, etc, not a general control
     * @memberof Attr2Options
     * @param {Hash} filtered filtered tag attributes
     * @returns {Hash} Google Map options
     */
    var getControlOptions = function(filtered) {
      var controlOptions = {};
      if (typeof filtered != 'object') {
        return false;
      }

      for (var attr in filtered) {
        if (filtered[attr]) {
          if (!attr.match(/(.*)ControlOptions$/)) {
            continue; // if not controlOptions, skip it
          }

          //change invalid json to valid one, i.e. {foo:1} to {"foo": 1}
          var orgValue = filtered[attr];
          var newValue = orgValue.replace(/'/g, '"');
          newValue = newValue.replace(/([^"]+)|("[^"]+")/g, function($0, $1, $2) {
            if ($1) {
              return $1.replace(/([a-zA-Z0-9]+?):/g, '"$1":');
            } else {
              return $2;
            }
          });
          try {
            var options = JSON.parse(newValue);
            for (var key in options) { //assign the right values
              if (options[key]) {
                var value = options[key];
                if (typeof value === 'string') {
                  value = value.toUpperCase();
                } else if (key === "mapTypeIds") {
                  value = value.map( function(str) {
                    if (str.match(/^[A-Z]+$/)) { // if constant
                      return google.maps.MapTypeId[str.toUpperCase()];
                    } else { // else, custom map-type
                      return str;
                    }
                  });
                }

                if (key === "style") {
                  var str = attr.charAt(0).toUpperCase() + attr.slice(1);
                  var objName = str.replace(/Options$/,'')+"Style";
                  options[key] = google.maps[objName][value];
                } else if (key === "position") {
                  options[key] = google.maps.ControlPosition[value];
                } else {
                  options[key] = value;
                }
              }
            }
            controlOptions[attr] = options;
          } catch (e) {
            console.error('invald option for', attr, newValue, e, e.stack);
          }
        }
      } // for

      return controlOptions;
    };

    return {
      camelCase: camelCase,
      filter: filter,
      getOptions: getOptions,
      getEvents: getEvents,
      getControlOptions: getControlOptions,
      toOptionValue: toOptionValue,
      getAttrsToObserve: getAttrsToObserve,
      orgAttributes: orgAttributes
    }; // return

  };
  Attr2Options.$inject= ['$parse', '$timeout', 'NavigatorGeolocation', 'GeoCoder'];

  angular.module('ngMap').service('Attr2Options', Attr2Options);
})();
<|endoftext|>


<commit_before>var _ = require('lodash');

var TelnetDevice = require('../lib/telnet-device');
var ConfigCheckpoint = require('./config-checkpoint');
var DataReader = require('./data-reader');

var logger = require('../lib/logger')('device');
var helpers = require('../lib/hash-helpers');
var schema = require('../lib/redis-schema');
var hashkeys = require('../lib/device-hashkeys');

function DeviceRouter(redis,deviceKey,note){
    var self = this;
    self.redis = redis;
    self.deviceKey = deviceKey;
    self.queueKey = schema.device.queue.useParam(deviceKey);
    self.messageBase = {queueKey: self.queueKey};
    self.settingsKey = schema.device.settings.useParam(deviceKey);
    self.noteStatus = note || function(){};

    self.status = 'pending';
    self.connectionChk = new ConfigCheckpoint(redis,self.settingsKey,hashkeys.connection,helpers.requirements(hashkeys.connection)).start(function(connectionEvent,connectionConfig){
        if (connectionEvent !== 'ready') return;

        switch(connectionConfig.type){
            case 'telnet':
                self.device = new TelnetDevice({host: connectionConfig.telnetAddress,port: connectionConfig.telnetPort});
                break;
            default:
                return self.noteStatus(self.status = 'error','unavailable connection type(' + self.deviceKey +'): ' + connectionConfig.type);
        }
        self.routeChk = new ConfigCheckpoint(redis,self.settingsKey,hashkeys.route,helpers.requirements(hashkeys.route)).start(function(routeEvent,routeConfig){
            if (routeEvent !== 'ready') return;

            switch(routeConfig.type){
                case 'none':
                    return self.noteStatus(self.status = 'off');
                case 'ad-hoc':
                    break;
                default:
                    return self.noteStatus(self.status = 'error','unavailable route type(' + self.deviceKey +'): ' + routeConfig.type)
            }
            self.reader = new DataReader(self.device).start(_.bind(self.readerEvent,self,_));
            self.noteStatus(self.status = 'ready');
        });
    });
}

DeviceRouter.prototype.readerEvent = function(event){
    var self = this;
    switch(self.status){
        case 'ready':
            break;
        case 'pending':
            switch(event){
                case 'ready':
                    return self.noteStatus(self.status = 'ready');
                case 'retry':
                    break;
                default:
                    return self.noteStatus(self.status = 'error','unexpected reader event(' + self.deviceKey +'): ' + event);
            }
            break;
        default:
            logger.error('ignore reader event(' + self.deviceKey + '): ' + event);
    }
};

DeviceRouter.prototype.noteAck = function(sequenceNumber){
    logger.info('ack(' + self.deviceKey + ') received: ' + sequenceNumber);
};

DeviceRouter.prototype.noteError = function(sequenceNumber){
    logger.info('error(' + self.deviceKey + ') received: ' + sequenceNumber);
};

DeviceRouter.prototype.processQueueEntry = function(entry){
    var self = this;
    logger.info('queue entry(' + self.deviceKey + '): ' + JSON.stringify(entry));
    if (entry && typeof entry === 'object' && entry.command)
        self.reader.submit(entry.command,function(error,command,response){
            if (error)
                logger.error('error(' + self.deviceKey + '): ' + error);
            else
                logger.info('response(' + self.deviceKey + '): ' + response);
            self.redis.lpush(schema.transmit.queue.key,JSON.stringify(_.defaults(self.messageBase,{
                10: command,
                11: response,
                12: error
            })));
        });
};

module.exports = DeviceRouter;<commit_msg>make sure the "messageBase" doesn't get updated...<commit_after>var _ = require('lodash');

var TelnetDevice = require('../lib/telnet-device');
var ConfigCheckpoint = require('./config-checkpoint');
var DataReader = require('./data-reader');

var logger = require('../lib/logger')('device');
var helpers = require('../lib/hash-helpers');
var schema = require('../lib/redis-schema');
var hashkeys = require('../lib/device-hashkeys');

function DeviceRouter(redis,deviceKey,note){
    var self = this;
    self.redis = redis;
    self.deviceKey = deviceKey;
    self.queueKey = schema.device.queue.useParam(deviceKey);
    self.messageBase = {queueKey: self.queueKey};
    self.settingsKey = schema.device.settings.useParam(deviceKey);
    self.noteStatus = note || function(){};

    self.status = 'pending';
    self.connectionChk = new ConfigCheckpoint(redis,self.settingsKey,hashkeys.connection,helpers.requirements(hashkeys.connection)).start(function(connectionEvent,connectionConfig){
        if (connectionEvent !== 'ready') return;

        switch(connectionConfig.type){
            case 'telnet':
                self.device = new TelnetDevice({host: connectionConfig.telnetAddress,port: connectionConfig.telnetPort});
                break;
            default:
                return self.noteStatus(self.status = 'error','unavailable connection type(' + self.deviceKey +'): ' + connectionConfig.type);
        }
        self.routeChk = new ConfigCheckpoint(redis,self.settingsKey,hashkeys.route,helpers.requirements(hashkeys.route)).start(function(routeEvent,routeConfig){
            if (routeEvent !== 'ready') return;

            switch(routeConfig.type){
                case 'none':
                    return self.noteStatus(self.status = 'off');
                case 'ad-hoc':
                    break;
                default:
                    return self.noteStatus(self.status = 'error','unavailable route type(' + self.deviceKey +'): ' + routeConfig.type)
            }
            self.reader = new DataReader(self.device).start(_.bind(self.readerEvent,self,_));
            self.noteStatus(self.status = 'ready');
        });
    });
}

DeviceRouter.prototype.readerEvent = function(event){
    var self = this;
    switch(self.status){
        case 'ready':
            break;
        case 'pending':
            switch(event){
                case 'ready':
                    return self.noteStatus(self.status = 'ready');
                case 'retry':
                    break;
                default:
                    return self.noteStatus(self.status = 'error','unexpected reader event(' + self.deviceKey +'): ' + event);
            }
            break;
        default:
            logger.error('ignore reader event(' + self.deviceKey + '): ' + event);
    }
};

DeviceRouter.prototype.noteAck = function(sequenceNumber){
    logger.info('ack(' + self.deviceKey + ') received: ' + sequenceNumber);
};

DeviceRouter.prototype.noteError = function(sequenceNumber){
    logger.info('error(' + self.deviceKey + ') received: ' + sequenceNumber);
};

DeviceRouter.prototype.processQueueEntry = function(entry){
    var self = this;
    logger.info('queue entry(' + self.deviceKey + '): ' + JSON.stringify(entry));
    if (entry && typeof entry === 'object' && entry.command)
        self.reader.submit(entry.command,function(error,command,response){
            if (error)
                logger.error('error(' + self.deviceKey + '): ' + error);
            else
                logger.info('response(' + self.deviceKey + '): ' + response);
            self.redis.lpush(schema.transmit.queue.key,JSON.stringify(_.defaults({},self.messageBase,{
                10: command,
                11: response,
                12: error
            })));
        });
};

module.exports = DeviceRouter;<|endoftext|>


<commit_before>(function(window) {

  var hasLocalStorage;
  var LS_STATE_KEY = "remotestorage:widget:state";
  // states allowed to immediately jump into after a reload.
  var VALID_ENTRY_STATES = {
    initial: true,
    connected: true,
    offline: true
  };

  function stateSetter(widget, state) {
    return function() {
      if (hasLocalStorage) {
        localStorage[LS_STATE_KEY] = state;
      }
      if (widget.view) {
        if (widget.rs.remote) {
          widget.view.setUserAddress(widget.rs.remote.userAddress);
        }
        widget.view.setState(state, arguments);
      } else {
        widget._rememberedState = state;
      }
    };
  }

  function errorsHandler(widget){
    //decided to not store error state
    return function(error){
      if (error instanceof RemoteStorage.DiscoveryError) {
        console.error('discovery failed',  error, '"' + error.message + '"');
        widget.view.setState('initial', [error.message]);
      } else if (error instanceof RemoteStorage.SyncError) {
        widget.view.setState('offline', []);
      } else if (error instanceof RemoteStorage.Unauthorized){
        widget.view.setState('unauthorized');
      } else {
        widget.view.setState('error', [error]);
      }
    };
  }

  function flashFor(evt) {
    if (evt.method === 'GET' && evt.isFolder) {
      return false;
    }
    return true;
  }

  /**
   * Class: RemoteStorage.Widget
   *   the Widget Controler that comunicates with the view
   *   and listens to its remoteStorage instance
   *
   *   While listening to the Events emitted by its remoteStorage
   *   it set's corresponding states of the View.
   *
   *   ready        :  connected
   *   disconnected :  initial
   *   connecting   :  authing
   *   authing      :  authing
   *   wire-busy    :  busy
   *   wire-done    :  connected
   *   error        :  depending on the error initial,offline, unauthorized or error
   **/
  RemoteStorage.Widget = function(remoteStorage) {
    this.requestsToFlashFor = 0;
    // setting event listeners on rs events to put
    // the widget into corresponding states
    this.rs = remoteStorage;
    this.rs.on('ready', stateSetter(this, 'connected'));
    this.rs.on('disconnected', stateSetter(this, 'initial'));
    this.rs.on('connecting', stateSetter(this, 'authing'));
    this.rs.on('authing', stateSetter(this, 'authing'));
    if(this.rs.remote) {
      this.rs.remote.on('wire-busy', function(evt) {
        if(flashFor(evt)) {
          this.requestsToFlashFor++;
          stateSetter(this, 'busy')();
        }
      }.bind(this));
      this.rs.remote.on('wire-done', function(evt) {
        if(flashFor(evt) && this.requestsToFlashFor === 0) {
          stateSetter(this, 'connected')();
        }
      }.bind(this));
    }
    this.rs.on('error', errorsHandler(this) );
    if (hasLocalStorage) {
      var state = localStorage[LS_STATE_KEY];
      if (state && VALID_ENTRY_STATES[state]) {
        this._rememberedState = state;

        if (state === 'connected' && ! remoteStorage.connected) {
          this._rememberedState = 'initial';
        }
      }
    }
  };

  RemoteStorage.Widget.prototype = {

    /**
    *   Method: display(domID)
    *     displays the widget via the view.display method
    *     returns: this
    **/
    display: function(domID) {
      if (! this.view) {
        this.setView(new RemoteStorage.Widget.View(this.rs));
      }
      this.view.display.apply(this.view, arguments);
      return this;
    },

    /**
    *   Method: setView(view)
    *    sets the view and initializes event listeners to
    *    react on widget(widget.view) events
    **/
    setView: function(view) {
      this.view = view;
      this.view.on('connect', function(options) {
        if (typeof(options) === 'string') {
          // options is simply a useraddress
          this.rs.connect(options);
        } else if (options.special) {
          this.rs[options.special].connect(options);
        }
      }.bind(this));
      this.view.on('disconnect', this.rs.disconnect.bind(this.rs));
      if (this.rs.sync) {
        this.view.on('sync', this.rs.sync.bind(this.rs));
      }
      try {
        this.view.on('reset', function(){
          var location = RemoteStorage.Authorize.getLocation();
          this.rs.on('disconnected', location.reload.bind(location));
          this.rs.disconnect();
        }.bind(this));
      } catch(e) {
        if (e.message && e.message.match(/Unknown event/)) {
          // ignored. (the 0.7 widget-view interface didn't have a 'reset' event)
        } else {
          throw e;
        }
      }

      if (this._rememberedState) {
        setTimeout(stateSetter(this, this._rememberedState), 0);
        delete this._rememberedState;
      }
    }
  };
  /**
   *  Method: displayWidget(domID)
   *    same as display
   **/
  RemoteStorage.prototype.displayWidget = function(domID) {
    return this.widget.display(domID);
  };

  RemoteStorage.Widget._rs_init = function(remoteStorage) {
    hasLocalStorage = remoteStorage.localStorageAvailable();
    if (! remoteStorage.widget) {
      remoteStorage.widget = new RemoteStorage.Widget(remoteStorage);
    }
  };

  RemoteStorage.Widget._rs_supported = function(remoteStorage) {
    return typeof(document) !== 'undefined';
  };

})(typeof(window) !== 'undefined' ? window : global);
<commit_msg>Make widget stop pulsing after all requests are done<commit_after>(function(window) {

  var hasLocalStorage;
  var LS_STATE_KEY = "remotestorage:widget:state";
  // states allowed to immediately jump into after a reload.
  var VALID_ENTRY_STATES = {
    initial: true,
    connected: true,
    offline: true
  };

  function stateSetter(widget, state) {
    return function() {
      if (hasLocalStorage) {
        localStorage[LS_STATE_KEY] = state;
      }
      if (widget.view) {
        if (widget.rs.remote) {
          widget.view.setUserAddress(widget.rs.remote.userAddress);
        }
        widget.view.setState(state, arguments);
      } else {
        widget._rememberedState = state;
      }
    };
  }

  function errorsHandler(widget){
    //decided to not store error state
    return function(error){
      if (error instanceof RemoteStorage.DiscoveryError) {
        console.error('discovery failed',  error, '"' + error.message + '"');
        widget.view.setState('initial', [error.message]);
      } else if (error instanceof RemoteStorage.SyncError) {
        widget.view.setState('offline', []);
      } else if (error instanceof RemoteStorage.Unauthorized){
        widget.view.setState('unauthorized');
      } else {
        widget.view.setState('error', [error]);
      }
    };
  }

  function flashFor(evt) {
    if (evt.method === 'GET' && evt.isFolder) {
      return false;
    }
    return true;
  }

  /**
   * Class: RemoteStorage.Widget
   *   the Widget Controler that comunicates with the view
   *   and listens to its remoteStorage instance
   *
   *   While listening to the Events emitted by its remoteStorage
   *   it set's corresponding states of the View.
   *
   *   ready        :  connected
   *   disconnected :  initial
   *   connecting   :  authing
   *   authing      :  authing
   *   wire-busy    :  busy
   *   wire-done    :  connected
   *   error        :  depending on the error initial,offline, unauthorized or error
   **/
  RemoteStorage.Widget = function(remoteStorage) {
    var requestsToFlashFor = 0;

    // setting event listeners on rs events to put
    // the widget into corresponding states
    this.rs = remoteStorage;
    this.rs.on('ready', stateSetter(this, 'connected'));
    this.rs.on('disconnected', stateSetter(this, 'initial'));
    this.rs.on('connecting', stateSetter(this, 'authing'));
    this.rs.on('authing', stateSetter(this, 'authing'));
    this.rs.on('error', errorsHandler(this));

    if (this.rs.remote) {
      this.rs.remote.on('wire-busy', function(evt) {
        if (flashFor(evt)) {
          requestsToFlashFor++;
          stateSetter(this, 'busy')();
        }
      }.bind(this));

      this.rs.remote.on('wire-done', function(evt) {
        if (flashFor(evt)) {
          requestsToFlashFor--;
          if (requestsToFlashFor <= 0) {
            stateSetter(this, 'connected')();
          }
        }
      }.bind(this));
    }

    if (hasLocalStorage) {
      var state = localStorage[LS_STATE_KEY];
      if (state && VALID_ENTRY_STATES[state]) {
        this._rememberedState = state;

        if (state === 'connected' && ! remoteStorage.connected) {
          this._rememberedState = 'initial';
        }
      }
    }
  };

  RemoteStorage.Widget.prototype = {

    /**
    *   Method: display(domID)
    *     displays the widget via the view.display method
    *     returns: this
    **/
    display: function(domID) {
      if (! this.view) {
        this.setView(new RemoteStorage.Widget.View(this.rs));
      }
      this.view.display.apply(this.view, arguments);
      return this;
    },

    /**
    *   Method: setView(view)
    *    sets the view and initializes event listeners to
    *    react on widget(widget.view) events
    **/
    setView: function(view) {
      this.view = view;
      this.view.on('connect', function(options) {
        if (typeof(options) === 'string') {
          // options is simply a useraddress
          this.rs.connect(options);
        } else if (options.special) {
          this.rs[options.special].connect(options);
        }
      }.bind(this));
      this.view.on('disconnect', this.rs.disconnect.bind(this.rs));
      if (this.rs.sync) {
        this.view.on('sync', this.rs.sync.bind(this.rs));
      }
      try {
        this.view.on('reset', function(){
          var location = RemoteStorage.Authorize.getLocation();
          this.rs.on('disconnected', location.reload.bind(location));
          this.rs.disconnect();
        }.bind(this));
      } catch(e) {
        if (e.message && e.message.match(/Unknown event/)) {
          // ignored. (the 0.7 widget-view interface didn't have a 'reset' event)
        } else {
          throw e;
        }
      }

      if (this._rememberedState) {
        setTimeout(stateSetter(this, this._rememberedState), 0);
        delete this._rememberedState;
      }
    }
  };
  /**
   *  Method: displayWidget(domID)
   *    same as display
   **/
  RemoteStorage.prototype.displayWidget = function(domID) {
    return this.widget.display(domID);
  };

  RemoteStorage.Widget._rs_init = function(remoteStorage) {
    hasLocalStorage = remoteStorage.localStorageAvailable();
    if (! remoteStorage.widget) {
      remoteStorage.widget = new RemoteStorage.Widget(remoteStorage);
    }
  };

  RemoteStorage.Widget._rs_supported = function(remoteStorage) {
    return typeof(document) !== 'undefined';
  };

})(typeof(window) !== 'undefined' ? window : global);
<|endoftext|>


<commit_before>(function() {

  function stateSetter(widget, state) {
    return function() {
      if(widget.view) {
        if(widget.rs.remote) {
          widget.view.setUserAddress(widget.rs.remote.userAddress);
        }
        widget.view.setState(state);
      }
    };
  }

  RemoteStorage.Widget = function(remoteStorage) {
    this.rs = remoteStorage;
    this.rs.on('ready', stateSetter(this, 'connected'));
    this.rs.on('disconnected', stateSetter(this, 'initial'));
    //this.rs.on('connecting', stateSetter(this, 'connecting'))
    this.rs.on('authing', stateSetter(this, 'authing'));
    this.rs.on('sync-busy', stateSetter(this, 'busy'));
    this.rs.on('sync-done', stateSetter(this, 'connected'));
  };

  RemoteStorage.Widget.prototype = {
    display: function() {
      if(! this.view) {
        this.setView(new View());
      }
      this.view.display.apply(this.view, arguments);
      return this;
    },

    setView: function(view) {
      this.view = view;
      this.view.on('connect', this.rs.connect.bind(this));
      this.view.on('disconnect', this.rs.disconnect.bind(this));
      this.view.on('sync', this.rs.sync.bind(this));
    }
  };

  RemoteStorage.prototype.displayWidget = function() {
    this.widget.display();
  };

  RemoteStorage.Widget._rs_init = function(remoteStorage) {
    remoteStorage.widget = new RemoteStorage.Widget(remoteStorage);
    window.addEventListener('load', function() {
      remoteStorage.displayWidget();
    });
  };

  var cEl = document.createElement.bind(document);

  function gCl(parent, className) {
    return parent.getElementsByClassName(className)[0];
  }
  function gTl(parent, className) {
    return parent.getElementsByTagName(className)[0];
  }

  function toggle_bubble(widget) {
    var el = gCl(widget,'bubble');
    if(el.className.search('hidden') < 0) {
      addClass(el, 'hidden');
    } else {
      removeClass(el, 'hidden');
      gTl(widget, 'form').userAddress.focus();
    }
  }

  function show(el, display) {
    if(typeof(display) === 'undefined') {
      display = 'block';
    }
    el.style.display = display;
    return el;
  }

  function hide(el) {
    show(el,'none');
    return el;
  }

  // MAYBE do those two in a el.className.split(' ') way more safe
  function removeClass(el, className) {
    el.className = el.className.split(' ').filter(function(val) {
      return val != className;
    }).join(' ');
  }

  function addClass(el, className) {
    el.className += ' ' + className;
  }

  function View() {
    if(typeof(document) === 'undefined') {
      throw "Widget not supported";
    }
    RemoteStorage.eventHandling(this,
                                'connect',
                                'disconnect',
                                'sync',
                                'reconnect',
                                'display');

    this.display = function() {

      if(typeof(this.widget) !== 'undefined')
        return this.widget;

      var element = cEl('div');
      var style = cEl('style');
      style.innerHTML = RemoteStorage.Assets.widgetCss;

      element.id = "remotestorage-widget";

      element.innerHTML = RemoteStorage.Assets.widget;

      element.appendChild(style);
      document.body.appendChild(element);

      var el;
      //sync button
      el = gCl(element, 'sync');
      gTl(el, 'img').src = RemoteStorage.Assets.syncIcon;
      el.addEventListener('click', this.events.sync.bind(this));

      //disconnect button
      el = gCl(element, 'disconnect');
      gTl(el, 'img').src = RemoteStorage.Assets.disconnectIcon;
      el.addEventListener('click', this.events.disconnect.bind(this));

      //connect button
      var cb = gCl(element,'connect');
      gTl(cb, 'img').src = RemoteStorage.Assets.connectIcon;
      cb.addEventListener('click', this.events.connect.bind(this));

      // input
      el = gTl(element, 'form').userAddress;
      el.addEventListener('keyup', function(event) {
        if(event.target.value) cb.removeAttribute('disabled');
        else cb.setAttribute('disabled','disabled');
      });

      //the cube
      el = gCl(element, 'cube');
      el.src = RemoteStorage.Assets.remoteStorageIcon;
      el.addEventListener('click', function() {
        toggle_bubble(this.div);
      }.bind(this));

      this.div = element;

      this.states.initial.call(this);
      this._emit('display');
      return this.div;
    };

    this.setState = function(state) {
      var s = this.states[state];
      if(typeof(s) === 'undefined') {
        throw new Error("Bad State assigned to view: " + state);
      }
      s.call(this);
    };

    this.setUserAddress = function(addr) {
      this.userAddress = addr;
    };
  }

  View.prototype = {
    // States:
    //  initial      - not connected
    //  authing      - in auth flow
    //  connected    - connected to remote storage, not syncing at the moment
    //  busy         - connected, syncing at the moment
    //  offline      - connected, but no network connectivity
    //  error        - connected, but sync error happened
    //  unauthorized - connected, but request returned 401
    currentState : 'initial',
    states :  {
      initial : function() {
        this.div.className = "remotestorage-state-initial";
        gCl(this.div, 'status-text').innerHTML = "Connect remotestorage";
      },
      authing : function() {
        this.div.className = "remotestorage-state-authing";
        gCl(this.div, 'status-text').innerHTML = "Connecting";
        addClass(gCl(this.div, 'cube'), 'remotestorage-loading'); //TODO needs to be undone when is that neccesary
      },
      connected : function() {
        this.div.className = "remotestorage-state-connected";
        gCl(this.div, 'userAddress').innerHTML = this.userAddress;
        var cube = gCl(this.div, 'cube');
        cube.src = RemoteStorage.Assets.remoteStorageIcon;
        removeClass(cube, 'remotestorage-loading');
      },
      busy : function() {
        this.div.className = "remotestorage-state-busy";
        addClass(gCl(this.div, 'cube'), 'remotestorage-loading'); //TODO needs to be undone when is that neccesary
      },
      offline : function() {
        this.div.className = "remotestorage-state-offline";
        gCl(this.div, 'cube').src = RemoteStorage.Assets.remoteStorageIconOffline;
      },
      error : function() {
        this.div.className = "remotestorage-state-error";
        gCl(this.div, 'cube').src = RemoteStorage.Assets.remoteStorageIconError;
      },
      unauthorized : function() {
        this.div.className = "remotestorage-state-unauthorized";
      }
    },
    events : {
      connect : function(event) {
        event.preventDefault();
        this._emit('connect', gTl(this.div, 'form').userAddress.value);
      },
      sync : function(event) {
        event.preventDefault();
        this._emit('sync');
      },
      disconnect : function(event) {
        event.preventDefault();
        this._emit('disconnect');
      },
      // FIXME: what are these???
      reconnect : function() {},
      display : function() {}
    }
  };

})();
<commit_msg>widget: fixed binding of event handlers<commit_after>(function() {

  function stateSetter(widget, state) {
    return function() {
      if(widget.view) {
        if(widget.rs.remote) {
          widget.view.setUserAddress(widget.rs.remote.userAddress);
        }
        widget.view.setState(state);
      }
    };
  }

  RemoteStorage.Widget = function(remoteStorage) {
    this.rs = remoteStorage;
    this.rs.on('ready', stateSetter(this, 'connected'));
    this.rs.on('disconnected', stateSetter(this, 'initial'));
    //this.rs.on('connecting', stateSetter(this, 'connecting'))
    this.rs.on('authing', stateSetter(this, 'authing'));
    this.rs.on('sync-busy', stateSetter(this, 'busy'));
    this.rs.on('sync-done', stateSetter(this, 'connected'));
  };

  RemoteStorage.Widget.prototype = {
    display: function() {
      if(! this.view) {
        this.setView(new View());
      }
      this.view.display.apply(this.view, arguments);
      return this;
    },

    setView: function(view) {
      this.view = view;
      this.view.on('connect', this.rs.connect.bind(this.rs));
      this.view.on('disconnect', this.rs.disconnect.bind(this.rs));
      this.view.on('sync', this.rs.sync.bind(this.rs));
    }
  };

  RemoteStorage.prototype.displayWidget = function() {
    this.widget.display();
  };

  RemoteStorage.Widget._rs_init = function(remoteStorage) {
    remoteStorage.widget = new RemoteStorage.Widget(remoteStorage);
    window.addEventListener('load', function() {
      remoteStorage.displayWidget();
    });
  };

  var cEl = document.createElement.bind(document);

  function gCl(parent, className) {
    return parent.getElementsByClassName(className)[0];
  }
  function gTl(parent, className) {
    return parent.getElementsByTagName(className)[0];
  }

  function toggle_bubble(widget) {
    var el = gCl(widget,'bubble');
    if(el.className.search('hidden') < 0) {
      addClass(el, 'hidden');
    } else {
      removeClass(el, 'hidden');
      gTl(widget, 'form').userAddress.focus();
    }
  }

  function show(el, display) {
    if(typeof(display) === 'undefined') {
      display = 'block';
    }
    el.style.display = display;
    return el;
  }

  function hide(el) {
    show(el,'none');
    return el;
  }

  // MAYBE do those two in a el.className.split(' ') way more safe
  function removeClass(el, className) {
    el.className = el.className.split(' ').filter(function(val) {
      return val != className;
    }).join(' ');
  }

  function addClass(el, className) {
    el.className += ' ' + className;
  }

  function View() {
    if(typeof(document) === 'undefined') {
      throw "Widget not supported";
    }
    RemoteStorage.eventHandling(this,
                                'connect',
                                'disconnect',
                                'sync',
                                'reconnect',
                                'display');

    this.display = function() {

      if(typeof(this.widget) !== 'undefined')
        return this.widget;

      var element = cEl('div');
      var style = cEl('style');
      style.innerHTML = RemoteStorage.Assets.widgetCss;

      element.id = "remotestorage-widget";

      element.innerHTML = RemoteStorage.Assets.widget;

      element.appendChild(style);
      document.body.appendChild(element);

      var el;
      //sync button
      el = gCl(element, 'sync');
      gTl(el, 'img').src = RemoteStorage.Assets.syncIcon;
      el.addEventListener('click', this.events.sync.bind(this));

      //disconnect button
      el = gCl(element, 'disconnect');
      gTl(el, 'img').src = RemoteStorage.Assets.disconnectIcon;
      el.addEventListener('click', this.events.disconnect.bind(this));

      //connect button
      var cb = gCl(element,'connect');
      gTl(cb, 'img').src = RemoteStorage.Assets.connectIcon;
      cb.addEventListener('click', this.events.connect.bind(this));

      // input
      el = gTl(element, 'form').userAddress;
      el.addEventListener('keyup', function(event) {
        if(event.target.value) cb.removeAttribute('disabled');
        else cb.setAttribute('disabled','disabled');
      });

      //the cube
      el = gCl(element, 'cube');
      el.src = RemoteStorage.Assets.remoteStorageIcon;
      el.addEventListener('click', function() {
        toggle_bubble(this.div);
      }.bind(this));

      this.div = element;

      this.states.initial.call(this);
      this._emit('display');
      return this.div;
    };

    this.setState = function(state) {
      var s = this.states[state];
      if(typeof(s) === 'undefined') {
        throw new Error("Bad State assigned to view: " + state);
      }
      s.call(this);
    };

    this.setUserAddress = function(addr) {
      this.userAddress = addr;
    };
  }

  View.prototype = {
    // States:
    //  initial      - not connected
    //  authing      - in auth flow
    //  connected    - connected to remote storage, not syncing at the moment
    //  busy         - connected, syncing at the moment
    //  offline      - connected, but no network connectivity
    //  error        - connected, but sync error happened
    //  unauthorized - connected, but request returned 401
    currentState : 'initial',
    states :  {
      initial : function() {
        this.div.className = "remotestorage-state-initial";
        gCl(this.div, 'status-text').innerHTML = "Connect remotestorage";
      },
      authing : function() {
        this.div.className = "remotestorage-state-authing";
        gCl(this.div, 'status-text').innerHTML = "Connecting";
        addClass(gCl(this.div, 'cube'), 'remotestorage-loading'); //TODO needs to be undone when is that neccesary
      },
      connected : function() {
        this.div.className = "remotestorage-state-connected";
        gCl(this.div, 'userAddress').innerHTML = this.userAddress;
        var cube = gCl(this.div, 'cube');
        cube.src = RemoteStorage.Assets.remoteStorageIcon;
        removeClass(cube, 'remotestorage-loading');
      },
      busy : function() {
        this.div.className = "remotestorage-state-busy";
        addClass(gCl(this.div, 'cube'), 'remotestorage-loading'); //TODO needs to be undone when is that neccesary
      },
      offline : function() {
        this.div.className = "remotestorage-state-offline";
        gCl(this.div, 'cube').src = RemoteStorage.Assets.remoteStorageIconOffline;
      },
      error : function() {
        this.div.className = "remotestorage-state-error";
        gCl(this.div, 'cube').src = RemoteStorage.Assets.remoteStorageIconError;
      },
      unauthorized : function() {
        this.div.className = "remotestorage-state-unauthorized";
      }
    },
    events : {
      connect : function(event) {
        event.preventDefault();
        this._emit('connect', gTl(this.div, 'form').userAddress.value);
      },
      sync : function(event) {
        event.preventDefault();
        this._emit('sync');
      },
      disconnect : function(event) {
        event.preventDefault();
        this._emit('disconnect');
      },
      // FIXME: what are these???
      reconnect : function() {},
      display : function() {}
    }
  };

})();
<|endoftext|>


<commit_before>'use strict'; // eslint-disable-line

const assert = require('assert');
const url = require('url');

const werelogs = require('werelogs');

const httpServer = require('../http/server');
const constants = require('../../constants');
const utils = require('./utils');
const httpUtils = require('../http/utils');
const errors = require('../../errors');

function setContentLength(response, contentLength) {
    response.setHeader('Content-Length', contentLength.toString());
}

function setContentRange(response, byteRange, objectSize) {
    const [start, end] = byteRange;
    assert(start !== undefined && end !== undefined);
    response.setHeader('Content-Range',
                       `bytes ${start}-${end}/${objectSize}`);
}

function sendError(res, log, error, optMessage) {
    res.writeHead(error.code);
    let message;
    if (optMessage) {
        message = optMessage;
    } else {
        message = error.description || '';
    }
    log.debug('sending back error response', { httpCode: error.code,
        errorType: error.message,
        error: message });
    res.end(`${JSON.stringify({ errorType: error.message,
        errorMessage: message })}\n`);
}

/**
 * Parse the given url and return a pathInfo object. Sanity checks are
 * performed.
 *
 * @param {String} urlStr - URL to parse
 * @param {Boolean} expectKey - whether the command expects to see a
 *   key in the URL
 * @return {Object} a pathInfo object with URL items containing the
 * following attributes:
 *   - pathInfo.service {String} - The name of REST service ("DataFile")
 *   - pathInfo.key {String} - The requested key
 */
function parseURL(urlStr, expectKey) {
    const urlObj = url.parse(urlStr);
    const pathInfo = utils.explodePath(urlObj.path);
    if (pathInfo.service !== constants.dataFileURL) {
        throw errors.InvalidAction.customizeDescription(
            `unsupported service '${pathInfo.service}'`);
    }
    if (expectKey && pathInfo.key === undefined) {
        throw errors.MissingParameter.customizeDescription(
            'URL is missing key');
    }
    if (!expectKey && pathInfo.key !== undefined) {
        // note: we may implement rewrite functionality by allowing a
        // key in the URL, though we may still provide the new key in
        // the Location header to keep immutability property and
        // atomicity of the update (we would just remove the old
        // object when the new one has been written entirely in this
        // case, saving a request over an equivalent PUT + DELETE).
        throw errors.InvalidURI.customizeDescription(
            'PUT url cannot contain a key');
    }
    return pathInfo;
}

/**
 * @class
 * @classdesc REST Server interface
 *
 * You have to call setup() to initialize the storage backend, then
 * start() to start listening to the configured port.
 */
class RESTServer extends httpServer {

    /**
     * @constructor
     * @param {Object} params - constructor params
     * @param {Number} params.port - TCP port where the server listens to
     * @param {arsenal.storage.data.file.Store} params.dataStore -
     *   data store object
     * @param {Number} [params.bindAddress='localhost'] - address
     * bound to the socket
     * @param {Object} [params.log] - logger configuration
     */
    constructor(params) {
        assert(params.port);

        werelogs.configure({
            level: params.log.logLevel,
            dump: params.log.dumpLevel,
        });
        const logging = new werelogs.Logger('DataFileRESTServer');
        super(params.port, logging);
        this.logging = logging;
        this.dataStore = params.dataStore;
        this.setBindAddress(params.bindAddress || 'localhost');

        // hooking our request processing function by calling the
        // parent's method for that
        this.onRequest(this._onRequest);
        this.reqMethods = {
            PUT: this._onPut.bind(this),
            GET: this._onGet.bind(this),
            DELETE: this._onDelete.bind(this),
        };
    }

    /**
     * Setup the storage backend
     *
     * @param {function} callback - called when finished
     * @return {undefined}
     */
    setup(callback) {
        this.dataStore.setup(callback);
    }

    /**
     * Create a new request logger object
     *
     * @param {String} reqUids - serialized request UIDs (as received in
     * the X-Scal-Request-Uids header)
     * @return {werelogs.RequestLogger} new request logger
     */
    createLogger(reqUids) {
        return reqUids ?
            this.logging.newRequestLoggerFromSerializedUids(reqUids) :
            this.logging.newRequestLogger();
    }

    /**
     * Main incoming request handler, dispatches to method-specific
     * handlers
     *
     * @param {http.IncomingMessage} req - HTTP request object
     * @param {http.ServerResponse} res - HTTP response object
     * @return {undefined}
     */
    _onRequest(req, res) {
        const reqUids = req.headers['x-scal-request-uids'];
        const log = this.createLogger(reqUids);
        log.debug('request received', { method: req.method,
            url: req.url });
        if (req.method in this.reqMethods) {
            this.reqMethods[req.method](req, res, log);
        } else {
            // Method Not Allowed
            sendError(res, log, errors.MethodNotAllowed);
        }
    }

    /**
     * Handler for PUT requests
     *
     * @param {http.IncomingMessage} req - HTTP request object
     * @param {http.ServerResponse} res - HTTP response object
     * @param {werelogs.RequestLogger} log - logger object
     * @return {undefined}
     */
    _onPut(req, res, log) {
        let size;
        try {
            parseURL(req.url, false);
            const contentLength = req.headers['content-length'];
            if (contentLength === undefined) {
                throw errors.MissingContentLength;
            }
            size = Number.parseInt(contentLength, 10);
            if (Number.isNaN(size)) {
                throw errors.InvalidInput.customizeDescription(
                    'bad Content-Length');
            }
        } catch (err) {
            return sendError(res, log, err);
        }
        this.dataStore.put(req, size, log, (err, key) => {
            if (err) {
                return sendError(res, log, err);
            }
            log.debug('sending back 201 response to PUT', { key });
            res.setHeader('Location', `${constants.dataFileURL}/${key}`);
            setContentLength(res, 0);
            res.writeHead(201);
            return res.end(() => {
                log.debug('PUT response sent', { key });
            });
        });
        return undefined;
    }

    /**
     * Handler for GET requests
     *
     * @param {http.IncomingMessage} req - HTTP request object
     * @param {http.ServerResponse} res - HTTP response object
     * @param {werelogs.RequestLogger} log - logger object
     * @return {undefined}
     */
    _onGet(req, res, log) {
        let pathInfo;
        let rangeSpec = undefined;

        // Get request on the toplevel endpoint with ?action
        if (req.url.startsWith(`${constants.dataFileURL}?`)) {
            const queryParam = url.parse(req.url).query;
            if (queryParam === 'diskUsage') {
                this.dataStore.getDiskUsage((err, result) => {
                    if (err) {
                        return sendError(res, log, err);
                    }
                    res.writeHead(200);
                    res.end(JSON.stringify(result));
                    return undefined;
                });
            }
        }

        // Get request on an actual object
        try {
            pathInfo = parseURL(req.url, true);
            const rangeHeader = req.headers.range;
            if (rangeHeader !== undefined) {
                rangeSpec = httpUtils.parseRangeSpec(rangeHeader);
                if (rangeSpec.error) {
                    // ignore header if syntax is invalid
                    rangeSpec = undefined;
                }
            }
        } catch (err) {
            return sendError(res, log, err);
        }
        this.dataStore.stat(pathInfo.key, log, (err, info) => {
            if (err) {
                return sendError(res, log, err);
            }
            let byteRange;
            let contentLength;
            if (rangeSpec) {
                const { range, error } = httpUtils.getByteRangeFromSpec(
                    rangeSpec, info.objectSize);
                if (error) {
                    return sendError(res, log, error);
                }
                byteRange = range;
            }
            if (byteRange) {
                contentLength = byteRange[1] - byteRange[0] + 1;
            } else {
                contentLength = info.objectSize;
            }
            this.dataStore.get(pathInfo.key, byteRange, log, (err, rs) => {
                if (err) {
                    return sendError(res, log, err);
                }
                log.debug('sending back 200/206 response with contents',
                          { key: pathInfo.key });
                setContentLength(res, contentLength);
                res.setHeader('Accept-Ranges', 'bytes');
                if (byteRange) {
                    // data is immutable, so objectSize is still correct
                    setContentRange(res, byteRange, info.objectSize);
                    res.writeHead(206);
                } else {
                    res.writeHead(200);
                }
                rs.pipe(res);
                return undefined;
            });
            return undefined;
        });
        return undefined;
    }

    /**
     * Handler for DELETE requests
     *
     * @param {http.IncomingMessage} req - HTTP request object
     * @param {http.ServerResponse} res - HTTP response object
     * @param {werelogs.RequestLogger} log - logger object
     * @return {undefined}
     */
    _onDelete(req, res, log) {
        let pathInfo;
        try {
            pathInfo = parseURL(req.url, true);
        } catch (err) {
            return sendError(res, log, err);
        }
        this.dataStore.delete(pathInfo.key, log, err => {
            if (err) {
                return sendError(res, log, err);
            }
            log.debug('sending back 204 response to DELETE',
                      { key: pathInfo.key });
            res.writeHead(204);
            return res.end(() => {
                log.debug('DELETE response sent', { key: pathInfo.key });
            });
        });
        return undefined;
    }
}

module.exports = RESTServer;
<commit_msg>bf: return timely on data diskUsage subresource<commit_after>'use strict'; // eslint-disable-line

const assert = require('assert');
const url = require('url');

const werelogs = require('werelogs');

const httpServer = require('../http/server');
const constants = require('../../constants');
const utils = require('./utils');
const httpUtils = require('../http/utils');
const errors = require('../../errors');

function setContentLength(response, contentLength) {
    response.setHeader('Content-Length', contentLength.toString());
}

function setContentRange(response, byteRange, objectSize) {
    const [start, end] = byteRange;
    assert(start !== undefined && end !== undefined);
    response.setHeader('Content-Range',
                       `bytes ${start}-${end}/${objectSize}`);
}

function sendError(res, log, error, optMessage) {
    res.writeHead(error.code);
    let message;
    if (optMessage) {
        message = optMessage;
    } else {
        message = error.description || '';
    }
    log.debug('sending back error response', { httpCode: error.code,
        errorType: error.message,
        error: message });
    res.end(`${JSON.stringify({ errorType: error.message,
        errorMessage: message })}\n`);
}

/**
 * Parse the given url and return a pathInfo object. Sanity checks are
 * performed.
 *
 * @param {String} urlStr - URL to parse
 * @param {Boolean} expectKey - whether the command expects to see a
 *   key in the URL
 * @return {Object} a pathInfo object with URL items containing the
 * following attributes:
 *   - pathInfo.service {String} - The name of REST service ("DataFile")
 *   - pathInfo.key {String} - The requested key
 */
function parseURL(urlStr, expectKey) {
    const urlObj = url.parse(urlStr);
    const pathInfo = utils.explodePath(urlObj.path);
    if (pathInfo.service !== constants.dataFileURL) {
        throw errors.InvalidAction.customizeDescription(
            `unsupported service '${pathInfo.service}'`);
    }
    if (expectKey && pathInfo.key === undefined) {
        throw errors.MissingParameter.customizeDescription(
            'URL is missing key');
    }
    if (!expectKey && pathInfo.key !== undefined) {
        // note: we may implement rewrite functionality by allowing a
        // key in the URL, though we may still provide the new key in
        // the Location header to keep immutability property and
        // atomicity of the update (we would just remove the old
        // object when the new one has been written entirely in this
        // case, saving a request over an equivalent PUT + DELETE).
        throw errors.InvalidURI.customizeDescription(
            'PUT url cannot contain a key');
    }
    return pathInfo;
}

/**
 * @class
 * @classdesc REST Server interface
 *
 * You have to call setup() to initialize the storage backend, then
 * start() to start listening to the configured port.
 */
class RESTServer extends httpServer {

    /**
     * @constructor
     * @param {Object} params - constructor params
     * @param {Number} params.port - TCP port where the server listens to
     * @param {arsenal.storage.data.file.Store} params.dataStore -
     *   data store object
     * @param {Number} [params.bindAddress='localhost'] - address
     * bound to the socket
     * @param {Object} [params.log] - logger configuration
     */
    constructor(params) {
        assert(params.port);

        werelogs.configure({
            level: params.log.logLevel,
            dump: params.log.dumpLevel,
        });
        const logging = new werelogs.Logger('DataFileRESTServer');
        super(params.port, logging);
        this.logging = logging;
        this.dataStore = params.dataStore;
        this.setBindAddress(params.bindAddress || 'localhost');

        // hooking our request processing function by calling the
        // parent's method for that
        this.onRequest(this._onRequest);
        this.reqMethods = {
            PUT: this._onPut.bind(this),
            GET: this._onGet.bind(this),
            DELETE: this._onDelete.bind(this),
        };
    }

    /**
     * Setup the storage backend
     *
     * @param {function} callback - called when finished
     * @return {undefined}
     */
    setup(callback) {
        this.dataStore.setup(callback);
    }

    /**
     * Create a new request logger object
     *
     * @param {String} reqUids - serialized request UIDs (as received in
     * the X-Scal-Request-Uids header)
     * @return {werelogs.RequestLogger} new request logger
     */
    createLogger(reqUids) {
        return reqUids ?
            this.logging.newRequestLoggerFromSerializedUids(reqUids) :
            this.logging.newRequestLogger();
    }

    /**
     * Main incoming request handler, dispatches to method-specific
     * handlers
     *
     * @param {http.IncomingMessage} req - HTTP request object
     * @param {http.ServerResponse} res - HTTP response object
     * @return {undefined}
     */
    _onRequest(req, res) {
        const reqUids = req.headers['x-scal-request-uids'];
        const log = this.createLogger(reqUids);
        log.debug('request received', { method: req.method,
            url: req.url });
        if (req.method in this.reqMethods) {
            this.reqMethods[req.method](req, res, log);
        } else {
            // Method Not Allowed
            sendError(res, log, errors.MethodNotAllowed);
        }
    }

    /**
     * Handler for PUT requests
     *
     * @param {http.IncomingMessage} req - HTTP request object
     * @param {http.ServerResponse} res - HTTP response object
     * @param {werelogs.RequestLogger} log - logger object
     * @return {undefined}
     */
    _onPut(req, res, log) {
        let size;
        try {
            parseURL(req.url, false);
            const contentLength = req.headers['content-length'];
            if (contentLength === undefined) {
                throw errors.MissingContentLength;
            }
            size = Number.parseInt(contentLength, 10);
            if (Number.isNaN(size)) {
                throw errors.InvalidInput.customizeDescription(
                    'bad Content-Length');
            }
        } catch (err) {
            return sendError(res, log, err);
        }
        this.dataStore.put(req, size, log, (err, key) => {
            if (err) {
                return sendError(res, log, err);
            }
            log.debug('sending back 201 response to PUT', { key });
            res.setHeader('Location', `${constants.dataFileURL}/${key}`);
            setContentLength(res, 0);
            res.writeHead(201);
            return res.end(() => {
                log.debug('PUT response sent', { key });
            });
        });
        return undefined;
    }

    /**
     * Handler for GET requests
     *
     * @param {http.IncomingMessage} req - HTTP request object
     * @param {http.ServerResponse} res - HTTP response object
     * @param {werelogs.RequestLogger} log - logger object
     * @return {undefined}
     */
    _onGet(req, res, log) {
        let pathInfo;
        let rangeSpec = undefined;

        // Get request on the toplevel endpoint with ?action
        if (req.url.startsWith(`${constants.dataFileURL}?`)) {
            const queryParam = url.parse(req.url).query;
            if (queryParam === 'diskUsage') {
                return this.dataStore.getDiskUsage((err, result) => {
                    if (err) {
                        return sendError(res, log, err);
                    }
                    res.writeHead(200);
                    res.end(JSON.stringify(result));
                    return undefined;
                });
            }
        }

        // Get request on an actual object
        try {
            pathInfo = parseURL(req.url, true);
            const rangeHeader = req.headers.range;
            if (rangeHeader !== undefined) {
                rangeSpec = httpUtils.parseRangeSpec(rangeHeader);
                if (rangeSpec.error) {
                    // ignore header if syntax is invalid
                    rangeSpec = undefined;
                }
            }
        } catch (err) {
            return sendError(res, log, err);
        }
        this.dataStore.stat(pathInfo.key, log, (err, info) => {
            if (err) {
                return sendError(res, log, err);
            }
            let byteRange;
            let contentLength;
            if (rangeSpec) {
                const { range, error } = httpUtils.getByteRangeFromSpec(
                    rangeSpec, info.objectSize);
                if (error) {
                    return sendError(res, log, error);
                }
                byteRange = range;
            }
            if (byteRange) {
                contentLength = byteRange[1] - byteRange[0] + 1;
            } else {
                contentLength = info.objectSize;
            }
            this.dataStore.get(pathInfo.key, byteRange, log, (err, rs) => {
                if (err) {
                    return sendError(res, log, err);
                }
                log.debug('sending back 200/206 response with contents',
                          { key: pathInfo.key });
                setContentLength(res, contentLength);
                res.setHeader('Accept-Ranges', 'bytes');
                if (byteRange) {
                    // data is immutable, so objectSize is still correct
                    setContentRange(res, byteRange, info.objectSize);
                    res.writeHead(206);
                } else {
                    res.writeHead(200);
                }
                rs.pipe(res);
                return undefined;
            });
            return undefined;
        });
        return undefined;
    }

    /**
     * Handler for DELETE requests
     *
     * @param {http.IncomingMessage} req - HTTP request object
     * @param {http.ServerResponse} res - HTTP response object
     * @param {werelogs.RequestLogger} log - logger object
     * @return {undefined}
     */
    _onDelete(req, res, log) {
        let pathInfo;
        try {
            pathInfo = parseURL(req.url, true);
        } catch (err) {
            return sendError(res, log, err);
        }
        this.dataStore.delete(pathInfo.key, log, err => {
            if (err) {
                return sendError(res, log, err);
            }
            log.debug('sending back 204 response to DELETE',
                      { key: pathInfo.key });
            res.writeHead(204);
            return res.end(() => {
                log.debug('DELETE response sent', { key: pathInfo.key });
            });
        });
        return undefined;
    }
}

module.exports = RESTServer;
<|endoftext|>


<commit_before>'use strict';

var dot = require('dot');
dot.templateSettings.strip = false;

var Node = require('../node');

var TYPE = 'intersection';
var PARAMS = {
    source: Node.PARAM.NODE,
    target: Node.PARAM.NODE
};

var Intersection = Node.create(TYPE, PARAMS);

module.exports = Intersection;
module.exports.TYPE = TYPE;
module.exports.PARAMS = PARAMS;

Intersection.prototype.sql = function() {
    return query({
        sourceQuery: this.source.getQuery(),
        targetQuery: this.target.getQuery(),
        columnNames: this.source.getColumns()
    });
};

var queryTemplate = dot.template([
    'WITH',
    '_cdb_analysis_source AS (',
    ' {{=it.sourceQuery}}',
    '),',
    '_cdb_analysis_target AS (',
    ' {{=it.targetQuery}}',
    ')',
    'SELECT {{=it.sourceQueryColumns}}',
    'FROM _cdb_analysis_source JOIN _cdb_analysis_target',
    'ON ST_Intersects(_cdb_analysis_target.the_geom, _cdb_analysis_source.the_geom)'
].join('\n'));

function query(it) {
    it.sourceQueryColumns = it.columnNames.map(function(name) { return '_cdb_analysis_source.' + name; }).join(', ');
    return queryTemplate(it);
}
<commit_msg>Fix accepted geometries in intersection node<commit_after>'use strict';

var dot = require('dot');
dot.templateSettings.strip = false;

var Node = require('../node');

var TYPE = 'intersection';
var PARAMS = {
    source: Node.PARAM.NODE(Node.GEOMETRY.ANY),
    target: Node.PARAM.NODE(Node.GEOMETRY.ANY)
};

var Intersection = Node.create(TYPE, PARAMS);

module.exports = Intersection;
module.exports.TYPE = TYPE;
module.exports.PARAMS = PARAMS;

Intersection.prototype.sql = function() {
    return query({
        sourceQuery: this.source.getQuery(),
        targetQuery: this.target.getQuery(),
        columnNames: this.source.getColumns()
    });
};

var queryTemplate = dot.template([
    'WITH',
    '_cdb_analysis_source AS (',
    ' {{=it.sourceQuery}}',
    '),',
    '_cdb_analysis_target AS (',
    ' {{=it.targetQuery}}',
    ')',
    'SELECT {{=it.sourceQueryColumns}}',
    'FROM _cdb_analysis_source JOIN _cdb_analysis_target',
    'ON ST_Intersects(_cdb_analysis_target.the_geom, _cdb_analysis_source.the_geom)'
].join('\n'));

function query(it) {
    it.sourceQueryColumns = it.columnNames.map(function(name) { return '_cdb_analysis_source.' + name; }).join(', ');
    return queryTemplate(it);
}
<|endoftext|>