<commit_before>/***********
Spaz_Tooltip
***********/

var Spaz_Tooltip_Timeout = {};
var Spaz_Tooltip_hideTimeout = {};

function Spaz_Tooltip(opts) {
	this.event		= opts.e;
	this.el			= opts.el;
	this.str		= opts.str;
	this.previewurl = opts.previewurl;
}

Spaz_Tooltip.prototype.show = function() {

	/*
		Hide any open tooltips
	*/
	$('#tooltip').stop().hide().css('width', '').css('height', '');

	/*
		clear any running tooltip timeouts
	*/
	clearTimeout(Spaz_Tooltip_Timeout);
	clearTimeout(Spaz_Tooltip_hideTimeout);

	/*
		We have to make a closure here to solve the scoping problems
		with accessing object properties in the setTimeout callback
	*/
	var thisTT = this;

	//air.trace('delaying tooltip "'+this.str+'" for 500 mseconds');

	Spaz_Tooltip_Timeout = setTimeout(delayedShow, Spaz.Prefs.get('window-tooltipdelay'));

	function delayedShow() {
		Spaz.dump('showing tooltip "'+thisTT.str+'"');

		if (!thisTT.event) {
			Spaz.dump('No event found in Spaz_Tooltip.show; returning');
			return;
		}

		// Spaz.dump(thisTT.el);

		// air.trace("message: "+thisTT.str);

		// var minwidth = 100;

		// air.trace('EVENT')
		// Spaz.dump(thisTT.event)
		// air.trace('EL')
		// Spaz.dump(thisTT.el)
		// air.trace('STR')
		// Spaz.dump(thisTT.str)
		// air.trace('PREVIEWURL')
		// Spaz.dump(thisTT.previewurl)
		// air.trace('ARGUMENTS')
		// Spaz.dump(arguments)

		// show the tooltip
		$('#tooltip').css('left', thisTT.event.pageX+10)
			.css('top',  thisTT.event.pageY+20)
			.show()
			.css('opacity', 0)
			.animate({'opacity':'0.85'}, {speed:'fast'});
			// .animate({'opacity':'0.85'}, {speed:200, queue:false});

		$('#tooltip').children('.tooltip-msg').html(thisTT.str);
		$('#tooltip').children('.preview').empty();

		// Spaz.dump(tt[0].outerHTML);

		// Reset the .preview div ID so we don't display the wrong preview
		$('#tooltip').children('.preview').attr('id', '')

		if ($(thisTT.el).attr('user-screen_name')) {

			Spaz.dump('This is a user profile tooltip')

			//var username = $(thisTT.el).text().replace(/@/, '');
			var username = $(thisTT.el).attr('user-screen_name');

			Spaz.dump('username is '+username)

			var url = Spaz.Data.getAPIURL('user_timeline')
			var data = {
				'id':username,
				'count':1
			}

			var previewid = "preview-username-"+username;

			Spaz.dump('previewid = '+previewid);

			$('#tooltip').children('.preview').attr('id', previewid)

			$.get(url, data, function(data, textStatus) {
				// air.trace('textStatus:'+textStatus);
				// air.trace('DATA:'+data);
				try {
					var tweets = JSON.parse(data);

					Spaz.dump(tweets);

					if (tweets.error) {
						Spaz.dump('Error when getting preview data for tooltip');
						$('#tooltip').children('.preview').empty();
						$('#tooltip').children('.preview').append("
Could not retrieve user. Probably protected.
");
						$('#tooltip').children('.preview').append("
Error message from Twitter:\""+tweets.error+"\"
");
						Spaz.dump($('#tooltip')[0].outerHTML);
					} else {

						// air.trace('No errors when getting preview data for tooltip');
						if (tweets[0].text) {

							$('#'+previewid).empty();
							$('#'+previewid).append("");
							$('#'+previewid).append("
"+tweets[0].user.name+" ("+tweets[0].user.screen_name+")
");
							if (tweets[0].user.location) {
								$('#'+previewid).append("
"+tweets[0].user.location+"
");
							}
							if (tweets[0].user.followers_count) {
								$('#'+previewid).append("
"+tweets[0].user.followers_count+" followers
");
							}
							if (tweets[0].user.description) {
								$('#'+previewid).append("
"+tweets[0].user.description+"
");
							}
							$('#'+previewid).append('
Latest: '+tweets[0].text+'
');
							Spaz.dump($('#tooltip')[0].outerHTML);
						}

						$('#'+previewid).fadeIn(500);
						thisTT.resetTooltipPosition();

					}
					Spaz.dump($('#tooltip')[0].outerHTML);
				} catch(e) {
					Spaz.dump("An exception occurred when eval'ing the returned data. Error name: " + e.name
					+ ". Error message: " + e.message)
				}
			})

		} else if (thisTT.previewurl) {

			Spaz.dump('This is an URL preview tooltip')

			var previewid = "preview-link-"+getTimeAsInt();

			Spaz.dump('previewid = '+previewid);

			$('#tooltip').children('.preview').attr('id', previewid)

         if (thisTT.previewurl.search(/^http:\/\//i) > -1) {

            // Support for twitpic
            var done = false;

            //
            var twitpicRE = new RegExp("^(http:\\/\\/" + "twitpic.com\\/)" + "(.*)$");
            var twitpicMatch = thisTT.previewurl.match(twitpicRE);

            // First detect if we deal with a twitpic URL
            if (twitpicMatch != null)
            {
               var width = $('#tooltip').css("width");
               var widthRE = new RegExp("^([0-9]+)px$");
               var widthMatch = width.match(widthRE);

               // Check the width of the tooltip window is like number + px because we need
               // the value to correctly resize the image
               if (widthMatch != null)
               {
                  width = widthMatch[1];
                  var imgURL = twitpicMatch[1] + "show/thumb/" + twitpicMatch[2] + ".jpg";
                  var s = '';
                  $('#tooltip').children('.preview').empty();
                  $('#'+previewid).html(s);
                  $('#'+previewid).fadeIn(500);
                  thisTT.resetPosition()
                  done = true;
               }
               else
               {
                  air.trace("Could not find the width of the tooltip window " + width);
               }
            }

            if (!done)
            {
               $.get(thisTT.previewurl, function(rtext, status, xhr) {
                  // air.trace('rtext:'+rtext);
                  var rtext_matches = rtext.match(/<title>([^<]*)<\/title>/mi);

                  // alert(rtext_matches);

                  if (rtext_matches && rtext_matches[1]) {
                     var title = rtext_matches[1];
                     // air.trace('jqpreview.innerText:'+jqpreview[0].innerText);
                     $('#tooltip').children('.preview').empty();
                     $('#'+previewid).html('Title: '+title);
                     $('#'+previewid).fadeIn(500);
                     thisTT.resetPosition()
                  }
               });
            }
			}

		}

		var vp  = Spaz.UI.getViewport();
		var off = $('#tooltip').offset();

		// air.trace('Viewport:')
		// Spaz.dump(vp);
		// air.trace('Offset:')
		// Spaz.dump(off);

		// check horizontal position
		if (vp.x + vp.cx < off.left + $('#tooltip').width()) {
			// air.trace('horz over')
			$('#tooltip').css('left', parseInt($('#tooltip').css('left')) - ($('#tooltip').width() + 20));
			if ($('#tooltip').offset().left < 5) {
				$('#tooltip').css('left', 5);
			}
		}

		// check vertical position
		if(vp.y + vp.cy < off.top + $('#tooltip').height()) {
			// air.trace('vert over');
			$('#tooltip').css('top', parseInt($('#tooltip').css('top')) - ($('#tooltip').height() + 20));
			if ($('#tooltip').offset().top < 5) {
				$('#tooltip').css('top', 5);
			}
		}

		// air.trace('setting tooltip hide timeout');

		// air.trace('Tooltip hide delay:'+Spaz.Prefs.get('window-tooltiphidedelay'));

		Spaz_Tooltip_hideTimeout = setTimeout(Spaz.UI.hideTooltips, Spaz.Prefs.get('window-tooltiphidedelay'));
		// $('#tooltip').bind('mouseout', Spaz.UI.hideTooltips);
	}

}

/*
	I kinda stole this from the excellent jquery.tooltip
*/
Spaz_Tooltip.prototype.resetPosition = function() {
	var vp  = Spaz.UI.getViewport();
	var off = $('#tooltip').offset();

	// Spaz.dump(vp);
	// Spaz.dump(off);

	// Spaz.dump('reset width');
	// Spaz.dump("old width: "+$('#tooltip').width());

	var newWidth = vp.cx - off.left - 10;
	$('#tooltip').width( newWidth );

	// Spaz.dump("old width: "+newWidth);
};

<commit_msg>better support for twitpic : makes an ajax request to get the twitpic real URL since we cannot assume twitpic will use jpg format<commit_after>/***********
Spaz_Tooltip
***********/

var Spaz_Tooltip_Timeout = {};
var Spaz_Tooltip_hideTimeout = {};

function Spaz_Tooltip(opts) {
	this.event		= opts.e;
	this.el			= opts.el;
	this.str		= opts.str;
	this.previewurl = opts.previewurl;
}

Spaz_Tooltip.prototype.show = function() {

	/*
		Hide any open tooltips
	*/
	$('#tooltip').stop().hide().css('width', '').css('height', '');

	/*
		clear any running tooltip timeouts
	*/
	clearTimeout(Spaz_Tooltip_Timeout);
	clearTimeout(Spaz_Tooltip_hideTimeout);

	/*
		We have to make a closure here to solve the scoping problems
		with accessing object properties in the setTimeout callback
	*/
	var thisTT = this;

	//air.trace('delaying tooltip "'+this.str+'" for 500 mseconds');

	Spaz_Tooltip_Timeout = setTimeout(delayedShow, Spaz.Prefs.get('window-tooltipdelay'));

	function delayedShow() {
		Spaz.dump('showing tooltip "'+thisTT.str+'"');

		if (!thisTT.event) {
			Spaz.dump('No event found in Spaz_Tooltip.show; returning');
			return;
		}

		// Spaz.dump(thisTT.el);

		// air.trace("message: "+thisTT.str);

		// var minwidth = 100;

		// air.trace('EVENT')
		// Spaz.dump(thisTT.event)
		// air.trace('EL')
		// Spaz.dump(thisTT.el)
		// air.trace('STR')
		// Spaz.dump(thisTT.str)
		// air.trace('PREVIEWURL')
		// Spaz.dump(thisTT.previewurl)
		// air.trace('ARGUMENTS')
		// Spaz.dump(arguments)

		// show the tooltip
		$('#tooltip').css('left', thisTT.event.pageX+10)
			.css('top',  thisTT.event.pageY+20)
			.show()
			.css('opacity', 0)
			.animate({'opacity':'0.85'}, {speed:'fast'});
			// .animate({'opacity':'0.85'}, {speed:200, queue:false});

		$('#tooltip').children('.tooltip-msg').html(thisTT.str);
		$('#tooltip').children('.preview').empty();

		// Spaz.dump(tt[0].outerHTML);

		// Reset the .preview div ID so we don't display the wrong preview
		$('#tooltip').children('.preview').attr('id', '')

		if ($(thisTT.el).attr('user-screen_name')) {

			Spaz.dump('This is a user profile tooltip')

			//var username = $(thisTT.el).text().replace(/@/, '');
			var username = $(thisTT.el).attr('user-screen_name');

			Spaz.dump('username is '+username)

			var url = Spaz.Data.getAPIURL('user_timeline')
			var data = {
				'id':username,
				'count':1
			}

			var previewid = "preview-username-"+username;

			Spaz.dump('previewid = '+previewid);

			$('#tooltip').children('.preview').attr('id', previewid)

			$.get(url, data, function(data, textStatus) {
				// air.trace('textStatus:'+textStatus);
				// air.trace('DATA:'+data);
				try {
					var tweets = JSON.parse(data);

					Spaz.dump(tweets);

					if (tweets.error) {
						Spaz.dump('Error when getting preview data for tooltip');
						$('#tooltip').children('.preview').empty();
						$('#tooltip').children('.preview').append("
Could not retrieve user. Probably protected.
");
						$('#tooltip').children('.preview').append("
Error message from Twitter:\""+tweets.error+"\"
");
						Spaz.dump($('#tooltip')[0].outerHTML);
					} else {

						// air.trace('No errors when getting preview data for tooltip');
						if (tweets[0].text) {

							$('#'+previewid).empty();
							$('#'+previewid).append("");
							$('#'+previewid).append("
"+tweets[0].user.name+" ("+tweets[0].user.screen_name+")
");
							if (tweets[0].user.location) {
								$('#'+previewid).append("
"+tweets[0].user.location+"
");
							}
							if (tweets[0].user.followers_count) {
								$('#'+previewid).append("
"+tweets[0].user.followers_count+" followers
");
							}
							if (tweets[0].user.description) {
								$('#'+previewid).append("
"+tweets[0].user.description+"
");
							}
							$('#'+previewid).append('
Latest: '+tweets[0].text+'
');
							Spaz.dump($('#tooltip')[0].outerHTML);
						}

						$('#'+previewid).fadeIn(500);
						thisTT.resetTooltipPosition();

					}
					Spaz.dump($('#tooltip')[0].outerHTML);
				} catch(e) {
					Spaz.dump("An exception occurred when eval'ing the returned data. Error name: " + e.name
					+ ". Error message: " + e.message)
				}
			})

		} else if (thisTT.previewurl) {

			Spaz.dump('This is an URL preview tooltip')

			var previewid = "preview-link-"+getTimeAsInt();

			Spaz.dump('previewid = '+previewid);

			$('#tooltip').children('.preview').attr('id', previewid)

         if (thisTT.previewurl.search(/^http:\/\//i) > -1) {

            // Support for twitpic
            var done = false;

            //
            var twitpicRE = new RegExp("^(http:\\/\\/" + "twitpic.com\\/)" + "(.+)$");
            var twitpicMatch = thisTT.previewurl.match(twitpicRE);

            // First detect if we deal with a twitpic URL
            if (twitpicMatch != null)
            {
               var width = $('#tooltip').css("width");
               var widthRE = new RegExp("^([0-9]+)px$");
               var widthMatch = width.match(widthRE);

               // Check the width of the tooltip window is like number + px because we need
               // the value to correctly resize the image
               if (widthMatch != null)
               {
                  done = true;
                  width = widthMatch[1];

                  //
                  $.get(thisTT.previewurl, function(text)
                  {
                     var imgURLPrefix = twitpicMatch[1] + "show/thumb/" + twitpicMatch[2] + ".";
                     air.trace("Going to look for real thumbnail URL using the prefix " + imgURLPrefix);
                     var index = text.indexOf(imgURLPrefix);
                     air.trace("Index of real thumbnail URL is " + index);
                     if (index != -1)
                     {
                        var imgURL = text.substring(index, index + imgURLPrefix.length + 3);
                        air.trace("Real URL is " + imgURL);

                        //
                        var s = '';
                        $('#tooltip').children('.preview').empty();
                        $('#'+previewid).html(s);
                        air.trace("HTML is " + s);
                        $('#'+previewid).fadeIn(500);
                        thisTT.resetPosition();
                     }
                     else
                     {
                        air.trace("Could not find the real thumbnail URL using the prefix " + imgURLPrefix);
                     }
                  });
               }
               else
               {
                  air.trace("Could not find the width of the tooltip window " + width);
               }
            }

            if (!done)
            {
               $.get(thisTT.previewurl, function(rtext, status, xhr) {
                  // air.trace('rtext:'+rtext);
                  var rtext_matches = rtext.match(/<title>([^<]*)<\/title>/mi);

                  // alert(rtext_matches);

                  if (rtext_matches && rtext_matches[1]) {
                     var title = rtext_matches[1];
                     // air.trace('jqpreview.innerText:'+jqpreview[0].innerText);
                     $('#tooltip').children('.preview').empty();
                     $('#'+previewid).html('Title: '+title);
                     $('#'+previewid).fadeIn(500);
                     thisTT.resetPosition();
                  }
               });
            }
			}

		}

		var vp  = Spaz.UI.getViewport();
		var off = $('#tooltip').offset();

		// air.trace('Viewport:')
		// Spaz.dump(vp);
		// air.trace('Offset:')
		// Spaz.dump(off);

		// check horizontal position
		if (vp.x + vp.cx < off.left + $('#tooltip').width()) {
			// air.trace('horz over')
			$('#tooltip').css('left', parseInt($('#tooltip').css('left')) - ($('#tooltip').width() + 20));
			if ($('#tooltip').offset().left < 5) {
				$('#tooltip').css('left', 5);
			}
		}

		// check vertical position
		if(vp.y + vp.cy < off.top + $('#tooltip').height()) {
			// air.trace('vert over');
			$('#tooltip').css('top', parseInt($('#tooltip').css('top')) - ($('#tooltip').height() + 20));
			if ($('#tooltip').offset().top < 5) {
				$('#tooltip').css('top', 5);
			}
		}

		// air.trace('setting tooltip hide timeout');

		// air.trace('Tooltip hide delay:'+Spaz.Prefs.get('window-tooltiphidedelay'));

		Spaz_Tooltip_hideTimeout = setTimeout(Spaz.UI.hideTooltips, Spaz.Prefs.get('window-tooltiphidedelay'));
		// $('#tooltip').bind('mouseout', Spaz.UI.hideTooltips);
	}

}

/*
	I kinda stole this from the excellent jquery.tooltip
*/
Spaz_Tooltip.prototype.resetPosition = function() {
	var vp  = Spaz.UI.getViewport();
	var off = $('#tooltip').offset();

	// Spaz.dump(vp);
	// Spaz.dump(off);

	// Spaz.dump('reset width');
	// Spaz.dump("old width: "+$('#tooltip').width());

	var newWidth = vp.cx - off.left - 10;
	$('#tooltip').width( newWidth );

	// Spaz.dump("old width: "+newWidth);
};

<|endoftext|>


<commit_before>/*
*     (C) Copyright 2008 Telefonica Investigacion y Desarrollo
*     S.A.Unipersonal (Telefonica I+D)
*
*     This file is part of Morfeo EzWeb Platform.
*
*     Morfeo EzWeb Platform is free software: you can redistribute it and/or modify
*     it under the terms of the GNU Affero General Public License as published by
*     the Free Software Foundation, either version 3 of the License, or
*     (at your option) any later version.
*
*     Morfeo EzWeb Platform is distributed in the hope that it will be useful,
*     but WITHOUT ANY WARRANTY; without even the implied warranty of
*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*     GNU Affero General Public License for more details.
*
*     You should have received a copy of the GNU Affero General Public License
*     along with Morfeo EzWeb Platform.  If not, see <http://www.gnu.org/licenses/>.
*
*     Info about members and contributors of the MORFEO project
*     is available at
*
*     http://morfeo-project.org
 */

function ContextManager (workspace_, workSpaceInfo_) {

	// ***********************
	// PRIVATED FUNCTIONS
	// ***********************

	/**
	 * Adds all variables from workspace data model
	 */
	this._addContextVarsFromTemplate = function (iGadget, cVars, type) {
		var varManager = this._workspace.getVarManager();
		for (var i = 0; i < cVars.size(); i++) {
			var cVar = cVars[i];
			cVar.setVarManager(varManager);
			var conceptName = cVar.getConceptName();
			var relatedConcept = this._name2Concept[conceptName];
			if (relatedConcept != null && relatedConcept._type != type)
				relatedConcept = null;

			if (relatedConcept == null) {
				var msg = gettext("There is not any concept of type \"%(type)s\" called \"%(concept)s\", the value of the iGadget variable \"%(varName)s\" will be empty.");
				msg = interpolate(msg, {concept: conceptName, type: type, varName: cVar.getName()}, true);
				OpManagerFactory.getInstance().logIGadgetError(iGadget.getId(), msg, Constants.Logging.ERROR_MSG);
				continue;
			}
			relatedConcept.addIGadgetVar(cVar);
		}
	}

	// Loads all concept from workspace data model.
	this._loadConceptsFromWorkspace = function (workSpaceInfo_) {
		this._concepts = new Hash();
		this._name2Concept = new Hash();

		var conceptsJson = workSpaceInfo_['workspace']['concepts'];

		// Parses concepts json
		for (var i = 0; i < conceptsJson.length; i++) {
			var curConcept = conceptsJson[i];
			// Creates the concept
			var concept = new Concept(curConcept.concept, curConcept.type, curConcept.adaptor);
			this._concepts[curConcept.concept] = concept;

			// Sets the concept value
			if (curConcept.value != undefined) {
				concept._setInitialValue(curConcept.value)
			}

			// Relates the concept name to all its concept
			for (var j = 0; j < curConcept.names.length; j++) {
				var cname = curConcept.names[j];
				var oldConcept = this._name2Concept[cname]
				if (oldConcept != null) {
					var msg = gettext("WARNING: concept name '%(cname)s' is already related to '%(concept)s'. New related concept is '%(newConcept)s'.");
					msg = interpolate(msg, {cname: cname, concept: oldConcept, newConcept: curConcept.concept}, true);
					LogManagerFactory.getInstance().log(msg);
				}
				this._name2Concept[cname] = concept;
			}
		}
	}

	// Load igadget's context variables from workspace data model
	this._loadIGadgetContextVarsFromWorkspace = function (workSpaceInfo) {

		var tabs = workSpaceInfo['workspace']['tabList'];

		// Tabs in workspace
		for (var i=0; i<tabs.length; i++) {
			var currentTab = tabs[i];
			var igadgets = currentTab.igadgetList;

			// igadgets in tab
			for (var j=0; j<igadgets.length; j++) {
				var currentIGadget = igadgets[j];
				var variables = currentIGadget['variables'];

				// Variables of igadgets
				for (var k = 0; k < variables.length; k++) {
				var currentVar = variables[k];
					switch (currentVar.aspect) {
					case Variable.prototype.EXTERNAL_CONTEXT:
					case Variable.prototype.GADGET_CONTEXT:
						var contextVar = new ContextVar(currentIGadget.id, currentVar.name, currentVar.concept)
						contextVar.setVarManager(this._workspace.getVarManager());
						var relatedConcept = this._name2Concept[currentVar.concept];
						if (relatedConcept) {
							if (currentVar.aspect !== relatedConcept._type) {
								var msg = gettext("There is not any concept of type \"%(type)s\" called \"%(concept)s\", the value of the iGadget variable \"%(varName)s\" will be empty.");
								msg = interpolate(msg,
									{concept: currentVar.concept,
									 type: relatedConcept._type,
									 varName: currentVar.name},
									true);
								OpManagerFactory.getInstance().logIGadgetError(currentIGadget.id, msg, Constants.Logging.ERROR_MSG);
							} else {
								relatedConcept.addIGadgetVar(contextVar);
							}
						}
						break;
					default:
						break;
					}
				}
			}
		}

		// Continues loading next module
		this._loaded = true;
	}

	// ****************
	// PUBLIC METHODS
	// ****************

	ContextManager.prototype.addInstance = function (iGadget, template) {
		if (!this._loaded)
			return;

		if (template == null)
			return;

		this._addContextVarsFromTemplate(iGadget, template.getExternalContextVars(iGadget.getId()), Concept.prototype.EXTERNAL);
		this._addContextVarsFromTemplate(iGadget, template.getGadgetContextVars(iGadget.getId()), Concept.prototype.IGADGET);
	}

	ContextManager.prototype.iGadgetLoaded = function (iGadget) {
		if (!this._loaded)
			return;

		var iGadgetId = iGadget.getId();
		var keys = this._concepts.keys();
		for (var i = 0; i < keys.length; i++) {
			var concept = this._concepts[keys[i]];
			concept.propagateIGadgetVarValues(iGadget);
		}
	}

	ContextManager.prototype.iGadgetUnloaded = function (iGadget) {
		if (!this._loaded)
			return;

		var keys = this._concepts.keys();
		for (var i = 0; i < keys.length; i++) {
			var concept = this._concepts[keys[i]];
			if (concept._type !== Concept.prototype.IGADGET)
				continue;

			var ivar = concept.getIGadgetVar(iGadget.getId());
			if (ivar != null)
				ivar._clearHandler();
		}
	}

	ContextManager.prototype.removeInstance = function (iGadgetId_) {
		if (!this._loaded)
			return;

		var keys = this._concepts.keys();
		for (var i = 0; i < keys.length; i++) {
			var key = keys[i];
			this._concepts[key].deleteIGadgetVars(iGadgetId_);
		}
	}

	/**
	 * Notifies a value change on an platform context concept.
	 *
	 * @param {String} concept
	 * @param {} value
	 */
	ContextManager.prototype.notifyModifiedConcept = function (concept, value) {
		if (!this._loaded)
			return;

		if (!this._concepts[concept])
			return;

		this._concepts[concept].setValue(value);
	}

	/**
	 * Notifies a value change on an igadget context concept.
	 *
	 * @param {iGadget} iGadget
	 * @param {String} concept
	 * @param {} value
	 */
	ContextManager.prototype.notifyModifiedGadgetConcept = function (iGadget, concept, value) {
		if (!this._loaded)
			return;

		if (this._concepts[concept] == null)
			return;

		var ivar = this._concepts[concept].getIGadgetVar(iGadget.getId());
		if (ivar == null) {
			// Do nothing, igadget has not variables related to this concept
			return;
		}

		ivar.setValue(value);
	}

	ContextManager.prototype.getWorkspace = function () {
		return this._workspace;
	}

	ContextManager.prototype.unload = function () {
		var i, namekeys, conceptkeys;

		// Delete all concept names
		namekeys = this._name2Concept.keys();
		for (i = 0; i < namekeys.length; i++) {
			delete this._name2Concept[namekeys[i]];
		}
		delete this._name2Concept;

		// Delete all the concepts
		conceptkeys = this._concepts.keys();
		for (i = 0; i < conceptkeys.length; i++) {
			this._concepts[conceptkeys[i]].unload();
			delete this._concepts[conceptkeys[i]];
		}
		delete this._concepts;

		// Delete all the ContextManager attributes
		delete this._loaded;
		delete this._workspace;
	}

	// *********************************************
	// PRIVATE VARIABLES AND CONSTRUCTOR OPERATIONS
	// *********************************************

	this._loaded = false;
	this._concepts = new Hash();     // a concept is its adaptor an its value
	this._name2Concept = new Hash(); // relates the name to its concept
	this._workspace = workspace_;

	// Load all igadget context variables and concepts (in this order!)
	this._loadConceptsFromWorkspace (workSpaceInfo_);
	this._loadIGadgetContextVarsFromWorkspace (workSpaceInfo_);
}<commit_msg>Adapt ContextManager to the model refactorization<commit_after>/*
*     (C) Copyright 2008 Telefonica Investigacion y Desarrollo
*     S.A.Unipersonal (Telefonica I+D)
*
*     This file is part of Morfeo EzWeb Platform.
*
*     Morfeo EzWeb Platform is free software: you can redistribute it and/or modify
*     it under the terms of the GNU Affero General Public License as published by
*     the Free Software Foundation, either version 3 of the License, or
*     (at your option) any later version.
*
*     Morfeo EzWeb Platform is distributed in the hope that it will be useful,
*     but WITHOUT ANY WARRANTY; without even the implied warranty of
*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*     GNU Affero General Public License for more details.
*
*     You should have received a copy of the GNU Affero General Public License
*     along with Morfeo EzWeb Platform.  If not, see <http://www.gnu.org/licenses/>.
*
*     Info about members and contributors of the MORFEO project
*     is available at
*
*     http://morfeo-project.org
 */

function ContextManager (workspace_, workSpaceInfo_) {

	// ***********************
	// PRIVATED FUNCTIONS
	// ***********************

	/**
	 * Adds all variables from workspace data model
	 */
	this._addContextVarsFromTemplate = function (iGadget, cVars, type) {
		var varManager = this._workspace.getVarManager();
		for (var i = 0; i < cVars.size(); i++) {
			var cVar = cVars[i];
			cVar.setVarManager(varManager);
			var conceptName = cVar.getConceptName();
			var relatedConcept = this._name2Concept[conceptName];
			if (relatedConcept != null && relatedConcept._type != type)
				relatedConcept = null;

			if (relatedConcept == null) {
				var msg = gettext("There is not any concept of type \"%(type)s\" called \"%(concept)s\", the value of the iGadget variable \"%(varName)s\" will be empty.");
				msg = interpolate(msg, {concept: conceptName, type: type, varName: cVar.getName()}, true);
				OpManagerFactory.getInstance().logIGadgetError(iGadget.getId(), msg, Constants.Logging.ERROR_MSG);
				continue;
			}
			relatedConcept.addIGadgetVar(cVar);
		}
	}

	// Loads all concept from workspace data model.
	this._loadConceptsFromWorkspace = function (workSpaceInfo_) {
		this._concepts = new Hash();
		this._name2Concept = new Hash();

		var conceptsJson = workSpaceInfo_['workspace']['concepts'];

		// Parses concepts json
		for (var i = 0; i < conceptsJson.length; i++) {
			var curConcept = conceptsJson[i];
			// Creates the concept
			var concept = new Concept(curConcept.concept, curConcept.type, curConcept.adaptor);
			this._concepts[curConcept.concept] = concept;

			// Sets the concept value
			if (curConcept.value != undefined) {
				concept._setInitialValue(curConcept.value)
			}

			// Relates the concept name to all its concept
			for (var j = 0; j < curConcept.names.length; j++) {
				var cname = curConcept.names[j];
				var oldConcept = this._name2Concept[cname]
				if (oldConcept != null) {
					var msg = gettext("WARNING: concept name '%(cname)s' is already related to '%(concept)s'. New related concept is '%(newConcept)s'.");
					msg = interpolate(msg, {cname: cname, concept: oldConcept, newConcept: curConcept.concept}, true);
					LogManagerFactory.getInstance().log(msg);
				}
				this._name2Concept[cname] = concept;
			}
		}
	}

    // Load igadget's context variables from workspace data model
    this._loadIGadgetContextVarsFromWorkspace = function (workSpaceInfo) {
        var i, j, tabs, currentTab, currentIGadget, currentVar, contextVar,
            dragboard, varname, relatedConcept, msg;

        tabs = workSpaceInfo['workspace']['tabList'];

        // Tabs in workspace
        for (i = 0; i < tabs.length; i++) {
            currentTab = tabs[i];
            dragboard = this._workspace.getTab(currentTab.id).getDragboard();

			// igadgets in tab
			for (j = 0; j < currentTab.igadgetList.length; j++) {
				currentIGadget = dragboard.getIGadget(currentTab.igadgetList[j].id);

                                variables = currentIGadget.getGadget().getTemplate().getVariables();

				// Variables of igadgets
				for (varname in variables) {
				    currentVar = variables[varname];
					switch (currentVar.aspect) {
					case Variable.prototype.EXTERNAL_CONTEXT:
					case Variable.prototype.GADGET_CONTEXT:
						contextVar = new ContextVar(currentIGadget.id, currentVar.name, currentVar.concept)
						contextVar.setVarManager(this._workspace.getVarManager());
						relatedConcept = this._name2Concept[currentVar.concept];
						if (relatedConcept) {
							if (currentVar.aspect !== relatedConcept._type) {
								msg = gettext("There is not any concept of type \"%(type)s\" called \"%(concept)s\", the value of the iGadget variable \"%(varName)s\" will be empty.");
								msg = interpolate(msg,
									{concept: currentVar.concept,
									 type: relatedConcept._type,
									 varName: currentVar.name},
									true);
								OpManagerFactory.getInstance().logIGadgetError(currentIGadget.id, msg, Constants.Logging.ERROR_MSG);
							} else {
								relatedConcept.addIGadgetVar(contextVar);
							}
						}
						break;
					default:
						break;
					}
				}
			}
		}

		// Continues loading next module
		this._loaded = true;
	}

	// ****************
	// PUBLIC METHODS
	// ****************

	ContextManager.prototype.addInstance = function (iGadget, template) {
		if (!this._loaded)
			return;

		if (template == null)
			return;

		this._addContextVarsFromTemplate(iGadget, template.getExternalContextVars(iGadget.getId()), Concept.prototype.EXTERNAL);
		this._addContextVarsFromTemplate(iGadget, template.getGadgetContextVars(iGadget.getId()), Concept.prototype.IGADGET);
	}

	ContextManager.prototype.iGadgetLoaded = function (iGadget) {
		if (!this._loaded)
			return;

		var iGadgetId = iGadget.getId();
		var keys = this._concepts.keys();
		for (var i = 0; i < keys.length; i++) {
			var concept = this._concepts[keys[i]];
			concept.propagateIGadgetVarValues(iGadget);
		}
	}

	ContextManager.prototype.iGadgetUnloaded = function (iGadget) {
		if (!this._loaded)
			return;

		var keys = this._concepts.keys();
		for (var i = 0; i < keys.length; i++) {
			var concept = this._concepts[keys[i]];
			if (concept._type !== Concept.prototype.IGADGET)
				continue;

			var ivar = concept.getIGadgetVar(iGadget.getId());
			if (ivar != null)
				ivar._clearHandler();
		}
	}

	ContextManager.prototype.removeInstance = function (iGadgetId_) {
		if (!this._loaded)
			return;

		var keys = this._concepts.keys();
		for (var i = 0; i < keys.length; i++) {
			var key = keys[i];
			this._concepts[key].deleteIGadgetVars(iGadgetId_);
		}
	}

	/**
	 * Notifies a value change on an platform context concept.
	 *
	 * @param {String} concept
	 * @param {} value
	 */
	ContextManager.prototype.notifyModifiedConcept = function (concept, value) {
		if (!this._loaded)
			return;

		if (!this._concepts[concept])
			return;

		this._concepts[concept].setValue(value);
	}

	/**
	 * Notifies a value change on an igadget context concept.
	 *
	 * @param {iGadget} iGadget
	 * @param {String} concept
	 * @param {} value
	 */
	ContextManager.prototype.notifyModifiedGadgetConcept = function (iGadget, concept, value) {
		if (!this._loaded)
			return;

		if (this._concepts[concept] == null)
			return;

		var ivar = this._concepts[concept].getIGadgetVar(iGadget.getId());
		if (ivar == null) {
			// Do nothing, igadget has not variables related to this concept
			return;
		}

		ivar.setValue(value);
	}

	ContextManager.prototype.getWorkspace = function () {
		return this._workspace;
	}

	ContextManager.prototype.unload = function () {
		var i, namekeys, conceptkeys;

		// Delete all concept names
		namekeys = this._name2Concept.keys();
		for (i = 0; i < namekeys.length; i++) {
			delete this._name2Concept[namekeys[i]];
		}
		delete this._name2Concept;

		// Delete all the concepts
		conceptkeys = this._concepts.keys();
		for (i = 0; i < conceptkeys.length; i++) {
			this._concepts[conceptkeys[i]].unload();
			delete this._concepts[conceptkeys[i]];
		}
		delete this._concepts;

		// Delete all the ContextManager attributes
		delete this._loaded;
		delete this._workspace;
	}

	// *********************************************
	// PRIVATE VARIABLES AND CONSTRUCTOR OPERATIONS
	// *********************************************

	this._loaded = false;
	this._concepts = new Hash();     // a concept is its adaptor an its value
	this._name2Concept = new Hash(); // relates the name to its concept
	this._workspace = workspace_;

	// Load all igadget context variables and concepts (in this order!)
	this._loadConceptsFromWorkspace (workSpaceInfo_);
	this._loadIGadgetContextVarsFromWorkspace (workSpaceInfo_);
}
<|endoftext|>


<commit_before>let _ = require('lodash/fp')
let JWT = require('./JWT')
let {method} = require('sails-async')
let F = require('futil-js')

module.exports = {
  login: (authenticate) => {
    let userId = await authenticate()
    let token = JWT.issue({
      user: userId
    })
    // Set here so client auto uses it
    res.set(JWT.renewTokenHeader, token);
    return {token}
  }),
  impersonate: (id='id') => method(async (req, res) => {
    let token = JWT.issue({
      // The new user will be whatever the target id is
      user: req.param(id),
      // Add the previous user to the back of the stack of users ids
      // Makes it easy to use with lodash :D
      impersonateStack: [...req.tokenPayload.impersonateStack || [], req.user.id]
    })
    res.set(JWT.renewTokenHeader, token)
    return {token}
  }),
  impersonatePop: method(async (req, res) => {
    let tokenRaw = {
      // Grab last user of the stack and make the new user
      user: _.last(req.tokenPayload.impersonateStack),
      // New stack should be the all but the last user
      // since they're the new user
      impersonateStack: _.initial(req.tokenPayload.impersonateStack)
    }
    let token = JWT.issue(tokenRaw)
    res.set(JWT.renewTokenHeader, token)
    return {token}
  }),
  verify: (fn, verify='verify', values='values') =>
    method(async req => fn(req.param('verify'), req.param('values')))
}
<commit_msg>cleanup<commit_after>let _ = require('lodash/fp')
let JWT = require('./JWT')
let {method} = require('sails-async')
let F = require('futil-js')

module.exports = {
  login: async (authenticate, res) => {
    let userId = await authenticate()
    let token = JWT.issue({
      user: userId
    })
    // Set here so client auto uses it
    res.set(JWT.renewTokenHeader, token)
    return {token}
  },
  impersonate: (id='id') => method(async (req, res) => {
    let token = JWT.issue({
      // The new user will be whatever the target id is
      user: req.param(id),
      // Add the previous user to the back of the stack of users ids
      // Makes it easy to use with lodash :D
      impersonateStack: [...req.tokenPayload.impersonateStack || [], req.user.id]
    })
    res.set(JWT.renewTokenHeader, token)
    return {token}
  }),
  impersonatePop: method(async (req, res) => {
    let tokenRaw = {
      // Grab last user of the stack and make the new user
      user: _.last(req.tokenPayload.impersonateStack),
      // New stack should be the all but the last user
      // since they're the new user
      impersonateStack: _.initial(req.tokenPayload.impersonateStack)
    }
    let token = JWT.issue(tokenRaw)
    res.set(JWT.renewTokenHeader, token)
    return {token}
  }),
  verify: (fn, verify='verify', values='values') =>
    method(async req => fn(req.param('verify'), req.param('values')))
}
<|endoftext|>


<commit_before>'use strict';

const Joi = require('joi');

const Message = require('./Message');
const MessageParsingBlinkError = require('../errors/MessageParsingBlinkError');

class CustomerioSmsBroadcastMessage extends Message {
  constructor(...args) {
    super(...args);

    const whenNullOrEmpty = Joi.valid(['', null]);
    const statusRegex = /broadcastId%3D.+$/;
    this.schema = Joi.object()
      .keys({
        To: Joi.string().required().empty(whenNullOrEmpty).regex(/^\+1[0-9]+$/, 'valid phone number'),
        Body: Joi.string().required().empty(whenNullOrEmpty),
        MessagingServiceSid: Joi.string().required().empty(whenNullOrEmpty),
        StatusCallback:Joi.string().required().empty(whenNullOrEmpty).regex(statusRegex, 'valid status callback'),
      });
  }

  getBroadcastId() {
    return this.getData().StatusCallback.match(/broadcastId%3D(.+)/)[1];
  }

  static fromCtx(ctx) {
    // TODO: save more metadata
    // TODO: metadata parse helper
    const meta = {
      request_id: ctx.id,
    };
    const message = new CustomerioSmsBroadcastMessage({
      data: ctx.request.body,
      meta,
    });
    return message;
  }

  static fromRabbitMessage(rabbitMessage) {
    const payload = this.parseIncomingPayload(rabbitMessage);
    if (!payload.data || !payload.meta) {
      throw new MessageParsingBlinkError('No data in message', payload);
    }

    // TODO: save more metadata
    // TODO: metadata parse helper
    const message = new CustomerioSmsBroadcastMessage({
      data: payload.data,
      meta: payload.meta,
    });
    message.fields = rabbitMessage.fields;
    return message;
  }
}

module.exports = CustomerioSmsBroadcastMessage;
<commit_msg>Fix lint<commit_after>'use strict';

const Joi = require('joi');

const Message = require('./Message');
const MessageParsingBlinkError = require('../errors/MessageParsingBlinkError');

class CustomerioSmsBroadcastMessage extends Message {
  constructor(...args) {
    super(...args);

    const whenNullOrEmpty = Joi.valid(['', null]);
    const statusRegex = /broadcastId%3D.+$/;
    this.schema = Joi.object()
      .keys({
        To: Joi.string().required().empty(whenNullOrEmpty).regex(/^\+1[0-9]+$/, 'valid phone number'),
        Body: Joi.string().required().empty(whenNullOrEmpty),
        MessagingServiceSid: Joi.string().required().empty(whenNullOrEmpty),
        StatusCallback: Joi.string().required().empty(whenNullOrEmpty).regex(statusRegex, 'valid status callback'),
      });
  }

  getBroadcastId() {
    return this.getData().StatusCallback.match(/broadcastId%3D(.+)/)[1];
  }

  static fromCtx(ctx) {
    // TODO: save more metadata
    // TODO: metadata parse helper
    const meta = {
      request_id: ctx.id,
    };
    const message = new CustomerioSmsBroadcastMessage({
      data: ctx.request.body,
      meta,
    });
    return message;
  }

  static fromRabbitMessage(rabbitMessage) {
    const payload = this.parseIncomingPayload(rabbitMessage);
    if (!payload.data || !payload.meta) {
      throw new MessageParsingBlinkError('No data in message', payload);
    }

    // TODO: save more metadata
    // TODO: metadata parse helper
    const message = new CustomerioSmsBroadcastMessage({
      data: payload.data,
      meta: payload.meta,
    });
    message.fields = rabbitMessage.fields;
    return message;
  }
}

module.exports = CustomerioSmsBroadcastMessage;
<|endoftext|>


<commit_before>let checkActivityPermitted = function(user, activity) {
    if (!user) {
        throw new Meteor.Error('Not-logged-in', 'The user must be logged in to perform activities.');
    }

    if (activity.actor != user.actor)
        throw new Meteor.Error('Actor mismatch!', 'Method actor does not match activity actor!');

    if (!Actors.findOne({id: activity.actor}))
        throw new Meteor.Error('Actor not found!', 'No actor with the given ID could be found in the database: ' + followerID);

    switch(activity.type) {

        //Users can follow without being verified. Thus, return here, instead of further down after the verification check.
        case 'Follow':
            return;

        case 'Update':
        case 'Delete':
            //Don't allow non-moderators to edit other peoples posts.
            if (activity.actor !== user.actor && !Roles.userIsInRole(user._id, ['moderator'])) {
                throw new Meteor.Error('Post Not Owned', "Only moderators may edit or delete posts they don't own.");
            }

        //No break here, as update and delete activities should be subject to the same restrictions as create and announce.
        case 'Create':
        case 'Announce':
            //Don't allow banned users to post or announce.
            if (user.isBanned) {
                throw new Meteor.Error('Banned', 'Banned users may not perform that activity.');
            }
            break;

    }

    //Don't allow unverified users to manipulate the forum. They can still follow people though.
    if (!user.emails || user.emails.length < 1 || !user.emails[0].verified) {
        throw new Meteor.Error('Unverified', 'Unverified users may not perform that activity.');
    }
};

let processCreateActivity = function(activity) {
    let post = activity.object;

    post.local = true;

    let post_ID = Posts.insert(post);
    activity.object = Posts.findOne({_id: post_ID});

    return activity;
};

let processDeleteActivity = function(activity) {
    let postID = activity.object;

    deletePost(postID);

    return activity;
};

let processUpdateActivity = function(activity) {
    let update = activity.object;

    Posts.update({id: update.id}, {$set: update});

    return activity;
};

let processClientFollowActivity = function(activity) {

    if (!actors.findOne({id: activity.object}))
        throw new Meteor.Error('Actor not found!', 'No actor with the given ID could be found: ' + activity.object);

    let follower = actors.findOne({id: activity.actor});

    FollowingLists.update({id: follower.following}, {$inc: {totalItems: 1}, $push: {orderedItems: activity.object}});

    return activity;
};

let encapsulateContentWithCreate = function(post) {

    //Don't allow posts with no content.
    if (!post.content || post.content.length < 1)
        throw new Meteor.Error('No content!', 'Cannot insert post without content!');

    //Don't allow posts with too much content
    if (post.content.length > 100000)
        throw new Meteor.Error('Too much content!', 'Cannot insert post with content greater than 100,000 characters!');

    //Don't allow posts with summariesw that are too long.
    if (post.summary && post.summary.length > 100)
        throw new Meteor.Error('Summary too long!', 'Cannot insert post with summary greater than 100 characters!');

    if (post.content.length > 500 && (!post.summary || post.summary.length < 1))
        throw new Meteor.Error('Summary needed!', 'Posts with more than 500 characters of content must have a summary!');

    //Don't allow posts that target posts that don't exist.
    if (post.inReplyTo && !Posts.findOne({id: post.inReplyTo}))
        throw new Meteor.Error('target invalid', 'Targeted post not found!');

    let activity = new ActivityPubActivity("Create", post.attributedTo, post);
    activity.published = post.published;

    return activity;
}

processClientActivity = function(user, object) {

    //Set the object as being published right now.
    object.published = new Date().toISOString();

    let activity;
    //We may or may not have an activity to work with here.
    if (!activityPubActivityTypes.includes(object.type)) {
        //If we don't and it's a content object, encapsulate the object in a create activity.
        if (activityPubContentTypes.includes(object.type))
            activity = encapsulateContentWithCreate(object);
        //If we don't, and we don't know what it is, throw an error.
        else throw new Meteor.Error('Unknown type!', 'Cannot handle that type of object!');
    } else {
        //If we do have an activity, proceed normally.
        activity = object;
    }

    checkActivityPermitted(user, activity);

    let result;

    switch(activity.type){
        case 'Create':
            result = processCreateActivity(activity);
            break;
        case 'Delete':
            result = processDeleteActivity(activity);
            break;
        case 'Follow':
            result = processFollowActivity(activity);
            break;
        case 'Update':
            result = processUpdateActivity(activity);
            break;
    }

    return result;
};
<commit_msg>rename methods to differentiate between client activities and server activities<commit_after>let checkClientActivityPermitted = function(user, activity) {
    if (!user) {
        throw new Meteor.Error('Not-logged-in', 'The user must be logged in to perform activities.');
    }

    if (activity.actor != user.actor)
        throw new Meteor.Error('Actor mismatch!', 'Method actor does not match activity actor!');

    if (!Actors.findOne({id: activity.actor}))
        throw new Meteor.Error('Actor not found!', 'No actor with the given ID could be found in the database: ' + followerID);

    switch(activity.type) {

        //Users can follow without being verified. Thus, return here, instead of further down after the verification check.
        case 'Follow':
            return;

        case 'Update':
        case 'Delete':
            //Don't allow non-moderators to edit other peoples posts.
            if (activity.actor !== user.actor && !Roles.userIsInRole(user._id, ['moderator'])) {
                throw new Meteor.Error('Post Not Owned', "Only moderators may edit or delete posts they don't own.");
            }

        //No break here, as update and delete activities should be subject to the same restrictions as create and announce.
        case 'Create':
        case 'Announce':
            //Don't allow banned users to post or announce.
            if (user.isBanned) {
                throw new Meteor.Error('Banned', 'Banned users may not perform that activity.');
            }
            break;

    }

    //Don't allow unverified users to manipulate the forum. They can still follow people though.
    if (!user.emails || user.emails.length < 1 || !user.emails[0].verified) {
        throw new Meteor.Error('Unverified', 'Unverified users may not perform that activity.');
    }
};

let processClientCreateActivity = function(activity) {
    let post = activity.object;

    post.local = true;

    let post_ID = Posts.insert(post);
    activity.object = Posts.findOne({_id: post_ID});

    return activity;
};

let processClientDeleteActivity = function(activity) {
    let postID = activity.object;

    deletePost(postID);

    return activity;
};

let processClientUpdateActivity = function(activity) {
    let update = activity.object;

    Posts.update({id: update.id}, {$set: update});

    return activity;
};

let processClientFollowActivity = function(activity) {

    if (!actors.findOne({id: activity.object}))
        throw new Meteor.Error('Actor not found!', 'No actor with the given ID could be found: ' + activity.object);

    let follower = actors.findOne({id: activity.actor});

    FollowingLists.update({id: follower.following}, {$inc: {totalItems: 1}, $push: {orderedItems: activity.object}});

    return activity;
};

let encapsulateContentWithCreate = function(post) {

    //Don't allow posts with no content.
    if (!post.content || post.content.length < 1)
        throw new Meteor.Error('No content!', 'Cannot insert post without content!');

    //Don't allow posts with too much content
    if (post.content.length > 100000)
        throw new Meteor.Error('Too much content!', 'Cannot insert post with content greater than 100,000 characters!');

    //Don't allow posts with summariesw that are too long.
    if (post.summary && post.summary.length > 100)
        throw new Meteor.Error('Summary too long!', 'Cannot insert post with summary greater than 100 characters!');

    if (post.content.length > 500 && (!post.summary || post.summary.length < 1))
        throw new Meteor.Error('Summary needed!', 'Posts with more than 500 characters of content must have a summary!');

    //Don't allow posts that target posts that don't exist.
    if (post.inReplyTo && !Posts.findOne({id: post.inReplyTo}))
        throw new Meteor.Error('target invalid', 'Targeted post not found!');

    let activity = new ActivityPubActivity("Create", post.attributedTo, post);
    activity.published = post.published;

    return activity;
}

processClientActivity = function(user, object) {

    //Set the object as being published right now.
    object.published = new Date().toISOString();

    let activity;
    //We may or may not have an activity to work with here.
    if (!activityPubActivityTypes.includes(object.type)) {
        //If we don't and it's a content object, encapsulate the object in a create activity.
        if (activityPubContentTypes.includes(object.type))
            activity = encapsulateContentWithCreate(object);
        //If we don't, and we don't know what it is, throw an error.
        else throw new Meteor.Error('Unknown type!', 'Cannot handle that type of object!');
    } else {
        //If we do have an activity, proceed normally.
        activity = object;
    }

    checkClientActivityPermitted(user, activity);

    switch(activity.type){
        case 'Create':
            activity = processClientCreateActivity(activity);
            break;
        case 'Delete':
            activity = processClientDeleteActivity(activity);
            break;
        case 'Follow':
            activity = processClientFollowActivity(activity);
            break;
        case 'Update':
            activity = processClientUpdateActivity(activity);
            break;
    }

    return activity;
};
<|endoftext|>


<commit_before>/*
 * Fizzle.js
 * Adapted from Sizzle.js
 */
var _ = require('_'),

    _cache         = require('../../../cache'),
    _tokenCache    = _cache(),
    _subqueryCache = _cache(),
    _boolAttrCache = _cache(),

    _error = (!console || !console.error) ? _.noop :
        function(selector) {
            console.error('Invalid query selector (caught): ' + selector);
        };

var _booleans = 'checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped',

    _fromCharCode = String.fromCharCode,

    // http://www.w3.org/TR/css3-selectors/#whitespace
    _whitespace = '[\\x20\\t\\r\\n\\f]',

    // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
    _identifier = '(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+',

    // NOTE: Leaving double quotes to reduce escaping
    // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
    _attributes = "\\[" + _whitespace + "*(" + _identifier + ")(?:" + _whitespace +
        // Operator (capture 2)
        "*([*^$|!~]?=)" + _whitespace +
        // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
        "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + _identifier + "))|)" + _whitespace +
        "*\\]",

    _pseudos = ":(" + _identifier + ")(?:\\((" +
        // To reduce the number of selectors needing _tokenize in the preFilter, prefer arguments:
        // 1. quoted (capture 3; capture 4 or capture 5)
        "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
        // 2. simple (capture 6)
        "((?:\\\\.|[^\\\\()[\\]]|" + _attributes + ")*)|" +
        // 3. anything else (capture 2)
        ".*" +
        ")\\)|)",

    _rcomma = new RegExp('^' + _whitespace + '*,' + _whitespace + '*'),
    _rcombinators = new RegExp('^' + _whitespace + '*([>+~]|' + _whitespace + ')' + _whitespace + '*'),

    _rpseudo = new RegExp(_pseudos),

    _matchExpr = {
        ID:     new RegExp('^#('   + _identifier + ')'),
        CLASS:  new RegExp('^\\.(' + _identifier + ')'),
        TAG:    new RegExp('^('    + _identifier + '|[*])'),
        ATTR:   new RegExp('^'     + _attributes),
        PSEUDO: new RegExp('^'     + _pseudos),
        CHILD:  new RegExp('^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(' + _whitespace +
            '*(even|odd|(([+-]|)(\\d*)n|)' + _whitespace + '*(?:([+-]|)' + _whitespace +
            '*(\\d+)|))' + _whitespace + '*\\)|)', 'i'),

        // Note: Using double quotes due to parsing weirdness
        bool:   new RegExp("^(?:" + _booleans + ")$", "i"),

        // For use in libraries implementing .is()
        // We use this for POS matching in `select`
        needsContext: new RegExp('^' + _whitespace + '*[>+~]|:(even|odd|nth|eq|gt|lt|first|last)(?:\\(' +
            _whitespace + '*((?:-\\d)?\\d*)' + _whitespace + '*\\)|)(?=[^-]|$)', 'i')
    },

    // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
    _runescape = new RegExp('\\\\([\\da-f]{1,6}' + _whitespace + '?|(' + _whitespace + ')|.)', 'ig'),
    _funescape = function(_, escaped, escapedWhitespace) {
        var high = '0x' + (escaped - 0x10000);
        // NaN means non-codepoint
        // Support: Firefox<24
        // Workaround erroneous numeric interpretation of +'0x'
        return high !== high || escapedWhitespace ?
            escaped :
            high < 0 ?
                // BMP codepoint
                _fromCharCode(high + 0x10000) :
                // Supplemental Plane codepoint (surrogate pair)
                _fromCharCode((high >> 10) | 0xD800, (high & 0x3FF) | 0xDC00);
    },

    _preFilter = {
        ATTR: function(match) {
            match[1] = match[1].replace(_runescape, _funescape);

            // Move the given value to match[3] whether quoted or unquoted
            match[3] = ( match[3] || match[4] || match[5] || '' ).replace(_runescape, _funescape);

            if (match[2] === '~=') {
                match[3] = ' ' + match[3] + ' ';
            }

            return match.slice(0, 4);
        },

        CHILD: function(match) {
            /* matches from _matchExpr['CHILD']
                1 type (only|nth|...)
                2 what (child|of-type)
                3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
                4 xn-component of xn+y argument ([+-]?\d*n|)
                5 sign of xn-component
                6 x of xn-component
                7 sign of y-component
                8 y of y-component
             */
            match[1] = match[1].toLowerCase();

            if (match[1].slice(0, 3) === 'nth') {
                // nth-* requires argument
                if (!match[3]) {
                    throw new Error(match[0]);
                }

                // numeric x and y parameters for Expr.filter.CHILD
                // remember that false/true cast respectively to 0/1
                match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === 'even' || match[3] === 'odd'));
                match[5] = +(( match[7] + match[8]) || match[3] === 'odd');

            // other types prohibit arguments
            } else if (match[3]) {
                throw new Error(match[0]);
            }

            return match;
        },

        PSEUDO: function(match) {
            var excess,
                unquoted = !match[6] && match[2];

            if (_matchExpr.CHILD.test(match[0])) {
                return null;
            }

            // Accept quoted arguments as-is
            if (match[3]) {
                match[2] = match[4] || match[5] || '';

            // Strip excess characters from unquoted arguments
            } else if (unquoted && _rpseudo.test(unquoted) &&
                // Get excess from _tokenize (recursively)
                (excess = _tokenize(unquoted, true)) &&
                // advance to the next closing parenthesis
                (excess = unquoted.indexOf(')', unquoted.length - excess) - unquoted.length)) {

                // excess is a negative index
                match[0] = match[0].slice(0, excess);
                match[2] = unquoted.slice(0, excess);
            }

            // Return only captures needed by the pseudo filter method (type and argument)
            return match.slice(0, 3);
        }
    };

/**
 * Splits the given comma-separated CSS selector into separate sub-queries.
 * @param  {String} selector Full CSS selector (e.g., 'a, input:focus, div[attr="value"]').
 * @param  {Boolean} [parseOnly=false]
 * @return {String[]|Number|null} Array of sub-queries (e.g., [ 'a', 'input:focus', 'div[attr="(value1),[value2]"]') or null if there was an error parsing.
 * @private
 */
var _tokenize = function(selector, parseOnly) {
    var cached = _tokenCache.get(selector);

    if (cached) {
        return parseOnly ? 0 : cached.slice(0);
    }

    var /** @type {String} */
        type,

        /** @type {RegExp} */
        regex,

        /** @type {Array} */
        match,

        /** @type {String} */
        matched,

        /** @type {String[]} */
        subqueries = [],

        /** @type {String} */
        subquery = '',

        /** @type {String} */
        soFar = selector;

    while (soFar) {
        // Comma and first run
        if (!matched || (match = _rcomma.exec(soFar))) {
            if (match) {
                // Don't consume trailing commas as valid
                soFar = soFar.slice(match[0].length) || soFar;
            }
            if (subquery) { subqueries.push(subquery); }
            subquery = '';
        }

        matched = null;

        // Combinators
        if ((match = _rcombinators.exec(soFar))) {
            matched = match.shift();
            subquery += matched;
            soFar = soFar.slice(matched.length);
        }

        // Filters
        for (type in _matchExpr) {
            regex = _matchExpr[type];
            match = regex.exec(soFar);

            if (match && (!_preFilter[type] || (match = _preFilter[type](match)))) {
                matched = match.shift();
                subquery += matched;
                soFar = soFar.slice(matched.length);

                break;
            }
        }

        if (!matched) {
            break;
        }
    }

    if (subquery) { subqueries.push(subquery); }

    // Return the length of the invalid excess
    // if we're just parsing.
    if (parseOnly) { return soFar.length; }

    if (soFar) { _error(selector); return null; }

    return _tokenCache.set(selector, subqueries).slice();
};

module.exports = {
    /**
     * Splits the given comma-separated CSS selector into separate sub-queries.
     * @param  {String} selector Full CSS selector (e.g., 'a, input:focus, div[attr="value"]').
     * @return {String[]|null} Array of sub-queries (e.g., [ 'a', 'input:focus', 'div[attr="(value1),[value2]"]') or null if there was an error parsing the selector.
     */
    subqueries: function(selector) {
        return _subqueryCache.getOrSet(selector, function() {
            return _tokenize(selector);
        });
    },

    isBooleanAttribute: function(name) {
        return _boolAttrCache.getOrSet(name, function() {
            return _matchExpr.bool.test(name);
        });
    }
};
<commit_msg>Minor - Removed old comment (no longer valid)<commit_after>/*
 * Fizzle.js
 * Adapted from Sizzle.js
 */
var _ = require('_'),

    _cache         = require('../../../cache'),
    _tokenCache    = _cache(),
    _subqueryCache = _cache(),
    _boolAttrCache = _cache(),

    _error = (!console || !console.error) ? _.noop :
        function(selector) {
            console.error('Invalid query selector (caught): ' + selector);
        };

var _booleans = 'checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped',

    _fromCharCode = String.fromCharCode,

    // http://www.w3.org/TR/css3-selectors/#whitespace
    _whitespace = '[\\x20\\t\\r\\n\\f]',

    // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
    _identifier = '(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+',

    // NOTE: Leaving double quotes to reduce escaping
    // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
    _attributes = "\\[" + _whitespace + "*(" + _identifier + ")(?:" + _whitespace +
        // Operator (capture 2)
        "*([*^$|!~]?=)" + _whitespace +
        // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
        "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + _identifier + "))|)" + _whitespace +
        "*\\]",

    _pseudos = ":(" + _identifier + ")(?:\\((" +
        // To reduce the number of selectors needing _tokenize in the preFilter, prefer arguments:
        // 1. quoted (capture 3; capture 4 or capture 5)
        "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
        // 2. simple (capture 6)
        "((?:\\\\.|[^\\\\()[\\]]|" + _attributes + ")*)|" +
        // 3. anything else (capture 2)
        ".*" +
        ")\\)|)",

    _rcomma = new RegExp('^' + _whitespace + '*,' + _whitespace + '*'),
    _rcombinators = new RegExp('^' + _whitespace + '*([>+~]|' + _whitespace + ')' + _whitespace + '*'),

    _rpseudo = new RegExp(_pseudos),

    _matchExpr = {
        ID:     new RegExp('^#('   + _identifier + ')'),
        CLASS:  new RegExp('^\\.(' + _identifier + ')'),
        TAG:    new RegExp('^('    + _identifier + '|[*])'),
        ATTR:   new RegExp('^'     + _attributes),
        PSEUDO: new RegExp('^'     + _pseudos),
        CHILD:  new RegExp('^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(' + _whitespace +
            '*(even|odd|(([+-]|)(\\d*)n|)' + _whitespace + '*(?:([+-]|)' + _whitespace +
            '*(\\d+)|))' + _whitespace + '*\\)|)', 'i'),

        bool:   new RegExp("^(?:" + _booleans + ")$", "i"),

        // For use in libraries implementing .is()
        // We use this for POS matching in `select`
        needsContext: new RegExp('^' + _whitespace + '*[>+~]|:(even|odd|nth|eq|gt|lt|first|last)(?:\\(' +
            _whitespace + '*((?:-\\d)?\\d*)' + _whitespace + '*\\)|)(?=[^-]|$)', 'i')
    },

    // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
    _runescape = new RegExp('\\\\([\\da-f]{1,6}' + _whitespace + '?|(' + _whitespace + ')|.)', 'ig'),
    _funescape = function(_, escaped, escapedWhitespace) {
        var high = '0x' + (escaped - 0x10000);
        // NaN means non-codepoint
        // Support: Firefox<24
        // Workaround erroneous numeric interpretation of +'0x'
        return high !== high || escapedWhitespace ?
            escaped :
            high < 0 ?
                // BMP codepoint
                _fromCharCode(high + 0x10000) :
                // Supplemental Plane codepoint (surrogate pair)
                _fromCharCode((high >> 10) | 0xD800, (high & 0x3FF) | 0xDC00);
    },

    _preFilter = {
        ATTR: function(match) {
            match[1] = match[1].replace(_runescape, _funescape);

            // Move the given value to match[3] whether quoted or unquoted
            match[3] = ( match[3] || match[4] || match[5] || '' ).replace(_runescape, _funescape);

            if (match[2] === '~=') {
                match[3] = ' ' + match[3] + ' ';
            }

            return match.slice(0, 4);
        },

        CHILD: function(match) {
            /* matches from _matchExpr['CHILD']
                1 type (only|nth|...)
                2 what (child|of-type)
                3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
                4 xn-component of xn+y argument ([+-]?\d*n|)
                5 sign of xn-component
                6 x of xn-component
                7 sign of y-component
                8 y of y-component
             */
            match[1] = match[1].toLowerCase();

            if (match[1].slice(0, 3) === 'nth') {
                // nth-* requires argument
                if (!match[3]) {
                    throw new Error(match[0]);
                }

                // numeric x and y parameters for Expr.filter.CHILD
                // remember that false/true cast respectively to 0/1
                match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === 'even' || match[3] === 'odd'));
                match[5] = +(( match[7] + match[8]) || match[3] === 'odd');

            // other types prohibit arguments
            } else if (match[3]) {
                throw new Error(match[0]);
            }

            return match;
        },

        PSEUDO: function(match) {
            var excess,
                unquoted = !match[6] && match[2];

            if (_matchExpr.CHILD.test(match[0])) {
                return null;
            }

            // Accept quoted arguments as-is
            if (match[3]) {
                match[2] = match[4] || match[5] || '';

            // Strip excess characters from unquoted arguments
            } else if (unquoted && _rpseudo.test(unquoted) &&
                // Get excess from _tokenize (recursively)
                (excess = _tokenize(unquoted, true)) &&
                // advance to the next closing parenthesis
                (excess = unquoted.indexOf(')', unquoted.length - excess) - unquoted.length)) {

                // excess is a negative index
                match[0] = match[0].slice(0, excess);
                match[2] = unquoted.slice(0, excess);
            }

            // Return only captures needed by the pseudo filter method (type and argument)
            return match.slice(0, 3);
        }
    };

/**
 * Splits the given comma-separated CSS selector into separate sub-queries.
 * @param  {String} selector Full CSS selector (e.g., 'a, input:focus, div[attr="value"]').
 * @param  {Boolean} [parseOnly=false]
 * @return {String[]|Number|null} Array of sub-queries (e.g., [ 'a', 'input:focus', 'div[attr="(value1),[value2]"]') or null if there was an error parsing.
 * @private
 */
var _tokenize = function(selector, parseOnly) {
    var cached = _tokenCache.get(selector);

    if (cached) {
        return parseOnly ? 0 : cached.slice(0);
    }

    var /** @type {String} */
        type,

        /** @type {RegExp} */
        regex,

        /** @type {Array} */
        match,

        /** @type {String} */
        matched,

        /** @type {String[]} */
        subqueries = [],

        /** @type {String} */
        subquery = '',

        /** @type {String} */
        soFar = selector;

    while (soFar) {
        // Comma and first run
        if (!matched || (match = _rcomma.exec(soFar))) {
            if (match) {
                // Don't consume trailing commas as valid
                soFar = soFar.slice(match[0].length) || soFar;
            }
            if (subquery) { subqueries.push(subquery); }
            subquery = '';
        }

        matched = null;

        // Combinators
        if ((match = _rcombinators.exec(soFar))) {
            matched = match.shift();
            subquery += matched;
            soFar = soFar.slice(matched.length);
        }

        // Filters
        for (type in _matchExpr) {
            regex = _matchExpr[type];
            match = regex.exec(soFar);

            if (match && (!_preFilter[type] || (match = _preFilter[type](match)))) {
                matched = match.shift();
                subquery += matched;
                soFar = soFar.slice(matched.length);

                break;
            }
        }

        if (!matched) {
            break;
        }
    }

    if (subquery) { subqueries.push(subquery); }

    // Return the length of the invalid excess
    // if we're just parsing.
    if (parseOnly) { return soFar.length; }

    if (soFar) { _error(selector); return null; }

    return _tokenCache.set(selector, subqueries).slice();
};

module.exports = {
    /**
     * Splits the given comma-separated CSS selector into separate sub-queries.
     * @param  {String} selector Full CSS selector (e.g., 'a, input:focus, div[attr="value"]').
     * @return {String[]|null} Array of sub-queries (e.g., [ 'a', 'input:focus', 'div[attr="(value1),[value2]"]') or null if there was an error parsing the selector.
     */
    subqueries: function(selector) {
        return _subqueryCache.getOrSet(selector, function() {
            return _tokenize(selector);
        });
    },

    isBooleanAttribute: function(name) {
        return _boolAttrCache.getOrSet(name, function() {
            return _matchExpr.bool.test(name);
        });
    }
};
<|endoftext|>


<commit_before>defineSuite([
        'Core/Cartesian3',
        'Core/Cartographic',
        'Core/Color',
        'Core/ColorGeometryInstanceAttribute',
        'Core/destroyObject',
        'Core/Ellipsoid',
        'Core/GeometryInstance',
        'Core/HeadingPitchRange',
        'Core/Math',
        'Core/Matrix4',
        'Core/Rectangle',
        'Core/RectangleGeometry',
        'Core/Transforms',
        'Renderer/Pass',
        'Renderer/RenderState',
        'Scene/Batched3DModel3DTileContent',
        'Scene/ClassificationType',
        'Scene/PerInstanceColorAppearance',
        'Scene/Primitive',
        'Scene/StencilConstants',
        'Specs/Cesium3DTilesTester',
        'Specs/createScene'
    ], 'Scene/Batched3DModel3DTileContentClassification', function(
        Cartesian3,
        Cartographic,
        Color,
        ColorGeometryInstanceAttribute,
        destroyObject,
        Ellipsoid,
        GeometryInstance,
        HeadingPitchRange,
        CesiumMath,
        Matrix4,
        Rectangle,
        RectangleGeometry,
        Transforms,
        Pass,
        RenderState,
        Batched3DModel3DTileContent,
        ClassificationType,
        PerInstanceColorAppearance,
        Primitive,
        StencilConstants,
        Cesium3DTilesTester,
        createScene) {
    'use strict';

    var scene;
    var modelMatrix;
    var centerLongitude = -1.31968;
    var centerLatitude = 0.698874;

    var withBatchTableUrl = './Data/Cesium3DTiles/Batched/BatchedWithBatchTable/tileset.json';
    var withBatchTableBinaryUrl = './Data/Cesium3DTiles/Batched/BatchedWithBatchTableBinary/tileset.json';

    function setCamera(longitude, latitude, offset) {
        // One feature is located at the center, point the camera there
        var center = Cartesian3.fromRadians(longitude, latitude);
        scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 15.0));
        scene.camera.moveUp(offset);
    }

    function viewCenter() {
        setCamera(centerLongitude, centerLatitude, 0.0);
    }

    function viewGlobePrimitive() {
        setCamera(centerLongitude, centerLatitude, 0.5);
    }

    function view3DTilesPrimitive() {
        setCamera(centerLongitude, centerLatitude, -0.5);
    }

    function MockPrimitive(rectangle, pass) {
        var renderState;
        if (pass === Pass.CESIUM_3D_TILE) {
            renderState = RenderState.fromCache({
                stencilTest : StencilConstants.setCesium3DTileBit(),
                stencilMask : StencilConstants.CESIUM_3D_TILE_MASK,
                depthTest : {
                    enabled : true
                }
            });
        }
        var depthColorAttribute = ColorGeometryInstanceAttribute.fromColor(new Color(0.0, 0.0, 0.0, 1.0));
        this._primitive = new Primitive({
            geometryInstances : new GeometryInstance({
                geometry : new RectangleGeometry({
                    ellipsoid : Ellipsoid.WGS84,
                    rectangle : rectangle
                }),
                id : 'depth rectangle',
                attributes : {
                    color : depthColorAttribute
                }
            }),
            appearance : new PerInstanceColorAppearance({
                translucent : false,
                flat : true,
                renderState : renderState
            }),
            asynchronous : false
        });

        this._pass = pass;
    }

    MockPrimitive.prototype.update = function(frameState) {
        var commandList = frameState.commandList;
        var startLength = commandList.length;
        this._primitive.update(frameState);

        for (var i = startLength; i < commandList.length; ++i) {
            var command = commandList[i];
            command.pass = this._pass;
        }
    };

    MockPrimitive.prototype.isDestroyed = function() {
        return false;
    };

    MockPrimitive.prototype.destroy = function() {
        this._primitive.destroy();
        return destroyObject(this);
    };

    beforeAll(function() {
        scene = createScene();

        var translation = Ellipsoid.WGS84.geodeticSurfaceNormalCartographic(new Cartographic(centerLongitude, centerLatitude));
        Cartesian3.multiplyByScalar(translation, -5.0, translation);
        modelMatrix = Matrix4.fromTranslation(translation);
    });

    afterAll(function() {
        scene.destroyForSpecs();
    });

    beforeEach(function() {
        var offset = CesiumMath.toRadians(0.01);
        var rectangle1 = new Rectangle(centerLongitude - offset, centerLatitude, centerLongitude + offset, centerLatitude + offset);
        var rectangle2 = new Rectangle(centerLongitude - offset, centerLatitude - offset, centerLongitude + offset, centerLatitude);

        // wrap rectangle primitive so it gets executed during the globe pass or 3D Tiles pass to lay down depth
        scene.primitives.add(new MockPrimitive(rectangle1, Pass.GLOBE));
        scene.primitives.add(new MockPrimitive(rectangle2, Pass.CESIUM_3D_TILE));

        viewCenter();
    });

    afterEach(function() {
        scene.primitives.removeAll();
    });

    it('classifies 3D Tiles', function() {
        return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl, {
            classificationType : ClassificationType.CESIUM_3D_TILE,
            modelMatrix : modelMatrix
        }).then(function(tileset) {
            view3DTilesPrimitive();
            Cesium3DTilesTester.expectRenderTileset(scene, tileset);
            viewGlobePrimitive();
            Cesium3DTilesTester.expectRenderBlank(scene, tileset);
        });
    });

    it('classifies globe', function() {
        return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl, {
            classificationType : ClassificationType.TERRAIN,
            modelMatrix : modelMatrix
        }).then(function(tileset) {
            view3DTilesPrimitive();
            Cesium3DTilesTester.expectRenderBlank(scene, tileset);
            viewGlobePrimitive();
            Cesium3DTilesTester.expectRenderTileset(scene, tileset);
        });
    });

    it('classifies both 3D Tiles and globe', function() {
        return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl, {
            classificationType : ClassificationType.BOTH,
            modelMatrix : modelMatrix
        }).then(function(tileset) {
            view3DTilesPrimitive();
            Cesium3DTilesTester.expectRenderTileset(scene, tileset);
            viewGlobePrimitive();
            Cesium3DTilesTester.expectRenderTileset(scene, tileset);
        });
    });

    it('renders with batch table', function() {
        return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl, {
            classificationType : ClassificationType.BOTH,
            modelMatrix : modelMatrix
        }).then(function(tileset) {
            view3DTilesPrimitive();
            Cesium3DTilesTester.expectRenderTileset(scene, tileset);
        });
    });

    it('renders with binary batch table', function() {
        return Cesium3DTilesTester.loadTileset(scene, withBatchTableBinaryUrl, {
            classificationType : ClassificationType.BOTH,
            modelMatrix : modelMatrix
        }).then(function(tileset) {
            view3DTilesPrimitive();
            Cesium3DTilesTester.expectRenderTileset(scene, tileset);
        });
    });

}, 'WebGL');
<commit_msg>Cleanup Batch3dModel3DTileContentClassificationSpec<commit_after>defineSuite([
        'Core/Cartesian3',
        'Core/Cartographic',
        'Core/Color',
        'Core/ColorGeometryInstanceAttribute',
        'Core/destroyObject',
        'Core/Ellipsoid',
        'Core/GeometryInstance',
        'Core/HeadingPitchRange',
        'Core/Math',
        'Core/Matrix4',
        'Core/Rectangle',
        'Core/RectangleGeometry',
        'Core/Transforms',
        'Renderer/Pass',
        'Renderer/RenderState',
        'Scene/Batched3DModel3DTileContent',
        'Scene/ClassificationType',
        'Scene/PerInstanceColorAppearance',
        'Scene/Primitive',
        'Scene/StencilConstants',
        'Specs/Cesium3DTilesTester',
        'Specs/createScene'
    ], 'Scene/Batched3DModel3DTileContentClassification', function(
        Cartesian3,
        Cartographic,
        Color,
        ColorGeometryInstanceAttribute,
        destroyObject,
        Ellipsoid,
        GeometryInstance,
        HeadingPitchRange,
        CesiumMath,
        Matrix4,
        Rectangle,
        RectangleGeometry,
        Transforms,
        Pass,
        RenderState,
        Batched3DModel3DTileContent,
        ClassificationType,
        PerInstanceColorAppearance,
        Primitive,
        StencilConstants,
        Cesium3DTilesTester,
        createScene) {
    'use strict';

    var scene;
    var centerLongitude = -1.31968;
    var centerLatitude = 0.698874;
    var modelMatrix;

    var withBatchTableUrl = './Data/Cesium3DTiles/Batched/BatchedWithBatchTable/tileset.json';
    var withBatchTableBinaryUrl = './Data/Cesium3DTiles/Batched/BatchedWithBatchTableBinary/tileset.json';

    var globePrimitive;
    var tilesetPrimitive;
    var reusableGlobePrimitive;
    var reusableTilesetPrimitive;

    function setCamera(longitude, latitude) {
        // One feature is located at the center, point the camera there
        var center = Cartesian3.fromRadians(longitude, latitude);
        scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 15.0));
    }

    function createPrimitive(rectangle, pass) {
        var renderState;
        if (pass === Pass.CESIUM_3D_TILE) {
            renderState = RenderState.fromCache({
                stencilTest : StencilConstants.setCesium3DTileBit(),
                stencilMask : StencilConstants.CESIUM_3D_TILE_MASK,
                depthTest : {
                    enabled : true
                }
            });
        }
        var depthColorAttribute = ColorGeometryInstanceAttribute.fromColor(new Color(0.0, 0.0, 0.0, 1.0));
        return new Primitive({
            geometryInstances : new GeometryInstance({
                geometry : new RectangleGeometry({
                    ellipsoid : Ellipsoid.WGS84,
                    rectangle : rectangle
                }),
                id : 'depth rectangle',
                attributes : {
                    color : depthColorAttribute
                }
            }),
            appearance : new PerInstanceColorAppearance({
                translucent : false,
                flat : true,
                renderState : renderState
            }),
            asynchronous : false
        });
    }

    function MockPrimitive(primitive, pass) {
        this._primitive = primitive;
        this._pass = pass;
        this.show = true;
    }

    MockPrimitive.prototype.update = function(frameState) {
        if (!this.show) {
            return;
        }

        var commandList = frameState.commandList;
        var startLength = commandList.length;
        this._primitive.update(frameState);

        for (var i = startLength; i < commandList.length; ++i) {
            var command = commandList[i];
            command.pass = this._pass;
        }
    };

    MockPrimitive.prototype.isDestroyed = function() {
        return false;
    };

    MockPrimitive.prototype.destroy = function() {
        return destroyObject(this);
    };

    beforeAll(function() {
        scene = createScene();

        var translation = Ellipsoid.WGS84.geodeticSurfaceNormalCartographic(new Cartographic(centerLongitude, centerLatitude));
        Cartesian3.multiplyByScalar(translation, -5.0, translation);
        modelMatrix = Matrix4.fromTranslation(translation);

        var offset = CesiumMath.toRadians(0.01);
        var rectangle = new Rectangle(centerLongitude - offset, centerLatitude - offset, centerLongitude + offset, centerLatitude + offset);
        reusableGlobePrimitive = createPrimitive(rectangle, Pass.GLOBE);
        reusableTilesetPrimitive = createPrimitive(rectangle, Pass.CESIUM_3D_TILE);
    });

    afterAll(function() {
        reusableGlobePrimitive.destroy();
        reusableTilesetPrimitive.destroy();
        scene.destroyForSpecs();
    });

    beforeEach(function() {
        setCamera(centerLongitude, centerLatitude);

        // wrap rectangle primitive so it gets executed during the globe pass and 3D Tiles pass to lay down depth
        globePrimitive = new MockPrimitive(reusableGlobePrimitive, Pass.GLOBE);
        tilesetPrimitive = new MockPrimitive(reusableTilesetPrimitive, Pass.CESIUM_3D_TILE);

        scene.primitives.add(globePrimitive);
        scene.primitives.add(tilesetPrimitive);
    });

    afterEach(function() {
        scene.primitives.removeAll();
        globePrimitive = globePrimitive && !globePrimitive.isDestroyed() && globePrimitive.destroy();
        tilesetPrimitive = tilesetPrimitive && !tilesetPrimitive.isDestroyed() && tilesetPrimitive.destroy();
    });

    it('classifies 3D Tiles', function() {
        return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl, {
            classificationType : ClassificationType.CESIUM_3D_TILE,
            modelMatrix : modelMatrix
        }).then(function(tileset) {
            globePrimitive.show = false;
            tilesetPrimitive.show = true;
            Cesium3DTilesTester.expectRenderTileset(scene, tileset);
            globePrimitive.show = true;
            tilesetPrimitive.show = false;
            Cesium3DTilesTester.expectRenderBlank(scene, tileset);
        });
    });

    it('classifies globe', function() {
        return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl, {
            classificationType : ClassificationType.TERRAIN,
            modelMatrix : modelMatrix
        }).then(function(tileset) {
            globePrimitive.show = false;
            tilesetPrimitive.show = true;
            Cesium3DTilesTester.expectRenderBlank(scene, tileset);
            globePrimitive.show = true;
            tilesetPrimitive.show = false;
            Cesium3DTilesTester.expectRenderTileset(scene, tileset);
            globePrimitive.show = true;
            tilesetPrimitive.show = true;
        });
    });

    it('classifies both 3D Tiles and globe', function() {
        return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl, {
            classificationType : ClassificationType.BOTH,
            modelMatrix : modelMatrix
        }).then(function(tileset) {
            globePrimitive.show = false;
            tilesetPrimitive.show = true;
            Cesium3DTilesTester.expectRenderTileset(scene, tileset);
            globePrimitive.show = true;
            tilesetPrimitive.show = false;
            Cesium3DTilesTester.expectRenderTileset(scene, tileset);
            globePrimitive.show = true;
            tilesetPrimitive.show = true;
        });
    });

    it('renders with batch table', function() {
        return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl, {
            classificationType : ClassificationType.BOTH,
            modelMatrix : modelMatrix
        }).then(function(tileset) {
            Cesium3DTilesTester.expectRenderTileset(scene, tileset);
        });
    });

    it('renders with binary batch table', function() {
        return Cesium3DTilesTester.loadTileset(scene, withBatchTableBinaryUrl, {
            classificationType : ClassificationType.BOTH,
            modelMatrix : modelMatrix
        }).then(function(tileset) {
            Cesium3DTilesTester.expectRenderTileset(scene, tileset);
        });
    });

}, 'WebGL');
<|endoftext|>


<commit_before>// @flow
/**
 * TimeMachine
 *
 * @module internal/machines/time-machine
 */

import type { VoidFn, Time } from '../flow-types'
import { noop } from '../utils'

export const InfiniteTimeMachine = (
  requestAnimationFrame: (fn: VoidFn) => void,
  cancelAnimationFrame: (frame: number) => void,
): Time => {

  let _frame: ?number = null;
  let _machineIsStopped: boolean = false;
  let _jobs: Function[] = [];

  const runIteration: VoidFn = () => {
    if (_machineIsStopped) return;

    _frame = requestAnimationFrame(() => {
      _jobs.forEach(job => job());
      runIteration();
    });
  }

  const machine: Time = {
    isStopped: (): boolean => _machineIsStopped,

    do: (job: Function) => {
      _jobs.push(job);
      return machine;
    },

    run: () => {
      _machineIsStopped = false;
      runIteration();
      return machine;
    },

    stop: () => {
      if (_frame) {
        cancelAnimationFrame(_frame);
      }
      _frame = null;
      _machineIsStopped = true;
      _jobs = [];
    }

  };

  return machine;
};

export const FiniteTimeMachine = (machine: Time, duration: number): Time => {

  let _startTime: number = 0;
  let _onComplete = () => {};

  const { do: _do, run: _run, ...rest } = machine;

  const finiteMachine = {
    ...rest,
    do: (job: Function) => {
      const _job = () => {
        const elapsedTime: number = Date.now() - _startTime;
        if (elapsedTime >= duration) {
          machine.stop();
          _onComplete();
        }
        job(elapsedTime);
      }
      _do(_job);
      return finiteMachine;
    },
    run: (onComplete) => {
      _startTime = Date.now();
      _onComplete = onComplete || _onComplete;
      _run();
      return finiteMachine;
    },
  };

  return finiteMachine;
};
<commit_msg>:bug: Move where the job gets called in the time-machine so it doesn't apply old styles<commit_after>// @flow
/**
 * TimeMachine
 *
 * @module internal/machines/time-machine
 */

import type { VoidFn, Time } from '../flow-types'
import { noop } from '../utils'

export const InfiniteTimeMachine = (
  requestAnimationFrame: (fn: VoidFn) => void,
  cancelAnimationFrame: (frame: number) => void,
): Time => {

  let _frame: ?number = null;
  let _machineIsStopped: boolean = false;
  let _jobs: Function[] = [];

  const runIteration: VoidFn = () => {
    if (_machineIsStopped) return;

    _frame = requestAnimationFrame(() => {
      _jobs.forEach(job => job());
      runIteration();
    });
  }

  const machine: Time = {
    isStopped: (): boolean => _machineIsStopped,

    do: (job: Function) => {
      _jobs.push(job);
      return machine;
    },

    run: () => {
      _machineIsStopped = false;
      runIteration();
      return machine;
    },

    stop: () => {
      if (_frame) {
        cancelAnimationFrame(_frame);
      }
      _frame = null;
      _machineIsStopped = true;
      _jobs = [];
    }

  };

  return machine;
};

export const FiniteTimeMachine = (machine: Time, duration: number): Time => {

  let _startTime: number = 0;
  let _onComplete = () => {};

  const { do: _do, run: _run, ...rest } = machine;

  const finiteMachine = {
    ...rest,
    do: (job: Function) => {
      const _job = () => {
        const elapsedTime: number = Date.now() - _startTime;
        job(elapsedTime);

        if (elapsedTime >= duration) {
          machine.stop();
          _onComplete();
        }
      }
      _do(_job);
      return finiteMachine;
    },
    run: (onComplete) => {
      _startTime = Date.now();
      _onComplete = onComplete || _onComplete;
      _run();
      return finiteMachine;
    },
  };

  return finiteMachine;
};
<|endoftext|>