<commit_before>/**
 * Simple HTTP requests monitor and analyzer
 */
exports.version = '1.1';

exports.module = function(phantomas) {
	// imports
	var HTTP_STATUS_CODES = phantomas.require('http').STATUS_CODES,
		parseUrl = phantomas.require('url').parse;

	var requests = [];

	// register metric
	phantomas.setMetric('requests');
	phantomas.setMetric('gzipRequests');
	phantomas.setMetric('postRequests');
	phantomas.setMetric('redirects');
	phantomas.setMetric('notFound');
	phantomas.setMetric('timeToFirstByte');
	phantomas.setMetric('timeToLastByte');
	phantomas.setMetric('bodySize'); // content only
	phantomas.setMetric('contentLength'); // content only

	// parse given URL to get protocol and domain
	function parseEntryUrl(entry) {
		var parsed;

		if (entry.url.indexOf('data:') !== 0) {
			// @see http://nodejs.org/api/url.html#url_url
			parsed = parseUrl(entry.url) || {};

			entry.protocol = parsed.protocol.replace(':', '');
			entry.domain = parsed.hostname;
			entry.query = parsed.query;

			if (entry.protocol === 'https') {
				entry.isSSL = true;
			}
		}
		else {
			// base64 encoded data
			entry.domain = false;
			entry.protocol = false;
			entry.isBase64 = true;
		}
	}

	// when the monitoring started?
	var start;
	phantomas.on('pageOpen', function(res) {
		start = Date.now();
	});

	phantomas.on('onResourceRequested', function(res) {
		// store current request data
		var entry = requests[res.id] = {
			id: res.id,
			url: res.url,
			method: res.method,
			requestHeaders: {},
			sendTime: res.time,
			bodySize: 0
		};

		res.headers.forEach(function(header) {
			entry.requestHeaders[header.name] = header.value;
		});

		parseEntryUrl(entry);

		if (!entry.isBase64) {
			phantomas.emit('send', entry, res);
		}
	});

	phantomas.on('onResourceReceived', function(res) {
		// current request data
		var entry = requests[res.id];

		switch(res.stage) {
			// the beginning of response
			case 'start':
				entry.recvStartTime = res.time;
				entry.timeToFirstByte = res.time - entry.sendTime;

				// FIXME: buggy
				// @see http://code.google.com/p/phantomjs/issues/detail?id=169
				entry.bodySize += res.bodySize || 0;
				break;

			// the end of response
			case 'end':
				// timing
				entry.recvEndTime = res.time;
				entry.timeToLastByte = res.time - entry.sendTime;
				entry.receiveTime = entry.recvEndTime - entry.recvStartTime;

				// request method
				switch(entry.method) {
					case 'POST':
						phantomas.incrMetric('postRequests');
						break;
				}

				// HTTP code
				entry.status = res.status || 200 /* for base64 data */;
				entry.statusText = HTTP_STATUS_CODES[entry.status];

				switch(entry.status) {
					case 301:
					case 302:
						phantomas.incrMetric('redirects');
						phantomas.addNotice(entry.url + ' is a redirect (HTTP ' + entry.status + ')');
						break;

					case 404:
						phantomas.incrMetric('notFound');
						phantomas.addNotice(entry.url + ' was not found (HTTP 404)');
						break;
				}

				parseEntryUrl(entry);

				// asset type
				entry.type = 'other';

				// analyze HTTP headers
				entry.headers = {};
				res.headers.forEach(function(header) {
					entry.headers[header.name] = header.value;

					switch (header.name.toLowerCase()) {
						// TODO: why it's not gzipped?
						// because: http://code.google.com/p/phantomjs/issues/detail?id=156
						// should equal bodySize
						case 'content-length':
							entry.contentLength = parseInt(header.value, 10);
							break;

						// detect content type
						case 'content-type':
							// parse header value
							var value = header.value.split(';').shift().toLowerCase();

							switch(value) {
								case 'text/html':
									entry.type = 'html';
									entry.isHTML = true;
									break;

								case 'text/css':
									entry.type = 'css';
									entry.isCSS = true;
									break;

								case 'application/x-javascript':
								case 'application/javascript':
								case 'text/javascript':
									entry.type = 'js';
									entry.isJS = true;
									break;

								case 'image/png':
								case 'image/jpeg':
								case 'image/gif':
									entry.type = 'image';
									entry.isImage = true;
									break;

								default:
									phantomas.addNotice('Unknown content type found: ' + value);
							}

						// detect content encoding
						case 'content-encoding':
							if (header.value === 'gzip') {
								entry.gzip = true;
							}
							break;
					}
				});

				// requests stats
				if (!entry.isBase64) {
					phantomas.incrMetric('requests');

					phantomas.incrMetric('bodySize', entry.bodySize); // content only
					phantomas.incrMetric('contentLength', entry.contentLength || entry.bodySize); // content only
				}

				if (entry.gzip) {
					phantomas.incrMetric('gzipRequests');
				}

				// emit an event for other modules
				phantomas.emit(entry.isBase64 ? 'base64recv' : 'recv' , entry, res);
				//phantomas.log(entry);
				break;
		}
	});

	// TTFB / TTLB metrics
	phantomas.on('recv', function(entry, res) {
		// check the first request
		if (entry.id === 1) {
			phantomas.setMetric('timeToFirstByte', entry.timeToFirstByte);
			phantomas.setMetric('timeToLastByte', entry.timeToLastByte);
		}

		// completion of the last HTTP request
		phantomas.setMetric('httpTrafficCompleted', entry.recvEndTime - start);
	});
};
<commit_msg>requestsMonitor: add missing break<commit_after>/**
 * Simple HTTP requests monitor and analyzer
 */
exports.version = '1.1';

exports.module = function(phantomas) {
	// imports
	var HTTP_STATUS_CODES = phantomas.require('http').STATUS_CODES,
		parseUrl = phantomas.require('url').parse;

	var requests = [];

	// register metric
	phantomas.setMetric('requests');
	phantomas.setMetric('gzipRequests');
	phantomas.setMetric('postRequests');
	phantomas.setMetric('redirects');
	phantomas.setMetric('notFound');
	phantomas.setMetric('timeToFirstByte');
	phantomas.setMetric('timeToLastByte');
	phantomas.setMetric('bodySize'); // content only
	phantomas.setMetric('contentLength'); // content only

	// parse given URL to get protocol and domain
	function parseEntryUrl(entry) {
		var parsed;

		if (entry.url.indexOf('data:') !== 0) {
			// @see http://nodejs.org/api/url.html#url_url
			parsed = parseUrl(entry.url) || {};

			entry.protocol = parsed.protocol.replace(':', '');
			entry.domain = parsed.hostname;
			entry.query = parsed.query;

			if (entry.protocol === 'https') {
				entry.isSSL = true;
			}
		}
		else {
			// base64 encoded data
			entry.domain = false;
			entry.protocol = false;
			entry.isBase64 = true;
		}
	}

	// when the monitoring started?
	var start;
	phantomas.on('pageOpen', function(res) {
		start = Date.now();
	});

	phantomas.on('onResourceRequested', function(res) {
		// store current request data
		var entry = requests[res.id] = {
			id: res.id,
			url: res.url,
			method: res.method,
			requestHeaders: {},
			sendTime: res.time,
			bodySize: 0
		};

		res.headers.forEach(function(header) {
			entry.requestHeaders[header.name] = header.value;
		});

		parseEntryUrl(entry);

		if (!entry.isBase64) {
			phantomas.emit('send', entry, res);
		}
	});

	phantomas.on('onResourceReceived', function(res) {
		// current request data
		var entry = requests[res.id];

		switch(res.stage) {
			// the beginning of response
			case 'start':
				entry.recvStartTime = res.time;
				entry.timeToFirstByte = res.time - entry.sendTime;

				// FIXME: buggy
				// @see http://code.google.com/p/phantomjs/issues/detail?id=169
				entry.bodySize += res.bodySize || 0;
				break;

			// the end of response
			case 'end':
				// timing
				entry.recvEndTime = res.time;
				entry.timeToLastByte = res.time - entry.sendTime;
				entry.receiveTime = entry.recvEndTime - entry.recvStartTime;

				// request method
				switch(entry.method) {
					case 'POST':
						phantomas.incrMetric('postRequests');
						break;
				}

				// HTTP code
				entry.status = res.status || 200 /* for base64 data */;
				entry.statusText = HTTP_STATUS_CODES[entry.status];

				switch(entry.status) {
					case 301:
					case 302:
						phantomas.incrMetric('redirects');
						phantomas.addNotice(entry.url + ' is a redirect (HTTP ' + entry.status + ')');
						break;

					case 404:
						phantomas.incrMetric('notFound');
						phantomas.addNotice(entry.url + ' was not found (HTTP 404)');
						break;
				}

				parseEntryUrl(entry);

				// asset type
				entry.type = 'other';

				// analyze HTTP headers
				entry.headers = {};
				res.headers.forEach(function(header) {
					entry.headers[header.name] = header.value;

					switch (header.name.toLowerCase()) {
						// TODO: why it's not gzipped?
						// because: http://code.google.com/p/phantomjs/issues/detail?id=156
						// should equal bodySize
						case 'content-length':
							entry.contentLength = parseInt(header.value, 10);
							break;

						// detect content type
						case 'content-type':
							// parse header value
							var value = header.value.split(';').shift().toLowerCase();

							switch(value) {
								case 'text/html':
									entry.type = 'html';
									entry.isHTML = true;
									break;

								case 'text/css':
									entry.type = 'css';
									entry.isCSS = true;
									break;

								case 'application/x-javascript':
								case 'application/javascript':
								case 'text/javascript':
									entry.type = 'js';
									entry.isJS = true;
									break;

								case 'image/png':
								case 'image/jpeg':
								case 'image/gif':
									entry.type = 'image';
									entry.isImage = true;
									break;

								default:
									phantomas.addNotice('Unknown content type found: ' + value);
							}
							break;

						// detect content encoding
						case 'content-encoding':
							if (header.value === 'gzip') {
								entry.gzip = true;
							}
							break;
					}
				});

				// requests stats
				if (!entry.isBase64) {
					phantomas.incrMetric('requests');

					phantomas.incrMetric('bodySize', entry.bodySize); // content only
					phantomas.incrMetric('contentLength', entry.contentLength || entry.bodySize); // content only
				}

				if (entry.gzip) {
					phantomas.incrMetric('gzipRequests');
				}

				// emit an event for other modules
				phantomas.emit(entry.isBase64 ? 'base64recv' : 'recv' , entry, res);
				//phantomas.log(entry);
				break;
		}
	});

	// TTFB / TTLB metrics
	phantomas.on('recv', function(entry, res) {
		// check the first request
		if (entry.id === 1) {
			phantomas.setMetric('timeToFirstByte', entry.timeToFirstByte);
			phantomas.setMetric('timeToLastByte', entry.timeToLastByte);
		}

		// completion of the last HTTP request
		phantomas.setMetric('httpTrafficCompleted', entry.recvEndTime - start);
	});
};
<|endoftext|>


<commit_before>/*global $*/

(function () {
	'use strict';

	console.log(111);
	document.addEventListener("DOMContentLoaded", function() {
		var head = $('head').html().
			replace('<script type="text/javascript" src="main17obf.js"></script>', '<script type="text/plain" src="https://raw.githubusercontent.com/richirm/agarz/master/src/app/agarz.main.js"></script>'),
			body = $('body').html();

		$('head >, body >').remove();

		$('body').append(body);
		$('head').append(head);
	}, false);

}());<commit_msg>cambios<commit_after>/*global $*/

(function () {
	'use strict';

	console.log(111);
	document.addEventListener("DOMContentLoaded", function() {
		console.log(window.onkeydown);
		var head = $('head').html().
			replace('<script type="text/javascript" src="main17obf.js"></script>', '<script type="text/plain" src="https://raw.githubusercontent.com/richirm/agarz/master/src/app/agarz.main.js"></script>'),
			body = $('body').html();

		$('head >, body >').remove();

		$('body').append(body);
		$('head').append(head);
	}, false);

}());<|endoftext|>


<commit_before>/**
 * Copyright 2004 - 2005 uitags
 *
 * 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.
 */

//////////////////////////////////////
////////// Class Definition //////////
//////////////////////////////////////

// @param domObjects either an array or a browser's native collection.
function uiHtml_Group(domObjects, optHandler) {
  this._super();
  this.__items = domObjects;
  this.__handler = optHandler;

  // (ctoohey) used to distinguish uiHtml_Select from uiHtml_Group when returned by uiHtml_Group.createByEither
  this.__type = "group";

  if (this.__handler == null) {
    // NOTE: in order for this to work, the collection should contain
    //       at least one item
    var firstItem = domObjects[0];
    if (firstItem == null) {
      // this violation could happen if a select does not contain any option
      throw new uiUtil_IllegalStateException(
          "A group should contain at least one item.");
    }

    // NOTE: list sometimes contains a lot of items, in which case it is
    //       highly inefficient to create objects for wrapping each,
    //       therefore it is better to get a handler for all of them
    //
    // assume that the rest of the elements are of the same type
    this.__handler = uiHtml_Group.__getWrapper(firstItem);
  }
}

uiHtml_Group = uiUtil_Object.declareClass(uiHtml_Group, uiUtil_Object);

////////////////////////////////////////
////////// Non-static Methods //////////
////////////////////////////////////////

uiHtml_Group.prototype.appendEventHandler = function(event, handler) {
  for (var i = 0; i < this.__items.length; ++i) {
    this.__handler.appendEventHandler(this.__items[i], event, handler);
  }
};

uiHtml_Group.prototype.executeAggregateEventHandler = function(event, optDomEvent) {
  for (var i = 0; i < this.__items.length; ++i) {
    this.__handler.executeAggregateEventHandler(this.__items[i], event, optDomEvent);
  }
};

uiHtml_Group.prototype.__constructItemArgs = function(item, args) {
  var argArray = new Array();
  var outputIndex = 0;
  argArray[outputIndex++] = item;

  var start = args.callee.length - 1;
  for (var i = start; i < args.length; ++i) {
    argArray[outputIndex++] = args[i];
  }
  return argArray;
};

uiHtml_Group.prototype.traverse = function(
    handlerOwner, handlerFunction, optArgN) {
  var argArray = this.__constructItemArgs(null, arguments);

  for (var i = 0; i < this.__items.length; ++i) {
    argArray[0] = this.__items[i];
    handlerFunction.apply(handlerOwner, argArray);
  }
};

uiHtml_Group.prototype.getItemHandler = function() {
  return this.__handler;
};

uiHtml_Group.prototype.size = function() {
  return this.__items.length;
};

uiHtml_Group.prototype.getItemAt = function(index) {
  return this.__items[index];
};

uiHtml_Group.prototype.setItemAt = function(index, item) {
  this.__items[index] = item;
};

uiHtml_Group.prototype.addItem = function(item) {
  throw new Exception("Operation not supported by super class. " +
      "This is an optional operation of the subclass.");
};

// Returns an array of items in the group.
uiHtml_Group.prototype._getItems = function() {
  return this.__items;
};

uiHtml_Group.prototype.hasValue = function(value) {
  for (var i = 0; i < this.__items.length; ++i) {
    if (this.__handler.getLogicalValue(this.__items[i]) == value) {
      return true;
    }
  }

  return false;
};

// author:ctoohey
// observe and ignore child tags matching their forValue is done via
// a regular expression match
uiHtml_Group.prototype.hasRegExpValue = function(forValue) {
  var forValueRegExp = new RegExp(forValue);
  // note: the __items array contains multiple items for selectboxes and
  //       radiobutton groups, but for all other types of element this array
  //       just contains a single widget
  // note: the forValue=null situation has already been handled in Rule._holds,
  //       so know that forValue is not null at this point, meaning that if
  //       this group represents selectible widgets (i.e. select options,
  //       radio buttons, checkboxes) that at least one of them is selected.
  //       thus, must iterate thru all of the selectible items to make sure none
  //       of them matches before returning false, but as soon as there is a match,
  //       return true.
  for (var i = 0; i < this.__items.length; ++i) {
    var logicalValue = this.__handler.getLogicalValue(this.__items[i]);
    if (logicalValue != null && logicalValue.match(forValueRegExp)) {
      return true;
    }
  }

  return false;
};

uiHtml_Group.prototype.getValues = function() {
  var values = new Array();
  for (var i = 0; i < this.__items.length; ++i) {
    var value = this.__handler.getLogicalValue(this.__items[i]);
    if (value != null) {
      values.push(value);
    }
  }

  return values;
};

uiHtml_Group.prototype.handleItemAtIndex = function(
    index, owner, handler, optArgN) {
  var argArray = this.__constructItemArgs(this.__items[index], arguments);
  return handler.apply(owner, argArray);
};

uiHtml_Group.prototype.handleItemWithValue = function(
    value, owner, handler, optArgN) {
  for (var i = 0; i < this.__items.length; ++i) {
    if (this.__items[i].value == value) {
      var argArray = this.__constructItemArgs(this.__items[i], arguments);
      return handler.apply(owner, argArray);
    }
  }
};

////////////////////////////////////
////////// Static Methods //////////
////////////////////////////////////

// Returns either a browser's native collection of multiple dom objects
// or an array of objects, thus allowing either to be accessed in a
// similar manner.
// The browser specific collection doesn't get converted to array, since
// it could impose big performance impact.
uiHtml_Group.__getDomObjectsByEither = function(id, name) {
  var domObjects;
  var domObject = uiHtml_Document.getInstance().getDomObjectById(id, false);
  if (domObject == null) {
    // either id was not specified, or must be name of a radio button group, need to use
    // getDomObjectsByName (all radio buttons have the same name)
    if (name == null || name.length == 0) {
      // special handling for LavaWeb component handler elementId which represents radio button group
      // need to construct the element name for the radio button group, which is of the format:
      // "component['COMPONENT_NAME'].PROPERTY_NAME

      // parse out component name from id
      var endComponent = id.indexOf("_");
      var component = id.substring(0, endComponent);
      // parse out property name from id
      var property = id.substring(endComponent + 1);

      name = "components['" + component + "']." + property;
    }
    domObjects = uiHtml_Document.getInstance().getDomObjectsByName(name, false);
  }
  else {
    domObjects = new Array(domObject);
  }

  // note that getElementsByName() always return a collection, so
  // it's best to check for the first item in the collection
  if (domObjects[0] == null) {
    throw new uiUtil_IllegalArgumentException(
        "Invalid element ID: " + id + " and name: " + name);
  }
  return domObjects;
};

uiHtml_Group.createByEither = function(id, name) {
  // if both id and name are specified, first the id is used to attempt to locate the
  //  HTML element, and if not found, then the name is used
  // if no component is specified in the tag and elementId is specifed, id is equal to
  //  elementId
  // if a component and elementId are specified in the tag, is component_elementId, e.g.
  // e.g. if elementId="noChgImp" component="instrument", then id="instrument_noChgImp"
  // if elementName is specifed in the tag, name is equal to elementName, and component
  //  is ignored
  var domObjects = uiHtml_Group.__getDomObjectsByEither(id, name);

  try {
    // it's not possible to have multiple select boxes with the same name
    // so we assume that 'obj' would never be an array of 'select'
    if (uiHtml_Element.getWidgetType(domObjects[0]) == "select") {
      return new uiHtml_Select(domObjects[0]);
    }
    else {
      return new uiHtml_Group(domObjects);
    }
  }
  catch (e) {
    // provide more detailed info
    if (e instanceof uiUtil_Exception) {
      throw new uiUtil_CreateException("[" + name + "] " + e.getMessage());
    }
  }
};

uiHtml_Group.__getWrapper = function(domWidget) {
  switch(uiHtml_Element.getWidgetType(domWidget)) {
    case "checkbox" :
        return uiHtml_CheckBoxWrapper.getInstance();
    case "radio"    :
        return uiHtml_RadioWrapper.getInstance();
    default         :
        return uiHtml_ElementWrapper.getInstance();
  }
};

<commit_msg>comment only<commit_after>/**
 * Copyright 2004 - 2005 uitags
 *
 * 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.
 */

//////////////////////////////////////
////////// Class Definition //////////
//////////////////////////////////////

// @param domObjects either an array or a browser's native collection.
function uiHtml_Group(domObjects, optHandler) {
  this._super();
  this.__items = domObjects;
  this.__handler = optHandler;

  // (ctoohey) used to distinguish uiHtml_Select from uiHtml_Group when returned by uiHtml_Group.createByEither
  this.__type = "group";

  if (this.__handler == null) {
    // NOTE: in order for this to work, the collection should contain
    //       at least one item
    var firstItem = domObjects[0];
    if (firstItem == null) {
      // this violation could happen if a select does not contain any option
      throw new uiUtil_IllegalStateException(
          "A group should contain at least one item.");
    }

    // NOTE: list sometimes contains a lot of items, in which case it is
    //       highly inefficient to create objects for wrapping each,
    //       therefore it is better to get a handler for all of them
    //
    // assume that the rest of the elements are of the same type
    this.__handler = uiHtml_Group.__getWrapper(firstItem);
  }
}

uiHtml_Group = uiUtil_Object.declareClass(uiHtml_Group, uiUtil_Object);

////////////////////////////////////////
////////// Non-static Methods //////////
////////////////////////////////////////

uiHtml_Group.prototype.appendEventHandler = function(event, handler) {
  for (var i = 0; i < this.__items.length; ++i) {
    this.__handler.appendEventHandler(this.__items[i], event, handler);
  }
};

uiHtml_Group.prototype.executeAggregateEventHandler = function(event, optDomEvent) {
  for (var i = 0; i < this.__items.length; ++i) {
    this.__handler.executeAggregateEventHandler(this.__items[i], event, optDomEvent);
  }
};

uiHtml_Group.prototype.__constructItemArgs = function(item, args) {
  var argArray = new Array();
  var outputIndex = 0;
  argArray[outputIndex++] = item;

  var start = args.callee.length - 1;
  for (var i = start; i < args.length; ++i) {
    argArray[outputIndex++] = args[i];
  }
  return argArray;
};

uiHtml_Group.prototype.traverse = function(
    handlerOwner, handlerFunction, optArgN) {
  var argArray = this.__constructItemArgs(null, arguments);

  for (var i = 0; i < this.__items.length; ++i) {
    argArray[0] = this.__items[i];
    handlerFunction.apply(handlerOwner, argArray);
  }
};

uiHtml_Group.prototype.getItemHandler = function() {
  return this.__handler;
};

uiHtml_Group.prototype.size = function() {
  return this.__items.length;
};

uiHtml_Group.prototype.getItemAt = function(index) {
  return this.__items[index];
};

uiHtml_Group.prototype.setItemAt = function(index, item) {
  this.__items[index] = item;
};

uiHtml_Group.prototype.addItem = function(item) {
  throw new Exception("Operation not supported by super class. " +
      "This is an optional operation of the subclass.");
};

// Returns an array of items in the group.
uiHtml_Group.prototype._getItems = function() {
  return this.__items;
};

uiHtml_Group.prototype.hasValue = function(value) {
  for (var i = 0; i < this.__items.length; ++i) {
    if (this.__handler.getLogicalValue(this.__items[i]) == value) {
      return true;
    }
  }

  return false;
};

// author:ctoohey
// observe and ignore child tags matching their forValue is done via
// a regular expression match
uiHtml_Group.prototype.hasRegExpValue = function(forValue) {
  var forValueRegExp = new RegExp(forValue);
  // note: the __items array contains multiple items for selectboxes and
  //       radiobutton groups, but for all other types of element this array
  //       just contains a single widget
  // note: the forValue=null (e.g. when observeForNull tag is used) situation has
  //       already been handled in Rule._holds,
  //       so know that forValue is not null at this point, meaning that if
  //       this group represents selectible widgets (i.e. select options,
  //       radio buttons, checkboxes) that at least one of them is selected.
  //       thus, must iterate thru all of the selectible items to make sure none
  //       of them matches before returning false, but as soon as there is a match,
  //       return true.
  for (var i = 0; i < this.__items.length; ++i) {
    var logicalValue = this.__handler.getLogicalValue(this.__items[i]);
    if (logicalValue != null && logicalValue.match(forValueRegExp)) {
      return true;
    }
  }

  return false;
};

uiHtml_Group.prototype.getValues = function() {
  var values = new Array();
  for (var i = 0; i < this.__items.length; ++i) {
    var value = this.__handler.getLogicalValue(this.__items[i]);
    if (value != null) {
      values.push(value);
    }
  }

  return values;
};

uiHtml_Group.prototype.handleItemAtIndex = function(
    index, owner, handler, optArgN) {
  var argArray = this.__constructItemArgs(this.__items[index], arguments);
  return handler.apply(owner, argArray);
};

uiHtml_Group.prototype.handleItemWithValue = function(
    value, owner, handler, optArgN) {
  for (var i = 0; i < this.__items.length; ++i) {
    if (this.__items[i].value == value) {
      var argArray = this.__constructItemArgs(this.__items[i], arguments);
      return handler.apply(owner, argArray);
    }
  }
};

////////////////////////////////////
////////// Static Methods //////////
////////////////////////////////////

// Returns either a browser's native collection of multiple dom objects
// or an array of objects, thus allowing either to be accessed in a
// similar manner.
// The browser specific collection doesn't get converted to array, since
// it could impose big performance impact.
uiHtml_Group.__getDomObjectsByEither = function(id, name) {
  var domObjects;
  var domObject = uiHtml_Document.getInstance().getDomObjectById(id, false);
  if (domObject == null) {
    // either id was not specified, or must be name of a radio button group, need to use
    // getDomObjectsByName (all radio buttons have the same name)
    if (name == null || name.length == 0) {
      // special handling for LavaWeb component handler elementId which represents radio button group
      // need to construct the element name for the radio button group, which is of the format:
      // "component['COMPONENT_NAME'].PROPERTY_NAME

      // parse out component name from id
      var endComponent = id.indexOf("_");
      var component = id.substring(0, endComponent);
      // parse out property name from id
      var property = id.substring(endComponent + 1);

      name = "components['" + component + "']." + property;
    }
    domObjects = uiHtml_Document.getInstance().getDomObjectsByName(name, false);
  }
  else {
    domObjects = new Array(domObject);
  }

  // note that getElementsByName() always return a collection, so
  // it's best to check for the first item in the collection
  if (domObjects[0] == null) {
    throw new uiUtil_IllegalArgumentException(
        "Invalid element ID: " + id + " and name: " + name);
  }
  return domObjects;
};

uiHtml_Group.createByEither = function(id, name) {
  // if both id and name are specified, first the id is used to attempt to locate the
  //  HTML element, and if not found, then the name is used
  // if no component is specified in the tag and elementId is specifed, id is equal to
  //  elementId
  // if a component and elementId are specified in the tag, is component_elementId, e.g.
  // e.g. if elementId="noChgImp" component="instrument", then id="instrument_noChgImp"
  // if elementName is specifed in the tag, name is equal to elementName, and component
  //  is ignored
  var domObjects = uiHtml_Group.__getDomObjectsByEither(id, name);

  try {
    // it's not possible to have multiple select boxes with the same name
    // so we assume that 'obj' would never be an array of 'select'
    if (uiHtml_Element.getWidgetType(domObjects[0]) == "select") {
      return new uiHtml_Select(domObjects[0]);
    }
    else {
      return new uiHtml_Group(domObjects);
    }
  }
  catch (e) {
    // provide more detailed info
    if (e instanceof uiUtil_Exception) {
      throw new uiUtil_CreateException("[" + name + "] " + e.getMessage());
    }
  }
};

uiHtml_Group.__getWrapper = function(domWidget) {
  switch(uiHtml_Element.getWidgetType(domWidget)) {
    case "checkbox" :
        return uiHtml_CheckBoxWrapper.getInstance();
    case "radio"    :
        return uiHtml_RadioWrapper.getInstance();
    default         :
        return uiHtml_ElementWrapper.getInstance();
  }
};

<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/**
 * The controller for the home page.
 */
angular.module('home').controller('homeController', ['$scope', '$injector',
        function homeController($scope, $injector) {

    // Get required types
    var ConnectionGroup  = $injector.get('ConnectionGroup');
    var ClientIdentifier = $injector.get('ClientIdentifier');
    var GroupListItem    = $injector.get('GroupListItem');

    // Get required services
    var authenticationService  = $injector.get('authenticationService');
    var connectionGroupService = $injector.get('connectionGroupService');
    var dataSourceService      = $injector.get('dataSourceService');
    var requestService         = $injector.get('requestService');

    /**
     * Map of data source identifier to the root connection group of that data
     * source, or null if the connection group hierarchy has not yet been
     * loaded.
     *
     * @type Object.<String, ConnectionGroup>
     */
    $scope.rootConnectionGroups = null;

    /**
     * Array of all connection properties that are filterable.
     *
     * @type String[]
     */
    $scope.filteredConnectionProperties = [
        'name'
    ];

    /**
     * Array of all connection group properties that are filterable.
     *
     * @type String[]
     */
    $scope.filteredConnectionGroupProperties = [
        'name'
    ];

    /**
     * Returns whether critical data has completed being loaded.
     *
     * @returns {Boolean}
     *     true if enough data has been loaded for the user interface to be
     *     useful, false otherwise.
     */
    $scope.isLoaded = function isLoaded() {

        return $scope.rootConnectionGroup !== null;

    };

    /**
     * Object passed to the guacGroupList directive, providing context-specific
     * functions or data.
     */
    $scope.context = {

        /**
         * Returns the unique string identifier which must be used when
         * connecting to a connection or connection group represented by the
         * given GroupListItem.
         *
         * @param {GroupListItem} item
         *     The GroupListItem to determine the client identifier of.
         *
         * @returns {String}
         *     The client identifier associated with the connection or
         *     connection group represented by the given GroupListItem, or null
         *     if the GroupListItem cannot have an associated client
         *     identifier.
         */
        getClientIdentifier : function getClientIdentifier(item) {

            // If the item is a connection, generate a connection identifier
            if (item.type === GroupListItem.Type.CONNECTION)
                return ClientIdentifier.toString({
                    dataSource : item.dataSource,
                    type       : ClientIdentifier.Types.CONNECTION,
                    id         : item.identifier
                });

            // If the item is a connection group, generate a connection group identifier
            if (item.type === GroupListItem.Type.CONNECTION_GROUP)
                return ClientIdentifier.toString({
                    dataSource : item.dataSource,
                    type       : ClientIdentifier.Types.CONNECTION_GROUP,
                    id         : item.identifier
                });

            // Otherwise, no such identifier can exist
            return null;

        }

    };

    // Retrieve root groups and all descendants
    dataSourceService.apply(
        connectionGroupService.getConnectionGroupTree,
        authenticationService.getAvailableDataSources(),
        ConnectionGroup.ROOT_IDENTIFIER
    )
    .then(function rootGroupsRetrieved(rootConnectionGroups) {
        $scope.rootConnectionGroups = rootConnectionGroups;
    }, requestService.WARN);

}]);
<commit_msg>GUACAMOLE-571: Merge correction to "rootConnectionGroups" typo in home controller.<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/**
 * The controller for the home page.
 */
angular.module('home').controller('homeController', ['$scope', '$injector',
        function homeController($scope, $injector) {

    // Get required types
    var ConnectionGroup  = $injector.get('ConnectionGroup');
    var ClientIdentifier = $injector.get('ClientIdentifier');
    var GroupListItem    = $injector.get('GroupListItem');

    // Get required services
    var authenticationService  = $injector.get('authenticationService');
    var connectionGroupService = $injector.get('connectionGroupService');
    var dataSourceService      = $injector.get('dataSourceService');
    var requestService         = $injector.get('requestService');

    /**
     * Map of data source identifier to the root connection group of that data
     * source, or null if the connection group hierarchy has not yet been
     * loaded.
     *
     * @type Object.<String, ConnectionGroup>
     */
    $scope.rootConnectionGroups = null;

    /**
     * Array of all connection properties that are filterable.
     *
     * @type String[]
     */
    $scope.filteredConnectionProperties = [
        'name'
    ];

    /**
     * Array of all connection group properties that are filterable.
     *
     * @type String[]
     */
    $scope.filteredConnectionGroupProperties = [
        'name'
    ];

    /**
     * Returns whether critical data has completed being loaded.
     *
     * @returns {Boolean}
     *     true if enough data has been loaded for the user interface to be
     *     useful, false otherwise.
     */
    $scope.isLoaded = function isLoaded() {

        return $scope.rootConnectionGroups !== null;

    };

    /**
     * Object passed to the guacGroupList directive, providing context-specific
     * functions or data.
     */
    $scope.context = {

        /**
         * Returns the unique string identifier which must be used when
         * connecting to a connection or connection group represented by the
         * given GroupListItem.
         *
         * @param {GroupListItem} item
         *     The GroupListItem to determine the client identifier of.
         *
         * @returns {String}
         *     The client identifier associated with the connection or
         *     connection group represented by the given GroupListItem, or null
         *     if the GroupListItem cannot have an associated client
         *     identifier.
         */
        getClientIdentifier : function getClientIdentifier(item) {

            // If the item is a connection, generate a connection identifier
            if (item.type === GroupListItem.Type.CONNECTION)
                return ClientIdentifier.toString({
                    dataSource : item.dataSource,
                    type       : ClientIdentifier.Types.CONNECTION,
                    id         : item.identifier
                });

            // If the item is a connection group, generate a connection group identifier
            if (item.type === GroupListItem.Type.CONNECTION_GROUP)
                return ClientIdentifier.toString({
                    dataSource : item.dataSource,
                    type       : ClientIdentifier.Types.CONNECTION_GROUP,
                    id         : item.identifier
                });

            // Otherwise, no such identifier can exist
            return null;

        }

    };

    // Retrieve root groups and all descendants
    dataSourceService.apply(
        connectionGroupService.getConnectionGroupTree,
        authenticationService.getAvailableDataSources(),
        ConnectionGroup.ROOT_IDENTIFIER
    )
    .then(function rootGroupsRetrieved(rootConnectionGroups) {
        $scope.rootConnectionGroups = rootConnectionGroups;
    }, requestService.WARN);

}]);
<|endoftext|>


<commit_before>var util = require('util');

var APIError = function(name, message, status, requestInfo, originalError){
  this.name = name || this.constructor.name || this.constructor.prototype.name || '';
  this.message = message || '';
  this.statusCode = status || (originalError && originalError.code);
  this.requestInfo = Object.assign({}, requestInfo);
  this.originalError = originalError;

  if (typeof Error.captureStackTrace === 'funciton') {
    Error.captureStackTrace(this, this.constructor);
  }
};

util.inherits(APIError, Error);

module.exports = APIError;
<commit_msg>Fix error stack trace for browsers<commit_after>var util = require('util');

var APIError = function(name, message, status, requestInfo, originalError){
  this.name = name || this.constructor.name || this.constructor.prototype.name || '';
  this.message = message || '';
  this.statusCode = status || (originalError && originalError.code);
  this.requestInfo = Object.assign({}, requestInfo);
  this.originalError = originalError;

  if (typeof Error.captureStackTrace === 'function') {
    Error.captureStackTrace(this, this.constructor);  // Node.js.
  } else {
    this.stack = new Error().stack;  // Browser.
  }
};

util.inherits(APIError, Error);

module.exports = APIError;
<|endoftext|>


<commit_before>const _ = require('lodash');
const Promise = require('bluebird');
const fs = require('fs-extra');
const join = require('path').join;
const errors = require('@tryghost/errors');

const notAPackageRegex = /^\.|_messages|README.md|node_modules|bower_components/i;
const packageJSONPath = 'package.json';

/**
 * @typedef {Object} Ii18n
 * @prop {(key: string) => string} t
 */

/**
 * # Package Utils
 *
 * Ghost has / is in the process of gaining support for several different types of sub-packages:
 * - Themes: have always been packages, but we're going to lean more heavily on npm & package.json in future
 * - Adapters: replace fundamental pieces like storage, will become npm modules
 *
 * These utils facilitate loading, reading, managing etc, packages from the file system.
 *
 */
module.exports = class PackageJson {
    /**
     * Creates an instance of PackageJson, an util used to read and validate package.json files
     * @param {Object} dependencies
     * @param {Ii18n} dependencies.i18n
     */
    constructor({i18n}) {
        this.i18n = i18n;
    }

    /**
     * ### Filter Packages
     * Normalizes packages read by read-packages so that the themes module can use them.
     * Iterates over each package and return an array of objects which are simplified representations of the package
     * with 3 properties:
     * - `name`    - the package name
     * - `package` - contents of the package.json or false if there isn't one
     * - `active`  - set to true if this package is active
     * This data structure is used for listings of packages provided over the API and as such
     * deliberately combines multiple sources of information in order to be efficient.
     *
     * TODO: simplify the package.json representation to contain only fields we use
     *
     * @param   {object}            packages    as returned by read-packages
     * @param   {array/string}      active      as read from the settings object
     * @returns {Array}                         of objects with useful info about themes
     */
    filter(packages, active) {
        // turn active into an array if it isn't one, so this function can deal with lists and one-offs
        if (!Array.isArray(active)) {
            active = [active];
        }

        return _.reduce(packages, function (result, pkg, key) {
            let item = {};
            if (!key.match(notAPackageRegex)) {
                item = {
                    name: key,
                    package: pkg['package.json'] || false,
                    active: _.indexOf(active, key) !== -1
                };

                result.push(item);
            }

            return result;
        }, []);
    }

    /**
     * Parse package.json and validate it has
     * all the required fields
     *
     * @param {string} path
     */
    async parse(path) {
        let source;
        let json;

        try {
            source = await fs.readFile(path);
        } catch (readError) {
            const err = new Error(this.i18n.t('errors.utils.parsepackagejson.couldNotReadPackage'));
            err.context = path;
            err.err = readError;

            return Promise.reject(err);
        }

        try {
            json = JSON.parse(source);
        } catch (parseError) {
            const err = new Error(this.i18n.t('errors.utils.parsepackagejson.themeFileIsMalformed'));
            err.context = path;
            err.err = parseError;
            err.help = this.i18n.t('errors.utils.parsepackagejson.willBeRequired', {url: 'https://ghost.org/docs/themes/'});

            return Promise.reject(err);
        }

        const hasRequiredKeys = json.name && json.version;

        if (!hasRequiredKeys) {
            const err = new Error(this.i18n.t('errors.utils.parsepackagejson.nameOrVersionMissing'));
            err.context = path;
            err.help = this.i18n.t('errors.utils.parsepackagejson.willBeRequired', {url: 'https://ghost.org/docs/themes/'});

            return Promise.reject(err);
        }

        return json;
    }

    /**
     * Recursively read directory and find the packages in it
     *
     * @param {string} absolutePath
     * @param {string} packageName
     * @returns {object}
     */
    async processPackage(absolutePath, packageName) {
        const pkg = {
            name: packageName,
            path: absolutePath
        };

        try {
            const packageJSON = await this.parse(join(absolutePath, packageJSONPath));
            pkg['package.json'] = packageJSON;
        } catch (err) {
            // ignore invalid package.json for now,
            // because Ghost does not rely/use them at the moment
            // in the future, this .catch() will need to be removed,
            // so that error is thrown on invalid json syntax
            pkg['package.json'] = null;
        }

        return pkg;
    }

    /**
     * @param {string} packagePath
     * @param {string} packageName
     */
    async readPackage(packagePath, packageName) {
        const absolutePath = join(packagePath, packageName);

        try {
            const stat = await fs.stat(absolutePath);
            if (!stat.isDirectory()) {
                return {};
            }

            const pkg = await this.processPackage(absolutePath, packageName);
            const res = {};
            res[packageName] = pkg;
            return res;
        } catch (err) {
            return Promise.reject(new errors.NotFoundError({
                message: 'Package not found',
                err: err,
                help: 'path: ' + packagePath,
                context: 'name: ' + packageName
            }));
        }
    }

    /**
     * @param {string} packagePath
     */
    readPackages(packagePath) {
        const self = this;

        return Promise.resolve(fs.readdir(packagePath))
            .filter(function (packageName) {
                // Filter out things which are not packages by regex
                if (packageName.match(notAPackageRegex)) {
                    return;
                }
                // Check the remaining items to ensure they are a directory
                return fs.stat(join(packagePath, packageName)).then(function (stat) {
                    return stat.isDirectory();
                });
            })
            .map(function readPackageJson(packageName) {
                const absolutePath = join(packagePath, packageName);
                return self.processPackage(absolutePath, packageName);
            })
            .then(function (packages) {
                return _.keyBy(packages, 'name');
            });
    }
};
<commit_msg>Changed `Error` to `IncorrectUsageError` in `package-json`<commit_after>const _ = require('lodash');
const Promise = require('bluebird');
const fs = require('fs-extra');
const join = require('path').join;
const errors = require('@tryghost/errors');

const notAPackageRegex = /^\.|_messages|README.md|node_modules|bower_components/i;
const packageJSONPath = 'package.json';

/**
 * @typedef {Object} Ii18n
 * @prop {(key: string) => string} t
 */

/**
 * # Package Utils
 *
 * Ghost has / is in the process of gaining support for several different types of sub-packages:
 * - Themes: have always been packages, but we're going to lean more heavily on npm & package.json in future
 * - Adapters: replace fundamental pieces like storage, will become npm modules
 *
 * These utils facilitate loading, reading, managing etc, packages from the file system.
 *
 */
module.exports = class PackageJson {
    /**
     * Creates an instance of PackageJson, an util used to read and validate package.json files
     * @param {Object} dependencies
     * @param {Ii18n} dependencies.i18n
     */
    constructor({i18n}) {
        this.i18n = i18n;
    }

    /**
     * ### Filter Packages
     * Normalizes packages read by read-packages so that the themes module can use them.
     * Iterates over each package and return an array of objects which are simplified representations of the package
     * with 3 properties:
     * - `name`    - the package name
     * - `package` - contents of the package.json or false if there isn't one
     * - `active`  - set to true if this package is active
     * This data structure is used for listings of packages provided over the API and as such
     * deliberately combines multiple sources of information in order to be efficient.
     *
     * TODO: simplify the package.json representation to contain only fields we use
     *
     * @param   {object}            packages    as returned by read-packages
     * @param   {array/string}      active      as read from the settings object
     * @returns {Array}                         of objects with useful info about themes
     */
    filter(packages, active) {
        // turn active into an array if it isn't one, so this function can deal with lists and one-offs
        if (!Array.isArray(active)) {
            active = [active];
        }

        return _.reduce(packages, function (result, pkg, key) {
            let item = {};
            if (!key.match(notAPackageRegex)) {
                item = {
                    name: key,
                    package: pkg['package.json'] || false,
                    active: _.indexOf(active, key) !== -1
                };

                result.push(item);
            }

            return result;
        }, []);
    }

    /**
     * Parse package.json and validate it has
     * all the required fields
     *
     * @param {string} path
     */
    async parse(path) {
        let source;
        let json;

        try {
            source = await fs.readFile(path);
        } catch (readError) {
            const err = new errors.IncorrectUsageError();
            err.message = this.i18n.t('errors.utils.parsepackagejson.couldNotReadPackage');
            err.context = path;
            err.err = readError;

            return Promise.reject(err);
        }

        try {
            json = JSON.parse(source);
        } catch (parseError) {
            const err = new errors.IncorrectUsageError();
            err.message = this.i18n.t('errors.utils.parsepackagejson.themeFileIsMalformed');
            err.context = path;
            err.err = parseError;
            err.help = this.i18n.t('errors.utils.parsepackagejson.willBeRequired', {url: 'https://ghost.org/docs/themes/'});

            return Promise.reject(err);
        }

        const hasRequiredKeys = json.name && json.version;

        if (!hasRequiredKeys) {
            const err = new errors.IncorrectUsageError();
            err.message = this.i18n.t('errors.utils.parsepackagejson.nameOrVersionMissing');
            err.context = path;
            err.help = this.i18n.t('errors.utils.parsepackagejson.willBeRequired', {url: 'https://ghost.org/docs/themes/'});

            return Promise.reject(err);
        }

        return json;
    }

    /**
     * Recursively read directory and find the packages in it
     *
     * @param {string} absolutePath
     * @param {string} packageName
     * @returns {object}
     */
    async processPackage(absolutePath, packageName) {
        const pkg = {
            name: packageName,
            path: absolutePath
        };

        try {
            const packageJSON = await this.parse(join(absolutePath, packageJSONPath));
            pkg['package.json'] = packageJSON;
        } catch (err) {
            // ignore invalid package.json for now,
            // because Ghost does not rely/use them at the moment
            // in the future, this .catch() will need to be removed,
            // so that error is thrown on invalid json syntax
            pkg['package.json'] = null;
        }

        return pkg;
    }

    /**
     * @param {string} packagePath
     * @param {string} packageName
     */
    async readPackage(packagePath, packageName) {
        const absolutePath = join(packagePath, packageName);

        try {
            const stat = await fs.stat(absolutePath);
            if (!stat.isDirectory()) {
                return {};
            }

            const pkg = await this.processPackage(absolutePath, packageName);
            const res = {};
            res[packageName] = pkg;
            return res;
        } catch (err) {
            return Promise.reject(new errors.NotFoundError({
                message: 'Package not found',
                err: err,
                help: 'path: ' + packagePath,
                context: 'name: ' + packageName
            }));
        }
    }

    /**
     * @param {string} packagePath
     */
    readPackages(packagePath) {
        const self = this;

        return Promise.resolve(fs.readdir(packagePath))
            .filter(function (packageName) {
                // Filter out things which are not packages by regex
                if (packageName.match(notAPackageRegex)) {
                    return;
                }
                // Check the remaining items to ensure they are a directory
                return fs.stat(join(packagePath, packageName)).then(function (stat) {
                    return stat.isDirectory();
                });
            })
            .map(function readPackageJson(packageName) {
                const absolutePath = join(packagePath, packageName);
                return self.processPackage(absolutePath, packageName);
            })
            .then(function (packages) {
                return _.keyBy(packages, 'name');
            });
    }
};
<|endoftext|>


<commit_before>/* Copyright 2018 Mozilla Foundation
 *
 * 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.
 */

const compatibilityParams = Object.create(null);
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
  const userAgent =
    (typeof navigator !== "undefined" && navigator.userAgent) || "";
  const platform =
    (typeof navigator !== "undefined" && navigator.platform) || "";
  const maxTouchPoints =
    (typeof navigator !== "undefined" && navigator.maxTouchPoints) || 1;

  const isAndroid = /Android/.test(userAgent);
  const isIOS =
    /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) ||
    (platform === "MacIntel" && maxTouchPoints > 1);
  const isIOSChrome = /CriOS/.test(userAgent);

  // Disables URL.createObjectURL() usage in some environments.
  // Support: Chrome on iOS
  (function checkOnBlobSupport() {
    // Sometimes Chrome on iOS loses data created with createObjectURL(),
    // see issue 8081.
    if (isIOSChrome) {
      compatibilityParams.disableCreateObjectURL = true;
    }
  })();

  // Limit canvas size to 5 mega-pixels on mobile.
  // Support: Android, iOS
  (function checkCanvasSizeLimitation() {
    if (isIOS || isAndroid) {
      compatibilityParams.maxCanvasPixels = 5242880;
    }
  })();
}

const OptionKind = {
  VIEWER: 0x02,
  API: 0x04,
  WORKER: 0x08,
  PREFERENCE: 0x80,
};

/**
 * PLEASE NOTE: To avoid introducing unnecessary dependencies, we specify the
 *              values below *explicitly* rather than relying on imported types.
 */
const defaultOptions = {
  cursorToolOnLoad: {
    /** @type {number} */
    value: 0,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  defaultUrl: {
    /** @type {string} */
    value: "compressed.tracemonkey-pldi-09.pdf",
    kind: OptionKind.VIEWER,
  },
  defaultZoomValue: {
    /** @type {string} */
    value: "",
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  disableHistory: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.VIEWER,
  },
  disablePageLabels: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  enablePermissions: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  enablePrintAutoRotate: {
    /** @type {boolean} */
    value: true,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  enableScripting: {
    /** @type {boolean} */
    value: true,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  externalLinkRel: {
    /** @type {string} */
    value: "noopener noreferrer nofollow",
    kind: OptionKind.VIEWER,
  },
  externalLinkTarget: {
    /** @type {number} */
    value: 0,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  historyUpdateUrl: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  ignoreDestinationZoom: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  imageResourcesPath: {
    /** @type {string} */
    value: "./images/",
    kind: OptionKind.VIEWER,
  },
  maxCanvasPixels: {
    /** @type {number} */
    value: 16777216,
    compatibility: compatibilityParams.maxCanvasPixels,
    kind: OptionKind.VIEWER,
  },
  pdfBugEnabled: {
    /** @type {boolean} */
    value: typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION"),
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  printResolution: {
    /** @type {number} */
    value: 150,
    kind: OptionKind.VIEWER,
  },
  renderer: {
    /** @type {string} */
    value: "canvas",
    kind: OptionKind.VIEWER,
  },
  renderInteractiveForms: {
    /** @type {boolean} */
    value: true,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  sidebarViewOnLoad: {
    /** @type {number} */
    value: -1,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  scrollModeOnLoad: {
    /** @type {number} */
    value: -1,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  spreadModeOnLoad: {
    /** @type {number} */
    value: -1,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  textLayerMode: {
    /** @type {number} */
    value: 1,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  useOnlyCssZoom: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  viewerCssTheme: {
    /** @type {number} */
    value: typeof PDFJSDev !== "undefined" && PDFJSDev.test("CHROME") ? 2 : 0,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  viewOnLoad: {
    /** @type {boolean} */
    value: 0,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },

  cMapPacked: {
    /** @type {boolean} */
    value: true,
    kind: OptionKind.API,
  },
  cMapUrl: {
    /** @type {string} */
    value:
      typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")
        ? "../external/bcmaps/"
        : "../web/cmaps/",
    kind: OptionKind.API,
  },
  disableAutoFetch: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.API + OptionKind.PREFERENCE,
  },
  disableFontFace: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.API + OptionKind.PREFERENCE,
  },
  disableRange: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.API + OptionKind.PREFERENCE,
  },
  disableStream: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.API + OptionKind.PREFERENCE,
  },
  docBaseUrl: {
    /** @type {string} */
    value: "",
    kind: OptionKind.API,
  },
  enableXfa: {
    /** @type {boolean} */
    value: typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION"),
    kind: OptionKind.API + OptionKind.PREFERENCE,
  },
  fontExtraProperties: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.API,
  },
  isEvalSupported: {
    /** @type {boolean} */
    value: true,
    kind: OptionKind.API,
  },
  maxImageSize: {
    /** @type {number} */
    value: -1,
    kind: OptionKind.API,
  },
  pdfBug: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.API,
  },
  standardFontDataUrl: {
    /** @type {string} */
    value:
      typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")
        ? "../external/standard_fonts/"
        : "../web/standard_fonts/",
    kind: OptionKind.API,
  },
  verbosity: {
    /** @type {number} */
    value: 1,
    kind: OptionKind.API,
  },

  workerPort: {
    /** @type {Object} */
    value: null,
    kind: OptionKind.WORKER,
  },
  workerSrc: {
    /** @type {string} */
    value:
      typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")
        ? "../src/worker_loader.js"
        : "../build/pdf.worker.js",
    kind: OptionKind.WORKER,
  },
};
if (
  typeof PDFJSDev === "undefined" ||
  PDFJSDev.test("!PRODUCTION || GENERIC")
) {
  defaultOptions.disablePreferences = {
    /** @type {boolean} */
    value: typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING"),
    kind: OptionKind.VIEWER,
  };
  defaultOptions.locale = {
    /** @type {string} */
    value: typeof navigator !== "undefined" ? navigator.language : "en-US",
    kind: OptionKind.VIEWER,
  };
  defaultOptions.sandboxBundleSrc = {
    /** @type {string} */
    value:
      typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")
        ? "../build/dev-sandbox/pdf.sandbox.js"
        : "../build/pdf.sandbox.js",
    kind: OptionKind.VIEWER,
  };

  defaultOptions.renderer.kind += OptionKind.PREFERENCE;
} else if (PDFJSDev.test("CHROME")) {
  defaultOptions.disableTelemetry = {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  };
  defaultOptions.sandboxBundleSrc = {
    /** @type {string} */
    value: "../build/pdf.sandbox.js",
    kind: OptionKind.VIEWER,
  };
}

const userOptions = Object.create(null);

class AppOptions {
  constructor() {
    throw new Error("Cannot initialize AppOptions.");
  }

  static get(name) {
    const userOption = userOptions[name];
    if (userOption !== undefined) {
      return userOption;
    }
    const defaultOption = defaultOptions[name];
    if (defaultOption !== undefined) {
      return defaultOption.compatibility ?? defaultOption.value;
    }
    return undefined;
  }

  static getAll(kind = null) {
    const options = Object.create(null);
    for (const name in defaultOptions) {
      const defaultOption = defaultOptions[name];
      if (kind) {
        if ((kind & defaultOption.kind) === 0) {
          continue;
        }
        if (kind === OptionKind.PREFERENCE) {
          const value = defaultOption.value,
            valueType = typeof value;

          if (
            valueType === "boolean" ||
            valueType === "string" ||
            (valueType === "number" && Number.isInteger(value))
          ) {
            options[name] = value;
            continue;
          }
          throw new Error(`Invalid type for preference: ${name}`);
        }
      }
      const userOption = userOptions[name];
      options[name] =
        userOption !== undefined
          ? userOption
          : defaultOption.compatibility ?? defaultOption.value;
    }
    return options;
  }

  static set(name, value) {
    userOptions[name] = value;
  }

  static setAll(options) {
    for (const name in options) {
      userOptions[name] = options[name];
    }
  }

  static remove(name) {
    delete userOptions[name];
  }
}

export { AppOptions, compatibilityParams, OptionKind };
<commit_msg>When running tests, enable XFA by default in the viewer (PR 13745 follow-up)<commit_after>/* Copyright 2018 Mozilla Foundation
 *
 * 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.
 */

const compatibilityParams = Object.create(null);
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
  const userAgent =
    (typeof navigator !== "undefined" && navigator.userAgent) || "";
  const platform =
    (typeof navigator !== "undefined" && navigator.platform) || "";
  const maxTouchPoints =
    (typeof navigator !== "undefined" && navigator.maxTouchPoints) || 1;

  const isAndroid = /Android/.test(userAgent);
  const isIOS =
    /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) ||
    (platform === "MacIntel" && maxTouchPoints > 1);
  const isIOSChrome = /CriOS/.test(userAgent);

  // Disables URL.createObjectURL() usage in some environments.
  // Support: Chrome on iOS
  (function checkOnBlobSupport() {
    // Sometimes Chrome on iOS loses data created with createObjectURL(),
    // see issue 8081.
    if (isIOSChrome) {
      compatibilityParams.disableCreateObjectURL = true;
    }
  })();

  // Limit canvas size to 5 mega-pixels on mobile.
  // Support: Android, iOS
  (function checkCanvasSizeLimitation() {
    if (isIOS || isAndroid) {
      compatibilityParams.maxCanvasPixels = 5242880;
    }
  })();
}

const OptionKind = {
  VIEWER: 0x02,
  API: 0x04,
  WORKER: 0x08,
  PREFERENCE: 0x80,
};

/**
 * PLEASE NOTE: To avoid introducing unnecessary dependencies, we specify the
 *              values below *explicitly* rather than relying on imported types.
 */
const defaultOptions = {
  cursorToolOnLoad: {
    /** @type {number} */
    value: 0,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  defaultUrl: {
    /** @type {string} */
    value: "compressed.tracemonkey-pldi-09.pdf",
    kind: OptionKind.VIEWER,
  },
  defaultZoomValue: {
    /** @type {string} */
    value: "",
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  disableHistory: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.VIEWER,
  },
  disablePageLabels: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  enablePermissions: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  enablePrintAutoRotate: {
    /** @type {boolean} */
    value: true,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  enableScripting: {
    /** @type {boolean} */
    value: true,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  externalLinkRel: {
    /** @type {string} */
    value: "noopener noreferrer nofollow",
    kind: OptionKind.VIEWER,
  },
  externalLinkTarget: {
    /** @type {number} */
    value: 0,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  historyUpdateUrl: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  ignoreDestinationZoom: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  imageResourcesPath: {
    /** @type {string} */
    value: "./images/",
    kind: OptionKind.VIEWER,
  },
  maxCanvasPixels: {
    /** @type {number} */
    value: 16777216,
    compatibility: compatibilityParams.maxCanvasPixels,
    kind: OptionKind.VIEWER,
  },
  pdfBugEnabled: {
    /** @type {boolean} */
    value: typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION"),
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  printResolution: {
    /** @type {number} */
    value: 150,
    kind: OptionKind.VIEWER,
  },
  renderer: {
    /** @type {string} */
    value: "canvas",
    kind: OptionKind.VIEWER,
  },
  renderInteractiveForms: {
    /** @type {boolean} */
    value: true,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  sidebarViewOnLoad: {
    /** @type {number} */
    value: -1,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  scrollModeOnLoad: {
    /** @type {number} */
    value: -1,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  spreadModeOnLoad: {
    /** @type {number} */
    value: -1,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  textLayerMode: {
    /** @type {number} */
    value: 1,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  useOnlyCssZoom: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  viewerCssTheme: {
    /** @type {number} */
    value: typeof PDFJSDev !== "undefined" && PDFJSDev.test("CHROME") ? 2 : 0,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },
  viewOnLoad: {
    /** @type {boolean} */
    value: 0,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  },

  cMapPacked: {
    /** @type {boolean} */
    value: true,
    kind: OptionKind.API,
  },
  cMapUrl: {
    /** @type {string} */
    value:
      typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")
        ? "../external/bcmaps/"
        : "../web/cmaps/",
    kind: OptionKind.API,
  },
  disableAutoFetch: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.API + OptionKind.PREFERENCE,
  },
  disableFontFace: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.API + OptionKind.PREFERENCE,
  },
  disableRange: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.API + OptionKind.PREFERENCE,
  },
  disableStream: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.API + OptionKind.PREFERENCE,
  },
  docBaseUrl: {
    /** @type {string} */
    value: "",
    kind: OptionKind.API,
  },
  enableXfa: {
    /** @type {boolean} */
    value:
      typeof PDFJSDev === "undefined" ||
      PDFJSDev.test("!PRODUCTION || TESTING"),
    kind: OptionKind.API + OptionKind.PREFERENCE,
  },
  fontExtraProperties: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.API,
  },
  isEvalSupported: {
    /** @type {boolean} */
    value: true,
    kind: OptionKind.API,
  },
  maxImageSize: {
    /** @type {number} */
    value: -1,
    kind: OptionKind.API,
  },
  pdfBug: {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.API,
  },
  standardFontDataUrl: {
    /** @type {string} */
    value:
      typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")
        ? "../external/standard_fonts/"
        : "../web/standard_fonts/",
    kind: OptionKind.API,
  },
  verbosity: {
    /** @type {number} */
    value: 1,
    kind: OptionKind.API,
  },

  workerPort: {
    /** @type {Object} */
    value: null,
    kind: OptionKind.WORKER,
  },
  workerSrc: {
    /** @type {string} */
    value:
      typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")
        ? "../src/worker_loader.js"
        : "../build/pdf.worker.js",
    kind: OptionKind.WORKER,
  },
};
if (
  typeof PDFJSDev === "undefined" ||
  PDFJSDev.test("!PRODUCTION || GENERIC")
) {
  defaultOptions.disablePreferences = {
    /** @type {boolean} */
    value: typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING"),
    kind: OptionKind.VIEWER,
  };
  defaultOptions.locale = {
    /** @type {string} */
    value: typeof navigator !== "undefined" ? navigator.language : "en-US",
    kind: OptionKind.VIEWER,
  };
  defaultOptions.sandboxBundleSrc = {
    /** @type {string} */
    value:
      typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")
        ? "../build/dev-sandbox/pdf.sandbox.js"
        : "../build/pdf.sandbox.js",
    kind: OptionKind.VIEWER,
  };

  defaultOptions.renderer.kind += OptionKind.PREFERENCE;
} else if (PDFJSDev.test("CHROME")) {
  defaultOptions.disableTelemetry = {
    /** @type {boolean} */
    value: false,
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
  };
  defaultOptions.sandboxBundleSrc = {
    /** @type {string} */
    value: "../build/pdf.sandbox.js",
    kind: OptionKind.VIEWER,
  };
}

const userOptions = Object.create(null);

class AppOptions {
  constructor() {
    throw new Error("Cannot initialize AppOptions.");
  }

  static get(name) {
    const userOption = userOptions[name];
    if (userOption !== undefined) {
      return userOption;
    }
    const defaultOption = defaultOptions[name];
    if (defaultOption !== undefined) {
      return defaultOption.compatibility ?? defaultOption.value;
    }
    return undefined;
  }

  static getAll(kind = null) {
    const options = Object.create(null);
    for (const name in defaultOptions) {
      const defaultOption = defaultOptions[name];
      if (kind) {
        if ((kind & defaultOption.kind) === 0) {
          continue;
        }
        if (kind === OptionKind.PREFERENCE) {
          const value = defaultOption.value,
            valueType = typeof value;

          if (
            valueType === "boolean" ||
            valueType === "string" ||
            (valueType === "number" && Number.isInteger(value))
          ) {
            options[name] = value;
            continue;
          }
          throw new Error(`Invalid type for preference: ${name}`);
        }
      }
      const userOption = userOptions[name];
      options[name] =
        userOption !== undefined
          ? userOption
          : defaultOption.compatibility ?? defaultOption.value;
    }
    return options;
  }

  static set(name, value) {
    userOptions[name] = value;
  }

  static setAll(options) {
    for (const name in options) {
      userOptions[name] = options[name];
    }
  }

  static remove(name) {
    delete userOptions[name];
  }
}

export { AppOptions, compatibilityParams, OptionKind };
<|endoftext|>


<commit_before>var VerticalTabsMultiSelect = {
    /*
     * Support for "selecting" multiple tabs
     */

    init: function() {
        var tabs = document.getElementById("tabbrowser-tabs");
        tabs.addEventListener('mousedown', this, true);
        tabs.addEventListener('TabSelect', this, false);
    },

    toggleMultiSelect: function(aTab) {
        if (aTab.selected) {
            let tab = this.findClosestMultiSelectedTab(aTab);
            let tabs = document.getElementById("tabbrowser-tabs");
            if (tab) {
                tab.setAttribute("multiselect-noclear", "true");
                tabs.tabbrowser.selectedTab = tab;
            }
            return;
        }
        if (aTab.getAttribute("multiselect") == "true") {
            aTab.removeAttribute("multiselect");
        } else {
            aTab.setAttribute("multiselect", "true");
        }
    },

    findClosestMultiSelectedTab: function(aTab) {
        var tabs = document.getElementById("tabbrowser-tabs");
        var i = 1;
        var tab;
        while ((aTab._tPos - i >= 0) ||
               (aTab._tPos + i < tabs.childNodes.length)) {
            if (aTab._tPos - i >= 0) {
                tab = tabs.childNodes[aTab._tPos - i];
                if (tab.getAttribute("multiselect") == "true") {
                    return tab;
                }
            }
            if (aTab._tPos + i < tabs.childNodes.length) {
                tab = tabs.childNodes[aTab._tPos + i];
                if (tab.getAttribute("multiselect") == "true") {
                    tab.setAttribute("multiselect-noclear", "true");
                    return tab;
                }
            }
            i++;
        }
        return null;
    },

    multiSpanSelect: function(aBeginTab, aEndTab) {
        this.clearMultiSelect();
        var tabs = document.getElementById("tabbrowser-tabs");
        var begin = aBeginTab._tPos;
        var end = aEndTab._tPos;
        if (begin > end) {
            [end, begin] = [begin, end];
        }
        for (let i=begin; i <= end; i++) {
            tabs.childNodes[i].setAttribute("multiselect", "true");
        }
    },

    clearMultiSelect: function() {
        var tabs = document.getElementById("tabbrowser-tabs");
        for (let i=0; i < tabs.childNodes.length; i++ ) {
            tabs.childNodes[i].removeAttribute("multiselect");
        }
    },

    getMultiSelection: function() {
        var tabs = document.getElementById("tabbrowser-tabs");
        var results = [];
        for (let i=0; i < tabs.childNodes.length; i++ ) {
            let tab = tabs.childNodes[i];
            if (tab.selected || (tab.getAttribute("multiselect") == "true")) {
                results.push(tab);
            }
        }
        return results;
    },

    /*** Event handlers ***/

    handleEvent: function(aEvent) {
        switch (aEvent.type) {
        case 'mousedown':
            this.onMouseDown(aEvent);
            return;
        case 'TabSelect':
            this.onTabSelect(aEvent);
            return;
        }
    },

    onMouseDown: function(aEvent) {
        if (aEvent.target.localName != "tab") {
            return;
        }
        if (aEvent.button != 0) {
            return;
        }

        // Check for Ctrl+click (multiselection).  On the Mac it's
        // Cmd+click which is represented by metaKey.  Ctrl+click won't be
        // possible on the Mac because that would be a right click (button 2)
        if (aEvent.ctrlKey || aEvent.metaKey) {
            this.toggleMultiSelect(aEvent.target);
            aEvent.stopPropagation();
        } else if (aEvent.shiftKey) {
            let tabs = document.getElementById("tabbrowser-tabs");
            this.multiSpanSelect(tabs.tabbrowser.selectedTab, aEvent.target);
            aEvent.stopPropagation();
        } else if (aEvent.target.selected) {
            // Clicking on the already selected tab won't fire a
            // TabSelect event, but we still want to deselect any
            // other tabs.
            this.clearMultiSelect();
        }
    },

    onTabSelect: function(aEvent) {
        if (aEvent.target.getAttribute("multiselect-noclear") == "true") {
            aEvent.target.removeAttribute("multiselect");
            aEvent.target.removeAttribute("multiselect-noclear");
            return;
        }
        this.clearMultiSelect();
    }

};
<commit_msg>Streamline<commit_after>var VerticalTabsMultiSelect = {
    /*
     * Support for "selecting" multiple tabs
     */

    init: function() {
        var tabs = document.getElementById("tabbrowser-tabs");
        tabs.addEventListener('mousedown', this, true);
        tabs.addEventListener('TabSelect', this, false);
    },

    toggleMultiSelect: function(aTab) {
        if (aTab.selected) {
            let tab = this.findClosestMultiSelectedTab(aTab);
            let tabs = document.getElementById("tabbrowser-tabs");
            if (tab) {
                // Prevent the tab switch from clearing the multiselection.
                tab.setAttribute("multiselect-noclear", "true");
                tabs.tabbrowser.selectedTab = tab;
            }
            return;
        }
        if (aTab.getAttribute("multiselect") == "true") {
            aTab.removeAttribute("multiselect");
        } else {
            aTab.setAttribute("multiselect", "true");
        }
    },

    findClosestMultiSelectedTab: function(aTab) {
        var tabs = document.getElementById("tabbrowser-tabs");
        var i = 1;
        var tab = null;
        while ((aTab._tPos - i >= 0) ||
               (aTab._tPos + i < tabs.childNodes.length)) {
            if (aTab._tPos - i >= 0) {
                tab = tabs.childNodes[aTab._tPos - i];
                if (tab.getAttribute("multiselect") == "true") {
                    break;
                }
            }
            if (aTab._tPos + i < tabs.childNodes.length) {
                tab = tabs.childNodes[aTab._tPos + i];
                if (tab.getAttribute("multiselect") == "true") {
                    break;
                }
            }
            i++;
        }
        return tab;
    },

    multiSpanSelect: function(aBeginTab, aEndTab) {
        this.clearMultiSelect();
        var tabs = document.getElementById("tabbrowser-tabs");
        var begin = aBeginTab._tPos;
        var end = aEndTab._tPos;
        if (begin > end) {
            [end, begin] = [begin, end];
        }
        for (let i=begin; i <= end; i++) {
            tabs.childNodes[i].setAttribute("multiselect", "true");
        }
    },

    clearMultiSelect: function() {
        var tabs = document.getElementById("tabbrowser-tabs");
        for (let i=0; i < tabs.childNodes.length; i++ ) {
            tabs.childNodes[i].removeAttribute("multiselect");
        }
    },

    getMultiSelection: function() {
        var tabs = document.getElementById("tabbrowser-tabs");
        var results = [];
        for (let i=0; i < tabs.childNodes.length; i++ ) {
            let tab = tabs.childNodes[i];
            if (tab.selected || (tab.getAttribute("multiselect") == "true")) {
                results.push(tab);
            }
        }
        return results;
    },

    /*** Event handlers ***/

    handleEvent: function(aEvent) {
        switch (aEvent.type) {
        case 'mousedown':
            this.onMouseDown(aEvent);
            return;
        case 'TabSelect':
            this.onTabSelect(aEvent);
            return;
        }
    },

    onMouseDown: function(aEvent) {
        if (aEvent.target.localName != "tab") {
            return;
        }
        if (aEvent.button != 0) {
            return;
        }

        // Check for Ctrl+click (multiselection).  On the Mac it's
        // Cmd+click which is represented by metaKey.  Ctrl+click won't be
        // possible on the Mac because that would be a right click (button 2)
        if (aEvent.ctrlKey || aEvent.metaKey) {
            this.toggleMultiSelect(aEvent.target);
            aEvent.stopPropagation();
        } else if (aEvent.shiftKey) {
            let tabs = document.getElementById("tabbrowser-tabs");
            this.multiSpanSelect(tabs.tabbrowser.selectedTab, aEvent.target);
            aEvent.stopPropagation();
        } else if (aEvent.target.selected) {
            // Clicking on the already selected tab won't fire a
            // TabSelect event, but we still want to deselect any
            // other tabs.
            this.clearMultiSelect();
        }
    },

    onTabSelect: function(aEvent) {
        if (aEvent.target.getAttribute("multiselect-noclear") == "true") {
            aEvent.target.removeAttribute("multiselect");
            aEvent.target.removeAttribute("multiselect-noclear");
            return;
        }
        this.clearMultiSelect();
    }

};
<|endoftext|>


<commit_before>'use strict';

angular.module('voyager')
  .factory('Fields', function(_, Dataset, vl, cp, Logger){

    var Fields = {
      fields: {},
      highlighted: {},
      selected: [],
      selectedKey: null
    };

    function resetField(field) {
      field.selected = undefined;
      field._any = !vl.encDef.isTypes(field, ['O', 'N']) && field.aggregate!=='count';
      delete field._raw;
      delete field._aggregate;
      delete field._timeUnit;
    }

    Fields.updateSchema = function(dataschema) {
      dataschema = dataschema || Dataset.dataschema;

      Fields.fields = _(dataschema).reduce(function(d, field){
        resetField(field);
        d[field.name] = field;
        return d;
      }, {});
      Fields.highlighted = {};
    };

    Fields.update = function() {
      var list = Fields.getList();
      Fields.selected = list.filter(function(d) { return d.selected; });
      Fields.selectedPKey = cp.gen.projections.key(Fields.selected);

      Logger.logInteraction(Logger.actions.FIELDS_CHANGE, Fields.selectedPKey, {
        selected: Fields.selected,
        list: list
      });

      return list;
    };

    Fields.reset = function() {
      _.each(Fields.fields, resetField);
    };

    Fields.getList = function() {
      var list = _.sortBy(_.values(Fields.fields), function(field) {
        return Dataset.fieldOrderBy.typeThenName(field);
      });
      return list;
    };

    Fields.setSelected = function(fieldName, val) {
      (Fields.fields[fieldName] || {}).selected = val;
    };

    Fields.toggleSelected = function(fieldName) {
      var field = Fields.fields[fieldName] || {};
      field.selected = field.selected ? undefined : true;
    };

    Fields.isSelected = function(fieldName) {
      return (Fields.fields[fieldName] || {}).selected;
    };

    Fields.setHighlight = function(fieldName, val) {
      Fields.highlighted[fieldName] = val;
    };

    Dataset.onUpdate.push(Fields.updateSchema);

    return Fields;
  });
<commit_msg>do not use isTypes<commit_after>'use strict';

angular.module('voyager')
  .factory('Fields', function(_, Dataset, vl, cp, Logger){

    var Fields = {
      fields: {},
      highlighted: {},
      selected: [],
      selectedKey: null
    };

    function resetField(field) {
      field.selected = undefined;
      field._any = field.type !== 'O' && field.type !== 'N' && field.aggregate!=='count';
      delete field._raw;
      delete field._aggregate;
      delete field._timeUnit;
    }

    Fields.updateSchema = function(dataschema) {
      dataschema = dataschema || Dataset.dataschema;

      Fields.fields = _(dataschema).reduce(function(d, field){
        resetField(field);
        d[field.name] = field;
        return d;
      }, {});
      Fields.highlighted = {};
    };

    Fields.update = function() {
      var list = Fields.getList();
      Fields.selected = list.filter(function(d) { return d.selected; });
      Fields.selectedPKey = cp.gen.projections.key(Fields.selected);

      Logger.logInteraction(Logger.actions.FIELDS_CHANGE, Fields.selectedPKey, {
        selected: Fields.selected,
        list: list
      });

      return list;
    };

    Fields.reset = function() {
      _.each(Fields.fields, resetField);
    };

    Fields.getList = function() {
      var list = _.sortBy(_.values(Fields.fields), function(field) {
        return Dataset.fieldOrderBy.typeThenName(field);
      });
      return list;
    };

    Fields.setSelected = function(fieldName, val) {
      (Fields.fields[fieldName] || {}).selected = val;
    };

    Fields.toggleSelected = function(fieldName) {
      var field = Fields.fields[fieldName] || {};
      field.selected = field.selected ? undefined : true;
    };

    Fields.isSelected = function(fieldName) {
      return (Fields.fields[fieldName] || {}).selected;
    };

    Fields.setHighlight = function(fieldName, val) {
      Fields.highlighted[fieldName] = val;
    };

    Dataset.onUpdate.push(Fields.updateSchema);

    return Fields;
  });
<|endoftext|>


<commit_before>var count = 0;
var bloodCount = 0;
var multiplier = 1;
var dayStatus;
var goldCount = 0;
var cycleFlag = false;
var raidFlag = false;
var goHunting; var goRaiding;
var hp = 20;
var hpMax = 20;
var dead = false;
var firstHPLoss = false;
var counter = document.getElementById("counter");
var blood = document.getElementById("blood");
var gold = document.getElementById("gold");
var statusCycle = [
	"day",
	"dusk",
	"night",
	"dawn"
];
var huntStatus = {
	"day":0,
	"dusk":3,
	"night":4,
	"dawn":2
};
var dayFlavor = [
	"The sun is bright outside..",
	"The sun is setting..",
	"The moon shines brightly..",
	"The sun is rising.."
];

setInterval(function() {
	count++;
	counter.innerHTML = count;
	triggers(count);
}, 1000);

function triggerDeath(cause) {
	var bloodloss = 20;
	addEventMsg("You have died from: "+cause);
	addEventMsg("Your death has cost you "+bloodloss+" of your precious blood!");
	if (bloodCount < 20) bloodCount = 0;
	else bloodCount -= bloodloss;
	blood.innerHTML = bloodCount;
	dead = true;
}

function healDamage(heal) {
	if (dead) {
		hp = 1;
		addEventMsg("The powerful of the nights moon revives you enough to resume hunting.");
		dead = false;
	} else {
		if ((hp+heal) > hpMax) hp = hpMax;
		else hp += heal;
		document.getElementById("hp").innerHTML = hp;
	}
}

function dealDamage(dmg,type) {
	if (!firstHPLoss) {
		firstHPLoss = true;
		document.getElementById("hpDiv").className = "";
	}
	if ((hp-dmg) <= 0) {
		hp = 0;
		triggerDeath(type);
	} else {
		hp -= dmg;
	}
	document.getElementById("hp").innerHTML = hp;
}

function addEventMsg(txt) {
	var msg = document.getElementById("msg");
  	msg.style.border = "1px solid black";
	txt = "-"+txt+"
"+msg.innerHTML;
	msg.innerHTML = txt;
}

function raidButton() {
	goRaiding = elm("button",{innerHTML:"Raid for Gold",id:"raidButton"},{});
	document.body.appendChild(goRaiding);
	goRaiding.addEventListener("click",raid.bind());
}

function bloodButton() {
	goHunting = elm("button",{innerHTML:"Hunt for Blood", id:"bloodButton"},{});
	document.body.appendChild(goHunting);
	goHunting.addEventListener("click",hunt.bind());
}

function enableButton(bid,bEvent,newTxt) {
	//accept id and enable triggered button
	var element = document.getElementById(bid);
	if (dead && dayStatus != "night") addEventMsg("You are too weak to "+bEvent+" until pure darkness allows it!");
	else {
		element.disabled = false;
		element.innerHTML = newTxt;
		healDamage(1);
	}
}

function hunt() {
	var btxt = document.getElementById("bloodButton");
	var bloodCollected;
	btxt.innerHTML = "Wait to hunt..";
	goHunting.disabled = true;
	if (dayStatus == statusCycle[0]) {
		dealDamage(10,"sunlight");
		addEventMsg("Hunting in the daylight has hurt you! -10 HP!");
	} else {
		bloodCollected = 1*multiplier;
		bloodCount += bloodCollected;
		blood.innerHTML = bloodCount;
		addEventMsg("Your hunt yielded "+bloodCollected+" pint(s) of blood!");
	}
}

function raid() {
	var goldDiv = document.getElementById("goldDiv").style.display = "block";
	var rtxt = document.getElementById("raidButton");
	var goldCollected;
	var hpLoss = 0;
	goRaiding.innerHTML = "Wait to raid..";
	goRaiding.disabled = true;
	if (dayStatus == statusCycle[0]) {
		dealDamage(15,"sunlight");
		addEventMsg("Raiding in the daylight has hurt you! -15 HP!");
	} else {
		hpLoss = Math.floor(Math.random()*(5-1+1)+1);
		goldCollected = Math.floor((Math.random()*100));
		goldCount += goldCollected;
		gold.innerHTML = goldCount;
		addEventMsg("Your raid yielded "+goldCollected+" gold coins at the cost of "+hpLoss+"HP from the townspeople!");
		healDamage(1);
	}
}

function elm(name,props,style){
	var el = document.createElement(name);
	for(var prop in props) if(props.hasOwnProperty(prop)) el[prop] = props[prop];
	for(var prop in style) if(style.hasOwnProperty(prop)) el.style[prop] = style[prop];
	return el;
}

function initDayCycle() {
	var day = document.getElementById("divCycle").style.display = "block";
	dayStatus = "dusk";
	var cycle = document.getElementById("cycle");
	cycle.innerHTML = dayStatus;
	multiplier = 3;
}

function changeDayCycle() {
	var index = statusCycle.indexOf(dayStatus);
	var cycleNext = statusCycle[(index+1)];
	if (cycleNext) {
		dayStatus = cycleNext;
		multiplier = huntStatus[cycleNext];
	}
	else {
		dayStatus = statusCycle[0];
		multiplier = huntStatus[dayStatus];
	}
	cycle.innerHTML = dayStatus;
	var newIndex = statusCycle.indexOf(dayStatus);
	addEventMsg(dayFlavor[newIndex]);
}

function triggers(count) {
	if(count == 5) bloodButton();
	if(!(count % 5) && count > 5) {
		enableButton("bloodButton","hunt","Hunt for Blood");
	}
	if(!(count % 10) && bloodCount > 35) {
		enableButton("raidButton","raid","Raid for Gold");
	}
	if (bloodCount >= 10 && !cycleFlag) {
		initDayCycle();
		cycleFlag = true;
	}
	if (bloodCount >= 35 && !raidFlag) {
		raidButton();
		raidFlag = true;
	}
	if (!(count%10) && cycleFlag) {
		changeDayCycle();
	}
}<commit_msg>Documentation<commit_after>//variables to keep track of player values, counters and other game values
//values change often
var count = 0;
var bloodCount = 0;
var multiplier = 1;
var dayStatus;
var goldCount = 0;
var hp = 20;
var hpMax = 20;

//flags for initial functions that shouldn't repeat
//(button appending for example)
//death is reoccurring
var cycleFlag = false;
var raidFlag = false;
var dead = false;
var firstHPLoss = false;

//uninitialized button variables
//dynamically created and assigned
var goHunting;
var goRaiding;

//html element variables
var counter = document.getElementById("counter");
var blood = document.getElementById("blood");
var gold = document.getElementById("gold");

//objects and arrays for day statuses and cycles
var statusCycle = [
	"day",
	"dusk",
	"night",
	"dawn"
];
var huntStatus = {
	"day":0,
	"dusk":3,
	"night":4,
	"dawn":2
};
var dayFlavor = [
	"The sun is bright outside..",
	"The sun is setting..",
	"The moon shines brightly..",
	"The sun is rising.."
];

//initial interval
//this shit controls the game!
setInterval(function() {
	count++;
	counter.innerHTML = count;
	triggers(count);
}, 1000);

//lose 20 pints of blood when you die
//add proper event log messages
//set dead flag for other functions to know you're dead
function triggerDeath(cause) {
	var bloodloss = 20;
	addEventMsg("You have died from: "+cause);
	addEventMsg("Your death has cost you "+bloodloss+" of your precious blood!");
	if (bloodCount < 20) bloodCount = 0;
	else bloodCount -= bloodloss;
	blood.innerHTML = bloodCount;
	dead = true;
}

//if player is dead, revive to 1HP during the night cycle only
//else heal player by designated amount, maxing out at players capped maxHP
function healDamage(heal) {
	if (dead) {
		hp = 1;
		addEventMsg("The powerful of the nights moon revives you enough to resume hunting.");
		dead = false;
	} else {
		if ((hp+heal) > hpMax) hp = hpMax;
		else hp += heal;
		document.getElementById("hp").innerHTML = hp;
	}
}

//first time losing HP - remove hidden class from the div!
//subtract damage dealt
//call death function appropriately, passing in what killed you
//update div to proper HP value
function dealDamage(dmg,type) {
	if (!firstHPLoss) {
		firstHPLoss = true;
		document.getElementById("hpDiv").className = "";
	}
	if ((hp-dmg) <= 0) {
		hp = 0;
		triggerDeath(type);
	} else {
		hp -= dmg;
	}
	document.getElementById("hp").innerHTML = hp;
}

//this function is a life saver
//properly appends the event log from top to bottom.
function addEventMsg(txt) {
	var msg = document.getElementById("msg");
  	msg.style.border = "1px solid black";
	txt = "-"+txt+"
"+msg.innerHTML;
	msg.innerHTML = txt;
}

//dynamic appending of the raid button when called
function raidButton() {
	goRaiding = elm("button",{innerHTML:"Raid for Gold",id:"raidButton"},{});
	document.body.appendChild(goRaiding);
	goRaiding.addEventListener("click",raid.bind());
}

//dynamic appending of the hunt button when called
function bloodButton() {
	goHunting = elm("button",{innerHTML:"Hunt for Blood", id:"bloodButton"},{});
	document.body.appendChild(goHunting);
	goHunting.addEventListener("click",hunt.bind());
}

//enables buttons when triggered
//if dead, will only enable when called during night cycle
//set html properly
function enableButton(bid,bEvent,newTxt) {
	var element = document.getElementById(bid);
	if (dead && dayStatus != "night") addEventMsg("You are too weak to "+bEvent+" until pure darkness allows it!");
	else {
		element.disabled = false;
		element.innerHTML = newTxt;
	}
}

//go hunting son!
//disable button
//add message and deal damage if hunting in the daylight
//collect yo blood and heal 1HP from drankin it
function hunt() {
	var btxt = document.getElementById("bloodButton");
	var bloodCollected;
	btxt.innerHTML = "Wait to hunt..";
	goHunting.disabled = true;
	if (dayStatus == statusCycle[0]) {
		dealDamage(10,"sunlight");
		addEventMsg("Hunting in the daylight has hurt you! -10 HP!");
	} else {
		bloodCollected = 1*multiplier;
		bloodCount += bloodCollected;
		blood.innerHTML = bloodCount;
		addEventMsg("Your hunt yielded "+bloodCollected+" pint(s) of blood!");
		healDamage(1);
	}
}

//holy shit we're going raiding.
//same shit as the hunt, just with gold
//why?
//cause raiding.
function raid() {
	var goldDiv = document.getElementById("goldDiv").style.display = "block";
	var rtxt = document.getElementById("raidButton");
	var goldCollected;
	var hpLoss = 0;
	goRaiding.innerHTML = "Wait to raid..";
	goRaiding.disabled = true;
	if (dayStatus == statusCycle[0]) {
		dealDamage(15,"sunlight");
		addEventMsg("Raiding in the daylight has hurt you! -15 HP!");
	} else {
		hpLoss = Math.floor(Math.random()*(5-1+1)+1); //random math 1-5 HP loss cause people fight back
		goldCollected = Math.floor((Math.random()*100)); //random coinage 1-100 like a boss
		goldCount += goldCollected;
		gold.innerHTML = goldCount;
		addEventMsg("Your raid yielded "+goldCollected+" gold coins at the cost of "+hpLoss+"HP from the townspeople!");
		healDamage(1);
	}
}

//bad ass element creation function thanks to @BenjaminGruenbaum on SO JS chat
//you rock bro
function elm(name,props,style){
	var el = document.createElement(name);
	for(var prop in props) if(props.hasOwnProperty(prop)) el[prop] = props[prop];
	for(var prop in style) if(style.hasOwnProperty(prop)) el.style[prop] = style[prop];
	return el;
}

//start cycling through the days
//initial values only!
//set dat *er
function initDayCycle() {
	var day = document.getElementById("divCycle").style.display = "block";
	dayStatus = "dusk";
	var cycle = document.getElementById("cycle");
	cycle.innerHTML = dayStatus;
	multiplier = 3;
}

//change day cycle into the next value
function changeDayCycle() {
	var index = statusCycle.indexOf(dayStatus);
	var cycleNext = statusCycle[(index+1)];
	if (cycleNext) {
		dayStatus = cycleNext;
		multiplier = huntStatus[cycleNext];
	}
	else {
		dayStatus = statusCycle[0];
		multiplier = huntStatus[dayStatus];
	}
	cycle.innerHTML = dayStatus;
	var newIndex = statusCycle.indexOf(dayStatus);
	addEventMsg(dayFlavor[newIndex]);
}

//THE SECOND MOST IMPORTANT FUNCTION
//these triggers control EVERYTHING
//triggered by the interval (trigger the triggers ha!)
function triggers(count) {
	if(count == 5) bloodButton();
	if(!(count % 5) && count > 5) {
		enableButton("bloodButton","hunt","Hunt for Blood");
	}
	if(!(count % 10) && bloodCount > 35) {
		enableButton("raidButton","raid","Raid for Gold");
	}
	if (bloodCount >= 10 && !cycleFlag) {
		initDayCycle();
		cycleFlag = true;
	}
	if (bloodCount >= 35 && !raidFlag) {
		raidButton();
		raidFlag = true;
	}
	if (!(count%10) && cycleFlag) {
		changeDayCycle();
	}
}<|endoftext|>