<commit_before>/*
 * Guide.js
 * https://github.com/TheLeanMachine/Guide.js
 *
 * Copyright (c) 2013 Kai Hoelscher
 * Licensed under the MIT license.
 */

// TODO: [BUG] Prevent XSS attacks (to for example the test of a guide)
// TODO: [BUG] what happens if an un-activaed Guide gets deaktivated?
// >>> TODO: [BUG] re-implement fadeOut of GUide
// TODO: [BUG] why does 'activateAll()' does not get calles when button clicked?
// >>> TODO: [BUG] guidejs_test: a) why does null check fail? b) what kind of error is thrown if no guideConfig is provided?
// TODO: [TEST] activate() and deactivate() AND
// TODO: [TEST] Module exporting, e.g. for require.js (???)
// TODO: [API] methods to clean up: destroyAll() -> detachListeners(), removeGuidesFromDom()
// TODO: [FEATURE] Move CSS styles to lib; pass CSS styles to guideConfig, otherwise renderer() draws a default theme
// TODO: [FEATURE] Provide hooks (events) like 'guideRendered', 'guideHidden'
// TODO: [FEATURE] Provide HTML template for Guide
// TODO: [FEATURE] Render parameters? (etc. where to render: Position clockwise? Relative to center?)
// TODO: [FEATURE] New Guide type: GuidedTour() ...at first, just a collection of Guiders
// TODO: [FEATURE] Implement DefaultRenderAdapter that natively renders the helpbox (via HTML API?) ????
// TODO: [REFACTOR] Use Array.prototype.slice() and co. instead of functions belonging to the object
// TODO: [REFACTOR] use some memoization instead of calls to '_libCache[...]'(?)
// TODO: [REFACTOR] Rename: displayDuration -> displayDurationsMillis
// TODO: [REFACTOR] expose concrete 'classes' instead of generic 'newGuide()' method: HelpBox, GuidedTour,...
// TODO: [REFACTOR] add Guide in DOM as child nodes(instead of sibling), make parent "position: relative;" and use this as starting point for rendering
// TODO: [REFACTOR] Rename HelpBoxGuide to HelpBox (???)
// TODO: [REFACTOR] Improve performance of methods like debugEnabled() oder renderer() (???)
// TODO: [VALIDATION] Args of createHelpBoxGuide() -> set to reasonable defaults otherwise
(function (undefined) { // we always get 'undefined' here, since this code is directly invoked without arguments

  //
  // "constants"
  //

  var GLOBAL_CONTEXT = this; // 'window' in the browser, or 'global' on the server (see very bottom of this file)
  var DEBUG_URL_HASH = 'debugGuideJs';
  var DOC_URL = 'https://github.com/TheLeanMachine/Guide.js/blob/master/README.md';

  //
  // private members
  //

  var _guides = []; // all Guides created by this lib
  var _lastAddedGuideId = 0; // incremented when Guide is created
  var _libCache = {};

  //
  // private functions
  //

  // TODO add doc(?)
  function registerGuide(helpBoxGuide) {
    _guides.push(helpBoxGuide);
  }

  /**
   * Deactivates all Guides (ATM this means to hide them).
   */
  function deactivateAll() {
    forEachIn(_guides, function(guide) {
      guide.deactivate();
    });
  }

  /**
   * Activates all Guides (ATM this means to display them, again).
   */
  function activateAll() {
    forEachIn(_guides, function(guide) {
      guide.activate();
    });
  }

  /**
   * Factory method for creating new {@link HelpBoxGuide} instances.
   *
   * @param guideConfig TODO doc
   */
  function createHelpBoxGuide(guideConfig) {
    var helpBoxGuide;
    try {
      helpBoxGuide = helpBoxFrom(guideConfig);
      registerGuide(helpBoxGuide);
    } catch (err) {
      logError(err.message);
    }
    return helpBoxGuide;
  }

  function helpBoxFrom(clientConfig) {
    var defaultText = 'This is the default text of a HelpBoxGuide';
    var defaultDisplayDuration = 1000;
    var defaultFadeOutMillis = 150;
    var validConfig = {
      renderTarget:clientConfig.renderTarget,
      text:(clientConfig.text) ? clientConfig.text : defaultText,
      displayDuration:(clientConfig.displayDuration) ? clientConfig.displayDuration : defaultDisplayDuration,
      fadeOutMillis:(clientConfig.fadeOutMillis) ? clientConfig.displayDuration : defaultFadeOutMillis
    };
    return new HelpBoxGuide(validConfig);
  }

  /**
   * A simple help box that gets displayed for a certain amount of time.
   * @param guideConfig TODO doc
   * @constructor
   */
  function HelpBoxGuide(guideConfig) {
    var guideId = _lastAddedGuideId++;
    var helpBoxCssId = 'guideJsHelpBox-' + guideId;
    var closeLinkCssId = 'guideJsHelpBoxCloseLink-' + guideId;
    var targetCssId = guideConfig.renderTarget;

    /**
     * Triggers the Guide to do its work: Display a help box, start a tour with Guiders etc.
     */
    function activate() { // TODO rename to 'augment()' or sth. else?
      var content = guideConfig.text;
      var fadeOutMillis = guideConfig.fadeOutMillis;
      var displayDuration = guideConfig.displayDuration;
      var html;
      var anchor = debugModeEnabled() ? DEBUG_URL_HASH : 'top';

      if (domService().domContainsGuide(helpBoxCssId)) {
        domService().showGuide(helpBoxCssId);
      } else {
        html = '
' + content + '
close
';
        domService().attachGuideTo(targetCssId, html, helpBoxCssId);
        logDebug('Attached Guide "#'+ helpBoxCssId +'" to DOM, as child of "#'+ targetCssId +'".');
      }

      timerService().delayFor(displayDuration, deactivate);

// TODO taskService / eventService ???
      domService().attachEventTo('click', closeLinkCssId, function() {
        deactivate();
      });
    }

    // TODO add doc
    function deactivate() {
// $('#' + helpBoxCssId).fadeOut(fadeOutMillis);
      domService().hideGuide(helpBoxCssId);
    }

    function isLoaded() {
      return true;
    }

    this.activate = activate;
    this.deactivate = deactivate;
    this.isLoaded = isLoaded;
  }

  // TODO doc
  function domService() {
    var cacheKey = 'domService';
    if (_libCache[cacheKey]) {
      return _libCache[cacheKey];
    }

    if (jQueryAvailable()) {
      return _libCache[cacheKey] = new JQueryDomService(GLOBAL_CONTEXT.jQuery);
    }

    logError('Cannot render any Guides: No appropriate lib found in global context.');
    return null;
  }

  // TODO add doc (rename to wrapJQuery() )
  function JQueryDomService($) {
    var renderedGuides = {};

    // TODO add doc
    function attachGuideTo(cssIdRenderTarget, html, cssIdGuideContainer) {
      $('#' + cssIdRenderTarget).prepend(html);
      rememberGuide(cssIdGuideContainer);
    }

    // TODO add doc
    function domContainsGuide(guideCssId) {
      return renderedGuides[guideCssId];
    }

    // TODO add doc
    function rememberGuide(guideCssId) {
      renderedGuides[guideCssId] = 'dummy'; // TODO sth. better that dummy value?
    }

    // TODO add doc
    function showGuide(guideCssId) {
      $('#' + guideCssId).show();
    }

    function hideGuide(guideCssId) {
      $('#' + guideCssId).hide();
    }

    // TODO add doc
    function attachEventTo(eventName, cssIdGuideContainer, fn) {
      $('#' + cssIdGuideContainer).on(eventName, fn);
    }

    this.attachGuideTo = attachGuideTo;
    this.showGuide = showGuide;
    this.hideGuide = hideGuide;
    this.attachEventTo = attachEventTo;
    this.domContainsGuide = domContainsGuide;
  }

  // TODO add doc
  function timerService() {
    var cacheKey = 'timerService';
    return _libCache[cacheKey] ? _libCache[cacheKey] : (_libCache[cacheKey] = new DefaultTimerService());
  }

  // TODO add doc
  function DefaultTimerService() {
    var timers = [];

    function delayFor(delayMillis, fn) {
      var timer = {
        timerId: null,
        start: function() {
          this.timerId = windowObj().setTimeout(fn, delayMillis);
        },
        stop: function() {
          windowObj().clearTimeout(this.timerId);
        }
      };
      timer.start();
      timers.push(timer);
    }

    function callEvery(intervalMillis, fn) {
      var timer = {
        timerId: null,
        start: function() {
          this.timerId = windowObj().setInterval(fn, intervalMillis);
        },
        stop: function() {
          windowObj().clearInterval(this.timerId);
        }
      };
      timer.start();
      timers.push(timer);
    }

    function stopAll() {
      forEachIn(timers, function(timer) {
        timer.stop();
      });
    }

    this.delayFor = delayFor;
    this.callEvery = callEvery;
    this.stopAll = stopAll;
  }

  //
  // Helper functions
  //

  function debugModeEnabled() {
    var cacheKey = 'debugModeEnabled';
    if (_libCache[cacheKey]) {
      return _libCache[cacheKey];
    }
    _libCache[cacheKey] = false;
    if (windowObj().location && windowObj().location.hash) {
      _libCache[cacheKey] = windowObj().location.hash === ('#' + DEBUG_URL_HASH);
    }
    return _libCache[cacheKey];
  }

  // TODO add doc
  function windowObj() {
    var cacheKey = 'windowObj';
    if (_libCache[cacheKey]) {
      return _libCache[cacheKey];
    }

    if (GLOBAL_CONTEXT.window) {
      _libCache[cacheKey] = GLOBAL_CONTEXT.window;
    } else {
      logError('No "window" object available in global context.');
    }
    return _libCache[cacheKey];
  }

  function jQueryAvailable() {
    return GLOBAL_CONTEXT.jQuery != null;
  }

  function commonJsAvailable() {
    return (typeof module !== 'undefined' && module.exports); // checks for node.js, too
  }

  function enderAvailable() {
    /*global ender:false */
    return typeof ender === 'undefined';
  }

  function requireJsAvailable() {
    /*global define:false */
    return (typeof define === "function") && define.amd;
  }

  function forEachIn(array, fn) {
    var i;

    for (i=0; i<array.length; ++i) {
      fn(array[i]);
    }
  }

  function objectHasPropertyWithValue(obj, val) {
    var key;
    for (key in obj) {
      if (obj.hasOwnProperty(key) && obj[key] === val) {
        return true;
      }
    }
    return false;
  }

  function isObject(obj) {
    return obj === Object(obj);
  }

  function isArray(obj) {
    return Array.isArray || Object.prototype.toString.call(obj) === '[object Array]';
  }

  function isFunction(fn) {
    return Object.prototype.toString.call(fn) === '[object Function]';
  }

  // TODO add isString(str)
/*

 // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
 each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
 _['is' + name] = function(obj) {
 return toString.call(obj) == '[object ' + name + ']';
 };
 });
*/

  function logError(msg) {
    log('[ERROR]', msg);
  }

  function logDebug(msg) {
    if (debugModeEnabled()) {
      log('[DEBUG]', msg);
    }
  }

  function log(level, msg) {
    /*global console:false */
    if (GLOBAL_CONTEXT.console) {
      GLOBAL_CONTEXT.console.log(level + ' GuideJs: ' + msg);
    }
  }

  function throwError(msg) {
    throw new Error(msg + ' - Check the API docs at ' + DOC_URL);
  }

  /**
   * The API to be exported by this library.
   */
  function GuideJsApi() {
    // variables
    this.version = '0.0.1';

    // methods
    this.createHelpBoxGuide = createHelpBoxGuide;
    this.activateAll = activateAll;
    this.deactivateAll = deactivateAll;
  }

  //
  // Exporting Guide.js
  //

  if (commonJsAvailable()) {
    module.exports = new GuideJsApi();
  }
  if (enderAvailable()) {
    // add `guide` as a global object via a string identifier,
    // for Closure Compiler "advanced" mode
    GLOBAL_CONTEXT['GuideJs'] = new GuideJsApi();
  }
  if (requireJsAvailable()) {
    /*global define:false */
    define([], function () {
      return new GuideJsApi();
    });
  }
}).call(this); // setting 'this' to the global context<commit_msg>Add ToDo<commit_after>/*
 * Guide.js
 * https://github.com/TheLeanMachine/Guide.js
 *
 * Copyright (c) 2013 Kai Hoelscher
 * Licensed under the MIT license.
 */

// TODO: [BUG] Prevent XSS attacks (to for example the test of a guide)
// >>> TODO: [BUG] re-implement fadeOut of GUide
// TODO: [BUG] why does 'activateAll()' does not get calles when button clicked?
// >>> TODO: [BUG] guidejs_test: a) why does null check fail? b) what kind of error is thrown if no guideConfig is provided?
// TODO: [RATED][BUG] what happens if an un-activaed Guide gets deaktivated?
// TODO: [TEST] activate() and deactivate() AND
// TODO: [TEST] Module exporting, e.g. for require.js (???)
// TODO: [API] methods to clean up: destroyAll() -> detachListeners(), removeGuidesFromDom()
// TODO: [RATED][FEATURE] New Guide type: GuidedTour() ...at first, just a collection of Guiders (rename: HelpBoxGuide() to 'Guider()'?)
// TODO: [FEATURE] Move CSS styles to lib; pass CSS styles to guideConfig, otherwise renderer() draws a default theme
// TODO: [FEATURE] Provide HTML template for Guide
// TODO: [FEATURE] Render parameters? (etc. where to render: Position clockwise? Relative to center?)
// TODO [RATED][FEATURE] Provide hooks (events) like 'guideRendered', 'guideHidden'
// TODO: [RATED][FEATURE] Implement DefaultRenderAdapter that natively renders the helpbox (via HTML API?) ????
// TODO: [REFACTOR] Use Array.prototype.slice() and co. instead of functions belonging to the object
// TODO: [REFACTOR] use some memoization instead of calls to '_libCache[...]'(?)
// TODO: [REFACTOR] Rename: displayDuration -> displayDurationsMillis
// TODO: [REFACTOR] expose concrete 'classes' instead of generic 'newGuide()' method: HelpBox, GuidedTour,...
// TODO: [REFACTOR] add Guide in DOM as child nodes(instead of sibling), make parent "position: relative;" and use this as starting point for rendering
// TODO: [REFACTOR] Improve performance of methods like debugEnabled() oder renderer() (???)
// TODO: [VALIDATION] Args of createHelpBoxGuide() -> set to reasonable defaults otherwise
(function (undefined) { // we always get 'undefined' here, since this code is directly invoked without arguments

  //
  // "constants"
  //

  var GLOBAL_CONTEXT = this; // 'window' in the browser, or 'global' on the server (see very bottom of this file)
  var DEBUG_URL_HASH = 'debugGuideJs';
  var DOC_URL = 'https://github.com/TheLeanMachine/Guide.js/blob/master/README.md';

  //
  // private members
  //

  var _guides = []; // all Guides created by this lib
  var _lastAddedGuideId = 0; // incremented when Guide is created
  var _libCache = {};

  //
  // private functions
  //

  // TODO add doc(?)
  function registerGuide(helpBoxGuide) {
    _guides.push(helpBoxGuide);
  }

  /**
   * Deactivates all Guides (ATM this means to hide them).
   */
  function deactivateAll() {
    forEachIn(_guides, function(guide) {
      guide.deactivate();
    });
  }

  /**
   * Activates all Guides (ATM this means to display them, again).
   */
  function activateAll() {
    forEachIn(_guides, function(guide) {
      guide.activate();
    });
  }

  /**
   * Factory method for creating new {@link HelpBoxGuide} instances.
   *
   * @param guideConfig TODO doc
   */
  function createHelpBoxGuide(guideConfig) {
    var helpBoxGuide;
    try {
      helpBoxGuide = helpBoxFrom(guideConfig);
      registerGuide(helpBoxGuide);
    } catch (err) {
      logError(err.message);
    }
    return helpBoxGuide;
  }

  function helpBoxFrom(clientConfig) {
    var defaultText = 'This is the default text of a HelpBoxGuide';
    var defaultDisplayDuration = 1000;
    var defaultFadeOutMillis = 150;
    var validConfig = {
      renderTarget:clientConfig.renderTarget,
      text:(clientConfig.text) ? clientConfig.text : defaultText,
      displayDuration:(clientConfig.displayDuration) ? clientConfig.displayDuration : defaultDisplayDuration,
      fadeOutMillis:(clientConfig.fadeOutMillis) ? clientConfig.displayDuration : defaultFadeOutMillis
    };
    return new HelpBoxGuide(validConfig);
  }

  /**
   * A simple help box that gets displayed for a certain amount of time.
   * @param guideConfig TODO doc
   * @constructor
   */
  function HelpBoxGuide(guideConfig) {
    var guideId = _lastAddedGuideId++;
    var helpBoxCssId = 'guideJsHelpBox-' + guideId;
    var closeLinkCssId = 'guideJsHelpBoxCloseLink-' + guideId;
    var targetCssId = guideConfig.renderTarget;

    /**
     * Triggers the Guide to do its work: Display a help box, start a tour with Guiders etc.
     */
    function activate() { // TODO rename to 'augment()' or sth. else?
      var content = guideConfig.text;
      var fadeOutMillis = guideConfig.fadeOutMillis;
      var displayDuration = guideConfig.displayDuration;
      var html;
      var anchor = debugModeEnabled() ? DEBUG_URL_HASH : 'top';

      if (domService().domContainsGuide(helpBoxCssId)) {
        domService().showGuide(helpBoxCssId);
      } else {
        html = '
' + content + '
close
';
        domService().attachGuideTo(targetCssId, html, helpBoxCssId);
        logDebug('Attached Guide "#'+ helpBoxCssId +'" to DOM, as child of "#'+ targetCssId +'".');
      }

      timerService().delayFor(displayDuration, deactivate);

// TODO taskService / eventService ???
      domService().attachEventTo('click', closeLinkCssId, function() {
        deactivate();
      });
    }

    // TODO add doc
    function deactivate() {
// $('#' + helpBoxCssId).fadeOut(fadeOutMillis);
      domService().hideGuide(helpBoxCssId);
    }

    function isLoaded() {
      return true;
    }

    this.activate = activate;
    this.deactivate = deactivate;
    this.isLoaded = isLoaded;
  }

  // TODO doc
  function domService() {
    var cacheKey = 'domService';
    if (_libCache[cacheKey]) {
      return _libCache[cacheKey];
    }

    if (jQueryAvailable()) {
      return _libCache[cacheKey] = new JQueryDomService(GLOBAL_CONTEXT.jQuery);
    }

    logError('Cannot render any Guides: No appropriate lib found in global context.');
    return null;
  }

  // TODO add doc (rename to wrapJQuery() )
  function JQueryDomService($) {
    var renderedGuides = {};

    // TODO add doc
    function attachGuideTo(cssIdRenderTarget, html, cssIdGuideContainer) {
      $('#' + cssIdRenderTarget).prepend(html);
      rememberGuide(cssIdGuideContainer);
    }

    // TODO add doc
    function domContainsGuide(guideCssId) {
      return renderedGuides[guideCssId];
    }

    // TODO add doc
    function rememberGuide(guideCssId) {
      renderedGuides[guideCssId] = 'dummy'; // TODO sth. better that dummy value?
    }

    // TODO add doc
    function showGuide(guideCssId) {
      $('#' + guideCssId).show();
    }

    function hideGuide(guideCssId) {
      $('#' + guideCssId).hide();
    }

    // TODO add doc
    function attachEventTo(eventName, cssIdGuideContainer, fn) {
      $('#' + cssIdGuideContainer).on(eventName, fn);
    }

    this.attachGuideTo = attachGuideTo;
    this.showGuide = showGuide;
    this.hideGuide = hideGuide;
    this.attachEventTo = attachEventTo;
    this.domContainsGuide = domContainsGuide;
  }

  // TODO add doc
  function timerService() {
    var cacheKey = 'timerService';
    return _libCache[cacheKey] ? _libCache[cacheKey] : (_libCache[cacheKey] = new DefaultTimerService());
  }

  // TODO add doc
  function DefaultTimerService() {
    var timers = [];

    function delayFor(delayMillis, fn) {
      var timer = {
        timerId: null,
        start: function() {
          this.timerId = windowObj().setTimeout(fn, delayMillis);
        },
        stop: function() {
          windowObj().clearTimeout(this.timerId);
        }
      };
      timer.start();
      timers.push(timer);
    }

    function callEvery(intervalMillis, fn) {
      var timer = {
        timerId: null,
        start: function() {
          this.timerId = windowObj().setInterval(fn, intervalMillis);
        },
        stop: function() {
          windowObj().clearInterval(this.timerId);
        }
      };
      timer.start();
      timers.push(timer);
    }

    function stopAll() {
      forEachIn(timers, function(timer) {
        timer.stop();
      });
    }

    this.delayFor = delayFor;
    this.callEvery = callEvery;
    this.stopAll = stopAll;
  }

  //
  // Helper functions
  //

  function debugModeEnabled() {
    var cacheKey = 'debugModeEnabled';
    if (_libCache[cacheKey]) {
      return _libCache[cacheKey];
    }
    _libCache[cacheKey] = false;
    if (windowObj().location && windowObj().location.hash) {
      _libCache[cacheKey] = windowObj().location.hash === ('#' + DEBUG_URL_HASH);
    }
    return _libCache[cacheKey];
  }

  // TODO add doc
  function windowObj() {
    var cacheKey = 'windowObj';
    if (_libCache[cacheKey]) {
      return _libCache[cacheKey];
    }

    if (GLOBAL_CONTEXT.window) {
      _libCache[cacheKey] = GLOBAL_CONTEXT.window;
    } else {
      logError('No "window" object available in global context.');
    }
    return _libCache[cacheKey];
  }

  function jQueryAvailable() {
    return GLOBAL_CONTEXT.jQuery != null;
  }

  function commonJsAvailable() {
    return (typeof module !== 'undefined' && module.exports); // checks for node.js, too
  }

  function enderAvailable() {
    /*global ender:false */
    return typeof ender === 'undefined';
  }

  function requireJsAvailable() {
    /*global define:false */
    return (typeof define === "function") && define.amd;
  }

  function forEachIn(array, fn) {
    var i;

    for (i=0; i<array.length; ++i) {
      fn(array[i]);
    }
  }

  function objectHasPropertyWithValue(obj, val) {
    var key;
    for (key in obj) {
      if (obj.hasOwnProperty(key) && obj[key] === val) {
        return true;
      }
    }
    return false;
  }

  function isObject(obj) {
    return obj === Object(obj);
  }

  function isArray(obj) {
    return Array.isArray || Object.prototype.toString.call(obj) === '[object Array]';
  }

  function isFunction(fn) {
    return Object.prototype.toString.call(fn) === '[object Function]';
  }

  // TODO add isString(str)
/*

 // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
 each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
 _['is' + name] = function(obj) {
 return toString.call(obj) == '[object ' + name + ']';
 };
 });
*/

  function logError(msg) {
    log('[ERROR]', msg);
  }

  function logDebug(msg) {
    if (debugModeEnabled()) {
      log('[DEBUG]', msg);
    }
  }

  function log(level, msg) {
    /*global console:false */
    if (GLOBAL_CONTEXT.console) {
      GLOBAL_CONTEXT.console.log(level + ' GuideJs: ' + msg);
    }
  }

  function throwError(msg) {
    throw new Error(msg + ' - Check the API docs at ' + DOC_URL);
  }

  /**
   * The API to be exported by this library.
   */
  function GuideJsApi() {
    // variables
    this.version = '0.0.1';

    // methods
    this.createHelpBoxGuide = createHelpBoxGuide;
    this.activateAll = activateAll;
    this.deactivateAll = deactivateAll;
  }

  //
  // Exporting Guide.js
  //

  if (commonJsAvailable()) {
    module.exports = new GuideJsApi();
  }
  if (enderAvailable()) {
    // add `guide` as a global object via a string identifier,
    // for Closure Compiler "advanced" mode
    GLOBAL_CONTEXT['GuideJs'] = new GuideJsApi();
  }
  if (requireJsAvailable()) {
    /*global define:false */
    define([], function () {
      return new GuideJsApi();
    });
  }
}).call(this); // setting 'this' to the global context<|endoftext|>


<commit_before>/*
 * raja browser client
 */
(function() {

function Raja() {
	this.delays = [];
	this.ready();
}

Raja.prototype.delay = function(url, query, listener) {
	this.delays.push([url, query, listener]);
	return this;
};

Raja.prototype.ready = function() {
	this.root = document.getElementById('raja');
	if (!this.root) return;
	var self = this;
	if (!this.pool) {
		this.pool = (this.root.getAttribute('client') || '').split(' ');
		loadScript(randomEl(this.pool) + '/socket.io/socket.io.js', function(err) {
			if (err) throw err;
			var proto = io.Manager.prototype;
			self._on = proto.on;
			self._emit = proto.emit;
			self.off = proto.off;
			self.listeners = proto.listeners;
			self.ready();
		});
		this.namespace = this.root.getAttribute('namespace') || '';
		this.room = this.root.getAttribute('room');
		if (!this.room) throw new Error("Raja cannot connect without a room url");
	}
	if (!window.io) {
		return;
	}

	var lastMod = this.root.getAttribute('last-modified');
	var now = new Date();
	if (!lastMod) {
		// work around webkit bug https://bugs.webkit.org/show_bug.cgi?id=4363
		lastMod = Date.parse(document.lastModified);
		var diff = (new Date(now.toLocaleString())).getTimezoneOffset() - now.getTimezoneOffset();
		if (!diff) diff = now.getTimezoneOffset() * 60000;
		else diff = 0;
		lastMod = lastMod - diff;
	}
	this.mtime = isNaN(lastMod) ? now : new Date(lastMod);
	this.root.setAttribute('last-modified', this.mtime.getTime());
	this.resources = JSON.parse(this.root.getAttribute('resources')) || {};
	for (var url in this.resources) {
		this.resources[url] = {mtime: tryDate(this.resources[url])};
	}
	var list = this.delays;
	delete this.delays;
	for (var i=0; i < list.length; i++) {
		this.on.apply(this, list[i]);
	}
};

Raja.prototype.update = function() {
	var resources = {};
	for (var url in this.resources) resources[url] = this.resources[url].mtime;
	this.root.setAttribute('resources', JSON.stringify(resources));
};

Raja.prototype.emit = function(what) {
	var args = Array.prototype.slice.call(arguments, 0);
	try {
		this._emit.apply(this, args);
	} catch(e) {
		console.error(e);
	}
	if (what == "error" && this.listeners("error").length == 0) {
		args.shift();
		console.error.apply(console, args);
	}
};

Raja.prototype.on = function(url, query, listener) {
	if (!listener && typeof query == "function") {
		listener = query;
		query = null;
	}
	if (!this.resources) {
		return this.delay(url, query, listener);
	}
	if (!this.io) this.setio();
	var self = this;
	if (url == "error") return this._on(url, listener);
	var plistener = function() {
		try {
			listener.apply(null, Array.prototype.slice.call(arguments));
		} catch(e) {
			self.emit('error', e);
		}
	};
	url = absolute(this.room, url);
	url = urlQuery(url, query);
	this._on(url, plistener);
	var resources = this.resources;
	var resource = resources[url];
	if (!resource) resource = resources[url] = {};
	if (resource.error) return;

	(function(next) {
		var reqs = resource.requests;
		if (resource.data !== undefined) {
			listener(resource.data, {
				method: "get",
				url: url,
				mtime: resource.mtime
			});
			return next();
		} else if (resource.mtime !== undefined) {
			// resource merged, just join it
			return next();
		} else if (resource.queue) {
			// resource is currently loading
			resource.queue.push(listener);
			return;
		}
		// resource has not been loaded, is not loading. Proceed
		resource.queue = [listener];
		var xhr = Raja.prototype.GET(url, function(err, obj) {
			if (err) {
				resource.error = err;
				return next(err);
			}
			var mtime = tryDate(xhr.getResponseHeader("Last-Modified"));
			resource.mtime = mtime;
			self.update();
			resource.data = obj;
			for (var i=0; i < resource.queue.length; i++) {
				try {
					resource.queue[i](obj, {
						method: "get",
						url: url,
						query: query,
						mtime: mtime
					});
				} catch(e) {
					console.error(e);
				}
			}
			delete resource.queue;
			next();
		});
	})(function(err) {
		if (err) self.emit('error', err);
	});
	return this;
};

Raja.prototype.setio = function() {
	var iohost = randomEl(this.pool);
	if (iohost.substring(0, 2) == '//') iohost = document.location.protocol + iohost;
	this.io = io(iohost + '/' + this.namespace);
	var self = this;
	this.io.once('reconnect_failed', function(err) {
		if (err) self.emit('error', err);
		self.io.removeAllListeners('message');
		setTimeout(function() {
			self.setio();
		}, 1000);
	});
	this.io.emit('join', {
		room: this.room,
		mtime: this.mtime.getTime()
	});

	this.io.on('message', function(msg) {
		if (!msg.url) return;
		var data = msg.data;
		if (data) delete msg.data;
		var stamp = msg.mtime;
		var mtime = tryDate(stamp);
		if (mtime) msg.mtime = mtime;
		var fresh = msg.mtime > self.mtime;
		if (fresh) {
			self.mtime = msg.mtime;
			self.root.setAttribute('last-modified', stamp);
		}
		var parents = msg.parents;
		parents.unshift(msg.url);
		for (var i=0; i < parents.length; i++) {
			var url = keyToUrl(parents[i]);
			var resource = self.resources[url];
			if (resource) {
				if (!resource.mtime || msg.mtime > resource.mtime) resource.mtime = msg.mtime;
				self.emit(url, data, msg);
			} else if (fresh && url != self.url) {
				// some dependency that isn't a resource - a static file ? - has changed
			}
		}
	});
};

function randomEl(arr) {
	var index = parseInt(Math.random() * arr.length);
	return arr[index];
}

function absolute(loc, url) {
	if (/^https?/i.test(url)) return url;
	if (typeof loc == "string") {
		if (!this.a) this.a = document.createElement('a');
		this.a.href = loc;
		loc = {
			href: this.a.href,
			pathname: this.a.pathname,
			protocol: this.a.protocol,
			host: this.a.host
		};
	}
	var path = loc.pathname;
	if (url.indexOf('..') == 0) {
		path = path.split('/');
		path.pop();
		url = path.join('/') + url.substring(2);
	} else if (url == '.') {
		 return loc.href;
	} else if (url.indexOf('.') == 0) {
		url = path + url.substring(1);
	} else if (url.indexOf('/') != 0) {
		var base = path.split('/');
		base.pop();
		base = base.join('/');
		url = base + '/' + url;
	}
	url = loc.protocol + '//' + loc.host + url;
	return url;
}
Raja.prototype.absolute = absolute;

function urlParams(url, params) {
	if (!params) return url;
	return url.replace(/\/:(\w+)/g, function(str, name) {
		var val = params[name];
		if (val != null) {
			delete params[name];
			return '/' + val;
		} else {
			return '/:' + name;
		}
	});
}
Raja.prototype.urlParams = urlParams;

function urlQuery(url, query) {
	if (!query) return url;
	var comps = [];
	for (var k in query) comps.push({key: k, val: query[k]});
	comps.sort(function(a, b) {
		if (a.key < b.key) return 1;
		else if (a.key > b.key) return -1;
		else return 0;
	});
	var str, list = [];
	for (var i=0; i < comps.length; i++) {
		str = encodeURIComponent(comps[i].key);
		if (comps[i].val != null) str += '=' + encodeURIComponent(comps[i].val);
		list.push(str);
	}
	if (list.length) {
		if (url.indexOf('?') > 0) url += '&';
		else url += '?';
		url += list.join('&');
	}
	return url;
}
Raja.prototype.urlQuery = urlQuery;

for (var method in {GET:1, PUT:1, POST:1, DELETE:1}) {
	Raja.prototype[method] = (function(method) { return function(url, query, body, cb) {
		if (!cb) {
			if (typeof body == "function") {
				cb = body;
				body = null;
			} else if (typeof query == "function") {
				cb = query;
				query = null;
			} else {
				cb = function(err) {
					if (err) console.error(err);
				};
			}
		}
		// consume parameters from query object
		url = urlParams(url, query);
		url = absolute(this.room, url);
		if (/^(HEAD|GET|COPY)$/i.test(method)) {
			query = query || body || {};
		} else {
			// give priority to body
			if (!body && query) {
				body = query;
				query = null;
			}
			if (body) body = JSON.stringify(body);
		}
		url = urlQuery(url, query);
		var xhr = new XMLHttpRequest();
		xhr.open(method, url, true);
		xhr.setRequestHeader('Accept', 'application/json');
		if (body) xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
		xhr.onreadystatechange = function (e) {
			if (xhr.readyState == 4) {
				var code = xhr.status;
				var response = tryJSON(xhr.responseText);
				if (code >= 200 && code < 400) {
					cb(null, response);
				} else {
					var err = new Error(response);
					err.code = code;
					cb(err);
				}
			}
		};
		xhr.send(body);
		return xhr;
	};})(method);
}

function loadScript(url, cb) {
	var script = document.createElement("script");
	script.async = true;
	script.type = 'text/javascript';
	script.charset = 'utf-8';
	script.src = url;
	function done() {
		script.onload = null;
		script.onerror = null;
		if (script.parentNode) {
			script.parentNode.removeChild(script);
		}
		script = null;
	}
	script.onload = function() {
		done();
		cb();
	};
	script.onerror = function(e) {
		done();
		cb(e);
	};
	// Circumvent IE6 bugs with base elements
	document.head.insertBefore(script, document.head.firstChild);
}
Raja.prototype.loadScript = loadScript;

function tryJSON(txt) {
	var obj;
	try {
		obj = JSON.parse(txt);
	} catch(e) {
		return txt;
	}
	return obj;
}

function tryDate(txt) {
	if (!txt) return;
	var date = new Date(txt);
	var time = date.getTime();
	if (isNaN(time)) return;
	else return date;
}

function $(str) {
	return document.querySelector(str);
}

function keyToUrl(key) {
	var find = /^(.*\s)?(https?:\/\/.+)$/.exec(key);
	if (find != null && find.length == 3) {
		if (find[2]) return find[2];
	}
	return key;
}

window.raja = new Raja();

})();
<commit_msg>Parse attribute to int before new Date()<commit_after>/*
 * raja browser client
 */
(function() {

function Raja() {
	this.delays = [];
	this.ready();
}

Raja.prototype.delay = function(url, query, listener) {
	this.delays.push([url, query, listener]);
	return this;
};

Raja.prototype.ready = function() {
	this.root = document.getElementById('raja');
	if (!this.root) return;
	var self = this;
	if (!this.pool) {
		this.pool = (this.root.getAttribute('client') || '').split(' ');
		loadScript(randomEl(this.pool) + '/socket.io/socket.io.js', function(err) {
			if (err) throw err;
			var proto = io.Manager.prototype;
			self._on = proto.on;
			self._emit = proto.emit;
			self.off = proto.off;
			self.listeners = proto.listeners;
			self.ready();
		});
		this.namespace = this.root.getAttribute('namespace') || '';
		this.room = this.root.getAttribute('room');
		if (!this.room) throw new Error("Raja cannot connect without a room url");
	}
	if (!window.io) {
		return;
	}

	var lastMod = this.root.getAttribute('last-modified');
	var now = new Date();
	if (!lastMod) {
		// work around webkit bug https://bugs.webkit.org/show_bug.cgi?id=4363
		lastMod = Date.parse(document.lastModified);
		var diff = (new Date(now.toLocaleString())).getTimezoneOffset() - now.getTimezoneOffset();
		if (!diff) diff = now.getTimezoneOffset() * 60000;
		else diff = 0;
		lastMod = lastMod - diff;
	} else {
		lastMod = parseInt(lastMod);
	}

	this.mtime = isNaN(lastMod) ? now : new Date(lastMod);
	this.root.setAttribute('last-modified', this.mtime.getTime());
	this.resources = JSON.parse(this.root.getAttribute('resources')) || {};
	for (var url in this.resources) {
		this.resources[url] = {mtime: tryDate(this.resources[url])};
	}
	var list = this.delays;
	delete this.delays;
	for (var i=0; i < list.length; i++) {
		this.on.apply(this, list[i]);
	}
};

Raja.prototype.update = function() {
	var resources = {};
	for (var url in this.resources) resources[url] = this.resources[url].mtime;
	this.root.setAttribute('resources', JSON.stringify(resources));
};

Raja.prototype.emit = function(what) {
	var args = Array.prototype.slice.call(arguments, 0);
	try {
		this._emit.apply(this, args);
	} catch(e) {
		console.error(e);
	}
	if (what == "error" && this.listeners("error").length == 0) {
		args.shift();
		console.error.apply(console, args);
	}
};

Raja.prototype.on = function(url, query, listener) {
	if (!listener && typeof query == "function") {
		listener = query;
		query = null;
	}
	if (!this.resources) {
		return this.delay(url, query, listener);
	}
	if (!this.io) this.setio();
	var self = this;
	if (url == "error") return this._on(url, listener);
	var plistener = function() {
		try {
			listener.apply(null, Array.prototype.slice.call(arguments));
		} catch(e) {
			self.emit('error', e);
		}
	};
	url = absolute(this.room, url);
	url = urlQuery(url, query);
	this._on(url, plistener);
	var resources = this.resources;
	var resource = resources[url];
	if (!resource) resource = resources[url] = {};
	if (resource.error) return;

	(function(next) {
		var reqs = resource.requests;
		if (resource.data !== undefined) {
			listener(resource.data, {
				method: "get",
				url: url,
				mtime: resource.mtime
			});
			return next();
		} else if (resource.mtime !== undefined) {
			// resource merged, just join it
			return next();
		} else if (resource.queue) {
			// resource is currently loading
			resource.queue.push(listener);
			return;
		}
		// resource has not been loaded, is not loading. Proceed
		resource.queue = [listener];
		var xhr = Raja.prototype.GET(url, function(err, obj) {
			if (err) {
				resource.error = err;
				return next(err);
			}
			var mtime = tryDate(xhr.getResponseHeader("Last-Modified"));
			resource.mtime = mtime;
			self.update();
			resource.data = obj;
			for (var i=0; i < resource.queue.length; i++) {
				try {
					resource.queue[i](obj, {
						method: "get",
						url: url,
						query: query,
						mtime: mtime
					});
				} catch(e) {
					console.error(e);
				}
			}
			delete resource.queue;
			next();
		});
	})(function(err) {
		if (err) self.emit('error', err);
	});
	return this;
};

Raja.prototype.setio = function() {
	var iohost = randomEl(this.pool);
	if (iohost.substring(0, 2) == '//') iohost = document.location.protocol + iohost;
	this.io = io(iohost + '/' + this.namespace);
	var self = this;
	this.io.once('reconnect_failed', function(err) {
		if (err) self.emit('error', err);
		self.io.removeAllListeners('message');
		setTimeout(function() {
			self.setio();
		}, 1000);
	});
	this.io.emit('join', {
		room: this.room,
		mtime: this.mtime.getTime()
	});

	this.io.on('message', function(msg) {
		if (!msg.url) return;
		var data = msg.data;
		if (data) delete msg.data;
		var stamp = msg.mtime;
		var mtime = tryDate(stamp);
		if (mtime) msg.mtime = mtime;
		var fresh = msg.mtime > self.mtime;
		if (fresh) {
			self.mtime = msg.mtime;
			self.root.setAttribute('last-modified', stamp);
		}
		var parents = msg.parents;
		parents.unshift(msg.url);
		for (var i=0; i < parents.length; i++) {
			var url = keyToUrl(parents[i]);
			var resource = self.resources[url];
			if (resource) {
				if (!resource.mtime || msg.mtime > resource.mtime) resource.mtime = msg.mtime;
				self.emit(url, data, msg);
			} else if (fresh && url != self.url) {
				// some dependency that isn't a resource - a static file ? - has changed
			}
		}
	});
};

function randomEl(arr) {
	var index = parseInt(Math.random() * arr.length);
	return arr[index];
}

function absolute(loc, url) {
	if (/^https?/i.test(url)) return url;
	if (typeof loc == "string") {
		if (!this.a) this.a = document.createElement('a');
		this.a.href = loc;
		loc = {
			href: this.a.href,
			pathname: this.a.pathname,
			protocol: this.a.protocol,
			host: this.a.host
		};
	}
	var path = loc.pathname;
	if (url.indexOf('..') == 0) {
		path = path.split('/');
		path.pop();
		url = path.join('/') + url.substring(2);
	} else if (url == '.') {
		 return loc.href;
	} else if (url.indexOf('.') == 0) {
		url = path + url.substring(1);
	} else if (url.indexOf('/') != 0) {
		var base = path.split('/');
		base.pop();
		base = base.join('/');
		url = base + '/' + url;
	}
	url = loc.protocol + '//' + loc.host + url;
	return url;
}
Raja.prototype.absolute = absolute;

function urlParams(url, params) {
	if (!params) return url;
	return url.replace(/\/:(\w+)/g, function(str, name) {
		var val = params[name];
		if (val != null) {
			delete params[name];
			return '/' + val;
		} else {
			return '/:' + name;
		}
	});
}
Raja.prototype.urlParams = urlParams;

function urlQuery(url, query) {
	if (!query) return url;
	var comps = [];
	for (var k in query) comps.push({key: k, val: query[k]});
	comps.sort(function(a, b) {
		if (a.key < b.key) return 1;
		else if (a.key > b.key) return -1;
		else return 0;
	});
	var str, list = [];
	for (var i=0; i < comps.length; i++) {
		str = encodeURIComponent(comps[i].key);
		if (comps[i].val != null) str += '=' + encodeURIComponent(comps[i].val);
		list.push(str);
	}
	if (list.length) {
		if (url.indexOf('?') > 0) url += '&';
		else url += '?';
		url += list.join('&');
	}
	return url;
}
Raja.prototype.urlQuery = urlQuery;

for (var method in {GET:1, PUT:1, POST:1, DELETE:1}) {
	Raja.prototype[method] = (function(method) { return function(url, query, body, cb) {
		if (!cb) {
			if (typeof body == "function") {
				cb = body;
				body = null;
			} else if (typeof query == "function") {
				cb = query;
				query = null;
			} else {
				cb = function(err) {
					if (err) console.error(err);
				};
			}
		}
		// consume parameters from query object
		url = urlParams(url, query);
		url = absolute(this.room, url);
		if (/^(HEAD|GET|COPY)$/i.test(method)) {
			query = query || body || {};
		} else {
			// give priority to body
			if (!body && query) {
				body = query;
				query = null;
			}
			if (body) body = JSON.stringify(body);
		}
		url = urlQuery(url, query);
		var xhr = new XMLHttpRequest();
		xhr.open(method, url, true);
		xhr.setRequestHeader('Accept', 'application/json');
		if (body) xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
		xhr.onreadystatechange = function (e) {
			if (xhr.readyState == 4) {
				var code = xhr.status;
				var response = tryJSON(xhr.responseText);
				if (code >= 200 && code < 400) {
					cb(null, response);
				} else {
					var err = new Error(response);
					err.code = code;
					cb(err);
				}
			}
		};
		xhr.send(body);
		return xhr;
	};})(method);
}

function loadScript(url, cb) {
	var script = document.createElement("script");
	script.async = true;
	script.type = 'text/javascript';
	script.charset = 'utf-8';
	script.src = url;
	function done() {
		script.onload = null;
		script.onerror = null;
		if (script.parentNode) {
			script.parentNode.removeChild(script);
		}
		script = null;
	}
	script.onload = function() {
		done();
		cb();
	};
	script.onerror = function(e) {
		done();
		cb(e);
	};
	// Circumvent IE6 bugs with base elements
	document.head.insertBefore(script, document.head.firstChild);
}
Raja.prototype.loadScript = loadScript;

function tryJSON(txt) {
	var obj;
	try {
		obj = JSON.parse(txt);
	} catch(e) {
		return txt;
	}
	return obj;
}

function tryDate(txt) {
	if (!txt) return;
	var date = new Date(txt);
	var time = date.getTime();
	if (isNaN(time)) return;
	else return date;
}

function $(str) {
	return document.querySelector(str);
}

function keyToUrl(key) {
	var find = /^(.*\s)?(https?:\/\/.+)$/.exec(key);
	if (find != null && find.length == 3) {
		if (find[2]) return find[2];
	}
	return key;
}

window.raja = new Raja();

})();
<|endoftext|>


<commit_before>/**
 * This is the rift
 */
var express = require('express');
//var app = express();

var app = express();

app.configure(function(){
  app.use(express.bodyParser());
});

/**
var MongoClient = require('mongodb').MongoClient;
var db = MongoClient.connect("mongodb://localhost:27017/cloudrim", function(err, db) {
  if(err) {
    console.log("Failed to connect");
    exit();
  }
});
console.log( db );
*/

var Db = require('mongodb').Db;
var Connection = require('mongodb').Connection;
var Server = require('mongodb').Server;
var BSON = require('mongodb').BSON;
var ObjectID = require('mongodb').ObjectID;

host = "127.0.0.1"
port = 27017

var db = new Db('cloudrim', new Server(host, port, {auto_reconnect: true}, {}), { w: -1 });
db.open(function(){});

app.get('/kaiju', function(req, res){
  db.collection( "kaiju" ).find().toArray(function(err, docs) {
    if(!err){
      var body = JSON.stringify({ data: docs });
      res.setHeader('Content-Type', 'application/json');
      res.setHeader('Content-Length', body.length);
      res.end(body);
    }
  });
});

app.post('/kaiju', function(req, res){
  var kaiju = {
    name: req.body.uuid,
    level: req.body.level
  }
  db.collection( "kaiju" ).insert( kaiju, {w:-1}, function(err, docs){
    if(err){
      console.log( "Error creating kaiju: " + err );
    }else{
      console.log( "Kijui created: " + JSON.stringify( docs ) );
      var body = JSON.stringify({ data: kaiju});
      res.setHeader('Content-Type', 'application/json');
      res.setHeader('Content-Length', body.length);
      res.end(body);
    }
  });
});

app.listen( 9000 );
console.log('Listening on port 9000');
<commit_msg>Updating handler<commit_after>/**
 * This is the rift
 */
var express = require('express');
//var app = express();

var app = express();

app.configure(function(){
  app.use(express.bodyParser());
});

/**
var MongoClient = require('mongodb').MongoClient;
var db = MongoClient.connect("mongodb://localhost:27017/cloudrim", function(err, db) {
  if(err) {
    console.log("Failed to connect");
    exit();
  }
});
console.log( db );
*/

var Db = require('mongodb').Db;
var Connection = require('mongodb').Connection;
var Server = require('mongodb').Server;
var BSON = require('mongodb').BSON;
var ObjectID = require('mongodb').ObjectID;

host = "127.0.0.1"
port = 27017

var db = new Db('cloudrim', new Server(host, port, {auto_reconnect: true}, {}), { w: -1 });
db.open(function(){});

app.get('/kaiju', function(req, res){
  db.collection( "kaiju" ).find().sort({ name: 1 }).limit( 10 ).toArray(function(err, docs) {
    if(!err){
      var body = JSON.stringify({ data: docs });
      res.setHeader('Content-Type', 'application/json');
      res.setHeader('Content-Length', body.length);
      res.end(body);
    }
  });
});

app.post('/kaiju', function(req, res){
  var kaiju = {
    name: req.body.uuid,
    level: req.body.level
  }
  db.collection( "kaiju" ).insert( kaiju, {w:-1}, function(err, docs){
    if(err){
      console.log( "Error creating kaiju: " + err );
    }else{
      console.log( "Kijui created: " + JSON.stringify( docs ) );
      var body = JSON.stringify({ data: kaiju});
      res.setHeader('Content-Type', 'application/json');
      res.setHeader('Content-Length', body.length);
      res.end(body);
    }
  });
});

app.listen( 9000 );
console.log('Listening on port 9000');
<|endoftext|>


<commit_before>/*

	ROBO entry point

*/

var RoboEvents = require('./receiver.js');
var roboMotion = require('./motion-control.js');

var twitter = new RoboEvents.Twitter;
var firebase = new RoboEvents.Firebase;

twitter.init()
	.on('stream.tweet',function(data){
		console.log(data.text);
	});

firebase.init()
	.on('moodChange',function(mood){
		console.log(mood + "robo");
	})
	.on('motionControl',function(motion){
		console.log(motion + " robo");

		if( roboMotion.board.ready ){
			if( motion == "forward"){
				roboMotion.forward();
			}

			if( motion == "back"){
				roboMotion.back();
			}

			if( motion == "stop"){
				roboMotion.forward();
			}
		}

	});

//Test the motion detection module

//require('./motion-detection.js');

//Test the motor module

<commit_msg>fix for motion control stop<commit_after>/*

	ROBO entry point

*/

var RoboEvents = require('./receiver.js');
var roboMotion = require('./motion-control.js');

var twitter = new RoboEvents.Twitter;
var firebase = new RoboEvents.Firebase;

twitter.init()
	.on('stream.tweet',function(data){
		console.log(data.text);
	});

firebase.init()
	.on('moodChange',function(mood){
		console.log(mood + "robo");
	})
	.on('motionControl',function(motion){
		console.log(motion + " robo");

		if( roboMotion.board.ready ){
			if( motion == "forward"){
				roboMotion.forward();
			}

			if( motion == "back"){
				roboMotion.back();
			}

			if( motion == "stop"){
				roboMotion.stop();
			}
		}

	});

//Test the motion detection module

//require('./motion-detection.js');

//Test the motor module

<|endoftext|>


<commit_before>/**
 * Created by Dean on 6/21/2015.
 */

var QUESTIFY = (function (QUESTIFY) {
	"use strict";
	function createQuest (actions, argumentsArr) {
		var that = {},
			finishedMap = new Array(actions.length),
			actionFinishedCallback = function () {},
			questFinishedCallback = function () {};

		(function initializeFinishedMap() {
			for (var i = 0, il = finishedMap.length; i < il; i++) {
				finishedMap[i] = false;
			}
		}());

		function reportQuestFinished() {
			questFinishedCallback();
		}

		function reportActionFinished(finishedAction, args) {
			actionFinishedCallback(finishedAction, args);
		}

		function isFinished() {
			return finishedMap.indexOf(false) === -1;
		}

		function completionPercentage() {
			var finishedCount = 0;

			for (var f = 0, fl = finishedMap.length; f < fl; f++) {
				if (finishedMap[f] === true) { finishedCount++; }
			}

			return (finishedMap.length !== 0) ? finishedCount/finishedMap.length : 0;
		}

		function getActionDescription(actionNumber) {
			if (actionNumber < descriptions.length && actionNumber >= 0) {
				return descriptions[actionNumber];
			}

			return "";
		}

		function setActionDescription(actionNumber, description) {
			if (actionNumber < descriptions.length && actionNumber >= 0) {
				description[actionNumber] = description;
			}
		}

		function getActionStatus(actionNumber) {
			if (actionNumber < finishedMap.length && actionNumber >= 0) {
				return finishedMap[actionNumber];
			}

			return false;
		}

		that.updateState = function() {
			var action;
			for (var a = 0, al = actions.length; a < al; a++) {
				action = actions[a];
				if (finishedMap[a] === false) {
					finishedMap[a] = (action.update(argumentsArr[a]) === true);

					if (finishedMap[a] === false) { return; }
					if (finishedMap[a] === true) { reportActionFinished(action, argumentsArr[a]); }
				}
			}

			if (isFinished()) { reportQuestFinished(); }
		};

		that.isFinished = isFinished;
		that.completionPercentage = completionPercentage;
		that.actionFinishedCallback = actionFinishedCallback;
		that.questFinishedCallback = questFinishedCallback;
		that.getActionDescription = getActionDescription;
		that.setActionDescription = setActionDescription;

		return that;
	}

	QUESTIFY.createQuest = createQuest;

	return QUESTIFY;
}(QUESTIFY || {}));<commit_msg>Added strategy/descriptions parameters. Strategy is public.<commit_after>/**
 * Created by Dean on 6/21/2015.
 */

var QUESTIFY = (function (QUESTIFY) {
	"use strict";
	function createQuest (strategy, actions, argumentsArr, descriptions) {
		var that = {},
			finishedMap = new Array(actions.length),
			actionFinishedCallback = function () {},
			questFinishedCallback = function () {};

		(function initializeFinishedMap() {
			for (var i = 0, il = finishedMap.length; i < il; i++) {
				finishedMap[i] = false;
			}
		}());

		function reportQuestFinished() {
			questFinishedCallback();
		}

		function reportActionFinished(finishedAction, args) {
			actionFinishedCallback(finishedAction, args);
		}

		function isFinished() {
			return finishedMap.indexOf(false) === -1;
		}

		function completionPercentage() {
			var finishedCount = 0;

			for (var f = 0, fl = finishedMap.length; f < fl; f++) {
				if (finishedMap[f] === true) { finishedCount++; }
			}

			return (finishedMap.length !== 0) ? finishedCount/finishedMap.length : 0;
		}

		function getActionDescription(actionNumber) {
			if (actionNumber < descriptions.length && actionNumber >= 0) {
				return descriptions[actionNumber];
			}

			return "";
		}

		function setActionDescription(actionNumber, description) {
			if (actionNumber < descriptions.length && actionNumber >= 0) {
				description[actionNumber] = description;
			}
		}

		function getActionStatus(actionNumber) {
			if (actionNumber < finishedMap.length && actionNumber >= 0) {
				return finishedMap[actionNumber];
			}

			return false;
		}

		that.updateState = function() {
			var action;
			for (var a = 0, al = actions.length; a < al; a++) {
				action = actions[a];
				if (finishedMap[a] === false) {
					finishedMap[a] = (action.update(argumentsArr[a]) === true);

					if (finishedMap[a] === false) { return; }
					if (finishedMap[a] === true) { reportActionFinished(action, argumentsArr[a]); }
				}
			}

			if (isFinished()) { reportQuestFinished(); }
		};

		that.actions = actions;
		that.strategy = strategy;
		that.isFinished = isFinished;
		that.completionPercentage = completionPercentage;
		that.actionFinishedCallback = actionFinishedCallback;
		that.questFinishedCallback = questFinishedCallback;
		that.getActionDescription = getActionDescription;
		that.setActionDescription = setActionDescription;

		return that;
	}

	QUESTIFY.createQuest = createQuest;

	return QUESTIFY;
}(QUESTIFY || {}));<|endoftext|>


<commit_before>// board is double array
// snake is a list w/head and tail

snake = [[1, 0], [0, 0]]; // x, y
dir = 'right';
var board = [];     // top left is 0, 0, bottom right is height-1, width-1
var food = [-1, -1];
var refreshRate = 500; // How quickly the snake moves. (ms)
var intervalId = null;

// initialize board and snake, and start snake movement
function initSnake() {
  console.log(intervalId);
  if (intervalId !== null) {
    console.log("Intervalid is null");
    return;
  }
  board.length = width; // board[x][y]
  for (var i = 0; i < width; i++) {
    board[i] = [];
    board[i].length = height;
  }
  intervalId = window.setInterval(aiLevel0, refreshRate);
  aiLevel0();
  updateBoard();
}

function speedUp() {
  refreshRate /= 1.5; // 50% faster
  window.clearInterval(intervalId);
  intervalId = window.setInterval(aiLevel0, refreshRate);
}

// String is of form x_y to allow compatibility with Board.js
function inSnake(string) {
  for (var s=0; s<snake.length; s++) {
    if (string == snake[s][0]+'_'+snake[s][1]) {
      return true;
    }
  }
  return false;
}

function moveHead(dir) {
  // move snake's head in given direction
  // 'right', 'left', 'up', and 'down'
  var newHead = snake[0];
  if (dir == 'up') {  // add new head above current one
    newHead[1]--;  // changes y-coordinate by -1 (going UP)
  } else if (dir == 'down') {
    newHead[1]++;
  } else if (dir == 'right') {
    newHead[0]++;
  } else if (dir == 'left') {
    newHead[0]--;
  }
//  if (newHead[0] < 0 || newHead[0] >= width || newHead[1] < 0 || newHead[1] >= height) {

//  }
  snake.unshift(newHead); // add newHead to the beginning of the list
  console.log(snake);
  updateBoard();
  if (snake[0][0] == food[0] && snake[0][1] == food[1]) { // if snake's head is on the food
    food = [-1, -1];
  } else {
    delTail();
  }
}

function delTail() {  // simple function to remove the tail
  console.log(snake.pop());
  updateBoard();
}

function placeFood(x, y) {
  initSnake();
  if (inSnake(x+'_'+y)) {
    console.log('Invalid food placement: Food collides with snake');
		return;
	}
	if (!(food[0] == -1 && food[1] == -1)) { // already food
		console.log('Invalid food placement: There is already food');
	} else if (x >= width || y >= height || x < 0 || y < 0) { // off of board
		console.log('Invalid food placement: Food is off board');
	} else {
		food = [x, y];
		console.log('Food placed at '+x+' '+y);
    updateBoard();
	}
}
<commit_msg>Added bounds checking to movement<commit_after>// board is double array
// snake is a list w/head and tail

snake = [[1, 0], [0, 0]]; // x, y
dir = 'right';
var board = [];     // top left is 0, 0, bottom right is height-1, width-1
var food = [-1, -1];
var refreshRate = 300; // How quickly the snake moves. (ms)
var intervalId = null;

// initialize board and snake, and start snake movement
function initSnake() {
  console.log(intervalId);
  if (intervalId !== null) {
    console.log("Intervalid is null");
    return;
  }
  board.length = width; // board[x][y]
  for (var i = 0; i < width; i++) {
    board[i] = [];
    board[i].length = height;
  }
  intervalId = window.setInterval(aiLevel0, refreshRate);
  aiLevel0();
  updateBoard();
}

function speedUp() {
  refreshRate /= 1.5; // 50% faster
  window.clearInterval(intervalId);
  intervalId = window.setInterval(aiLevel0, refreshRate);
}

// String is of form x_y to allow compatibility with Board.js
function inSnake(string) {
  for (var s=0; s<snake.length; s++) {
    if (string == snake[s][0]+'_'+snake[s][1]) {
      return true;
    }
  }
  return false;
}

function moveHead(dir) {
  // move snake's head in given direction
  // 'right', 'left', 'up', and 'down'
  var newHead = snake[0];
  if (dir == 'up') {  // add new head above current one
    if (newHead[1] === 0) {
      throw 'cannot move up from ' + newHead[0] + ', ' + newHead[1];
    }
    newHead[1]--;  // changes y-coordinate by -1 (going UP)
  } else if (dir == 'down') {
    if (newHead[1] == height - 1) {
      throw 'cannot move down from ' + newHead[0] + ', ' + newHead[1];
    }
    newHead[1]++;
  } else if (dir == 'right') {
    if (newHead[0] == width - 1) {
      throw 'cannot move right from' + newHead[0] + ', ' + newHead[1];
    }
    newHead[0]++;
  } else if (dir == 'left') {
    if (newHead[0] === 0) {
      throw 'cannot move left from' + newHead[0] + ', ' + newHead[1];
    }
    newHead[0]--;
  }
  snake.unshift(newHead); // add newHead to the beginning of the list
  console.log(snake);
  updateBoard();
  if (snake[0][0] == food[0] && snake[0][1] == food[1]) { // if snake's head is on the food
    food = [-1, -1];
  } else {
    delTail();
  }
}

function delTail() {  // simple function to remove the tail
  console.log(snake.pop());
  updateBoard();
}

function placeFood(x, y) {
  initSnake();
  if (inSnake(x+'_'+y)) {
    console.log('Invalid food placement: Food collides with snake');
		return;
	}
	if (!(food[0] == -1 && food[1] == -1)) { // already food
		console.log('Invalid food placement: There is already food');
	} else if (x >= width || y >= height || x < 0 || y < 0) { // off of board
		console.log('Invalid food placement: Food is off board');
	} else {
		food = [x, y];
		console.log('Food placed at '+x+' '+y);
    updateBoard();
	}
}
<|endoftext|>


<commit_before>Ext.define('Mba.ux.Data.Store', {
    override: 'Ext.data.Store',
    requires: ['Ext.ux.Deferred'],

    applyProxy: function(proxy, currentProxy) {
        if (Ext.isObject(proxy)) {
            if (!proxy.model) {
                proxy.model = this.getModel().$className;
            }
        }
        proxy = Ext.factory(proxy, Ext.data.Proxy, currentProxy, 'proxy');
        if (!proxy && this.getModel()) {
            proxy = this.getModel().getProxy();
        }

        if (!proxy) {
            proxy = new Ext.data.proxy.Memory({
                model: this.getModel()
            });
        }

        if (proxy.isMemoryProxy) {
            this.setSyncRemovedRecords(false);
        }
        return proxy;
    },

    /** Constroi a promise e faz o wrap do callback do usuario
     *  @return {Object} Contexto de execucao
     *  @return {Object} return.dfd: A instancia do deferred com a promessa
     *  @return {Object} return.options: Objeto options alterado para ser passado para callParent
     *  @return {Object} return.scope: Escopo de chamada, o mesmo scope passado para a funcao
     *  @private
     **/
    prepareDeferred: function(options, scope) {
        var dfd = Ext.create('Ext.ux.Deferred'),
            userCallback = Ext.emptyFn,
            me = this,
            argumentsPromise;

        options = options || {};

        if (Ext.isFunction(options)) {
            userCallback = options;
            options = {};
        } else if (Ext.isObject(options)) {
            userCallback = options.callback || Ext.emptyFn;
        }

        options.callback = function() {
            userCallback.apply(me, arguments);
            argumentsPromise = Ext.Array.slice(arguments);
            argumentsPromise.push(me);
            if (arguments[2]) {
                dfd.resolve.apply(dfd, argumentsPromise);
                return;
            }
            dfd.reject.apply(dfd, argumentsPromise);
        };

        return {
            dfd: dfd,
            options: options,
            scope: scope
        };
    },

    /** Executa uma funcao de load deffered. Os parametros sao os mesmos
     *  de uma store normal
     *  @returns {Object} Uma promessa de load */
    load: function(options, scope) {
        var r = this.prepareDeferred(options, scope),
            promise = r.dfd.promise();
        this.callParent([r.options, r.scope]);
        return promise;
    },

    /** Executa uma funcao de loadPage deffered. Os parametros sao os mesmos
     *  de uma store normal
     *  @returns {Object} Uma promessa de loadPage */
    loadPage: function(page, options, scope) {
        var r = this.prepareDeferred(options, scope),
            promise = r.dfd.promise();
        this.callParent([page, r.options, r.scope]);
        return promise;
    },

    /** Executa uma funcao de nextPage deffered. Os parametros sao os mesmos
     *  de uma store normal
     *  @returns {Object} Uma promessa de nextPage */
    nextPage: function(options) {
        var r = this.prepareDeferred(options),
            promise = r.dfd.promise();
        this.callParent([r.options]);
        return promise;
    },

    /** Executa uma funcao de previousPage deffered. Os parametros sao os mesmos
     *  de uma store normal
     *  @returns {Object} Uma promessa de previousPage */
    previousPage: function(options) {
        var r = this.prepareDeferred(options),
            promise = r.dfd.promise();
        this.callParent([r.options]);
        return promise;
    }
});
<commit_msg>ajuste para verificar conexão nos proxys remotos e falhar na promise<commit_after>Ext.define('Mba.ux.Data.Store', {
    override: 'Ext.data.Store',

    requires: [
        'Ext.ux.Deferred',
        'Ext.device.Connection'
    ],

    applyProxy: function(proxy, currentProxy) {
        if (Ext.isObject(proxy)) {
            if (!proxy.model) {
                proxy.model = this.getModel().$className;
            }
        }
        proxy = Ext.factory(proxy, Ext.data.Proxy, currentProxy, 'proxy');
        if (!proxy && this.getModel()) {
            proxy = this.getModel().getProxy();
        }

        if (!proxy) {
            proxy = new Ext.data.proxy.Memory({
                model: this.getModel()
            });
        }

        if (proxy.isMemoryProxy) {
            this.setSyncRemovedRecords(false);
        }
        return proxy;
    },

    /** Constroi a promise e faz o wrap do callback do usuario
     *  @return {Object} Contexto de execucao
     *  @return {Object} return.dfd: A instancia do deferred com a promessa
     *  @return {Object} return.options: Objeto options alterado para ser passado para callParent
     *  @return {Object} return.scope: Escopo de chamada, o mesmo scope passado para a funcao
     *  @private
     **/
    prepareDeferred: function(options, scope) {
        var dfd = Ext.create('Ext.ux.Deferred'),
            userCallback = Ext.emptyFn,
            me = this,
            argumentsPromise;

        options = options || {};

        if (Ext.isFunction(options)) {
            userCallback = options;
            options = {};
        } else if (Ext.isObject(options)) {
            userCallback = options.callback || Ext.emptyFn;
        }

        options.callback = function() {
            userCallback.apply(me, arguments);
            argumentsPromise = Ext.Array.slice(arguments);
            argumentsPromise.push(me);
            if (arguments[2]) {
                dfd.resolve.apply(dfd, argumentsPromise);
                return;
            }
            dfd.reject.apply(dfd, argumentsPromise);
        };

        return {
            dfd: dfd,
            options: options,
            scope: scope
        };
    },

    /** Executa uma funcao de load deffered. Os parametros sao os mesmos
     *  de uma store normal
     *  @returns {Object} Uma promessa de load */
    load: function(options, scope) {
        var r = this.prepareDeferred(options, scope),
            promise = r.dfd.promise(), remoteProxys = ['Mba.ux.Data.MbaRestProxy', 'Ext.data.proxy.Ajax',
            'Ext.data.proxy.Rest'];
        if (this.getProxy() && remoteProxys.indexOf(this.getProxy().$className) !== -1) {
            if (!Ext.device.Connection.isOnline()) {
                r.dfd.reject([], {
                    error: {
                        statusText: 'Sem conexão de dados.'
                    }
                });
                return promise;
            }
        }

        this.callParent([r.options, r.scope]);
        return promise;
    },

    /** Executa uma funcao de loadPage deffered. Os parametros sao os mesmos
     *  de uma store normal
     *  @returns {Object} Uma promessa de loadPage */
    loadPage: function(page, options, scope) {
        var r = this.prepareDeferred(options, scope),
            promise = r.dfd.promise();
        this.callParent([page, r.options, r.scope]);
        return promise;
    },

    /** Executa uma funcao de nextPage deffered. Os parametros sao os mesmos
     *  de uma store normal
     *  @returns {Object} Uma promessa de nextPage */
    nextPage: function(options) {
        var r = this.prepareDeferred(options),
            promise = r.dfd.promise();
        this.callParent([r.options]);
        return promise;
    },

    /** Executa uma funcao de previousPage deffered. Os parametros sao os mesmos
     *  de uma store normal
     *  @returns {Object} Uma promessa de previousPage */
    previousPage: function(options) {
        var r = this.prepareDeferred(options),
            promise = r.dfd.promise();
        this.callParent([r.options]);
        return promise;
    }
});
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react'
import Match from 'react-router/Match';

/* shared stripes components */
import Pane from '@folio/stripes-components/lib/Pane'
import Paneset from '@folio/stripes-components/lib/Paneset'
import PaneMenu from '@folio/stripes-components/lib/PaneMenu'
import Button from '@folio/stripes-components/lib/Button'
import Icon from '@folio/stripes-components/lib/Icon'
import MultiColumnListUsers from './lib/MultiColumnList'
import KeyValue from '@folio/stripes-components/lib/KeyValue'
import {Row, Col} from 'react-bootstrap'
import TextField from '@folio/stripes-components/lib/TextField'
import Checkbox from '@folio/stripes-components/lib/Checkbox'
import FilterPaneSearch from '@folio/stripes-components/lib/FilterPaneSearch'
import FilterControlGroup from '@folio/stripes-components/lib/FilterControlGroup'
import Select from '@folio/stripes-components/lib/Select'
import ViewUser from './ViewUser'

class Users extends React.Component{
  static contextTypes = {
    router: PropTypes.object.isRequired
  };

  constructor(props){
    super(props);
    this.state={
      //Search/Filter state...
      patronFilter: true,
      employeeFilter: false,
      searchTerm: ''
    };

    this.onChangeSearch = this.onChangeSearch.bind(this);
    this.onClearSearch = this.onClearSearch.bind(this);
  }

  static manifest = {
    users: {
      type: 'okapi',
      records: 'users',
      path: 'users?query={"username":"?{query}"}',
      // And when we move to PostgreSQL: ?query=[{"field":"'username'","value":"knord","op":"="}]
      staticFallback: { path: 'users' },
    }
  };

  //search Handlers...
  onChangeFilter(e){
    let stateObj = {};
    stateObj[e.target.id] = !this.state[e.target.id];
    this.setState(stateObj);
  }

  onChangeSearch(e){
    let term = e.target.value;
    console.log("User searched:", term);
    this.setState({ 'searchTerm': term });
    this.context.router.transitionTo('/users?query=' + term);
  }

  onClearSearch(e){
    console.log("User cleared search");
    this.setState({ 'searchTerm': '' });
    this.context.router.transitionTo("/users");
  }
  //end search Handlers

  onClickItemHandler (userId) {
    console.log("User clicked: ",userId);
    this.context.router.transitionTo("/users/view/"+userId);
  }

  render(){
    const { data, params, pathname } = this.props;
    if (!data.users) return <div/>;
    const resultMenu = <PaneMenu><button><Icon icon="bookmark"/></button></PaneMenu>
    const displayUsers = data.users.reduce((results, user) => {
      results.push({"id": user.id, Name: user.personal.full_name, Username: user.username, Email: user.personal.email_primary});
      return results;
    }, []);

    /*searchHeader is a 'custom pane header'*/
    const searchHeader = <FilterPaneSearch id="SearchField" onChange={this.onChangeSearch} onClear={this.onClearSearch} value={this.state.searchTerm} />
    console.log(params);

    return(
            <Paneset>
              {/*Filter Pane */}
              <Pane defaultWidth="16%" header={searchHeader}>
                <FilterControlGroup label="Filters">
                  <Checkbox
                    id="patronFilter"
                    label="Patrons"
                    checked={this.state.patronFilter}
                    onChange={this.onChangeFilter.bind(this)}
                    marginBottom0
                    hover
                    fullWidth
                  />
                  <Checkbox
                    id="employeeFilter"
                    label="Employees"
                    checked={this.state.employeeFilter}
                    onChange={this.onChangeFilter.bind(this)}
                    marginBottom0 hover fullWidth
                  />
                </FilterControlGroup>
                <FilterControlGroup label="Actions">
                  <Button fullWidth>Add User</Button>
                </FilterControlGroup>
              </Pane>

              {/*Results Pane*/}
              <Pane defaultWidth="fit-content" paneTitle="Results" lastMenu={resultMenu}>
                     <MultiColumnListUsers contentData={displayUsers} onClickItemHandler={this.onClickItemHandler.bind(this)}/>
              </Pane>

              {/*Details Pane*/}
              <Match pattern={`${pathname}/view/:userid`} component={ViewUser}/>
            </Paneset>
            )
  }

}

export default Users;
<commit_msg>Fix STRIPES-106: changes to the query don't discard the viewed record.<commit_after>import React, { PropTypes } from 'react'
import Match from 'react-router/Match';

/* shared stripes components */
import Pane from '@folio/stripes-components/lib/Pane'
import Paneset from '@folio/stripes-components/lib/Paneset'
import PaneMenu from '@folio/stripes-components/lib/PaneMenu'
import Button from '@folio/stripes-components/lib/Button'
import Icon from '@folio/stripes-components/lib/Icon'
import MultiColumnListUsers from './lib/MultiColumnList'
import KeyValue from '@folio/stripes-components/lib/KeyValue'
import {Row, Col} from 'react-bootstrap'
import TextField from '@folio/stripes-components/lib/TextField'
import Checkbox from '@folio/stripes-components/lib/Checkbox'
import FilterPaneSearch from '@folio/stripes-components/lib/FilterPaneSearch'
import FilterControlGroup from '@folio/stripes-components/lib/FilterControlGroup'
import Select from '@folio/stripes-components/lib/Select'
import ViewUser from './ViewUser'

class Users extends React.Component{
  static contextTypes = {
    router: PropTypes.object.isRequired
  };

  constructor(props){
    super(props);
    this.state={
      //Search/Filter state...
      patronFilter: true,
      employeeFilter: false,
      searchTerm: ''
    };

    this.onChangeSearch = this.onChangeSearch.bind(this);
    this.onClearSearch = this.onClearSearch.bind(this);
  }

  static manifest = {
    users: {
      type: 'okapi',
      records: 'users',
      path: 'users?query={"username":"?{query}"}',
      // And when we move to PostgreSQL: ?query=[{"field":"'username'","value":"knord","op":"="}]
      staticFallback: { path: 'users' },
    }
  };

  //search Handlers...
  onChangeFilter(e){
    let stateObj = {};
    stateObj[e.target.id] = !this.state[e.target.id];
    this.setState(stateObj);
  }

  onChangeSearch(e){
    let term = e.target.value;
    console.log("User searched:", term, "at", this.props.location.pathname);
    this.setState({ 'searchTerm': term });
    this.context.router.transitionTo(this.props.location.pathname + '?query=' + term);
  }

  onClearSearch(e){
    console.log("User cleared search");
    this.setState({ 'searchTerm': '' });
    this.context.router.transitionTo("/users");
  }
  //end search Handlers

  onClickItemHandler (userId) {
    console.log("User clicked: ",userId);
    this.context.router.transitionTo("/users/view/"+userId);
  }

  render(){
    const { data, params, pathname } = this.props;
    if (!data.users) return <div/>;
    const resultMenu = <PaneMenu><button><Icon icon="bookmark"/></button></PaneMenu>
    const displayUsers = data.users.reduce((results, user) => {
      results.push({"id": user.id, Name: user.personal.full_name, Username: user.username, Email: user.personal.email_primary});
      return results;
    }, []);

    /*searchHeader is a 'custom pane header'*/
    const searchHeader = <FilterPaneSearch id="SearchField" onChange={this.onChangeSearch} onClear={this.onClearSearch} value={this.state.searchTerm} />
    console.log(params);

    return(
            <Paneset>
              {/*Filter Pane */}
              <Pane defaultWidth="16%" header={searchHeader}>
                <FilterControlGroup label="Filters">
                  <Checkbox
                    id="patronFilter"
                    label="Patrons"
                    checked={this.state.patronFilter}
                    onChange={this.onChangeFilter.bind(this)}
                    marginBottom0
                    hover
                    fullWidth
                  />
                  <Checkbox
                    id="employeeFilter"
                    label="Employees"
                    checked={this.state.employeeFilter}
                    onChange={this.onChangeFilter.bind(this)}
                    marginBottom0 hover fullWidth
                  />
                </FilterControlGroup>
                <FilterControlGroup label="Actions">
                  <Button fullWidth>Add User</Button>
                </FilterControlGroup>
              </Pane>

              {/*Results Pane*/}
              <Pane defaultWidth="fit-content" paneTitle="Results" lastMenu={resultMenu}>
                     <MultiColumnListUsers contentData={displayUsers} onClickItemHandler={this.onClickItemHandler.bind(this)}/>
              </Pane>

              {/*Details Pane*/}
              <Match pattern={`${pathname}/view/:userid`} component={ViewUser}/>
            </Paneset>
            )
  }

}

export default Users;
<|endoftext|>


<commit_before>import _ from 'lodash'; // eslint-disable-line
import React, { PropTypes, Component } from 'react'; // eslint-disable-line
import Match from 'react-router/Match'; // eslint-disable-line
import {Row, Col} from 'react-bootstrap'; // eslint-disable-line

import Pane from '@folio/stripes-components/lib/Pane'; // eslint-disable-line
import Paneset from '@folio/stripes-components/lib/Paneset'; // eslint-disable-line
import PaneMenu from '@folio/stripes-components/lib/PaneMenu'; // eslint-disable-line
import Button from '@folio/stripes-components/lib/Button'; // eslint-disable-line
import Icon from '@folio/stripes-components/lib/Icon'; // eslint-disable-line
import Checkbox from '@folio/stripes-components/lib/Checkbox'; // eslint-disable-line
import TextField from '@folio/stripes-components/lib/TextField'; // eslint-disable-line
import MultiColumnList from '@folio/stripes-components/lib/MultiColumnList'; // eslint-disable-line
import KeyValue from '@folio/stripes-components/lib/KeyValue'; // eslint-disable-line
import FilterPaneSearch from '@folio/stripes-components/lib/FilterPaneSearch'; // eslint-disable-line
import FilterControlGroup from '@folio/stripes-components/lib/FilterControlGroup'; // eslint-disable-line
import Select from '@folio/stripes-components/lib/Select'; // eslint-disable-line
import Layer from '@folio/stripes-components/lib/Layer'; // eslint-disable-line

import UserForm from './UserForm';
import ViewUser from './ViewUser';

class Users extends Component {
  static contextTypes = {
    router: PropTypes.object.isRequired,
    store: PropTypes.object,
  };

  static propTypes = {
    data: PropTypes.object.isRequired,
    pathname: PropTypes.string.isRequired,
    location: PropTypes.shape({
      pathname: PropTypes.string.isRequired,
      query: PropTypes.object, // object of key=value pairs
      search: PropTypes.string, // string combining all parts of query
    }).isRequired,
    mutator: PropTypes.object,
  };

  static manifest = Object.freeze({
    addUserMode: { },
    users: {
      type: 'okapi',
      records: 'users',
      path: (queryParams, _pathComponents, _resourceValues) => {
        // console.log('Users manifest "users" path function, queryParams = ', queryParams);
        const { query, filterActive, filterInactive, sort } = queryParams || {};

        let cql;
        if (query) {
          cql = `username="${query}*" or personal.first_name="${query}*" or personal.last_name="${query}*"`;
        }

        let filterCql;
        if (filterActive && !filterInactive) {
          filterCql = 'active=true';
        } else if (filterInactive && !filterActive) {
          filterCql = 'active=false';
        } else if (!filterActive && !filterInactive) {
          // Technically, we should force this configuration to find
          // no records; but it probably makes more sense to do
          // nothing, and allow both active AND inactive records.
        }

        if (filterCql) {
          if (cql) {
            cql = `(${cql}) and ${filterCql}`;
          } else {
            cql = filterCql;
          }
        }

        if (sort) {
          const sortMap = {
            Active: 'active',
            Name: 'personal.last_name personal.first_name',
            Username: 'username',
            Email: 'personal.email',
          };
          const sortIndex = sortMap[sort];
          if (sortIndex) {
            if (cql === undefined) cql = 'username=*';
            cql += ` sortby ${sortIndex}`;
          }
        }

        let path = 'users';
        if (cql) path += `?query=title=${encodeURIComponent(cql)}`;

        console.log(`query=${query} active=${filterActive} inactive=${filterInactive} sort=${sort} -> ${path}`);
        return path;
      },
      staticFallback: { path: 'users' },
    }
  });

  constructor(props, context) {
    super(props);

    const query = props.location.query || {};
    this.state = {
      filter: {
        active: query.filterActive || false,
        inactive: query.filterInactive || false,
      },
      selectedItem: {},
      searchTerm: query.query || '',
      sortOrder: query.sort || '',
    };
    props.mutator.addUserMode.replace({ mode: false });

    this.okapi = context.store.getState().okapi;

    this.onClickAddNewUser = this.onClickAddNewUser.bind(this);
    this.onClickCloseNewUser = this.onClickCloseNewUser.bind(this);
    this.onChangeFilter = this.onChangeFilter.bind(this);
    this.performSearch = _.debounce(this.performSearch.bind(this), 250);
    this.onChangeSearch = this.onChangeSearch.bind(this);
    this.onClearSearch = this.onClearSearch.bind(this);
    this.onSort = this.onSort.bind(this);
    this.onSelectRow = this.onSelectRow.bind(this);
  }

  // search Handlers...
  onChangeFilter(e) {
    const filter = this.state.filter;
    filter[e.target.id] = !filter[e.target.id];
    console.log('onChangeFilter setting state', filter);
    this.setState({ filter });
    this.updateSearch(this.state.searchTerm, this.state.sortOrder, filter);
  }

  onChangeSearch(e) {
    const term = e.target.value;
    this.setState({ searchTerm: term });
    this.performSearch(term);
  }

  performSearch(term) {
    console.log('User searched:', term, 'at', this.props.location.pathname);
    const transitionPath = term === "" ?  this.props.location.pathname : `${this.props.location.pathname}?query=${term}`;
    this.context.router.transitionTo(transitionPath);
  }

  onClearSearch() {
    console.log('User cleared search');
    this.setState({ searchTerm: '' });
    this.context.router.transitionTo(this.props.location.pathname);
  }

  onSort(e, meta) {
    const sortOrder = meta.name;
    console.log('User sorted by', sortOrder);
    this.setState({ sortOrder });
    this.updateSearch(this.state.searchTerm, sortOrder, this.state.filter);
  }

  onSelectRow(e, meta) {
    const userId = meta.id;
    console.log('User clicked', userId, 'location = ', this.props.location);
    this.setState({ selectedItem: meta });
    this.context.router.transitionTo(`/users/view/${userId}${this.props.location.search}`);
  }

  // end search Handlers

  // AddUser Handlers
  onClickAddNewUser(e) {
    if (e) e.preventDefault();
    this.props.mutator.addUserMode.replace({ mode: true })
  }

  onClickCloseNewUser(e) {
    if (e) e.preventDefault();
    this.props.mutator.addUserMode.replace({ mode: false })
  }
  // end AddUser Handlers

  // We need to explicitly pass changed values into this function,
  // as state-change only happens after event is handled.
  updateSearch(query, sortOrder, filter) {
    console.log(`updateSearch('${query}', '${sortOrder}',`, filter, ')');
    let transitionLoc = this.props.location.pathname;
    const params = {};
    if (query) params.query = query;
    if (sortOrder) params.sort = sortOrder;
    if (filter.active) params.filterActive = true;
    if (filter.inactive) params.filterInactive = true;
    const keys = Object.keys(params);
    if (keys.length) {
      // eslint-disable-next-line prefer-template
      transitionLoc += '?' + keys.map(key => `${key}=${encodeURIComponent(params[key])}`).join('&');
    }
    this.context.router.transitionTo(transitionLoc);
  }

  create(data) {
    // extract creds object from user object
    const creds = Object.assign({}, data.creds, { username: data.username });
    if (data.creds) delete data.creds;
    // POST user record
    this.props.mutator.users.POST(data);
    // POST credentials, permission-user, permissions;
    this.postCreds(data.username, { credentials: creds });
    this.onClickCloseNewUser();
  }

  postCreds(username, creds) {
    fetch(`${this.okapi.url}/authn/users`, {
      method: 'POST',
      headers: Object.assign({}, { 'X-Okapi-Tenant': this.okapi.tenant, 'X-Okapi-Token': this.okapi.token }),
      body: JSON.stringify(creds),
    }).then((response) => {
      if (response.status >= 400) {
        console.log("Users. POST of creds failed.");
      } else {
        this.postPerms(username, 'users.super');
      }
    });
  }

  postPerms (username, perms) {
    fetch(`${this.okapi.url}/perms/users`, {
      method: 'POST',
      headers: Object.assign({}, { 'X-Okapi-Tenant': this.okapi.tenant, 'X-Okapi-Token': this.okapi.token }),
      body: username,
    }).then((response) => {
      if (response.status >= 400) {
        console.log("Users. POST of username failed.");
      } else {
        this.postUsersPerms(username, perms);
      }
    });
  }

  postUsersPerms(username, perm) {
    fetch(`${this.okapi.url}/perms/users/${username}/permissions`, {
      method: 'POST',
      headers: Object.assign({}, { 'X-Okapi-Tenant': this.okapi.tenant, 'X-Okapi-Token': this.okapi.token }),
      body: JSON.stringify({ permission_name: perm }),
    }).then((response) => {
      if (response.status >= 400) {
        console.log("Users. POST of user's perms failed.");
      } else {
      }
    });

  }

  render() {
    const { data, pathname } = this.props;
    const users = data.users || [];

    /* searchHeader is a 'custom pane header'*/
    const searchHeader = <FilterPaneSearch id="SearchField" onChange={this.onChangeSearch} onClear={this.onClearSearch} value={this.state.searchTerm} />;
    const resultMenu = <PaneMenu><button><Icon icon="bookmark" /></button></PaneMenu>;
    const fineHistory = [{ 'Due Date': '11/12/2014', 'Amount': '34.23', 'Status': 'Unpaid' }]; // eslint-disable-line

    const resultsFormatter = {
      Active: user => user.active,
      Name: user => `${_.get(user, ['personal', 'last_name'], '')}, ${_.get(user, ['personal', 'first_name'], '')}`,
      Username: user => user.username,
      Email: user => _.get(user, ['personal', 'email']),
    };

    return (
      <Paneset>
        {/* Filter Pane */}
        <Pane defaultWidth="16%" header={searchHeader}>
          <FilterControlGroup label="Filters">
            <Checkbox
              id="active"
              label="Active"
              checked={this.state.filter.active}
              onChange={this.onChangeFilter}
              marginBottom0
              hover
              fullWidth
              checkedIcon={<Icon icon="eye" />}
            />
            <Checkbox
              id="inactive"
              label="Inactive"
              checked={this.state.filter.inactive}
              onChange={this.onChangeFilter}
              marginBottom0
              hover
              fullWidth
              checkedIcon={<Icon icon="eye" />}
            />
          </FilterControlGroup>
          <FilterControlGroup label="Actions">
            <Button fullWidth onClick={this.onClickAddNewUser}>New user</Button>
          </FilterControlGroup>
        </Pane>
        {/* Results Pane */}
        <Pane
          defaultWidth="40%"
          paneTitle={

              Results

                {users.length} Result{users.length === 1 ? '' : 's'} Found

          }
          lastMenu={resultMenu}
        >
          <MultiColumnList
            contentData={users}
            selectedRow={this.state.selectedItem}
            rowMetadata={['id']}
            formatter={resultsFormatter}
            onRowClick={this.onSelectRow}
            onHeaderClick={this.onSort}
            visibleColumns={['Active', 'Name', 'Username', 'Email']}
            fullWidth
            sortOrder={this.state.sortOrder}
            isEmptyMessage={`No results found for "${this.state.searchTerm}". Please check your spelling and filters.`}
          />
        </Pane>

        {/* Details Pane */}
        <Match pattern={`${pathname}/view/:userid`} render={props => <ViewUser placeholder={'placeholder'} {...props} />} />
        <Layer isOpen={data.addUserMode ? data.addUserMode.mode : false } label="Add New User Dialog">
          <UserForm
            onSubmit={(record) => { this.create(record); }}
            onCancel={this.onClickCloseNewUser}
          />
        </Layer>
      </Paneset>
    );
  }
}

export default Users;
<commit_msg>Remove extraneous "title=" from every single CQL query!<commit_after>import _ from 'lodash'; // eslint-disable-line
import React, { PropTypes, Component } from 'react'; // eslint-disable-line
import Match from 'react-router/Match'; // eslint-disable-line
import {Row, Col} from 'react-bootstrap'; // eslint-disable-line

import Pane from '@folio/stripes-components/lib/Pane'; // eslint-disable-line
import Paneset from '@folio/stripes-components/lib/Paneset'; // eslint-disable-line
import PaneMenu from '@folio/stripes-components/lib/PaneMenu'; // eslint-disable-line
import Button from '@folio/stripes-components/lib/Button'; // eslint-disable-line
import Icon from '@folio/stripes-components/lib/Icon'; // eslint-disable-line
import Checkbox from '@folio/stripes-components/lib/Checkbox'; // eslint-disable-line
import TextField from '@folio/stripes-components/lib/TextField'; // eslint-disable-line
import MultiColumnList from '@folio/stripes-components/lib/MultiColumnList'; // eslint-disable-line
import KeyValue from '@folio/stripes-components/lib/KeyValue'; // eslint-disable-line
import FilterPaneSearch from '@folio/stripes-components/lib/FilterPaneSearch'; // eslint-disable-line
import FilterControlGroup from '@folio/stripes-components/lib/FilterControlGroup'; // eslint-disable-line
import Select from '@folio/stripes-components/lib/Select'; // eslint-disable-line
import Layer from '@folio/stripes-components/lib/Layer'; // eslint-disable-line

import UserForm from './UserForm';
import ViewUser from './ViewUser';

class Users extends Component {
  static contextTypes = {
    router: PropTypes.object.isRequired,
    store: PropTypes.object,
  };

  static propTypes = {
    data: PropTypes.object.isRequired,
    pathname: PropTypes.string.isRequired,
    location: PropTypes.shape({
      pathname: PropTypes.string.isRequired,
      query: PropTypes.object, // object of key=value pairs
      search: PropTypes.string, // string combining all parts of query
    }).isRequired,
    mutator: PropTypes.object,
  };

  static manifest = Object.freeze({
    addUserMode: { },
    users: {
      type: 'okapi',
      records: 'users',
      path: (queryParams, _pathComponents, _resourceValues) => {
        // console.log('Users manifest "users" path function, queryParams = ', queryParams);
        const { query, filterActive, filterInactive, sort } = queryParams || {};

        let cql;
        if (query) {
          cql = `username="${query}*" or personal.first_name="${query}*" or personal.last_name="${query}*"`;
        }

        let filterCql;
        if (filterActive && !filterInactive) {
          filterCql = 'active=true';
        } else if (filterInactive && !filterActive) {
          filterCql = 'active=false';
        } else if (!filterActive && !filterInactive) {
          // Technically, we should force this configuration to find
          // no records; but it probably makes more sense to do
          // nothing, and allow both active AND inactive records.
        }

        if (filterCql) {
          if (cql) {
            cql = `(${cql}) and ${filterCql}`;
          } else {
            cql = filterCql;
          }
        }

        if (sort) {
          const sortMap = {
            Active: 'active',
            Name: 'personal.last_name personal.first_name',
            Username: 'username',
            Email: 'personal.email',
          };
          const sortIndex = sortMap[sort];
          if (sortIndex) {
            if (cql === undefined) cql = 'username=*';
            cql += ` sortby ${sortIndex}`;
          }
        }

        let path = 'users';
        if (cql) path += `?query=${encodeURIComponent(cql)}`;

        console.log(`query=${query} active=${filterActive} inactive=${filterInactive} sort=${sort} -> ${path}`);
        return path;
      },
      staticFallback: { path: 'users' },
    }
  });

  constructor(props, context) {
    super(props);

    const query = props.location.query || {};
    this.state = {
      filter: {
        active: query.filterActive || false,
        inactive: query.filterInactive || false,
      },
      selectedItem: {},
      searchTerm: query.query || '',
      sortOrder: query.sort || '',
    };
    props.mutator.addUserMode.replace({ mode: false });

    this.okapi = context.store.getState().okapi;

    this.onClickAddNewUser = this.onClickAddNewUser.bind(this);
    this.onClickCloseNewUser = this.onClickCloseNewUser.bind(this);
    this.onChangeFilter = this.onChangeFilter.bind(this);
    this.performSearch = _.debounce(this.performSearch.bind(this), 250);
    this.onChangeSearch = this.onChangeSearch.bind(this);
    this.onClearSearch = this.onClearSearch.bind(this);
    this.onSort = this.onSort.bind(this);
    this.onSelectRow = this.onSelectRow.bind(this);
  }

  // search Handlers...
  onChangeFilter(e) {
    const filter = this.state.filter;
    filter[e.target.id] = !filter[e.target.id];
    console.log('onChangeFilter setting state', filter);
    this.setState({ filter });
    this.updateSearch(this.state.searchTerm, this.state.sortOrder, filter);
  }

  onChangeSearch(e) {
    const term = e.target.value;
    this.setState({ searchTerm: term });
    this.performSearch(term);
  }

  performSearch(term) {
    console.log('User searched:', term, 'at', this.props.location.pathname);
    const transitionPath = term === "" ?  this.props.location.pathname : `${this.props.location.pathname}?query=${term}`;
    this.context.router.transitionTo(transitionPath);
  }

  onClearSearch() {
    console.log('User cleared search');
    this.setState({ searchTerm: '' });
    this.context.router.transitionTo(this.props.location.pathname);
  }

  onSort(e, meta) {
    const sortOrder = meta.name;
    console.log('User sorted by', sortOrder);
    this.setState({ sortOrder });
    this.updateSearch(this.state.searchTerm, sortOrder, this.state.filter);
  }

  onSelectRow(e, meta) {
    const userId = meta.id;
    console.log('User clicked', userId, 'location = ', this.props.location);
    this.setState({ selectedItem: meta });
    this.context.router.transitionTo(`/users/view/${userId}${this.props.location.search}`);
  }

  // end search Handlers

  // AddUser Handlers
  onClickAddNewUser(e) {
    if (e) e.preventDefault();
    this.props.mutator.addUserMode.replace({ mode: true })
  }

  onClickCloseNewUser(e) {
    if (e) e.preventDefault();
    this.props.mutator.addUserMode.replace({ mode: false })
  }
  // end AddUser Handlers

  // We need to explicitly pass changed values into this function,
  // as state-change only happens after event is handled.
  updateSearch(query, sortOrder, filter) {
    console.log(`updateSearch('${query}', '${sortOrder}',`, filter, ')');
    let transitionLoc = this.props.location.pathname;
    const params = {};
    if (query) params.query = query;
    if (sortOrder) params.sort = sortOrder;
    if (filter.active) params.filterActive = true;
    if (filter.inactive) params.filterInactive = true;
    const keys = Object.keys(params);
    if (keys.length) {
      // eslint-disable-next-line prefer-template
      transitionLoc += '?' + keys.map(key => `${key}=${encodeURIComponent(params[key])}`).join('&');
    }
    this.context.router.transitionTo(transitionLoc);
  }

  create(data) {
    // extract creds object from user object
    const creds = Object.assign({}, data.creds, { username: data.username });
    if (data.creds) delete data.creds;
    // POST user record
    this.props.mutator.users.POST(data);
    // POST credentials, permission-user, permissions;
    this.postCreds(data.username, { credentials: creds });
    this.onClickCloseNewUser();
  }

  postCreds(username, creds) {
    fetch(`${this.okapi.url}/authn/users`, {
      method: 'POST',
      headers: Object.assign({}, { 'X-Okapi-Tenant': this.okapi.tenant, 'X-Okapi-Token': this.okapi.token }),
      body: JSON.stringify(creds),
    }).then((response) => {
      if (response.status >= 400) {
        console.log("Users. POST of creds failed.");
      } else {
        this.postPerms(username, 'users.super');
      }
    });
  }

  postPerms (username, perms) {
    fetch(`${this.okapi.url}/perms/users`, {
      method: 'POST',
      headers: Object.assign({}, { 'X-Okapi-Tenant': this.okapi.tenant, 'X-Okapi-Token': this.okapi.token }),
      body: username,
    }).then((response) => {
      if (response.status >= 400) {
        console.log("Users. POST of username failed.");
      } else {
        this.postUsersPerms(username, perms);
      }
    });
  }

  postUsersPerms(username, perm) {
    fetch(`${this.okapi.url}/perms/users/${username}/permissions`, {
      method: 'POST',
      headers: Object.assign({}, { 'X-Okapi-Tenant': this.okapi.tenant, 'X-Okapi-Token': this.okapi.token }),
      body: JSON.stringify({ permission_name: perm }),
    }).then((response) => {
      if (response.status >= 400) {
        console.log("Users. POST of user's perms failed.");
      } else {
      }
    });

  }

  render() {
    const { data, pathname } = this.props;
    const users = data.users || [];

    /* searchHeader is a 'custom pane header'*/
    const searchHeader = <FilterPaneSearch id="SearchField" onChange={this.onChangeSearch} onClear={this.onClearSearch} value={this.state.searchTerm} />;
    const resultMenu = <PaneMenu><button><Icon icon="bookmark" /></button></PaneMenu>;
    const fineHistory = [{ 'Due Date': '11/12/2014', 'Amount': '34.23', 'Status': 'Unpaid' }]; // eslint-disable-line

    const resultsFormatter = {
      Active: user => user.active,
      Name: user => `${_.get(user, ['personal', 'last_name'], '')}, ${_.get(user, ['personal', 'first_name'], '')}`,
      Username: user => user.username,
      Email: user => _.get(user, ['personal', 'email']),
    };

    return (
      <Paneset>
        {/* Filter Pane */}
        <Pane defaultWidth="16%" header={searchHeader}>
          <FilterControlGroup label="Filters">
            <Checkbox
              id="active"
              label="Active"
              checked={this.state.filter.active}
              onChange={this.onChangeFilter}
              marginBottom0
              hover
              fullWidth
              checkedIcon={<Icon icon="eye" />}
            />
            <Checkbox
              id="inactive"
              label="Inactive"
              checked={this.state.filter.inactive}
              onChange={this.onChangeFilter}
              marginBottom0
              hover
              fullWidth
              checkedIcon={<Icon icon="eye" />}
            />
          </FilterControlGroup>
          <FilterControlGroup label="Actions">
            <Button fullWidth onClick={this.onClickAddNewUser}>New user</Button>
          </FilterControlGroup>
        </Pane>
        {/* Results Pane */}
        <Pane
          defaultWidth="40%"
          paneTitle={

              Results

                {users.length} Result{users.length === 1 ? '' : 's'} Found

          }
          lastMenu={resultMenu}
        >
          <MultiColumnList
            contentData={users}
            selectedRow={this.state.selectedItem}
            rowMetadata={['id']}
            formatter={resultsFormatter}
            onRowClick={this.onSelectRow}
            onHeaderClick={this.onSort}
            visibleColumns={['Active', 'Name', 'Username', 'Email']}
            fullWidth
            sortOrder={this.state.sortOrder}
            isEmptyMessage={`No results found for "${this.state.searchTerm}". Please check your spelling and filters.`}
          />
        </Pane>

        {/* Details Pane */}
        <Match pattern={`${pathname}/view/:userid`} render={props => <ViewUser placeholder={'placeholder'} {...props} />} />
        <Layer isOpen={data.addUserMode ? data.addUserMode.mode : false } label="Add New User Dialog">
          <UserForm
            onSubmit={(record) => { this.create(record); }}
            onCancel={this.onClickCloseNewUser}
          />
        </Layer>
      </Paneset>
    );
  }
}

export default Users;
<|endoftext|>