<commit_before>/**
 * XMLHttpRequest.js
 *
 * Copyright 2013, Moxiecode Systems AB
 * Released under GPL License.
 *
 * License: http://www.plupload.com/license
 * Contributing: http://www.plupload.com/contributing
 */

/*global ActiveXObject:true */

/**
@class moxie/runtime/html5/xhr/XMLHttpRequest
@private
*/
define("moxie/runtime/html5/xhr/XMLHttpRequest", [
	"moxie/runtime/html5/Runtime",
	"moxie/core/utils/Basic",
	"moxie/core/utils/Mime",
	"moxie/core/utils/Url",
	"moxie/file/File",
	"moxie/file/Blob",
	"moxie/xhr/FormData",
	"moxie/core/Exceptions",
	"moxie/core/utils/Env"
], function(extensions, Basic, Mime, Url, File, Blob, FormData, x, Env) {

	function XMLHttpRequest() {
		var self = this
		, _xhr
		, _filename
		;

		Basic.extend(this, {
			send: function(meta, data) {
				var target = this
				, isGecko2_5_6 = (Env.browser === 'Mozilla' && Env.verComp(Env.version, 4, '>=') && Env.verComp(Env.version, 7, '<'))
				, isAndroidBrowser = Env.browser === 'Android Browser'
				, mustSendAsBinary = false
				;

				// extract file name
				_filename = meta.url.replace(/^.+?\/([\w\-\.]+)$/, '$1').toLowerCase();

				_xhr = _getNativeXHR();
				_xhr.open(meta.method, meta.url, meta.async, meta.user, meta.password);

				// prepare data to be sent
				if (data instanceof Blob) {
					if (data.isDetached()) {
						mustSendAsBinary = true;
					}
					data = data.getSource();
				} else if (data instanceof FormData) {

					if (data.hasBlob()) {
						if (data.getBlob().isDetached()) {
							data = _prepareMultipart.call(target, data); // _xhr must be instantiated and be in OPENED state
							mustSendAsBinary = true;
						} else if ((isGecko2_5_6 || isAndroidBrowser) && Basic.typeOf(data.getBlob().getSource()) === 'blob' && window.FileReader) {
							// Gecko 2/5/6 can't send blob in FormData: https://bugzilla.mozilla.org/show_bug.cgi?id=649150
							// Android browsers (default one and Dolphin) seem to have the same issue, see: #613
							_preloadAndSend.call(target, meta, data);
							return; // _preloadAndSend will reinvoke send() with transmutated FormData =%D
						}
					}

					// transfer fields to real FormData
					if (data instanceof FormData) { // if still a FormData, e.g. not mangled by _prepareMultipart()
						var fd = new window.FormData();
						data.each(function(value, name) {
							if (value instanceof Blob) {
								fd.append(name, value.getSource());
							} else {
								fd.append(name, value);
							}
						});
						data = fd;
					}
				}

				// if XHR L2
				if (_xhr.upload) {
					if (meta.withCredentials) {
						_xhr.withCredentials = true;
					}

					_xhr.addEventListener('load', function(e) {
						target.trigger(e);
					});

					_xhr.addEventListener('error', function(e) {
						target.trigger(e);
					});

					// additionally listen to progress events
					_xhr.addEventListener('progress', function(e) {
						target.trigger(e);
					});

					_xhr.upload.addEventListener('progress', function(e) {
						target.trigger({
							type: 'UploadProgress',
							loaded: e.loaded,
							total: e.total
						});
					});
				// ... otherwise simulate XHR L2
				} else {
					_xhr.onreadystatechange = function onReadyStateChange() {

						// fake Level 2 events
						switch (_xhr.readyState) {

							case 1: // XMLHttpRequest.OPENED
								// readystatechanged is fired twice for OPENED state (in IE and Mozilla) - neu
								break;

							// looks like HEADERS_RECEIVED (state 2) is not reported in Opera (or it's old versions) - neu
							case 2: // XMLHttpRequest.HEADERS_RECEIVED
								break;

							case 3: // XMLHttpRequest.LOADING
								// try to fire progress event for not XHR L2
								var total, loaded;

								try {
									if (Url.hasSameOrigin(meta.url)) { // Content-Length not accessible for cross-domain on some browsers
										total = _xhr.getResponseHeader('Content-Length') || 0; // old Safari throws an exception here
									}

									if (_xhr.responseText) { // responseText was introduced in IE7
										loaded = _xhr.responseText.length;
									}
								} catch(ex) {
									total = loaded = 0;
								}

								target.trigger({
									type: 'progress',
									lengthComputable: !!total,
									total: parseInt(total, 10),
									loaded: loaded
								});
								break;

							case 4: // XMLHttpRequest.DONE
								// release readystatechange handler (mostly for IE)
								_xhr.onreadystatechange = function() {};

								// usually status 0 is returned when server is unreachable, but FF also fails to status 0 for 408 timeout
								if (_xhr.status === 0) {
									target.trigger('error');
								} else {
									target.trigger('load');
								}
								break;
						}
					};
				}

				// set request headers
				if (!Basic.isEmptyObj(meta.headers)) {
					Basic.each(meta.headers, function(value, header) {
						_xhr.setRequestHeader(header, value);
					});
				}

				// request response type
				if ("" !== meta.responseType && 'responseType' in _xhr) {
					if ('json' === meta.responseType && !Env.can('return_response_type', 'json')) { // we can fake this one
						_xhr.responseType = 'text';
					} else {
						_xhr.responseType = meta.responseType;
					}
				}

				// send ...
				if (!mustSendAsBinary) {
					_xhr.send(data);
				} else {
					if (_xhr.sendAsBinary) { // Gecko
						_xhr.sendAsBinary(data);
					} else { // other browsers having support for typed arrays
						(function() {
							// mimic Gecko's sendAsBinary
							var ui8a = new Uint8Array(data.length);
							for (var i = 0; i < data.length; i++) {
								ui8a[i] = (data.charCodeAt(i) & 0xff);
							}
							_xhr.send(ui8a.buffer);
						}());
					}
				}

				target.trigger('loadstart');
			},

			getStatus: function() {
				// according to W3C spec it should return 0 for readyState < 3, but instead it throws an exception
				try {
					if (_xhr) {
						return _xhr.status;
					}
				} catch(ex) {}
				return 0;
			},

			getResponse: function(responseType) {
				var I = this.getRuntime();

				try {
					switch (responseType) {
						case 'blob':
							var file = new File(I.uid, _xhr.response);

							// try to extract file name from content-disposition if possible (might be - not, if CORS for example)
							var disposition = _xhr.getResponseHeader('Content-Disposition');
							if (disposition) {
								// extract filename from response header if available
								var match = disposition.match(/filename=([\'\"'])([^\1]+)\1/);
								if (match) {
									_filename = match[2];
								}
							}
							file.name = _filename;

							// pre-webkit Opera doesn't set type property on the blob response
							if (!file.type) {
								file.type = Mime.getFileMime(_filename);
							}
							return file;

						case 'json':
							if (!Env.can('return_response_type', 'json')) {
								return _xhr.status === 200 && !!window.JSON ? JSON.parse(_xhr.responseText) : null;
							}
							return _xhr.response;

						case 'document':
							return _getDocument(_xhr);

						default:
							return _xhr.responseText !== '' ? _xhr.responseText : null; // against the specs, but for consistency across the runtimes
					}
				} catch(ex) {
					return null;
				}
			},

			getAllResponseHeaders: function() {
				try {
					return _xhr.getAllResponseHeaders();
				} catch(ex) {}
				return '';
			},

			abort: function() {
				if (_xhr) {
					_xhr.abort();
				}
			},

			destroy: function() {
				self = _filename = null;
			}
		});

		// here we go... ugly fix for ugly bug
		function _preloadAndSend(meta, data) {
			var target = this, blob, fr;

			// get original blob
			blob = data.getBlob().getSource();

			// preload blob in memory to be sent as binary string
			fr = new window.FileReader();
			fr.onload = function() {
				// overwrite original blob
				data.append(data.getBlobName(), new Blob(null, {
					type: blob.type,
					data: fr.result
				}));
				// invoke send operation again
				self.send.call(target, meta, data);
			};
			fr.readAsBinaryString(blob);
		}

		function _getNativeXHR() {
			if (window.XMLHttpRequest && !(Env.browser === 'IE' && Env.verComp(Env.version, 8, '<'))) { // IE7 has native XHR but it's buggy
				return new window.XMLHttpRequest();
			} else {
				return (function() {
					var progIDs = ['Msxml2.XMLHTTP.6.0', 'Microsoft.XMLHTTP']; // if 6.0 available, use it, otherwise failback to default 3.0
					for (var i = 0; i < progIDs.length; i++) {
						try {
							return new ActiveXObject(progIDs[i]);
						} catch (ex) {}
					}
				})();
			}
		}

		// @credits Sergey Ilinsky	(http://www.ilinsky.com/)
		function _getDocument(xhr) {
			var rXML = xhr.responseXML;
			var rText = xhr.responseText;

			// Try parsing responseText (@see: http://www.ilinsky.com/articles/XMLHttpRequest/#bugs-ie-responseXML-content-type)
			if (Env.browser === 'IE' && rText && rXML && !rXML.documentElement && /[^\/]+\/[^\+]+\+xml/.test(xhr.getResponseHeader("Content-Type"))) {
				rXML = new window.ActiveXObject("Microsoft.XMLDOM");
				rXML.async = false;
				rXML.validateOnParse = false;
				rXML.loadXML(rText);
			}

			// Check if there is no error in document
			if (rXML) {
				if ((Env.browser === 'IE' && rXML.parseError !== 0) || !rXML.documentElement || rXML.documentElement.tagName === "parsererror") {
					return null;
				}
			}
			return rXML;
		}

		function _prepareMultipart(fd) {
			var boundary = '----moxieboundary' + new Date().getTime()
			, dashdash = '--'
			, crlf = '\r\n'
			, multipart = ''
			, I = this.getRuntime()
			;

			if (!I.can('send_binary_string')) {
				throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
			}

			_xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);

			// append multipart parameters
			fd.each(function(value, name) {
				// Firefox 3.6 failed to convert multibyte characters to UTF-8 in sendAsBinary(),
				// so we try it here ourselves with: unescape(encodeURIComponent(value))
				if (value instanceof Blob) {
					// Build RFC2388 blob
					multipart += dashdash + boundary + crlf +
						'Content-Disposition: form-data; name="' + name + '"; filename="' + unescape(encodeURIComponent(value.name || 'blob')) + '"' + crlf +
						'Content-Type: ' + (value.type || 'application/octet-stream') + crlf + crlf +
						value.getSource() + crlf;
				} else {
					multipart += dashdash + boundary + crlf +
						'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf +
						unescape(encodeURIComponent(value)) + crlf;
				}
			});

			multipart += dashdash + boundary + dashdash + crlf;

			return multipart;
		}
	}

	return (extensions.XMLHttpRequest = XMLHttpRequest);
});
<commit_msg>XHR, HTML5: clarify onload logic for envs with no support for XHR2<commit_after>/**
 * XMLHttpRequest.js
 *
 * Copyright 2013, Moxiecode Systems AB
 * Released under GPL License.
 *
 * License: http://www.plupload.com/license
 * Contributing: http://www.plupload.com/contributing
 */

/*global ActiveXObject:true */

/**
@class moxie/runtime/html5/xhr/XMLHttpRequest
@private
*/
define("moxie/runtime/html5/xhr/XMLHttpRequest", [
	"moxie/runtime/html5/Runtime",
	"moxie/core/utils/Basic",
	"moxie/core/utils/Mime",
	"moxie/core/utils/Url",
	"moxie/file/File",
	"moxie/file/Blob",
	"moxie/xhr/FormData",
	"moxie/core/Exceptions",
	"moxie/core/utils/Env"
], function(extensions, Basic, Mime, Url, File, Blob, FormData, x, Env) {

	function XMLHttpRequest() {
		var self = this
		, _xhr
		, _filename
		;

		Basic.extend(this, {
			send: function(meta, data) {
				var target = this
				, isGecko2_5_6 = (Env.browser === 'Mozilla' && Env.verComp(Env.version, 4, '>=') && Env.verComp(Env.version, 7, '<'))
				, isAndroidBrowser = Env.browser === 'Android Browser'
				, mustSendAsBinary = false
				;

				// extract file name
				_filename = meta.url.replace(/^.+?\/([\w\-\.]+)$/, '$1').toLowerCase();

				_xhr = _getNativeXHR();
				_xhr.open(meta.method, meta.url, meta.async, meta.user, meta.password);

				// prepare data to be sent
				if (data instanceof Blob) {
					if (data.isDetached()) {
						mustSendAsBinary = true;
					}
					data = data.getSource();
				} else if (data instanceof FormData) {

					if (data.hasBlob()) {
						if (data.getBlob().isDetached()) {
							data = _prepareMultipart.call(target, data); // _xhr must be instantiated and be in OPENED state
							mustSendAsBinary = true;
						} else if ((isGecko2_5_6 || isAndroidBrowser) && Basic.typeOf(data.getBlob().getSource()) === 'blob' && window.FileReader) {
							// Gecko 2/5/6 can't send blob in FormData: https://bugzilla.mozilla.org/show_bug.cgi?id=649150
							// Android browsers (default one and Dolphin) seem to have the same issue, see: #613
							_preloadAndSend.call(target, meta, data);
							return; // _preloadAndSend will reinvoke send() with transmutated FormData =%D
						}
					}

					// transfer fields to real FormData
					if (data instanceof FormData) { // if still a FormData, e.g. not mangled by _prepareMultipart()
						var fd = new window.FormData();
						data.each(function(value, name) {
							if (value instanceof Blob) {
								fd.append(name, value.getSource());
							} else {
								fd.append(name, value);
							}
						});
						data = fd;
					}
				}

				// if XHR L2
				if (_xhr.upload) {
					if (meta.withCredentials) {
						_xhr.withCredentials = true;
					}

					_xhr.addEventListener('load', function(e) {
						target.trigger(e);
					});

					_xhr.addEventListener('error', function(e) {
						target.trigger(e);
					});

					// additionally listen to progress events
					_xhr.addEventListener('progress', function(e) {
						target.trigger(e);
					});

					_xhr.upload.addEventListener('progress', function(e) {
						target.trigger({
							type: 'UploadProgress',
							loaded: e.loaded,
							total: e.total
						});
					});
				// ... otherwise simulate XHR L2
				} else {
					_xhr.onreadystatechange = function onReadyStateChange() {

						// fake Level 2 events
						switch (_xhr.readyState) {

							case 1: // XMLHttpRequest.OPENED
								// readystatechanged is fired twice for OPENED state (in IE and Mozilla) - neu
								break;

							// looks like HEADERS_RECEIVED (state 2) is not reported in Opera (or it's old versions) - neu
							case 2: // XMLHttpRequest.HEADERS_RECEIVED
								break;

							case 3: // XMLHttpRequest.LOADING
								// try to fire progress event for not XHR L2
								var total, loaded;

								try {
									if (Url.hasSameOrigin(meta.url)) { // Content-Length not accessible for cross-domain on some browsers
										total = _xhr.getResponseHeader('Content-Length') || 0; // old Safari throws an exception here
									}

									if (_xhr.responseText) { // responseText was introduced in IE7
										loaded = _xhr.responseText.length;
									}
								} catch(ex) {
									total = loaded = 0;
								}

								target.trigger({
									type: 'progress',
									lengthComputable: !!total,
									total: parseInt(total, 10),
									loaded: loaded
								});
								break;

							case 4: // XMLHttpRequest.DONE
								// release readystatechange handler (mostly for IE)
								_xhr.onreadystatechange = function() {};

								// usually status 0 is returned when server is unreachable, but FF also fails to status 0 for 408 timeout
								try {
									if (_xhr.status >= 200 && _xhr.status < 400) {
										target.trigger('load');
										break;
									}
								} catch(ex) {}

								target.trigger('error');
								break;
						}
					};
				}

				// set request headers
				if (!Basic.isEmptyObj(meta.headers)) {
					Basic.each(meta.headers, function(value, header) {
						_xhr.setRequestHeader(header, value);
					});
				}

				// request response type
				if ("" !== meta.responseType && 'responseType' in _xhr) {
					if ('json' === meta.responseType && !Env.can('return_response_type', 'json')) { // we can fake this one
						_xhr.responseType = 'text';
					} else {
						_xhr.responseType = meta.responseType;
					}
				}

				// send ...
				if (!mustSendAsBinary) {
					_xhr.send(data);
				} else {
					if (_xhr.sendAsBinary) { // Gecko
						_xhr.sendAsBinary(data);
					} else { // other browsers having support for typed arrays
						(function() {
							// mimic Gecko's sendAsBinary
							var ui8a = new Uint8Array(data.length);
							for (var i = 0; i < data.length; i++) {
								ui8a[i] = (data.charCodeAt(i) & 0xff);
							}
							_xhr.send(ui8a.buffer);
						}());
					}
				}

				target.trigger('loadstart');
			},

			getStatus: function() {
				// according to W3C spec it should return 0 for readyState < 3, but instead it throws an exception
				try {
					if (_xhr) {
						return _xhr.status;
					}
				} catch(ex) {}
				return 0;
			},

			getResponse: function(responseType) {
				var I = this.getRuntime();

				try {
					switch (responseType) {
						case 'blob':
							var file = new File(I.uid, _xhr.response);

							// try to extract file name from content-disposition if possible (might be - not, if CORS for example)
							var disposition = _xhr.getResponseHeader('Content-Disposition');
							if (disposition) {
								// extract filename from response header if available
								var match = disposition.match(/filename=([\'\"'])([^\1]+)\1/);
								if (match) {
									_filename = match[2];
								}
							}
							file.name = _filename;

							// pre-webkit Opera doesn't set type property on the blob response
							if (!file.type) {
								file.type = Mime.getFileMime(_filename);
							}
							return file;

						case 'json':
							if (!Env.can('return_response_type', 'json')) {
								return _xhr.status === 200 && !!window.JSON ? JSON.parse(_xhr.responseText) : null;
							}
							return _xhr.response;

						case 'document':
							return _getDocument(_xhr);

						default:
							return _xhr.responseText !== '' ? _xhr.responseText : null; // against the specs, but for consistency across the runtimes
					}
				} catch(ex) {
					return null;
				}
			},

			getAllResponseHeaders: function() {
				try {
					return _xhr.getAllResponseHeaders();
				} catch(ex) {}
				return '';
			},

			abort: function() {
				if (_xhr) {
					_xhr.abort();
				}
			},

			destroy: function() {
				self = _filename = null;
			}
		});

		// here we go... ugly fix for ugly bug
		function _preloadAndSend(meta, data) {
			var target = this, blob, fr;

			// get original blob
			blob = data.getBlob().getSource();

			// preload blob in memory to be sent as binary string
			fr = new window.FileReader();
			fr.onload = function() {
				// overwrite original blob
				data.append(data.getBlobName(), new Blob(null, {
					type: blob.type,
					data: fr.result
				}));
				// invoke send operation again
				self.send.call(target, meta, data);
			};
			fr.readAsBinaryString(blob);
		}

		function _getNativeXHR() {
			if (window.XMLHttpRequest && !(Env.browser === 'IE' && Env.verComp(Env.version, 8, '<'))) { // IE7 has native XHR but it's buggy
				return new window.XMLHttpRequest();
			} else {
				return (function() {
					var progIDs = ['Msxml2.XMLHTTP.6.0', 'Microsoft.XMLHTTP']; // if 6.0 available, use it, otherwise failback to default 3.0
					for (var i = 0; i < progIDs.length; i++) {
						try {
							return new ActiveXObject(progIDs[i]);
						} catch (ex) {}
					}
				})();
			}
		}

		// @credits Sergey Ilinsky	(http://www.ilinsky.com/)
		function _getDocument(xhr) {
			var rXML = xhr.responseXML;
			var rText = xhr.responseText;

			// Try parsing responseText (@see: http://www.ilinsky.com/articles/XMLHttpRequest/#bugs-ie-responseXML-content-type)
			if (Env.browser === 'IE' && rText && rXML && !rXML.documentElement && /[^\/]+\/[^\+]+\+xml/.test(xhr.getResponseHeader("Content-Type"))) {
				rXML = new window.ActiveXObject("Microsoft.XMLDOM");
				rXML.async = false;
				rXML.validateOnParse = false;
				rXML.loadXML(rText);
			}

			// Check if there is no error in document
			if (rXML) {
				if ((Env.browser === 'IE' && rXML.parseError !== 0) || !rXML.documentElement || rXML.documentElement.tagName === "parsererror") {
					return null;
				}
			}
			return rXML;
		}

		function _prepareMultipart(fd) {
			var boundary = '----moxieboundary' + new Date().getTime()
			, dashdash = '--'
			, crlf = '\r\n'
			, multipart = ''
			, I = this.getRuntime()
			;

			if (!I.can('send_binary_string')) {
				throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
			}

			_xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);

			// append multipart parameters
			fd.each(function(value, name) {
				// Firefox 3.6 failed to convert multibyte characters to UTF-8 in sendAsBinary(),
				// so we try it here ourselves with: unescape(encodeURIComponent(value))
				if (value instanceof Blob) {
					// Build RFC2388 blob
					multipart += dashdash + boundary + crlf +
						'Content-Disposition: form-data; name="' + name + '"; filename="' + unescape(encodeURIComponent(value.name || 'blob')) + '"' + crlf +
						'Content-Type: ' + (value.type || 'application/octet-stream') + crlf + crlf +
						value.getSource() + crlf;
				} else {
					multipart += dashdash + boundary + crlf +
						'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf +
						unescape(encodeURIComponent(value)) + crlf;
				}
			});

			multipart += dashdash + boundary + dashdash + crlf;

			return multipart;
		}
	}

	return (extensions.XMLHttpRequest = XMLHttpRequest);
});
<|endoftext|>


<commit_before>(function() {

  var handler = Gmaps.build('Google');
  // console.dir(handler);
  var mapOptions = $('meta[name=mapOptions]').attr('content');
  var locations = $('meta[name=locations]').attr('content');
  var categories = $('meta[name=categories]').attr('content');

  var markerLocations = [];
  var filteredLocations = [];
  var meetupList = $('.list a');
  var defaultCoord = {lat: 49.282982, lng: -123.056554};
  var defaultLatLng = new google.maps.LatLng(defaultCoord.lat, defaultCoord.lng);
  var categoryList = $('.js-menu > ul');
  var markerIcon = {
    "url": '/images/directory/map-pin.png',
    "width": 33,
    "height": 39
  };

  var generateMarkerData = function(element) {

    var orgMarkup = "";

    orgMarkup += "
"+element.name+"
";
    orgMarkup += "
"+element.address+"
";
    orgMarkup += "
Go to website
";

    element.infowindow = "
"+orgMarkup+"
";
    element.picture = markerIcon;

    if(element.lat && element.lng){
      markerLocations.push(element);
    }

  }

  var setDefaultLocation = function() {
    handler.buildMap(mapOptions, function() {
      handler.map.centerOn(defaultLatLng);
      handler.getMap().setZoom(14);
    });
  }

  var setZoomBasedOnLatitudePosition = function (latitudePosition) {
    if(latitudePosition != defaultCoord.lat){
      handler.getMap().setZoom(16);
    }else{
      handler.getMap().setZoom(14);
    }
  }

  var setGeolocation = function(pos) {
    var crd = pos.coords;
    var latlng = new google.maps.LatLng(crd.latitude, crd.longitude);
    handler.map.centerOn(latlng);
    setZoomBasedOnLatitudePosition(handler.getMap().getCenter().k);
  }

  var bindLiToMarker = function(json_array) {
    _.each(json_array, function(json){

      var markerId = json.name.toLowerCase().replace(/\W/g, '');
      var currentMarker = $('#'+markerId);

      currentMarker.on('click', function(e){
        meetupList.removeClass('active');
        $(this).addClass("active");
        e.preventDefault();
        handler.getMap().setZoom(16);
        json.marker.setMap(handler.getMap()); //because clusterer removes map property from marker
        json.marker.panTo();
        google.maps.event.trigger(json.marker.getServiceObject(), 'click');

        $("html, body").animate({
          scrollTop:0
        },"slow");
      });

      google.maps.event.addListener(json.marker.getServiceObject(), 'click', function(){
        meetupList.removeClass('active');
        currentMarker.addClass("active");
        handler.getMap().setZoom(20);
      });
    });
  }

  var drawMap = function(points) {
    var markers = handler.addMarkers(points);

    _.each(points, function(json, index){
      json.marker = markers[index];
    });

    // bindLiToMarker(markerLocations);

    handler.bounds.extendWith(markers);

    // setZoomBasedOnLatitudePosition(handler.getMap().getCenter().k);
  }

  var cleanMap = function(points) {
    handler.removeMarkers();
  }

  var zoomToPosition = function(position) {
    var marker = handler.addMarker({
      lat: position.coords.latitude,
      lng: position.coords.longitude
    });
    handler.map.centerOn(marker);
    handler.bounds.extendWith(marker);
    handler.getMap().setZoom(18);
  }

  var generateCategoriesList = function(element) {
    var link = $("", {html: element.name, href: '#'});
    var listItem = $("
").append(link);
    categoryList.append(listItem);
    link.on('click', function(e){
      filterCategories(element.name);
      $('.js-menu-screen').trigger('click');
    });
  }

  var generateCategories = function() {
    _.each(categories, generateCategoriesList);
  }

  var filterCategories = function(categoryFilter){

    var filteredLocations = _.filter(markerLocations, function(item){
      if ((typeof(item.category) !== 'undefined') && (item.category !== null)) {
        return item.category.name == categoryFilter;
      }
    });

    cleanMap(markerLocations);
    buildMap(filteredLocations);

    handler.map.centerOn(defaultLatLng);
    handler.getMap().setZoom(16);

  }

  var buildMap = function(points) {
    handler.buildMap(mapOptions, function() {
      drawMap(points);
    });
  }

  mapOptions = JSON.parse(mapOptions);
  locations = JSON.parse(locations);
  categories = JSON.parse(categories);
  mapOptions.provider.zoomControlOptions = google.maps.ZoomControlStyle.SMALL;

  setDefaultLocation();
  navigator.geolocation.getCurrentPosition(setGeolocation);

  // map all locations on page load
  _.each(locations,generateMarkerData);
  buildMap(markerLocations);

  generateCategories();

})();
<commit_msg>add js to make center of map responsive<commit_after>(function() {

  var handler = Gmaps.build('Google');
  // console.dir(handler);
  var mapOptions = $('meta[name=mapOptions]').attr('content');
  var locations = $('meta[name=locations]').attr('content');
  var categories = $('meta[name=categories]').attr('content');

  var markerLocations = [];
  var filteredLocations = [];
  var meetupList = $('.list a');
  var defaultCoord = {lat: 49.282982, lng: -123.056554};
  var defaultLatLng = new google.maps.LatLng(defaultCoord.lat, defaultCoord.lng);
  var categoryList = $('.js-menu > ul');
  var markerIcon = {
    "url": '/images/directory/map-pin.png',
    "width": 33,
    "height": 39
  };

  var generateMarkerData = function(element) {

    var orgMarkup = "";

    orgMarkup += "
"+element.name+"
";
    orgMarkup += "
"+element.address+"
";
    orgMarkup += "
Go to website
";

    element.infowindow = "
"+orgMarkup+"
";
    element.picture = markerIcon;

    if(element.lat && element.lng){
      markerLocations.push(element);
    }

  }

  var setDefaultLocation = function() {
    handler.buildMap(mapOptions, function() {
      handler.map.centerOn(defaultLatLng);
      handler.getMap().setZoom(14);
    });
  }

  var setZoomBasedOnLatitudePosition = function (latitudePosition) {
    if(latitudePosition != defaultCoord.lat){
      handler.getMap().setZoom(16);
    }else{
      handler.getMap().setZoom(14);
    }
  }

  var setGeolocation = function(pos) {
    var crd = pos.coords;
    var latlng = new google.maps.LatLng(crd.latitude, crd.longitude);
    handler.map.centerOn(latlng);
    setZoomBasedOnLatitudePosition(handler.getMap().getCenter().k);
  }

  var bindLiToMarker = function(json_array) {
    _.each(json_array, function(json){

      var markerId = json.name.toLowerCase().replace(/\W/g, '');
      var currentMarker = $('#'+markerId);

      currentMarker.on('click', function(e){
        meetupList.removeClass('active');
        $(this).addClass("active");
        e.preventDefault();
        handler.getMap().setZoom(16);
        json.marker.setMap(handler.getMap()); //because clusterer removes map property from marker
        json.marker.panTo();
        google.maps.event.trigger(json.marker.getServiceObject(), 'click');

        $("html, body").animate({
          scrollTop:0
        },"slow");
      });

      google.maps.event.addListener(json.marker.getServiceObject(), 'click', function(){
        meetupList.removeClass('active');
        currentMarker.addClass("active");
        handler.getMap().setZoom(20);
      });
    });
  }

  var drawMap = function(points) {
    var markers = handler.addMarkers(points);

    _.each(points, function(json, index){
      json.marker = markers[index];
    });

    // bindLiToMarker(markerLocations);

    handler.bounds.extendWith(markers);

    // setZoomBasedOnLatitudePosition(handler.getMap().getCenter().k);
  }

  var cleanMap = function(points) {
    handler.removeMarkers();
  }

  var zoomToPosition = function(position) {
    var marker = handler.addMarker({
      lat: position.coords.latitude,
      lng: position.coords.longitude
    });
    handler.map.centerOn(marker);
    handler.bounds.extendWith(marker);
    handler.getMap().setZoom(18);
  }

  var generateCategoriesList = function(element) {
    var link = $("", {html: element.name, href: '#'});
    var listItem = $("
").append(link);
    categoryList.append(listItem);
    link.on('click', function(e){
      filterCategories(element.name);
      $('.js-menu-screen').trigger('click');
    });
  }

  var generateCategories = function() {
    _.each(categories, generateCategoriesList);
  }

  var filterCategories = function(categoryFilter){

    var filteredLocations = _.filter(markerLocations, function(item){
      if ((typeof(item.category) !== 'undefined') && (item.category !== null)) {
        return item.category.name == categoryFilter;
      }
    });

    cleanMap(markerLocations);
    buildMap(filteredLocations);

    handler.map.centerOn(defaultLatLng);
    handler.getMap().setZoom(16);

  }

  var buildMap = function(points) {
    handler.buildMap(mapOptions, function() {
      drawMap(points);
    });
  }

  mapOptions = JSON.parse(mapOptions);
  locations = JSON.parse(locations);
  categories = JSON.parse(categories);
  mapOptions.provider.zoomControlOptions = google.maps.ZoomControlStyle.SMALL;

  setDefaultLocation();
  navigator.geolocation.getCurrentPosition(setGeolocation);

  // map all locations on page load
  _.each(locations,generateMarkerData);
  buildMap(markerLocations);

  google.maps.event.addDomListener(window, "resize", function() {
     var center = handler.getMap().getCenter();
     google.maps.event.trigger(handler.getMap(), "resize");
     handler.getMap().setCenter(center);
  });

  generateCategories();

})();
<|endoftext|>


<commit_before>/**
 *
 * # Fastbinder
 *
 * Fast and worry-free dynamic event binding.
 *
 * https://github.com/andrewchilds/fastbinder
 *
 * ## Supported Attributes
 *
 * - data-on-blur
 * - data-on-click
 * - data-on-change
 * - data-on-focus
 * - data-on-hover
 * - data-on-keydown
 * - data-on-keyup
 * - data-on-mousedown
 * - data-on-mouseup
 * - data-on-scroll
 * - data-on-submit
 *
 * ## Scope to Controller
 *
 * - data-controller
 *
 * ## Usage
 *
 * jQuery.fastbinder();
 * jQuery.fastbinder({ hoverDelay: 250 });
 * jQuery.fastbinder.setOptions({ forceExternalLinks: false });
 * jQuery.fastbinder.destroy();
 *
 * ## Attribute Examples
 *
 * <input type="text" data-on-change="MyLibrary.myFunction" />
 * Execute myFunction on click
 *
 */
(function ($) {

  // Utils

  // Faster than jQuery.data
  function data(el, name, val) {
    return attr(el, 'data-' + name, val);
  }

  function attr(el, name, val) {
    if (el && el.jquery) {
      el = el[0];
    }
    if (el && el.getAttribute) {
      if (typeof val !== 'undefined') {
        el.setAttribute(name, val);
      } else {
        var elAttr = el.getAttribute(name);
        return convertNumber(elAttr);
      }
    }
  }

  function convertNumber(str) {
    return (str === '' || isNaN(str)) ? str : parseFloat(str);
  }

  function strToFunction(functionName, context) {
    context = context || window;
    var namespaces = functionName.split('.');
    var func = namespaces.pop();
    for (var i = 0; i < namespaces.length; i++) {
      if (!context[namespaces[i]]) {
        return false;
      }
      context = context[namespaces[i]];
    }
    return context[func];
  }

  function getController(target) {
    var controller = '';
    var controllerElement = target.closest('[data-controller]');
    if (controllerElement.length > 0) {
      controller = $.fastbinder.options.controllerPrefix + data(controllerElement, 'controller');
    }
    return controller;
  }

  function keyPressed(e, key) {
    var keys = {
      'LEFT_CLICK': 1,
      'MIDDLE_CLICK': 2,
      'RIGHT_CLICK': 3,
      'TAB': 9,
      'ENTER': 13,
      'ESCAPE': 27,
      'LEFT_ARROW': 37,
      'UP_ARROW': 38,
      'RIGHT_ARROW': 39,
      'DOWN_ARROW': 40,
      'TILDE': 192
    };

    return e && e.which === keys[key];
  }

  // Handlers

  function fireEventHandler(target, eventType, e) {
    if (target.length > 0) {
      var handler = data(target, eventType);
      if (handler) {
        var controller = getController(target);
        var handlerFn = strToFunction(handler);
        var controllerHandlerFn = strToFunction(controller + '.' + handler);
        if (typeof controllerHandlerFn === 'function') {
          return controllerHandlerFn.call(target[0], e);
        }
        if (typeof handlerFn === 'function') {
          return handlerFn.call(target[0], e);
        }
      }
    }
  }

  function genericBinder(options) {
    options = $.extend({
      attribute: 'on-click',
      beforeTrigger: null,
      context: document.body,
      delay: 0,
      deferLookup: false,
      name: 'click'
    }, options);

    var names = options.name.split(' ');
    $.each(names, function (key, val) {
      names[key] = val + '.' + $.fastbinder.options.namespace;
    });

    var timeout;
    $(options.context).on(names.join(' '), function (e) {
      var target = $(e.target).closest('[data-' + options.attribute + ']');

      if (options.beforeTrigger && !options.beforeTrigger(e)) {
        return;
      }
      if (target.length || options.deferLookup) {
        var fn = function () {
          if (options.deferLookup) {
            target = $(e.target).closest('[data-' + options.attribute + ']');
            if (target.length === 0) {
              return;
            }
          }
          return fireEventHandler(target, options.attribute, e);
        };
        var delay = (options.delay && $.isFunction(options.delay)) ? options.delay(target) : options.delay;
        if (delay) {
          clearTimeout(timeout);
          timeout = setTimeout(fn, delay);
        } else {
          return fn();
        }
      }
    });
  }

  function initKeyupHandler() {
    var timeoutID;
    $(window).on('keydown.' + $.fastbinder.options.namespace, function (e) {
      var target = $(document.activeElement);
      if (target.is('input, textarea')) {
        var fn = function () {
          fireEventHandler(target, 'on-keydown', e);
        };
        if ($.fastbinder.options.keydownDelay > 0) {
          clearTimeout(timeoutID);
          timeoutID = setTimeout(fn, $.fastbinder.options.keydownDelay);
        } else {
          fn();
        }
      }
    }).on('keyup.' + $.fastbinder.options.namespace, function (e) {
      var target = $(document.activeElement);
      if (target.is('input, textarea')) {
        if (keyPressed(e, 'ENTER')) {
          fireEventHandler(target, 'on-submit', e);
        } else {
          var fn = function () {
            fireEventHandler(target, 'on-keyup', e);
          };
          if ($.fastbinder.options.keyupDelay > 0) {
            clearTimeout(timeoutID);
            timeoutID = setTimeout(fn, $.fastbinder.options.keyupDelay);
          } else {
            fn();
          }
        }
      }
    });
  }

  function handleExternalLinks(e) {
    // Handle proper links
    var target = $(e.target);
    if (target.is('a') && target.attr('href') &&
      target.attr('href') !== '#' && !data(target, 'on-click')) {
      if ($.fastbinder.options.forceExternalLinks &&
        target.attr('href').toLowerCase().indexOf('http') === 0) {
        target.attr('target', '_blank');
      }
      return false;
    }
    return true;
  }

  // Public API

  $.fastbinder = function (options) {
    $.fastbinder.setOptions(options);
    $.fastbinder.destroy();
    $.fastbinder.init();
  };

  $.fastbinder.on = genericBinder;

  $.fastbinder.defaults = {
    namespace: 'fastbinder',
    controllerPrefix: '',
    hoverDelay: 50,
    keydownDelay: 0,
    keyupDelay: 50,
    scrollDelay: 50,
    forceExternalLinks: true
  };

  $.fastbinder.setOptions = function (options) {
    $.fastbinder.options = $.extend($.fastbinder.options || $.fastbinder.defaults, options);
  };

  $.fastbinder.destroy = function () {
    $(document.body).off('.' + $.fastbinder.options.namespace);
    $(window).off('.' + $.fastbinder.options.namespace);
  };

  $.fastbinder.off = function (eventName) {
    $(document.body).off(eventName + '.' + $.fastbinder.options.namespace);
    $(window).off(eventName + '.' + $.fastbinder.options.namespace);
  };

  $.fastbinder.init = function () {
    $.fastbinder.on({ name: 'click', attribute: 'on-click', beforeTrigger: handleExternalLinks });
    $.fastbinder.on({ name: 'mousedown', attribute: 'on-mousedown' });
    $.fastbinder.on({ name: 'mouseup', attribute: 'on-mouseup' });
    $.fastbinder.on({ name: 'submit', attribute: 'on-submit', context: window });
    $.fastbinder.on({ name: 'change', attribute: 'on-change', context: window });
    $.fastbinder.on({ name: 'focusin', attribute: 'on-focus' });
    $.fastbinder.on({ name: 'focusout', attribute: 'on-blur' });

    $.fastbinder.on({
      name: 'scroll',
      attribute: 'on-scroll',
      context: window,
      delay: function () {
        return $.fastbinder.options.scrollDelay;
      },
      deferLookup: true
    });
    $.fastbinder.on({
      name: 'mousemove',
      attribute: 'on-hover',
      delay: function (target) {
        return data(target, 'hover-delay') || $.fastbinder.options.hoverDelay;
      },
      deferLookup: true
    });

    initKeyupHandler();
  };

}(window.jQuery));
<commit_msg>We don't need a general-purpose keyPressed function<commit_after>/**
 *
 * # Fastbinder
 *
 * Fast and worry-free dynamic event binding.
 *
 * https://github.com/andrewchilds/fastbinder
 *
 * ## Supported Attributes
 *
 * - data-on-blur
 * - data-on-click
 * - data-on-change
 * - data-on-focus
 * - data-on-hover
 * - data-on-keydown
 * - data-on-keyup
 * - data-on-mousedown
 * - data-on-mouseup
 * - data-on-scroll
 * - data-on-submit
 *
 * ## Scope to Controller
 *
 * - data-controller
 *
 * ## Usage
 *
 * jQuery.fastbinder();
 * jQuery.fastbinder({ hoverDelay: 250 });
 * jQuery.fastbinder.setOptions({ forceExternalLinks: false });
 * jQuery.fastbinder.destroy();
 *
 * ## Attribute Examples
 *
 * <input type="text" data-on-change="MyLibrary.myFunction" />
 * Execute myFunction on click
 *
 */
(function ($) {

  // Utils

  // Faster than jQuery.data
  function data(el, name, val) {
    return attr(el, 'data-' + name, val);
  }

  function attr(el, name, val) {
    if (el && el.jquery) {
      el = el[0];
    }
    if (el && el.getAttribute) {
      if (typeof val !== 'undefined') {
        el.setAttribute(name, val);
      } else {
        var elAttr = el.getAttribute(name);
        return convertNumber(elAttr);
      }
    }
  }

  function convertNumber(str) {
    return (str === '' || isNaN(str)) ? str : parseFloat(str);
  }

  function strToFunction(functionName, context) {
    context = context || window;
    var namespaces = functionName.split('.');
    var func = namespaces.pop();
    for (var i = 0; i < namespaces.length; i++) {
      if (!context[namespaces[i]]) {
        return false;
      }
      context = context[namespaces[i]];
    }
    return context[func];
  }

  function getController(target) {
    var controller = '';
    var controllerElement = target.closest('[data-controller]');
    if (controllerElement.length > 0) {
      controller = $.fastbinder.options.controllerPrefix + data(controllerElement, 'controller');
    }
    return controller;
  }

  function isEnterKey(e) {
    return e && e.which === 13;
  }

  // Handlers

  function fireEventHandler(target, eventType, e) {
    if (target.length > 0) {
      var handler = data(target, eventType);
      if (handler) {
        var controller = getController(target);
        var handlerFn = strToFunction(handler);
        var controllerHandlerFn = strToFunction(controller + '.' + handler);
        if (typeof controllerHandlerFn === 'function') {
          return controllerHandlerFn.call(target[0], e);
        }
        if (typeof handlerFn === 'function') {
          return handlerFn.call(target[0], e);
        }
      }
    }
  }

  function genericBinder(options) {
    options = $.extend({
      attribute: 'on-click',
      beforeTrigger: null,
      context: document.body,
      delay: 0,
      deferLookup: false,
      name: 'click'
    }, options);

    var names = options.name.split(' ');
    $.each(names, function (key, val) {
      names[key] = val + '.' + $.fastbinder.options.namespace;
    });

    var timeout;
    $(options.context).on(names.join(' '), function (e) {
      var target = $(e.target).closest('[data-' + options.attribute + ']');

      if (options.beforeTrigger && !options.beforeTrigger(e)) {
        return;
      }
      if (target.length || options.deferLookup) {
        var fn = function () {
          if (options.deferLookup) {
            target = $(e.target).closest('[data-' + options.attribute + ']');
            if (target.length === 0) {
              return;
            }
          }
          return fireEventHandler(target, options.attribute, e);
        };
        var delay = (options.delay && $.isFunction(options.delay)) ? options.delay(target) : options.delay;
        if (delay) {
          clearTimeout(timeout);
          timeout = setTimeout(fn, delay);
        } else {
          return fn();
        }
      }
    });
  }

  function initKeyupHandler() {
    var timeoutID;
    $(window).on('keydown.' + $.fastbinder.options.namespace, function (e) {
      var target = $(document.activeElement);
      if (target.is('input, textarea')) {
        var fn = function () {
          fireEventHandler(target, 'on-keydown', e);
        };
        if ($.fastbinder.options.keydownDelay > 0) {
          clearTimeout(timeoutID);
          timeoutID = setTimeout(fn, $.fastbinder.options.keydownDelay);
        } else {
          fn();
        }
      }
    }).on('keyup.' + $.fastbinder.options.namespace, function (e) {
      var target = $(document.activeElement);
      if (target.is('input, textarea')) {
        if (isEnterKey(e)) {
          fireEventHandler(target, 'on-submit', e);
        } else {
          var fn = function () {
            fireEventHandler(target, 'on-keyup', e);
          };
          if ($.fastbinder.options.keyupDelay > 0) {
            clearTimeout(timeoutID);
            timeoutID = setTimeout(fn, $.fastbinder.options.keyupDelay);
          } else {
            fn();
          }
        }
      }
    });
  }

  function handleExternalLinks(e) {
    // Handle proper links
    var target = $(e.target);
    if (target.is('a') && target.attr('href') &&
      target.attr('href') !== '#' && !data(target, 'on-click')) {
      if ($.fastbinder.options.forceExternalLinks &&
        target.attr('href').toLowerCase().indexOf('http') === 0) {
        target.attr('target', '_blank');
      }
      return false;
    }
    return true;
  }

  // Public API

  $.fastbinder = function (options) {
    $.fastbinder.setOptions(options);
    $.fastbinder.destroy();
    $.fastbinder.init();
  };

  $.fastbinder.on = genericBinder;

  $.fastbinder.defaults = {
    namespace: 'fastbinder',
    controllerPrefix: '',
    hoverDelay: 50,
    keydownDelay: 0,
    keyupDelay: 50,
    scrollDelay: 50,
    forceExternalLinks: true
  };

  $.fastbinder.setOptions = function (options) {
    $.fastbinder.options = $.extend($.fastbinder.options || $.fastbinder.defaults, options);
  };

  $.fastbinder.destroy = function () {
    $(document.body).off('.' + $.fastbinder.options.namespace);
    $(window).off('.' + $.fastbinder.options.namespace);
  };

  $.fastbinder.off = function (eventName) {
    $(document.body).off(eventName + '.' + $.fastbinder.options.namespace);
    $(window).off(eventName + '.' + $.fastbinder.options.namespace);
  };

  $.fastbinder.init = function () {
    $.fastbinder.on({ name: 'click', attribute: 'on-click', beforeTrigger: handleExternalLinks });
    $.fastbinder.on({ name: 'mousedown', attribute: 'on-mousedown' });
    $.fastbinder.on({ name: 'mouseup', attribute: 'on-mouseup' });
    $.fastbinder.on({ name: 'submit', attribute: 'on-submit', context: window });
    $.fastbinder.on({ name: 'change', attribute: 'on-change', context: window });
    $.fastbinder.on({ name: 'focusin', attribute: 'on-focus' });
    $.fastbinder.on({ name: 'focusout', attribute: 'on-blur' });

    $.fastbinder.on({
      name: 'scroll',
      attribute: 'on-scroll',
      context: window,
      delay: function () {
        return $.fastbinder.options.scrollDelay;
      },
      deferLookup: true
    });
    $.fastbinder.on({
      name: 'mousemove',
      attribute: 'on-hover',
      delay: function (target) {
        return data(target, 'hover-delay') || $.fastbinder.options.hoverDelay;
      },
      deferLookup: true
    });

    initKeyupHandler();
  };

}(window.jQuery));
<|endoftext|>


<commit_before>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return ;
    if (move !== null) {
        move === move;
    } else {
        move === getInput();
    }

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return ;
    if (move !== null) {
        move === move;
    } else {
        move === randomPlay();
    }

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    /* YOUR CODE HERE */

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
    return [playerWins, computerWins];
}

<commit_msg>RPS - Unit 4 Homework - 2nd Attempt<commit_after>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.");
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move || getInput();
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return move || randomPlay();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    /* YOUR CODE HERE */
    if (playerMove === computerMove) {
        winner = 'tie';
    } else if (playerMove === 'rock' && computerMove === 'scissors') {
        winner = 'player';
    } else if (playerMove === 'paper' && computerMove === 'rock') {
        winner = 'player';
    } else if (playerMove === 'scissors' && computerMove === 'paper') {
        winner = 'player';
    } else if (playerMove === 'rock' && computerMove === 'paper') {
        winner = 'computer';
    } else if (playerMove === 'paper' && computerMove === 'scissors') {
        winner = 'computer';
    } else if (playerMove === 'scissors' && computerMove === 'rock') {
        winner = 'computer';
    }
    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
    return [playerWins, computerWins];
}

<|endoftext|>


<commit_before>import React, { useState, useEffect } from 'react';
import { c } from 'ttag';
import {
    SubTitle,
    Alert,
    DowngradeModal,
    MozillaInfoPanel,
    useSubscription,
    Loader,
    usePlans,
    useApi,
    useUser,
    useModals,
    useEventManager,
    useNotifications
} from 'react-components';

import { checkSubscription, deleteSubscription } from 'proton-shared/lib/api/payments';
import { DEFAULT_CURRENCY, DEFAULT_CYCLE } from 'proton-shared/lib/constants';
import { getPlans, isBundleEligible } from 'proton-shared/lib/helpers/subscription';

import SubscriptionModal from './subscription/SubscriptionModal';
import { mergePlansMap, getCheckParams } from './subscription/helpers';
import UpgradeModal from './subscription/UpgradeModal';
import PlansTable from './PlansTable';

const PlansSection = () => {
    const { call } = useEventManager();
    const { createNotification } = useNotifications();
    const { createModal } = useModals();
    const [user] = useUser();
    const { isFree } = user;
    const [subscription = {}, loadingSubscription] = useSubscription();
    const [plans = [], loadingPlans] = usePlans();
    const api = useApi();

    const [showUpgradeModal, setShowUpgradeModel] = useState(false);
    const [currency, setCurrency] = useState(DEFAULT_CURRENCY);
    const [cycle, setCycle] = useState(DEFAULT_CYCLE);
    const bundleEligible = isBundleEligible(subscription);
    const { CouponCode, Plans = [] } = subscription;
    const names = getPlans(subscription)
        .map(({ Title }) => Title)
        .join(c('Separator, spacing is important').t` and `);

    const handleUnsubscribe = async () => {
        await api(deleteSubscription());
        await call();
        createNotification({ text: c('Success').t`You have successfully unsubscribed` });
    };

    const handleOpenModal = () => {
        if (isFree) {
            return createNotification({ type: 'error', text: c('Info').t`You already have a free account` });
        }
        createModal(<DowngradeModal onConfirm={handleUnsubscribe} />);
    };

    const handleModal = (newPlansMap) => async () => {
        if (!newPlansMap) {
            handleOpenModal();
            return;
        }

        const plansMap = mergePlansMap(newPlansMap, subscription);
        const couponCode = CouponCode ? CouponCode : undefined; // From current subscription; CouponCode can be null
        const { Coupon } = await api(
            checkSubscription(getCheckParams({ plans, plansMap, currency, cycle, coupon: couponCode }))
        );
        const coupon = Coupon ? Coupon.Code : undefined; // Coupon can equals null

        createModal(
            <SubscriptionModal
                subscription={subscription}
                plansMap={plansMap}
                coupon={coupon}
                currency={currency}
                cycle={cycle}
            />
        );
    };

    useEffect(() => {
        if (loadingPlans || loadingSubscription) {
            return;
        }
        const [{ Currency, Cycle } = {}] = plans;
        setCurrency(subscription.Currency || Currency);
        setCycle(subscription.Cycle || Cycle);
        if (isFree) {
            setShowUpgradeModel(true);
        }
    }, [loadingSubscription, loadingPlans]);

    useEffect(() => {
        if (showUpgradeModal) {
            createModal(<UpgradeModal plans={plans} onUpgrade={handleModal({ plus: 1 })} />);
        }
    }, [showUpgradeModal]);

    if (subscription.isManagedByMozilla) {
        return (
            <>
                <SubTitle>{c('Title').t`Plans`}</SubTitle>
                <MozillaInfoPanel />
            </>
        );
    }

    if (loadingSubscription || loadingPlans) {
        return (
            <>
                <SubTitle>{c('Title').t`Plans`}</SubTitle>
                <Loader />
            </>
        );
    }

    return (
        <>
            <SubTitle>{c('Title').t`Plans`}</SubTitle>
            <Alert learnMore="https://protonmail.com/support/knowledge-base/paid-plans/">
                {bundleEligible ? (

{c('Info')
                        .t`Get 20% bundle discount when you purchase ProtonMail and ProtonVPN together.`}

                ) : null}
                {Plans.length ?
{c('Info').t`You are currently subscribed to ${names}.`}
 : null}
            </Alert>
            <PlansTable
                currency={currency}
                cycle={cycle}
                updateCurrency={setCurrency}
                updateCycle={setCycle}
                onSelect={handleModal}
                user={user}
                subscription={subscription}
                plans={plans}
            />

* {c('Info concerning plan features').t`denotes customizable features`}

        </>
    );
};

export default PlansSection;
<commit_msg>Remove UpgradeModal<commit_after>import React, { useState, useEffect } from 'react';
import { c } from 'ttag';
import {
    SubTitle,
    Alert,
    DowngradeModal,
    MozillaInfoPanel,
    useSubscription,
    Loader,
    usePlans,
    useApi,
    useUser,
    useModals,
    useEventManager,
    useNotifications
} from 'react-components';

import { checkSubscription, deleteSubscription } from 'proton-shared/lib/api/payments';
import { DEFAULT_CURRENCY, DEFAULT_CYCLE } from 'proton-shared/lib/constants';
import { getPlans, isBundleEligible } from 'proton-shared/lib/helpers/subscription';

import SubscriptionModal from './subscription/SubscriptionModal';
import { mergePlansMap, getCheckParams } from './subscription/helpers';
import PlansTable from './PlansTable';

const PlansSection = () => {
    const { call } = useEventManager();
    const { createNotification } = useNotifications();
    const { createModal } = useModals();
    const [user] = useUser();
    const { isFree } = user;
    const [subscription = {}, loadingSubscription] = useSubscription();
    const [plans = [], loadingPlans] = usePlans();
    const api = useApi();

    const [currency, setCurrency] = useState(DEFAULT_CURRENCY);
    const [cycle, setCycle] = useState(DEFAULT_CYCLE);
    const bundleEligible = isBundleEligible(subscription);
    const { CouponCode, Plans = [] } = subscription;
    const names = getPlans(subscription)
        .map(({ Title }) => Title)
        .join(c('Separator, spacing is important').t` and `);

    const handleUnsubscribe = async () => {
        await api(deleteSubscription());
        await call();
        createNotification({ text: c('Success').t`You have successfully unsubscribed` });
    };

    const handleOpenModal = () => {
        if (isFree) {
            return createNotification({ type: 'error', text: c('Info').t`You already have a free account` });
        }
        createModal(<DowngradeModal onConfirm={handleUnsubscribe} />);
    };

    const handleModal = (newPlansMap) => async () => {
        if (!newPlansMap) {
            handleOpenModal();
            return;
        }

        const plansMap = mergePlansMap(newPlansMap, subscription);
        const couponCode = CouponCode ? CouponCode : undefined; // From current subscription; CouponCode can be null
        const { Coupon } = await api(
            checkSubscription(getCheckParams({ plans, plansMap, currency, cycle, coupon: couponCode }))
        );
        const coupon = Coupon ? Coupon.Code : undefined; // Coupon can equals null

        createModal(
            <SubscriptionModal
                subscription={subscription}
                plansMap={plansMap}
                coupon={coupon}
                currency={currency}
                cycle={cycle}
            />
        );
    };

    useEffect(() => {
        if (loadingPlans || loadingSubscription) {
            return;
        }
        const [{ Currency, Cycle } = {}] = plans;
        setCurrency(subscription.Currency || Currency);
        setCycle(subscription.Cycle || Cycle);
    }, [loadingSubscription, loadingPlans]);

    if (subscription.isManagedByMozilla) {
        return (
            <>
                <SubTitle>{c('Title').t`Plans`}</SubTitle>
                <MozillaInfoPanel />
            </>
        );
    }

    if (loadingSubscription || loadingPlans) {
        return (
            <>
                <SubTitle>{c('Title').t`Plans`}</SubTitle>
                <Loader />
            </>
        );
    }

    return (
        <>
            <SubTitle>{c('Title').t`Plans`}</SubTitle>
            <Alert learnMore="https://protonmail.com/support/knowledge-base/paid-plans/">
                {bundleEligible ? (

{c('Info')
                        .t`Get 20% bundle discount when you purchase ProtonMail and ProtonVPN together.`}

                ) : null}
                {Plans.length ?
{c('Info').t`You are currently subscribed to ${names}.`}
 : null}
            </Alert>
            <PlansTable
                currency={currency}
                cycle={cycle}
                updateCurrency={setCurrency}
                updateCycle={setCycle}
                onSelect={handleModal}
                user={user}
                subscription={subscription}
                plans={plans}
            />

* {c('Info concerning plan features').t`denotes customizable features`}

        </>
    );
};

export default PlansSection;
<|endoftext|>


<commit_before>//
// Author: Nuno Aguiar

plugin("ZIP");
ow.loadObj();

var createTmp = false;

//Check if a Jar was repacked
function isRepackJar(aJarFilePath) {
	var res = true;

	var aJar = new ZIP();
	try {
		aJar.loadFile(aJarFilePath);
		var listJar = aJar.list();

		for(let i in listJar) {
			//if(listJar[i].name.match(/jarinjarloader/) && listJar[i].name.match(/eclipse/)) {
			if (listJar[i].name.match(/\/js\.jar/)) {
				res = false;
			}
		}
	} catch(e) { }
	aJar.close();

	return res;
}

function getModulesToExclude() {
	loadUnderscore();
	var plugins = __expr.split(/,/);
	var toExclude = [];

	var vad = io.readFile(getOpenAFJar() + "::versionsAndDeps.json");

	for(let i in plugins) {
		var libsOut = _.flatten($from(vad.plugins).equals("name", plugins[i]).equals("removable", true).select(function(r) { return r.deps; }));
		var libsIn  = _.flatten($from(vad.plugins).not().equals("name", plugins[i]).select(function(r) { return r.deps; }));

		toExclude = toExclude.concat(_.without(libsOut, libsIn));
	}

	toExclude = _.uniq(toExclude);
	for(var i in toExclude) {
		if (isDef(toExclude[i]) && toExclude[i].match(/^lib\//)) {
			toExclude[i] = toExclude[i].replace(/^lib\//, "");
		}
	}

	return toExclude;
}

function isRepacked() {
	return irj;
}

function repackIncludeFile(aZipPath, aFilePath) {
	includeMore[aZipPath] = {
		name: aZipPath,
		outside: true,
		outsideName: aFilePath
	}
}

function repackSetMainClass(aClass) {
	mainClass = aClass;
}

try {
  var curDir    = java.lang.System.getProperty("user.dir") + "";
  var classPath = getOpenAFJar();
  var os        = String(java.lang.System.getProperty("os.name"));
} catch (e) {
  logErr("Couldn't retrieve system properties: " + e.message);
  java.lang.System.exit(0);
}

log("Checking if repacking OpenAF for faster loading is needed...");

var zip    = new ZIP();
var zipNew = new ZIP();
var includeMore = {};
var mainClass = undefined;

var irj = isRepackJar(classPath);

try {
// Set .package.json

packJson = jsonParse(af.fromBytes2String(zip.streamGetFile(getOpenAFJar(), ".package.json")));
packJson.version = getVersion();

var fileDB = getOpenAFPath() + "/" + PACKAGESJSON_DB;

var packages = {};
var zipdb = new ZIP();
try {
	packages = af.fromJson(af.fromBytes2String(zipdb.streamGetFile(fileDB, PACKAGESJSON)));
} catch(e) {
	 if (!(e.message.match(/FileNotFoundException/))) logErr(e.message);
}

if (!isUndefined(packages)) {
	packages["OpenAF"] = packJson;
} else {
	packages = {};
	packages["OpenAF"] = packJson;
}

try {
	zipdb.streamPutFile(fileDB, PACKAGESJSON, af.fromString2Bytes(stringify(packages)));
} catch (e) {
	logErr(e.message);
}

// PreRepack actions
$from(ow.obj.fromObj2Array(getOPackLocalDB(), "path")).notEmpty("scripts.prerepack").select(function(r) {
	if (r.name == "OpenCli" && r.version != af.getVersion()) {
		logWarn("Please update OpenCli to match the version " + af.getVersion());
	} else {
		log("Executing prepack actions from oPack '" + r.name + "'");
		try {
			var s = new Function(r.scripts.prerepack);
			s();
		} catch(e) {
			logErr("opack '" + r.name + "': " + e);
		}
	}
});

if (!irj || __expr != "" || Object.keys(includeMore).length > 0) {
	var oldVersionFile = classPath.replace(/openaf.jar/, "openaf.jar.orig");

	if (!irj) {
		log("Backup to " + oldVersionFile);
		io.writeFileBytes(oldVersionFile, io.readFileBytes(classPath));
	}

	var toExclude = [];
	if (__expr != "") toExclude = getModulesToExclude();

	try {
		zip.loadFile(oldVersionFile);
	} catch(e) {
		logErr("For the repack operation, excluding or adding modules the original un-repacked openaf.jar version (openaf.jar.orig) is needed!");
		throw e;
	}

	var list = zip.list(oldVersionFile);
	list = merge(list, includeMore);

	var c = 0;
	for(let i in list) {
		c++;
		var el = list[i];

		lognl("Progress " + Math.round(c * 100 / Object.keys(list).length) + "% (" + c + "/" + Object.keys(list).length + ")\r");

		if (toExclude.indexOf(el.name) >= 0) {
			log("Excluding " + el.name);
			continue;
		}

		if(el.name.match(/\.jar$/)) {
			var zipTemp = new ZIP();

			if (el.name.match(/tools-attach.jar$/) &&
			    Packages.jodd.util.ClassLoaderUtil.findToolsJar() != null) {
				zipTemp.loadFile(String(Packages.jodd.util.ClassLoaderUtil.findToolsJar()));
			} else {
				if (!el.outside)
					zipTemp.load(zip.getFile(el.name));
				else
					zipTemp.loadFile(el.outsideName);
			}

			var listTemp = zipTemp.list();

			for (let ii in listTemp) {
				var elTemp = listTemp[ii];
				if (!(elTemp.name.match(/MANIFEST.MF$/)) && !(elTemp.name.match(/ECLIPSE_.RSA$/))) {
					zipNew.putFile(elTemp.name, zipTemp.getFile(elTemp.name));
				}
			}
			zipTemp.close();
		} else {
			if( el.name.match(/MANIFEST.MF$/) ) {
				var str;

				str = af.fromBytes2String(zip.getFile(el.name));

				var newClass = (isDef(mainClass)) ? mainClass : "openaf.AFCmdOS";
				if ((str.match(/jarinjarloader/) && str.match(/eclipse/) )) {
					str = str.replace(/org\.eclipse\.jdt\.internal\.jarinjarloader\.JarRsrcLoader/, newClass);
				} else {
					str = str.replace(/^Main-Class: .+$/m, "Main-Class: " + newClass);
                }
				zipNew.putFile(el.name, af.fromString2Bytes(str));
			} else {
				if (!(el.name.match(/jarinjarloader/))) {
					if (!el.outside)
						zipNew.putFile(el.name, zip.getFile(el.name));
					else
						zipNew.putFile(el.name, io.readFileBytes(el.outsideName));
				}
			}
		}
	}

	ow.loadObj();
	var ilist = "JarIndex-Version: 1.0\n\n" +
				$from(ow.obj.fromObj2Array(zipNew.list()))
				.notStarts("name", "META-INF/")
				.ends("name", "/")
				.select((r)=>{ return r.name.substr(0, r.name.length -1); })
				.join("\n");
	zipNew.putFile("META-INF/INDEX.LIST", af.fromString2Bytes(ilist));
	log("Writing new repacked openaf.jar...");
	zipNew.generate2File(classPath + ".tmp", {"compressionLevel": 9}, true);
	createTmp = true;
	zip.close();
	zipNew.close();
} else {
	log("OpenAF is repacked.");
}

if (createTmp) {
	io.writeFileBytes(classPath.replace(/\\/g, "/"), io.readFileBytes(classPath.replace(/openaf.jar/, "openaf.jar.tmp")));
	io.rm(classPath.replace(/openaf.jar/, "openaf.jar.tmp"));
}

log("Done repacking OpenAF.jar");
// We need to stop (but no longer needed)
//java.lang.System.exit(0);
} catch(e) { printErr(e); if (isDef(e.javaException)) se.javaException.printStackTrace(); }<commit_msg>repack url<commit_after>//
// Author: Nuno Aguiar

plugin("ZIP");
ow.loadObj();

var createTmp = false;

//Check if a Jar was repacked
function isRepackJar(aJarFilePath) {
	var res = true;

	var aJar = new ZIP();
	try {
		aJar.loadFile(aJarFilePath);
		var listJar = aJar.list();

		for(let i in listJar) {
			//if(listJar[i].name.match(/jarinjarloader/) && listJar[i].name.match(/eclipse/)) {
			if (listJar[i].name.match(/\/js\.jar/)) {
				res = false;
			}
		}
	} catch(e) { }
	aJar.close();

	return res;
}

function getModulesToExclude() {
	loadUnderscore();
	var plugins = __expr.split(/,/);
	var toExclude = [];

	var vad = io.readFile(getOpenAFJar() + "::versionsAndDeps.json");

	for(let i in plugins) {
		var libsOut = _.flatten($from(vad.plugins).equals("name", plugins[i]).equals("removable", true).select(function(r) { return r.deps; }));
		var libsIn  = _.flatten($from(vad.plugins).not().equals("name", plugins[i]).select(function(r) { return r.deps; }));

		toExclude = toExclude.concat(_.without(libsOut, libsIn));
	}

	toExclude = _.uniq(toExclude);
	for(var i in toExclude) {
		if (isDef(toExclude[i]) && toExclude[i].match(/^lib\//)) {
			toExclude[i] = toExclude[i].replace(/^lib\//, "");
		}
	}

	return toExclude;
}

function isRepacked() {
	return irj;
}

function repackIncludeFile(aZipPath, aFilePath) {
	includeMore[aZipPath] = {
		name: aZipPath,
		outside: true,
		outsideName: aFilePath
	}
}

function repackSetMainClass(aClass) {
	mainClass = aClass;
}

try {
  var curDir    = java.lang.System.getProperty("user.dir") + "";
  var classPath = getOpenAFJar();
  var os        = String(java.lang.System.getProperty("os.name"));
} catch (e) {
  logErr("Couldn't retrieve system properties: " + e.message);
  java.lang.System.exit(0);
}

log("Checking if repacking OpenAF for faster loading is needed...");

var zip    = new ZIP();
var zipNew = new ZIP();
var includeMore = {};
var mainClass = undefined;

var irj = isRepackJar(classPath);

try {
// Set .package.json

packJson = jsonParse(af.fromBytes2String(zip.streamGetFile(getOpenAFJar(), ".package.json")));
packJson.version = getVersion();

var fileDB = getOpenAFPath() + "/" + PACKAGESJSON_DB;

var packages = {};
var zipdb = new ZIP();
try {
	packages = af.fromJson(af.fromBytes2String(zipdb.streamGetFile(fileDB, PACKAGESJSON)));
} catch(e) {
	 if (!(e.message.match(/FileNotFoundException/))) logErr(e.message);
}

if (!isUndefined(packages)) {
	packages["OpenAF"] = packJson;
} else {
	packages = {};
	packages["OpenAF"] = packJson;
}

try {
	zipdb.streamPutFile(fileDB, PACKAGESJSON, af.fromString2Bytes(stringify(packages)));
} catch (e) {
	logErr(e.message);
}

// PreRepack actions
$from(ow.obj.fromObj2Array(getOPackLocalDB(), "path")).notEmpty("scripts.prerepack").select(function(r) {
	if (r.name == "OpenCli" && r.version != af.getVersion()) {
		logWarn("Please update OpenCli to match the version " + af.getVersion());
		if (io.fileExists(r.path + "/.url")) {
			logWarn("by executing 'opack install " + eval( io.readFileYAML(r.path + "/.url").c ) + "'" );
		}
	} else {
		log("Executing prepack actions from oPack '" + r.name + "'");
		try {
			var s = new Function(r.scripts.prerepack);
			s();
		} catch(e) {
			logErr("opack '" + r.name + "': " + e);
		}
	}
});

if (!irj || __expr != "" || Object.keys(includeMore).length > 0) {
	var oldVersionFile = classPath.replace(/openaf.jar/, "openaf.jar.orig");

	if (!irj) {
		log("Backup to " + oldVersionFile);
		io.writeFileBytes(oldVersionFile, io.readFileBytes(classPath));
	}

	var toExclude = [];
	if (__expr != "") toExclude = getModulesToExclude();

	try {
		zip.loadFile(oldVersionFile);
	} catch(e) {
		logErr("For the repack operation, excluding or adding modules the original un-repacked openaf.jar version (openaf.jar.orig) is needed!");
		throw e;
	}

	var list = zip.list(oldVersionFile);
	list = merge(list, includeMore);

	var c = 0;
	for(let i in list) {
		c++;
		var el = list[i];

		lognl("Progress " + Math.round(c * 100 / Object.keys(list).length) + "% (" + c + "/" + Object.keys(list).length + ")\r");

		if (toExclude.indexOf(el.name) >= 0) {
			log("Excluding " + el.name);
			continue;
		}

		if(el.name.match(/\.jar$/)) {
			var zipTemp = new ZIP();

			if (el.name.match(/tools-attach.jar$/) &&
			    Packages.jodd.util.ClassLoaderUtil.findToolsJar() != null) {
				zipTemp.loadFile(String(Packages.jodd.util.ClassLoaderUtil.findToolsJar()));
			} else {
				if (!el.outside)
					zipTemp.load(zip.getFile(el.name));
				else
					zipTemp.loadFile(el.outsideName);
			}

			var listTemp = zipTemp.list();

			for (let ii in listTemp) {
				var elTemp = listTemp[ii];
				if (!(elTemp.name.match(/MANIFEST.MF$/)) && !(elTemp.name.match(/ECLIPSE_.RSA$/))) {
					zipNew.putFile(elTemp.name, zipTemp.getFile(elTemp.name));
				}
			}
			zipTemp.close();
		} else {
			if( el.name.match(/MANIFEST.MF$/) ) {
				var str;

				str = af.fromBytes2String(zip.getFile(el.name));

				var newClass = (isDef(mainClass)) ? mainClass : "openaf.AFCmdOS";
				if ((str.match(/jarinjarloader/) && str.match(/eclipse/) )) {
					str = str.replace(/org\.eclipse\.jdt\.internal\.jarinjarloader\.JarRsrcLoader/, newClass);
				} else {
					str = str.replace(/^Main-Class: .+$/m, "Main-Class: " + newClass);
                }
				zipNew.putFile(el.name, af.fromString2Bytes(str));
			} else {
				if (!(el.name.match(/jarinjarloader/))) {
					if (!el.outside)
						zipNew.putFile(el.name, zip.getFile(el.name));
					else
						zipNew.putFile(el.name, io.readFileBytes(el.outsideName));
				}
			}
		}
	}

	ow.loadObj();
	var ilist = "JarIndex-Version: 1.0\n\n" +
				$from(ow.obj.fromObj2Array(zipNew.list()))
				.notStarts("name", "META-INF/")
				.ends("name", "/")
				.select((r)=>{ return r.name.substr(0, r.name.length -1); })
				.join("\n");
	zipNew.putFile("META-INF/INDEX.LIST", af.fromString2Bytes(ilist));
	log("Writing new repacked openaf.jar...");
	zipNew.generate2File(classPath + ".tmp", {"compressionLevel": 9}, true);
	createTmp = true;
	zip.close();
	zipNew.close();
} else {
	log("OpenAF is repacked.");
}

if (createTmp) {
	io.writeFileBytes(classPath.replace(/\\/g, "/"), io.readFileBytes(classPath.replace(/openaf.jar/, "openaf.jar.tmp")));
	io.rm(classPath.replace(/openaf.jar/, "openaf.jar.tmp"));
}

log("Done repacking OpenAF.jar");
// We need to stop (but no longer needed)
//java.lang.System.exit(0);
} catch(e) { printErr(e); if (isDef(e.javaException)) se.javaException.printStackTrace(); }<|endoftext|>


<commit_before>import { EventEmitter } from 'events';
import Promise from 'pinkie';
import timeLimit from 'time-limit-promise';
import promisifyEvent from 'promisify-event';
import noop from 'noop-fn';
import LocalBrowserConnection from '../browser-connection/local';
import { MESSAGE, getText } from '../messages';
import remove from '../utils/array-remove';

export default class BrowserSet extends EventEmitter {
    constructor (connections) {
        super();

        this.READY_TIMEOUT   = 30000;
        this.RELEASE_TIMEOUT = 10000;

        this.pendingReleases = [];

        this.connections = connections;

        this.browserErrorHandler = error => this.emit('error', error);

        connections.forEach(bc => bc.on('error', this.browserErrorHandler));

        //NOTE: We're setting an empty error handler, because Node kills the process on an 'error' event
        //if there is no handler. See: https://nodejs.org/api/events.html#events_class_events_eventemitter
        this.on('error', noop);
    }

    static async _waitIdle (bc) {
        if (bc.idle || bc.closed || !bc.ready)
            return;

        await Promise.race([
            promisifyEvent(bc, 'idle'),
            promisifyEvent(bc, 'closed')
        ]);
    }

    static async _closeConnection (bc) {
        if (bc.closed || !bc.ready)
            return;

        bc.close();

        await promisifyEvent(bc, 'closed');
    }

    _waitConnectionsReady () {
        var connectionsReadyPromise = Promise.all(
            this.connections
                .filter(bc => !bc.ready)
                .map(bc => promisifyEvent(bc, 'ready'))
        );

        var timeoutError = new Error(getText(MESSAGE.cantEstablishBrowserConnection));

        return timeLimit(connectionsReadyPromise, this.READY_TIMEOUT, { rejectWith: timeoutError });
    }

    _checkForDisconnections () {
        var disconnectedUserAgents = this.connections
            .filter(bc => bc.closed)
            .map(bc => bc.userAgent);

        if (disconnectedUserAgents.length)
            throw new Error(getText(MESSAGE.cantRunAgainstDisconnectedBrowsers, disconnectedUserAgents.join(', ')));
    }

    //API
    static from (connections) {
        var browserSet = new BrowserSet(connections);

        var prepareConnection = Promise.resolve()
            .then(() => {
                browserSet._checkForDisconnections();
                return browserSet._waitConnectionsReady();
            })
            .then(() => browserSet);

        return Promise
            .race([
                prepareConnection,
                promisifyEvent(browserSet, 'error')
            ])
            .catch(async error => {
                await browserSet.dispose();

                throw error;
            });
    }

    releaseConnection (bc) {
        if (this.connections.indexOf(bc) < 0)
            return Promise.resolve();

        remove(this.connections, bc);

        bc.removeListener('error', this.browserErrorHandler);

        var appropriateStateSwitch = bc instanceof LocalBrowserConnection ?
                                     BrowserSet._closeConnection(bc) :
                                     BrowserSet._waitIdle(bc);

        var release = timeLimit(appropriateStateSwitch, this.RELEASE_TIMEOUT).then(() => remove(this.pendingReleases, release));

        this.pendingReleases.push(release);

        return release;
    }

    async dispose () {
        // FIXME: make a shallow copy of `this.connections`, because it
        // will be modified inside `releaseConnection`.
        // Not the most clear piece of code here. I hope we can do
        // better. But I'm out of ideas for now.
        this.connections.slice().forEach(bc => this.releaseConnection(bc));

        await Promise.all(this.pendingReleases);
    }
}
<commit_msg>Fixed '_waitIdle' method for browser set (closes #271)<commit_after>import { EventEmitter } from 'events';
import Promise from 'pinkie';
import timeLimit from 'time-limit-promise';
import promisifyEvent from 'promisify-event';
import noop from 'noop-fn';
import LocalBrowserConnection from '../browser-connection/local';
import { MESSAGE, getText } from '../messages';
import remove from '../utils/array-remove';

export default class BrowserSet extends EventEmitter {
    constructor (connections) {
        super();

        this.READY_TIMEOUT   = 30000;
        this.RELEASE_TIMEOUT = 10000;

        this.pendingReleases = [];

        this.connections = connections;

        this.browserErrorHandler = error => this.emit('error', error);

        connections.forEach(bc => bc.on('error', this.browserErrorHandler));

        // NOTE: We're setting an empty error handler, because Node kills the process on an 'error' event
        // if there is no handler. See: https://nodejs.org/api/events.html#events_class_events_eventemitter
        this.on('error', noop);
    }

    static async _waitIdle (bc) {
        if (bc.idle || bc.closed || !bc.ready)
            return;

        var idlePromise  = promisifyEvent(bc, 'idle');
        var closePromise = promisifyEvent(bc, 'closed');

        await Promise.race([
            idlePromise,
            closePromise
        ]);

        // NOTE: We must delete both listeners from the browser connection after
        // one of them is executed to avoid exceeding the subscribers limit.
        idlePromise.cancel();
        closePromise.cancel();
    }

    static async _closeConnection (bc) {
        if (bc.closed || !bc.ready)
            return;

        bc.close();

        await promisifyEvent(bc, 'closed');
    }

    _waitConnectionsReady () {
        var connectionsReadyPromise = Promise.all(
            this.connections
                .filter(bc => !bc.ready)
                .map(bc => promisifyEvent(bc, 'ready'))
        );

        var timeoutError = new Error(getText(MESSAGE.cantEstablishBrowserConnection));

        return timeLimit(connectionsReadyPromise, this.READY_TIMEOUT, { rejectWith: timeoutError });
    }

    _checkForDisconnections () {
        var disconnectedUserAgents = this.connections
            .filter(bc => bc.closed)
            .map(bc => bc.userAgent);

        if (disconnectedUserAgents.length)
            throw new Error(getText(MESSAGE.cantRunAgainstDisconnectedBrowsers, disconnectedUserAgents.join(', ')));
    }

    //API
    static from (connections) {
        var browserSet = new BrowserSet(connections);

        var prepareConnection = Promise.resolve()
            .then(() => {
                browserSet._checkForDisconnections();
                return browserSet._waitConnectionsReady();
            })
            .then(() => browserSet);

        return Promise
            .race([
                prepareConnection,
                promisifyEvent(browserSet, 'error')
            ])
            .catch(async error => {
                await browserSet.dispose();

                throw error;
            });
    }

    releaseConnection (bc) {
        if (this.connections.indexOf(bc) < 0)
            return Promise.resolve();

        remove(this.connections, bc);

        bc.removeListener('error', this.browserErrorHandler);

        var appropriateStateSwitch = bc instanceof LocalBrowserConnection ?
                                     BrowserSet._closeConnection(bc) :
                                     BrowserSet._waitIdle(bc);

        var release = timeLimit(appropriateStateSwitch, this.RELEASE_TIMEOUT).then(() => remove(this.pendingReleases, release));

        this.pendingReleases.push(release);

        return release;
    }

    async dispose () {
        // FIXME: make a shallow copy of `this.connections`, because it
        // will be modified inside `releaseConnection`.
        // Not the most clear piece of code here. I hope we can do
        // better. But I'm out of ideas for now.
        this.connections.slice().forEach(bc => this.releaseConnection(bc));

        await Promise.all(this.pendingReleases);
    }
}
<|endoftext|>