<commit_before>/*
	TemPIC - Copyright (c) PotcFdk, 2014 - 2017

	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.
*/

// Detect browser capabilities
function isUpToDate () {
	return Modernizr.filereader && Modernizr.flexbox && window.FormData !== undefined
}

function canUseFormData () {
	return window.FormData !== undefined
}

function tempicOnLoad () {
	if (isUpToDate ())
		document.getElementById("browser_warning_text").style.display = 'none';
}

function resetTitle () {
	if ($.type(album_name) == 'string')
		document.title = album_name + " - " + instance_name;
	else
		document.title = instance_name;
}

function initRemainingLifetime (remaining)
{
	function updateRemainingLifetime () {
		if (remaining > 0) {
			$('#lifetime_text').html('
Album removal Remaining time: '
				+ millisecondsToAccurateStr (remaining*1000)+'
');
			-- remaining;
		} else {
			$('#lifetime_text').html('
Removed '
				+ 'This album has been removed.
');
			setInterval (function() { window.location = url_base; }, 1000);
		}
	}
	updateRemainingLifetime();
	setInterval (updateRemainingLifetime, 1000);
}

function retryThumbnail (obj) {
	var src = obj.data('src');

	if (!src)
		throw new Error('Cannot retry thumbnail: Object has no src!');

	obj.data('failure', false);
	obj.attr('src', src);
}

function onThumbnailLoad (obj) {
	obj = $(obj);
	if (!obj.data('failure')) {
		obj.removeClass('no-thumbnail');
		obj.attr('alt', 'Uploaded Image');
	}
}

function onThumbnailError (obj) {
	obj = $(obj);

	if (!obj.data('src'))
		obj.data('src', obj.attr('src'));

	if (!obj.data('failure')) {
		obj.data('failure', true);
		obj.attr('alt', 'Thumbnail currently unavailable.');
		obj.addClass('no-thumbnail');
		obj.attr('src', 'img/ico_loading.gif');
		setTimeout(retryThumbnail, 30000, obj);
	}

	info('Some thumbnails have not yet been generated.');
}

var fileBrowse;

$(function() {
	$('#div_filelist_preview').hide();
	$('#div_albumname_input').hide();
	$('#div_albumdescription_input').hide();
	$('#div_warn_element').hide();
	$('#warn_element').hide();
	$('#div_progressbar').hide();
	$('#progressbar').hide();
	$('#div_progresstext').hide();
	$(".checksum-field").hide();
	$("#button-file-wipe").hide();
	$("#button-upload").hide();
	$("#button-abort").hide();

	var upload_in_progress = false;

	var base_text = $('#checksums-toggle').text();
	var is_showing_checksums = false;
	$('#checksums-toggle').on('click', function() {
		if (is_showing_checksums) {
			is_showing_checksums = false;
			$(".checksum-field").hide(300);
			$('#checksums-toggle').text(base_text);
		} else {
			is_showing_checksums = true;
			$(".checksum-field").show(300);
			$('#checksums-toggle').text(base_text.replace("Show","Hide"));
		}
	});

	var fileInput = $('#file');
	fileBrowse = function () {
		// fileInput show()/hide():
		//  compatibility hack (e.g. older android devices)

		if (!isUpToDate ())
			fileInput.show ();
		fileInput.click();
		if (!isUpToDate ())
			fileInput.hide ();
	}

	var upload_started = 0;

	function uploadProgress(evt) {
	  if (evt.lengthComputable) {
		var percentComplete = evt.loaded * 100 / evt.total;
		var percentCompleteStr = Math.round(percentComplete).toString() + " %";
		var duration = (Date.now() - upload_started);
		var speed = evt.loaded / duration;
		$('#progressbar').attr('value', percentComplete.toString());
		$('#progresstext').html("Uploading: " + percentCompleteStr + "
"
			+ humanFileSize(evt.loaded) + " / " + humanFileSize(evt.total) + " total"
				+ " @ " + humanFileSize((speed*1000).toFixed(2)) + " per second
"
			+ "Elapsed: " + millisecondsToStr(duration) + "
"
			+ 'ETA: ' + millisecondsToStr((evt.total - evt.loaded)/speed));
		document.title = percentCompleteStr + " - " + instance_name + " (uploading)";
	  }
	  else {
		$('#progressbar').removeAttr('value');
	  }
	}

	function uploadBegin() {
		upload_in_progress = true;

		$("#button-file-wipe").hide();
		$("#button-upload").hide();
		$("#button-abort").show();
		$('#button-browse').prop('disabled', true);

		$('#lifetime').prop('disabled', true);

		$('#div_progress').hide();

		$('#div_progressbar').show();
		$('#progressbar').show();
		$('#div_progresstext').show();

		$('#div_upload_data').slideUp(400, 'swing', function() {
			$('#div_progress').slideDown(400, 'swing');
		});
	}

	function uploadEnd() {
		upload_in_progress = false;

		resetTitle();

		$("#button-file-wipe").show();
		$("#button-upload").show();
		$("#button-abort").hide();
		$('#button-browse').prop('disabled', false);

		$('#lifetime').prop('disabled', false);

		$('#div_progress').slideUp(200, 'swing', function() {
			$('#div_progressbar').hide();
			$('#progressbar').hide();
			$('#div_progresstext').hide();
		});

		$('#div_upload_data').slideDown(200, 'swing');
	}

	function uploadComplete(evt) {
		if (evt.target.status == 200) {
			if (evt.target.responseText) {
				var response_obj;
				try {
					response_obj = JSON.parse(evt.target.responseText);
				} catch (e) {
					return uploadFailed(evt);
				}
				if (response_obj.success)
					window.location = response_obj.location || album_url;
				else if (response_obj.error_type == 'auth')
				{
					$("#upload-deny_element").show();
					return uploadEnd();
				}
				else
					return uploadFailed(evt);
			} else {
				window.location = url_base;
			}
		} else if (evt.target.status == 401) {
			$("#upload-deny_element").show();

			var response_obj;
			try {
				response_obj = JSON.parse(evt.target.responseText);
			} catch (e) {
				return uploadEnd();
			}
			if (response_obj.location)
				window.location = response_obj.location;

			return uploadEnd();
		} else {
			return uploadFailed(evt);
		}
	}

	function uploadFailed(evt) {
		warn("There was an error attempting to upload the file.");
		uploadEnd();
	}

	function uploadCanceled(evt) {
		warn("The upload has been canceled by the user or the browser dropped the connection.");
		uploadEnd();
	}

	// UploadManager observers

	function observerFilePreview(files) {
		if (files.length) {
			$("#div_filelist_preview_box").empty();

			for (var x = 0; x < files.length; x++)
			{
				var entry = document.createElement("div");
					entry.setAttribute("class", "row");
				var col = document.createElement("div");
					col.setAttribute("class", "col-md-12");

				var inner_entry = document.createElement("div")
					inner_entry.setAttribute("class", "file-preview-entry");
					inner_entry.setAttribute("onclick", "um.delFile(".concat(x,")"));

				var button = document.createElement("button");
					button.setAttribute("class", "btn-file-remove-base btn-file-remove");
					button.setAttribute("type", "button");
				var txt = document.createTextNode("\u00D7");
				button.appendChild(txt);

				var filename = document.createTextNode(files[x].name);
				var filesize = document.createElement("span");
				filesize.setAttribute("class", "text-muted");
				filesize.innerHTML = " (" + humanFileSize(files[x].size, true) + ")";

				inner_entry.appendChild(button);
				inner_entry.appendChild(filename);
				inner_entry.appendChild(filesize);

				col.appendChild(inner_entry)

				entry.appendChild(col);

				document.getElementById("div_filelist_preview_box").appendChild(entry);
			}

			$("#div_filelist_preview").show();
		}
		else
			$("#div_filelist_preview").hide();
	}

	function observerAlbumForm(files) {
		if(files.length) {
			$('#div_albumname_input').show();
			$('#div_albumdescription_input').show();
		}
		else {
			$('#div_albumname_input').hide();
			$('#div_albumdescription_input').hide();
		}
	}

	function observerFileOverview(files) {
		if(files.length == 1)
			$("#file-overview-text").text(files[0].name.toString().concat(" (", humanFileSize(um.getUploadSize(), true), ")"));
		else if(files.length > 1)
			$("#file-overview-text").text(files.length.toString().concat(" files ready to upload (", humanFileSize(um.getUploadSize(), true),")"));
		else
			$("#file-overview-text").text("");
	}

	function observerFileWipeButton(files) {
		if(files.length)
			$("#button-file-wipe").show();
		else
			$("#button-file-wipe").hide();
	}

	function observerUploadButton(files) {
		if(files.length)
			$("#button-upload").show();
		else
			$("#button-upload").hide();
	}

	// UploadManager - global

	um = new UploadManager(size_limit, url_base, uploadProgress, uploadComplete, uploadFailed, uploadCanceled);
	um.registerFileObserver(observerFileOverview);
	um.registerFileObserver(observerFileWipeButton);
	um.registerFileObserver(observerUploadButton);
	um.registerFileObserver(observerFilePreview)
	um.registerFileObserver(observerAlbumForm);

	// File upload form setup.

	$("[data-hide]").on("click", function(){
		$("." + $(this).attr("data-hide")).hide();
	});

	//Add eventListeners to input -> add values to UploadManager on change

	$("#file").on("change", function(e){
		var files = this.files;
		for(var x = 0; x < files.length; x++)
		{
			um.addFile(files[x]);
		}

		// reset input, as input type=file is read only
		// (!) compatibility hack: don't do this when FormData doesn't work
		if (canUseFormData ()) {
			$(this).wrap('<form>').closest('form').get(0).reset();
			$(this).unwrap();
		}
	});

	$("#lifetime").on("change", function(e){
		um.setLifetime(this.value);
	});

	$("#album_name").on("change", function(e){
		um.setAlbumName(this.value);
	});

	$("#album_description").on("change", function(e){
		um.setAlbumDescription(this.value);
	});

	// Drag&Drop feature setup

	dragCounter = 0; //necessary for entering/leaving child elements of html while dragging stuff

	$("html").on("dragenter", function(e){
		dragCounter++;
		e.preventDefault();
		if (upload_in_progress) return;
		$(this).addClass("draghover");
	});

	$("html").on("dragover", function(e){
		e.preventDefault();
	});

	$("html").on("dragend", function(e){
		e.preventDefault();
		dragCounter = 0;
		$(this).removeClass("draghover");
	});

	$("html").on("dragleave", function(e){
		dragCounter--;
		e.preventDefault();
		if(dragCounter == 0)
			$(this).removeClass("draghover");
	});

	$("html").on("drop", function(e){
		e.preventDefault();
		dragCounter = 0;
		$(this).removeClass("draghover");
		if (upload_in_progress) return;
		var files = e.originalEvent.dataTransfer.files;
		for (var x = 0; x < files.length; x++)
		{
			um.addFile(files[x]);
		}
	});

	$("#button-file-wipe").on("click", function(e){
		um.wipeFiles();
	});

	$("#button-abort").on("click", function(e){
		um.abort();
	});

	var btn = $('button[type=submit]');
	btn.prop('type', 'button');
	btn.on('click', function() {
		warn(); // Close the current warning, if applicable.

		um.send(um.makePOSTData());
		upload_started = Date.now();
		uploadBegin();
	});
});<commit_msg>feature: confirm before closing while uploading<commit_after>/*
	TemPIC - Copyright (c) PotcFdk, 2014 - 2017

	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.
*/

// Detect browser capabilities
function isUpToDate () {
	return Modernizr.filereader && Modernizr.flexbox && window.FormData !== undefined
}

function canUseFormData () {
	return window.FormData !== undefined
}

function tempicOnLoad () {
	if (isUpToDate ())
		document.getElementById("browser_warning_text").style.display = 'none';
}

function resetTitle () {
	if ($.type(album_name) == 'string')
		document.title = album_name + " - " + instance_name;
	else
		document.title = instance_name;
}

function initRemainingLifetime (remaining)
{
	function updateRemainingLifetime () {
		if (remaining > 0) {
			$('#lifetime_text').html('
Album removal Remaining time: '
				+ millisecondsToAccurateStr (remaining*1000)+'
');
			-- remaining;
		} else {
			$('#lifetime_text').html('
Removed '
				+ 'This album has been removed.
');
			setInterval (function() { window.location = url_base; }, 1000);
		}
	}
	updateRemainingLifetime();
	setInterval (updateRemainingLifetime, 1000);
}

function retryThumbnail (obj) {
	var src = obj.data('src');

	if (!src)
		throw new Error('Cannot retry thumbnail: Object has no src!');

	obj.data('failure', false);
	obj.attr('src', src);
}

function onThumbnailLoad (obj) {
	obj = $(obj);
	if (!obj.data('failure')) {
		obj.removeClass('no-thumbnail');
		obj.attr('alt', 'Uploaded Image');
	}
}

function onThumbnailError (obj) {
	obj = $(obj);

	if (!obj.data('src'))
		obj.data('src', obj.attr('src'));

	if (!obj.data('failure')) {
		obj.data('failure', true);
		obj.attr('alt', 'Thumbnail currently unavailable.');
		obj.addClass('no-thumbnail');
		obj.attr('src', 'img/ico_loading.gif');
		setTimeout(retryThumbnail, 30000, obj);
	}

	info('Some thumbnails have not yet been generated.');
}

var fileBrowse;

$(function() {
	$('#div_filelist_preview').hide();
	$('#div_albumname_input').hide();
	$('#div_albumdescription_input').hide();
	$('#div_warn_element').hide();
	$('#warn_element').hide();
	$('#div_progressbar').hide();
	$('#progressbar').hide();
	$('#div_progresstext').hide();
	$(".checksum-field").hide();
	$("#button-file-wipe").hide();
	$("#button-upload").hide();
	$("#button-abort").hide();

	var upload_in_progress = false;

	var base_text = $('#checksums-toggle').text();
	var is_showing_checksums = false;
	$('#checksums-toggle').on('click', function() {
		if (is_showing_checksums) {
			is_showing_checksums = false;
			$(".checksum-field").hide(300);
			$('#checksums-toggle').text(base_text);
		} else {
			is_showing_checksums = true;
			$(".checksum-field").show(300);
			$('#checksums-toggle').text(base_text.replace("Show","Hide"));
		}
	});

	var fileInput = $('#file');
	fileBrowse = function () {
		// fileInput show()/hide():
		//  compatibility hack (e.g. older android devices)

		if (!isUpToDate ())
			fileInput.show ();
		fileInput.click();
		if (!isUpToDate ())
			fileInput.hide ();
	}

	var upload_started = 0;

	function uploadProgress(evt) {
	  if (evt.lengthComputable) {
		var percentComplete = evt.loaded * 100 / evt.total;
		var percentCompleteStr = Math.round(percentComplete).toString() + " %";
		var duration = (Date.now() - upload_started);
		var speed = evt.loaded / duration;
		$('#progressbar').attr('value', percentComplete.toString());
		$('#progresstext').html("Uploading: " + percentCompleteStr + "
"
			+ humanFileSize(evt.loaded) + " / " + humanFileSize(evt.total) + " total"
				+ " @ " + humanFileSize((speed*1000).toFixed(2)) + " per second
"
			+ "Elapsed: " + millisecondsToStr(duration) + "
"
			+ 'ETA: ' + millisecondsToStr((evt.total - evt.loaded)/speed));
		document.title = percentCompleteStr + " - " + instance_name + " (uploading)";
	  }
	  else {
		$('#progressbar').removeAttr('value');
	  }
	}

	function uploadBegin() {
		upload_in_progress = true;
		window.onbeforeunload = function (e) {
			e = e || window.event;

			// For IE and Firefox prior to version 4
			if (e) {
				e.returnValue = 'Sure?';
			}

			// For Safari
			return 'Sure?';
		}

		$("#button-file-wipe").hide();
		$("#button-upload").hide();
		$("#button-abort").show();
		$('#button-browse').prop('disabled', true);

		$('#lifetime').prop('disabled', true);

		$('#div_progress').hide();

		$('#div_progressbar').show();
		$('#progressbar').show();
		$('#div_progresstext').show();

		$('#div_upload_data').slideUp(400, 'swing', function() {
			$('#div_progress').slideDown(400, 'swing');
		});
	}

	function uploadEnd() {
		upload_in_progress = false;
		window.onbeforeunload = undefined;

		resetTitle();

		$("#button-file-wipe").show();
		$("#button-upload").show();
		$("#button-abort").hide();
		$('#button-browse').prop('disabled', false);

		$('#lifetime').prop('disabled', false);

		$('#div_progress').slideUp(200, 'swing', function() {
			$('#div_progressbar').hide();
			$('#progressbar').hide();
			$('#div_progresstext').hide();
		});

		$('#div_upload_data').slideDown(200, 'swing');
	}

	function uploadComplete(evt) {
		if (evt.target.status == 200) {
			if (evt.target.responseText) {
				var response_obj;
				try {
					response_obj = JSON.parse(evt.target.responseText);
				} catch (e) {
					return uploadFailed(evt);
				}
				if (response_obj.success)
					window.location = response_obj.location || album_url;
				else if (response_obj.error_type == 'auth')
				{
					$("#upload-deny_element").show();
					return uploadEnd();
				}
				else
					return uploadFailed(evt);
			} else {
				window.location = url_base;
			}
		} else if (evt.target.status == 401) {
			$("#upload-deny_element").show();

			var response_obj;
			try {
				response_obj = JSON.parse(evt.target.responseText);
			} catch (e) {
				return uploadEnd();
			}
			if (response_obj.location)
				window.location = response_obj.location;

			return uploadEnd();
		} else {
			return uploadFailed(evt);
		}
	}

	function uploadFailed(evt) {
		warn("There was an error attempting to upload the file.");
		uploadEnd();
	}

	function uploadCanceled(evt) {
		warn("The upload has been canceled by the user or the browser dropped the connection.");
		uploadEnd();
	}

	// UploadManager observers

	function observerFilePreview(files) {
		if (files.length) {
			$("#div_filelist_preview_box").empty();

			for (var x = 0; x < files.length; x++)
			{
				var entry = document.createElement("div");
					entry.setAttribute("class", "row");
				var col = document.createElement("div");
					col.setAttribute("class", "col-md-12");

				var inner_entry = document.createElement("div")
					inner_entry.setAttribute("class", "file-preview-entry");
					inner_entry.setAttribute("onclick", "um.delFile(".concat(x,")"));

				var button = document.createElement("button");
					button.setAttribute("class", "btn-file-remove-base btn-file-remove");
					button.setAttribute("type", "button");
				var txt = document.createTextNode("\u00D7");
				button.appendChild(txt);

				var filename = document.createTextNode(files[x].name);
				var filesize = document.createElement("span");
				filesize.setAttribute("class", "text-muted");
				filesize.innerHTML = " (" + humanFileSize(files[x].size, true) + ")";

				inner_entry.appendChild(button);
				inner_entry.appendChild(filename);
				inner_entry.appendChild(filesize);

				col.appendChild(inner_entry)

				entry.appendChild(col);

				document.getElementById("div_filelist_preview_box").appendChild(entry);
			}

			$("#div_filelist_preview").show();
		}
		else
			$("#div_filelist_preview").hide();
	}

	function observerAlbumForm(files) {
		if(files.length) {
			$('#div_albumname_input').show();
			$('#div_albumdescription_input').show();
		}
		else {
			$('#div_albumname_input').hide();
			$('#div_albumdescription_input').hide();
		}
	}

	function observerFileOverview(files) {
		if(files.length == 1)
			$("#file-overview-text").text(files[0].name.toString().concat(" (", humanFileSize(um.getUploadSize(), true), ")"));
		else if(files.length > 1)
			$("#file-overview-text").text(files.length.toString().concat(" files ready to upload (", humanFileSize(um.getUploadSize(), true),")"));
		else
			$("#file-overview-text").text("");
	}

	function observerFileWipeButton(files) {
		if(files.length)
			$("#button-file-wipe").show();
		else
			$("#button-file-wipe").hide();
	}

	function observerUploadButton(files) {
		if(files.length)
			$("#button-upload").show();
		else
			$("#button-upload").hide();
	}

	// UploadManager - global

	um = new UploadManager(size_limit, url_base, uploadProgress, uploadComplete, uploadFailed, uploadCanceled);
	um.registerFileObserver(observerFileOverview);
	um.registerFileObserver(observerFileWipeButton);
	um.registerFileObserver(observerUploadButton);
	um.registerFileObserver(observerFilePreview)
	um.registerFileObserver(observerAlbumForm);

	// File upload form setup.

	$("[data-hide]").on("click", function(){
		$("." + $(this).attr("data-hide")).hide();
	});

	//Add eventListeners to input -> add values to UploadManager on change

	$("#file").on("change", function(e){
		var files = this.files;
		for(var x = 0; x < files.length; x++)
		{
			um.addFile(files[x]);
		}

		// reset input, as input type=file is read only
		// (!) compatibility hack: don't do this when FormData doesn't work
		if (canUseFormData ()) {
			$(this).wrap('<form>').closest('form').get(0).reset();
			$(this).unwrap();
		}
	});

	$("#lifetime").on("change", function(e){
		um.setLifetime(this.value);
	});

	$("#album_name").on("change", function(e){
		um.setAlbumName(this.value);
	});

	$("#album_description").on("change", function(e){
		um.setAlbumDescription(this.value);
	});

	// Drag&Drop feature setup

	dragCounter = 0; //necessary for entering/leaving child elements of html while dragging stuff

	$("html").on("dragenter", function(e){
		dragCounter++;
		e.preventDefault();
		if (upload_in_progress) return;
		$(this).addClass("draghover");
	});

	$("html").on("dragover", function(e){
		e.preventDefault();
	});

	$("html").on("dragend", function(e){
		e.preventDefault();
		dragCounter = 0;
		$(this).removeClass("draghover");
	});

	$("html").on("dragleave", function(e){
		dragCounter--;
		e.preventDefault();
		if(dragCounter == 0)
			$(this).removeClass("draghover");
	});

	$("html").on("drop", function(e){
		e.preventDefault();
		dragCounter = 0;
		$(this).removeClass("draghover");
		if (upload_in_progress) return;
		var files = e.originalEvent.dataTransfer.files;
		for (var x = 0; x < files.length; x++)
		{
			um.addFile(files[x]);
		}
	});

	$("#button-file-wipe").on("click", function(e){
		um.wipeFiles();
	});

	$("#button-abort").on("click", function(e){
		um.abort();
	});

	var btn = $('button[type=submit]');
	btn.prop('type', 'button');
	btn.on('click', function() {
		warn(); // Close the current warning, if applicable.

		um.send(um.makePOSTData());
		upload_started = Date.now();
		uploadBegin();
	});
});<|endoftext|>


<commit_before>/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
 * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/Style.js
 * @requires OpenLayers/Feature/Vector.js
 */

/**
 * Class: OpenLayers.StyleMap
 */
OpenLayers.StyleMap = OpenLayers.Class({

    /**
     * Property: styles
     * Hash of {<OpenLayers.Style>}, keyed by names of well known
     * rendering intents (e.g. "default", "temporary", "select").
     */
    styles: null,

    /**
     * Property: extendDefault
     * {Boolean} if true, every render intent will extend the symbolizers
     * specified for the "default" intent at rendering time. Otherwise, every
     * rendering intent will be treated as a completely independent style.
     */
    extendDefault: true,

    /**
     * Constructor: OpenLayers.StyleMap
     *
     * Parameters:
     * style   - {Object} Optional. Either a style hash, or a style object, or
     *           a hash of style objects (style hashes) keyed by rendering
     *           intent. If just one style hash or style object is passed,
     *           this will be used for all known render intents (default,
     *           select, temporary)
     * options - {Object} optional hash of additional options for this
     *           instance
     */
    initialize: function (style, options) {
        this.styles = {
            "default": new OpenLayers.Style(
                OpenLayers.Feature.Vector.style["default"]),
            "select": new OpenLayers.Style(
                OpenLayers.Feature.Vector.style["select"]),
            "temporary": new OpenLayers.Style(
                OpenLayers.Feature.Vector.style["temporary"])
        };

        // take whatever the user passed as style parameter and convert it
        // into parts of stylemap.
        if(style instanceof OpenLayers.Style) {
            // user passed a style object
            this.styles["default"] = style;
            this.styles["select"] = style;
            this.styles["temporary"] = style;
        } else if(typeof style == "object") {
            for(var key in style) {
                if(style[key] instanceof OpenLayers.Style) {
                    // user passed a hash of style objects
                    this.styles[key] = style[key];
                } else if(typeof style[key] == "object") {
                    // user passsed a hash of style hashes
                    this.styles[key] = new OpenLayers.Style(style[key]);
                } else {
                    // user passed a style hash (i.e. symbolizer)
                    this.styles["default"] = new OpenLayers.Style(style);
                    this.styles["select"] = new OpenLayers.Style(style);
                    this.styles["temporary"] = new OpenLayers.Style(style);
                    break;
                }
            }
        }
        OpenLayers.Util.extend(this, options);
    },

    /**
     * Method: destroy
     */
    destroy: function() {
        for(var key in this.styles) {
            this.styles[key].destroy();
        }
        this.styles = null;
    },

    /**
     * Method: createSymbolizer
     * Creates the symbolizer for a feature for a render intent.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature>} The feature to evaluate the rules
     *           of the intended style against.
     * intent  - {String} The intent determines the symbolizer that will be
     *           used to draw the feature. Well known intents are "default"
     *           (for just drawing the features), "select" (for selected
     *           features) and "temporary" (for drawing features).
     *
     * Returns:
     * {Object} symbolizer hash
     */
    createSymbolizer: function(feature, intent) {
        if(!feature) {
            feature = new OpenLayers.Feature.Vector();
        }
        if(!this.styles[intent]) {
            intent = "default";
        }
        feature.renderIntent = intent;
        var defaultSymbolizer = {};
        if(this.extendDefault && intent != "default") {
            defaultSymbolizer = this.styles["default"].createSymbolizer(feature);
        }
        return OpenLayers.Util.extend(defaultSymbolizer,
            this.styles[intent].createSymbolizer(feature));
    },

    /**
     * Method: addUniqueValueRules
     * Convenience method to create comparison rules for unique values of a
     * property. The rules will be added to the style object for a specified
     * rendering intent. This method is a shortcut for creating something like
     * the "unique value legends" familiar from well known desktop GIS systems
     *
     * Parameters:
     * renderIntent - {String} rendering intent to add the rules to
     * property     - {String} values of feature attributes to create the
     *                rules for
     * symbolizers  - {Object} Hash of symbolizers, keyed by the desired
     *                property values
     */
    addUniqueValueRules: function(renderIntent, property, symbolizers) {
        var rules = [];
        for (var value in symbolizers) {
            rules.push(new OpenLayers.Rule.Comparison({
                type: OpenLayers.Rule.Comparison.EQUAL_TO,
                property: property,
                value: value,
                symbolizer: symbolizers[value]}));
        }
        this.styles[renderIntent].addRules(rules);
    },

    CLASS_NAME: "OpenLayers.StyleMap"
});
<commit_msg>Modifying the addUniqueValueRules method to use filter subclass.  r=crschmidt (closes #1492)<commit_after>/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
 * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/Style.js
 * @requires OpenLayers/Feature/Vector.js
 */

/**
 * Class: OpenLayers.StyleMap
 */
OpenLayers.StyleMap = OpenLayers.Class({

    /**
     * Property: styles
     * Hash of {<OpenLayers.Style>}, keyed by names of well known
     * rendering intents (e.g. "default", "temporary", "select").
     */
    styles: null,

    /**
     * Property: extendDefault
     * {Boolean} if true, every render intent will extend the symbolizers
     * specified for the "default" intent at rendering time. Otherwise, every
     * rendering intent will be treated as a completely independent style.
     */
    extendDefault: true,

    /**
     * Constructor: OpenLayers.StyleMap
     *
     * Parameters:
     * style   - {Object} Optional. Either a style hash, or a style object, or
     *           a hash of style objects (style hashes) keyed by rendering
     *           intent. If just one style hash or style object is passed,
     *           this will be used for all known render intents (default,
     *           select, temporary)
     * options - {Object} optional hash of additional options for this
     *           instance
     */
    initialize: function (style, options) {
        this.styles = {
            "default": new OpenLayers.Style(
                OpenLayers.Feature.Vector.style["default"]),
            "select": new OpenLayers.Style(
                OpenLayers.Feature.Vector.style["select"]),
            "temporary": new OpenLayers.Style(
                OpenLayers.Feature.Vector.style["temporary"])
        };

        // take whatever the user passed as style parameter and convert it
        // into parts of stylemap.
        if(style instanceof OpenLayers.Style) {
            // user passed a style object
            this.styles["default"] = style;
            this.styles["select"] = style;
            this.styles["temporary"] = style;
        } else if(typeof style == "object") {
            for(var key in style) {
                if(style[key] instanceof OpenLayers.Style) {
                    // user passed a hash of style objects
                    this.styles[key] = style[key];
                } else if(typeof style[key] == "object") {
                    // user passsed a hash of style hashes
                    this.styles[key] = new OpenLayers.Style(style[key]);
                } else {
                    // user passed a style hash (i.e. symbolizer)
                    this.styles["default"] = new OpenLayers.Style(style);
                    this.styles["select"] = new OpenLayers.Style(style);
                    this.styles["temporary"] = new OpenLayers.Style(style);
                    break;
                }
            }
        }
        OpenLayers.Util.extend(this, options);
    },

    /**
     * Method: destroy
     */
    destroy: function() {
        for(var key in this.styles) {
            this.styles[key].destroy();
        }
        this.styles = null;
    },

    /**
     * Method: createSymbolizer
     * Creates the symbolizer for a feature for a render intent.
     *
     * Parameters:
     * feature - {<OpenLayers.Feature>} The feature to evaluate the rules
     *           of the intended style against.
     * intent  - {String} The intent determines the symbolizer that will be
     *           used to draw the feature. Well known intents are "default"
     *           (for just drawing the features), "select" (for selected
     *           features) and "temporary" (for drawing features).
     *
     * Returns:
     * {Object} symbolizer hash
     */
    createSymbolizer: function(feature, intent) {
        if(!feature) {
            feature = new OpenLayers.Feature.Vector();
        }
        if(!this.styles[intent]) {
            intent = "default";
        }
        feature.renderIntent = intent;
        var defaultSymbolizer = {};
        if(this.extendDefault && intent != "default") {
            defaultSymbolizer = this.styles["default"].createSymbolizer(feature);
        }
        return OpenLayers.Util.extend(defaultSymbolizer,
            this.styles[intent].createSymbolizer(feature));
    },

    /**
     * Method: addUniqueValueRules
     * Convenience method to create comparison rules for unique values of a
     * property. The rules will be added to the style object for a specified
     * rendering intent. This method is a shortcut for creating something like
     * the "unique value legends" familiar from well known desktop GIS systems
     *
     * Parameters:
     * renderIntent - {String} rendering intent to add the rules to
     * property     - {String} values of feature attributes to create the
     *                rules for
     * symbolizers  - {Object} Hash of symbolizers, keyed by the desired
     *                property values
     */
    addUniqueValueRules: function(renderIntent, property, symbolizers) {
        var rules = [];
        for (var value in symbolizers) {
            rules.push(new OpenLayers.Rule({
                symbolizer: symbolizers[value],
                filter: new OpenLayers.Filter.Comparison({
                    type: OpenLayers.Filter.Comparison.EQUAL_TO,
                    property: property,
                    value: value
                })
            }));
        }
        this.styles[renderIntent].addRules(rules);
    },

    CLASS_NAME: "OpenLayers.StyleMap"
});
<|endoftext|>


<commit_before>/** clipboard_manager.js
 *  This utility handles the Copy/Paste behavior for the Knowledge Library.
 *
 *  By injecting this code into the articles, the user can select a block of text
 */
const FADE_DURATION = 200;

$(document).ready(function () {
    var mouse_is_down = false;
    // Webview should start focused
    var window_focus = true;
    $(window).focus(function() {
        window_focus = true;
    }).blur(function() {
        window_focus = false;
    });
    // Updates the copy button to appear at the beginning of the selection. If the
    // mouse is currently down we hide the copy button until the selection
    // drag is completed.
    var update_copy_button = function() {
        var selection = window.getSelection();
        if (selection.isCollapsed || mouse_is_down || !window_focus) {
            $('#copy-button').fadeOut(FADE_DURATION);
        } else {
            var range = selection.getRangeAt(0).cloneRange();
            range.collapse(true);
            var rect = range.getClientRects()[0];

            var top_position = Math.max(rect.top - $('#copy-button').outerHeight(true), 0) + $(window).scrollTop();
            var left_position =  Math.max(rect.left - $('#copy-button').outerWidth(true), 0) + $(window).scrollLeft();
            $('#copy-button').css({
                top: top_position,
                left: left_position,
            });
            $('#copy-button').fadeIn(FADE_DURATION);
        }
    };

    // Update copy button location on any selectionchange or mouseup.
    $(document).mousedown(function() {
        mouse_is_down = true;
    }).mouseup(function() {
        mouse_is_down = false;
        update_copy_button();
    }).on('selectionchange', function() {
        update_copy_button();
    });

    $('#copy-button').mousedown(function (event) {
        // Returning false prevents mousedown signal from propagating up the DOM tree.
        // This keeps us from losing our selection when clicking on the copy
        // button.
        return false;
    }).click(function () {
        document.execCommand('Copy');
        $('#copy-button').fadeOut(FADE_DURATION);
    });
});
<commit_msg>clipboard-manager: Use a constant copy_button variable<commit_after>/** clipboard_manager.js
 *  This utility handles the Copy/Paste behavior for the Knowledge Library.
 *
 *  By injecting this code into the articles, the user can select a block of text
 */
const FADE_DURATION = 200;

$(document).ready(function () {
    var $copy_button = $('#copy-button');

    var mouse_is_down = false;
    // Webview should start focused
    var window_focus = true;
    $(window).focus(function() {
        window_focus = true;
    }).blur(function() {
        window_focus = false;
    });
    // Updates the copy button to appear at the beginning of the selection. If the
    // mouse is currently down we hide the copy button until the selection
    // drag is completed.
    var update_copy_button = function() {
        var selection = window.getSelection();
        if (selection.isCollapsed || mouse_is_down || !window_focus) {
            $copy_button.fadeOut(FADE_DURATION);
        } else {
            var range = selection.getRangeAt(0).cloneRange();
            range.collapse(true);
            var rect = range.getClientRects()[0];

            var top_position = Math.max(rect.top - $copy_button.outerHeight(true), 0) + $(window).scrollTop();
            var left_position =  Math.max(rect.left - $copy_button.outerWidth(true), 0) + $(window).scrollLeft();
            $copy_button.css({
                top: top_position,
                left: left_position,
            });
            $copy_button.fadeIn(FADE_DURATION);
        }
    };

    // Update copy button location on any selectionchange or mouseup.
    $(document).mousedown(function() {
        mouse_is_down = true;
    }).mouseup(function() {
        mouse_is_down = false;
        update_copy_button();
    }).on('selectionchange', function() {
        update_copy_button();
    });

    $copy_button.mousedown(function (event) {
        // Returning false prevents mousedown signal from propagating up the DOM tree.
        // This keeps us from losing our selection when clicking on the copy
        // button.
        return false;
    }).click(function () {
        document.execCommand('Copy');
        $copy_button.fadeOut(FADE_DURATION);
    });
});
<|endoftext|>


<commit_before>describe('topbar directive', function () {
  var $rootScope, element, $document;

  var setMobile = function(windowMock){
    windowMock.matchMedia.andReturn({matches: false});
  };

  var setDesktop = function(windowMock){
    windowMock.matchMedia.andReturn({matches: true});
  };

  beforeEach(module('template/topbar/top-bar.html'));
  beforeEach(module('template/topbar/has-dropdown.html'));
  beforeEach(module('template/topbar/toggle-top-bar.html'));
  beforeEach(module('template/topbar/top-bar-section.html'));
  beforeEach(module('template/topbar/top-bar-dropdown.html'));

  beforeEach(module('mm.foundation.topbar', function($provide){
    window.matchMedia = jasmine.createSpy('matchMedia').andReturn({matches: false});
    $provide.value('$window', window);
  }));

  beforeEach(inject(function(_$compile_, _$rootScope_, _$document_) {
    $compile = _$compile_;
    $rootScope = _$rootScope_;
    $document = _$document_;

    element = $compile(
          '' +
            '
' +
              '<top-bar scrolltop="false">' +
                '
' +
                  '
' +
                    '
My Site
' +
                  '
' +
                  '
' +
                    'Menu' +
                  '
' +
                '
' +
                '<top-bar-section id="top-section">' +
                    '
' +
                      '
' +
                        'Active' +
                      '
' +
                      '
' +
                        'Dropdown' +
                        '
' +
                          '
First link in dropdown
' +
                        '
' +
                      '
' +
                    '
' +
                    '
' +
                      '
Left
' +
                    '
' +
                '</top-bar-section>' +
              '</top-bar>' +
              '
Content
' +
            '
' +
          '')($rootScope);
    $('body', $document).append(element);
    $rootScope.$digest();
  }));

  beforeEach(inject(function ($rootScope) {
    this.addMatchers({
      toHaveDropDownsOpen: function(noOfLevels) {
        var dropDownDomEls = this.actual.find('li.has-dropdown.not-click');
        return dropDownDomEls.length === noOfLevels;
      },
      toHaveMobileMenuOpen: function() {
        var els = this.actual.find('nav.top-bar.expanded');
        return !!els.length;
      }
    });
  }));

  it('has a "top-bar" css class', function() {
    expect(element.children('nav')).toHaveClass('top-bar');
  });

  it('has a drop down open on large screen', inject(function($window) {
    setDesktop($window);
    $('#dropdown', element).trigger('mouseenter');
    expect($window.matchMedia).toHaveBeenCalled();
    expect(element).toHaveDropDownsOpen(1);
  }));

  it('has no drop downs open on small screen', inject(function($window) {
    setMobile($window);
    $('#dropdown', element).trigger('mouseenter');
    expect($window.matchMedia).toHaveBeenCalled();
    expect(element).toHaveDropDownsOpen(0);
  }));

  it('has no mobile menu opening on large screen', inject(function($window) {
    setDesktop($window);
    $('#menu-toggle', element).trigger('click');
    expect($window.matchMedia).toHaveBeenCalled();
    expect(element).not.toHaveMobileMenuOpen();
  }));

  it('opens and closes mobile menu on small screen', inject(function($window) {
    setMobile($window);
    $('#menu-toggle', element).trigger('click');
    expect($window.matchMedia).toHaveBeenCalled();
    expect(element).toHaveMobileMenuOpen();
    $('#menu-toggle', element).trigger('click');
    expect(element).not.toHaveMobileMenuOpen();
  }));

  it('opens the submenu when a dropdown is clicked on mobile', inject(function($window) {
    setMobile($window);
    $('#menu-toggle', element).trigger('click');
    expect($window.matchMedia).toHaveBeenCalled();
    var beforeHeight = $('.top-bar', element)[0].style.height;
    $('#dropdown', element).trigger('click');
    var afterHeight = $('.top-bar', element)[0].style.height;
    expect(afterHeight).toNotEqual(beforeHeight);
    expect($('#top-section', element)[0].style.left).toEqual('-100%');
  }));

  // it('has f-topbar-fixed class on body after link is clicked on a fixed mobile topbar', inject(function($window) {
  //   setMobile($window);
  //   $('#menu-toggle', element).trigger('click');
  //   expect($window.matchMedia).toHaveBeenCalled();
  //   $('#dropdown', element).trigger('click');
  //   $('#alink', element).trigger('click');
  //   expect($('body', $document)).toHaveClass('f-topbar-fixed');
  // }));

});
<commit_msg>chore(topbar): Refactor topbar specs<commit_after>describe('topbar directive', function() {
  var $rootScope, $document, $compile, $window, element, containerElement;

  beforeEach(function() {
    $window = angular.extend(window, {
      pageYOffset: 0,
      scrollTo: jasmine.createSpy('scrollTo'),
      matchMedia: jasmine.createSpy('matchMedia').andReturn({matches: false}),
    });

    module(
      'mm.foundation.topbar',
      'template/topbar/top-bar.html',
      'template/topbar/has-dropdown.html',
      'template/topbar/toggle-top-bar.html',
      'template/topbar/top-bar-section.html',
      'template/topbar/top-bar-dropdown.html',
      {$window: $window});

    inject(function(_$compile_, _$rootScope_, _$document_) {
      $compile = _$compile_;
      $rootScope = _$rootScope_;
      $document = _$document_;

    });
  });

  beforeEach(inject(function ($rootScope) {
    this.addMatchers({
      toHaveDropDownsOpen: function(noOfLevels) {
        var dropDownDomEls = element.find('li.has-dropdown.not-click');
        return dropDownDomEls.length === noOfLevels;
      },
      toHaveMobileMenuOpen: function() {
        return element.hasClass("expanded");
      }
    });
  }));

  var setMobile = function() {
    $window.matchMedia.andReturn({matches: false});
  };

  var setDesktop = function() {
    $window.matchMedia.andReturn({matches: true});
  };

  var compileDirective = function(markup) {
    if (angular.isUndefined(markup)) {
      markup =
        '
' +
          '<top-bar scrolltop="false">' +
            '
' +
              '
' +
                '
My Site
' +
              '
' +
              '
' +
                'Menu' +
              '
' +
            '
' +
            '<top-bar-section id="top-section">' +
              '
' +
                '
' +
                  'Active' +
                '
' +
                '
' +
                  'Dropdown' +
                  '
' +
                    '
First link in dropdown
' +
                  '
' +
                '
' +
              '
' +
              '
' +
                '
Left
' +
              '
' +
            '</top-bar-section>' +
          '</top-bar>' +
          '
Content
' +
        '
';
      containerElement = $compile(markup)($rootScope);
      $('body', $document).append(element);
      $rootScope.$digest();
      element = containerElement.find("nav");
    }
  }

  describe("basic behavior", function() {
    beforeEach(function() {
      compileDirective();
    });

    it('has a "top-bar" css class', function() {
      expect(element).toHaveClass('top-bar');
    });

    it('has a drop down open on large screen', inject(function($window) {
      setDesktop();
      $('#dropdown', element).trigger('mouseenter');
      expect($window.matchMedia).toHaveBeenCalled();
      expect(element).toHaveDropDownsOpen(1);
    }));

    it('has no drop downs open on small screen', inject(function($window) {
      setMobile();
      $('#dropdown', element).trigger('mouseenter');
      expect($window.matchMedia).toHaveBeenCalled();
      expect(element).toHaveDropDownsOpen(0);
    }));

    it('has no mobile menu opening on large screen', inject(function($window) {
      setDesktop($window);
      $('#menu-toggle', element).trigger('click');
      expect($window.matchMedia).toHaveBeenCalled();
      expect(element).not.toHaveMobileMenuOpen();
    }));

    it('opens and closes mobile menu on small screen', inject(function($window) {
      setMobile();
      $('#menu-toggle', element).trigger('click');
      expect($window.matchMedia).toHaveBeenCalled();
      expect(element).toHaveMobileMenuOpen();
      $('#menu-toggle', element).trigger('click');
      expect(element).not.toHaveMobileMenuOpen();
    }));

    it('opens the submenu when a dropdown is clicked on mobile', inject(function($window) {
      var topSection = element.find('#top-section');
      var menuToggle = element.find('#menu-toggle');
      setMobile();
      expect(element.hasClass("expanded")).toBe(false);
      menuToggle.trigger('click');
      expect($window.matchMedia).toHaveBeenCalled();
      expect(element.hasClass("expanded")).toBe(true);
    }));
  });
});
<|endoftext|>


<commit_before>var math = require('mathjs');
var tripwire = require('tripwire');

var Attachment = require('./attachment');
var formatter = require('./formatter');

var freshStart = true;

var mathParser = {};

module.exports = {
  setMathParser: function(parserObj) {
    mathParser = parserObj;
  },
  evalGet: function(req, resp) {
    resp.send('/eval only currently accept POST requests.');
  },
  evalPost: function(req, resp) {
    var result = {};
    var attachments = [], att;  // att is for temporarily storing an attachment
    var post = req.body;
    var expr = post.text;
    var trigger = post.trigger_word;

    // do not respond to bot-users (including itself)
    if(post.user_name == 'slackbot'){
      resp.end();
      return;
    }

    if (!expr) {
      result.ok = false;
      result.text = 'No message sent.';
      resp.json(result);
      return;
    }

    if (trigger) {
      //truncate trigger word
      expr = expr.slice(trigger.length);
    }

    var dispName = '@' + post.user_name;
    result.text = '\00';

    if (freshStart) {
      att = new Attachment('Welcome to MathJS v' + math.version + '! \n Configurations:');
      att.pretext = 'MathJS server had restarted. (last commit: ' + '2015/4/27' + ')';
      att.fields = [];
      var config = math.config();
      for (var x in config) {
        att.fields.push({
          title: x,
          value: config[x],
          short: true
        });
      }
      attachments.push(att);
      freshStart = false;
    }

    try {
      result.ok = true;

      tripwire.resetTripwire(10000, {
        request: req,
        dispName: dispName
      });

      var answer = mathParser.eval(expr);

      tripwire.clearTripwire();

      var outGuide = formatter(answer);
      var outRaw = outGuide.output;
      var output = outRaw;

      if (outGuide.newl)
        output = '\n' + output;
      else
        output = '*' + output + '*';

      if (answer == null) {
        att = new Attachment(dispName + ': ' + output);
        att.fallback = dispName + ': ' + outRaw;
      } else {
        att = new Attachment(dispName + ': ans = ' + output);
        att.fallback = dispName + ': ans = ' + outRaw;
        mathParser.set('ans', answer);
      }
      att.color = 'good';
      attachments.push(att);

    } catch (err) {
      result.ok = false;

      // if error occurred, the clearTripwire part is never reached.
      tripwire.clearTripwire();

      if (err.message.indexOf('(char 1)') >= 0){
        // fail silently
        result.text = '';
      } else {
        att = new Attachment();
        att.color = 'danger';
        att.fallback = dispName + ' ' + err.toString();
        att.text = dispName + ' *' + err.name + '*: ' + err.message;
        attachments.push(att);
      }

      result.error = {
        type: err.name,
        message: err.message
      };
    }

    if (attachments.length)
      result.attachments = attachments;

    resp.json(result);

  },

  scopeReadGet: function(req, resp) {
    resp.json(mathParser.scope);
  }

};

process.on('uncaughtException', function (e) {
  var context = tripwire.getContext();
  if (context) {
    console.log('MathJS execution killed!');

    var attTle = new Attachment();
    attTle.color = 'warning';
    attTle.fallback = '*TLE*: Code execution time limit exceeded!';
    attTle.text = context.dispName + ' *TLE*: Code execution time limit exceeded! Your expr was dropped.';
    context.request.json(attTle);
  } else {
    throw e;
    process.exit(1);
  }
});
<commit_msg>try to log more<commit_after>var math = require('mathjs');
var tripwire = require('tripwire');

var Attachment = require('./attachment');
var formatter = require('./formatter');

var freshStart = true;

var mathParser = {};

module.exports = {
  setMathParser: function(parserObj) {
    mathParser = parserObj;
  },
  evalGet: function(req, resp) {
    resp.send('/eval only currently accept POST requests.');
  },
  evalPost: function(req, resp) {
    var result = {};
    var attachments = [], att;  // att is for temporarily storing an attachment
    var post = req.body;
    var expr = post.text;
    var trigger = post.trigger_word;

    // do not respond to bot-users (including itself)
    if(post.user_name == 'slackbot'){
      resp.end();
      return;
    }

    if (!expr) {
      result.ok = false;
      result.text = 'No message sent.';
      resp.json(result);
      return;
    }

    if (trigger) {
      //truncate trigger word
      expr = expr.slice(trigger.length);
    }

    var dispName = '@' + post.user_name;
    result.text = '\00';

    if (freshStart) {
      att = new Attachment('Welcome to MathJS v' + math.version + '! \n Configurations:');
      att.pretext = 'MathJS server had restarted. (last commit: ' + '2015/4/27' + ')';
      att.fields = [];
      var config = math.config();
      for (var x in config) {
        att.fields.push({
          title: x,
          value: config[x],
          short: true
        });
      }
      attachments.push(att);
      freshStart = false;
    }

    try {
      result.ok = true;

      tripwire.resetTripwire(10000, {
        request: req,
        dispName: dispName
      });

      var answer = mathParser.eval(expr);

      tripwire.clearTripwire();

      var outGuide = formatter(answer);
      var outRaw = outGuide.output;
      var output = outRaw;

      if (outGuide.newl)
        output = '\n' + output;
      else
        output = '*' + output + '*';

      if (answer == null) {
        att = new Attachment(dispName + ': ' + output);
        att.fallback = dispName + ': ' + outRaw;
      } else {
        att = new Attachment(dispName + ': ans = ' + output);
        att.fallback = dispName + ': ans = ' + outRaw;
        mathParser.set('ans', answer);
      }
      att.color = 'good';
      attachments.push(att);

    } catch (err) {
      result.ok = false;

      // if error occurred, the clearTripwire part is never reached.
      tripwire.clearTripwire();

      if (err.message.indexOf('(char 1)') >= 0){
        // fail silently
        result.text = '';
      } else {
        att = new Attachment();
        att.color = 'danger';
        att.fallback = dispName + ' ' + err.toString();
        att.text = dispName + ' *' + err.name + '*: ' + err.message;
        attachments.push(att);
      }

      result.error = {
        type: err.name,
        message: err.message
      };
    }

    if (attachments.length)
      result.attachments = attachments;

    resp.json(result);

  },

  scopeReadGet: function(req, resp) {
    resp.json(mathParser.scope);
  }

};

process.on('uncaughtException', function (e) {
  var context = tripwire.getContext();
  if (context) {

    var attTle = new Attachment();
    attTle.color = 'warning';
    attTle.fallback = '*TLE*: Code execution time limit exceeded!';
    attTle.text = context.dispName + ' *TLE*: Code execution time limit exceeded! Your expr was dropped.';

    console.log('@' + context.dispName + ': MathJS execution killed!');
    context.request.json(attTle);
  } else {
    throw e;
    process.exit(1);
  }
});
<|endoftext|>


<commit_before>
var sys = require("sys");
var tcp = require("net");

var Log = require("./common").Log;

var xml = require("../../vendor/node-xml/lib/node-xml");
var Do  = require("../../vendor/do/lib/do");

/*******************************************************************************
 **** Server Config ************************************************************
 *******************************************************************************/

/**
 * XMPP updstream message processing pipeline.  Each instance is responsible for
 * a single connection, taking raw character stream in chunks as input any
 * resulting messages that are generated as a result of processing input are
 * pushed to supplied router callback.
 * @constructor
 */
exports.XMPPDownstreamPipeline = function(socket) {

    // Iteratively render an attribute list as a string
    var renderAttrs = function(attrs) {
        var response = "";
        for (key in attrs) response += key + "=\"" + attrs[key] + "\" ";
        return response.trim();
    }

    // Recursively render and XML element as a string
    var renderElement = function(element) {
        if (typeof element === "string") {
            return element;
        } else {
            var response = "<" + ((element.prefix === undefined) ? element.prefix + ":" : "") + " " + renderAttrs(element.attrs) + ">";
            for (child in element.children) {
                response += renderElement(child);
            }

            response += "</" + ((element.prefix === undefined) ? element.prefix + ":" : "") + ">";
            return response;
        }
    }

    // Processes a chunk of character data - calls router asynchronously on each
    // generated XMPP message.
    this.process = function(data) {
        return function(callback errorHandler) {

            // Treat streams as a special case
            if (data.element === "stream" && data.prefix === "stream") {
                callback("<stream:stream " + renderAttrs(data.attrs); + ">")
            } else {
                var response = renderElement(data);
                socket.write(response, function() { Log.debug("Sent " + response) });
            }
        }
    }
}<commit_msg>fixing syntax bugs<commit_after>
var sys = require("sys");
var tcp = require("net");

var Log = require("./common").Log;

var xml = require("../../vendor/node-xml/lib/node-xml");
var Do  = require("../../vendor/do/lib/do");

/*******************************************************************************
 **** Server Config ************************************************************
 *******************************************************************************/

/**
 * XMPP updstream message processing pipeline.  Each instance is responsible for
 * a single connection, taking raw character stream in chunks as input any
 * resulting messages that are generated as a result of processing input are
 * pushed to supplied router callback.
 * @constructor
 */
exports.XMPPDownstreamPipeline = function(socket) {

    // Iteratively render an attribute list as a string
    var renderAttrs = function(attrs) {
        var response = "";
        for (key in attrs) response += key + "=\"" + attrs[key] + "\" ";
        return response.trim();
    }

    // Recursively render and XML element as a string
    var renderElement = function(element) {
        if (typeof element === "string") {
            return element;
        } else {
            var response = "<" + ((element.prefix === undefined) ? element.prefix + ":" : "") + " " + renderAttrs(element.attrs) + ">";
            for (child in element.children) {
                response += renderElement(child);
            }

            response += "</" + ((element.prefix === undefined) ? element.prefix + ":" : "") + ">";
            return response;
        }
    }

    // Processes a chunk of character data - calls router asynchronously on each
    // generated XMPP message.
    this.process = function(data) {
        return function(callback, errorHandler) {

            // Treat streams as a special case
            if (data.element === "stream" && data.prefix === "stream") {
                callback("<stream:stream " + renderAttrs(data.attrs) + ">")
            } else {
                var response = renderElement(data);
                socket.write(response, function() { Log.debug("Sent " + response) });
            }
        }
    }
}
<|endoftext|>


<commit_before>'use babel'

import { CompositeDisposable } from 'atom'
import { getSiblings } from './utils'

export default {

  config: {
    expandedWidth: {
      title: 'Focused Pane Width',
      description: 'Sets the Percentage between 0 and 100 of how much the focused pane will grow',
      type: 'integer',
      default: 94,
      minimum: 1,
      maximum: 100
    }
  },

  subscriptions: null,
  ActivePane: null,
  FollowObserver: null,
  modifiedPanes: [],

  activate(state) {
    this.subscriptions = new CompositeDisposable()

    this.subscriptions.add(atom.commands.add('atom-workspace', {
      'hey-pane:toggle-focus-of-active-pane': () => this.toggleFocus(),
      'hey-pane:toggle-follow-mode': () => this.followMe()
    }))
  },

  deactivate() {
    this.subscriptions.dispose()

    if (this.FollowObserver != null)
      this.FollowObserver.dispose()
  },

  // Activate/deactivate follow mode
  followMe() {
    if (this.FollowObserver != null) {
      this.FollowObserver.dispose()
      this.FollowObserver = null
    } else {
      this.FollowObserver = atom.workspace.onDidStopChangingActivePaneItem((pane) => {
        this.setAutoFocus()
      })
    }
  },

  setAutoFocus() {
    if (this.ActivePane != null) {
      this.undoFocus()
    }
    this.doFocus()
  },

  // Toggle Focus of active pane
  toggleFocus() {
    if (this.ActivePane != null) {
      this.undoFocus()
    } else {
      this.doFocus()
    }
  },

  doFocus() {
    this.ActivePane = this.getActivePane()
    this.ActivePane.classList.add('hey-pane-focus')

    const expandedWidth = atom.config.get('hey-pane.expandedWidth') / 100
    const collapsedWidth = 1 - expandedWidth

    var recursiveSet = (node) => {
      if (node.parentNode.nodeName === 'ATOM-PANE-AXIS') {
        this.saveElementStateAndSetFlex(node, expandedWidth)
        getSiblings(node)
        .filter(pane => pane.nodeName !== 'ATOM-PANE-RESIZE-HANDLE')
        .forEach(pane => {
          this.saveElementStateAndSetFlex(pane, collapsedWidth)
        })

        if (node.parentNode.parentNode.nodeName !== 'ATOM-PANE-CONTAINER') {
          recursiveSet(node.parentNode)
        }
      }
    }

    recursiveSet(this.ActivePane);
  },

  undoFocus() {
    this.ActivePane.classList.remove('hey-pane-focus')
    this.ActivePane = null
    this.restorePanes()
    this.emptyPaneStates()
  },

  saveElementStateAndSetFlex(el, newFlexValue) {
    const oldFlexValue = el.style.flexGrow
    this.modifiedPanes.push({ el, oldFlexValue })
    el.style.flexGrow = newFlexValue
  },

  restorePanes() {
    const Container = this.getPanesContainer()
    this.modifiedPanes.forEach(pane => {
      if (Container.contains(pane.el)) {
        pane.el.style.flexGrow = pane.oldFlexValue
      }
    })
  },

  emptyPaneStates() {
    this.modifiedPanes = []
  },

  getPanesContainer() {
    const View = atom.views.getView(atom.workspace);
    return View.querySelector('.panes');
  },

  getActivePane() {
    const View = atom.views.getView(atom.workspace);
    return View.querySelector('.pane.active');
  }

};
<commit_msg>Added incompatible message for nuclide (see #3)<commit_after>'use babel'

import { CompositeDisposable } from 'atom'
import { getSiblings } from './utils'

export default {

  config: {
    expandedWidth: {
      title: 'Focused Pane Width',
      description: 'Sets the Percentage between 0 and 100 of how much the focused pane will grow',
      type: 'integer',
      default: 94,
      minimum: 1,
      maximum: 100
    }
  },

  subscriptions: null,
  ActivePane: null,
  FollowObserver: null,
  modifiedPanes: [],
  incompatiblePackages: ['nuclide'],

  activate(state) {
    this.subscriptions = new CompositeDisposable()

    this.subscriptions.add(atom.packages.onDidActivatePackage(
      this.checkIncompatiblePackages.bind(this)))

    this.subscriptions.add(atom.commands.add('atom-workspace', {
      'hey-pane:toggle-focus-of-active-pane': () => this.toggleFocus(),
      'hey-pane:toggle-follow-mode': () => this.followMe()
    }))
  },

  deactivate() {
    this.subscriptions.dispose()

    if (this.FollowObserver != null)
      this.FollowObserver.dispose()
  },

  // Activate/deactivate follow mode
  followMe() {
    if (this.FollowObserver != null) {
      this.FollowObserver.dispose()
      this.FollowObserver = null
    } else {
      this.FollowObserver = atom.workspace.onDidStopChangingActivePaneItem(
        (pane) => { this.setAutoFocus() }
      )
    }
  },

  setAutoFocus() {
    if (this.ActivePane != null) {
      this.undoFocus()
    }
    this.doFocus()
  },

  // Toggle Focus of active pane
  toggleFocus() {
    if (this.ActivePane != null) {
      this.undoFocus()
    } else {
      this.doFocus()
    }
  },

  doFocus() {
    this.ActivePane = this.getActivePane()
    this.ActivePane.classList.add('hey-pane-focus')

    const expandedWidth = atom.config.get('hey-pane.expandedWidth') / 100
    const collapsedWidth = 1 - expandedWidth

    var recursiveSet = (node) => {
      if (node.parentNode.nodeName === 'ATOM-PANE-AXIS') {
        this.saveElementStateAndSetFlex(node, expandedWidth)
        getSiblings(node)
        .filter(pane => pane.nodeName !== 'ATOM-PANE-RESIZE-HANDLE')
        .forEach(pane => {
          this.saveElementStateAndSetFlex(pane, collapsedWidth)
        })

        if (node.parentNode.parentNode.nodeName !== 'ATOM-PANE-CONTAINER') {
          recursiveSet(node.parentNode)
        }
      }
    }

    recursiveSet(this.ActivePane);
  },

  undoFocus() {
    this.ActivePane.classList.remove('hey-pane-focus')
    this.ActivePane = null
    this.restorePanes()
    this.emptyPaneStates()
  },

  saveElementStateAndSetFlex(el, newFlexValue) {
    const oldFlexValue = el.style.flexGrow
    this.modifiedPanes.push({ el, oldFlexValue })
    el.style.flexGrow = newFlexValue
  },

  restorePanes() {
    const Container = this.getPanesContainer()
    this.modifiedPanes.forEach(pane => {
      if (Container.contains(pane.el)) {
        pane.el.style.flexGrow = pane.oldFlexValue
      }
    })
  },

  emptyPaneStates() {
    this.modifiedPanes = []
  },

  getPanesContainer() {
    const View = atom.views.getView(atom.workspace)
    return View.querySelector('.panes')
  },

  getActivePane() {
    const View = atom.views.getView(atom.workspace)
    return View.querySelector('.pane.active')
  },

  checkIncompatiblePackages(package) {
    if (this.incompatiblePackages.includes(package.name)) {
      atom.notifications.addError('Incompatible Package Detected',
        {
          dismissable: true,
          detail: `hey-pane does not work when package "${package.name}" is activated.`
        }
      )
    }
  }

};
<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const { exec } = require('child_process');
const async = require('async');
const jar = require('vnu-jar');
const chunkify = require('./chunkify');
const javadetect = require('./javadetect');

function htmllint(config, done) {
  const MAX_CHARS = 5000;

  // increase child process buffer to accommodate large amounts of
  // validation output. (the default is a paltry 200k)
  // https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback
  const MAX_BUFFER = 20000 * 1024;

  // replace left/right quotation marks with normal quotation marks
  function normalizeQuotationMarks(str) {
    if (str) {
      str = str.replace(/[\u201C\u201D]/g, '"');
    }

    return str;
  }

  // parse and, if needed, normalize error messages from HttpClient to java -jar format
  // java -jar: one object containing messages for all files
  //   { messages: [{ message, type, url, ... }, ...] }
  // HttpClient: one object per file, separated by a newline, each object containing messages for only that file
  //   { messages: [{ message, type, ...}, ...], url }\n{ ... }
  function parseErrorMessages(errors) {
    const parsed = JSON.parse(config.server ? `[${errors.trim().replace(/\n/g, ',')}]` : errors);
    let { messages } = parsed;

    if (config.server) {
      // extract "messages" property from each object and set the url of each message
      // this results in an array of arrays instead of array of objects, which is then flattened by concatenation
      messages = [].concat(...messages, parsed.map(file => {
        return file.messages.map(message => {
          message.url = file.url;
          return message;
        });
      }));
    }

    return messages;
  }

  // determine proper jarfile command and arguments
  function cmd(java, chunk) {
    let args = '';

    if (config.server) {
      if (config.server.host) {
        args += ` -Dnu.validator.client.host=${config.server.host}`;
      }

      if (config.server.port) {
        args += ` -Dnu.validator.client.port=${config.server.port}`;
      }

      args += ' -Dnu.validator.client.out=json nu.validator.client.HttpClient';
    } else {
      args += ' --format json';
    }

    if (config.noLangDetect) {
      args += ' --no-langdetect';
    }

    const invoke = `${config.server ? '-cp' : '-jar'} "${jar}"${args}`;

    // command to call java, increasing the default stack size for ia32 versions of the JRE and using the default setting for x64 versions
    return `java ${java.arch === 'ia32' ? '-Xss512k ' : ''}${invoke} ${chunk}`;
  }

  if (config.files.length === 0) {
    return done(null, []);
  }

  javadetect((err, java) => {
    if (err) {
      throw err;
    }

    const javaVersion = java.version.split('.').map(part => Number(part));

    if ((javaVersion[0] !== 1 && javaVersion[0] < 8) || (javaVersion[0] === 1 && javaVersion[1] < 8)) {
      throw new Error(`\nUnsupported Java version used: ${java.version}. Java 8 environment or up is required!`);
    }

    const files = config.files.map(file => path.normalize(file));

    async.mapSeries(chunkify(files, MAX_CHARS), (chunk, cb) => {
      exec(cmd(java, chunk), { maxBuffer: MAX_BUFFER }, (error, stdout, stderr) => {
        if (error && (error.code !== 1 || error.killed || error.signal)) {
          cb(error);
          return;
        }

        stderr = config.server ? stdout : stderr;
        let result = [];

        if (stderr) {
          try {
            result = parseErrorMessages(stderr);
          } catch (error_) {
            throw new Error(`${error_}\nInvalid input follows below:\n\n${stderr}`);
          }

          result.forEach(message => {
            if (message.url) {
              // eslint-disable-next-line no-negated-condition
              message.file = path.relative('.', message.url.replace(path.sep !== '\\' ? 'file:' : 'file:/', ''));
            }

            if (config.absoluteFilePathsForReporter) {
              message.file = path.resolve(message.file);
            }
          });

          if (config.ignore) {
            const ignore = Array.isArray(config.ignore) ? config.ignore : [config.ignore];

            result = result.filter(message => {
              // Iterate over the ignore rules and test the message against each rule.
              // A match should return false, which causes every() to return false and the message to be filtered out.
              return ignore.every(currentValue => {
                if (currentValue instanceof RegExp) {
                  return !currentValue.test(message.message);
                }

                return normalizeQuotationMarks(currentValue) !== normalizeQuotationMarks(message.message);
              });
            });
          }
        }

        cb(null, result);
      });
    }, (error, results) => {
      if (error) {
        done(error);
        return;
      }

      let result = [];

      for (result of results) {
        result = [...result];
      }

      done(null, result.filter(item => {
        return config.errorlevels.includes(item.type);
      }));
    });
  });
}

module.exports = htmllint;
<commit_msg>Remove negated condition<commit_after>'use strict';

const path = require('path');
const { exec } = require('child_process');
const async = require('async');
const jar = require('vnu-jar');
const chunkify = require('./chunkify');
const javadetect = require('./javadetect');

function htmllint(config, done) {
  const MAX_CHARS = 5000;

  // increase child process buffer to accommodate large amounts of
  // validation output. (the default is a paltry 200k)
  // https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback
  const MAX_BUFFER = 20000 * 1024;

  // replace left/right quotation marks with normal quotation marks
  function normalizeQuotationMarks(str) {
    if (str) {
      str = str.replace(/[\u201C\u201D]/g, '"');
    }

    return str;
  }

  // parse and, if needed, normalize error messages from HttpClient to java -jar format
  // java -jar: one object containing messages for all files
  //   { messages: [{ message, type, url, ... }, ...] }
  // HttpClient: one object per file, separated by a newline, each object containing messages for only that file
  //   { messages: [{ message, type, ...}, ...], url }\n{ ... }
  function parseErrorMessages(errors) {
    const parsed = JSON.parse(config.server ? `[${errors.trim().replace(/\n/g, ',')}]` : errors);
    let { messages } = parsed;

    if (config.server) {
      // extract "messages" property from each object and set the url of each message
      // this results in an array of arrays instead of array of objects, which is then flattened by concatenation
      messages = [].concat(...messages, parsed.map(file => {
        return file.messages.map(message => {
          message.url = file.url;
          return message;
        });
      }));
    }

    return messages;
  }

  // determine proper jarfile command and arguments
  function cmd(java, chunk) {
    let args = '';

    if (config.server) {
      if (config.server.host) {
        args += ` -Dnu.validator.client.host=${config.server.host}`;
      }

      if (config.server.port) {
        args += ` -Dnu.validator.client.port=${config.server.port}`;
      }

      args += ' -Dnu.validator.client.out=json nu.validator.client.HttpClient';
    } else {
      args += ' --format json';
    }

    if (config.noLangDetect) {
      args += ' --no-langdetect';
    }

    const invoke = `${config.server ? '-cp' : '-jar'} "${jar}"${args}`;

    // command to call java, increasing the default stack size for ia32 versions of the JRE and using the default setting for x64 versions
    return `java ${java.arch === 'ia32' ? '-Xss512k ' : ''}${invoke} ${chunk}`;
  }

  if (config.files.length === 0) {
    return done(null, []);
  }

  javadetect((err, java) => {
    if (err) {
      throw err;
    }

    const javaVersion = java.version.split('.').map(part => Number(part));

    if ((javaVersion[0] !== 1 && javaVersion[0] < 8) || (javaVersion[0] === 1 && javaVersion[1] < 8)) {
      throw new Error(`\nUnsupported Java version used: ${java.version}. Java 8 environment or up is required!`);
    }

    const files = config.files.map(file => path.normalize(file));

    async.mapSeries(chunkify(files, MAX_CHARS), (chunk, cb) => {
      exec(cmd(java, chunk), { maxBuffer: MAX_BUFFER }, (error, stdout, stderr) => {
        if (error && (error.code !== 1 || error.killed || error.signal)) {
          cb(error);
          return;
        }

        stderr = config.server ? stdout : stderr;
        let result = [];

        if (stderr) {
          try {
            result = parseErrorMessages(stderr);
          } catch (error_) {
            throw new Error(`${error_}\nInvalid input follows below:\n\n${stderr}`);
          }

          result.forEach(message => {
            if (message.url) {
              message.file = path.relative('.', message.url.replace(path.sep === '\\' ? 'file:/' : 'file:', ''));
            }

            if (config.absoluteFilePathsForReporter) {
              message.file = path.resolve(message.file);
            }
          });

          if (config.ignore) {
            const ignore = Array.isArray(config.ignore) ? config.ignore : [config.ignore];

            result = result.filter(message => {
              // Iterate over the ignore rules and test the message against each rule.
              // A match should return false, which causes every() to return false and the message to be filtered out.
              return ignore.every(currentValue => {
                if (currentValue instanceof RegExp) {
                  return !currentValue.test(message.message);
                }

                return normalizeQuotationMarks(currentValue) !== normalizeQuotationMarks(message.message);
              });
            });
          }
        }

        cb(null, result);
      });
    }, (error, results) => {
      if (error) {
        done(error);
        return;
      }

      let result = [];

      for (result of results) {
        result = [...result];
      }

      done(null, result.filter(item => {
        return config.errorlevels.includes(item.type);
      }));
    });
  });
}

module.exports = htmllint;
<|endoftext|>


<commit_before>"use strict";
var handlerStack = {
  counter: 1,
  stack: [],
  push: function(func, env) {
    var id = ++this.counter;
    this.stack.push([func, env || null, id]);
    return id;
  },
  bubbleEvent: function(event) {
    var ref = this.stack, i = ref.length, item, result;
    while (0 <= --i) {
      item = ref[i];
      result = item[0].call(item[1], event);
      if (result === 0) {
        continue;
      }
      if (result === 2) {
        event.preventDefault();
      }
      event.stopImmediatePropagation();
      return true;
    }
    return false;
  },
  remove: function(id) {
    if (!(id > 0)) { return 0; }
    var ref = this.stack, i = ref.length;
    while (0 <= --i) {
      if (ref[i][2] === id) {
        ref.splice(i, 1);
        break;
      }
    }
    return id;
  },
  SuppressMost: function(event) {
    var n = event.keyCode;
    return (n > KeyCodes.f1 && n <= KeyCodes.f12) ? 1 : 2;
  }
};
<commit_msg>keydown: handlerStack.SuppressMost: suppress F2<commit_after>"use strict";
var handlerStack = {
  counter: 1,
  stack: [],
  push: function(func, env) {
    var id = ++this.counter;
    this.stack.push([func, env || null, id]);
    return id;
  },
  bubbleEvent: function(event) {
    var ref = this.stack, i = ref.length, item, result;
    while (0 <= --i) {
      item = ref[i];
      result = item[0].call(item[1], event);
      if (result === 0) {
        continue;
      }
      if (result === 2) {
        event.preventDefault();
      }
      event.stopImmediatePropagation();
      return true;
    }
    return false;
  },
  remove: function(id) {
    if (!(id > 0)) { return 0; }
    var ref = this.stack, i = ref.length;
    while (0 <= --i) {
      if (ref[i][2] === id) {
        ref.splice(i, 1);
        break;
      }
    }
    return id;
  },
  SuppressMost: function(event) {
    var n = event.keyCode;
    return (n > KeyCodes.f1 + 1 && n <= KeyCodes.f12) ? 1 : 2;
  }
};
<|endoftext|>


<commit_before>var program = require('commander');

function ioscript(o) {
    program.
        version(o.version).
        option('-i --input <input>', 'input (file/directory)').
        option('-o --output <output>', 'output (file/directory)').
        option('-s --silent', 'silent').
        parse(o.args);
}

module.exports = ioscript;

<commit_msg>Show errors on missing input or output<commit_after>var program = require('commander');

function ioscript(o) {
    program.
        version(o.version).
        option('-i --input <input>', 'input (file/directory)').
        option('-o --output <output>', 'output (file/directory)').
        option('-s --silent', 'silent').
        parse(o.args);

    if(!program.input) quit('Missing input');
    if(!program.output) quit('Missing output');
}

function quit(msg) {
    console.log(msg);
    process.exit();
}

module.exports = ioscript;

<|endoftext|>


<commit_before>var cors_http = require("corsproxy");
var static_http = require("connect/lib/middleware/static");

module.exports = make_hoodie_server;

function make_hoodie_server(couchdb, name, host) {
  hoodie_server.couchdb = couchdb;
  hoodie_server.name = name;
  this.host = host;
  return hoodie_server.bind(this);
}

make_hoodie_server.prototype.serve_static = function(host, name) {
  if(host == name + "." + this.host) {
    return true;
  } else {
    return false;
  }
};

make_hoodie_server.prototype.serve_cors = function(host, name) {
  if(host == "api." + name + "." + this.host) {
    return true;
  } else {
    return false;
  }
};

var hoodie_server = function(req, res, proxy) {

  var host = req.headers.host;

  // frontend proxy duties
  //   if host == APPNAME.domain
  //     serve ./www
  if(this.serve_static(host, this.name)) {
    console.log("serve static req");
    var static_server = static_http("./www");
    return static_server(req, res, function() {});
  }
  //   if host == api.APPNAME.domain
  //     serve CORS
  if(this.serve_cors(host, this.name)) {
    console.log("serve api req");
    cors_http.options = {
      target: this.couchdb
    }
    return cors_http(req, res, proxy);
  }

  // launch httpd for Admin UI on $PORT + 1
  // TBD

  // TBD add default handler
};
<commit_msg>fix variable propagation<commit_after>var cors_http = require("corsproxy");
var static_http = require("connect/lib/middleware/static");

module.exports = make_hoodie_server;

function make_hoodie_server(couchdb, name, host) {
  hoodie_server.couchdb = couchdb;
  this.name = name;
  this.host = host;
  return hoodie_server.bind(this);
}

make_hoodie_server.prototype.serve_static = function(host, name) {
  if(host == name + "." + this.host) {
    return true;
  } else {
    return false;
  }
};

make_hoodie_server.prototype.serve_cors = function(host, name) {
  if(host == "api." + name + "." + this.host) {
    return true;
  } else {
    return false;
  }
};

var hoodie_server = function(req, res, proxy) {

  var host = req.headers.host;

  // frontend proxy duties
  //   if host == APPNAME.domain
  //     serve ./www
  if(this.serve_static(host, this.name)) {
    console.log("serve static req");
    var static_server = static_http("./www");
    return static_server(req, res, function() {});
  }
  //   if host == api.APPNAME.domain
  //     serve CORS
  if(this.serve_cors(host, this.name)) {
    console.log("serve api req");
    cors_http.options = {
      target: this.couchdb
    }
    return cors_http(req, res, proxy);
  }

  // launch httpd for Admin UI on $PORT + 1
  // TBD

  // TBD add default handler
};
<|endoftext|>


<commit_before>/*
Copyright 2019 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.

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.
*/

import React from 'react';
import PropTypes from 'prop-types';

import { _t } from "../../../../languageHandler";
import {MatrixClientPeg} from "../../../../MatrixClientPeg";
import * as sdk from '../../../../index';
import Modal from '../../../../Modal';
import AddThreepid from '../../../../AddThreepid';
import {replaceableComponent} from "../../../../utils/replaceableComponent";

/*
TODO: Improve the UX for everything in here.
It's very much placeholder, but it gets the job done. The old way of handling
email addresses in user settings was to use dialogs to communicate state, however
due to our dialog system overriding dialogs (causing unmounts) this creates problems
for a sane UX. For instance, the user could easily end up entering an email address
and receive a dialog to verify the address, which then causes the component here
to forget what it was doing and ultimately fail. Dialogs are still used in some
places to communicate errors - these should be replaced with inline validation when
that is available.
*/

/*
TODO: Reduce all the copying between account vs. discovery components.
*/

export class EmailAddress extends React.Component {
    static propTypes = {
        email: PropTypes.object.isRequired,
    };

    constructor(props) {
        super(props);

        const { bound } = props.email;

        this.state = {
            verifying: false,
            addTask: null,
            continueDisabled: false,
            bound,
        };
    }

    // TODO: [REACT-WARNING] Replace with appropriate lifecycle event
    UNSAFE_componentWillReceiveProps(nextProps) { // eslint-disable-line camelcase
        const { bound } = nextProps.email;
        this.setState({ bound });
    }

    async changeBinding({ bind, label, errorTitle }) {
        if (!await MatrixClientPeg.get().doesServerSupportSeparateAddAndBind()) {
            return this.changeBindingTangledAddBind({ bind, label, errorTitle });
        }

        const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
        const { medium, address } = this.props.email;

        try {
            if (bind) {
                const task = new AddThreepid();
                this.setState({
                    verifying: true,
                    continueDisabled: true,
                    addTask: task,
                });
                await task.bindEmailAddress(address);
                this.setState({
                    continueDisabled: false,
                });
            } else {
                await MatrixClientPeg.get().unbindThreePid(medium, address);
            }
            this.setState({ bound: bind });
        } catch (err) {
            console.error(`Unable to ${label} email address ${address} ${err}`);
            this.setState({
                verifying: false,
                continueDisabled: false,
                addTask: null,
            });
            Modal.createTrackedDialog(`Unable to ${label} email address`, '', ErrorDialog, {
                title: errorTitle,
                description: ((err && err.message) ? err.message : _t("Operation failed")),
            });
        }
    }

    async changeBindingTangledAddBind({ bind, label, errorTitle }) {
        const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
        const { medium, address } = this.props.email;

        const task = new AddThreepid();
        this.setState({
            verifying: true,
            continueDisabled: true,
            addTask: task,
        });

        try {
            await MatrixClientPeg.get().deleteThreePid(medium, address);
            if (bind) {
                await task.bindEmailAddress(address);
            } else {
                await task.addEmailAddress(address);
            }
            this.setState({
                continueDisabled: false,
                bound: bind,
            });
        } catch (err) {
            console.error(`Unable to ${label} email address ${address} ${err}`);
            this.setState({
                verifying: false,
                continueDisabled: false,
                addTask: null,
            });
            Modal.createTrackedDialog(`Unable to ${label} email address`, '', ErrorDialog, {
                title: errorTitle,
                description: ((err && err.message) ? err.message : _t("Operation failed")),
            });
        }
    }

    onRevokeClick = (e) => {
        e.stopPropagation();
        e.preventDefault();
        this.changeBinding({
            bind: false,
            label: "revoke",
            errorTitle: _t("Unable to revoke sharing for email address"),
        });
    }

    onShareClick = (e) => {
        e.stopPropagation();
        e.preventDefault();
        this.changeBinding({
            bind: true,
            label: "share",
            errorTitle: _t("Unable to share email address"),
        });
    }

    onContinueClick = async (e) => {
        e.stopPropagation();
        e.preventDefault();

        this.setState({ continueDisabled: true });
        try {
            await this.state.addTask.checkEmailLinkClicked();
            this.setState({
                addTask: null,
                continueDisabled: false,
                verifying: false,
            });
        } catch (err) {
            this.setState({ continueDisabled: false });
            const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
            if (err.errcode === 'M_THREEPID_AUTH_FAILED') {
                Modal.createTrackedDialog("E-mail hasn't been verified yet", "", ErrorDialog, {
                    title: _t("Your email address hasn't been verified yet"),
                    description: _t("Click the link in the email you received to verify " +
                        "and then click continue again."),
                });
            } else {
                console.error("Unable to verify email address: " + err);
                Modal.createTrackedDialog('Unable to verify email address', '', ErrorDialog, {
                    title: _t("Unable to verify email address."),
                    description: ((err && err.message) ? err.message : _t("Operation failed")),
                });
            }
        }
    }

    render() {
        const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
        const { address } = this.props.email;
        const { verifying, bound } = this.state;

        let status;
        if (verifying) {
            status =
                {_t("Verify the link in your inbox")}
                <AccessibleButton
                    className="mx_ExistingEmailAddress_confirmBtn"
                    kind="primary_sm"
                    onClick={this.onContinueClick}
                >
                    {_t("Complete")}
                </AccessibleButton>
            ;
        } else if (bound) {
            status = <AccessibleButton
                className="mx_ExistingEmailAddress_confirmBtn"
                kind="danger_sm"
                onClick={this.onRevokeClick}
            >
                {_t("Revoke")}
            </AccessibleButton>;
        } else {
            status = <AccessibleButton
                className="mx_ExistingEmailAddress_confirmBtn"
                kind="primary_sm"
                onClick={this.onShareClick}
            >
                {_t("Share")}
            </AccessibleButton>;
        }

        return (

                {address}
                {status}

        );
    }
}

@replaceableComponent("views.settings.discovery.EmailAddresses")
export default class EmailAddresses extends React.Component {
    static propTypes = {
        emails: PropTypes.array.isRequired,
    }

    render() {
        let content;
        if (this.props.emails.length > 0) {
            content = this.props.emails.map((e) => {
                return <EmailAddress email={e} key={e.address} />;
            });
        } else {
            content =
                {_t("Discovery options will appear once you have added an email above.")}
            ;
        }

        return (

                {content}

        );
    }
}
<commit_msg>Fixing the minor UI issues in the email discovery<commit_after>/*
Copyright 2019 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.

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.
*/

import React from 'react';
import PropTypes from 'prop-types';

import { _t } from "../../../../languageHandler";
import {MatrixClientPeg} from "../../../../MatrixClientPeg";
import * as sdk from '../../../../index';
import Modal from '../../../../Modal';
import AddThreepid from '../../../../AddThreepid';
import {replaceableComponent} from "../../../../utils/replaceableComponent";

/*
TODO: Improve the UX for everything in here.
It's very much placeholder, but it gets the job done. The old way of handling
email addresses in user settings was to use dialogs to communicate state, however
due to our dialog system overriding dialogs (causing unmounts) this creates problems
for a sane UX. For instance, the user could easily end up entering an email address
and receive a dialog to verify the address, which then causes the component here
to forget what it was doing and ultimately fail. Dialogs are still used in some
places to communicate errors - these should be replaced with inline validation when
that is available.
*/

/*
TODO: Reduce all the copying between account vs. discovery components.
*/

export class EmailAddress extends React.Component {
    static propTypes = {
        email: PropTypes.object.isRequired,
    };

    constructor(props) {
        super(props);

        const { bound } = props.email;

        this.state = {
            verifying: false,
            addTask: null,
            continueDisabled: false,
            bound,
        };
    }

    // TODO: [REACT-WARNING] Replace with appropriate lifecycle event
    UNSAFE_componentWillReceiveProps(nextProps) { // eslint-disable-line camelcase
        const { bound } = nextProps.email;
        this.setState({ bound });
    }

    async changeBinding({ bind, label, errorTitle }) {
        if (!await MatrixClientPeg.get().doesServerSupportSeparateAddAndBind()) {
            return this.changeBindingTangledAddBind({ bind, label, errorTitle });
        }

        const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
        const { medium, address } = this.props.email;

        try {
            if (bind) {
                const task = new AddThreepid();
                this.setState({
                    verifying: true,
                    continueDisabled: true,
                    addTask: task,
                });
                await task.bindEmailAddress(address);
                this.setState({
                    continueDisabled: false,
                });
            } else {
                await MatrixClientPeg.get().unbindThreePid(medium, address);
            }
            this.setState({ bound: bind });
        } catch (err) {
            console.error(`Unable to ${label} email address ${address} ${err}`);
            this.setState({
                verifying: false,
                continueDisabled: false,
                addTask: null,
            });
            Modal.createTrackedDialog(`Unable to ${label} email address`, '', ErrorDialog, {
                title: errorTitle,
                description: ((err && err.message) ? err.message : _t("Operation failed")),
            });
        }
    }

    async changeBindingTangledAddBind({ bind, label, errorTitle }) {
        const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
        const { medium, address } = this.props.email;

        const task = new AddThreepid();
        this.setState({
            verifying: true,
            continueDisabled: true,
            addTask: task,
        });

        try {
            await MatrixClientPeg.get().deleteThreePid(medium, address);
            if (bind) {
                await task.bindEmailAddress(address);
            } else {
                await task.addEmailAddress(address);
            }
            this.setState({
                continueDisabled: false,
                bound: bind,
            });
        } catch (err) {
            console.error(`Unable to ${label} email address ${address} ${err}`);
            this.setState({
                verifying: false,
                continueDisabled: false,
                addTask: null,
            });
            Modal.createTrackedDialog(`Unable to ${label} email address`, '', ErrorDialog, {
                title: errorTitle,
                description: ((err && err.message) ? err.message : _t("Operation failed")),
            });
        }
    }

    onRevokeClick = (e) => {
        e.stopPropagation();
        e.preventDefault();
        this.changeBinding({
            bind: false,
            label: "revoke",
            errorTitle: _t("Unable to revoke sharing for email address"),
        });
    }

    onShareClick = (e) => {
        e.stopPropagation();
        e.preventDefault();
        this.changeBinding({
            bind: true,
            label: "share",
            errorTitle: _t("Unable to share email address"),
        });
    }

    onContinueClick = async (e) => {
        e.stopPropagation();
        e.preventDefault();

        this.setState({ continueDisabled: true });
        try {
            await this.state.addTask.checkEmailLinkClicked();
            this.setState({
                addTask: null,
                continueDisabled: false,
                verifying: false,
            });
        } catch (err) {
            this.setState({ continueDisabled: false });
            const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
            if (err.errcode === 'M_THREEPID_AUTH_FAILED') {
                Modal.createTrackedDialog("E-mail hasn't been verified yet", "", ErrorDialog, {
                    title: _t("Your email address hasn't been verified yet"),
                    description: _t("Click the link in the email you received to verify " +
                        "and then click continue again."),
                });
            } else {
                console.error("Unable to verify email address: " + err);
                Modal.createTrackedDialog('Unable to verify email address', '', ErrorDialog, {
                    title: _t("Unable to verify email address."),
                    description: ((err && err.message) ? err.message : _t("Operation failed")),
                });
            }
        }
    }

    render() {
        const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
        const { address } = this.props.email;
        const { verifying, bound } = this.state;

        let status;
        if (verifying) {
            status =
                {_t("Verify the link in your inbox")}
                <AccessibleButton
                    className="mx_ExistingEmailAddress_confirmBtn"
                    kind="primary_sm"
                    onClick={this.onContinueClick}
                    disabled={this.state.continueDisabled}
                >
                    {_t("Complete")}
                </AccessibleButton>
            ;
        } else if (bound) {
            status = <AccessibleButton
                className="mx_ExistingEmailAddress_confirmBtn"
                kind="danger_sm"
                onClick={this.onRevokeClick}
            >
                {_t("Revoke")}
            </AccessibleButton>;
        } else {
            status = <AccessibleButton
                className="mx_ExistingEmailAddress_confirmBtn"
                kind="primary_sm"
                onClick={this.onShareClick}
            >
                {_t("Share")}
            </AccessibleButton>;
        }

        return (

                {address}
                {status}

        );
    }
}

@replaceableComponent("views.settings.discovery.EmailAddresses")
export default class EmailAddresses extends React.Component {
    static propTypes = {
        emails: PropTypes.array.isRequired,
    }

    render() {
        let content;
        if (this.props.emails.length > 0) {
            content = this.props.emails.map((e) => {
                return <EmailAddress email={e} key={e.address} />;
            });
        } else {
            content =
                {_t("Discovery options will appear once you have added an email above.")}
            ;
        }

        return (

                {content}

        );
    }
}
<|endoftext|>