/**
* This is the class actionLibrary
*
*
* @class ActionLibrary
* @private
*/
define(["util", "underscore", "validate", "volition", "ruleLibrary"],
function(util, _, validate, volition, ruleLibrary, testSocial, testActions) {
var actions = []; //An array containing all of the actions available in this social world.
//Experimenting with having a 'grammar' to define the actions of the world.
var startSymbols = [];
var nonTerminals = [];
var terminalActions = [];
/**
* @method getAllActions
* @private
* @description returns an array containing every action (terminal or otherwise) available in the social world.
* @return {Array} [An array containing every single action defined in the social world.]
*/
var getAllActions = function(){
return actions;
};
/**
* @method getStartSymbols
* @private
* @description Returns an array containing every 'start action.' Conceived to return all actions specifically tied to an intent.
* @return {Array} [An array containing every 'root' acton (every action tied to an intent) in the social world]
*/
var getStartSymbols = function(){
return startSymbols;
};
/**
* @method getNonTerminals
* @private
* @description Returns an array containing every 'non terminal' This will include both root and non-root actions, but exclude terminal actions.
* @return {[type]} [An array containing every 'non terminal' action.]
*/
var getNonTerminals = function(){
return nonTerminals;
};
/**
* @method getTerminalActions
* @description Returns an array containing every terminal action.
* @return {[type]} [An array containing every terminal action]
*/
var getTerminalActions = function(){
return terminalActions;
};
/**
* @methodclearActionLibrary
* @description Completely empties out the the action library by zero-ing out the arrays of actions, startSymbols, nonTerminals, and terminalActions. Used mainly for testing purposes.
*/
var clearActionLibrary = function(){
actions = [];
startSymbols = [];
nonTerminals = [];
terminalActions = [];
};
/**
* @method addActions
* @public
* @memberOf CiF
* @description Takes in either a JSON file or a JSON string representing the definition of an action or actions and stores it in the action library. This effect is cumulative; calling this function on multiple files will lead to the actions from both files being stored in the action library.]
* @param {JSON} data - Either a JSON string or a JSON file defining an action or actions.
* @return {array} [An array of every action currently stored in the action library.]
*/
var parseActions = function(data){
var parsedActions;
var fileName;
var actionsToCategorize = [];
try {
if (typeof data === "string") {
parsedActions = (JSON.parse(data)).actions;
fileName = (JSON.parse(data)).fileName;
} else if (typeof data === "object") {
parsedActions = data.actions;
fileName = data.fileName;
} else {
console.log("unexpected value:", data);
throw new Error("Error parseActions: unexpected data value: ", typeof data);
}
} catch (e) {
throw new Error("JSON Error parseActions " + e);
}
if (parsedActions === undefined) {
throw new Error("Error: social structure data file must be JSON that defines a top-level key 'socialStructure'");
}
for (var i = 0; i < parsedActions.length; i++) {
var action = parsedActions[i];
action.fileName = fileName;
// Error Checking
// ////#CODEREVIEW: add validation that there can't be two different actions that have the same intent defined.
validate.action(action, "Examining action #" + i);
if(actionAlreadyExists(action)){
console.error("Error! The action " + action.name + " is already defined!" );
continue;
}
actions.push(util.clone(action));
actionsToCategorize.push(action);
}
categorizeActionGrammar(actionsToCategorize);
return actions;
};
/**
* @method actionAlreadyExists
* @private
* @description a simple helper function to see if a newly parsed in action hasn't already been defined -- this is done by looking at the name of the action. This means that even if two actions are quite different, if they share the same name an error will be printed to the console.]
* @param {Object} potentialNewAction [The action that has just been read in, and is to be checked against the actions already in the action library.]
* @return {Boolean} [Returns true if the action already exists. False otherwise.]
*/
var actionAlreadyExists = function(potentialNewAction){
for(var i = 0; i < actions.length; i += 1){
if(actions[i].name === potentialNewAction.name){
//uh oh, is already exists!
return true;
}
}
};
/**
* @method categorizeActionGrammar
* @description This method takes in an unsorted list of actions (in the style returned from the parseActions method) and, based on the properties of these actions, determines if they are 'start', 'terminal' or 'non-terminal' actions and stores them in teh appropriate array of actionLibrary
* @param {[array]} actionPool [Contains an unsorted list of all of the action termainals and non terminals]
*/
var categorizeActionGrammar = function(actionPool){
var currentAction;
for(var i = 0; i < actionPool.length; i += 1){
currentAction = util.clone(actionPool[i]);
if(actionPool[i].intent !== undefined){
startSymbols.push(currentAction);
}
if(actionPool[i].leadsTo !== undefined){
nonTerminals.push(currentAction); // so start terminals ALSO end up here. Maybe that's good? Can change into an else-if if not!
}
if(actionPool[i].effects !== undefined){
terminalActions.push(currentAction);
}
}
};
/**
* @method getSortedActionsFromVolition
* @description Finds the actions that the initiator wants to take towards the responder, and sorts them by volition score.
* @param {String} initiator [The name of the initiator of the action]
* @param {String} responder [The name of the responder of the action]
* @param {Object} registeredVolition [A registered volition object]
* @param {Boolean} isAccepted [Whether or not the responder accepts the intent of the volition.]
* @param {Number} weight [How much the initiator wants to pursue this volition.]
* @param {[Number]} numActionsPerGroup [Used to determine how many 'actions per group' to include. Will ultimately default to one if unspecified.]
* @param {Array} cast [The characters to use in consideration for the binding of various roles the actions might need.]
* @return {[Array]} [An array of actions the initiator wants to take towards the responder, sorted by weight.]
*/
var getSortedActionsFromVolition = function(initiator, responder, registeredVolition, isAccepted, weight, numActionsPerGroup, cast){
//console.log("Inside of getSortedactionsFromVolition");
var actions = getTerminalActionsFromVolition(initiator, responder, registeredVolition, isAccepted, weight, numActionsPerGroup, cast);
var sortedActions = sortActionsByVolitionScore(actions);
return sortedActions;
};
/**
* @method sortActionsByVolitionScore
* @private
* @description Sorts an array of actions based on their weights in descending order.. Specifically, each action has a list of actions that it 'leads to' -- and it is THIS list of actions that is being sorted. Uses recursion to get to the end of the chain. Also sorts the GoodBindings of each weight as well.
* @param {Array} actions [An array of actions to be sorted]
* @return {Array} [The sorted actions]
*/
var sortActionsByVolitionScore = function(actions){
var descSortedActions = _.sortBy(actions, "weight");
actions = descSortedActions.reverse(); // now all of our actions are sorted, sweet!
//And, uh, I guess now we want to do the same as we drill downwards?
for(var i = 0; i < actions.length; i += 1){
var nextActions = actions[i].actions;
if(nextActions !== undefined){
actions[i].actions = sortActionsByVolitionScore(nextActions);
}
//let's try sorting the 'good bindings' by their weight$$ property.
if(actions[i].goodBindings !== undefined){
var descSortedBindings = _.sortBy(actions[i].goodBindings, "weight$$");
actions[i].goodBindings = descSortedBindings.reverse();
}
}
return actions;
};
/**
* @method getTerminalActionsFromVolition
* @description This method takes the names of the initiator and responder of an action and a registered volition
* between them, and will go through the entire grammar for the intnet specified in the volition and return all
* terminal actions that are appropriate (are of the correct accept/reject polarity, have all conditions met, etc.)
* The number of actions returned per action group is determined by numActionsPerGroup.
* Cast indicates the characters to use for role binding.
* @param {[String]} initiator [The name of the initiator of the action.]
* @param {[String]} responder [The name of the responder of the action.]
* @param {[Object]} registeredVolition [The registered volition between the initiator and responder]
* @param {[Number]} numActionsPerGroup [The number of terminal actions to return per 'action group.' They will ultimately be sorted by salience; i.e. if this number is 1, then only the most salient terminal action per action group will be returned. If 2, the top two salient terminal actions, etc.]
* @param {[Array]} cast [The characters to be used in the role binding process]
* @return {[Array]} [An Array of potential actions that can be carried out from the initiator to the responder]
*/
var getTerminalActionsFromVolition = function(initiator, responder, volition, isAccepted, weight, numActionsPerGroup, cast){
var actionIntent;
var goodTerminals = [];
var returnTerminalList = [];
var potentialTerminal;
//#CODREVIEW -- probably only need uniqueBindings or initialGoodBindings
var uniqueBindings = {};
uniqueBindings["initiator"] = initiator;
uniqueBindings["responder"] = responder;
//This name is a little misleading, as we don't know yet if the binding is good or bad,
//but we DO know that this binding has to take place, so I think it works...
var initialGoodBindings = {
"initiator" : initiator,
"responder" : responder
};
//first, we need to find the 'start' action based on the volition
for(var i = 0; i < startSymbols.length; i += 1){
actionIntent = startSymbols[i].intent;
if(actionIntent.class === volition.class &&
actionIntent.type === volition.type &&
actionIntent.intentDirection === volition.intentDirection){
//it appears that this is an action pertaining to this volition!
var rootAction = util.clone(startSymbols[i]);
rootAction.goodBindings = [];
rootAction.goodBindings.push(initialGoodBindings);
rootAction.weight = weight; // This is the 'base' score that came from our microtheories equivalent.
goodTerminals = getTerminalActionsFromNonTerminal(rootAction, isAccepted, numActionsPerGroup, uniqueBindings, cast);
if(goodTerminals === undefined){ // this means we didn't find any good actions!
console.log("found no valid actions for init: " + initiator + ", respond: " + responder + ", for volition " , volition);
return;
}
//#CODEREVIEW: Maybe just return goodTerminals right here.
returnTerminalList = goodTerminals; //Ok, so, it said temp temp temp, but actually I think this is pretty much exactly what we want!
}
}
return returnTerminalList;
};
/**
* @method getTerminalActionsFromNonTerminal
* @description Returns an array that contains all of the terminal actions that you can reach from a given nonTerminal action.
* @param {[Object]} nonTerminal [A 'non-terminal object that theoretically has a "leadsTo" field defined. This leadsTo field may lead to terminals or nonTerminals. If nonTerminals, this function is called recursively until terminals are reached.']
* @return {[Array]} [An Array of all of the non-terminals you can reach from the provided nonTerminal]
*/
var getTerminalActionsFromNonTerminal = function(nonTerminal, isAccepted, actionsPerGroup, uniqueBindings, cast){
var returnList = [];
var terminalsAtThisLevel = false;
var currentUniqueBindings = uniqueBindings;
var startingWeight = nonTerminal.weight;
actionsPerGroup = actionsPerGroup || 1; //By default, assume you want the MOST salient action per group (as opposed to, say, the top TWO salient actions)
isAccepted = typeof isAccepted !== 'undefined' ? isAccepted : true;
if(nonTerminal.leadsTo === undefined){
//we don't know what to do here! Uh, end of the road? Return?
return;
}
currentUniqueBindings = getUniqueActionBindings(nonTerminal, uniqueBindings);
//#CODEREVIEW -- why is cast passed in twice here? Ah, because one is available and one is all. But "all" never changes, so insead of passing in a clone, how about just a reference.
var nonTerminalWorkingBindingCombinations = getWorkingBindingCombinations(nonTerminal, util.clone(uniqueBindings), util.clone(cast), util.clone(nonTerminal.goodBindings), util.clone(cast));
if(nonTerminalWorkingBindingCombinations.length <= 0){
//Oops, there is no possible combination of cast members that make this work!
//So no point in going down this path anymore!
return;
}
nonTerminal.goodBindings = nonTerminalWorkingBindingCombinations;
//So, now at this point, where I have all of the 'good bindings' at this level... I guess what I want to do
//is go through all of the influence rules, for each binding, and re-score them?
//The starting score should come from the 'parent' element.
//oh, wait, it has it already I think, because we don't have any children yet. OK.
computeInfluenceRuleWeight(nonTerminal);
//console.log("$$$$$ Here is my terminal action before going into the 'I found a terminal action' thing!", nonTerminal);
//#CODEREVIEW -- do we need this terminalActionsParentObject? Why not just keep on using nonTerminal instead?
var terminalActionParentObject = {};
terminalActionParentObject.name = nonTerminal.name;
terminalActionParentObject.weight = nonTerminal.weight;
terminalActionParentObject.goodBindings = nonTerminal.goodBindings;
terminalActionParentObject.actions = [];
var potentialActionsToReturn = [];
//#CODEREVIEW: Maybe think about breaking this for-loop into it's own function?
for(var i = 0; i < nonTerminal.leadsTo.length; i += 1){
var actionName = nonTerminal.leadsTo[i];
//We're going through each one of the 'leads to' thingies!
//If these lead-to things are terminals, then great, I guess we're done?
//
//TODO: Intead of having to recompute this every time, it would be cool to
//actually construct something that kept track of this structure... using associative arrays
//I suppose? Maybe pointers? Hmmmm..
//#CODEREVIEW -- fix the name of this fuction/remove extraneous functions with similar names.
var terminalAction = getTerminalActionFromNameGeneric(actionName, terminalActions);
if(terminalAction !== undefined){
terminalsAtThisLevel = true;
terminalAction.goodBindings = util.clone(nonTerminal.goodBindings);
if(nonTerminal.lineage === undefined){
terminalAction.lineage = nonTerminal.name;
}
else{
terminalAction.lineage = nonTerminal.lineage + "-" + nonTerminal.name;
}
//terminalAction.lineage = nonTerminal.lineage + "-" + nonTerminal.name;
currentUniqueBindings = getUniqueActionBindings(terminalAction, uniqueBindings);
var workingBindingCombinations = getWorkingBindingCombinations(terminalAction, util.clone(currentUniqueBindings), util.clone(cast), util.clone(terminalAction.goodBindings), util.clone(cast));
terminalAction.goodBindings = workingBindingCombinations;
//we found a terminal symbol! Great, let's add it to the list!
//Let's do some checks to make sure that the action that we're looking at is good.
//This means checking it's conditions, and checking if it's "isAccept" matches what we want.
if(!actionIsAppropriate(terminalAction, isAccepted, currentUniqueBindings)){
//oops, either the conditions or the isAccept didn't pass! Let's move along...
//console.log("how many times do you see me? inappropriate action: " , terminalAction);
continue;
}
//In "traditional CiF" we would only want one of these things. The most salient.
//But here we have the power to take the X most salient, if we so desire.
//TODO: (Of course) there is a LOT of thinking that has to go into how conditions work with all of this stuff... I'm kind of dreading that a little big!
//So, ok... here is what I'm going to do... I'm going to change all of this
//returnList manipulation, into creating a new 'action object' thingy, which will
//have an action array, and it is THAt array that will under go manipulation.
//AND FINE, I'm caving in! Let's compute influence rules for this terminal action, too!
computeInfluenceRuleWeight(terminalAction);
if(terminalAction.salience === undefined ){
terminalAction.salience = 0;
}
if(terminalAction.weight === undefined){
terminalAction.weight = 0;
}
terminalAction.salience = terminalAction.weight + terminalAction.salience; // if there is a hard-coded sailence, honor it.
//#CODEREVIEW: Get rid of salience code? Just comment it out maybe. We shouldn't have code executing that isn't doing anything.
//#CODEREVIEW: AH, ok! Change all of these things that are looking at salience to instead look at influence rule weight instead.
//#CODEREVIEW: Currently doing the above suggestion by just assigning the weight to the salience property.
if(terminalActionParentObject.actions === undefined || terminalActionParentObject.actions.length <= 0){
terminalActionParentObject.actions = [];
if(terminalAction.salience === undefined){
terminalAction.salience = computeActionSalience(terminalAction);
}
terminalActionParentObject.actions.push(terminalAction);
}
else{
if(terminalAction.salience === undefined){
terminalAction.salience = computeActionSalience(terminalAction);
}
var actionListLength = terminalActionParentObject.actions.length; // want to store this, because we'll be adjusting the length inside of the loop
for(var salienceIndex = actionListLength; salienceIndex > 0; salienceIndex -= 1){
if(terminalActionParentObject.actions[salienceIndex-1].salience >= terminalAction.salience){
//it's time to stop. use the length to decide if we should even bother adding it or not, I guess.
if(salienceIndex === actionListLength && actionListLength >= actionsPerGroup){
//This new guy isn't even good enough to make the list, ignore it and stop going through the list!
}
else{
//ok, cool, our new guy is bigger. Let's put him in.
terminalActionParentObject.actions.splice(salienceIndex, 0, terminalAction);
//And now check to see if anything needs to be removed.
if(terminalActionParentObject.actions.length > actionsPerGroup){
terminalActionParentObject.actions.splice(actionsPerGroup, terminalActionParentObject.actions.length - actionsPerGroup);
}
}
break;
}
//If we've made it to here, that implies that we've found a new most salience thing
//but let's wrap it an if just in case.
if( (salienceIndex-1) === 0 && terminalAction.salience > terminalActionParentObject.actions[salienceIndex-1].salience){
//we found a new 'most salience' thing, so put it at the front of the list!
terminalActionParentObject.actions.splice(salienceIndex - 1, 0, terminalAction);
//And now check to see if anything needs to be removed.
if(terminalActionParentObject.actions.length > actionsPerGroup){
terminalActionParentObject.actions.splice(actionsPerGroup, terminalActionParentObject.actions.length - actionsPerGroup);
}
break; // We're at the end of the loop, but let's break anywya just because.
}
}
}
}
else{ // Ah, we must be dealing with another non-terminal! let's DIG DEEPER!
//#CODEREVIEW: This code is pretty much exactly repeated elsewhere in this function. Make it it's own function, maybe passing in special parametrs as needed.
var nonTerminalAction = getTerminalActionFromNameGeneric(actionName, nonTerminals);
nonTerminalAction.goodBindings = nonTerminal.goodBindings;
nonTerminalAction.weight = nonTerminal.weight;
//Figure out the 'lineage' of the action (i.e., keep track of the path we've taken down the tree.)
if(nonTerminal.lineage === undefined){
nonTerminalAction.lineage = nonTerminal.name;
}
else{
nonTerminalAction.lineage = nonTerminal.lineage + "-" + nonTerminal.name;
}
//Get the unique bindings that still work.
currentUniqueBindings = getUniqueActionBindings(nonTerminalAction, uniqueBindings);
if(!actionIsAppropriate(nonTerminalAction, isAccepted, currentUniqueBindings)){
//oops, either the conditions or the isAccept didn't pass! Let's move along...
//console.log("how many times do you see me? inappropriate action: " , terminalAction);
continue;
}
//RECURSIVE CALL! Using the non-terminal we're on as the starting point for the next level down the tree.
var diggingDeeperActions = getTerminalActionsFromNonTerminal(nonTerminalAction, isAccepted, actionsPerGroup, util.clone(currentUniqueBindings), util.clone(cast));
if(diggingDeeperActions === undefined || diggingDeeperActions.length <= 0){
continue; // oops! This 'leads to' led to something that had no valid bindings! Better move on!
}
//Store the actions we found by 'digging deeper'
nonTerminalAction.actions = [];
for(var ddActionIndex = 0; ddActionIndex < diggingDeeperActions.length; ddActionIndex += 1){
var thingToAdd = diggingDeeperActions[ddActionIndex];
nonTerminalAction.actions.push(util.clone(thingToAdd));
}
//And return the nonTerminalAction we created, that has stored within it now all of the 'good actions' that it can lead to.
returnList.push(util.clone(nonTerminalAction));
}
}
//Because there might be non-terminals and terminals at the same level, do a check
//to see if we need to add anything in at this level in the tree.
if(terminalsAtThisLevel === true){
for(var terminalsToPushUpIndex = 0; terminalsToPushUpIndex < terminalActionParentObject.actions.length; terminalsToPushUpIndex += 1){
returnList.push(util.clone(terminalActionParentObject.actions[terminalsToPushUpIndex]));
}
}
//If we've gotten here, we must have gotten everything we need!
return returnList;
};
/**
* @method computeActionsSalience
* @description Takes an action as a parameter. If it's salience score is undefined, computes a new salience score based on it's conditions.
* @param {[Object]} terminalAction [An action that should come at the 'end' of the action tree (i.e. it should have effects associated with it). This actions conditions are used to compute salience.]
* @return {[Number]} [The number representing the salience of this particular action.]
*/
var computeActionSalience = function(terminalAction){
var returnValue;
var multiplier = 5; // Maybe this should live in some constants thing? Or, better yet, be something that the user can specify?
if(terminalAction.salience !== undefined){
returnValue = terminalAction.salience;
}
else{
var numConditions = terminalAction.conditions.length;
if(numConditions === undefined){
numConditions = 0;
}
var salienceCalculation = numConditions * multiplier;
returnValue = salienceCalculation;
}
return returnValue;
};
//MYU OLD INFLUENCE RULE CODE, but separated out (because I think other things were calling it!)
//Going to change all instances of 'nonTerminal' to 'action', because I think any action can actually
//be passed through this now.
/**
* @method computeInfluenceRuleWeight
* @private
* @description Takes in an action, goes through all of its valid bindings, and evaluates the influence rule for each set of bindings. Stores the weight with each binding and, for the best weight (i.e. the best binding) stores it at the level of the action.
* @param {Object} action [The action to compute the weight for. Should have at least one 'goodBinding' attached to it]
*/
var computeInfluenceRuleWeight = function(action){
var bestWeightFoundSoFar = -999999;
for(var goodBindingIndex = 0; goodBindingIndex < action.goodBindings.length; goodBindingIndex += 1){
var tempGoodBindings = action.goodBindings[goodBindingIndex];
//var oldWeight = findWeightFromPreviousBinding(tempGoodBindings, oldGoodBindings);
var oldWeight = tempGoodBindings.weight$$;
if(oldWeight === undefined){
//This should only happen at the 'top level' I think.
oldWeight = action.weight; // This should be equal to the 'starting volition'
}
var scoreFromInfluenceRules = evaluateActionInfluenceRules(action, tempGoodBindings);
//console.log("Getting here! Here is score from influence rules! " , scoreFromInfluenceRules);
//I'm starting to get a little doubtful that this is going to work. Oh, unless... unless the score LIVEs inside of the good bindings?
//Sure, the score can live there, but the 'BEST' score should also live at the level of the influence rule itself... yah?
//AND DON'T FORGET! The score is adjusted by what has come before it, too!
//var candidateWeight = startingWeight + scoreFromInfluenceRules;
var candidateWeight = oldWeight + scoreFromInfluenceRules;
if(candidateWeight > bestWeightFoundSoFar){
//We've found a new best candidate!
action.weight = candidateWeight;
bestWeightFoundSoFar = candidateWeight;
}
action.goodBindings[goodBindingIndex].weight$$ = candidateWeight;
}
};
/**
* @method actionIsAppropriate
* @description actionIsAppropriate checks various qualities that would make an action "not appropriate", such as an action being marked as an "accept" action when we are looking for a reject action.
* @param {[Object]} action [The method uses properties of this action, such as isAccept and goodBindings, to confirm if the action is still appropriate.]
* @param {Boolean} isAccepted [A boolean representing the type of action we are looking for -- true for an accept action, false for a reject action.]
* @param {[Object]} uniqueBindings [All of the unique roles that have been defined for the action tree.]
* @return {[Boolean]} [Returns true if the action is still appropriate, false otherwise. Returning false here halts continuation down the action tree, as this being false means all subsequent actions will also be false.]
*/
var actionIsAppropriate = function(action, isAccepted, uniqueBindings){
if(action.isAccept !== undefined){
if(isAccepted !== action.isAccept){
return false; // oops, looking for one truth value but found another!
}
}
//If actions don't have an isAccept defined, assume that they are an isAccept of true.
//This only works with TERMINAL ACTIONS.
//TODO: Come up with a more robust means of teting for terminal actions than looking at existance of leadsTo and effects
if(action.isAccept === undefined && action.leadsTo === undefined && action.effects !== undefined){
if(isAccepted === false){
return false; // oops, if undefined we assume true, but we are looking for false!
}
}
//If we get to this point, and the action has no "goodBindings" associated with it,
//that means that there is no combination of characters that exists that satisfies all
//of the conditions that have been specified by this point in the "action tree." Therefore,
//there is no point in going further.
if(action.goodBindings.length <= 0){
return false; // if there are no good bindings here, the action is not appropriate?
}
return true;
};
//#CODEREVIEW: Consolodate these three functions. Maybe create a separate 'isTerminal' function that returns a boolean?
/**
* @method getActionFromNameGeneric
* @private
* @description Given the name of an action, searches through a provided array to find the corresponding action object and returns it.
* @param {string} actionName [The name of the action we are hunting for in the provided array.]
* @return {object} [An object representing all relevant information pertaining to the requested action. Returns undefined if no such action exists.]
*/
var getTerminalActionFromNameGeneric = function(actionName, actionArray){
for(var i = 0; i < actionArray.length; i += 1){
if(actionArray[i].name === actionName){
return util.clone(actionArray[i]);
}
}
return undefined;
};
/**
* @method getTerminalActionFromName
* @private
* @description Given the name of an action, searches through the terminal action array to find the corresponding action object and returns it.
* @param {string} actionName [The name of the action we are hunting for in the actions array.]
* @return {object} [An object representing all relevant information pertaining to the requested action. Returns undefined if no such action exists.]
*/
var getTerminalActionFromName = function(actionName){
for(var i = 0; i < terminalActions.length; i += 1){
if(terminalActions[i].name === actionName){
return util.clone(actions[i]);
}
}
return undefined;
};
/**
* @method getActionFromName
* @private
* @description Given the name of an action, searches through the action array to find the corresponding action object and returns it.
* @param {string} actionName [The name of the action we are hunting for in the actions array.]
* @return {object} [An object representing all relevant information pertaining to the requested action. Returns undefined if no such action exists.]
*/
var getActionFromName = function(actionName){
for(var i = 0; i < actions.length; i += 1){
if(actions[i].name === actionName){
return util.clone(actions[i]);
}
}
return undefined;
};
//#CODEREVIEW: Give this a better name so that we know this is the 'real' bindActionEffects
var bindActionEffects2 = function(actionObject, bindingsToUse){
for(var i = 0; i < actionObject.effects.length; i += 1){
actionObject.effects[i].first = bindingsToUse[actionObject.effects[i].first];
actionObject.effects[i].second = bindingsToUse[actionObject.effects[i].second];
}
return actionObject;
};
/**
* @method getUniqueActionBindings
* @description Given an action (actionObject) and an object representing all of the unique roles we've encountered thus far (uniqueBindings), go through the roles specified in the action and, if not already present in the uniqueBindings object, add them to it!
* @param {[Object]} actionObject [An action object. This method goes through it's first and second roles of each of it's conditions, and adds any new roles it finds to the unique bindings object]
* @param {[Object]} uniqueBindings [An object representing all of the unique roles found by this point in the action chain. If undefined, this method will create a new one.]
* @return {[Object]} [An object containing all of the unique roles used by this point in the action chain.]
*/
var getUniqueActionBindings = function(actionObject, uniqueBindings){
//Go through all of the conditions and check them for new roles
var conditions = actionObject.conditions;
for (var i = 0 ; i < conditions.length ; i += 1) {
var predicate = conditions[i]; //store the current condition in a temp
//if the dictionary does not have an entry for the current predicate's first, initialize it
if (uniqueBindings[predicate.first] === undefined) {
uniqueBindings[predicate.first] = ""; //possible optimization to change the initialization to zero
}
//and the same for the second entry in there is a second character in the predicate
if (predicate.second !== undefined) {
if (uniqueBindings[predicate.second] === undefined) {
uniqueBindings[predicate.second] = "";
}
}
}
return uniqueBindings;
};
/**
* @method getWorkingBindingCombinations
* @description This method figures out potential combinations of characters that will satisfy all of the conditions
* that have been specified by this point in the action tree. Actions passed into the function through the 'action' parameter
* are assumed to have a field called "goodBindings" that represent working combinations of characters to roles found through
* previous calls to this function. These good bindings will be updated in this function as new roles are discovered (e.g a new role
* that appeared later on down the action tree). Additionally, as new conditions are found, old combinations of bindings that
* used to work may no longer work; this function will accomadate that as well. This method uses recursion.
* @param {[Object]} action [The action we are finding valid combinations of bindings for. Assumes it has both a conditions array and a goodBindings array.]
* @param {[Object]} uniqueBindings [A list of the roles that need to be filled. Some roles, such as initiator and responder, should be pre-populated with the initiator and responder of the action.]
* @param {[Array} availableCastMembers [The cast members to use in filling in roles. As a character can only fulfill one role at a time, characters are 'removed' from the cast once they are assigned a role.]
* @param {[Array]} combinationsToUse [Although the action parameter will have all of the potential combinations, due to the recursive nature of this function, it is important to specify which set of combinations we want to use. In general, when this function is called non-recursively, this parameter should include all of the 'goodBindings' found in the action. When called recursively, you shoudl only pass in a single binding at a time.s]
* @return {[Array]} [An array of all valid character-role combinations for the given action]
*/
var getWorkingBindingCombinations = function(action, uniqueBindings, availableCastMembers, combinationsToUse, allCastMembers){
var returnArray = [];
var newCombinationsToUse = [];
//We want to do the following for each of our existing 'good' Combinations.
//NOTE: This should only be > 1 when called from the outside. When called recursively, combinationsToUse should only consist of a single combination.
for(var workingCombinationIndex = 0; workingCombinationIndex < combinationsToUse.length; workingCombinationIndex += 1){
//#CODEREVIEW - get rid of this test.
if(action.name === "BOND" && workingCombinationIndex === 1){
//console.log("At our problem child...");
}
newCombinationsToUse = []; // kinda weird, but we want to zero it out each time, because we only ever want it to have one entry.
newCombinationsToUse.push(util.clone(combinationsToUse[workingCombinationIndex]));
availableCastMembers = util.clone(allCastMembers);
//I feel like we need to do something here to re-populate availableCastMembers with
//the people previously spliced out from the previous uniqueBindings?
//We want to start off by filling in the roles stored in 'uniqueBindings' with the roles
//that we've found that work from the previous combinations discovered.
for (var role in combinationsToUse[workingCombinationIndex]){
var characterName = combinationsToUse[workingCombinationIndex][role];
if( characterName !== ""){
//a character has been specified to work in this role (could be initiator, responder, or something else)
//remove them from the available cast members, but make sure that they are 'lodged' in the unique bindings.
//We remove them from the available cast members, because it means this character should be unavailable for any other role.
if(availableCastMembers !== undefined){
var castIndex = availableCastMembers.indexOf(characterName);
if(castIndex >= 0){
availableCastMembers.splice(castIndex, 1);
}
}
//And just as the initiator and responder roles have already been clearly defined earlier,
//inside of uniqueBidings, let's do the same for this new role...
uniqueBindings[role] = characterName;
}
}
//Used to help us find out if there are any roles that still need to be specified
//Even though we just went through previous combinations to fill in roles, there could
//still be some unspecified if this new action has introduced NEW roles.
var isFilled = true;
var emptyKey = "";
//find an unbound key in the uniqueBindings dictionary
for (var key in uniqueBindings) {
if (uniqueBindings[key] === "") {
emptyKey = key;
isFilled = false;
break;
}
}
//All of the roles are filled. We can check to see if the conditions of this action
//evaluate to true with this particular combination of roles and characters.
if(isFilled === true){
//Replace placeholder variables in conditions with actual character names.
var boundConditions = ruleLibrary.doBinding(uniqueBindings, util.clone(action.conditions));
//Find out if the conditions are true with this particular set of characters in these roles.
var evaluationResult = ruleLibrary.evaluateConditions(boundConditions);
if(evaluationResult === true){
//Awesome! It's true! Push it on to our return array for later!
returnArray.push(util.clone(uniqueBindings));
}
else{
//console.log("FAILURE FAILURE. not even going to bother printing the combination.");
}
}
else{ // uniqueBindings is not totally filled in yet.
//time to recurse.
for(var i = 0; i < availableCastMembers.length; i += 1){
uniqueBindings[emptyKey] = availableCastMembers[i]; // place an available cast member into the empty slot in the dictionary
var updatedCastMembers = util.clone(availableCastMembers);
updatedCastMembers.splice(i, 1); // the updated cast has the currently assigned member removed for the recursion
var potentialCombinations = getWorkingBindingCombinations(action, uniqueBindings, updatedCastMembers, newCombinationsToUse, allCastMembers);
//Depending on where we are in the recursion chain, there's a chance that potentialCombinations
//might have a length > 1. At least I think that's the case. If not, better safe than sorry, yeah?
for(var k = 0; k < potentialCombinations.length; k += 1){
returnArray.push(util.clone(potentialCombinations[k]));
}
}
//If we've gotten here, we want to 'clear out' the uniqueBindings slot of the current 'emptyKey'
//Because we want it to be clear for when we pop back up to the previous level of recursion.
uniqueBindings[emptyKey] = "";
}
}
return returnArray;
};
/**
* @method bindActionCondition
* @description Takes in an array of conditions and a specific binding to use, and replaces all 'generic roles' in the conditions (e.g., "x", "y", "cheater", etc.) with actual character names.
* @param {Array} conditions [An Array of conditions filled with generic roles (such a initiator, x, or cheater)]
* @param {[Object]} bindingToUse [A dictionary of sorts mapping which charactes should be used to fill in which roles]
* @return {[Array]} [An array of the same conditions passed in, but with their generic roles filled in with character names.]
*/
var bindActionCondition = function(conditions, bindingToUse){
for(var i = 0; i < conditions.length; i += 1){
if(conditions[i].first !== undefined){
conditions[i].first = bindingToUse[conditions[i].first];
}
if(conditions[i].second !== undefined){
conditions[i].second = bindingToUse[conditions[i].second];
}
}
return conditions;
};
//Given a binding, goes througha all of the influence rules of an action
//and keeps a running sum of their effects. Then returns that sum.
/**
* @method evaluateActionInfluenceRules
* @description Given a binding, goes through all of the influence rules of an action and keeps a rnning sum of their effects, then returns that sum.
* @param {[Object]} action [An action, with specified influence rules]
* @param {[Object]} bindingToUse [A specfication of the characters to use to fill in each role in the action's influence rules]
* @return {[Number]} [The sum of the influence rules for this action given this binding.]
*/
var evaluateActionInfluenceRules = function(action, bindingToUse){
var volitionSum = 0;
for(var i = 0; i < action.influenceRules.length; i += 1){
var rule = action.influenceRules[i];
var boundConditions = bindActionCondition(util.clone(rule.conditions), bindingToUse);
var isRuleTrue = ruleLibrary.evaluateConditions(boundConditions);
if(isRuleTrue === true){
volitionSum += rule.weight;
}
}
return volitionSum;
};
//Returns the 'best' terminal based on an actionList (where an actionList is presumambly)
//a list of potential actions that has been computed given a certain cast. Everything should
//already be sorted already, so it's just an easy matter of finding the 'first' thing in every
//action list until we find one with no other actions -- then that means that we're at the
//best terminal!
/**
* @method getBestTerminalFromActionList
* @description Returns the 'best' terminal from an actionList, where best is defined to be the terminal with the highest weight. This function assumes the actionList has already been sorted.
* @param {[Array]} actionList [An array of actions. Each of these actions itself contains another array of actions. All of these arrays within arrays, however, should be sorted already before calling this function.]
* @return {[Object]} [The best (highest weighted) terminal action, with it's roles filled in with the best binding of characters]
*/
var getBestTerminalFromActionList = function(actionList){
//console.log("inside of getTerminalsFromActionList");
if(actionList.length <= 0){
//we shouldn't be getting in here with an empty actionList!
return undefined;
}
if(actionList[0].actions !== undefined && actionList[0].actions.length > 0){
//we are not at a terminal! Keep digging deeper!
//And because we are only concerned with THE BEST, and the actionList should already be sorted,
//it should just be a matter of looking at the first entry; no need to look at the rest of the list.
return getBestTerminalFromActionList(actionList[0].actions);
}
else{
//Ok, we're at the best terminal!
var terminal = actionList[0];
//BUT -- we need to get the 'best binding!'
//There might be multiple best bindings!
var potentialBestBindings = [];
for(var i = 0; i < terminal.goodBindings.length; i += 1){
//See if this goodBinding is in the running for being a bestBinding!
if(terminal.goodBindings[i].weight$$ === terminal.weight){
potentialBestBindings.push(terminal.goodBindings[i]);
}
}
//Ok, pick one of the potentialBestBindings at random!
var goodBindingIndex = _.random(0, potentialBestBindings.length-1);
var bindingsToUse = potentialBestBindings[goodBindingIndex];
//and NOW what we want to do is 'fill in' the action with this good binding!
return bindActionEffects2(terminal, bindingsToUse);
}
};
//Given a volition object, returns the single 'best' action for that volition,
//using the best binding. if multiple best bindings exist, just picks one at random.
/**
* @method getAction
* @description CiF Interface function. Given a volition object, returns the single 'best' action for that volition using the best binding. If multiple best bindings exist, it will pick one at random.
* @param {[String]} initiator [The name of the character initiating the action]
* @param {[String]} responder [The name of the 'recipient of the action']
* @param {[Object]} volition [A registered volition object]
* @param {[Array]} cast [The cast of characters to be used for consideration of the filling in of roles.]
* @param {[Number]} numActionsPerGroup [How many terminals from a single 'actionGroup' should be returned. Defaults to 1 if unspecified.]
* @return {[Object]} [Returns the best, bound action for this particular initiator, responder, and cast.]
*/
var getAction = function(initiator, responder, volition, cast, numActionsPerGroup){
console.log("inside getAction");
//console.log("This is the contents of the actionLibrary: " , actionLibrary);
if(numActionsPerGroup === undefined){
numActionsPerGroup = 1;
}
var actionList;
var volitionInstance = volition.getFirst(initiator, responder);
while(actionList === undefined || actionList.length === 0){
var acceptedObject = volition.isAccepted(initiator, responder, volitionInstance);
var isAccepted = acceptedObject.accepted;
var weight = volitionInstance.weight;
actionList = getSortedActionsFromVolition(initiator, responder, volitionInstance, isAccepted, weight, numActionsPerGroup, cast);
volitionInstance = volition.getNext(initiator, responder);
//#CODEREVIEW -- move this if check into the while condition.
if(volitionInstance === undefined){
break;
}
}
var boundAction = getBestTerminalFromActionList(actionList);
return boundAction;
};
/**
* @method getActions
* @memberOf CiF
* @public
* @description Similar to getAction, but allows the user to specify the number of intents to draw from, and the number of actions that shold come from each intent.
* @param {String} initiator - The name of the character initiating the action
* @param {String} responder - The name of the recipient of the action
* @param {Object} volition - The registered volition object.
* @param {Array} cast - The pool of characters to be used for consideration for the filling in of roles.
* @param {Number} numIntents - The total number of different intents to pull actions from.
* @param {Number} numActionsPerIntent - How many actions should come from each intent.
* @param {Number} numActionsPerGroup - How many terminals should come from any given 'action group'
* @return {Array} A list of terminals, with roles bound with characters, that represent what the initiator most wants to do with the responder.
*/
var getActions = function(initiator, responder, volition, cast, numIntents, numActionsPerIntent, numActionsPerGroup){
//console.log("inside of getActions!");
if(numActionsPerGroup === undefined) numActionsPerGroup = 1;
var returnList = [];
var actionList;
var volitionInstance = volition.getFirst(initiator, responder);
if(volitionInstance === undefined){
//This means that this initiator has NO volitions towards this responder. Abort!
var emptyList = [];
return emptyList;
}
var intentsRepresented = 0;
var numActionsFromThisIntent = 0;
var thisIntentCountedYet = false;
while(intentsRepresented < numIntents){
thisIntentCountedYet = false;
numActionsFromThisIntent = 0;
var acceptedObject = volition.isAccepted(initiator, responder, volitionInstance);
var isAccepted = acceptedObject.accepted;
var weight = volitionInstance.weight;
actionList = getSortedActionsFromVolition(initiator, responder, volitionInstance, isAccepted, weight, numActionsPerGroup, cast);
for(var i = 0; i < actionList.length; i += 1){
returnList.push(util.clone(actionList[i]));
//console.log("What does returnList look like at this point...? ", returnList);
if(thisIntentCountedYet === false){
intentsRepresented += 1;
thisIntentCountedYet = true;
}
//We've found an action from this intent, and have already added it to the return list.
numActionsFromThisIntent += 1;
if(numActionsFromThisIntent === numActionsPerIntent){
//We've reached our quota for this intent--let's move on to the next intent, even if there are more actions left that could be added.
break;
}
}
volitionInstance = volition.getNext(initiator, responder);
if(volitionInstance === undefined){
break;
}
}
var boundActions = extractAndSortTerminalsFromActionList(returnList);
return boundActions;
};
//TODO: Does this work if you ahve more than two layers worth of actions?
//TODO: Or for ANY non-standard structure for that matter?
/**
* @method extractAndSortTerminalsFromActionList
* @description Given an actionList, gets the terminals out of them, finds the best binding for each one, sorts them, and returns them in sorted order.
* @param {[Array]} actionList [An array of actions -- many of these will likely have their own arrays of actions to lead to]
* @return {[Array]} [A sorted list of all terminals.]
*/
var extractAndSortTerminalsFromActionList = function(actionList){
//console.log("inside of extractAndSortTerminalsFromActionList!");
var allTerminals = [];
for(var i = 0; i < actionList.length; i += 1){
//Any given 'entry' in this list might have multiple actions, if 'numActionsPerGroup was > 1' in previous calls.
var currentAction = actionList[i];
if(actionList[i].actions !== undefined){
for(var j = 0; j < actionList[i].actions.length; j += 1){
//Umm... are the actions bound at this point? I'm not sure if they are. We might have to
//do something special here.
//These are now bound at this point yet -- we will have to do that eventually!
allTerminals.push(actionList[i].actions[j]);
}
}
else{
//if actionList[i].actions is undefined, that must mean that we are DEALING with a terminal already!
allTerminals.push(actionList[i]);
}
}
//Sort them based on their score.
var sortedTerminals = sortActionsByVolitionScore(allTerminals);
for(var k = 0; k < sortedTerminals.length; k += 1){
var bestBindings = getBestBindingFromTerminal(sortedTerminals[k]);
sortedTerminals[k] = bindActionEffects2(sortedTerminals[k], bestBindings);
}
return sortedTerminals;
};
/**
* @method getBestBindingFromTerminal
* @description Given a terminal action, looks at it's list of good bindings and finds the one that matches the score of the action itself. If multiple ones do, picks one at random.
* @param {[Object]} terminal [An Action]
* @return {[Object]} [An object representing which bindings are the best ones to use for this action]
*/
var getBestBindingFromTerminal = function(terminal){
//There might be multiple best bindings!
var potentialBestBindings = [];
for(var i = 0; i < terminal.goodBindings.length; i += 1){
//See if this goodBinding is in the running for being a bestBinding!
if(terminal.goodBindings[i].weight$$ === terminal.weight){
potentialBestBindings.push(terminal.goodBindings[i]);
}
}
//Ok, pick one of the potentialBestBindings at random!
var goodBindingIndex = _.random(0, potentialBestBindings.length-1);
var bindingsToUse = potentialBestBindings[goodBindingIndex];
return bindingsToUse;
};
var actionLibraryInterface = {
parseActions : parseActions,
getAllActions : getAllActions,
getActionFromName : getActionFromName,
//bindActionEffects : bindActionEffects,
bindActionEffects2 : bindActionEffects2,
categorizeActionGrammar : categorizeActionGrammar,
getStartSymbols : getStartSymbols,
getNonTerminals : getNonTerminals,
getTerminalActions : getTerminalActions,
getTerminalActionsFromNonTerminal : getTerminalActionsFromNonTerminal,
clearActionLibrary : clearActionLibrary,
getTerminalActionsFromVolition : getTerminalActionsFromVolition,
getSortedActionsFromVolition : getSortedActionsFromVolition,
getBestTerminalFromActionList : getBestTerminalFromActionList,
getAction : getAction,
getActions : getActions
};
/* test-code */
//actionLibraryInterface.bindActionEffects = bindActionEffects;
actionLibraryInterface.getWorkingBindingCombinations = getWorkingBindingCombinations;
/* end-test-code */
return actionLibraryInterface;
});


Audio Detection example
This example shows how to use an
AudioMeter
to detect if your microphone is working correctly. It also shows how to deal with various problems that can occur when requesting microphone access.
Request Microphone


Follow these steps to add new organizations to your profile:
- Log in to the Algorithm Lab.
- In the top navigation bar, click Connected as: organizationName.
- In the Switch Organization panel, click Create Organization.
- Enter the organization name and then click Add.
The organization name must be unique. "Created Successfully" displays.


Please provide your feedback on our performance.
How satisfied are you with our services?
How often do you use our services?
What type of features would you like us to add?
Do you have any aditional feedback for us?


The Entertainment Industry is being controlled by deadly spirits -Patapaa
by Lizbeth BrownSwedru-based hiplife musician Patapaa has made a very surprising statement about the entertainment industry.
According to the “One Corner” hitmaker, there are evil forces in the entertainment industry that are working hard to cause destruction.
Patapaa explained that there are several things that go on in the entertainment industry therefore artists must be spiritually strong to overcome these evil forces.
The musician made this comment when he disclosed am unfortunate incident that happened to him a few weeks ago at Tarkwa.
He disclosed that he was hospitalized after his close friend tried to poison him before going on stage to perform at Tarkwa.
This comes after there were reports earlier that Patapaa fainted just a few minutes to a show he was headlined to perform.
The musician was rushed to a nearby hospital and was said to be in a critical condition.
This, however, confirms Eagle Prophet’s prophecy where he recently revealed that Patapaa will be poisoned by his close friend.


| Characters | Description | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Atsushi Nakajima | Named after Atsushi Nakajima. A 18-year-old teenager who used to live at an orphanage before the caretakers threw him out.His ability is named Beast Beneath the Moonlight (月下獣, Gekkajū), which allows him to turn into a large white tiger with incredible strength, speed, regenerative capabilities and durability, although he has no control over it and retains no memory if he fully transforms. | |||||||||
| Osamu Dazai | Named after Osamu Dazai. A member of the Armed Detective Agency who takes Atsushi under his wing and is known as a "suicide maniac" due to his constant suicide attempts and contemplations of a peaceful death, preferably with a beautiful woman. | |||||||||
| Doppo Kunikida | Named after Doppo Kunikida. Dazai's partner, known for his meticulous planning, organisation and perfectionistic tendencies; due to this, he is easily riled by Dazai's pranks. He has a habit of writing and planning everything ahead in his signature notebook, with the front cover labelled "Ideals". | |||||||||
| Ranpo Edagawa | Named after Edogawa Ranpo. The only Agency member without an ability and a self-proclaimed detective. Although he is one of the oldest in the office, he lacks basic everyday skills, preferring to focus his intelligence on solving cases instead. | |||||||||
| Junichirō Tanizaki | Named after Jun'ichirō Tanizaki. An 18-year-old assistant at the Agency who mainly focuses on gathering information as his ability, Light Snow (細雪, Sasameyuki), allows him to project illusions within a certain area, which is not extremely suited for combat. | |||||||||
| Kenji Miyazawa | Named after Kenji Miyazawa. A 14-year-old optimistic and carefree boy hailing from the countryside, he is extremely popular among Yokohama residents due to his honesty and cheerful attitude. This makes him the Agency's primary data collector from eyewitnesses. | |||||||||
| Akiko Yosano | Named after Yosano Akiko. She is the medic of the Agency feared for her torturous treatments. While her ability Thou Shalt Not Die (君死にたもうこと勿れ, Kimi Shinitamou koto nakare) allows her to heal any wound, as long as the patient is on the verge of death; this results in her often injuring her patients thoroughly before healing them. | |||||||||
| Yukichi Fukuzawa | Named after Fukuzawa Yukichi. He is the President of the Armed Detective Agency, as well as Kunikida's mentor. His ability is All Men Are Created Equal (人上人不造, Hito no Ue ni Hito wo Tsukurazu), which allows him to control the abilities of his subordinates. This ability is especially useful for those who lack control over their abilities like Atsushi and Kyōka. |


Help System
Menu for the XCL12 Package
Menu for the XCL12 Package
- edge
- 2-D image edge massaging.
- fill
- Baade-Lucy background "filling" algorithm.
- hstpos
- Plot the position of HST on a map of the world
- hsubtract
- Baade-Lucy background subtraction algorithm.
- ils
- Iterative Least Squares image restoration.
- immean
- Compute mean of an image and save value as task parameter.
- jimage
- Create a jitter image from U2,U3 coordinates in a table.
- lgrlist
- Expand a list of images and group numbers
- registration
- Compute registration parameters and resample unaligned
- (Type
"help playpen opt=sys" for more information about the playpen package)


| S | stats toolbox needed | I | interactive (user input required) |
| B | bioinformatics toolbox needed | M | matlab needed (will not work in octave) |
| O | optimization toolbox needed | W | windows needed (will not work in linux) |
| X | currently broken | * | slow (two stars indicates very slow) |
| File Name | Brief Description | Page Number(s) | Tags |
|---|---|---|---|
| bayesLinRegDemo2d | Bayesian infernece for simple linear regression with known noise variance | 258 | |
| leastSquaresProjection | An illustration of least squares projection | 246 | |
| linregBayesCaterpillar | Bayesian linear regression with an uninformative prior | 261, 262 | S |
| linregDemo1 | Linear Regression Demo | 14, 250, 382 | |
| logregLaplaceGirolamiDemo | Example of the laplace approximation for logistic regression | 267, 268 | |
| logregMultinomKernelDemo | Multiclass Logistic Regression | 270 | |
| rankDefDemo | Rank Deficiency Demo | 247, 249, 732 | |
| softmaxDemo2 | Plot the softmax function as a histogram for various temperatures | 270 | |
| splineBasisDemo | Ridge regression for splines | 255, 257 |


css tips
z-index
flexbox
CSS methdologies
responsive design vs adaptive design?
- Responsive: There is one basic layout, and it changes responsively to
screen changes - Adaptive: For each possible screen size, there is a distinct layout.
icons
sprites
Tout sur les sprites CSS - la-cascade.io - 20150324
Les sprites CSS sont une façon de combiner plusieurs images dans un fichier image unique, permettant ainsi d’améliorer la performance de votre site en réduisant le nombre de requêtes HTTP.
CSS Image Sprites - Pros and Cons - getlevelten.com/blog/ahmad-kharbat - 20150911
ProS
- Fewer HTTP requests, which means less server overhead.
- Fewer HTTP requests also means reduced page load time on browser.
- Images appear faster (Especially the hover state images) because the Image Sprite is loaded once and for all.
Cons
- More development time for slicing images, combining them, and programming background positions in the CSS.
- More maintenance time. Whenever a modification is needed, the whole sprite needs to be re-generated carefully
- Less SEO friendly. Some images are better be placed in the HTML rather than being backgrounds. HTML images can contain Titles and Alternative texts that are more beneficial to SEO, while CSS backgrounds cannot.
persons
Former co-chairman of the W3C CSS Working Group, entrepreneur, software engineer


For checkbox and radio inputs, you can change them to select with `multiple="true"` or `multiple="false"` instead.


Kinetics is the study of reaction rates and how they are affected. Many factors, such as concentration, pressure, temperature, and enzyme activity, can impact the rate of a reaction. For example, a molecule's kinetic energy is directly proportional to its temperature, so increasing the temperature will result in an increase in reaction rate.
Definition of reaction rate, and examples of calculating the average rate of reaction.
Using method of initial rates to determine the order of a reaction.
How to find the units for the rate constant k for a zero, first, or second order reaction.
Screenshot as an example...
Deriving the integrated rate law for first-order reactions using calculus. How you can graph first-order rate data to see a linear relationship.
Example of graphing first-order rate data to see a linear relationship, and calculating rate constant k from the slope.


/*====================================================================* * * Copyright (c) 2011 Qualcomm Atheros Inc. * * Permission to use, copy, modify, and/or distribute this software * for any purpose with or without fee is hereby granted, provided * that the above copyright notice and this permission notice appear * in all copies.  IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * *--------------------------------------------------------------------*/ /*====================================================================* * * signed Transmit (struct plc * plc, byte source [], byte target []) ; * * send TCP/IP frames to a remote powerline device to establish * the source device TX PHY rate and remote device RX PHY rate; * *--------------------------------------------------------------------*/ #ifndef TRANSMIT_SOURCE #define TRANSMIT_SOURCE #include <memory.h> #include <errno.h> #include <sys/time.h> #include "../tools/error.h" #include "../tools/flags.h" #include "../tools/types.h" #include "../tools/timer.h" #include "../plc/plc.h" signed Transmit (struct plc * plc, byte source [], byte target []) { struct channel * channel = (struct channel *)(plc->channel); struct message * message = (struct message *)(plc->message); struct timeval ts; struct timeval tc; unsigned timer = 0; if (_allclr (plc->flags, PLC_SILENCE)) { char sourcename [ETHER_ADDR_LEN * 3]; char targetname [ETHER_ADDR_LEN * 3]; hexdecode (source, ETHER_ADDR_LEN, sourcename, sizeof (sourcename)); hexdecode (target, ETHER_ADDR_LEN, targetname, sizeof (targetname)); fprintf (stderr, "%s %s %s\n", channel->ifname, sourcename, targetname); } memset (message, 0xA5, sizeof (* message)); EthernetHeader (message, target, source, ETHERTYPE_IP); if (gettimeofday (&ts, NULL) == -1) { error (1, errno, CANT_START_TIMER); } for (timer = 0; timer < plc->timer; timer = SECONDS (ts, tc)) { if (sendpacket (channel, message, sizeof (* message)) <= 0) { error (1, ECANCELED, CHANNEL_CANTSEND); } if (gettimeofday (&tc, NULL) == -1) { error (1, errno, CANT_RESET_TIMER); } SLEEP (100); } return (0); } #endif


« CSS « CSS Reference
The :-moz-only-whitespace
pseudo-class matches an element that has no child nodes at all or empty text nodes or text nodes that have only white-space in them. Only when there are element nodes or text nodes with one or more characters inside the element, the element doesn't match this pseudo-class anymore.
span:-moz-only-whitespace { style properties }
span:-moz-only-whitespace::before { background-color: lime; }
...where...
<span> </span>


@article{hsieh2020pksensi, title={pksensi: An R package to apply global sensitivity analysis in physiologically based kinetic modeling}, author={Hsieh, Nan-Hung and Reisfeld, Brad and Chiu, Weihsueh A}, journal={SoftwareX}, volume={12}, pages={100609}, year={2020}, doi={https://doi.org/10.1016/j.softx.2020.100609}, publisher={Elsevier} }


Module: ActiveRecord::Scoping::ClassMethods
Do not use. This module is for internal use only.
| Relationships & Source Files | |
| Defined in: | activerecord/lib/active_record/scoping.rb |
Instance Attribute Summary
-
#scope_attributes
readonly
Collects attributes from scopes that should be applied when creating an AR instance for the particular class this is called on.
-
#scope_attributes? ⇒ Boolean
readonly
Are there attributes associated with this scope?
Instance Method Summary
Instance Attribute Details
#scope_attributes (readonly)
Collects attributes from scopes that should be applied when creating an AR instance for the particular class this is called on.
# File 'activerecord/lib/active_record/scoping.rb', line 17
def scope_attributes all.scope_for_create end
#scope_attributes? ⇒ Boolean
(readonly)
Are there attributes associated with this scope?
# File 'activerecord/lib/active_record/scoping.rb', line 22
def scope_attributes? current_scope end
Instance Method Details
#current_scope(skip_inherited_scope = false)
[ GitHub ]# File 'activerecord/lib/active_record/scoping.rb', line 26
def current_scope(skip_inherited_scope = false) ScopeRegistry.current_scope(self, skip_inherited_scope) end
#current_scope=(scope)
[ GitHub ]# File 'activerecord/lib/active_record/scoping.rb', line 30
def current_scope=(scope) ScopeRegistry.set_current_scope(self, scope) end
#global_current_scope(skip_inherited_scope = false)
[ GitHub ]# File 'activerecord/lib/active_record/scoping.rb', line 34
def global_current_scope(skip_inherited_scope = false) ScopeRegistry.global_current_scope(self, skip_inherited_scope) end
#global_current_scope=(scope)
[ GitHub ]# File 'activerecord/lib/active_record/scoping.rb', line 38
def global_current_scope=(scope) ScopeRegistry.set_global_current_scope(self, scope) end
#scope_registry
[ GitHub ]# File 'activerecord/lib/active_record/scoping.rb', line 42
def scope_registry ScopeRegistry.instance end


Finder Class
The Finder class allows for searching through a search path for a given file, as well as loading a given file.
Search order
The finder uses the following search logic to locale files:
- If there are any flash paths defined, these will be searched first, in order of definition
- If the current request context is a module, the module will be searched next
- If there are any more request paths defined, these will be the next in line, in order of definition
- Next, the APPPATH is searched
- All loaded packages will be searched
- And finally, the COREPATH will be searched
If you have enabled 'caching' in your app/config.php, and you have defined a valid cache path, the finder will
cache all files found, so it doesn't have to crawl the disk the next time a file is looked for. You can also specify the
cache lifetime in your config file.
forge($paths = array())
The forge method returns a new finder object.
| Static |
Yes |
| Parameters |
| Param |
Default |
Description |
| $paths |
array()
|
Array of paths to initialise this finder instance with. |
|
| Returns |
Finder Object |
| Example |
$array = array(APPPATH, COREPATH);
$finder = Finder::forge($array));
|
instance()
The instance method returns the singleton object of the Finder.
This instance is also used by the FuelPHP core classes to find files, and is instantiated
when first called with the APPPATH
and COREPATH
as default search paths.
| Static |
Yes |
| Parameters |
None
|
| Returns |
Finder Object |
| Example |
$finder = Finder::instance();
|
search($dir, $file, $ext = '.php', $multiple = false, $cache = true)
The search method is a static alias for locate()
on the default finder instance.
| Static |
Yes |
| Parameters |
| Param |
Default |
Description |
| $dir |
string |
Relative directory to search in. It is appended to all search paths defined when trying to locate the file. |
| $file |
string |
Basename of the file to find. |
| $ext |
'.php'
|
Extension of the file to find. This MUST include the leading dot. |
| $multiple |
false
|
If false, stop searching at the first file found. If true, search all paths, and return all files found as an array. |
| $cache |
true
|
If true, cache the results for subsequent requests to prevent unnecessary disk access. |
|
| Mixed |
The fully qualified path of the file found, or false if no file was found.
In case of a multiple search, an array of paths found is returned, or an empty array if no files were found. |
| Example |
// will return APPPATH/views/welcome/index.php
$viewfile = Finder::search('views', 'welcome/index');
|
add_path($paths, $pos = null)
The add_path method adds a new search path to the Finder instance, at the given position.
| Static |
No |
| Parameters |
| Param |
Default |
Description |
| $paths |
mixed |
Path or array of paths to add to the Finder's instance search paths. |
| $pos |
null
|
The position at which the path should be added to the list.
Possible options are:
null to append at the end of the list,
-1 to prepend at the start of the list, or
index to insert the path AFTER in the list after the given index number.
|
|
| Returns |
The current object for chaining |
| Thows |
OutOfBoundsException, when the given index position is out of range. |
| Example |
// make sure the finder searches 'mypackage' first
Finder::instance()->add_path(PKGPATH.'mypackage', -1);
|
remove_path($path)
The remove_path method removes the given path from the Finder instance search list.
| Static |
No |
| Parameters |
| Param |
Default |
Description |
| $path |
string |
Path to remove. |
|
| Returns |
The current object for chaining |
| Example |
// remove 'mypackage' from the search path list
Finder::instance()->remove_path(PKGPATH.'mypackage');
|
paths()
The paths method returns the list of defined search paths.
| Static |
No |
| Parameters |
None
|
| Returns |
array of paths |
| Example |
// fetch the defined paths for the default instance.
$paths = Finder::instance()->paths();
print_r($paths);
|
list_files($directory = null, $filter = '*.php')
The list_files method gets a list of all the files in a given directory inside
all of the loaded search paths (e.g. the cascading file system). This is useful for things like
finding all the config files in all the search paths.
| Static |
No |
| Parameters |
| Param |
Default |
Description |
| $directory |
null
|
Relative path from which to list the files. The path will be appended to all defined search paths. |
| $filter |
'*.php'
|
Type of files to look for. |
|
| Returns |
array, list of fully qualified filenames of all files found |
| Example |
// find all database config files
$dbcfg = Finder::instance()->list_files('config', 'db.php');
|
This method is aware of the current request context. This means that when the active request is an HMVC call to a module
controller, the module paths is dynamically added to the list of paths to search.
locate($dir, $file, $ext = '.php', $multiple = false, $cache = true)
The locate method locates files in the defined search paths.
| Static |
No |
| Parameters |
| Param |
Default |
Description |
| $dir |
string |
Relative directory to search in. It is appended to all search paths defined when trying to locate the file. |
| $file |
string |
Basename of the file to find. |
| $ext |
'.php'
|
Extension of the file to find. This MUST include the leading dot. |
| $multiple |
false
|
If false, stop searching at the first file found. If true, search all paths, and return all files found as an array. |
| $cache |
true
|
If true, cache the results for subsequent requests to prevent unnecessary disk access. |
|
| Mixed |
The fully qualified path of the file found, or false if no file was found.
In case of a multiple search, an array of paths found is returned, or an empty array if no files were found. |
| Example |
// will return APPPATH/views/welcome/index.php
$viewfile = Finder::instance()->locate('views', 'welcome/index');
|


@import tags._ @(account: Account) @help(account, 0){
@messages.at("help.tutor_register")
To complete the tutor registration, Please follow the steps below:
Fill in your personal particulars and press ‘Submit’ button to complete the registration.
Finally, We will review your profile and get result back to you by email.


Accordion - Nested
Accordion - Basic
Nested
Attractions
First Item
First item content!
Second Item
Second item content!
Third Item
Third item content!
Nested Disabled
Attractions
First Item
First item content!
Second Item
Second item content!
Third Item
Third item content!
Nested Parent Disabled
Attractions
First Item
First item content!
Second Item
Second item content!
Third Item
Third item content!


Tanigawa et al. 2019, Nature Communications datasets
The following datasets are available now:
Comprehensive datasets
The following datasets are available now:
Naming convention
The name of the datasets corresponds to the following conditions:
- all, coding, non-coding, and PTVs: This indicates the type of variants included in the analysis. PTVs = Protein Truncating Variants, coding = coding variants, non-coding = non-coding variants (does NOT include coding variants), and all = coding + non-coding.
- nonMHC: By default, all the variants on autosomes are included in the analysis. nonMHC dataset has variants outside of major histocompatibility complex region.
- z: The elements of summary statistic matrix is Z-score
- non-center: By default, the left/right-singular vector from truncated-singular value decomposition is centered around zero. non-center datasets skip this procedure.
- p[some value]: The default p-value threshold is 0.001. If there is a suffix like 'p0.01', that means the p-value threshold is adjusted to the specified value.


Chocolate Pizza
POSTED ON 15 DECEMBER 2013/DESSERTS
For the fig swirl: melt butter over medium heat in a saucepan. Add brown sugar and stir to dissolve. Halve all of the figs and toss in the saucepan with water and lemon juice. Cook over medium heat, stirring frequently, until you have a chunky-jammy mixture. Add salt with one or two stirs, set aside and let cool completely.
Ice Cream: In a small pot over medium heat, combine milk, and granulated sugar until sugar is completely dissolved and the milk is just barely lukewarm. Whisk in the egg yolks. Set mixture in the fridge and wait until the fig mixture is cooled.
Using an ice cream machine, pour liquids into the frozen basin and process according to manufactrer instructions, i.e., let spin and thicken for 20 minutes before adding mascarpone, fig jam mixture, and the nuts. Continue to process for +/- 10 minutes. Pour semi-frozen mixture into a pyrex dish or glass tupperware. Freeze for at least two hours before serving.
1 1/2 cups milk
1/2 mascarpone
1/2 tsp pink salt
1 lb Black Mission Figs
1/2 cup brown sugar
2-4 tbsp water
1 1/2 cups heavy cream
1/3 granulated sugar
2 egg yolk
1 lemon, juiced
1 cup honey roasted pecans, roughly chopped


本书pdf是 文字版，彩图版，书签良好。
相关书籍：
The Behavior of Gases and Liquids
Work, Heat, and Energy: The First Law of Thermodynamics
The Second and Third Laws of Thermodynamics: Entropy
The Thermodynamics of Real Systems
Phase Equilibrium
The Thermodynamics of Solutions
Chemical Equilibrium
The Thermodynamics of Electrochemical Systems
Gas Kinetic Theory: The Molecular Theory of Dilute Gases at Equilibrium
Transport Processes
The Rates of Chemical Reactions
Chemical Reaction Mechanisms I: Rate Laws and Mechanisms
Chemical Reaction Mechanisms II: Catalysis and Miscellaneous Topics
Classical Mechanics and the Old Quantum Theory
The Principles of Quantum Mechanics. I. De BroglieWaves and the Schrödinger Equation
The Principles of Quantum Mechanics. II. The Postulates of Quantum Mechanics
The Electronic States of Atoms. I. The Hydrogen Atom
The Electronic States ofAtoms. II.The Zero-OrderApproximation for Multielectron Atoms
The Electronic States of Atoms. III. Higher-Order Approximations
The Electronic States of Diatomic Molecules
The Electronic Structure of Polyatomic Molecules
Translational, Rotational, and Vibrational States of Atoms and Molecules
Optical Spectroscopy and Photochemistry
Magnetic Resonance Spectroscopy
Equilibrium Statistical Mechanics I. The Probability Distribution for Molecular States
Equilibrium Statistical Mechanics. II. Statistical Thermodynamics
Equilibrium Statistical Mechanics. III. Ensembles
The Structure of Solids, Liquids, and Polymers


Home
Classes
Interests
Worldview
Second Semester Classes
This semester, I'm teaching the following classes:
Click me.
Algebra 1
Geometry
Web Design
Yearbook


--- url: /protocols/saml section: articles classes: topic-page title: SAML topics: - saml contentType: - index useCase: - add-idp ---
Documentation on SAML protocol.
This article explains the various configuration options of SAML available with Auth0.
List of Identity Provider services known to support the SAML protocol.
How to use Auth0 in a SAML2 web application.
This page lists SAML Configurations for various Single Sign-on (SSO) integrations including Atlassian, G Suite, Hosted Graphite, Litmos, Cisco Webex, Sprout Video, FreshDesk, Tableau Server, Datadog, Egencia, Workday, and Pluralsight.
How to configure a SAML connection for use with Microsoft Active Directory Federations Services (ADFS).
How to configure Auth0 to use other Identity Providers.


Services
Architecture
Enterprise | Solution | Technical
Native Solutions
Power Platform | Applications | Integration
Governance
Security | Monitoring | Cost Optmisation
Design
Lean UX Analysis focused on your success
FinOps
Optimising Cloud Spend
Delivery
Agile execution on time and budget
Innovative Solutions
Explore AllNews
{% for post in site.posts limit:4 %}
{% endfor %}
{% include ads-block.html %}
Counters
2
Architects
4
Developers
50+
Projects delivered
100K+
Cups of coffee consumed


Sign up and gain the insights today!
×
Select your database
Oracle Database 12c
MySQL
Database Host
Enter the database host address.
Database Name
Enter the database instance name.
Username
Enter login account name of the database.
Password
Enter the password corresponding to the account.
I agree with the
End User Agreement
Add Database
Cancel
Checking information provided...


Visual Basic 6 applications store references to type libraries in the project (.vbp) file. VB allows you to link projects by setting references via the Project/References menu option. When you build a VB application that does not have binary compatibility enabled, VB will generate a new GUID for the typelib. Now when you wish to build any dependent VB projects, you must first remove the previous reference the old typelib and recreate the reference to the new typelib.
When building a large VB project, this process can take quite a long time. FIXVBPRef is a tool that will automatically fix missing typelib references for you.
In the VBP file, typelib references are stored in the following format
Reference=*\G{2E4F4861-542D-11D2-8B41-00C04F991474}#1.0#0#..\..\..\..\DLLs\AdStatusEventsSvr.dll#AdStatusEventsSvr 1.0 Type Library
The reference line is a # delimited string containing the following elements
To fix an invalid reference to a typelib, FIXVBPRef does the following
NOTE: FIXVBPRef will attempt to update the GUID of all referenced components, including some that may never change, therefore it must be able to load each referenced typelib.
When the vbp file was created, the typelib locations are stored using a relative path. In most cases, this allows for better location transparency since most developers tend to use the same directory structure on a project by project basis. However, there are many cases where the relative path fails to locate the typelib correctly because it may be located on a different drive or directory. FIXVBPRef will first attempt to load the typelib using the relative path stored in the vbp file. If that fails it will search in order
Most projects contain a BIN directory where the DLL and EXE files are written to. Some project further segregate binary components into subdirectories according to function or location. For example
C:\MyProject - Project root
\Source - Root
of source directories
\Test - Root of test directories
\Bin - Root of bin
directories
\Client - Contains client components and applications
\COM+ - Contains COM+ applications
\ASP - Contains ASP scripts
When FIXVBPRef cannot find a typelib it looks at the Bin root you specify as an argument on the command line and will recursively search the bin directory and all child directories for the desired typelib.
If you need to reference a component typelib that is not in the bin root, you can place a text file in the bin root directory that contains a list of directories (one per line) to recursively search as well. For example
(Sample FIXVBPRef.OPT)
C:\MyComponents\
C:\SomeThirdPartyComponent\
FIXVBPRef will look for the FIXVBPRef.opt file in the project root bin directory.
FIXVBPREF MyProject.vbp [MyBinDir]
Using a tool like FIXVBPRef you can completely automate builds of VB projects.
The sample makefile below is used to build the AdPublisher component of the Island Hopper Classifieds COM+ Sample Application
#VB Project Make File
PROJNAME=AdPublisher
PROJECT=$(PROJNAME).vbp
BINROOT=$(MSSDK)Samples\Com\Application_Samples\Island_Hopper_Classifieds\DLLs
TARGET="$(BINROOT)\$(PROJNAME).dll"
VBLOG="$(BINROOT)\VBBUILD.LOG"
#Modify the line below if you installed VB in a non-standard location
VB6="%ProgramFiles%\Microsoft Visual Studio\vb98\vb6.exe"
ALL : CLEAN $(TARGET) POSTCLEAN
CLEAN :
-@erase $(TARGET)
$(TARGET) : $(PROJECT)
fixvbpref $(PROJECT) $(BINROOT)
$(VB6) /make /out $(VBLOG) $(PROJECT)
POSTCLEAN :
-@erase $(BINROOT)\$(PROJNAME).exp
-@erase $(BINROOT)\$(PROJNAME).lib
FIXVBPRef is provided as an unsupported application sample.


Preparation time
overnight
Cooking time
30 mins to 1 hour
Serves
Serves 6
This is either a poor man’s Wellington, or a posh sausage roll, depending on how you look at it. It’s certainly good enough for a special meal. The sausage filling is spiked with black pudding, enhanced with a savoury mushroom base and topped with caramelised onions. Wrapped in crisp, buttery ‘plaited’ pastry, it looks really impressive but is easy to make.
For the puff pastry, combine the flours and salt in a bowl. Mix in enough cold water to form a reasonably tight but still kneadable dough (about 75-100ml/2½-3½fl oz).
Turn out on to a lightly floured surface and knead for 5-10 minutes, or until smooth.
Form into a rough rectangle, wrap in cling film and place in the fridge for at least seven hours.
Meanwhile, use a rolling pin to flatten the butter into a rectangle, 20cm/8in long and just slightly less than 12cm/4½in wide. Wrap this in cling film and return to the fridge.
On a floured surface, roll out the chilled dough to a rectangle, 12x30cm/4½x12in.
Place the chilled butter on the dough so that it covers the bottom two-thirds. Make sure it’s positioned neatly and comes almost to the edges of the dough.
Lift the exposed dough at the top and fold down over half of the butter. Fold the butter-covered bottom half of dough over the top.
You will now have a sandwich of two layers of butter and three of dough.
Seal the edges by pinching together. Place in a plastic food bag and chill in the fridge for an hour.
Remove the dough from the bag and with the short end towards you, fold the top quarter down and the bottom quarter up so that they meet in the middle, then fold the dough in half along the centre line. Chill for an hour.
Remove the dough and with the short end towards you, fold down one-third of the dough and fold the bottom third up. Chill for an hour.
Remove the dough and repeat the last process. The dough is now ready to use. Wrap in cling film and chill in the fridge while you make the filling.
Heat your oven to 200C/400F/Gas 6 and line a large, lipped baking tray with baking parchment (some butter may leak out of the pastry).
Put the mushrooms in a food processor and season with salt and pepper. Pulse until the mushrooms are broken down to a rough paste. Add the thyme and give the mix a final pulse.
Put the mushroom mixture into a dry frying pan on a medium-high heat and cook, stirring often, until all the moisture has evaporated from the mushrooms. Remove from the pan and leave to cool.
Meanwhile, heat the oil and butter in a large frying pan over a medium-low heat. Add the onions with the sugar and cook slowly until they are very soft and sweet. This will take at least 20 minutes.
Once caramelised, stir in the sherry vinegar.
Roll out the pastry into a rectangle, about 26x30cm/10½x12in, and place on the prepared baking tray. Spread the mushroom paste down the central third of the pastry, leaving a 5cm/2in gap at the top and bottom.
Mix the sausagemeat with the black pudding, mould into a long sausage shape that will fit on top of the mushroom paste and place it on the paste. Spread the caramelised onions on top of it.
Cut 2cm/¾in strips all the way down the pastry on each side of the filling. Take one strip over the filling from one side, then one from the other and so on, crossing the strips over to form a plaited effect. Tuck the ends of the pastry under the plait, trimming off excess if necessary. Brush the plait with beaten egg and sprinkle with sesame seeds.
Bake for 30 minutes or until the pastry is golden-brown. Leave to settle for 10 minutes or so, then serve hot or cold. This is delicious with a dollop of apple sauce on the side.


Guide Pages
Overview
An Inventory integration will allow you to configure Product price and inventory availability in Endless Aisle.
Figure 1: Illustrates a Product Detail View in Endless Aisle
The table below lists where each component comes from and how to modify it, where possible:
Table 1: Source for each component of Figure 5
| Component | Source | Service | How to Modify |
|---|---|---|---|
| Caitlin Mary Jane Shoe - Youth | Product.Name | Product Library | See Updating a Product |
| Hero Shot | Product.HeroShot | Product Library | |
| $29.99 | Pricing.OverridePrice or Pricing.RegularPrice | Pricing | See Pricing Rules |
| IN STOCK | Availability.Quantity | Availability | See Availability Rules |
| Navy | ColorDefinition.Name | Product Library | See Updating a Product |
Pricing Rules
Endless Aisle displays Product price using the request Getting Product Pricing for a Retail Location and the following rules:
- If
PricingTermId
has value, get the PricingTerm and display term information - Or, if
OverridePrice
has value, display it - Otherwise, display
RegularPrice
Pricing can be updated in three different ways:
Availability Rules
Endless Aisle displays the availability of a Product using the request Getting Availability For a Catalog Item By Location and the following rules:
- If
Quantity
is greater than 0, display IN STOCK - If
Quantity
is 0, display OUT OF STOCK
Availability can be updated using Updating Availability.
Creating a Sale Price
Creating a sale price for a Product involves…
- Getting the Catalog Item Identifier
- Getting the Location Identifier
- Getting the Pricing Identifier
- Creating the Sale Price
Steps
Step 1 - Getting the Catalog Item Identifier
Before you can create a sale price, you must know the Catalog Item Identifier associated with the Product.
This value is not shown in Endless Aisle, so you will need to search your Catalog using Searching for Products.
An example of this request is already provided in Getting the Product Slug.
From the response you can see the Catalog Item Identifier of the Product is bb54cb25-e1df-4710-9e05-c2473192cc99
.
Step 2 - Getting the Location Identifier
Before you can create a sale price, you have get the Identifier for the Location of the sale.
We can use Getting All Locations for a Company to look for a Location in Chicago called Atrium Mall.
Example Request
GET https://entitymanagerdemo.iqmetrix.net/v1/Companies(14146)/Locations
Authorization: Bearer (Access Token)
Accept: application/json
Example Response
From the response you can see the Location Id is 14239
.

]
Step 3 - Getting the Pricing Identifier
To create a sale price, the Product must have an existing Pricing, which you can find using Getting Product Pricing for a Retail Level, and the Identifiers from the previous two steps.
Example Request
GET https://pricingdemo.iqmetrix.net/v1/Companies(14146)/Entities(14239)/CatalogItems(bb54cb25-e1df-4710-9e05-c2473192cc99)/Pricing
Authorization: Bearer (Access Token)
Accept: application/json
Example Response
From this response you can determine the Pricing Pricing Identifier is 16446
.
If this request returned nothing, you would need to create a Pricing using either:
- Creating or Updating Product Pricing at Company Level or
- Creating or Updating Product Pricing at Location Level
HTTP 200 Content-Type: application/json
[
{
"Id": 16446,
"CatalogItemId": "a183f1a9-c58f-426a-930a-9a6357db52ed",
"CompanyId": 14146,
"EntityId": 14239,
"FloorPrice": 3.99,
"IsDiscountable": false,
"OriginalPrice": null,
"OverridePrice": 3.99,
"OverridePriceId": 512,
"PricingTermId": 78,
"RegularPrice": 10
}
]
Step 4 - Creating the Sale Price
Now that you have a Pricing Pricing Identifier, you can put the Product on sale. For this example a one week period in January and a sale price of 29.99 will be used.
Example Request
POST https://pricingdemo.iqmetrix.net/v1/Companies(14146)/Pricing(16445)/SaleOverridePrices
Authorization: Bearer (Access Token)
Accept: application/json
Content-Type: application/json
{
"IsDefault": false,
"SalePrice": 29.99,
"StartDateUTC": "2016-01-03T00:00:00",
"StopDateUTC": "2016-01-09T00:00:00"
}
Example Response
HTTP 201 Content-Type: application/json
{
"Id": 1177,
"CompanyId": 14146,
"IsDefault": false,
"PricingInformationId": 16445,
"SalePrice": 29.99,
"StartDateUTC": "2016-01-03T00:00:00",
"StopDateUTC": "2016-01-09T00:00:00"
}
Updating Pricing at Location Level
Updating the price of a Product for one Locations in the Company involves…
Step 1 - Getting the Catalog Item Identifier
Before you can update Pricing, you must know the Catalog Item Identifier associated with the Product.
This value is not shown in Endless Aisle, so you will need to search your Catalog using Searching for Products.
An example of this request is already provided in Getting the Product Slug.
From the response you can see the CatalogItemId
of the Product is bb54cb25-e1df-4710-9e05-c2473192cc99
.
Step 2 - Getting the Location Identifier
Before you can update a pricing for a Location, you must get its Identifier.
We can use Getting All Locations for a Company to look for a Location in Chicago called Atrium Mall.
An example of this request is already provided in Getting the Location Identifier.
From the response, you can see the Id
of Atrium Mall is 14239
.
Step 3 - Updating the Pricing
We can now update the Pricing using Creating or Updating Product Pricing at Location Level.
Note that the CompanyId
and EntityId
are different values.
Example Request
POST https://pricingdemo.iqmetrix.net/v1/Companies(14146)/Entities(14239)/CatalogItems(a183f1a9-c58f-426a-930a-9a6357db52ed)/Pricing
Authorization: Bearer (Access Token)
Accept: application/json
Content-Type: application/json
{
"CatalogItemId": "a183f1a9-c58f-426a-930a-9a6357db52ed",
"CompanyId": 14146,
"EntityId": 14239,
"FloorPrice": 49.99,
"IsDiscountable": false,
"OriginalPrice": null,
"PricingTermId": null,
"RegularPrice": 39.99
}
Example Response
HTTP 201 Content-Type: application/json
{
"Id": 16446,
"CatalogItemId": "a183f1a9-c58f-426a-930a-9a6357db52ed",
"CompanyId": 14146,
"EntityId": 14239,
"FloorPrice": 49.99,
"IsDiscountable": false,
"OriginalPrice": null,
"OverridePrice": null,
"OverridePriceId": null,
"PricingTermId": null,
"RegularPrice": 39.99
}
Updating Pricing at Company Level
Updating the price of a Product for all Locations in the Company involves…
Step 1 - Getting the Catalog Item Identifier
Before you can update Pricing, you must know the Catalog Item Identifier associated with the Product.
This value is not shown in Endless Aisle, so you will need to search your Catalog using Searching for Products.
An example of this request is already provided in Getting the Product Slug.
From the response you can see the CatalogItemId
of the Product is bb54cb25-e1df-4710-9e05-c2473192cc99
.
Step 2 - Updating the Pricing
We can now update the Pricing using Creating or Updating Product Pricing at Company Level.
Note that the CompanyId
and EntityId
are the same value.
Example Request
POST https://pricingdemo.iqmetrix.net/v1/Companies(14146)/Pricing
Authorization: Bearer (Access Token)
Accept: application/json
Content-Type: application/json
{
"CatalogItemId": "a183f1a9-c58f-426a-930a-9a6357db52ed",
"CompanyId": 14146,
"EntityId": 14146,
"FloorPrice": 49.99,
"IsDiscountable": false,
"OriginalPrice": null,
"PricingTermId": null,
"RegularPrice": 39.99
}
Example Response
HTTP 201 Content-Type: application/json
{
"Id": 16445,
"CatalogItemId": "a183f1a9-c58f-426a-930a-9a6357db52ed",
"CompanyId": 14146,
"EntityId": 14146,
"FloorPrice": 49.99,
"IsDiscountable": false,
"OriginalPrice": null,
"OverridePrice": 3.99,
"OverridePriceId": null,
"PricingTermId": null,
"RegularPrice": 39.99
}
Updating Availability
Updating the inventory availability of a Product involves…
Step 1 - Getting the Catalog Item Identifier
Before you can update availability, you must know the Catalog Item Identifier associated with the Product.
This value is not shown in Endless Aisle, so you will need to search your Catalog using Searching for Products.
An example of this request is already provided above om Getting the Product Slug.
From the response you can see the Catalog Item Identifier of the Product is bb54cb25-e1df-4710-9e05-c2473192cc99
.
Step 2 - Getting the Location Identifier
Before you can update availability for a Location, you must get its Identifier.
We can use Getting All Locations for a Company to look for a Location in Chicago called Atrium Mall.
An example of this request is already provided in Getting the Location Identifier.
From the response, you can see the Id
of Atrium Mall is 14239
.
Step 3 - Updating Availability
Finally, you can update availability using Configuring Availability and the Identifiers from the previous steps.
Example Request
POST https://availabilitydemo.iqmetrix.net/v1/Companies(14146)/CatalogItems
Authorization: Bearer (Access Token)
Accept: application/json
Content-Type: application/json
{
"Id": "bb54cb25-e1df-4710-9e05-c2473192cc99",
"EntityId": 14239,
"Quantity": 1,
"IsDropShippable": false,
"IsSerialized": false
}
Example Response
HTTP 201 Content-Type: application/json
{
"Id": "bb54cb25-e1df-4710-9e05-c2473192cc99",
"EntityId": 14239,
"Quantity": 1,
"IsDropShippable": false,
"IsSerialized": false
}


Enroll for Courses
Welcome
first name
Roles
NO
CourseID
CourseName
Credits
Lecturer Name
Course Capacity
Current Enrolment
courseStartDate
courseEndDate
Operation
NO
Course ID
Course Name
Credits
Lecturer Name
Course Capacity
Current Enrolment
courseStartDate
courseEndDate
Enroll Now


JCR Shell provides a command-line tool to get access to a remote JCR Webdav Server which provides JCR API access over WebDAV/HTTP(S).
JCR Shell is a pure JCR/Jackrabbit based client tool. Therefore, this tool should work against any Apache Jackrabbit based JCR system.
If you want to use JCR Shell against Hippo CMS, enable JCR Webdav Server in the system. See Hippo Repository JCR/WebDAV Support forge project homepage for detail.
You can download an executable JAR file of JCR Shell from Bloomreach Forge Maven repository: https://maven.onehippo.com/maven2-forge/org/onehippo/forge/jcrshell/jcrshell/. Move to the latest version directory and download jcrshell-x.x.x.jar from there.
You can run JCR Shell like the following:
$ java -jar jcrshell-2.0.0.jar --server="http://localhost:8080/cms/server" --user="admin:admin" . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.0.4.RELEASE) JCR Shell 2.0.0 exit or quit leaves program. help lists commands. jcr-shell:>
You can execute help to see all the available commands with descriptions.
jcr-shell:> help ---------------------------------------------------------------------------------------------------------------- Command Usage ---------------------------------------------------------------------------------------------------------------- aliases aliases cd cd [<path>|<reference property>] cdprev cdprev cduuid cduuid <uuid> credentials credentials <username> exit exit filecd filecd <path> filelist filelist [<directory>] filepwd filepwd <path> findreferences findreferences finduuid finduuid <uuid> help help [<command>] jexl jexl <path> [<argument> [..]] login login logout logout ls ls [<path>] mixinadd mixinadd <mixin type> mixinlist mixinlist mixinremove mixinremove <mixin type> namespaceadd namespaceadd <prefix> <uri> namespacelist namespacelist namespaceremove namespaceremove <prefix> nodeadd nodeadd <nodename> [<type>] nodeallowed nodeallowed nodecheckin checkin nodecheckout checkout nodecopy nodecopy <nodename> <target parent>/[name] nodediff nodediff <nodeame> [<path>/]<base> nodeexport nodeexport <nodename> <xml file> [<skipBinaries>] nodeimport nodeimport <xml file> [<uuidBehavior> [<referenceBehavior> [<mergeBehavior>]]] nodemove nodemove <nnodeame> [<path>/]<new nodename> noderemove noderemove <nodename> nodetree nodetree [<levels>] nodetypeget nodetypeget <name> nodetypelist nodetypelist [<primary|mixin>] order order <child node> (before|after|up|down|first|last) [<child node>] propadd propadd <property> [<type>] propallowed propallowed propdelete propdelete <property> [<property> [..]] propget propget <property> [<property> [..]] proplist proplist [<node>] propload propload <binary property> <file> propset propset <property> <value> [<type>] propstore propstore <binary property> <file> pwd pwd query query <sql|xpath> <statement> [limit <count>] refresh refresh reset reset save save server server [<http(s)_url>] sessionsave sessionsave status status syspropget syspropget [<property>] syspropset syspropset <property> <value> valueadd valueadd <propertyname> <value> [<type>] valueremove valueremove <property> <value> [<type>] versioncd versioncd <uuid> versioncreate versioncreate [<label>] versiondiff versiondiff [version [<otherversion>]] versioninfo versioninfo [<version>] versionlabeladd versionslabeladd <version> <label> [<true|false>] versionlabelremove versionslabelremove <label> versionlist versionlist versionremove versionremove <version>|<label> versionremoveall versionremoveall versionrestore versionrestore <version>|<label> [<true|false>] versiontree versiontree [<levels>] ---------------------------------------------------------------------------------------------------------------- Command completed in 27 msecs. jcr-shell:>
You can execute help <command> to see the detail of the specific command like the following example:
jcr-shell:> help pwd Usage: pwd Show path to current node Command completed in 0 msecs.
In this section, let's try to change a property value and save it, as an example.
jcr-shell:> cd /webfiles/site done. Command completed in 879 msecs. admin:/webfiles/site> proplist ---------------------------------------------------------------------------------------------------------------- Name Type Value ---------------------------------------------------------------------------------------------------------------- jcr:primaryType Name webfiles:bundle webfiles:anticache String<PHONE_NUMBER>692 ---------------------------------------------------------------------------------------------------------------- Command completed in 55 msecs. admin:/webfiles/site> propset webfiles:anticache<PHONE_NUMBER>694 Command completed in 0 msecs. admin:/webfiles/site> propget webfiles:anticache<PHONE_NUMBER>694 Command completed in 25 msecs. admin:/webfiles/site> save Node saved. Command completed in 31 msecs. jcr-shell:> quit Bye bye!
The jexl command allows you to execute a JEXL script file for more advanced use cases.
The following variables are provided to JEXL script files:
| Variable | Description |
|---|---|
| arguments | The command line arguments passed to the JEXL script. The first argument is the file path of the JEXL script, followed by other arguments for the JEXL script. For example, if you run > jexl test.jexl 1 2 3, then the arguments variable will look like [ "test.jexl", "1", "2", "3" ]. |
| out | The output console, providing #println(CharSequence) method for JEXL scripts |
| node | The JCR node you are currently based on in the shell. |
Here's a very simple JEXL script file example:
// ~/temp/test.jexl var nu = new("org.apache.commons.lang3.math.NumberUtils"); var sum = 0; for (arg : arguments) { // 0 on parsing error as the first arg item is actually the jexl script file name. sum += nu.toInt(arg, 0); } out.println("sum = " + sum); out.println("You're currently on " + node.path + "."); return "Optional return value to show after execution: Hello!";
Then you can execute the JEXL script file like this:
admin:/> cd content/documents admin:...nt/documents> jexl ~/temp/test.jexl 1 2 3 4 5 6 7 8 9 sum = 45 You're currently on /content/documents. JEXL script executed. Return: Optional return value to show after execution: Hello! Command completed in 3 msecs.
For more information about the JEXL syntax, see JEXL Syntax page.
If you need to depend on any additional JAR files, not included in the jcrshell-x.x.x.jar by default, you can use Spring Boot's loader.path system property to add any extra JARs to the classpath.
For example, the following will add all the JAR files found in lib/ directory when executing the JCR Shell:
$ java -Dloader.path="lib/" \ -jar jcrshell-2.0.0.jar \ --server="http://localhost:8080/cms/server" \ --user="admin:admin"
You can execute a batch file containing one or multiple lines of each command explained above as well by specifying --batch argument like the following example:
$ java -jar jcrshell-2.0.0.jar --server="http://localhost:8080/cms/server" --user="admin:admin" --batch="test.sh" . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.0.4.RELEASE) JCR Shell 2.0.0 ...
If you specify a batch file by --batch argument, then JCR Shell will read all the non-blank lines from the file except of comment lines.
If a line in a batch file starts with "#", the line is regarded as a comment.


Richard's To-do List
2 November 2015
Buy groceries
Vacuum the floor
Wash the car
Call the plumber
Feed the dog