<commit_before>/**
 * Used for JQuery Autocomplete dropdown input boxes
 */

/**
 * Helper function to call DWR search methods and put results into an autocomplete list
 *
 * Example use:
 *
 * new AutoComplete("person_name", new CreateCallback().personCallback(), {
 *			select: function(event, ui) {
 *				$j('#person_name_id').val(ui.item.object.personId);
 *			},
 *          placeholder:'<spring:message code="Person.search.placeholder" javaScriptEscape="true"/>'
 *		});
 *
 * General options:
 * onerror: a function to deal with errors

 * onsuccess: a function that gets called with the results if there are some and no error occurred
 * maxresults: limit the results to this. -1 means show all (defaults to 50)
 * placeholder: The text to appear as placeholder of the input text box
 *
 * See each *callback method below for more options that can be used
 *
 */
function CreateCallback(options) {
	if (options == null)
		options = {};

	var maxresults = options.maxresults;
	if (maxresults == null)
		maxresults = 50;

	// this will be the unique incrementing number assigned to the most recent query
	this.searchCounter = 0;

	/**
	 * Use this method if searching for general person objects
	 *
	 * additional options:
	 * roles: a comma separated list of role names to restrict to
	 */
	this.personCallback = function() { var thisObject = this; return function(q, response) {
		if (jQuery.trim(q).length == 0)
			return response(false);

		thisObject.searchCounter += 1;
		DWRPersonService.findPeopleByRoles(q, false, options.roles, thisObject.makeRows(q, response, thisObject.searchCounter, thisObject.displayPerson));
	}}

	/**
	 * Use this method if searching for patients
	 */
	this.patientCallback = function() { var thisObject = this; return function(q, response) {
		if (jQuery.trim(q).length == 0)
			return response(false);

		thisObject.searchCounter += 1;
		DWRPatientService.findPatients(q, false, thisObject.makeRows(q, response, thisObject.searchCounter, thisObject.displayPerson));
	}}

	/**
	 * Use this method if searching for users
	 *
	 * additional options:
	 * roles: a comma separated list of role names to restrict to
	 */
	this.userCallback = function() { var thisObject = this; return function(q, response) {
		if (jQuery.trim(q).length == 0)
			return response(false);

		var rolesArray = [];
		if (options.roles.length > 0)
			rolesArray = options.roles.split(",");

		thisObject.searchCounter += 1;
		DWRUserService.findUsers(q, rolesArray, false, thisObject.makeRows(q, response, thisObject.searchCounter, thisObject.displayPerson));
	}}

	/**
	 * Additional options:
	 * includeClasses: an array of class names to restrict to
	 * excludeClasses: an array of class names to leave out of the results
	 * includeDatatypes: an array of datatype names to restrict to
	 * excludeDatatypes: an array of datatype names to leave out of the results
	 */
	this.conceptCallback = function() { var thisObject = this; return function(q, response) {
		if (jQuery.trim(q).length == 0)
			return response(false);

		// changes a single element into an array
		var includeClasses = jQuery.makeArray(options.includeClasses);
		var excludeClasses = jQuery.makeArray(options.excludeClasses);
		var includeDatatypes = jQuery.makeArray(options.includeDatatypes);
		var excludeDatatypes = jQuery.makeArray(options.excludeDatatypes);
		/*$j("#log").html($j("#log").html() + "
" + thisObject.test + "--" + thisObject.testing);*/

		thisObject.searchCounter += 1;
		DWRConceptService.findConcepts(q, false, includeClasses, excludeClasses, includeDatatypes, excludeDatatypes, false, thisObject.makeRows(q, response, thisObject.searchCounter, thisObject.displayNamedObject));
	}}

	/**
	 * Additional options:
	 * showAnswersFor: a concept id. if non-null the search space is restricted to the answers to the given concept id
	 */
	this.conceptAnswersCallback = function() { var thisObject = this; return function(q, response) {
		// do NOT return false if no text given, instead should return all answers
		thisObject.searchCounter += 1;
		DWRConceptService.findConceptAnswers(q, options.showAnswersFor, false, false, thisObject.makeRows(q, response, thisObject.searchCounter, thisObject.displayNamedObject));
	}}

	/**
	 * Additional options:
	 * showAnswersFor: a concept id. if non-null the search space is restricted to the answers to the given concept id
	 */
	this.encounterCallback = function() { var thisObject = this; return function(q, response) {
		if (jQuery.trim(q).length == 0)
			return response(false);

		// do NOT return false if no text given, instead should return all answers
		thisObject.searchCounter += 1;
		DWREncounterService.findEncounters(q, false, thisObject.makeRows(q, response, thisObject.searchCounter, thisObject.displayEncounter));
	}}

	/**
	 * Use this method if searching for concept reference terms
	 * @param sourceElement (optional) the element whose value is the conceptSourceId for the source to search for terms
	 */
	this.conceptReferenceTermCallback = function(sourceElement) { var thisObject = this; return function(q, response) {
		if (jQuery.trim(q).length == 0)
			return response(false);
		var sourceId = null;
		if(sourceElement)
			sourceId = sourceElement.value;

		thisObject.searchCounter += 1;
		DWRConceptService.findBatchOfConceptReferenceTerms(q, sourceId, null, maxresults, false, thisObject.makeRows(q, response, thisObject.searchCounter, thisObject.displayConceptReferenceTerm));
	}}

	/*
	 * a 'private' method
	 * the method that dwr calls back with results
	 */
	this.makeRows = function(q, response, searchId, displayFunction) { var thisObject = this; return function(objs) {
		if (searchId < thisObject.searchCounter) {
			//alert("got a slow query with: '" + q + "' main counter at: " + thisObject.searchCounter);
			return;
		}
		else {
			//alert("not a slow query, " + q + " searchId: " + searchId + " main counter: " + thisObject.searchCounter);
			thisObject.searchCounter = searchId;
		}

		//convert objs from single obj into array (if needed)
		objs = jQuery.makeArray(objs);

		//check if we have an error
		if(options.onerror) {
			if(objs.length >= 1) {
				if(typeof objs[0] == 'string') {
					// we have an error, tell the user
					options.onerror(objs[0]);
					// clear other results
					response(false);

					return;
				}
			}
		}

		// let the caller know about a success (if they sent us a function to call)
		if (options.onsuccess)
			options.onsuccess(objs);

		if (maxresults > 0 && maxresults < objs.length) {
			var objectsSliced = objs.length - maxresults;
			objs = objs.slice(0, maxresults);
			objs.push("(" + objectsSliced + " " + omsgs.resultsNotDisplayed +")");
		}

		response(jQuery.map(objs, displayFunction(q)));
	}; }

	// a 'private' method
	// This is what maps each PersonListItem returned object to a name in the dropdown
	this.displayPerson = function(origQuery) { return function(person) {
		// dwr methods sometimes put strings into the results, just display those
		if (typeof person == 'string')
			return { label: person, value: "" };

		// item is a PersonListItem object
		var imageText = "";
		if (person.gender == 'M')
			imageText = "♂"; //";
		else if (person.gender == "F")
			imageText = "♀"; //""
		//else
		//	imageText = "?";

		// adding space here for both the regexp matching and the gap
		// between the image and the identifier
		var textShown = " ";

		if (person.identifier)
			textShown += person.identifier;

		textShown += " ";

		textShown += person.personName;

		// highlight each search term in the results
		textShown = highlightWords(textShown, origQuery);

		var ageText = "";
		if (person.age) {
			ageText = " (" + person.age + " " + omsgs.yearsOld + ")";
		}

		// append the gender image and age AFTER word highlighting so regex doesn't match it

		textShown = imageText + textShown + ageText; // space was inserted into beginning of 'textShown' var

		// wrap each result in a span tag (needed?)
		textShown = "" + textShown + "";

		return { label: textShown, value: person.personName, id: person.personId, object: person };
	}; }

	// a 'private' method
	// This is what maps each ConceptListItem or LocationListItem returned object to a name in the dropdown
	this.displayNamedObject = function(origQuery) { return function(item) {
		// dwr sometimes puts strings into the results, just display those
		if (typeof item == 'string')
			return { label: item, value: "" };

		// item is a ConceptListItem or LocationListItem object
		// add a space so the term highlighter below thinks the first word is a word
		var textShown = " " + item.name;

		// highlight each search term in the results
		textShown = highlightWords(textShown, origQuery);

		var value = item.name;
		if (item.preferredName) {
			textShown += " ⇒ " + item.preferredName + "";
			//value = item.preferredName;
		}

		textShown = "" + textShown + "";

		return { label: textShown, value: value, object: item};
	}; };

	// a 'private' method
	// This is what maps each EncounterListItem returned object to a name in the dropdown
	this.displayEncounter = function(origQuery) { return function(enc) {
		// dwr sometimes puts strings into the results, just display those
		if (typeof enc == 'string')
			return { label: enc, value: "" };

		// enc is an EncounterListenc
		// add a space so the term highlighter below thinks the first word is a word
		var textShown = " " + enc.encounterDateString;
		textShown += " " + enc.encounterType;
		textShown += " - " + enc.personName;
		textShown += " - " + enc.providerName;
		textShown += " - " + enc.location;

		// highlight each search term in the results
		textShown = highlightWords(textShown, origQuery);

		textShown = "" + textShown + "";

		value = enc.location + " - " + enc.encounterDateString;

		return { label: textShown, value: value, object: enc};
	}; };

	/*
	 * Private method, used when display persons or concepts to show
	 * which part of the word was a match.
	 *
	 * Each separate word in "origQuery" will be highlighted with a 'hit' class in
	 * the "textShown" string.
	 */
	function highlightWords(textShown, origQuery) {
		var words = origQuery.split(" ");
		for (var x=0; x<words.length; x++) {
			if (jQuery.trim(words[x]).length > 0) {
				var word = " " + words[x]; // only match the beginning of words
				// replace each occurrence case insensitively while replacing with original case
				textShown = textShown.replace(word, function(matchedTxt) { return "{{{{" + matchedTxt + "}}}}"}, "gi");
			}
		}

		textShown = textShown.replace(/{{{{/g, "");
		textShown = textShown.replace(/}}}}/g, "");

		return textShown;
	}

	// a 'private' method
	// This is what maps each ConceptListItem or LocationListItem returned object to a name in the dropdown
	this.displayConceptReferenceTerm = function(origQuery) { return function(item) {
		// dwr sometimes puts strings into the results, just display those
		if (typeof item == 'string')
			return { label: item, value: "" };

		var textShown = " " + item.code+((item.name != null && item.name.trim() != '') ? " - "+item.name : "")+" ["+item.conceptSourceName+"]";

		// highlight each search term in the results
		textShown = highlightWords(textShown, origQuery);

		var value = item.code;
		textShown = "" + textShown + "";

		return { label: textShown, value: value, object: item};
	}; };
}<commit_msg>Fixing: Encounter field tag should not display 'null' string for encounters with null location - TRUNK-2670<commit_after>/**
 * Used for JQuery Autocomplete dropdown input boxes
 */

/**
 * Helper function to call DWR search methods and put results into an autocomplete list
 *
 * Example use:
 *
 * new AutoComplete("person_name", new CreateCallback().personCallback(), {
 *			select: function(event, ui) {
 *				$j('#person_name_id').val(ui.item.object.personId);
 *			},
 *          placeholder:'<spring:message code="Person.search.placeholder" javaScriptEscape="true"/>'
 *		});
 *
 * General options:
 * onerror: a function to deal with errors

 * onsuccess: a function that gets called with the results if there are some and no error occurred
 * maxresults: limit the results to this. -1 means show all (defaults to 50)
 * placeholder: The text to appear as placeholder of the input text box
 *
 * See each *callback method below for more options that can be used
 *
 */
function CreateCallback(options) {
	if (options == null)
		options = {};

	var maxresults = options.maxresults;
	if (maxresults == null)
		maxresults = 50;

	// this will be the unique incrementing number assigned to the most recent query
	this.searchCounter = 0;

	/**
	 * Use this method if searching for general person objects
	 *
	 * additional options:
	 * roles: a comma separated list of role names to restrict to
	 */
	this.personCallback = function() { var thisObject = this; return function(q, response) {
		if (jQuery.trim(q).length == 0)
			return response(false);

		thisObject.searchCounter += 1;
		DWRPersonService.findPeopleByRoles(q, false, options.roles, thisObject.makeRows(q, response, thisObject.searchCounter, thisObject.displayPerson));
	}}

	/**
	 * Use this method if searching for patients
	 */
	this.patientCallback = function() { var thisObject = this; return function(q, response) {
		if (jQuery.trim(q).length == 0)
			return response(false);

		thisObject.searchCounter += 1;
		DWRPatientService.findPatients(q, false, thisObject.makeRows(q, response, thisObject.searchCounter, thisObject.displayPerson));
	}}

	/**
	 * Use this method if searching for users
	 *
	 * additional options:
	 * roles: a comma separated list of role names to restrict to
	 */
	this.userCallback = function() { var thisObject = this; return function(q, response) {
		if (jQuery.trim(q).length == 0)
			return response(false);

		var rolesArray = [];
		if (options.roles.length > 0)
			rolesArray = options.roles.split(",");

		thisObject.searchCounter += 1;
		DWRUserService.findUsers(q, rolesArray, false, thisObject.makeRows(q, response, thisObject.searchCounter, thisObject.displayPerson));
	}}

	/**
	 * Additional options:
	 * includeClasses: an array of class names to restrict to
	 * excludeClasses: an array of class names to leave out of the results
	 * includeDatatypes: an array of datatype names to restrict to
	 * excludeDatatypes: an array of datatype names to leave out of the results
	 */
	this.conceptCallback = function() { var thisObject = this; return function(q, response) {
		if (jQuery.trim(q).length == 0)
			return response(false);

		// changes a single element into an array
		var includeClasses = jQuery.makeArray(options.includeClasses);
		var excludeClasses = jQuery.makeArray(options.excludeClasses);
		var includeDatatypes = jQuery.makeArray(options.includeDatatypes);
		var excludeDatatypes = jQuery.makeArray(options.excludeDatatypes);
		/*$j("#log").html($j("#log").html() + "
" + thisObject.test + "--" + thisObject.testing);*/

		thisObject.searchCounter += 1;
		DWRConceptService.findConcepts(q, false, includeClasses, excludeClasses, includeDatatypes, excludeDatatypes, false, thisObject.makeRows(q, response, thisObject.searchCounter, thisObject.displayNamedObject));
	}}

	/**
	 * Additional options:
	 * showAnswersFor: a concept id. if non-null the search space is restricted to the answers to the given concept id
	 */
	this.conceptAnswersCallback = function() { var thisObject = this; return function(q, response) {
		// do NOT return false if no text given, instead should return all answers
		thisObject.searchCounter += 1;
		DWRConceptService.findConceptAnswers(q, options.showAnswersFor, false, false, thisObject.makeRows(q, response, thisObject.searchCounter, thisObject.displayNamedObject));
	}}

	/**
	 * Additional options:
	 * showAnswersFor: a concept id. if non-null the search space is restricted to the answers to the given concept id
	 */
	this.encounterCallback = function() { var thisObject = this; return function(q, response) {
		if (jQuery.trim(q).length == 0)
			return response(false);

		// do NOT return false if no text given, instead should return all answers
		thisObject.searchCounter += 1;
		DWREncounterService.findEncounters(q, false, thisObject.makeRows(q, response, thisObject.searchCounter, thisObject.displayEncounter));
	}}

	/**
	 * Use this method if searching for concept reference terms
	 * @param sourceElement (optional) the element whose value is the conceptSourceId for the source to search for terms
	 */
	this.conceptReferenceTermCallback = function(sourceElement) { var thisObject = this; return function(q, response) {
		if (jQuery.trim(q).length == 0)
			return response(false);
		var sourceId = null;
		if(sourceElement)
			sourceId = sourceElement.value;

		thisObject.searchCounter += 1;
		DWRConceptService.findBatchOfConceptReferenceTerms(q, sourceId, null, maxresults, false, thisObject.makeRows(q, response, thisObject.searchCounter, thisObject.displayConceptReferenceTerm));
	}}

	/*
	 * a 'private' method
	 * the method that dwr calls back with results
	 */
	this.makeRows = function(q, response, searchId, displayFunction) { var thisObject = this; return function(objs) {
		if (searchId < thisObject.searchCounter) {
			//alert("got a slow query with: '" + q + "' main counter at: " + thisObject.searchCounter);
			return;
		}
		else {
			//alert("not a slow query, " + q + " searchId: " + searchId + " main counter: " + thisObject.searchCounter);
			thisObject.searchCounter = searchId;
		}

		//convert objs from single obj into array (if needed)
		objs = jQuery.makeArray(objs);

		//check if we have an error
		if(options.onerror) {
			if(objs.length >= 1) {
				if(typeof objs[0] == 'string') {
					// we have an error, tell the user
					options.onerror(objs[0]);
					// clear other results
					response(false);

					return;
				}
			}
		}

		// let the caller know about a success (if they sent us a function to call)
		if (options.onsuccess)
			options.onsuccess(objs);

		if (maxresults > 0 && maxresults < objs.length) {
			var objectsSliced = objs.length - maxresults;
			objs = objs.slice(0, maxresults);
			objs.push("(" + objectsSliced + " " + omsgs.resultsNotDisplayed +")");
		}

		response(jQuery.map(objs, displayFunction(q)));
	}; }

	// a 'private' method
	// This is what maps each PersonListItem returned object to a name in the dropdown
	this.displayPerson = function(origQuery) { return function(person) {
		// dwr methods sometimes put strings into the results, just display those
		if (typeof person == 'string')
			return { label: person, value: "" };

		// item is a PersonListItem object
		var imageText = "";
		if (person.gender == 'M')
			imageText = "♂"; //";
		else if (person.gender == "F")
			imageText = "♀"; //""
		//else
		//	imageText = "?";

		// adding space here for both the regexp matching and the gap
		// between the image and the identifier
		var textShown = " ";

		if (person.identifier)
			textShown += person.identifier;

		textShown += " ";

		textShown += person.personName;

		// highlight each search term in the results
		textShown = highlightWords(textShown, origQuery);

		var ageText = "";
		if (person.age) {
			ageText = " (" + person.age + " " + omsgs.yearsOld + ")";
		}

		// append the gender image and age AFTER word highlighting so regex doesn't match it

		textShown = imageText + textShown + ageText; // space was inserted into beginning of 'textShown' var

		// wrap each result in a span tag (needed?)
		textShown = "" + textShown + "";

		return { label: textShown, value: person.personName, id: person.personId, object: person };
	}; }

	// a 'private' method
	// This is what maps each ConceptListItem or LocationListItem returned object to a name in the dropdown
	this.displayNamedObject = function(origQuery) { return function(item) {
		// dwr sometimes puts strings into the results, just display those
		if (typeof item == 'string')
			return { label: item, value: "" };

		// item is a ConceptListItem or LocationListItem object
		// add a space so the term highlighter below thinks the first word is a word
		var textShown = " " + item.name;

		// highlight each search term in the results
		textShown = highlightWords(textShown, origQuery);

		var value = item.name;
		if (item.preferredName) {
			textShown += " ⇒ " + item.preferredName + "";
			//value = item.preferredName;
		}

		textShown = "" + textShown + "";

		return { label: textShown, value: value, object: item};
	}; };

	// a 'private' method
	// This is what maps each EncounterListItem returned object to a name in the dropdown
	this.displayEncounter = function(origQuery) { return function(enc) {
		// dwr sometimes puts strings into the results, just display those
		if (typeof enc == 'string')
			return { label: enc, value: "" };

		// enc is an EncounterListenc
		// add a space so the term highlighter below thinks the first word is a word
		var textShown = " " + enc.encounterDateString;
		textShown += " " + enc.encounterType;
		textShown += " - " + enc.personName;
		textShown += " - " + enc.providerName;

		if (enc.location) {
			textShown += " - " + enc.location;
		}

		// highlight each search term in the results
		textShown = highlightWords(textShown, origQuery);

		textShown = "" + textShown + "";

		value = enc.location + " - " + enc.encounterDateString;

		return { label: textShown, value: value, object: enc};
	}; };

	/*
	 * Private method, used when display persons or concepts to show
	 * which part of the word was a match.
	 *
	 * Each separate word in "origQuery" will be highlighted with a 'hit' class in
	 * the "textShown" string.
	 */
	function highlightWords(textShown, origQuery) {
		var words = origQuery.split(" ");
		for (var x=0; x<words.length; x++) {
			if (jQuery.trim(words[x]).length > 0) {
				var word = " " + words[x]; // only match the beginning of words
				// replace each occurrence case insensitively while replacing with original case
				textShown = textShown.replace(word, function(matchedTxt) { return "{{{{" + matchedTxt + "}}}}"}, "gi");
			}
		}

		textShown = textShown.replace(/{{{{/g, "");
		textShown = textShown.replace(/}}}}/g, "");

		return textShown;
	}

	// a 'private' method
	// This is what maps each ConceptListItem or LocationListItem returned object to a name in the dropdown
	this.displayConceptReferenceTerm = function(origQuery) { return function(item) {
		// dwr sometimes puts strings into the results, just display those
		if (typeof item == 'string')
			return { label: item, value: "" };

		var textShown = " " + item.code+((item.name != null && item.name.trim() != '') ? " - "+item.name : "")+" ["+item.conceptSourceName+"]";

		// highlight each search term in the results
		textShown = highlightWords(textShown, origQuery);

		var value = item.code;
		textShown = "" + textShown + "";

		return { label: textShown, value: value, object: item};
	}; };
}<|endoftext|>


<commit_before>/**
 * Copyright 2017 M. I. Bell
 *
 * 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.
 **/

module.exports = function(RED) {
    function GateNode(config) {
        RED.nodes.createNode(this,config);
        var node = this;
        this.on('input', function(msg) {
            var context = this.context();
            this.controlTopic = config.controlTopic.toLowerCase();
            this.openCmd = config.openCmd.toLowerCase();
            this.closeCmd = config.closeCmd.toLowerCase();
            this.toggleCmd = config.toggleCmd.toLowerCase();
            this.defaultCmd = config.defaultCmd.toLowerCase();
            this.defaultState = config.defaultState.toLowerCase();
            var openStatus = {fill:"green",shape:"dot"};
            var closedStatus = {fill:"red",shape:"dot"};
            var state = context.get('state') || this.defaultState;
            var status;
            if (state === 'open') {
                status = openStatus;
            } else {
                status = closedStatus;
            }
            node.status(status);
            if (msg.topic.toLowerCase() === this.controlTopic) {
                switch (msg.payload.toLowerCase()) {
                    case this.openCmd:
                        state = 'open';
                        status = openStatus;
                        break;
                    case this.closeCmd:
                        state = 'closed';
                        status = closedStatus;
                        break;
                    case this.toggleCmd:
                        if (state === 'open') {
                            state = 'closed';
                            status = closedStatus;
                        } else {
                            state = 'open';
                            status = openStatus;
                        }
                        break;
                    case this.defaultCmd:
                        state = this.defaultState;
                        if (state === 'open') {
                            status = openStatus;
                        } else {
                            status = closedStatus;
                        }
                        break;
                    default:
                        node.error('Invalid command');
                        break;
                }
                context.set('state',state);
                node.status(status);
                node.send(null);
            }
            else if (state === 'open') {
                    node.send(msg);
                } else {
                    node.send(null);
            }
                    });
                }
                RED.nodes.registerType("gate",GateNode);
            }
<commit_msg>display status on deploy<commit_after>/**
 * Copyright 2017 M. I. Bell
 *
 * 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.
 **/

module.exports = function(RED) {
    function GateNode(config) {
        RED.nodes.createNode(this,config);
        this.defaultState = config.defaultState.toLowerCase();
        var openStatus = {fill:"green",shape:"dot"};
        var closedStatus = {fill:"red",shape:"dot"};
        var state = this.defaultState;
        if (state === 'open') {
        	this.status (openStatus);
        } else {
        	this.status (closedStatus);
        }
        this.warn ('starting up v0.0.2.4')
        this.on('input', function(msg) {
            var context = this.context();
            this.controlTopic = config.controlTopic.toLowerCase();
            this.openCmd = config.openCmd.toLowerCase();
            this.closeCmd = config.closeCmd.toLowerCase();
            this.toggleCmd = config.toggleCmd.toLowerCase();
            this.defaultCmd = config.defaultCmd.toLowerCase();
            var state = context.get('state') || this.defaultState;
            if (state === 'open') {
                this.status (openStatus);
            } else {
                this.status (closedStatus);
            }
           // Change state
            if (msg.topic.toLowerCase() === this.controlTopic) {
                switch (msg.payload.toLowerCase()) {
                    case this.openCmd:
                        state = 'open';
                        break;
                    case this.closeCmd:
                        state = 'closed';
                        break;
                    case this.toggleCmd:
                        if (state === 'open') {
                            state = 'closed';
                        } else {
                            state = 'open';
                        }
                        break;
                    case this.defaultCmd:
                        state = this.defaultState;
                        break;
                    default:
                        this.error('Invalid command');
                        break;
                }
                // Save state
                context.set('state',state);
                // Show status
                if (state === 'open') {
                    this.status (openStatus);
                } else {
                    this.status (closedStatus);
                }
                this.send(null);
            }
            // Transmit message
            else if (state === 'open') {
                    this.send(msg);
                } else {
                    this.send(null);
            }
        });
    }
    RED.nodes.registerType("gate",GateNode);
}
<|endoftext|>


<commit_before>/**
 * Created by damon on 15/12/13.
 */

/**
 * @param element {object} Such as, document.getElementById('id');
 * @constructor
 */
function Gate(element) {

    if (!this.isInitialize) {
        Gate.initialize();
    }

    // Create an empty <div> element if element is no provided
    if (element == null) {
        element = document.createElement('div');
    }

    // Set original position
    element.style.margin = '0px';
    element.style.padding = '0px';
    element.style.position = 'absolute';
    element.style[this.browserPrefix + 'TransformStyle'] = 'preserve-3d';
    element.style.width = this.width + 'px';
    element.style.height = this.height + 'px';
    element.style.opacity = this.opacity;

    this.domElement = element;
    this.domStyle = element.style;
    this.child = [];
    //console.log(this); // For debug
}

// Gate DOM element
Gate.prototype.domElement = null;

// Gate DOM's style
Gate.prototype.style = null;

// Initialize
Gate.prototype.isInitialize = false;

// Support browser old version.
Gate.prototype.transformProperty = 'Transform';

// Browser prefix
Gate.prototype.browserPrefix = '';

// The number of this.child
Gate.prototype.childNum = 0;

// domElement's width
Gate.prototype.width = 0;
// domElement's height
Gate.prototype.height = 0;

// The X axis position
Gate.prototype.x = 0;
// The Y axis position
Gate.prototype.y = 0;
// The Z axis position
Gate.prototype.z = 0;

// The X axis scale
Gate.prototype.scaleX = 1;
// The Y axis scale
Gate.prototype.scaleY = 1;
// The Z axis scale
Gate.prototype.scaleZ = 1;

// The X axis rotation
Gate.prototype.rotateX = 0;
// The Y axis rotation
Gate.prototype.rotateY = 0;
// The Z axis rotation
Gate.prototype.rotateZ = 0;

// Opacity
Gate.prototype.opacity = 1;

Gate.prototype.transition = false;

// Transform property
Gate.prototype.transformValue = '__translate __scale __rotateX __rotateY __rotateZ';

// Transform origin
Gate.prototype.transformOrigin = '0 0';

/**
 * Enable transition
 * @returns {Gate}
 */
Gate.prototype.enableTransition = function() {
    this.domStyle[this.browserPrefix + 'Transition'] = 'all 1s';
    return this;
};

/**
 * Set domElement opacity
 * @param o
 * @returns {Gate}
 */
Gate.prototype.setOpacity = function(o) {
    this.domStyle.opacity = o;
    return this;
};

/**
 * Set domElement width
 * @param w
 * @returns {Gate}
 */
Gate.prototype.setWidth = function(w) {
    this.domStyle.width = w + 'px';
    return this;
};

/**
 * Set domElement height
 * @param h
 * @returns {Gate}
 */
Gate.prototype.setHeight = function(h) {
    this.domStyle['height'] = h + 'px';
    return this;
};

/**
 * Set dom class name
 * @param className
 * @returns {Gate}
 */
Gate.prototype.setClassName = function(className) {
    this.domElement.className = className;
    return this;
};

/**
 * Get dom class name
 * @returns {*|string|string}
 */
Gate.prototype.getClassName = function() {
    return this.domElement.className;
};

/**
 * Add dom class name
 * @param className
 * @returns {Gate}
 */
Gate.prototype.addClassName = function(className) {
    this.domElement.className += ' ' + className + ' ';
    return this;
};

/**
 * Remove class name
 * @param className
 * @returns {Gate}
 */
Gate.prototype.removeClassName = function(className) {
    this.domElement.className += this.domElement.className.replace(className, '');
    return this;
};

/**
 * Set dom element id
 * @param id
 * @returns {*}
 */
Gate.prototype.setId = function(id) {
    this.domElement.id = id;
    return this;
};

/**
 * Get dom element id
 * @returns {*|string}
 */
Gate.prototype.getId = function() {
    return this.domElement.id;
};

/**
 * Append child element to this.domElement
 * @param ele {object} Gate object.
 * @returns {*}
 */
Gate.prototype.addChild = function(ele) {
    this.childNum = this.child.push(ele);
    this.domElement.appendChild(ele.domElement);
    return ele;
};

/**
 * Translate on X axis
 * @param x
 * @returns {Gate}
 */
Gate.prototype.moveX = function(x) {
    this.x += x;
    return this;
};

/**
 * Translate on Y axis
 * @param y
 * @returns {Gate}
 */
Gate.prototype.moveY = function(y) {
    this.y += y;
    return this;
};

/**
 * Translate on Z axis
 * @param z
 * @returns {Gate}
 */
Gate.prototype.moveZ = function(z) {
    this.z += z;
    return this;
};

/**
 * Set scale on X axis
 * @param x
 * @returns {Gate}
 */
Gate.prototype.setScaleX = function(x) {
    this.scaleX = x;
    return this;
};

/**
 * Set Scale on Y axis
 * @param y
 * @returns {Gate}
 */
Gate.prototype.setScaleY = function(y) {
    this.scaleY = y;
    return this;
};

Gate.prototype.setConScaleX = function(x) {
    this.scaleX += x;
    return this;
};

Gate.prototype.setConScaleY = function(y) {
    this.scaleY += y;
    return this;
};

/**
 * Set scale on Z axis
 * @param z
 * @returns {Gate}
 */
Gate.prototype.setScaleZ = function(z) {
    this.scaleZ = z;
    return this;
};

/**
 * Set rotation on X axis
 * @param x
 * @returns {Gate}
 */
Gate.prototype.setRotateX = function(x) {
    this.rotateX += x;
    return this;
};

/**
 * Set rotation on Y axis
 * @param y
 * @returns {Gate}
 */
Gate.prototype.setRotateY = function(y) {
    this.rotateY += y;
    return this;
};

/**
 * Set rotation on Z axis
 * @param z
 * @returns {Gate}
 */
Gate.prototype.setRotateZ = function(z) {
    this.rotateZ += z;
    return this;
};

/**
 * Set X axis position
 * @param x
 * @returns {Gate}
 */
Gate.prototype.setX = function(x) {
    this.x = x;
    return this;
};

/**
 * Set Y axis position
 * @param y
 * @returns {Gate}
 */
Gate.prototype.setY = function(y) {
    this.y = y;
    return this;
};

/**
 * Set Z axis position
 * @param z
 * @returns {Gate}
 */
Gate.prototype.setZ = function(z) {
    this.z = z;
    return this;
};

/**
 * Set transform origin
 * @param x
 * @param y
 * @param z
 * @returns {Gate}
 */
Gate.prototype.setTransformOrigin = function(x, y, z) {
    this.domStyle['transformOrigin'] = x + ' ' + y + ' ' + z;
    return this;
};

/**
 * Set domElement CSS
 * @param key
 * @param val
 * @returns {Gate}
 */
Gate.prototype.setCSS = function(key, val) {
    this.domStyle[key] = val;
    return this;
};

/**
 * Update all actions.
 * @returns {Gate}
 */
Gate.prototype.go = function() {
    this.translate = 'translate3d(' + this.x + 'px,' + this.y + 'px,' + this.z + 'px) ';
    this.scale = 'scale3d(' + this.scaleX + ',' + this.scaleY + ',' + this.scaleZ + ') ';
    this.rx = 'rotateX(' + this.rotateX + 'deg)';
    this.ry = 'rotateY(' + this.rotateY + 'deg)';
    this.rz = 'rotateZ(' + this.rotateZ + 'deg)';

    this.tv = this.transformValue;
    this.tv = this.tv.replace('__translate', this.translate);
    this.tv = this.tv.replace('__scale', this.scale);
    this.tv = this.tv.replace('__rotateX', this.rx);
    this.tv = this.tv.replace('__rotateY', this.ry);
    this.tv = this.tv.replace('__rotateZ', this.rz);

    this.domStyle[this.transformProperty] = this.tv;
    return this;
};

/**
 * Create main container div element
 * @returns {Gate}
 */
Gate.createStage = function(left, top) {
    var dom = document.createElement('div'),
        style = dom.style;

    if (!Gate.prototype.isInitialize) {
        Gate.initialize();
    }

    // Initialize 3D property
    style[Gate.prototype.browserPrefix + 'Perspective'] = '800px';
    style[Gate.prototype.browserPrefix + 'PerspectiveOrigin'] = '0 0';
    style[Gate.prototype.browserPrefix + 'TransformOrigin'] = this.transformOrigin;
    style[Gate.prototype.browserPrefix + 'Transform'] = 'translateZ(0px)';

    // Initialize style
    style.position = 'absolute';
    style.left = !left ? '0px' : left;
    style.top = !top ? '0px' : top;
    style.margin = '0px';
    style.padding = '0px';

    // Set class name
    dom.className = 'stage';

    // Append to body
    document.body.appendChild(dom);

    return new Gate(dom);
};

/**
 * Initialize
 * @returns {boolean}
 */
Gate.initialize = function() {
    var dom = document.createElement('div'),
        style = dom.style,
        supported = ['', 'webkit', 'moz', 'ms'],
        len = supported.length,
        i;

    // Check transform supported
    for (i = 0; i < len; i++) {
        if (supported[i] + 'Perspective' in style || supported[i] + 'Transform' in style) {
            Gate.prototype.isInitialize = true;
            Gate.prototype.transformProperty = supported[i] + 'Transform';
            Gate.prototype.browserPrefix = supported[i];
            return true;
        }
    }

    return false;
};<commit_msg>Comment for setConScaleX and setConScaleY.<commit_after>/**
 * Created by damon on 15/12/13.
 */

/**
 * @param element {object} Such as, document.getElementById('id');
 * @constructor
 */
function Gate(element) {

    if (!this.isInitialize) {
        Gate.initialize();
    }

    // Create an empty <div> element if element is no provided
    if (element == null) {
        element = document.createElement('div');
    }

    // Set original position
    element.style.margin = '0px';
    element.style.padding = '0px';
    element.style.position = 'absolute';
    element.style[this.browserPrefix + 'TransformStyle'] = 'preserve-3d';
    element.style.width = this.width + 'px';
    element.style.height = this.height + 'px';
    element.style.opacity = this.opacity;

    this.domElement = element;
    this.domStyle = element.style;
    this.child = [];
    //console.log(this); // For debug
}

// Gate DOM element
Gate.prototype.domElement = null;

// Gate DOM's style
Gate.prototype.style = null;

// Initialize
Gate.prototype.isInitialize = false;

// Support browser old version.
Gate.prototype.transformProperty = 'Transform';

// Browser prefix
Gate.prototype.browserPrefix = '';

// The number of this.child
Gate.prototype.childNum = 0;

// domElement's width
Gate.prototype.width = 0;
// domElement's height
Gate.prototype.height = 0;

// The X axis position
Gate.prototype.x = 0;
// The Y axis position
Gate.prototype.y = 0;
// The Z axis position
Gate.prototype.z = 0;

// The X axis scale
Gate.prototype.scaleX = 1;
// The Y axis scale
Gate.prototype.scaleY = 1;
// The Z axis scale
Gate.prototype.scaleZ = 1;

// The X axis rotation
Gate.prototype.rotateX = 0;
// The Y axis rotation
Gate.prototype.rotateY = 0;
// The Z axis rotation
Gate.prototype.rotateZ = 0;

// Opacity
Gate.prototype.opacity = 1;

Gate.prototype.transition = false;

// Transform property
Gate.prototype.transformValue = '__translate __scale __rotateX __rotateY __rotateZ';

// Transform origin
Gate.prototype.transformOrigin = '0 0';

/**
 * Enable transition
 * @returns {Gate}
 */
Gate.prototype.enableTransition = function() {
    this.domStyle[this.browserPrefix + 'Transition'] = 'all 1s';
    return this;
};

/**
 * Set domElement opacity
 * @param o
 * @returns {Gate}
 */
Gate.prototype.setOpacity = function(o) {
    this.domStyle.opacity = o;
    return this;
};

/**
 * Set domElement width
 * @param w
 * @returns {Gate}
 */
Gate.prototype.setWidth = function(w) {
    this.domStyle.width = w + 'px';
    return this;
};

/**
 * Set domElement height
 * @param h
 * @returns {Gate}
 */
Gate.prototype.setHeight = function(h) {
    this.domStyle['height'] = h + 'px';
    return this;
};

/**
 * Set dom class name
 * @param className
 * @returns {Gate}
 */
Gate.prototype.setClassName = function(className) {
    this.domElement.className = className;
    return this;
};

/**
 * Get dom class name
 * @returns {*|string|string}
 */
Gate.prototype.getClassName = function() {
    return this.domElement.className;
};

/**
 * Add dom class name
 * @param className
 * @returns {Gate}
 */
Gate.prototype.addClassName = function(className) {
    this.domElement.className += ' ' + className + ' ';
    return this;
};

/**
 * Remove class name
 * @param className
 * @returns {Gate}
 */
Gate.prototype.removeClassName = function(className) {
    this.domElement.className += this.domElement.className.replace(className, '');
    return this;
};

/**
 * Set dom element id
 * @param id
 * @returns {*}
 */
Gate.prototype.setId = function(id) {
    this.domElement.id = id;
    return this;
};

/**
 * Get dom element id
 * @returns {*|string}
 */
Gate.prototype.getId = function() {
    return this.domElement.id;
};

/**
 * Append child element to this.domElement
 * @param ele {object} Gate object.
 * @returns {*}
 */
Gate.prototype.addChild = function(ele) {
    this.childNum = this.child.push(ele);
    this.domElement.appendChild(ele.domElement);
    return ele;
};

/**
 * Translate on X axis
 * @param x
 * @returns {Gate}
 */
Gate.prototype.moveX = function(x) {
    this.x += x;
    return this;
};

/**
 * Translate on Y axis
 * @param y
 * @returns {Gate}
 */
Gate.prototype.moveY = function(y) {
    this.y += y;
    return this;
};

/**
 * Translate on Z axis
 * @param z
 * @returns {Gate}
 */
Gate.prototype.moveZ = function(z) {
    this.z += z;
    return this;
};

/**
 * Set scale on X axis
 * @param x
 * @returns {Gate}
 */
Gate.prototype.setScaleX = function(x) {
    this.scaleX = x;
    return this;
};

/**
 * Set Scale on Y axis
 * @param y
 * @returns {Gate}
 */
Gate.prototype.setScaleY = function(y) {
    this.scaleY = y;
    return this;
};

/**
 * Continued scale X
 * @param x
 * @returns {Gate}
 */
Gate.prototype.setConScaleX = function(x) {
    this.scaleX += x;
    return this;
};

/**
 * Continued scale y
 * @param y
 * @returns {Gate}
 */
Gate.prototype.setConScaleY = function(y) {
    this.scaleY += y;
    return this;
};

/**
 * Set scale on Z axis
 * @param z
 * @returns {Gate}
 */
Gate.prototype.setScaleZ = function(z) {
    this.scaleZ = z;
    return this;
};

/**
 * Set rotation on X axis
 * @param x
 * @returns {Gate}
 */
Gate.prototype.setRotateX = function(x) {
    this.rotateX += x;
    return this;
};

/**
 * Set rotation on Y axis
 * @param y
 * @returns {Gate}
 */
Gate.prototype.setRotateY = function(y) {
    this.rotateY += y;
    return this;
};

/**
 * Set rotation on Z axis
 * @param z
 * @returns {Gate}
 */
Gate.prototype.setRotateZ = function(z) {
    this.rotateZ += z;
    return this;
};

/**
 * Set X axis position
 * @param x
 * @returns {Gate}
 */
Gate.prototype.setX = function(x) {
    this.x = x;
    return this;
};

/**
 * Set Y axis position
 * @param y
 * @returns {Gate}
 */
Gate.prototype.setY = function(y) {
    this.y = y;
    return this;
};

/**
 * Set Z axis position
 * @param z
 * @returns {Gate}
 */
Gate.prototype.setZ = function(z) {
    this.z = z;
    return this;
};

/**
 * Set transform origin
 * @param x
 * @param y
 * @param z
 * @returns {Gate}
 */
Gate.prototype.setTransformOrigin = function(x, y, z) {
    this.domStyle['transformOrigin'] = x + ' ' + y + ' ' + z;
    return this;
};

/**
 * Set domElement CSS
 * @param key
 * @param val
 * @returns {Gate}
 */
Gate.prototype.setCSS = function(key, val) {
    this.domStyle[key] = val;
    return this;
};

/**
 * Update all actions.
 * @returns {Gate}
 */
Gate.prototype.go = function() {
    this.translate = 'translate3d(' + this.x + 'px,' + this.y + 'px,' + this.z + 'px) ';
    this.scale = 'scale3d(' + this.scaleX + ',' + this.scaleY + ',' + this.scaleZ + ') ';
    this.rx = 'rotateX(' + this.rotateX + 'deg)';
    this.ry = 'rotateY(' + this.rotateY + 'deg)';
    this.rz = 'rotateZ(' + this.rotateZ + 'deg)';

    this.tv = this.transformValue;
    this.tv = this.tv.replace('__translate', this.translate);
    this.tv = this.tv.replace('__scale', this.scale);
    this.tv = this.tv.replace('__rotateX', this.rx);
    this.tv = this.tv.replace('__rotateY', this.ry);
    this.tv = this.tv.replace('__rotateZ', this.rz);

    this.domStyle[this.transformProperty] = this.tv;
    return this;
};

/**
 * Create main container div element
 * @returns {Gate}
 */
Gate.createStage = function(left, top) {
    var dom = document.createElement('div'),
        style = dom.style;

    if (!Gate.prototype.isInitialize) {
        Gate.initialize();
    }

    // Initialize 3D property
    style[Gate.prototype.browserPrefix + 'Perspective'] = '800px';
    style[Gate.prototype.browserPrefix + 'PerspectiveOrigin'] = '0 0';
    style[Gate.prototype.browserPrefix + 'TransformOrigin'] = this.transformOrigin;
    style[Gate.prototype.browserPrefix + 'Transform'] = 'translateZ(0px)';

    // Initialize style
    style.position = 'absolute';
    style.left = !left ? '0px' : left;
    style.top = !top ? '0px' : top;
    style.margin = '0px';
    style.padding = '0px';

    // Set class name
    dom.className = 'stage';

    // Append to body
    document.body.appendChild(dom);

    return new Gate(dom);
};

/**
 * Initialize
 * @returns {boolean}
 */
Gate.initialize = function() {
    var dom = document.createElement('div'),
        style = dom.style,
        supported = ['', 'webkit', 'moz', 'ms'],
        len = supported.length,
        i;

    // Check transform supported
    for (i = 0; i < len; i++) {
        if (supported[i] + 'Perspective' in style || supported[i] + 'Transform' in style) {
            Gate.prototype.isInitialize = true;
            Gate.prototype.transformProperty = supported[i] + 'Transform';
            Gate.prototype.browserPrefix = supported[i];
            return true;
        }
    }

    return false;
};<|endoftext|>


<commit_before><commit_msg>mandelbrot nutzt nur noch einen shader, beseitigt crash auf Odroid XU4<commit_after><|endoftext|>


<commit_before>/**
 * Step 7
 * Where installation are run (npm, bower)
 */

var chalk = require('chalk');

module.exports = {
    /**
     * Install npm dependencies
     */
    installNpmDependencies: function () {
        if (!(this.options['skip-project-install'] || this.options['skip-all'])) {
            this.log(chalk.yellow('Start installing npm dependencies, please wait...'));
            this.npmInstall([], {
                color: 'always',
                verbose: this.options.verbose
            }, function (error) {
                if (error) {
                    console.error(error.stack || error);
                    return process.exit(1);
                }
            });
        }
    }
};
<commit_msg>Move on npm install done callback<commit_after>/**
 * Step 7
 * Where installation are run (npm, bower)
 */

var chalk = require('chalk');

/**
 * Triggers when npm install is done
 * @param {Object} error
 * @private
 */
function _onNpmInstallClose(error) {
    if (error) {
        console.error(error.stack || error);
        return process.exit(1);
    }
}

module.exports = {
    /**
     * Install npm dependencies
     */
    installNpmDependencies: function () {
        if (!(this.options['skip-project-install'] || this.options['skip-all'])) {
            this.log(chalk.yellow('Start installing npm dependencies, please wait...'));
            this.npmInstall([], {
                color: 'always',
                verbose: this.options.verbose
            }, _onNpmInstallClose.bind(this));
        }
    }
};
<|endoftext|>


<commit_before>"use strict";

const GSUI = {

	noop() {},
	dragshield: document.createElement( "gsui-dragshield" ),

	// .........................................................................
	clamp( n, min, max ) {
		return (
			min < max
				? Math.max( min, Math.min( n || 0, max ) )
				: Math.max( max, Math.min( n || 0, min ) )
		);
	},

	// .........................................................................
	diffObjects( a, b ) {
		let empty = true;
		const diff = Object.entries( b ).reduce( ( obj, [ bk, bv ] ) => {
				const av = a[ bk ],
					newval = av === bv ? undefined :
						typeof bv !== "object" || bv === null ? bv :
						typeof av !== "object" || av === null
							? Object.freeze( JSON.parse( JSON.stringify( bv ) ) )
							: GSUI.diffObjects( av, bv );

				if ( newval !== undefined ) {
					empty = false;
					obj[ bk ] = newval;
				}
				return obj;
			}, {} );

		return empty ? undefined : Object.freeze( diff );
	},

	// .........................................................................
	findElements( root, graph ) {
		return typeof graph === "string"
			? GSUI._findElemStr( root, graph )
			: Object.freeze( Array.isArray( graph )
				? GSUI._findElemArr( root, graph )
				: GSUI._findElemObj( root, graph ) );
	},
	_findElemArr( root, arr ) {
		return arr.map( sel => GSUI.findElements( root, sel ) );
	},
	_findElemObj( root, obj ) {
		const ent = Object.entries( obj );

		ent.forEach( kv => kv[ 1 ] = GSUI.findElements( root, kv[ 1 ] ) );
		return Object.fromEntries( ent );
	},
	_findElemStr( root, sel ) {
		if ( Array.isArray( root ) ) {
			let el;

			Array.prototype.find.call( root, r => el = GSUI._findElemQuery( r, sel ) );
			return el || null;
		}
		return GSUI._findElemQuery( root, sel );
	},
	_findElemQuery( root, sel ) {
		return root.matches( sel )
			? root
			: root.querySelector( sel );
	},

	// .........................................................................
	dispatchEvent( el, component, eventName, ...args ) {
		el.dispatchEvent( new CustomEvent( "gsuiEvents", {
			bubbles: true,
			detail: { component, eventName, args },
		} ) );
	},
	listenEvents( el, cbs ) {
		el.addEventListener( "gsuiEvents", e => {
			const d = e.detail,
				cbs2 = cbs[ d.component ] || cbs.default,
				fn = cbs2 && ( cbs2[ d.eventName ] || cbs2.default );

			if ( fn && fn( d, e.target, e ) !== true ) {
				e.stopPropagation();
				e.stopImmediatePropagation();
			}
		} );
	},

	// .........................................................................
	_templates: new Map(),
	setTemplate( tmpId, fn ) {
		GSUI._templates.set( tmpId, fn );
	},
	getTemplate( tmpId, ...args ) {
		return GSUI._templates.get( tmpId )( ...args );
	},

	// .........................................................................
	createElement( tag, attr, ...children ) {
		return GSUI._createElement( document.createElement( tag ), attr, children );
	},
	createElementNS( tag, attr, ...children ) {
		return GSUI._createElement( document.createElementNS( "http://www.w3.org/2000/svg", tag ), attr, children );
	},
	_createElement( el, attr, children ) {
		if ( attr ) {
			Object.entries( attr ).forEach( kv => GSUI.setAttribute( el, ...kv ) );
		}
		el.append( ...children.flat( 1 ).filter( Boolean ) );
		return el;
	},

	// .........................................................................
	_resizeMap: new Map(),
	observeSizeOf( el, fn ) {
		if ( GSUI._resizeMap.has( el ) ) {
			GSUI._resizeMap.get( el ).push( fn );
		} else {
			GSUI._resizeMap.set( el, [ fn ] );
		}
		GSUI._resizeObs.observe( el );
	},
	unobserveSizeOf( el, fn ) {
		const fns = GSUI._resizeMap.get( el ),
			fnInd = fns.indexOf( fn );

		GSUI._resizeObs.unobserve( el );
		if ( fnInd > -1 ) {
			fns.splice( fnInd, 1 );
			if ( fns.length === 0 ) {
				GSUI._resizeMap.delete( el );
			}
		}
	},
	_resizeObsCallback( entries ) {
		entries.forEach( e => GSUI._resizeMap.get( e.target )
			.forEach( fn => fn( e.contentRect.width, e.contentRect.height ) ) );
	},

	// .........................................................................
	unselectText() {
		window.getSelection().removeAllRanges();
	},
	setAttribute( el, attr, valBrut ) {
		const val = arguments.length === 2 || valBrut;

		val === false || val === null || val === undefined
			? el.removeAttribute( attr )
			: el.setAttribute( attr, val === true ? "" : val );
	},
	recallAttributes( el, props ) {
		Object.entries( props ).forEach( ( [ p, val ] ) => {
			el.hasAttribute( p )
				? el.attributeChangedCallback( p, null, el.getAttribute( p ) )
				: GSUI.setAttribute( el, p, val );
		} );
	},
};

GSUI._resizeObs = new ResizeObserver( GSUI._resizeObsCallback );

document.body.prepend( GSUI.dragshield );
<commit_msg>gsui.js: diff, fix<commit_after>"use strict";

const GSUI = {

	noop() {},
	dragshield: document.createElement( "gsui-dragshield" ),

	// .........................................................................
	clamp( n, min, max ) {
		return (
			min < max
				? Math.max( min, Math.min( n || 0, max ) )
				: Math.max( max, Math.min( n || 0, min ) )
		);
	},

	// .........................................................................
	diffObjects( a, b ) {
		let empty = true;
		const diff = Object.entries( b ).reduce( ( diff, [ bk, bv ] ) => {
				const av = a[ bk ],
					newval = av === bv ? undefined :
						typeof bv !== "object" || bv === null ? bv :
						typeof av !== "object" || av === null
							? Object.freeze( JSON.parse( JSON.stringify( bv ) ) )
							: GSUI.diffObjects( av, bv );

				if ( newval !== undefined ) {
					empty = false;
					diff[ bk ] = newval;
				}
				return diff;
			}, {} );

		Object.keys( a ).forEach( ak => {
			if ( !( ak in b ) ) {
				empty = false;
				diff[ ak ] = undefined;
			}
		} );
		return empty ? undefined : Object.freeze( diff );
	},

	// .........................................................................
	findElements( root, graph ) {
		return typeof graph === "string"
			? GSUI._findElemStr( root, graph )
			: Object.freeze( Array.isArray( graph )
				? GSUI._findElemArr( root, graph )
				: GSUI._findElemObj( root, graph ) );
	},
	_findElemArr( root, arr ) {
		return arr.map( sel => GSUI.findElements( root, sel ) );
	},
	_findElemObj( root, obj ) {
		const ent = Object.entries( obj );

		ent.forEach( kv => kv[ 1 ] = GSUI.findElements( root, kv[ 1 ] ) );
		return Object.fromEntries( ent );
	},
	_findElemStr( root, sel ) {
		if ( Array.isArray( root ) ) {
			let el;

			Array.prototype.find.call( root, r => el = GSUI._findElemQuery( r, sel ) );
			return el || null;
		}
		return GSUI._findElemQuery( root, sel );
	},
	_findElemQuery( root, sel ) {
		return root.matches( sel )
			? root
			: root.querySelector( sel );
	},

	// .........................................................................
	dispatchEvent( el, component, eventName, ...args ) {
		el.dispatchEvent( new CustomEvent( "gsuiEvents", {
			bubbles: true,
			detail: { component, eventName, args },
		} ) );
	},
	listenEvents( el, cbs ) {
		el.addEventListener( "gsuiEvents", e => {
			const d = e.detail,
				cbs2 = cbs[ d.component ] || cbs.default,
				fn = cbs2 && ( cbs2[ d.eventName ] || cbs2.default );

			if ( fn && fn( d, e.target, e ) !== true ) {
				e.stopPropagation();
				e.stopImmediatePropagation();
			}
		} );
	},

	// .........................................................................
	_templates: new Map(),
	setTemplate( tmpId, fn ) {
		GSUI._templates.set( tmpId, fn );
	},
	getTemplate( tmpId, ...args ) {
		return GSUI._templates.get( tmpId )( ...args );
	},

	// .........................................................................
	createElement( tag, attr, ...children ) {
		return GSUI._createElement( document.createElement( tag ), attr, children );
	},
	createElementNS( tag, attr, ...children ) {
		return GSUI._createElement( document.createElementNS( "http://www.w3.org/2000/svg", tag ), attr, children );
	},
	_createElement( el, attr, children ) {
		if ( attr ) {
			Object.entries( attr ).forEach( kv => GSUI.setAttribute( el, ...kv ) );
		}
		el.append( ...children.flat( 1 ).filter( Boolean ) );
		return el;
	},

	// .........................................................................
	_resizeMap: new Map(),
	observeSizeOf( el, fn ) {
		if ( GSUI._resizeMap.has( el ) ) {
			GSUI._resizeMap.get( el ).push( fn );
		} else {
			GSUI._resizeMap.set( el, [ fn ] );
		}
		GSUI._resizeObs.observe( el );
	},
	unobserveSizeOf( el, fn ) {
		const fns = GSUI._resizeMap.get( el ),
			fnInd = fns.indexOf( fn );

		GSUI._resizeObs.unobserve( el );
		if ( fnInd > -1 ) {
			fns.splice( fnInd, 1 );
			if ( fns.length === 0 ) {
				GSUI._resizeMap.delete( el );
			}
		}
	},
	_resizeObsCallback( entries ) {
		entries.forEach( e => GSUI._resizeMap.get( e.target )
			.forEach( fn => fn( e.contentRect.width, e.contentRect.height ) ) );
	},

	// .........................................................................
	unselectText() {
		window.getSelection().removeAllRanges();
	},
	setAttribute( el, attr, valBrut ) {
		const val = arguments.length === 2 || valBrut;

		val === false || val === null || val === undefined
			? el.removeAttribute( attr )
			: el.setAttribute( attr, val === true ? "" : val );
	},
	recallAttributes( el, props ) {
		Object.entries( props ).forEach( ( [ p, val ] ) => {
			el.hasAttribute( p )
				? el.attributeChangedCallback( p, null, el.getAttribute( p ) )
				: GSUI.setAttribute( el, p, val );
		} );
	},
};

GSUI._resizeObs = new ResizeObserver( GSUI._resizeObsCallback );

document.body.prepend( GSUI.dragshield );
<|endoftext|>


<commit_before>import {combineReducers} from "redux";

import app from './appReducers.ios.js';

export default combineReducers({
  app,
})<commit_msg>(Enhancement) Add AddIngredientReducer<commit_after>import {combineReducers} from "redux";

import app from './appReducers.ios.js';
import addIngredient from './addIngredientReducers.ios.js';

export default combineReducers({
  app,
  addIngredient,
})<|endoftext|>


<commit_before>const path = require('path');
const fs = require('fs');
const os = require('os');
/**
 * Util contains a number of static utility functions used throughout
 * the DART application. It has no constructor. Simply call Util.<method>(<args>)
 * to use any of its methods.
 *
 */

class Util {

    /**
      * Returns a version 4 uuid string.
      *
      * Thanks https://gist.github.com/kaizhu256/4482069
      * @returns {string }
      */
    static uuid4() {
        var uuid = '', ii;
        for (ii = 0; ii < 32; ii += 1) {
            switch (ii) {
            case 8:
            case 20:
                uuid += '-';
                uuid += (Math.random() * 16 | 0).toString(16);
                break;
            case 12:
                uuid += '-';
                uuid += '4';
                break;
            case 16:
                uuid += '-';
                uuid += (Math.random() * 4 | 8).toString(16);
                break;
            default:
                uuid += (Math.random() * 16 | 0).toString(16);
            }
        }
        return uuid;
    }

    /**
      * Returns the byte length of an utf8 string
      *
      * @param {string} str - The string to measure.
      * @returns {number}
      */
    static unicodeByteLength(str) {
        var s = str.length;
        for (var i=str.length-1; i>=0; i--) {
            var code = str.charCodeAt(i);
            if (code > 0x7f && code <= 0x7ff) s++;
            else if (code > 0x7ff && code <= 0xffff) s+=2;
            if (code >= 0xDC00 && code <= 0xDFFF) i--; //trail surrogate
        }
        return s;
    }

    /**
      * Returns true if str matches the regex for hex-formatted uuid.
      *
      * @param {string} str - The string to measure.
      * @returns {boolean}
      */
    static looksLikeUUID(str) {
        var match = null
        try {
            var re = /^([a-f\d]{8}(-[a-f\d]{4}){3}-[a-f\d]{12}?)$/i;
            match = str.match(re);
        } catch (ex) {
            // null string or non-string
        }
        return match != null;
    }

    /**
      * Returns true if str is null or empty.
      *
      * @param {string} str - The string to check.
      * @returns {boolean}
      */
    static isEmpty(str) {
        return (str == null || ((typeof str) == "string" && str.trim() == ""));
    }

    /**
      * Returns true if array of strings is empty, or if all elements
      * of the array are null or empty.
      *
      * @param {string[]} arr - The list of strings to check.
      * @returns {boolean}
      */
    static isEmptyStringArray(arr) {
        if(arr == null || arr.length == 0) {
            return true;
        }
        for(let str of arr) {
            if (!Util.isEmpty(str)) {
                return false;
            }
        }
        return true;
    }

    /**
      * Returns an array of strings, with all null and empty strings
      * removed.
      *
      * @param {string[]} arr - The list of strings to filter.
      * @returns {string[]} - The list of strings, minus null and empty entries.
      */
    static filterEmptyStrings(arr) {
        if(arr == null || !Array.isArray(arr)) {
            console.log(`filterEmpties: param arr is not an array. Value: ${arr}`)
            return [];
        }
        return arr.map(item => item? item.trim() : "").filter(item => item != "");
    }

    /**
      * Returns true if list contains item. The list should contain simple
      * scalar values that can be compared with a simple equality test.
      * This is similar to the builtin array.includes(), but includes some
      * special handling for boolean values.
      *
      * @param {string[]|number[]|boolean[]} list - The list items to search.
      * @param {string|number|boolean} item - The item to look for.
      * @returns {boolean} True if the item is in the list.
      */
    static listContains(list, item) {
        for (var i of list) {
            if (i == item || Util.boolEqual(i, item)) {
                return true;
            }
        }
        return false;
    }

    /**
      * Returns true if a and b are both non-null and both indicate
      * the same truth value. E.g. true = "true" = "yes" and
      * false = "false" = "no".
      *
      * @param {boolean|string} a - First value to compare.
      * @param {boolean|string} b - Second value to compare.
      * @returns {boolean} True if the two values indicate the same boolean value.
      */
    static boolEqual(a, b) {
        var aValue = Util.boolValue(a);
        var bValue = Util.boolValue(b);
        return (aValue != null && aValue == bValue);
    }

    /**
      * Returns the boolean value of a string. "true" and "yes"
      * are true. "false" and "no" are false. String is case-insensitive.
      *
      * @param {boolean|string} str - The string to examine.
      * @returns {boolean} The boolean value of the string, or null if it can't be determined.
      */
    static boolValue(str) {
        var lcString = String(str).toLowerCase();
        if (lcString == "true" || lcString == "yes") {
            return true;
        } else if (lcString == "false" || lcString == "no") {
            return false;
        }
        return null;
    }

    /**
     * toHumanSize returns a human-readable size for the given
     * number of bytes. The return value is trucated at two
     * decimal places. E.g. 2621440 converts to "2.50 MB"
     *
     * @param {number} bytes - The number of bytes to convert to human size.
     * @returns {string} - A human-readable string, like "2.5 MB"
     */
    static toHumanSize(bytes) {
        if (isNaN(bytes)) {
            return 'Not a Number';
        }
        var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
        var hs = bytes;
        for(var i=0; i < sizes.length; i++) {
            hs = bytes / (1024 ** i);
            if (hs < 1024) {
                break;
            }
        }
        return `${hs.toFixed(2)} ${sizes[i]}`;
    }

    /**
      * Truncates a string at len characters, and appends '..." to the end.
      *
      * @param {string} str - The string to truncate.
      * @param {number} len - Truncate the string at len characters.
      * @returns {string} - The truncated string, with three trailing dots.
      */
    static truncateString(str, len) {
        if (Util.isEmpty(str) || str.length <= len) {
            return str;
        }
        return str.slice(0, len - 1) + '...';
    }

    /**
	  * Converts an absolute Windows path to a path with forward slashes suitable
	  * for a BagIt file or tar file.
      *
      * @param {string} winPath - An absolute Windows path.
      * @returns {string} - Path with drive and share removed, and slashes leaning the right way.
      *
    */
	static normalizeWindowsPath(winPath) {
		// Remove C:
		winPath = winPath.replace(/^[A-Z]:/i, '');
		// Remove \\share
		winPath = winPath.replace(/^\\\\[^\\]+/, '');
		// Backslash to forward slash
		return winPath.replace(/\\/g, '/');
	}

    /**
     * walkSync recursively lists all files in a directory and its
     * subdirectories and returns them in filelist. If you want to
     * filter the list, include a callback filterFunction, which takes
     * the filepath as its sole param (a string) and returns true or
     * false to indicate whether to include the file in the list.
     *
     * The returned list is a list of hashes, and each hash has keys
     * absPath: the absolute path to the file
     * stats: a Node fs.Stats object with info about the file
     * The returned list will not include links, only files.
     *
     * @param {string} dir - Path to directory.
     * @param {filterFunction} filterFunction - A function to filter out items that should not go into filelist.
     * @returns {string[]} A list of file paths under dir that pass the filter.
    */
    static walkSync(dir, filterFunction) {
        var files = fs.readdirSync(dir);
        var filelist = [];
        filterFunction = filterFunction || function(file) { return true };
        files.forEach(function(file) {
            var absPath = path.join(dir, file);
            if (!fs.existsSync(absPath)) {
                //console.log(`Does not exist: ${absPath}`);
                return;  // Symlinks give ENOENT error
            }
            var stats = fs.statSync(absPath);
            if (stats.isDirectory()) {
                filelist = Util.walkSync(absPath, filelist, filterFunction);
            }
            else if (stats.isFile() && filterFunction(absPath)) {
                filelist.push({
                    absPath: absPath,
                    stats: stats
                });
            }
        });
        return filelist;
    };
}

module.exports.Util = Util;
<commit_msg>Added Util.getSortFunction()<commit_after>const path = require('path');
const fs = require('fs');
const os = require('os');
/**
 * Util contains a number of static utility functions used throughout
 * the DART application. It has no constructor. Simply call Util.<method>(<args>)
 * to use any of its methods.
 *
 */

class Util {

    /**
      * Returns a version 4 uuid string.
      *
      * Thanks https://gist.github.com/kaizhu256/4482069
      * @returns {string }
      */
    static uuid4() {
        var uuid = '', ii;
        for (ii = 0; ii < 32; ii += 1) {
            switch (ii) {
            case 8:
            case 20:
                uuid += '-';
                uuid += (Math.random() * 16 | 0).toString(16);
                break;
            case 12:
                uuid += '-';
                uuid += '4';
                break;
            case 16:
                uuid += '-';
                uuid += (Math.random() * 4 | 8).toString(16);
                break;
            default:
                uuid += (Math.random() * 16 | 0).toString(16);
            }
        }
        return uuid;
    }

    /**
      * Returns the byte length of an utf8 string
      *
      * @param {string} str - The string to measure.
      * @returns {number}
      */
    static unicodeByteLength(str) {
        var s = str.length;
        for (var i=str.length-1; i>=0; i--) {
            var code = str.charCodeAt(i);
            if (code > 0x7f && code <= 0x7ff) s++;
            else if (code > 0x7ff && code <= 0xffff) s+=2;
            if (code >= 0xDC00 && code <= 0xDFFF) i--; //trail surrogate
        }
        return s;
    }

    /**
      * Returns true if str matches the regex for hex-formatted uuid.
      *
      * @param {string} str - The string to measure.
      * @returns {boolean}
      */
    static looksLikeUUID(str) {
        var match = null
        try {
            var re = /^([a-f\d]{8}(-[a-f\d]{4}){3}-[a-f\d]{12}?)$/i;
            match = str.match(re);
        } catch (ex) {
            // null string or non-string
        }
        return match != null;
    }

    /**
      * Returns true if str is null or empty.
      *
      * @param {string} str - The string to check.
      * @returns {boolean}
      */
    static isEmpty(str) {
        return (str == null || ((typeof str) == "string" && str.trim() == ""));
    }

    /**
      * Returns true if array of strings is empty, or if all elements
      * of the array are null or empty.
      *
      * @param {string[]} arr - The list of strings to check.
      * @returns {boolean}
      */
    static isEmptyStringArray(arr) {
        if(arr == null || arr.length == 0) {
            return true;
        }
        for(let str of arr) {
            if (!Util.isEmpty(str)) {
                return false;
            }
        }
        return true;
    }

    /**
      * Returns an array of strings, with all null and empty strings
      * removed.
      *
      * @param {string[]} arr - The list of strings to filter.
      * @returns {string[]} - The list of strings, minus null and empty entries.
      */
    static filterEmptyStrings(arr) {
        if(arr == null || !Array.isArray(arr)) {
            //console.log(`filterEmpties: param arr is not an array. Value: ${arr}`)
            return [];
        }
        return arr.map(item => item? item.trim() : "").filter(item => item != "");
    }

    /**
      * Returns true if list contains item. The list should contain simple
      * scalar values that can be compared with a simple equality test.
      * This is similar to the builtin array.includes(), but includes some
      * special handling for boolean values.
      *
      * @param {string[]|number[]|boolean[]} list - The list items to search.
      * @param {string|number|boolean} item - The item to look for.
      * @returns {boolean} True if the item is in the list.
      */
    static listContains(list, item) {
        for (var i of list) {
            if (i == item || Util.boolEqual(i, item)) {
                return true;
            }
        }
        return false;
    }

    /**
      * Returns a function suitable for sorting a list of objects
      * in ascending or desdending order.
      *
      * @param {string} property - The name of the object property to sort on.
      * @param {string} direction - 'desc' or 'asc' for descending or ascending.
      * @returns {function} A function with params (a, b) where a and b are items to be compared.
      */
    static getSortFunction(property, direction) {
        if (direction == 'desc') {
            return function(a, b) {
                // descending sort
                if (a[property] < b[property]) { return 1; }
                if (a[property] > b[property]) { return -1; }
                return 0;
            };
        } else {
            return function(a, b) {
                // ascending sort
                if (a[property] < b[property]) { return -1; }
                if (a[property] > b[property]) { return 1; }
                return 0;
            }
        }
    }

    /**
      * Returns true if a and b are both non-null and both indicate
      * the same truth value. E.g. true = "true" = "yes" and
      * false = "false" = "no".
      *
      * @param {boolean|string} a - First value to compare.
      * @param {boolean|string} b - Second value to compare.
      * @returns {boolean} True if the two values indicate the same boolean value.
      */
    static boolEqual(a, b) {
        var aValue = Util.boolValue(a);
        var bValue = Util.boolValue(b);
        return (aValue != null && aValue == bValue);
    }

    /**
      * Returns the boolean value of a string. "true" and "yes"
      * are true. "false" and "no" are false. String is case-insensitive.
      *
      * @param {boolean|string} str - The string to examine.
      * @returns {boolean} The boolean value of the string, or null if it can't be determined.
      */
    static boolValue(str) {
        var lcString = String(str).toLowerCase();
        if (lcString == "true" || lcString == "yes") {
            return true;
        } else if (lcString == "false" || lcString == "no") {
            return false;
        }
        return null;
    }

    /**
     * toHumanSize returns a human-readable size for the given
     * number of bytes. The return value is trucated at two
     * decimal places. E.g. 2621440 converts to "2.50 MB"
     *
     * @param {number} bytes - The number of bytes to convert to human size.
     * @returns {string} - A human-readable string, like "2.5 MB"
     */
    static toHumanSize(bytes) {
        if (isNaN(bytes)) {
            return 'Not a Number';
        }
        var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
        var hs = bytes;
        for(var i=0; i < sizes.length; i++) {
            hs = bytes / (1024 ** i);
            if (hs < 1024) {
                break;
            }
        }
        return `${hs.toFixed(2)} ${sizes[i]}`;
    }

    /**
      * Truncates a string at len characters, and appends '..." to the end.
      *
      * @param {string} str - The string to truncate.
      * @param {number} len - Truncate the string at len characters.
      * @returns {string} - The truncated string, with three trailing dots.
      */
    static truncateString(str, len) {
        if (Util.isEmpty(str) || str.length <= len) {
            return str;
        }
        return str.slice(0, len - 1) + '...';
    }

    /**
	  * Converts an absolute Windows path to a path with forward slashes suitable
	  * for a BagIt file or tar file.
      *
      * @param {string} winPath - An absolute Windows path.
      * @returns {string} - Path with drive and share removed, and slashes leaning the right way.
      *
    */
	static normalizeWindowsPath(winPath) {
		// Remove C:
		winPath = winPath.replace(/^[A-Z]:/i, '');
		// Remove \\share
		winPath = winPath.replace(/^\\\\[^\\]+/, '');
		// Backslash to forward slash
		return winPath.replace(/\\/g, '/');
	}

    /**
     * walkSync recursively lists all files in a directory and its
     * subdirectories and returns them in filelist. If you want to
     * filter the list, include a callback filterFunction, which takes
     * the filepath as its sole param (a string) and returns true or
     * false to indicate whether to include the file in the list.
     *
     * The returned list is a list of hashes, and each hash has keys
     * absPath: the absolute path to the file
     * stats: a Node fs.Stats object with info about the file
     * The returned list will not include links, only files.
     *
     * @param {string} dir - Path to directory.
     * @param {filterFunction} filterFunction - A function to filter out items that should not go into filelist.
     * @returns {string[]} A list of file paths under dir that pass the filter.
    */
    static walkSync(dir, filterFunction) {
        var files = fs.readdirSync(dir);
        var filelist = [];
        filterFunction = filterFunction || function(file) { return true };
        files.forEach(function(file) {
            var absPath = path.join(dir, file);
            if (!fs.existsSync(absPath)) {
                //console.log(`Does not exist: ${absPath}`);
                return;  // Symlinks give ENOENT error
            }
            var stats = fs.statSync(absPath);
            if (stats.isDirectory()) {
                filelist = Util.walkSync(absPath, filelist, filterFunction);
            }
            else if (stats.isFile() && filterFunction(absPath)) {
                filelist.push({
                    absPath: absPath,
                    stats: stats
                });
            }
        });
        return filelist;
    };
}

module.exports.Util = Util;
<|endoftext|>