<commit_before>"use strict";

/**
 * Mouse instance for input in sync with the running 3D application.
 *
 * The mouse object provided by scripts is automatically updated by the runtime handler.
 *
 * @class Mouse
 * @module Input
 * @constructor
 */
function Mouse()
{
	//Raw data
	this._keys = new Array(3);
	this._position = new THREE.Vector2(0, 0);
	this._positionUpdated = false;
	this._delta = new THREE.Vector2(0, 0);
	this._wheel = 0;
	this._wheelUpdated = false;
	this._doubleClicked = false;

	/**
	 * Array with mouse buttons status.
	 *
	 * @type {array}
	 * @property keys
	 */
	this.keys = new Array(3);

	/**
	 * Mouse position inside of the window (coordinates in window space).
	 *
	 * @type {Vector2}
	 * @property position
	 */
	this.position = new THREE.Vector2(0,0);

	/**
	 * Mouse movement (coordinates in window space).
	 *
	 * @type {Vector2}
	 * @property delta
	 */
	this.delta = new THREE.Vector2(0,0);

	/**
	 * Mouse scroll wheel movement.
	 *
	 * @type {Number}
	 * @property wheel
	 */
	this.wheel = 0;

	/**
	 * Indicates if some button of the mouse was just double clicked.
	 *
	 * @type {Boolean}
	 * @property doubleClicked
	 */
	this.doubleClicked = false;

	/**
	 * Canvas attached to this mouse instance used to calculate position and delta in canvas space coordinates.
	 *
	 * @type {DOM}
	 * @property canvas
	 */
	this.canvas = null;

	//Events
	this.events = new EventManager();

	//Initialize key instances
	for(var i = 0; i < 3; i++)
	{
		this._keys[i] = new Key();
		this.keys[i] = new Key();
	}

	//Self pointer
	var self = this;

	//Scroll wheel
	if(window.onmousewheel !== undefined)
	{
		//Chrome, edge
		this.events.add(window, "mousewheel", function(event)
		{
			self._wheel = event.deltaY;
			self._wheelUpdated = true;
		});
	}
	else if(window.addEventListener !== undefined)
	{
		//Firefox
		this.events.add(window, "DOMMouseScroll", function(event)
		{
			self._wheel = event.detail * 30;
			self._wheelUpdated = true;
		});
	}
	else
	{
		this.events.add(window, "wheel", function(event)
		{
			self._wheel = event.deltaY;
			self._wheelUpdated = true;
		});
	}

	//Touchscreen input events
	if("ontouchstart" in window || navigator.msMaxTouchPoints > 0)
	{
		//Auxiliar variables to calculate touch delta
		var lastTouch = new Vector2(0, 0);

		//Touch start event
		this.events.add(window, "touchstart", function(event)
		{
			var touch = event.touches[0];

			self.updatePosition(touch.clientX, touch.clientY, 0, 0);
			self.updateKey(Mouse.LEFT, Key.DOWN);

			lastTouch.set(touch.clientX, touch.clientY);
		});

		//Touch end event
		this.events.add(window, "touchend", function(event)
		{
			self.updateKey(Mouse.LEFT, Key.UP);
		});

		//Touch cancel event
		this.events.add(window, "touchcancel", function(event)
		{
			self.updateKey(Mouse.LEFT, Key.UP);
		});

		//Touch move event
		this.events.add(document.body, "touchmove", function(event)
		{
			var touch = event.touches[0];

			self.updatePosition(touch.clientX, touch.clientY, touch.clientX - lastTouch.x, touch.clientY - lastTouch.y);

			lastTouch.set(touch.clientX, touch.clientY);
		});
	}

	//Move
	this.events.add(window, "mousemove", function(event)
	{
		self.updatePosition(event.clientX, event.clientY, event.movementX, event.movementY);
	});

	//Button pressed
	this.events.add(window, "mousedown", function(event)
	{
		self.updateKey(event.which - 1, Key.DOWN);
	});

	//Button released
	this.events.add(window, "mouseup", function(event)
	{
		self.updateKey(event.which - 1, Key.UP);
	});

	//Drag start
	this.events.add(window, "dragstart", function(event)
	{
		self.updateKey(event.which - 1, Key.UP);
	});

	//Mouse double click
	this.events.add(window, "dblclick", function(event)
	{
		self._doubleClicked = true;
	});

	this.events.create();
}

Mouse.prototype = Mouse;
Mouse.prototype.constructor = Mouse;

/**
 * LEFT mouse button
 * @attribute LEFT
 * @type {Number}
 */
Mouse.LEFT = 0;
/**
 * MIDDLE mouse button
 * @attribute MIDDLE
 * @type {Number}
 */
Mouse.MIDDLE = 1;
/**
 * RIGHT mouse button
 * @attribute RIGHT
 * @type {Number}
 */
Mouse.RIGHT = 2;

/**
 * Canvas to be used for coordinates calculation relative to that canvas.
 *
 * @method setCanvas
 * @param {DOM} canvas Canvas to be attached to the Mouse instance
 */
Mouse.setCanvas = function(canvas)
{
	this.canvas = canvas;

	canvas.mouseInside = false;

	canvas.addEventListener("mouseenter", function()
	{
		this.mouseInside = true;
	});

	canvas.addEventListener("mouseleave", function()
	{
		this.mouseInside = false;
	});
};

/**
 * Check if mouse is inside attached canvas (updated async).
 *
 * @method insideCanvas
 * @return {boolean} True if mouse is currently inside the canvas
 */
Mouse.insideCanvas = function()
{
	if(this.canvas === null)
	{
		return false;
	}

	return this.canvas.mouseInside;
};

/**
 * Set mouse lock state.
 *
 * @method setLock
 * @param {boolean} value If true pointer lock will be requested for the canvas attached to the Mouse instance
 */
Mouse.setLock = function(value)
{
	if(this.canvas !== null)
	{
		if(value)
		{
			if(this.canvas.requestPointerLock)
			{
				this.canvas.requestPointerLock();
			}
			else if(this.canvas.mozRequestPointerLock)
			{
				this.canvas.mozRequestPointerLock();
			}
			else if(this.canvas.webkitRequestPointerLock)
			{
				this.canvas.webkitRequestPointerLock();
			}
		}
		else
		{
			if(document.exitPointerLock)
			{
				document.exitPointerLock();
			}
			else if(document.mozExitPointerLock)
			{
				document.mozExitPointerLock();
			}
			else if(document.webkitExitPointerLock)
			{
				document.webkitExitPointerLock();
			}
		}
	}
};

/**
 * Check if mouse button is currently pressed.
 *
 * @method buttonPressed
 * @param {Number} button Button to check status of
 * @return {boolean} True if button is currently pressed
 */
Mouse.buttonPressed = function(button)
{
	return this.keys[button].pressed;
};

/**
 * Check if Mouse button was double clicked.
 *
 * @method buttonDoubleClicked
 * @return {boolean} True if some mouse button was just double clicked
 */
Mouse.buttonDoubleClicked = function()
{
	return this.doubleClicked;
};

/**
 * Check if a mouse button was just pressed.
 *
 * @method buttonJustPressed
 * @param {Number} button Button to check status of
 * @return {boolean} True if button was just pressed
 */
Mouse.buttonJustPressed = function(button)
{
	return this.keys[button].justPressed;
};

/**
 * Check if a mouse button was just released.
 *
 * @method buttonJustReleased
 * @param {Number} button Button to check status of
 * @return {boolean} True if button was just released
 */
Mouse.buttonJustReleased = function(button)
{
	return this.keys[button].justReleased;
};

/**
 * Update mouse position.
 *
 * Automatically called by the runtime.
 *
 * @method updatePosition
 * @param {Number} x
 * @param {Number} y
 * @param {Number} xDiff
 * @param {Number} yDiff
 */
Mouse.updatePosition = function(x, y, xDiff, yDiff)
{
	if(this.canvas !== null)
	{
		var rect = this.canvas.getBoundingClientRect();
		x -= rect.left;
		y -= rect.top;
	}

	this._position.set(x, y);
	this._delta.x += xDiff;
	this._delta.y += yDiff;
	this._positionUpdated = true;
};

/**
 * Update a mouse button.
 *
 * Automatically called by the runtime.
 *
 * @method updateKey
 * @param {Number} button
 * @param {Number} action
 */
Mouse.updateKey = function(button, action)
{
	if(button > -1)
	{
		this._keys[button].update(action);
	}
};

/**
 * Update mouse buttons state, position, wheel and delta synchronously.
 *
 * @method update
 */
Mouse.update = function()
{
	//Update mouse keys state
	for(var i = 0; i < this._keys.length; i++)
	{
		if(this._keys[i].justPressed && this.keys[i].justPressed)
		{
			this._keys[i].justPressed = false;
		}
		if(this._keys[i].justReleased && this.keys[i].justReleased)
		{
			this._keys[i].justReleased = false;
		}
		this.keys[i].set(this._keys[i].justPressed, this._keys[i].pressed, this._keys[i].justReleased);
	}

	//Update mouse wheel
	if(this._wheelUpdated)
	{
		this.wheel = this._wheel;
		this._wheelUpdated = false;
	}
	else
	{
		this.wheel = 0;
	}

	//Update mouse double click
	if(this._doubleClicked)
	{
		this.doubleClicked = true;
		this._doubleClicked = false;
	}
	else
	{
		this.doubleClicked = false;
	}

	//Update mouse Position if needed
	if(this._positionUpdated)
	{
		this.delta.copy(this._delta);
		this.position.copy(this._position);

		this._delta.set(0,0);
		this._positionUpdated = false;
	}
	else
	{
		this.delta.x = 0;
		this.delta.y = 0;
	}
};

/**
 * Dispose mouse events.
 *
 * @method dispose
 */
Mouse.dispose = function()
{
	this.events.destroy();
};
<commit_msg>Mouse clean up<commit_after>"use strict";

/**
 * Mouse instance for input in sync with the running 3D application.
 *
 * The mouse object provided by scripts is automatically updated by the runtime handler.
 *
 * @class Mouse
 * @module Input
 * @constructor
 */
function Mouse(domElement)
{
	//Raw data
	this._keys = new Array(3);
	this._position = new THREE.Vector2(0, 0);
	this._positionUpdated = false;
	this._delta = new THREE.Vector2(0, 0);
	this._wheel = 0;
	this._wheelUpdated = false;
	this._doubleClicked = false;

	/**
	 * Array with mouse buttons status.
	 *
	 * @type {array}
	 * @property keys
	 */
	this.keys = new Array(3);

	/**
	 * Mouse position inside of the window (coordinates in window space).
	 *
	 * @type {Vector2}
	 * @property position
	 */
	this.position = new THREE.Vector2(0,0);

	/**
	 * Mouse movement (coordinates in window space).
	 *
	 * @type {Vector2}
	 * @property delta
	 */
	this.delta = new THREE.Vector2(0,0);

	/**
	 * Mouse scroll wheel movement.
	 *
	 * @type {Number}
	 * @property wheel
	 */
	this.wheel = 0;

	/**
	 * Indicates if some button of the mouse was just double clicked.
	 *
	 * @type {Boolean}
	 * @property doubleClicked
	 */
	this.doubleClicked = false;

	/**
	 * DOM element where to attach the mouse events.
	 *
	 * @property domElement
	 * @type {DOM}
	 */
	this.domElement = (domElement !== undefined) ? domElement : window;

	/**
	 * Canvas attached to this mouse instance used to calculate position and delta in canvas space coordinates.
	 *
	 * @type {DOM}
	 * @property canvas
	 */
	this.canvas = null;

	//Events
	this.events = new EventManager();

	//Initialize key instances
	for(var i = 0; i < 3; i++)
	{
		this._keys[i] = new Key();
		this.keys[i] = new Key();
	}

	//Self pointer
	var self = this;

	//Scroll wheel
	if(window.onmousewheel !== undefined)
	{
		//Chrome, edge
		this.events.add(this.domElement, "mousewheel", function(event)
		{
			self._wheel = event.deltaY;
			self._wheelUpdated = true;
			event.preventDefault();
		});
	}
	else if(window.addEventListener !== undefined)
	{
		//Firefox
		this.events.add(this.domElement, "DOMMouseScroll", function(event)
		{
			self._wheel = event.detail * 30;
			self._wheelUpdated = true;
			event.preventDefault();
		});
	}
	else
	{
		this.events.add(this.domElement, "wheel", function(event)
		{
			self._wheel = event.deltaY;
			self._wheelUpdated = true;
			event.preventDefault();
		});
	}

	//Touchscreen input events
	if("ontouchstart" in window || navigator.msMaxTouchPoints > 0)
	{
		//Auxiliar variables to calculate touch delta
		var lastTouch = new Vector2(0, 0);

		//Touch start event
		this.events.add(this.domElement, "touchstart", function(event)
		{
			var touch = event.touches[0];

			self.updatePosition(touch.clientX, touch.clientY, 0, 0);
			self.updateKey(Mouse.LEFT, Key.DOWN);

			lastTouch.set(touch.clientX, touch.clientY);
		});

		//Touch end event
		this.events.add(this.domElement, "touchend", function(event)
		{
			self.updateKey(Mouse.LEFT, Key.UP);
		});

		//Touch cancel event
		this.events.add(this.domElement, "touchcancel", function(event)
		{
			self.updateKey(Mouse.LEFT, Key.UP);
		});

		//Touch move event
		this.events.add(document.body, "touchmove", function(event)
		{
			var touch = event.touches[0];

			self.updatePosition(touch.clientX, touch.clientY, touch.clientX - lastTouch.x, touch.clientY - lastTouch.y);

			lastTouch.set(touch.clientX, touch.clientY);
		});
	}

	//Move
	this.events.add(this.domElement, "mousemove", function(event)
	{
		self.updatePosition(event.clientX, event.clientY, event.movementX, event.movementY);
	});

	//Button pressed
	this.events.add(this.domElement, "mousedown", function(event)
	{
		self.updateKey(event.which - 1, Key.DOWN);
	});

	//Button released
	this.events.add(this.domElement, "mouseup", function(event)
	{
		self.updateKey(event.which - 1, Key.UP);
	});

	//Drag start
	this.events.add(this.domElement, "dragstart", function(event)
	{
		self.updateKey(event.which - 1, Key.UP);
	});

	//Mouse double click
	this.events.add(this.domElement, "dblclick", function(event)
	{
		self._doubleClicked = true;
	});

	this.events.create();
}

Mouse.prototype = Mouse;
Mouse.prototype.constructor = Mouse;

/**
 * LEFT mouse button
 * @attribute LEFT
 * @type {Number}
 */
Mouse.LEFT = 0;
/**
 * MIDDLE mouse button
 * @attribute MIDDLE
 * @type {Number}
 */
Mouse.MIDDLE = 1;
/**
 * RIGHT mouse button
 * @attribute RIGHT
 * @type {Number}
 */
Mouse.RIGHT = 2;

/**
 * Canvas to be used for coordinates calculation relative to that canvas.
 *
 * @method setCanvas
 * @param {DOM} canvas Canvas to be attached to the Mouse instance
 */
Mouse.setCanvas = function(canvas)
{
	this.canvas = canvas;

	canvas.mouseInside = false;

	canvas.addEventListener("mouseenter", function()
	{
		this.mouseInside = true;
	});

	canvas.addEventListener("mouseleave", function()
	{
		this.mouseInside = false;
	});
};

/**
 * Check if mouse is inside attached canvas (updated async).
 *
 * @method insideCanvas
 * @return {boolean} True if mouse is currently inside the canvas
 */
Mouse.insideCanvas = function()
{
	if(this.canvas === null)
	{
		return false;
	}

	return this.canvas.mouseInside;
};

/**
 * Set mouse lock state.
 *
 * @method setLock
 * @param {boolean} value If true pointer lock will be requested for the canvas attached to the Mouse instance
 */
Mouse.setLock = function(value)
{
	if(this.canvas !== null)
	{
		if(value)
		{
			if(this.canvas.requestPointerLock)
			{
				this.canvas.requestPointerLock();
			}
			else if(this.canvas.mozRequestPointerLock)
			{
				this.canvas.mozRequestPointerLock();
			}
			else if(this.canvas.webkitRequestPointerLock)
			{
				this.canvas.webkitRequestPointerLock();
			}
		}
		else
		{
			if(document.exitPointerLock)
			{
				document.exitPointerLock();
			}
			else if(document.mozExitPointerLock)
			{
				document.mozExitPointerLock();
			}
			else if(document.webkitExitPointerLock)
			{
				document.webkitExitPointerLock();
			}
		}
	}
};

/**
 * Check if mouse button is currently pressed.
 *
 * @method buttonPressed
 * @param {Number} button Button to check status of
 * @return {boolean} True if button is currently pressed
 */
Mouse.buttonPressed = function(button)
{
	return this.keys[button].pressed;
};

/**
 * Check if Mouse button was double clicked.
 *
 * @method buttonDoubleClicked
 * @return {boolean} True if some mouse button was just double clicked
 */
Mouse.buttonDoubleClicked = function()
{
	return this.doubleClicked;
};

/**
 * Check if a mouse button was just pressed.
 *
 * @method buttonJustPressed
 * @param {Number} button Button to check status of
 * @return {boolean} True if button was just pressed
 */
Mouse.buttonJustPressed = function(button)
{
	return this.keys[button].justPressed;
};

/**
 * Check if a mouse button was just released.
 *
 * @method buttonJustReleased
 * @param {Number} button Button to check status of
 * @return {boolean} True if button was just released
 */
Mouse.buttonJustReleased = function(button)
{
	return this.keys[button].justReleased;
};

/**
 * Update mouse position.
 *
 * Automatically called by the runtime.
 *
 * @method updatePosition
 * @param {Number} x
 * @param {Number} y
 * @param {Number} xDiff
 * @param {Number} yDiff
 */
Mouse.updatePosition = function(x, y, xDiff, yDiff)
{
	if(this.canvas !== null)
	{
		var rect = this.canvas.getBoundingClientRect();
		x -= rect.left;
		y -= rect.top;
	}

	this._position.set(x, y);
	this._delta.x += xDiff;
	this._delta.y += yDiff;
	this._positionUpdated = true;
};

/**
 * Update a mouse button.
 *
 * Automatically called by the runtime.
 *
 * @method updateKey
 * @param {Number} button
 * @param {Number} action
 */
Mouse.updateKey = function(button, action)
{
	if(button > -1)
	{
		this._keys[button].update(action);
	}
};

/**
 * Update mouse buttons state, position, wheel and delta synchronously.
 *
 * @method update
 */
Mouse.update = function()
{
	//Update mouse keys state
	for(var i = 0; i < this._keys.length; i++)
	{
		if(this._keys[i].justPressed && this.keys[i].justPressed)
		{
			this._keys[i].justPressed = false;
		}
		if(this._keys[i].justReleased && this.keys[i].justReleased)
		{
			this._keys[i].justReleased = false;
		}
		this.keys[i].set(this._keys[i].justPressed, this._keys[i].pressed, this._keys[i].justReleased);
	}

	//Update mouse wheel
	if(this._wheelUpdated)
	{
		this.wheel = this._wheel;
		this._wheelUpdated = false;
	}
	else
	{
		this.wheel = 0;
	}

	//Update mouse double click
	if(this._doubleClicked)
	{
		this.doubleClicked = true;
		this._doubleClicked = false;
	}
	else
	{
		this.doubleClicked = false;
	}

	//Update mouse Position if needed
	if(this._positionUpdated)
	{
		this.delta.copy(this._delta);
		this.position.copy(this._position);

		this._delta.set(0,0);
		this._positionUpdated = false;
	}
	else
	{
		this.delta.x = 0;
		this.delta.y = 0;
	}
};

/**
 * Dispose mouse events.
 *
 * @method dispose
 */
Mouse.dispose = function()
{
	this.events.destroy();
};
<|endoftext|>


<commit_before>
'use strict';

(function() {

  // Pseudo-constants:
  var VERSION             = '0.2.0';
  var BASE_URL            = 'https://api-test.w3.org/';
  var APIARY_PLACEHOLDER  = /[\^\ ]apiary-([^\ ]+)/g;
  var TYPE_DOMAIN_PAGE    = 1;
  var TYPE_GROUP_PAGE     = 2;
  var TYPE_USER_PAGE      = 3;
  var TYPE_GROUPS         = 4;
  var TYPE_CHAIRS         = 5;
  var TYPE_SPECIFICATIONS = 6;

  // “Global” variables:
  var apiKey;
  var type;
  var id;
  var placeholders = {};
  var data         = {};

  /**
   * Main function.
   *
   * I know everything you need to know, baby.
   */

  $(document).ready(function() {

    inferTypeAndId();

    if (apiKey && type && id) {
      findPlaceholders();
      getDataForType(type, id, injectValues);
    } else {
      window.alert('Apiary ' + VERSION + '\n' +
        'ERROR: could not get all necessary metadata.\n' +
        'apiKey: “' + apiKey + '”\n' +
        'type: “' + type + '”\n' +
        'id: “' + id + '”');
    }

  });

  /**
   * Infer the type of page (domain, group…) and the ID of the corresponding entity; resolve API key.
   *
   * After this function is done, variables “apiKey”, “type” and “id” should have their right values set.
   */

  var inferTypeAndId = function() {

    if (1 === $('html[data-api-key]').length) {
      apiKey = $('html[data-api-key]').data('api-key');
    }

    if ($('[data-domain-id]').length > 0) {
      type = TYPE_DOMAIN_PAGE;
      id = $('[data-domain-id]').data('domain-id');
    } else if ($('[data-group-id]').length > 0) {
      type = TYPE_GROUP_PAGE;
      id = $('[data-group-id]').data('group-id');
    } else if ($('[data-user-id]').length > 0) {
      type = TYPE_USER_PAGE;
      id = $('[data-user-id]').data('user-id');
    }

  };

  /**
   * Traverse the DOM in search of all elements with class “apiary-*”.
   *
   * After this function is done, “placeholders” should be an object containing all keys found in the DOM;
   * and for every key, an array of all elements mentioning that key.
   * For example:
   * {
   *   name: [
   *     <title> element,
   *
 element
   *   ],
   *   lead: [
 element],
   *   groups: [
 element]
   * }
   */

  var findPlaceholders = function() {
    var candidates = $('[class^="apiary"]');
    var cand, match;
    for (var c = 0; c < candidates.length; c ++) {
      cand = $(candidates[c]);
      match = APIARY_PLACEHOLDER.exec(cand.attr('class'));
      while (match) {
        if (!placeholders[match[1]]) {
          placeholders[match[1]] = [];
        }
        placeholders[match[1]].push(cand);
        match = APIARY_PLACEHOLDER.exec(cand.attr('class'));
      }
    }
  };

  /**
   * Get basic data for a particular entity from the W3C API, given a type of item and its value.
   *
   * @param {TYPE}     item     type of entity, eg TYPE_DOMAIN_PAGE
   * @param {Object}   value    ID of the entity, eg “1234”
   * @param {Function} callback eg injectValues
   */

  var getDataForType = function(item, value, callback) {
    if (Object.keys(placeholders).length > 0) {
      if (TYPE_DOMAIN_PAGE === item) {
        get(BASE_URL + 'domains/' + value, function(json) {
          data.name = json.name;
          data.lead = json._links.lead.title;
          if (placeholders.groups) {
            digDownData(TYPE_GROUPS, json._links.groups.href, callback);
          } else if (callback) {
            callback.call();
          }
        });
      } else if (TYPE_GROUP_PAGE === item) {
        get(BASE_URL + 'groups/' + value, function(json) {
          data.name = json.name;
          data.type = json.type;
          data.description = json.description;
          if (placeholders.chairs) {
            digDownData(TYPE_CHAIRS, json._links.chairs.href, callback);
          } else if (callback) {
            callback.call();
          }
        });
      } else if (TYPE_USER_PAGE === item) {
        get(BASE_URL + 'users/' + value, function(json) {
          data.name = json.name;
          data.family = json.family;
          data.given = json.given;
          data.photo = '';
          if (placeholders.specifications) {
            digDownData(TYPE_SPECIFICATIONS, json._links.specifications.href, callback);
          } else if (callback) {
            callback.call();
          }
        });
      } else {
        if (callback) {
          callback.call();
        }
      }
    } else {
      if (callback) {
        callback.call();
      }
    }
  };

  /**
   * Get data recursively, given a URL and the type of data.
   *
   * @param {TYPE}     item     eg TYPE_GROUPS
   * @param {String}   url      eg “https://api-test.w3.org/domains/109/groups”
   * @param {Function} callback eg injectValues
   */

  var digDownData = function(item, url, callback) {
    var list, i;
    get(url, function(json) {
      if (TYPE_GROUPS === item) {
        list = '
';
        for (i = 0; i < json._links.groups.length; i ++) {
          list += '
' + json._links.groups[i].title + '
';
        }
        list += '
';
        data.groups = list;
      } else if (TYPE_CHAIRS === item) {
        list = '
';
        for (i = 0; i < json._links.chairs.length; i ++) {
          list += '
' + json._links.chairs[i].title + '
';
        }
        list += '
';
        data.chairs = list;
      } else if (TYPE_SPECIFICATIONS === item) {
        list = '
';
        for (i = 0; i < json._links.specifications.length; i ++) {
          list += '
' + json._links.specifications[i].title + '
';
        }
        list += '
';
        data.specifications = list;
      }
      if (callback) {
        callback.call();
      }
    });
  };

  /**
   * Inject values retrieved from the API into the relevant elements of the DOM.
   */

  var injectValues = function() {
    for (var i in placeholders) {
      if (placeholders.hasOwnProperty(i)) {
        for (var j in placeholders[i]) {
          placeholders[i][j].html(data[i]);
        }
      }
    }
  };

  /**
   * GET data from the API, using the API key.
   *
   * @param {String}   url      target URL, including base URL and parameters, but not an API key.
   * @param {Function} callback function(json){}
   */

  var get = function(url, callback) {

    var newUrl = url;

    if (-1 === newUrl.indexOf('?')) {
      newUrl += '?apikey=' + apiKey;
    } else if (-1 === newUrl.toLowerCase().indexOf('apikey=')) {
      newUrl += '&apikey=' + apiKey;
    }

    $.get(newUrl, callback);

  };

  /**
   * Find the largest photo available from an array of them.
   *
   * @param {Array} photos eg, [{name: 'large', href: 'size-L.jpg'}, {name: 'medium', href: 'size-M.jpg'}]
   */

  var getLargestPhotoUrl = function(photos) {
    var VALUE = {large: 2, thumbnail: 1, tiny: 0};
    var result;
    for (var i = 0; i < photos.length; i ++) {
      if (!result || VALUE[photos[i].name] > VALUE[result.name]) {
        result = photos[i];
      }
    }
    return result.href;
  };

})();

<commit_msg>Crawl the API according to HATEOAS (fix #15; fix #18)<commit_after>
'use strict';

(function() {

  // Pseudo-constants:
  var VERSION            = '0.3.0';
  var BASE_URL           = 'https://api-test.w3.org/';
  var APIARY_PLACEHOLDER = /[\^\ ]apiary-([^\ ]+)/g;
  var APIARY_SELECTOR    = '[class^="apiary"]';
  var TYPE_DOMAIN_PAGE   = 1;
  var TYPE_GROUP_PAGE    = 2;
  var TYPE_USER_PAGE     = 3;
  var PHOTO_VALUE        = {
    large:     2,
    thumbnail: 1,
    tiny:      0
  };

  // “Global” variables:
  var apiKey;
  var type;
  var id;
  var placeholders = {};
  var cache        = {};

  /**
   * Main function.
   *
   * @TODO: document.
   */

  var process = function() {
    inferTypeAndId();
    if (apiKey && type && id) {
      findPlaceholders();
      getDataForType();
    } else {
      window.alert('Apiary ' + VERSION + '\n' +
        'ERROR: could not get all necessary metadata.\n' +
        'apiKey: “' + apiKey + '”\n' +
        'type: “' + type + '”\n' +
        'id: “' + id + '”');
    }
  };

  /**
   * Infer the type of page (domain, group…) and the ID of the corresponding entity; resolve API key.
   *
   * After this function is done, variables “apiKey”, “type” and “id” should have their right values set.
   */

  var inferTypeAndId = function() {
    if (1 === $('html[data-api-key]').length) {
      apiKey = $('html[data-api-key]').data('api-key');
    }
    if ($('[data-domain-id]').length > 0) {
      type = TYPE_DOMAIN_PAGE;
      id = $('[data-domain-id]').data('domain-id');
    } else if ($('[data-group-id]').length > 0) {
      type = TYPE_GROUP_PAGE;
      id = $('[data-group-id]').data('group-id');
    } else if ($('[data-user-id]').length > 0) {
      type = TYPE_USER_PAGE;
      id = $('[data-user-id]').data('user-id');
    }
  };

  /**
   * Traverse the DOM in search of all elements with class “apiary-*”.
   *
   * After this function is done, “placeholders” should be an object containing all keys found in the DOM;
   * and for every key, an array of all elements mentioning that key.
   * For example:
   * {
   *   name: [
   *     <title> element,
   *
 element
   *   ],
   *   lead: [
 element],
   *   groups: [
 element]
   * }
   */

  var findPlaceholders = function() {
    var candidates = $(APIARY_SELECTOR);
    var cand, match;
    for (var c = 0; c < candidates.length; c ++) {
      cand = $(candidates[c]);
      match = APIARY_PLACEHOLDER.exec(cand.attr('class'));
      while (match) {
        if (!placeholders[match[1]]) {
          placeholders[match[1]] = [];
        }
        placeholders[match[1]].push(cand);
        match = APIARY_PLACEHOLDER.exec(cand.attr('class'));
      }
    }
  };

  /**
   * Get basic data for a particular entity from the W3C API, given a type of item and its value.
   *
   * @TODO: document.
   */

  var getDataForType = function() {
    if (Object.keys(placeholders).length > 0) {
      if (TYPE_DOMAIN_PAGE === type) {
        get(BASE_URL + 'domains/' + id, crawl);
      } else if (TYPE_GROUP_PAGE === type) {
        get(BASE_URL + 'groups/' + id, crawl);
      } else if (TYPE_USER_PAGE === type) {
        get(BASE_URL + 'users/' + id, crawl);
      }
    }
  };

  /**
   * @TODO: document.
   */

  var crawl = function(json) {
    var i, keys, key, prefix, rest;
    keys = Object.keys(placeholders);
    for (key in keys) {
      i = keys[key];
      if (json.hasOwnProperty(i)) {
        if (1 === Object.keys(json[i]).length && json[i].hasOwnProperty('href')) {
          get(json[i].href, crawl);
        } else {
          injectValues(i, json[i]);
        }
      } else if (i.indexOf('-') > -1) {
        prefix = i.substr(0, i.indexOf('-'));
        rest = i.substr(i.indexOf('-') + 1);
        Object.defineProperty(placeholders, rest, Object.getOwnPropertyDescriptor(placeholders, i));
        delete placeholders[i];
        crawl(json[prefix]);
      }
    }
  };

  /**
   * Inject values retrieved from the API into the relevant elements of the DOM.
   *
   * @TODO: document.
   */

  var injectValues = function(key, value) {
    var chunk;
    if ('string' === typeof value || 'number' === typeof value) {
      chunk = String(value);
    } else if (value instanceof Array) {
      chunk = getLargestPhoto(value);
      if (!chunk) {
        chunk = '
';
        for (var i = 0; i < value.length; i ++) {
          if (value[i].hasOwnProperty('name')) {
            chunk += '
' + value[i].name + '
';
          } else if (value[i].hasOwnProperty('title')) {
            chunk += '
' + value[i].title + '
';
          }
        }
        chunk += '
';
      }
    } else if ('object' === typeof value) {
      if (value.hasOwnProperty('href')) {
        if (value.hasOwnProperty('name')) {
          chunk = '' + value.name + '';
        }
      }
    }
    for (var i in placeholders[key]) {
      placeholders[key][i].html(chunk);
      placeholders[key][i].addClass('apiary-done');
    }
    delete placeholders[key];
  };

  /**
   * GET data from the API, using the API key, and return the flattened version.
   *
   * @param {String}   url      target URL, including base URL and parameters, but not an API key.
   * @param {Function} callback function(json){}
   */

  var get = function(url, callback) {
    var newUrl = url;
    if (-1 === newUrl.indexOf('?')) {
      newUrl += '?apikey=' + apiKey + '&embed=true';
    } else {
      newUrl += '&apikey=' + apiKey + '&embed=true';
    }
    if (cache.hasOwnProperty(newUrl)) {
      callback(cache[newUrl]);
    } else {
      $.get(newUrl, function(result) {
        var i, j;
        for (i in {'_links': true, '_embedded': true}) {
          if (result.hasOwnProperty(i)) {
            for (j in result[i]) {
              if (result[i].hasOwnProperty(j)) {
                result[j] = result[i][j];
              }
            }
            delete result[i];
          }
        }
        cache[newUrl] = result;
        callback(result);
      });
    }
  };

  /**
   * Find the largest photo available from an array of them, and return an IMG element.
   *
   * @TODO: document.
   */

  var getLargestPhoto = function(data) {
    var largest, result;
    if (data && data.length > 0) {
      for (var i = 0; i < data.length; i ++) {
        if (data[i].href && data[i].name && (!largest || PHOTO_VALUE[data[i].name] > PHOTO_VALUE[largest.name])) {
          largest = data[i];
        }
      }
      if (largest) {
        result = '';
      }
    }
    return result;
  };

  // Process stuff!
  $(document).ready(process);

})();

<|endoftext|>


<commit_before>// blue leaf object
// TODO use maps and sets
var blueleaf = {
    customrules: {
        properties: {}, // TODO use map
        enabledSelectors: new Map(),
        addProperty: function (mq, sel, rule, options) {
            if (this.properties[mq] == undefined)
                this.properties[mq] = {
                    selectors: {},
                    active: false
                };

            if (this.properties[mq].selectors[sel] == undefined)
                this.properties[mq].selectors[sel] = new Array();

            this.properties[mq].selectors[sel].push({
                rule: rule,
                options: options
            });
        },
        addProperties: function (tree) {
            for (var mq in tree) {
                for (var sel in tree[mq]) {
                    for (var i = 0; i < tree[mq][sel].length; i++) {
                        for (var cl in tree[mq][sel][i])
                            this.addProperty(mq, sel, cl, tree[mq][sel][i][cl]);
                    }
                }
            }
        },
        enableSelector: function (elm, mq, sel) {
            var enProps = this.enabledSelectors.get(elm);
            if (enProps == undefined) { // TODO use set
                enProps = {};
                this.enabledSelectors.set(elm, enProps);
            }
            if (enProps[mq + "~" + sel] == true)
                return;
            enProps[mq + "~" + sel] = true;

            var rules = this.properties[mq].selectors[sel];

            for (var i = 0; i < rules.length; i++) {
                blue.Plugins.use(elm, rules[i].rule, rules[i].options, true);
            }
        },
        disableSelector: function (elm, mq, sel) {
            var enProps = this.enabledSelectors.get(elm);

            if (enProps == undefined)
                return;
            if (enProps[mq + "~" + sel] == undefined)
                return;
            delete enProps[mq + "~" + sel];

            var rules = this.properties[mq].selectors[sel];

            for (var i = 0; i < rules.length; i++) {
                blue.Plugins.use(elm, rules[i].rule, rules[i].options, false);
            }

        },
        apply: function () { // re-applys custom rules (if you need this, it's a bug)
            for (var mq in this.properties) {
                var properties = this.properties[mq];
                var mql = window.matchMedia(mq);

                if (mql.matches) {
                    properties.active = true;

                    for (var sel in properties.selectors) {
                        var lst = document.querySelectorAll(sel);
                        for (var n = 0; n < lst.length; n++) {
                            this.enableSelector(lst[n], mq, sel);
                        }
                    }
                }
                else {
                    properties.active = false;

                    for (var sel in properties.selectors) {
                        var lst = document.querySelectorAll(sel);
                        for (var n = 0; n < lst.length; n++) {
                            this.disableSelector(lst[n], mq, sel);
                        }
                    }
                }
            }
        },
        init: function () {
            for (var mq in this.properties) {
                (function (mq1, properties, that) {
                    var mql = window.matchMedia(mq1);

                    if (mql.matches) { // apply instantly
                        properties.active = true;

                        for (var sel in properties.selectors) {
                            var lst = document.querySelectorAll(sel);
                            for (var n = 0; n < lst.length; n++) {
                                that.enableSelector(lst[n], mq1, sel);
                            }
                        }
                    }

                    mql.addListener(function (mql) { // add listener to mediaquery
                        if (mql.matches) {
                            properties.active = true;

                            for (var sel in properties.selectors) {
                                var lst = document.querySelectorAll(sel);
                                for (var n = 0; n < lst.length; n++) {
                                    that.enableSelector(lst[n], mq1, sel);
                                }
                            }
                        }
                        else {
                            properties.active = false;

                            for (var sel in properties.selectors) {
                                var lst = document.querySelectorAll(sel);
                                for (var n = 0; n < lst.length; n++) {
                                    that.disableSelector(lst[n], mq1, sel);
                                }
                            }
                        }
                    });
                })(mq, this.properties[mq], this);
            }

            var that = this;

            var changes = [];
            function pushChange(elm, type) { // 0:addAll,1:removeAll,2:update
                var length = changes.length;
                for (var i = 0; i < length; i++) {
                    if (changes[i].elm == elm) {
                        if (changes[i].type != type && changes[i].type == 2) {
                            changes[i].type = type;
                            return;
                        }
                    }
                    else if (isDescendant(changes[i].elm, elm)) {
                        if (changes[i].type != type && changes[i].type == 2) {
                            changes.push({elm: elm, type: type, exclude: new Set()});
                            changes[i].exclude.add(elm);
                        }
                        return;
                    }
                    else if (isDescendant(elm, changes[i].elm)) {
                        if (changes[i].type != type && type == 2) {
                            changes.push(changes[i]);
                            changes[i] = {elm: elm, type: type, exclude: new Set()};
                            changes[i].exclude.add(changes[i].elm);
                        }
                        else {
                            changes[i] = {elm: elm, type: type, exclude: new Set()};
                        }
                        return;
                    }
                }
                changes.push({elm: elm, type: type, exclude: new Set()});
            }
            function processChanges() {
                for (var i = 0; i < changes.length; i++) {
                    var c = changes[i];

                    if (c.elm.querySelectorAll == undefined)
                        continue;

                    if (c.type == 0) { // addAll
                        for (var mq in that.properties) {
                            if (that.properties[mq].active == true) {
                                for (var sel in that.properties[mq].selectors) {
                                    var lst = c.elm.querySelectorAll(sel);
                                    for (var n = 0; n < lst.length; n++) {
                                        if (!c.exclude.has(lst[n])) {
                                            that.enableSelector(lst[n], mq, sel);
                                        }
                                    }

                                    if (c.elm.matches(sel)) {
                                        that.enableSelector(c.elm, mq, sel);
                                    }
                                }
                            }
                        }
                    }
                    else if (changes[i].type == 1) { // removeAll
                        traverseChildElements(c.elm, function (elm) {
                            var enProps = that.enabledSelectors.get(elm);
                            if (enProps != undefined) {
                                for (var key in enProps) {
                                    var prop = key.split("~");
                                    that.disableSelector(elm, prop[0], prop[1]);
                                }
                            }
                            return true;
                        });
                    }
                    else { // update
                        // remove invalid rules
                        traverseChildElements(c.elm, function (elm) {
                            var enProps = that.enabledSelectors.get(elm);
                            if (enProps != undefined) {
                                for (var key in enProps) {
                                    var prop = key.split("~");
                                    if (!elm.matches(prop[1])) {
                                        that.disableSelector(elm, prop[0], prop[1]);
                                    }
                                }
                            }
                        });

                        // add new rules
                        for (var mq in that.properties) {
                            if (that.properties[mq].active == true) {
                                for (var sel in that.properties[mq].selectors) {
                                    var lst = c.elm.querySelectorAll(sel);
                                    for (var n = 0; n < lst.length; n++) {
                                        that.enableSelector(lst[n], mq, sel);
                                    }

                                    if (c.elm.matches(sel)) {
                                        that.enableSelector(c.elm, mq, sel);
                                    }
                                }
                            }
                        }
                    }
                }

                changes = [];
            }
            var _timeout;

            var observer = new MutationObserver(function (mutations) {
                for (var i = 0; i < mutations.length; i++) {
                    if (mutations[i].type == "attributes") {
                        pushChange(mutations[i].target, 2);
                    }
                    else if (mutations[i].type == "childList") {
                        for (var j = 0; j < mutations[i].addedNodes.length; j++) {
                            pushChange(mutations[i].addedNodes.item(j), 0);
                        }
                        for (var j = 0; j < mutations[i].removedNodes.length; j++) {
                            pushChange(mutations[i].removedNodes.item(j), 1);
                        }
                    }
                }

                if (!!_timeout) {
                    clearTimeout(_timeout);
                }
                _timeout = setTimeout(function () {
                    processChanges();
                }, 50);
            });
            observer.observe(document, {attributes: true, childList: true, subtree: true});

            // helper functions
            function traverseChildElements(elm, fn) {
                fn(elm);
                var children = elm.children;
                if (children == undefined)
                    return;
                for (var i = 0; i < children.length; i++) {
                    if (traverseChildElements(children[i], fn) == false)
                        return;
                }
            }
            function isDescendant(parent, child) {
                var node = child.parentNode;
                while (node != null) {
                    if (node == parent) {
                        return true;
                    }
                    node = node.parentNode;
                }
                return false;
            }
        }
    }

};<commit_msg>core improvement<commit_after>// blue leaf code
var blueleaf = {
    customrules: {
        properties: {},
        enabledSelectors: new Map(),
        addProperty: function (mq, sel, rule, options) {
            if (this.properties[mq] == undefined)
                this.properties[mq] = {
                    selectors: {},
                    active: false
                };

            if (this.properties[mq].selectors[sel] == undefined)
                this.properties[mq].selectors[sel] = new Array();

            this.properties[mq].selectors[sel].push({
                rule: rule,
                options: options
            });
        },
        addProperties: function (tree) {
            for (var mq in tree) {
                for (var sel in tree[mq]) {
                    for (var i = 0; i < tree[mq][sel].length; i++) {
                        for (var cl in tree[mq][sel][i])
                            this.addProperty(mq, sel, cl, tree[mq][sel][i][cl]);
                    }
                }
            }
        },
        enableSelector: function (elm, mq, sel) {
            var enProps = this.enabledSelectors.get(elm);
            if (enProps == undefined) {
                enProps = new Set();
                this.enabledSelectors.set(elm, enProps);
            }
            if (enProps.has(mq + "~" + sel))
                return;
            enProps.add(mq + "~" + sel);

            var rules = this.properties[mq].selectors[sel];

            for (var i = 0; i < rules.length; i++) {
                blue.Plugins.use(elm, rules[i].rule, rules[i].options, true);
            }
        },
        disableSelector: function (elm, mq, sel) {
            var enProps = this.enabledSelectors.get(elm);

            if (enProps == undefined)
                return;
            if (!enProps.has(mq + "~" + sel))
                return;
            delete enProps.delete(mq + "~" + sel);

            var rules = this.properties[mq].selectors[sel];

            for (var i = 0; i < rules.length; i++) {
                blue.Plugins.use(elm, rules[i].rule, rules[i].options, false);
            }

        },
        apply: function () { // re-applys custom rules (if you need this, it's a bug)
            for (var mq in this.properties) {
                var properties = this.properties[mq];
                var mql = window.matchMedia(mq);

                if (mql.matches) {
                    properties.active = true;

                    for (var sel in properties.selectors) {
                        var lst = document.querySelectorAll(sel);
                        for (var n = 0; n < lst.length; n++) {
                            this.enableSelector(lst[n], mq, sel);
                        }
                    }
                }
                else {
                    properties.active = false;

                    for (var sel in properties.selectors) {
                        var lst = document.querySelectorAll(sel);
                        for (var n = 0; n < lst.length; n++) {
                            this.disableSelector(lst[n], mq, sel);
                        }
                    }
                }
            }
        },
        init: function () {
            for (var mq in this.properties) {
                (function (mq1, properties, that) {
                    var mql = window.matchMedia(mq1);

                    if (mql.matches) { // apply instantly
                        properties.active = true;

                        for (var sel in properties.selectors) {
                            var lst = document.querySelectorAll(sel);
                            for (var n = 0; n < lst.length; n++) {
                                that.enableSelector(lst[n], mq1, sel);
                            }
                        }
                    }

                    mql.addListener(function (mql) { // add listener to mediaquery
                        if (mql.matches) {
                            properties.active = true;

                            for (var sel in properties.selectors) {
                                var lst = document.querySelectorAll(sel);
                                for (var n = 0; n < lst.length; n++) {
                                    that.enableSelector(lst[n], mq1, sel);
                                }
                            }
                        }
                        else {
                            properties.active = false;

                            for (var sel in properties.selectors) {
                                var lst = document.querySelectorAll(sel);
                                for (var n = 0; n < lst.length; n++) {
                                    that.disableSelector(lst[n], mq1, sel);
                                }
                            }
                        }
                    });
                })(mq, this.properties[mq], this);
            }

            var that = this;

            var changes = [];
            function pushChange(elm, type) { // 0:addAll,1:removeAll,2:update
                var length = changes.length;
                for (var i = 0; i < length; i++) {
                    if (changes[i].elm == elm) {
                        if (changes[i].type != type && changes[i].type == 2) {
                            changes[i].type = type;
                            return;
                        }
                    }
                    else if (isDescendant(changes[i].elm, elm)) {
                        if (changes[i].type != type && changes[i].type == 2) {
                            changes.push({elm: elm, type: type, exclude: new Set()});
                            changes[i].exclude.add(elm);
                        }
                        return;
                    }
                    else if (isDescendant(elm, changes[i].elm)) {
                        if (changes[i].type != type && type == 2) {
                            changes.push(changes[i]);
                            changes[i] = {elm: elm, type: type, exclude: new Set()};
                            changes[i].exclude.add(changes[i].elm);
                        }
                        else {
                            changes[i] = {elm: elm, type: type, exclude: new Set()};
                        }
                        return;
                    }
                }
                changes.push({elm: elm, type: type, exclude: new Set()});
            }
            function processChanges() {
                for (var i = 0; i < changes.length; i++) {
                    var c = changes[i];

                    if (c.elm.querySelectorAll == undefined)
                        continue;

                    if (c.type == 0) { // addAll
                        for (var mq in that.properties) {
                            if (that.properties[mq].active == true) {
                                for (var sel in that.properties[mq].selectors) {
                                    var lst = c.elm.querySelectorAll(sel);
                                    for (var n = 0; n < lst.length; n++) {
                                        if (!c.exclude.has(lst[n])) {
                                            that.enableSelector(lst[n], mq, sel);
                                        }
                                    }

                                    if (c.elm.matches(sel)) {
                                        that.enableSelector(c.elm, mq, sel);
                                    }
                                }
                            }
                        }
                    }
                    else if (changes[i].type == 1) { // removeAll
                        traverseChildElements(c.elm, function (elm) {
                            var enProps = that.enabledSelectors.get(elm);
                            if (enProps != undefined) {
                                enProps.forEach(function(key) {
                                    var prop = key.split("~");
                                    that.disableSelector(elm, prop[0], prop[1]);
                                });
                            }
                            return true;
                        });
                    }
                    else { // update
                        // remove invalid rules
                        traverseChildElements(c.elm, function (elm) {
                            var enProps = that.enabledSelectors.get(elm);
                            if (enProps != undefined) {
                                enProps.forEach(function(key) {
                                    var prop = key.split("~");
                                    if (!elm.matches(prop[1])) {
                                        that.disableSelector(elm, prop[0], prop[1]);
                                    }
                                });
                            }
                        });

                        // add new rules
                        for (var mq in that.properties) {
                            if (that.properties[mq].active == true) {
                                for (var sel in that.properties[mq].selectors) {
                                    var lst = c.elm.querySelectorAll(sel);
                                    for (var n = 0; n < lst.length; n++) {
                                        that.enableSelector(lst[n], mq, sel);
                                    }

                                    if (c.elm.matches(sel)) {
                                        that.enableSelector(c.elm, mq, sel);
                                    }
                                }
                            }
                        }
                    }
                }

                changes = [];
            }
            var _timeout;

            var observer = new MutationObserver(function (mutations) {
                for (var i = 0; i < mutations.length; i++) {
                    if (mutations[i].type == "attributes") {
                        pushChange(mutations[i].target, 2);
                    }
                    else if (mutations[i].type == "childList") {
                        for (var j = 0; j < mutations[i].addedNodes.length; j++) {
                            pushChange(mutations[i].addedNodes.item(j), 0);
                        }
                        for (var j = 0; j < mutations[i].removedNodes.length; j++) {
                            pushChange(mutations[i].removedNodes.item(j), 1);
                        }
                    }
                }

                if (!!_timeout) {
                    clearTimeout(_timeout);
                }
                _timeout = setTimeout(function () {
                    processChanges();
                }, 50);
            });
            observer.observe(document, {attributes: true, childList: true, subtree: true});

            // helper functions
            function traverseChildElements(elm, fn) {
                fn(elm);
                var children = elm.children;
                if (children == undefined)
                    return;
                for (var i = 0; i < children.length; i++) {
                    if (traverseChildElements(children[i], fn) == false)
                        return;
                }
            }
            function isDescendant(parent, child) {
                var node = child.parentNode;
                while (node != null) {
                    if (node == parent) {
                        return true;
                    }
                    node = node.parentNode;
                }
                return false;
            }
        }
    }

};<|endoftext|>


<commit_before>'use strict';

const spawnSync = require('cross-spawn').sync;
const path = require('path');
const fs = require('fs');

const indent = require('indent-string');
const budo = require('budo');
const chokidar = require('chokidar');
const chalk = require('chalk');
const hasbinSync = require('hasbin').sync;

const parseArgs = require('./parse-args');
const debounce = require('./debounce');

const SUCCESS = 0;
const FAILURE = 1;

const bold = chalk.bold;
const dim = chalk.dim;

/*
  ({
    outputStream: WritableStream,
    inputStream: ReadableStream,
  }) =>
    exitCode: Integer | Null
*/
module.exports = (argv, options) => {
  const outputStream = options.outputStream;
  const inputStream = options.inputStream;
  const args = parseArgs(argv);

  // Display help
  if (args.help) {
    if (hasbinSync('man')) {
      const manpagePath =
        path.resolve(__dirname, '../manpages/elm-live.1');
      const manProcess =
        spawnSync('man', [manpagePath], { stdio: [
          inputStream, outputStream, outputStream,
        ] });

      if (manProcess.error) throw manProcess.error;
    } else {
      const fallbackPath =
        path.resolve(__dirname, '../manpages/elm-live.1.txt');
      const plainTextHelp =
        fs.readFileSync(fallbackPath, 'utf8');
      outputStream.write(plainTextHelp);
    }

    return SUCCESS;
  }

  const auxiliaryBuild = (execPath) => {
    if (!execPath) {
      return { fatal: false, exitCode: SUCCESS };
    }

    const process = spawnSync(execPath, [], {
      stdio: [inputStream, outputStream, outputStream],
    });

    if (process.error && process.error.code === 'ENOENT') {
      outputStream.write(
`\n${dim('elm-live:')}
  I can’t find the command ${bold(execPath)}!
  Please make sure you can call ${bold(execPath)}
  from your command line.

`
      );

      return { fatal: true, exitCode: FAILURE };
    } else if (process.error) {
      outputStream.write(
`\n${dim('elm-live:')} Error while calling ${bold(execPath)}! This output may be helpful:
${indent(String(process.error), 2)}

`
      );
    }

    if (args.recover && process.status !== SUCCESS) outputStream.write(
`\n${dim('elm-live:')}
  ${bold(execPath)} failed! You can find more info above. Keep calm and take your time
  to check why the command is failing. We’ll try to run it again as soon as you change an Elm file.

`
    );

    return { fatal: false, exitCode: process.status };
  };

  // Build logic
  const build = () => {
    const beforeBuild = auxiliaryBuild(args.beforeBuild);
    if (beforeBuild.exitCode !== SUCCESS) {
      return beforeBuild;
    }

    const elmMake = spawnSync(args.pathToElmMake, args.elmMakeArgs, {
      stdio: [inputStream, outputStream, outputStream],
    });

    if (elmMake.error && elmMake.error.code === 'ENOENT') {
      outputStream.write(
`\n${dim('elm-live:')}
  I can’t find the command ${bold(args.pathToElmMake)}!
  Looks like ${bold('elm-platform')} isn’t installed. Make sure you’ve followed
  the steps at https://git.io/elm-platform and that you can call
  ${bold(args.pathToElmMake)} from your command line.

  If that fails, have a look at open issues:
  https://github.com/tomekwi/elm-live/issues .

`
      );

      return { fatal: true, exitCode: FAILURE };
    } else if (elmMake.error) {
      outputStream.write(
`\n${dim('elm-live:')} Error while calling ${bold('elm-make')}! This output may be helpful:
${indent(String(elmMake.error), 2)}

`
      );
    }

    if (args.recover && elmMake.status !== SUCCESS) outputStream.write(
`\n${dim('elm-live:')}
  ${bold('elm-make')} failed! You can find more info above. Keep calm and take your time
  to fix your code. We’ll try to compile it again as soon as you change a file.

`
    );

    const afterBuild = auxiliaryBuild(args.afterBuild);
    if (afterBuild.exitCode !== SUCCESS) {
      return afterBuild;
    }

    return { fatal: false, exitCode: elmMake.status };
  };

  // Server logic
  let serverStarted;
  const startServer = () => {
    outputStream.write(
`\n${dim('elm-live:')}
  The build has succeeded. Starting the server!${args.open ? (
` We’ll open your app
  in the default browser as soon as it’s up and running.`) : ''}

`
    );
    const server = budo({
      live: true,
      watchGlob: path.join(args.dir, '**/*.{html,css,js}'),
      port: args.port,
      host: args.host,
      open: args.open,
      dir: args.dir,
      stream: outputStream,
      pushstate: args.pushstate,
    });
    server.on('error', (error) => { throw error; });

    serverStarted = true;
  };

  // First build
  const firstBuildResult = build();
  if (
    firstBuildResult.fatal ||
    (!args.recover && firstBuildResult.exitCode !== SUCCESS)
  ) {
    return firstBuildResult.exitCode;
  } else if (firstBuildResult.exitCode === SUCCESS) {
    startServer();
  }

  const eventNameMap = {
    add: 'added',
    addDir: 'added',
    change: 'changed',
    unlink: 'removed',
    unlinkDir: 'removed',
  };

  // Watch Elm files
  const watcher = chokidar.watch('**/*.elm', { ignoreInitial: true });

  watcher.on('all', debounce((event, filePath) => {
    const relativePath = path.relative(process.cwd(), filePath);
    const eventName = eventNameMap[event] || event;

    outputStream.write(
`\n${dim('elm-live:')}
  You’ve ${eventName} \`${relativePath}\`. Rebuilding!

`
    );

    const buildResult = build();
    if (!serverStarted && buildResult.exitCode === SUCCESS) {
      startServer();
    }
  }), 100);

  return null;
};
<commit_msg>Attempt at fixing infinite loop when symlinks come to play<commit_after>'use strict';

const spawnSync = require('cross-spawn').sync;
const path = require('path');
const fs = require('fs');

const indent = require('indent-string');
const budo = require('budo');
const chokidar = require('chokidar');
const chalk = require('chalk');
const hasbinSync = require('hasbin').sync;

const parseArgs = require('./parse-args');
const debounce = require('./debounce');

const SUCCESS = 0;
const FAILURE = 1;

const bold = chalk.bold;
const dim = chalk.dim;

/*
  ({
    outputStream: WritableStream,
    inputStream: ReadableStream,
  }) =>
    exitCode: Integer | Null
*/
module.exports = (argv, options) => {
  const outputStream = options.outputStream;
  const inputStream = options.inputStream;
  const args = parseArgs(argv);

  // Display help
  if (args.help) {
    if (hasbinSync('man')) {
      const manpagePath =
        path.resolve(__dirname, '../manpages/elm-live.1');
      const manProcess =
        spawnSync('man', [manpagePath], { stdio: [
          inputStream, outputStream, outputStream,
        ] });

      if (manProcess.error) throw manProcess.error;
    } else {
      const fallbackPath =
        path.resolve(__dirname, '../manpages/elm-live.1.txt');
      const plainTextHelp =
        fs.readFileSync(fallbackPath, 'utf8');
      outputStream.write(plainTextHelp);
    }

    return SUCCESS;
  }

  const auxiliaryBuild = (execPath) => {
    if (!execPath) {
      return { fatal: false, exitCode: SUCCESS };
    }

    const process = spawnSync(execPath, [], {
      stdio: [inputStream, outputStream, outputStream],
    });

    if (process.error && process.error.code === 'ENOENT') {
      outputStream.write(
`\n${dim('elm-live:')}
  I can’t find the command ${bold(execPath)}!
  Please make sure you can call ${bold(execPath)}
  from your command line.

`
      );

      return { fatal: true, exitCode: FAILURE };
    } else if (process.error) {
      outputStream.write(
`\n${dim('elm-live:')} Error while calling ${bold(execPath)}! This output may be helpful:
${indent(String(process.error), 2)}

`
      );
    }

    if (args.recover && process.status !== SUCCESS) outputStream.write(
`\n${dim('elm-live:')}
  ${bold(execPath)} failed! You can find more info above. Keep calm and take your time
  to check why the command is failing. We’ll try to run it again as soon as you change an Elm file.

`
    );

    return { fatal: false, exitCode: process.status };
  };

  // Build logic
  const build = () => {
    const beforeBuild = auxiliaryBuild(args.beforeBuild);
    if (beforeBuild.exitCode !== SUCCESS) {
      return beforeBuild;
    }

    const elmMake = spawnSync(args.pathToElmMake, args.elmMakeArgs, {
      stdio: [inputStream, outputStream, outputStream],
    });

    if (elmMake.error && elmMake.error.code === 'ENOENT') {
      outputStream.write(
`\n${dim('elm-live:')}
  I can’t find the command ${bold(args.pathToElmMake)}!
  Looks like ${bold('elm-platform')} isn’t installed. Make sure you’ve followed
  the steps at https://git.io/elm-platform and that you can call
  ${bold(args.pathToElmMake)} from your command line.

  If that fails, have a look at open issues:
  https://github.com/tomekwi/elm-live/issues .

`
      );

      return { fatal: true, exitCode: FAILURE };
    } else if (elmMake.error) {
      outputStream.write(
`\n${dim('elm-live:')} Error while calling ${bold('elm-make')}! This output may be helpful:
${indent(String(elmMake.error), 2)}

`
      );
    }

    if (args.recover && elmMake.status !== SUCCESS) outputStream.write(
`\n${dim('elm-live:')}
  ${bold('elm-make')} failed! You can find more info above. Keep calm and take your time
  to fix your code. We’ll try to compile it again as soon as you change a file.

`
    );

    const afterBuild = auxiliaryBuild(args.afterBuild);
    if (afterBuild.exitCode !== SUCCESS) {
      return afterBuild;
    }

    return { fatal: false, exitCode: elmMake.status };
  };

  // Server logic
  let serverStarted;
  const startServer = () => {
    outputStream.write(
`\n${dim('elm-live:')}
  The build has succeeded. Starting the server!${args.open ? (
` We’ll open your app
  in the default browser as soon as it’s up and running.`) : ''}

`
    );
    const server = budo({
      live: true,
      watchGlob: path.join(args.dir, '**/*.{html,css,js}'),
      port: args.port,
      host: args.host,
      open: args.open,
      dir: args.dir,
      stream: outputStream,
      pushstate: args.pushstate,
    });
    server.on('error', (error) => { throw error; });

    serverStarted = true;
  };

  // First build
  const firstBuildResult = build();
  if (
    firstBuildResult.fatal ||
    (!args.recover && firstBuildResult.exitCode !== SUCCESS)
  ) {
    return firstBuildResult.exitCode;
  } else if (firstBuildResult.exitCode === SUCCESS) {
    startServer();
  }

  const eventNameMap = {
    add: 'added',
    addDir: 'added',
    change: 'changed',
    unlink: 'removed',
    unlinkDir: 'removed',
  };

  // Watch Elm files
  const watcher = chokidar.watch('**/*.elm', { ignoreInitial: true, followSymlinks: false });

  watcher.on('all', debounce((event, filePath) => {
    const relativePath = path.relative(process.cwd(), filePath);
    const eventName = eventNameMap[event] || event;

    outputStream.write(
`\n${dim('elm-live:')}
  You’ve ${eventName} \`${relativePath}\`. Rebuilding!

`
    );

    const buildResult = build();
    if (!serverStarted && buildResult.exitCode === SUCCESS) {
      startServer();
    }
  }), 100);

  return null;
};
<|endoftext|>


<commit_before>'use strict';

const spawnSync = require('cross-spawn').sync;
const path = require('path');

const indent = require('indent-string');
const budo = require('budo');
const chokidar = require('chokidar');
const chalk = require('chalk');
const bold = chalk.bold;
const dim = chalk.dim;

const SUCCESS = 0;
const FAILURE = 1;

const parseArgs = require('./parse-args');

/*
  ({
    outputStream: WritableStream,
    inputStream: ReadableStream,
  }) =>
    exitCode: Integer | Null
*/
module.exports = (argv, options) => {
  const outputStream = options.outputStream;
  const inputStream = options.inputStream;
  const args = parseArgs(argv);

  // Display help
  if (args.help) {
    spawnSync('man', [
      path.resolve(__dirname, '../manpages/elm-live.1'),
    ], { stdio: 'inherit' });

    return SUCCESS;
  }

  // Build logic
  const build = () => {
    const elmMake = spawnSync('elm-make', args.elmMakeArgs, {
      stdio: [inputStream, outputStream, outputStream],
    });

    if (elmMake.error && elmMake.error.code === 'ENOENT') {
      outputStream.write(
`\n${ dim('elm-live:') }
  I can’t find the command ${ bold('elm-make') }! Looks like ${ bold('elm-platform') }
  isn’t installed. Make sure you’ve followed the steps
  at https://git.io/elm-platform and that you can call ${ bold('elm-make') }
  from your command line.

  If that fails, have a look at open issues:
  https://github.com/tomekwi/elm-live/issues .

`
      );

      return { fatal: true, exitCode: FAILURE };
    } else if (elmMake.error) {
      outputStream.write(
`\n${ dim('elm-live:') } Error while calling ${ bold('elm-make') }! This output may be helpful:
${ indent(String(elmMake.error), '  ') }

`
      );
    }

    if (args.recover && elmMake.status !== SUCCESS) outputStream.write(
`\n${ dim('elm-live:') }
  ${ bold('elm-make') } failed! You can find more info above. Keep calm and take your time
  to fix your code. We’ll try to compile it again as soon as you change a file.

`
    );

    return { fatal: false, exitCode: elmMake.status };
  };

  // Server logic
  let serverStarted;
  const startServer = () => {
    outputStream.write(
`\n${ dim('elm-live:') }
  ${ bold('elm-make') } has succeeded. Starting the server!${ args.open ? (
` We’ll open your app
  in the default browser as soon as it’s up and running.`) : '' }

`
    );
    const server = budo({
      live: true,
      watchGlob: '**/*.{html,css,js}',
      port: args.port,
      open: args.open,
      stream: outputStream,
    });
    server.on('error', (error) => { throw error; });

    serverStarted = true;
  };

  // First build
  const firstBuildResult = build();
  if (
    firstBuildResult.fatal ||
    (!args.recover && firstBuildResult.exitCode !== SUCCESS)
  ) {
    return firstBuildResult.exitCode;
  } else if (firstBuildResult.exitCode === SUCCESS) {
    startServer();
  }

  // Watch Elm files
  const watcher = chokidar.watch('**/*.elm', { ignoreInitial: true, ignorePermissionErrors: true });

  watcher.on('all', (event, filePath) => {
    const relativePath = path.relative(process.cwd(), filePath);

    outputStream.write(
`\n${ dim('elm-live:') }
  You’ve ${ event } \`${ relativePath }\`. Rebuilding!

`
    );

    const buildResult = build();
    if (!serverStarted && buildResult.exitCode === SUCCESS) {
      startServer();
    }
  });

  return null;
};
<commit_msg>Don't pass ignorePermissionErrors config<commit_after>'use strict';

const spawnSync = require('cross-spawn').sync;
const path = require('path');

const indent = require('indent-string');
const budo = require('budo');
const chokidar = require('chokidar');
const chalk = require('chalk');
const bold = chalk.bold;
const dim = chalk.dim;

const SUCCESS = 0;
const FAILURE = 1;

const parseArgs = require('./parse-args');

/*
  ({
    outputStream: WritableStream,
    inputStream: ReadableStream,
  }) =>
    exitCode: Integer | Null
*/
module.exports = (argv, options) => {
  const outputStream = options.outputStream;
  const inputStream = options.inputStream;
  const args = parseArgs(argv);

  // Display help
  if (args.help) {
    spawnSync('man', [
      path.resolve(__dirname, '../manpages/elm-live.1'),
    ], { stdio: 'inherit' });

    return SUCCESS;
  }

  // Build logic
  const build = () => {
    const elmMake = spawnSync('elm-make', args.elmMakeArgs, {
      stdio: [inputStream, outputStream, outputStream],
    });

    if (elmMake.error && elmMake.error.code === 'ENOENT') {
      outputStream.write(
`\n${ dim('elm-live:') }
  I can’t find the command ${ bold('elm-make') }! Looks like ${ bold('elm-platform') }
  isn’t installed. Make sure you’ve followed the steps
  at https://git.io/elm-platform and that you can call ${ bold('elm-make') }
  from your command line.

  If that fails, have a look at open issues:
  https://github.com/tomekwi/elm-live/issues .

`
      );

      return { fatal: true, exitCode: FAILURE };
    } else if (elmMake.error) {
      outputStream.write(
`\n${ dim('elm-live:') } Error while calling ${ bold('elm-make') }! This output may be helpful:
${ indent(String(elmMake.error), '  ') }

`
      );
    }

    if (args.recover && elmMake.status !== SUCCESS) outputStream.write(
`\n${ dim('elm-live:') }
  ${ bold('elm-make') } failed! You can find more info above. Keep calm and take your time
  to fix your code. We’ll try to compile it again as soon as you change a file.

`
    );

    return { fatal: false, exitCode: elmMake.status };
  };

  // Server logic
  let serverStarted;
  const startServer = () => {
    outputStream.write(
`\n${ dim('elm-live:') }
  ${ bold('elm-make') } has succeeded. Starting the server!${ args.open ? (
` We’ll open your app
  in the default browser as soon as it’s up and running.`) : '' }

`
    );
    const server = budo({
      live: true,
      watchGlob: '**/*.{html,css,js}',
      port: args.port,
      open: args.open,
      stream: outputStream,
    });
    server.on('error', (error) => { throw error; });

    serverStarted = true;
  };

  // First build
  const firstBuildResult = build();
  if (
    firstBuildResult.fatal ||
    (!args.recover && firstBuildResult.exitCode !== SUCCESS)
  ) {
    return firstBuildResult.exitCode;
  } else if (firstBuildResult.exitCode === SUCCESS) {
    startServer();
  }

  // Watch Elm files
  const watcher = chokidar.watch('**/*.elm', { ignoreInitial: true });

  watcher.on('all', (event, filePath) => {
    const relativePath = path.relative(process.cwd(), filePath);

    outputStream.write(
`\n${ dim('elm-live:') }
  You’ve ${ event } \`${ relativePath }\`. Rebuilding!

`
    );

    const buildResult = build();
    if (!serverStarted && buildResult.exitCode === SUCCESS) {
      startServer();
    }
  });

  return null;
};
<|endoftext|>


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

'use strict';

const test = require(`ava`);
const {runAsync} = require('@google-cloud/nodejs-repo-tools');

const cmd = 'node detect.v2beta1.js';
const testQuery = `Where is my data stored?`;

const testKnowledgeBaseName = 'TestKnowledgeBase';

const testDocName = `TestDoc`;
const testDocumentPath = `https://cloud.google.com/storage/docs/faq`;

test.serial(`It should create a knowledge base`, async t => {
  // Check that the knowledge base does not yet exist
  let output = await runAsync(`${cmd} listKnowledgeBases`);
  t.false(output.includes(testKnowledgeBaseName));

  // Creates a knowledge base
  output = await runAsync(
    `${cmd} createKnowledgeBase -k ${testKnowledgeBaseName}`
  );
  t.true(output.includes(`displayName: ${testKnowledgeBaseName}`));
  const knowbaseFullName = output
    .split(`\n`)[0]
    .split(`:`)[1]
    .trim();
  const knowbaseId = output
    .split(`\n`)[0]
    .split(`knowledgeBases/`)[1]
    .trim();

  // List the knowledge base
  output = await runAsync(`${cmd} listKnowledgeBases`);
  t.true(output.includes(testKnowledgeBaseName));

  // Get the knowledge base
  output = await runAsync(`${cmd} getKnowledgeBase -b "${knowbaseId}"`);
  t.true(output.includes(`displayName: ${testKnowledgeBaseName}`));
  t.true(output.includes(`name: ${knowbaseFullName}`));

  // Create a document
  output = await runAsync(
    `${cmd} createDocument -n "${knowbaseFullName}" -z "${testDocumentPath}" -m "${testDocName}"`
  );
  t.true(output.includes(`Document created`));

  // List the Document
  output = await runAsync(`${cmd} listDocuments -n "${knowbaseFullName}"`);
  const parsedOut = output.split(`\n`);
  const documentFullPath = parsedOut[parsedOut.length - 1].split(`:`)[1];
  t.true(output.includes(`There are 1 documents in ${knowbaseFullName}`));

  // Detect intent with Knowledge Base
  output = await runAsync(
    `${cmd} detectIntentKnowledge -q "${testQuery}" -n "${knowbaseId}"`
  );
  t.true(output.includes(`Detected Intent:`));

  // Delete the Document
  output = await runAsync(`${cmd} deleteDocument -d ${documentFullPath}`);
  t.true(output.includes(`document deleted`));

  // List the Document
  output = await runAsync(`${cmd} listDocuments -n "${knowbaseFullName}"`);
  t.false(output.includes(documentFullPath));

  // Delete the Knowledge Base
  output = await runAsync(
    `${cmd} deleteKnowledgeBase -n "${knowbaseFullName}"`
  );

  // List the Knowledge Base
  output = await runAsync(`${cmd} listKnowledgeBases`);
  t.false(output.includes(testKnowledgeBaseName));
});

test(`It should detect Intent with Model Selection`, async t => {
  const output = await runAsync(`${cmd} detectIntentwithModelSelection`);
  t.true(
    output.includes(
      `Response: I can help with that. Where would you like to reserve a room?`
    )
  );
});

test(`It should detect Intent with Text to Speech Response`, async t => {
  const output = await runAsync(
    `${cmd} detectIntentwithTexttoSpeechResponse -q "${testQuery}"`
  );
  t.true(
    output.includes(`Audio content written to file: ./resources/output.wav`)
  );
});

test(`It should detect sentiment with intent`, async t => {
  const output = await runAsync(
    `${cmd} detectIntentandSentiment -q "${testQuery}"`
  );
  t.true(output.includes(`Detected sentiment`));
});
<commit_msg>fix: use unique name for sample test knowledge base (#198)<commit_after>/**
 * Copyright 2018, Google, LLC.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

const test = require(`ava`);
const {runAsync} = require('@google-cloud/nodejs-repo-tools');
const uuid = require('uuid/v4');

const cmd = 'node detect.v2beta1.js';
const testQuery = `Where is my data stored?`;
const testKnowledgeBaseName = `${uuid().split('-')[0]}-TestKnowledgeBase`;
const testDocName = `TestDoc`;
const testDocumentPath = `https://cloud.google.com/storage/docs/faq`;

test.serial(`It should create a knowledge base`, async t => {
  // Check that the knowledge base does not yet exist
  let output = await runAsync(`${cmd} listKnowledgeBases`);
  t.false(output.includes(testKnowledgeBaseName));

  // Creates a knowledge base
  output = await runAsync(
    `${cmd} createKnowledgeBase -k ${testKnowledgeBaseName}`
  );
  t.true(output.includes(`displayName: ${testKnowledgeBaseName}`));
  const knowbaseFullName = output
    .split(`\n`)[0]
    .split(`:`)[1]
    .trim();
  const knowbaseId = output
    .split(`\n`)[0]
    .split(`knowledgeBases/`)[1]
    .trim();

  // List the knowledge base
  output = await runAsync(`${cmd} listKnowledgeBases`);
  t.true(output.includes(testKnowledgeBaseName));

  // Get the knowledge base
  output = await runAsync(`${cmd} getKnowledgeBase -b "${knowbaseId}"`);
  t.true(output.includes(`displayName: ${testKnowledgeBaseName}`));
  t.true(output.includes(`name: ${knowbaseFullName}`));

  // Create a document
  output = await runAsync(
    `${cmd} createDocument -n "${knowbaseFullName}" -z "${testDocumentPath}" -m "${testDocName}"`
  );
  t.true(output.includes(`Document created`));

  // List the Document
  output = await runAsync(`${cmd} listDocuments -n "${knowbaseFullName}"`);
  const parsedOut = output.split(`\n`);
  const documentFullPath = parsedOut[parsedOut.length - 1].split(`:`)[1];
  t.true(output.includes(`There are 1 documents in ${knowbaseFullName}`));

  // Detect intent with Knowledge Base
  output = await runAsync(
    `${cmd} detectIntentKnowledge -q "${testQuery}" -n "${knowbaseId}"`
  );
  t.true(output.includes(`Detected Intent:`));

  // Delete the Document
  output = await runAsync(`${cmd} deleteDocument -d ${documentFullPath}`);
  t.true(output.includes(`document deleted`));

  // List the Document
  output = await runAsync(`${cmd} listDocuments -n "${knowbaseFullName}"`);
  t.false(output.includes(documentFullPath));

  // Delete the Knowledge Base
  output = await runAsync(
    `${cmd} deleteKnowledgeBase -n "${knowbaseFullName}"`
  );

  // List the Knowledge Base
  output = await runAsync(`${cmd} listKnowledgeBases`);
  t.false(output.includes(testKnowledgeBaseName));
});

test(`It should detect Intent with Model Selection`, async t => {
  const output = await runAsync(`${cmd} detectIntentwithModelSelection`);
  t.true(
    output.includes(
      `Response: I can help with that. Where would you like to reserve a room?`
    )
  );
});

test(`It should detect Intent with Text to Speech Response`, async t => {
  const output = await runAsync(
    `${cmd} detectIntentwithTexttoSpeechResponse -q "${testQuery}"`
  );
  t.true(
    output.includes(`Audio content written to file: ./resources/output.wav`)
  );
});

test(`It should detect sentiment with intent`, async t => {
  const output = await runAsync(
    `${cmd} detectIntentandSentiment -q "${testQuery}"`
  );
  t.true(output.includes(`Detected sentiment`));
});
<|endoftext|>


<commit_before>$(document).ready(function(){
	$.ajaxSetup({cache: false});
	var speakers;

	$.getJSON( "../assets/json/data.json", function(data) {
		console.dir(data);
		speakers = data.speakers;
		initSecond();
	});
	//var speakers = [];
	var mobileQuery = window.matchMedia('(max-width : 767px)');
	var modalShown = false;

	$( document ).ajaxError(function() {
		$('.top-buffer').prepend("Need to be on server to access external speakers file. Here is some test content.");
		console.log("Need to be on server to access external speakers file. Here is some test content.");
		offline();
	});

	function offline(){
		var info = "Bushra\|\|Senior Director\|Nicholas Cage\'presentations\'stuff\|aldksflkj description\|Adding Cage\-ism\|Friday October 21, 7:00\-8:00PM\|loremipsum.com\|http://loremipsum.com\|link.com\|socialMedia.com\\Person\|\|Junior Something\|eqwr\'sdf\'jobs\'stuffs\|dfjljjjf desc\|Bloops\|Sunday, 5\-2AM\|bleepbloop.com\|http://website.com\|otherlink.com\|http://url.com\\Kiddo\|\|Manager of Someplace\|laskdfj\'ekcv\'lafkj\|bnc,mznvew descr\|Meeps\|Monday, 4\-0PM\|meepmeep.com\|http://website.com\|otherotherlink.com\|http://url.com\\Fourtho\|\|Manager of Someotherplace\|cxzxcv\'qweg\'lfdhshh\|erasdgardff descr\|Mops\|Monday, 4\-6PM\|meepmop.com\|http://website.com\|otherslink.com\|http://url.com";
		//sortData(info);
		initSecond();
	}

	function initSecond(){
		$('.modal-closer').click(function(){
			closeModal();
		});

		$('.modal__x').click(function(){
			closeModal();
		});

    $('.speaker').click(function(){
      showModal(this);
    });
	}

  /*$(window).resize(function(){ // also changes clicking on speaker to clicking on view more
		$('.speaker').off();
		$('.speaker-expand').off();
		$('.speaker-image').off();
		if($('.speaker-expand').css('display') == 'none'){
			//mobile = false;
			$('.speaker').click(function(){
				showModal(this);
			});
		}
		else{
			//mobile = true;
			$('.speaker-expand').click(function(){
				showModal($(this).parents('.speaker'));
			});
			$('.speaker-image').click(function(){
				showModal($(this).parent());
			});
		}
		if(mobileQuery.matches)
			$('.container-fluid').removeClass('blur');
		if(!mobileQuery.matches && modalShown)
			$('.container-fluid').addClass('blur');
	});*/

  function showModal(speaker) {
    modalShown = true;
    //$('.modal__content').detach();
    fillModal($(speaker).index());
    $('.speakers-modal').toggleClass('modal--hidden');
    $('.modal-closer').toggleClass('modal--hidden');

    /*if(!mobileQuery.matches)
			$('.container-fluid').addClass('blur');
		$('.speakers-splash-words').attr('id', 'changeBG');*/
  }

  function closeModal() {
    modalShown = false;
    $('.speakers-modal').toggleClass('modal--hidden');
    $('.modal-closer').toggleClass('modal--hidden');

    /*if(!mobileQuery.matches)
			$('.container-fluid').removeClass('blur');
		$('.speakers-splash-words').removeAttr('id');*/
  }

  function fillModal(i) {
    $('.speakers-modal__name').html(speakers[i].firstName + " " + speakers[i].lastName);
    $('.speakers-modal__position').html(speakers[i].position + " at " + speakers[i].company);
    $('.speakers-modal__headshot').attr('src', speakers[i].headshot);
    $('.speakers-modal__social').html("");
    speakers[i].socialMedia.forEach(function(social) {
      $('.speakers-modal__social').append('');
    });

    $('.modal__accord').html('
Presentations
');
    speakers[i].presentations.forEach(function(pres) {
      $('.modal__accord').append('
+ ' + pres.title + '

' + pres.desc + '

');
    });

    $('.modal__accord-title').click(function() {
      if ($(this).children('span').html() == '–')
        $(this).children('span').html('+');
      else
        $(this).children('span').html('–');

      $(this).next().toggleClass('open');
    });

    /*if($('.speakers-modal__headshot').attr('src') == 'https://taw.imgix.net/speakers/jeff_smith.jpg?w=.779&h=1&crop=focalpoint&fit=crop&fp-x=0.2&fp-y=0.3')
			$('.speakers-modal__headshot').attr('title', 'Jeff didn\'t give us a good picture.');
		else
			$('.speakers-modal__headshot').removeAttr('title');*/
  }
});
<commit_msg>update description in modal<commit_after>$(document).ready(function(){
	$.ajaxSetup({cache: false});
	var speakers;

	$.getJSON( "../assets/json/data.json", function(data) {
		console.dir(data);
		speakers = data.speakers;
		initSecond();
	});
	//var speakers = [];
	var mobileQuery = window.matchMedia('(max-width : 767px)');
	var modalShown = false;

	$( document ).ajaxError(function() {
		$('.top-buffer').prepend("Need to be on server to access external speakers file. Here is some test content.");
		console.log("Need to be on server to access external speakers file. Here is some test content.");
		offline();
	});

	function offline(){
		var info = "Bushra\|\|Senior Director\|Nicholas Cage\'presentations\'stuff\|aldksflkj description\|Adding Cage\-ism\|Friday October 21, 7:00\-8:00PM\|loremipsum.com\|http://loremipsum.com\|link.com\|socialMedia.com\\Person\|\|Junior Something\|eqwr\'sdf\'jobs\'stuffs\|dfjljjjf desc\|Bloops\|Sunday, 5\-2AM\|bleepbloop.com\|http://website.com\|otherlink.com\|http://url.com\\Kiddo\|\|Manager of Someplace\|laskdfj\'ekcv\'lafkj\|bnc,mznvew descr\|Meeps\|Monday, 4\-0PM\|meepmeep.com\|http://website.com\|otherotherlink.com\|http://url.com\\Fourtho\|\|Manager of Someotherplace\|cxzxcv\'qweg\'lfdhshh\|erasdgardff descr\|Mops\|Monday, 4\-6PM\|meepmop.com\|http://website.com\|otherslink.com\|http://url.com";
		//sortData(info);
		initSecond();
	}

	function initSecond(){
		$('.modal-closer').click(function(){
			closeModal();
		});

		$('.modal__x').click(function(){
			closeModal();
		});

    $('.speaker').click(function(){
      showModal(this);
    });
	}

  /*$(window).resize(function(){ // also changes clicking on speaker to clicking on view more
		$('.speaker').off();
		$('.speaker-expand').off();
		$('.speaker-image').off();
		if($('.speaker-expand').css('display') == 'none'){
			//mobile = false;
			$('.speaker').click(function(){
				showModal(this);
			});
		}
		else{
			//mobile = true;
			$('.speaker-expand').click(function(){
				showModal($(this).parents('.speaker'));
			});
			$('.speaker-image').click(function(){
				showModal($(this).parent());
			});
		}
		if(mobileQuery.matches)
			$('.container-fluid').removeClass('blur');
		if(!mobileQuery.matches && modalShown)
			$('.container-fluid').addClass('blur');
	});*/

  function showModal(speaker) {
    modalShown = true;
    //$('.modal__content').detach();
    fillModal($(speaker).index());
    $('.speakers-modal').toggleClass('modal--hidden');
    $('.modal-closer').toggleClass('modal--hidden');

    /*if(!mobileQuery.matches)
			$('.container-fluid').addClass('blur');
		$('.speakers-splash-words').attr('id', 'changeBG');*/
  }

  function closeModal() {
    modalShown = false;
    $('.speakers-modal').toggleClass('modal--hidden');
    $('.modal-closer').toggleClass('modal--hidden');

    /*if(!mobileQuery.matches)
			$('.container-fluid').removeClass('blur');
		$('.speakers-splash-words').removeAttr('id');*/
  }

  function fillModal(i) {
    $('.speakers-modal__name').html(speakers[i].firstName + " " + speakers[i].lastName);
    $('.speakers-modal__position').html(speakers[i].position + " at " + speakers[i].company);
    $('.speakers-modal__desc').html(speakers[i].bio);
    $('.speakers-modal__headshot').attr('src', speakers[i].headshot);
    $('.speakers-modal__social').html("");
    speakers[i].socialMedia.forEach(function(social) {
      $('.speakers-modal__social').append('');
    });

    $('.modal__accord').html('
Presentations
');
    speakers[i].presentations.forEach(function(pres) {
      $('.modal__accord').append('
+ ' + pres.title + '

' + pres.desc + '

');
    });

    $('.modal__accord-title').click(function() {
      if ($(this).children('span').html() == '–')
        $(this).children('span').html('+');
      else
        $(this).children('span').html('–');

      $(this).next().toggleClass('open');
    });

    /*if($('.speakers-modal__headshot').attr('src') == 'https://taw.imgix.net/speakers/jeff_smith.jpg?w=.779&h=1&crop=focalpoint&fit=crop&fp-x=0.2&fp-y=0.3')
			$('.speakers-modal__headshot').attr('title', 'Jeff didn\'t give us a good picture.');
		else
			$('.speakers-modal__headshot').removeAttr('title');*/
  }
});
<|endoftext|>


<commit_before>
if(Common.getInstance().currentPageIsGeocacheDetailPage === true){
	// run the extension scripts
	runElevationFeature();
	runFriendFeature();
}<commit_msg>Improve starting performance<commit_after>
if(Common.getInstance().currentPageIsGeocacheDetailPage === true){
	// run the extension scripts
	setTimeout(runElevationFeature, 0);
	setTimeout(runFriendFeature, 0);
}<|endoftext|>


<commit_before>// @flow
import React from 'react'
import {RefreshControl} from 'react-native'
import {ScrollView} from 'glamorous-native'
import {Markdown} from '../components/markdown'
import {reportNetworkProblem} from '../../lib/report-network-problem'
import LoadingView from '../components/loading'
import * as defaultData from '../../../docs/faqs.json'
import delay from 'delay'

const faqsUrl = 'https://stodevx.github.io/AAO-React-Native/faqs.json'

export class FaqView extends React.PureComponent {
  static navigationOptions = {
    title: 'FAQs',
  }

  state = {
    text: defaultData.text,
    loading: true,
    refreshing: false,
  }

  componentWillMount() {
    this.fetchData().then(() => {
      this.setState(() => ({loading: false}))
    })
  }

  fetchData = async () => {
    let {text} = await fetchJson(faqsUrl).catch(err => {
      reportNetworkProblem(err)
      return {text: 'There was a problem loading the FAQs'}
    })

    if (process.env.NODE_ENV === 'development') {
      text = defaultData.text
    }

    this.setState(() => ({text}))
  }

  refresh = async () => {
    const start = Date.now()
    this.setState(() => ({refreshing: true}))

    await this.fetchData()

    // wait 0.5 seconds – if we let it go at normal speed, it feels broken.
    const elapsed = Date.now() - start
    if (elapsed < 500) {
      await delay(500 - elapsed)
    }
    this.setState(() => ({refreshing: false}))
  }

  render() {
    if (this.state.loading) {
      return <LoadingView />
    }

    const refreshControl = (
      <RefreshControl
        refreshing={this.state.refreshing}
        onRefresh={this.refresh}
      />
    )

    return (
      <ScrollView refreshControl={refreshControl} paddingHorizontal={15}>
        <Markdown source={this.state.text} />
      </ScrollView>
    )
  }
}
<commit_msg>Use AAO_USER_AGENT to fetch FAQ's<commit_after>// @flow
import React from 'react'
import {RefreshControl} from 'react-native'
import {ScrollView} from 'glamorous-native'
import {Markdown} from '../components/markdown'
import {reportNetworkProblem} from '../../lib/report-network-problem'
import {AAO_USER_AGENT} from '../../user-agent'
import LoadingView from '../components/loading'
import * as defaultData from '../../../docs/faqs.json'
import delay from 'delay'

const faqsUrl = 'https://stodevx.github.io/AAO-React-Native/faqs.json'

export class FaqView extends React.PureComponent {
  static navigationOptions = {
    title: 'FAQs',
  }

  state = {
    text: defaultData.text,
    loading: true,
    refreshing: false,
  }

  componentWillMount() {
    this.fetchData().then(() => {
      this.setState(() => ({loading: false}))
    })
  }

  fetchData = async () => {
    let {text} = await fetchJson(faqsUrl, {
      headers: new Headers({'User-Agent': AAO_USER_AGENT}),
    }).catch(err => {
      reportNetworkProblem(err)
      return {text: 'There was a problem loading the FAQs'}
    })

    if (process.env.NODE_ENV === 'development') {
      text = defaultData.text
    }

    this.setState(() => ({text}))
  }

  refresh = async () => {
    const start = Date.now()
    this.setState(() => ({refreshing: true}))

    await this.fetchData()

    // wait 0.5 seconds – if we let it go at normal speed, it feels broken.
    const elapsed = Date.now() - start
    if (elapsed < 500) {
      await delay(500 - elapsed)
    }
    this.setState(() => ({refreshing: false}))
  }

  render() {
    if (this.state.loading) {
      return <LoadingView />
    }

    const refreshControl = (
      <RefreshControl
        refreshing={this.state.refreshing}
        onRefresh={this.refresh}
      />
    )

    return (
      <ScrollView refreshControl={refreshControl} paddingHorizontal={15}>
        <Markdown source={this.state.text} />
      </ScrollView>
    )
  }
}
<|endoftext|>


<commit_before>import Game from 'game/index';
import ui from 'ui';

ui.screen.size = {
	width: 224*2,
	height: 256*2
};

const game = Game();

game
	.on('end', level => {
		game.start(level + 1);
	})
	.start(1);
<commit_msg>loop to level 1 when level 32 is terminated<commit_after>import Game from 'game/index';
import ui from 'ui';

ui.screen.size = {
	width: 224*2,
	height: 256*2
};

const game = Game();

game
	.on('end', level => {
		game.start(level === 32 ? 1 : level + 1);
	})
	.start(1);
<|endoftext|>


<commit_before>/**
 * @typedef {Array<string|Object|Array>} AST
 */
let AST;

/**
 * Get the all children with the given name. Automatically skips attributes
 *
 * @param   {!AST}    ast   The parent
 * @param   {string}  name  The name of the children, without any prefixes
 *
 * @return  {Array<AST>}  The matching children
 */
function getChildren (ast, name) {
	const children = [];
	for (let i = 1; i < ast.length; ++i) {
		if (!Array.isArray(ast[i])) {
			continue;
		}
		if (name === '*' || ast[i][0] === name) {
			children.push(ast[i]);
		}
	}
	return children;
}

/**
 * Get the first child with the given name. Automatically skips attributes
 *
 * @param   {!AST}    ast   The parent
 * @param   {string}  name  The name of the child, without any prefixes
 *
 * @return  {?AST}  The matching child, or null
 */
function getFirstChild (ast, name) {
	for (let i = 1; i < ast.length; ++i) {
		if (!Array.isArray(ast[i])) {
			continue;
		}
		if (name === '*' || ast[i][0] === name) {
			return ast[i];
		}
	}
	return null;
}

/**
 * Get the textContent of the given ast node (assuming its type is simpleContent)
 *
 * @param   {!AST}    ast  The parent
 * @return  {string}  The string content
 */
function getTextContent (ast) {
	if (ast.length < 2) {
		return '';
	}
	if (typeof ast[1] === 'object') {
		return ast[2];
	}
	return ast[1];
}

/**
 * Follow a path to an AST node
 *
 * @param   {!AST}            ast
 * @param   {!Array<string>}  path
 *
 * @return  {?AST}
 */
function followPath (ast, path) {
	return path.reduce(getFirstChild, ast);
}

/**
 * Get the value of the given attribute
 *
 * @param  {!AST}    ast
 * @param  {string}  name
 *
 * @return {atring|null}
 */
function getAttribute (ast, attributeName) {
	if (!Array.isArray(ast)) {
		return null;
	}
	const attrs = ast[1];
	if (typeof attrs !== 'object' || !Array.isArray(attrs)) {
		return null;
	}

	return attrs[attributeName] || null;
}

export default {
	followPath: followPath,
	getChildren, getChildren,
	getFirstChild: getFirstChild,
	getTextContent: getTextContent,
	getAttribute: getAttribute
};
<commit_msg>[skip ci] Fix getAttribute<commit_after>/**
 * @typedef {Array<string|Object|Array>} AST
 */
let AST;

/**
 * Get the all children with the given name. Automatically skips attributes
 *
 * @param   {!AST}    ast   The parent
 * @param   {string}  name  The name of the children, without any prefixes
 *
 * @return  {Array<AST>}  The matching children
 */
function getChildren (ast, name) {
	const children = [];
	for (let i = 1; i < ast.length; ++i) {
		if (!Array.isArray(ast[i])) {
			continue;
		}
		if (name === '*' || ast[i][0] === name) {
			children.push(ast[i]);
		}
	}
	return children;
}

/**
 * Get the first child with the given name. Automatically skips attributes
 *
 * @param   {!AST}    ast   The parent
 * @param   {string}  name  The name of the child, without any prefixes
 *
 * @return  {?AST}  The matching child, or null
 */
function getFirstChild (ast, name) {
	for (let i = 1; i < ast.length; ++i) {
		if (!Array.isArray(ast[i])) {
			continue;
		}
		if (name === '*' || ast[i][0] === name) {
			return ast[i];
		}
	}
	return null;
}

/**
 * Get the textContent of the given ast node (assuming its type is simpleContent)
 *
 * @param   {!AST}    ast  The parent
 * @return  {string}  The string content
 */
function getTextContent (ast) {
	if (ast.length < 2) {
		return '';
	}
	if (typeof ast[1] === 'object') {
		return ast[2];
	}
	return ast[1];
}

/**
 * Follow a path to an AST node
 *
 * @param   {!AST}            ast
 * @param   {!Array<string>}  path
 *
 * @return  {?AST}
 */
function followPath (ast, path) {
	return path.reduce(getFirstChild, ast);
}

/**
 * Get the value of the given attribute
 *
 * @param  {!AST}    ast
 * @param  {string}  name
 *
 * @return {atring|null}
 */
function getAttribute (ast, attributeName) {
	if (!Array.isArray(ast)) {
		return null;
	}
	const attrs = ast[1];
	if (typeof attrs !== 'object' || Array.isArray(attrs)) {
		return null;
	}

	return attrs[attributeName] || null;
}

export default {
	followPath: followPath,
	getChildren, getChildren,
	getFirstChild: getFirstChild,
	getTextContent: getTextContent,
	getAttribute: getAttribute
};
<|endoftext|>