Get paid to do a handful of simple activities such as clicking links, reading ads and signing up for websites. We pay you competitively for each of these things which means maximum profit for your time!
We strive to offer our advertisers the best of the best advertising methods! With our specialized anti-cheat system and a large member base, you can be sure that with Clicksia you get the most out of your advertising dollars.
If you need something done fast and by a lot of people, Clicksia's offers service will help you accomplish that, we connect you with our members and give you the tools necessary to get granted results.
Clicksia is an international service, we have members from over 190 different countries. It doesn't matter if you live in The United States, Brazil, or India: you can start earning with Clicksia today!
Our premium advertising services present an excellent opportunity for you to get valuable traffic to your site at very affordable and competitive pricing. As any internet businessperson will tell you, quality traffic equates to quality leads and customers.
Here in the world of Clicksia, you can earn an extra stream of income by completing simple tasks; We have advertisers that will pay you real cash money to simply view their websites, and other advertisers will pay you even more to join their various programs!


Weight scheme setup¶
Using the Rim
class¶
The Rim
object’s purpose is to define the required setup of the weighting process, i.e. the weight scheme that should be used to compute the actual factor results per case in the dataset. While its main purpose is to provide a simple interface to structure weight schemes of all complexities, it also offers advanced options that control the underlying weighting algorithm itself and thus might impact the results.
To start working with a Rim
object, we only need to think of a name for our scheme:
>>> scheme = qp.Rim('my_first_scheme')
Target distributions¶
A major and (probably the most important) step in specifying a weight scheme
is mapping the desired target population proportions to the categories of the related variables inside the data. This is done via a dict
mapping.
For example, to equally weight female and male respondents in our sample, we simply define:
>>> gender_targets = {}
>>> gender_targets['gender'] = {1: 50.0, 2: 50.0}
>>> gender_targets
{'gender': {1: 50.0, 2: 50.0}}
Since we are normally dealing with multiple variables at once, we collect
them in a list
, adding other variables naturally in the same way:
>>> dataset.band('age', [(19, 25), (26-35), (36, 49)])
>>> age_targets = {'age_banded': {1: 45.0, 2: 29.78, 3: 25.22}}
>>> all_targets = [gender_targets, age_targets]
The set_targets()
method can now use the all_targets
list to apply the target distributions to the Rim
weight scheme setup (we are also providing an optional name for our group of variables) .
>>> scheme.set_targets(targets=all_targets, group_name='basic weights')
The Rim
instance also allows inspecting these targets from itself now (you can
see the group_name
parameter reflected here, it would fall back to
'_default_name_'
if none was provided):
>>> scheme.groups['basic weights']['targets']
[{'gender': {1: 50.0, 2: 50.0}}, {'age_banded': {1: 45.0, 2: 29.78, 3: 25.22}}]
Weight groups and filters¶
For more elaborate weight schemes, we are instead using the add_group()
method
which is effectively a generalized version of set_targets()
that supports
addressing subsets of the data by filtering. For example, differing target distributions (or even the scheme defining variables of interest) might be
required across several market segments or between survey periods.
We can illustrate this using the variable 'Wave'
from the dataset:
>>> dataset.crosstab('Wave', text=True, pct=True)
Question Wave. Wave
Values @
Question Values
Wave. Wave All 100.0
Wave 1 19.6
Wave 2 20.2
Wave 3 20.5
Wave 4 19.8
Wave 5 19.9
Let’s assume we want to use the original targets for the first three waves but the remaining two waves need to reflect some changes in both gender and the age distributions. We first define a new set of targets that should apply only to the waves 4 and 5:
gender_targets_2 = {'gender': {1: 30.0, 2: 70.0}}
age_targets_2 = {'age_banded': {1: 35.4, 2: 60.91, 3: 3.69}}
all_targets_2 = [gender_targets_2, age_targets_2]
We then set the filter expressions for the respective subsets of the data, as per:
>>> filter_wave1 = 'Wave == 1'
>>> filter_wave2 = 'Wave == 2'
>>> filter_wave3 = 'Wave == 3'
>>> filter_wave4 = 'Wave == 4'
>>> filter_wave5 = 'Wave == 5'
And add our weight specifications accordingly:
>>> scheme = qp.Rim('my_complex_scheme')
>>> scheme.add_group(name='wave 1', filter_def=filter_wave1, targets=all_targets)
>>> scheme.add_group(name='wave 2', filter_def=filter_wave2, targets=all_targets)
>>> scheme.add_group(name='wave 3', filter_def=filter_wave3, targets=all_targets)
>>> scheme.add_group(name='wave 4', filter_def=filter_wave4, targets=all_targets_2)
>>> scheme.add_group(name='wave 5', filter_def=filter_wave5, targets=all_targets_2)
Note
For historical reasons, the logic operators currently do not work within the Rim
module. This means that all filter definitions need to be valid
string expressions suitable for the pandas.DataFrame.query()
method.
We are planning to abandon this limitation as soon as possible to enable
easier and more complex filters that are consistent with the rest of the library.
Setting group targets¶
At this stage it might also be needed to balance out the survey waves themselves in a certain way, e.g. make each wave count exactly the same (as you can see above each wave accounts for roughly 20% of the full sample but not quite exactly).
With Rim.group_targets()
we can apply an outer weighting to the between
group distribution while keeping the already set inner target proportions within each of them. Again we are using a dict
, this time mapping the
group names from above to the desired outcome percentages:
>>> group_targets = {'wave 1': 20.0,
... 'wave 2': 20.0,
... 'wave 3': 20.0,
... 'wave 4': 20.0,
... 'wave 5': 20.0}
>>> scheme.group_targets(group_targets)
To sum it up: Our weight scheme consists of five groups based on 'Wave'
that
resp. need to match two different sets of target distributions on the 'gender'
and 'age_banded'
variables with each group coming out as 20% of the full sample.
Integration within DataSet
¶
The computational core of the weighting algorithm is the
quantipy.core.weights.rim.Rake
class which can be accessed by working
with qp.WeightEngine()
, but it is much easier to directly use the DataSet.weight()
method. Its full signature looks as follows:
DataSet.weight(weight_scheme,
weight_name='weight',
unique_key='identity',
subset=None,
report=True,
path_report=None,
inplace=True,
verbose=True)
Weighting and weighted aggregations¶
As can been seen, we can simply provide our weight scheme Rim
instance to
the method. Since the dataset already contains a variable called 'weight'
(and we do not want to overwrite that one) we set weight_name
to be
'weights_new'
. We also need to set unique_key='unique_id'
as that is our
identifying key variable (that is needed to map the weight factors back into our
dataset):
>>> dataset.weight(scheme, weight_name='weights_new', unique_key='unique_id')
Before we take a look at the report that is printed (because of report=True
),
we want to manually check our results. For that, we can simply analyze some cross-
tabulations, weighted by our new weights! For a start, we check if we arrived at
the desired proportions for 'gender'
and 'age_banded'
per 'Wave'
:
>>> dataset.crosstab(x='gender', y='Wave', w='weights_new', pct=True)
Question Wave. Wave
Values All Wave 1 Wave 2 Wave 3 Wave 4 Wave 5
Question Values
gender. What is your gender? All 100.0 100.0 100.0 100.0 100.0 100.0
Male 42.0 50.0 50.0 50.0 30.0 30.0
Female 58.0 50.0 50.0 50.0 70.0 70.0
>>> dataset.crosstab(x='age_banded', y='Wave', w='weights_new', pct=True,
... decimals=2)
Question Wave. Wave
Values All Wave 1 Wave 2 Wave 3 Wave 4 Wave 5
Question Values
age_banded. Age All 100.00 100.00 100.00 100.00 100.00 100.00
19-25 41.16 45.00 45.00 45.00 35.40 35.40
26-35 42.23 29.78 29.78 29.78 60.91 60.91
36-49 16.61 25.22 25.22 25.22 3.69 3.69
Both results accurately reflect the desired proportions from our scheme. And we
can also verify the weighted distribution of 'Wave'
, now completely
balanced:
>>> dataset.crosstab(x='Wave', w='weights_new', pct=True)
Question Wave. Wave
Values @
Question Values
Wave. Wave All 100.0
Wave 1 20.0
Wave 2 20.0
Wave 3 20.0
Wave 4 20.0
Wave 5 20.0
The isolated weight dataframe¶
By default, the weighting operates inplace
, i.e. the weight vector will
be placed into the DataSet
instance as a regular columns
element:
>>> dataset.meta('weights_new')
float
weights_new: my_first_scheme weights N/A
>>> dataset['weights_new'].head()
unique_id weights_new
0 402891 0.885593
1 27541022 1.941677
2 335506 0.984491
3 22885610 1.282057
4 229122 0.593834
It is also possible to return a new pd.DataFrame
that contains all relevant Rim
scheme variables incl. the factor vector for external use cases or further
analysis:
>>> wdf = dataset.weight(scheme, weight_name='weights_new', unique_key='unique_id',
inplace=False)
>>> wdf.head()
unique_id gender age_banded weights_new Wave
0 402891 1 1.0 0.885593 4
1 27541022 2 1.0 1.941677 1
2 335506 1 2.0 0.984491 3
3 22885610 1 2.0 1.282057 5
4 229122 1 3.0 0.593834 1


Welcome to part 4 guys! Where it all comes together! The intricate puzzle pieces we've carefully jigsawed will finally snap into place, revealing the glorious picture which is your very first ensemble-based game. Let's get started!
First things first -- let's load up that social schema package we worked so hard on in Part 3! We'll be doing this with a series of calls to ensemble functions that take the .json files of your schema as parameters. First, you'll want to load in your schema file itself (that defines your categories and types), as ensemble will use it to help with the validation of your other files. This should all be in your html file, right after your call to ensemble.init() (reprinted here for convenience). So, something like this:
//Init ensemble var loadResult = ensemble.init(); console.log(loadResult); var rawSchema = ensemble.loadFile("data/schema.json"); var schema = ensemble.loadSocialStructure(rawSchema);
And there you go, your schema file is loaded! The path provided to schema.json should be relative to the location of the html file your game lives in. ensemble now understands all of the categories and types that compose the social structure of your game, and consequently will express concern if you load up rules or history that are not aligned with the structure you've defined. And don't worry: even though we're storing the schema in the schema variable, we won't need to use it directly as ensemble now has everything it needs internally, at least with regards to social structure.
What ensemble *doesn't* have is understanding of the cast, rules, actions, and history of your game. Let's take care of that, pronto!
var rawCast = ensemble.loadFile("data/cast.json"); var cast = ensemble.addCharacters(rawCast); var rawTriggerRules = ensemble.loadFile("data/triggerRules.json"); var triggerRules = ensemble.addRules(rawTriggerRules); var rawVolitionRules = ensemble.loadFile("data/volitionRules.json"); var volitionRules = ensemble.addRules(rawVolitionRules); var rawActions = ensemble.loadFile("data/actions.json"); var actions = ensemble.addActions(rawActions); var rawHistory = ensemble.loadFile("data/history.json"); var history = ensemble.addHistory(rawHistory);
We'll actually be using the cast variable later on, so holding on to that is a good idea!
Next, we'll be setting up some initial game state with a couple of calls to functions that we'll soon be writing in loversAndRivals.js
//Set up our initial state setUpLoversAndRivalsInitialState();
As you may recall, most of our initial state is actually defined in our history file, so we don't have too much 'assigning' of state to do right here. Instead, setUpLoversAndRivalsInitialState will simply take that initial state we've specified in the history file and use it to fill in all those NA values we currently have in our game.
var setUpLoversAndRivalsInitialState = function(){ //update our local copies of these variables, and display them. updateLocalStateInformation(); displayStateInformation(); };
We see here that this function is just a wrapper for two other functions, updateLocalStateInformation() and displayStateInformation(). Let's take the time to talk about both of these guys for a little bit.
updateLocalStateInformation() asks ensemble several questions about the current social state, and then stores the answers in a local variable for ease of access. The questions it asks are along the lines of "what is the current attraction value from the hero to the love" or "what is the hero's current intelligence value?" The way it asks these questions is by passing in predicate variables into ensemble's "get" function, like so:
var updateLocalStateInformation = function(){ //First, let's grab the data we'll want to display. var loveToHeroClosenessPred = { "category" : "feeling", "type" : "closeness", "first" : "love", "second" : "hero" }; //Get love to hero closeness. var results = ensemble.get(loveToHeroClosenessPred); stateInformation.loveToHeroCloseness = results[0].value;
In the above example, we have our predicate, "heroToLoveClosenessPred" -- as with other predicates that we've seen before, it specifies a category ("feeling"), and the specific type within that category ("closeness"), as well as a first and a second. In english, this predicate could be thought to express "what is the value of the love's closeness feeling for the hero?" Once we've formed the predicate, we pass it into ensemble.get. You may be asking "well, wait a second. We've defined other predicates in the past, say inside of history.json, that also had to specify a value. Why is that missing here?" That is an astute observaton, dear reader, and it all ties in with how ensemble.get works.
ensemble.get takes in a predicate, and returns an array of predicates. The predicate it takes in can be a fully specified predicate (i.e., it has category, type, first, second, and value defined), or it can be missing any of those fields. Regardless of how well specified it is, the passed in predicate is checked against the social record (i.e., the current social state, as well as the complete social history of the game) and the function returns a copy of all social record predicates that match the specified fields of the passed in predicate. By default it only looks at the current time step of the social record (i.e., it doesn't look at the history, only the present moment), but additional parameters can be passed in to expres how far back into the history you'd like your search to encompass.
So, here, by passing in this predicate, it will return an array of all predicates that pertain to the love's closeness feelings for the hero, regardless of the value. Fortunately for us, there should only be one such predicate, for as this value changes through gameplay, ensemble doesn't create new entries in the social record, it simply updates existing ones. Thus, we check with confidence the first entry in the array, and since we are interested in the value, that is the field that we check. Finally, we store it in the appropriate field of our stateInformation variable which we created way back when in section 2.
Phew! A lot of information for a small function, but now you know that much more about how ensemble works. The above was just a piece of the updateLocalStateInformation() function, but now that you understand that one part the rest should hopefully be fairly easy to piece together! Here's the whole thing!
var updateLocalStateInformation = function(){ //First, let's grab the data we'll want to display. var loveToHeroClosenessPred = { "category" : "feeling", "type" : "closeness", "first" : "love", "second" : "hero" }; var loveToRivalClosenessPred = { "category" : "feeling", "type" : "closeness", "first" : "love", "second" : "rival" }; var heroToLoveClosenessPred = { "category" : "feeling", "type" : "closeness", "first" : "hero", "second" : "love" }; var loveToHeroAttractionPred = { "category" : "feeling", "type" : "attraction", "first" : "love", "second" : "hero" }; var heroToLoveattractionPred = { "category" : "feeling", "type" : "attraction", "first" : "hero", "second" : "love" }; var loveToRivalAttractionPred = { "category" : "feeling", "type" : "attraction", "first" : "love", "second" : "rival" }; var heroIntelligencePred = { "category" : "attribute", "type" : "intelligence", "first" : "hero" }; var heroStrengthPred = { "category" : "attribute", "type" : "strength", "first" : "hero" }; //Get love to hero closeness. var results = ensemble.get(loveToHeroClosenessPred); stateInformation.loveToHeroCloseness = results[0].value; //Get love to rival closeness results = ensemble.get(loveToRivalClosenessPred); stateInformation.loveToRivalCloseness= results[0].value; //Get hero to Love closeness results = ensemble.get(heroToLoveClosenessPred); stateInformation.heroToLoveCloseness = results[0].value; //get love to hero attraction results = ensemble.get(loveToHeroAttractionPred); stateInformation.loveToHeroAttraction = results[0].value; //get love to rival attraction results = ensemble.get(loveToRivalAttractionPred); stateInformation.loveToRivalAttraction = results[0].value; //get hero to love attraction results = ensemble.get(heroToLoveattractionPred); stateInformation.heroToLoveAttraction = results[0].value; //get hero intelligence. results = ensemble.get(heroIntelligencePred); stateInformation.heroIntelligence = results[0].value; //get hero strength. results = ensemble.get(heroStrengthPred); stateInformation.heroStrength = results[0].value; };
Now that we have all this great information, what are we going to do with it? Well, this is where displayStateInformation() comes into play! Essentially, what this function does is find html elements defined in the html file, and changes their value to whatever was stored inside of ensemble's social record. This funciton is fairly short, so we'll give it to you all at once:
var displayStateInformation = function(){ document.getElementById("closenessHeroToLoverNumber").innerHTML = stateInformation.heroToLoveCloseness; document.getElementById("closenessLoverToHeroNumber").innerHTML = stateInformation.loveToHeroCloseness; document.getElementById("closenessLoverToRivalNumber").innerHTML = stateInformation.loveToRivalCloseness; document.getElementById("attractionHeroToLoverNumber").innerHTML = stateInformation.heroToLoveAttraction; document.getElementById("attractionLoverToHeroNumber").innerHTML = stateInformation.loveToHeroAttraction; document.getElementById("attractionLoverToRivalNumber").innerHTML = stateInformation.loveToRivalAttraction; document.getElementById("heroStrengthNumber").innerHTML = stateInformation.heroStrength; document.getElementById("heroIntelligenceNumber").innerHTML = stateInformation.heroIntelligence; };
So, you remember in our html file, we had all of those "NAs"? Well, no more! Now that we have this in place, those place holder values should now be filled in with actual data from ensemble! How exciting!
As a brief aside, we have a small bit of irony here worth pointing out. We're using document.getElementById(ID_OF_ELEMENT) to find our html components here. However, if you haven't heard about jQuery then you should check it our right away (as soon as you'll done with this tutorial, of course!). We're not using it in this project to keep you from only having to learn one new javascript library, BUT as anyone whose used jQuery will testify, using jQuery is actually much simpler than not using it!
But back to ensemble!
If you've been following along at home, then your version of Lovers And Rivals should look a little something like this...
That is to say, not altogether too different from how we last saw it beyond those lovely, georgeous 0s taking the place of the NAs of yesteryear. Next, let's get our three characters to take their proper positions on the field. We'll start by adding a line to our html file just under our call to initializing the game state.
setupCharacterPositions(500);
setupCharacterPositions will place our three characters at different places in the field, so they aren't all standing on top of each other. The 500 we pass in is just a parameter that makes it look nice with the width of the field being what it is. You can adjust it if you like, it doesn't really matter.
The function itself gets defined in the javascript file. We'll break it down here piece by piece.
var setupCharacterPositions = function(widthOfField){ var hero = document.getElementById("hero"); var love = document.getElementById("love"); var rival = document.getElementById("rival");
First thing we do is grab the html component that represents the three characters (i.e., the div tags that house our 0\ and @.o people).
//Get love to hero closeness. var loveToHeroCloseness = stateInformation.loveToHeroCloseness; //Get love to rival closeness var loveToRivalCloseness = stateInformation.loveToRivalCloseness; //Get hero to Love closeness var heroToLoveCloseness = stateInformation.heroToLoveCloseness; //store the width of field information stateInformation.widthOfField = widthOfField;
We then grab some pertinent information from our local stateInformation variable that we've set up, as well as store the passed in 'width of field' parameter for future calculations.
//Actually reposition the characters based on their closeness values. //The love's position is an amalgamation of things. var lovePosition = (widthOfField/2) + loveToRivalCloseness - loveToHeroCloseness; // starts in middle, pulled in both directions.
This game is all about the affections of the love drawing them closer to the rival and the hero, using physical distance to represent the leanings of the love's heart. But to start, we want the love to be right in the middle of the two suitors, thus, we do a little bit of math to find where the love should be standing.
hero.style.left = heroToLoveCloseness + 'px'; love.style.left = lovePosition + "px"; rival.style.left = widthOfField + "px"; // rival never moves. };
Finally, we actually position the characters based on the values we determined; the hero is positioned based solely on their closeness to the love, the love is positioned based on what we just calculated above, and the rival is just plopped on the far right hand side of the field, never moving. If you're totally offput by setting these positions by setting an int and the string 'px' to the left field, well, I'm sorry. You are more than welcome to switch over to using jQuery on your own time.
Ok, great! With that in place, your characters should finally stop standing on top of each other!
Now we're finally ready to get into the main game loop. The main game loop is going to look something like this:
var storedVolitions = ensemble.calculateVolition(cast);
This tiny little line is actually doing quite a bit of heavy lifting. It's taking the current social state and social history (at present, only what you've defined in your history file), and running it against all of the volition rules you wrote back in part 3 to determine what the characters want to do with each other. At this point though, the volitions are *solely* in the form of volitions, such as 'raise strength' and 'increase closeness.' If we want to translate these volitions into actual actions (such as "do pushups" or "invite to movies"), we're gonna have to do a tiny bit more work.
Namely, to get our actions we'll call a function tailored specifically for Lovers and Rivals.
populateActionLists(storedVolitions, cast);populateActionLists, defined in the js file, is actually pretty straightforward, as its just a wrapper function for a few calls to populateActionList (singular)
//Fills in all of the actionList divs with buttons corresponding to the actions the player can take //by calling individual instances of populateActionList var populateActionLists = function(storedVolitions, cast){ //populate the action list of hero to love: populateActionList("hero", "love", storedVolitions, cast); populateActionList("hero", "rival", storedVolitions, cast); populateActionList("hero", "hero", storedVolitions, cast); };
As you can see, for each one of these calls, we pass in two characters, the volitions we calculated, and the cast. We always pass in the hero as the first character because in Lovers and Rivals, all of the actions are done through the hero's perspective (though you could easily make a game where the love or the rival could take actions as well!) Lets take a look at the function that actually populates the action list!
//Fills the actionList div with buttons corresponding to the actions the player can take. var populateActionList = function(initiator, responder, storedVolitions, cast){ var char1 = initiator; var char2 = responder; var possibleActions = ensemble.getActions(char1, char2, storedVolitions, cast, gameVariables.numIntents, gameVariables.numActionsPerIntent);
We see from the parameters of this function that the first character passed in will be the initiator (stored in the local variable char1), and the second character will be the responder. We then figure out the actions that the initiator wants to take towards the responder with a call to ensemble.getActions, the two chars, storedVolitions, and cast arguments should be pretty familiar, but what about those last two parameters? Well, gameVariables is referring to a variable defined at the top of the javascript file. numIntents is refers to the number of distinct intents we want to see actions for, and numActionsPerIntent is the maximum number of actions to return for any given intent.
But just like the seemingly innocent looking ensemble.calculateVolitions, ensemble.getActions has returned an array of everything that the initiator wants to towards the responder, given the constraints of the parameters passed in to the function.
var divName = "actionList_" + char1 + "_" + char2; var actionList = document.getElementById(divName);
Because this function is used for different pairs of characters, we need to do a smidgen of string manipulation in order to get the html element that refers to the proper action list (i.e., is this the div where the hero's actions towards the love will go? Or the hero towards themselves?).
//Let's make a button for each action the hero wants to take! for(var i = 0; i < possibleActions.length; i += 1){ //Make a new button var action = possibleActions[i]; //If the character doesn't have a strong volition to do this action, //don't include it in the action list. if(action.weight < 0){ continue; } var buttonnode= document.createElement('input'); buttonnode.setAttribute('type','button'); buttonnode.setAttribute('name',action); buttonnode.setAttribute('value',action.displayName); buttonnode.actionToPerform = action; buttonnode.cast = cast; buttonnode.onclick = actionButtonClicked; actionList.appendChild(buttonnode); }
So we've figured out our array of actions. Now all that we need do is loop through them and create buttons for them that the user can click on. For each action in possibleActions, we store it in a temporary variable, do a quick check on its weight to make sure that it is positive (and, thus, something that the character actually wants to do towards the responder), and then we actually create the button! The calls to buttonnode.setAttribute is just doing things like identifying it *as* a button, and setting the text of the button itself. But we can also add whatever additional properties we want. As we'll find, it'll actually be pretty convenient for us to add both the cast and the action to the button itself.
We'll also give the button a function for its onclick event: actionButtonClicked. We'll discuss it in depth as soon as we're done with this function, but suffice it to say, its the function that gets called whenever this button gets clicked on. And finally, we add the button that we just made to the actionList div through the call to actionList.appendChild.
//Write a little message if there were no possible actions. if(actionList.innerHTML === ""){ actionList.innerHTML = "No Actions Available"; } };
After the for loop, if there weren't any actions available, we'll add a little note saying that there were no available actions for that specific initiator-responder pair.
Okay, I said we'd be taking a look at actionButtonClicked and I wasn't lying to you! This function gets called whenever, surprise surprise, an action button is clicked, and is defined in the javascript file. This function is a bit of a doozy, and makes several calls to other functions, which we'll describe AS we see them.
var actionButtonClicked = function(){ //Clean away all of the other actions -- they made their choice! clearActionList();
We start by cleaning out the action list. Don't worry, it'll come back eventually! Essentially, all this function is doing is making the whole area of the screen where actions are presented hidden (i.e., making them not show up), and then removing their contents by setting the property of their innerHTML field to the empty string.
var clearActionList = function(){ //We're first going to make the entire action list disappear var actionArea = document.getElementById("actionArea"); actionArea.style.visibility = "hidden"; //Now we're actually going to remove the actions from the actionLists, because with the new socialState, //characters will likely want to take new actions towards each other. var heroToLoveActionList = document.getElementById("actionList_hero_love"); heroToLoveActionList.innerHTML = ""; var heroToRivalActionList = document.getElementById("actionList_hero_rival"); heroToRivalActionList.innerHTML = ""; var heroToHeroActionList = document.getElementById("actionList_hero_hero"); heroToHeroActionList.innerHTML = ""; };
Jumping back to actionButtonClicked -- We also want to change the social state basic on the action that the player selected. This is why we wanted to attach the action to the button itself; for the action has all of the effects (bound with the correct characters) that need to be added to the social record!
//CHANGE THE SOCIAL STATE -- social physics baby!!! var effects = this.actionToPerform.effects; // should be an array of effects. for(var i = 0; i < effects.length; i += 1){ ensemble.set(effects[i]); }
Above, we're simply looping through the effects array (which will be an array of predicates) of the action that was stored in the button ("this", in this context, refers to the button pressed), and passing each effect into ensemble.set. ensemble.set is kind of the sister function of ensemble.get. While ensemble.get returns predicates that represent the current state of the social record, ensemble.set takes a predicate and either adds it to the record as a new social fact, or uses it to update an existing one, as appropriate.
Okay, we're doing well! Moving right along, we'll add this line...
//RUN SOME TRIGGER RULES based on the new state! ensemble.runTriggerRules(this.cast);
So now that we've updated the social state, its time to run our trigger rules! You remember trigger rules, right? They're the guys that check the social record to see if something new should be enacted, like, automatically lowering the closeness of people who engaged in self-involved activity. Well, running them as simple as the above line!
You may be asking yourself, "why do we have to pass the entire cast in each time?" Well, the reason is that you might not *want* to use the entire cast all the time. You can imagine a game that has multiple levels, and only a subset of your entire cast appears on each level. It might not make sense to have characters that are "off stage" forming volition and being affected by trigger rules, so ensemble gives you the ability to specify the cast of characters to use.
Moving on! Let's add a note letting the player know if the action was accepted or rejected.
//Print out if the action was 'accepted' or rejected! var statusArea = document.getElementById("statusMessage"); var acceptMessage = this.actionToPerform.displayName + " successful!"; if(this.actionToPerform.isAccept !== undefined && this.actionToPerform.isAccept === false){ acceptMessage = this.actionToPerform.displayName + " failed!"; } statusArea.innerHTML = acceptMessage;
We find ourselves once again wielding our mastery over grabbing html elements by id, here the statusMessage div. Each action has the field "isAccept" defined -- a boolean which if true means that the spirit of the action was accepted by the responder, and false if otherwise. Whether the responder accepts or rejects is determined by the volition rules written, plus any action specific influence rules that might be present. Also, though every action *should* have isAccept defined for clarity, if it is left unspecified ensemble assumes the action to be an 'isAccept' action.
Next, we'll be updating some local state information, as well as moving the characters to their new positions.
//Re-draw the people (maybe even by having them MOVE to their new positions...) //Also re-draw any debug/state informaton we want. updateLocalStateInformation(); displayStateInformation(); moveAllCharacters();Our old friends, updateLocalStateInformation() and displayStateInformation() need no introduction. However, the new addition to the party, moveAllCharacters() deserves a warm welcome. This function is going to handle the totally sweet (if somewhat minimal) animation we have in our game.
var moveAllCharacters = function() { console.log("inside of moveAllCharacters"); //Takes a little bit of computation! var loveDestination = (stateInformation.widthOfField/2 - stateInformation.loveToHeroCloseness*1.5 + stateInformation.loveToRivalCloseness*2.5); moveByCharacterName("hero", stateInformation.heroToLoveCloseness); moveByCharacterName("love", loveDestination); };
Okay okay fine, you caught us. We've got another wrapper function here that makes a couple calls to moveByCharacterName(), which I suppose is the real star here. We also do a little bit of math to figure out where the love wants to move, as a function of their current feelings for the hero and for the rival. Diving deeper into moveByCharacterName...
var moveByCharacterName = function(name, destination){ var elem = document.getElementById(name); var startPos = parseInt(elem.style.left, 10); // start off with their current left position. var currentPos = startPos; function frame() { if(startPos > destination){ // we are moving backwards. console.log("decrementing..."); currentPos -= 1; } else if (startPos < destination){ // we are moving forwards. currentPos += 1; console.log("incrementing..."); } elem.style.left = currentPos + 'px'; if (currentPos == destination) { clearInterval(id); } } var id = setInterval(frame, 10); // draw every 10ms };
The basic premise here is very similar to that temporary move function we wrote together back in Part 2. We get the html element representing the character we care about through their name, and figure out their starting position by looking at that element's "left" value. At the bottom of the function, we set up an interval, specifying a function to be called every 10 milleseconds, the "frame" function. The frame function is defined just above the call to setInterval. It essentially checks to see if the character's destination is less than or greater than their current position, and increments or decrements their current position accordingly, ultimately assigning it to their left attribute. Finally, if the currentPos is equal to the destination (i.e., they have reached their destination), then we clear the interval, ending the every-10ms-call to the frame function.
How you holding up? We're gonna jump back to actionButtonClicked() to finish it up, and then we'll be able to come back up for air, I promise.
//set up next turn. var event = document.createEvent('Event'); event.initEvent('nextTurn', true, true); document.dispatchEvent(event); };
The final thing we do in this function is create a new event object, which we call 'nextTurn', and dispatch it. This will allow other parts of the html document to understand that ensemble has finished updating the social record, running trigger rules, and animating the characters. We'll take a look at this in just a minute, but first, lets check out a couple of screen shots of how your game should be looking.
When you first load up the game, it should look like the above, with a collection of lovely actions for you to select from! And if you were to, say, select "study math" then you should be greeted by something that looks like this...
The hero should stay in place because they holed up in their room studying math, and the love, disappointed by the hero's self-involved behavior, will have moved closer to the rival (thanks to one of our trigger rules!). The status area should also have updated, letting us know that our attempts to study math were a rousing success! Good for us! Plus, if you scroll down your game a little, you'll see that all that studying has really paid off, increasing our hero's intelligence!
We've made great progress, but we're not done yet! For one thing, after selecting that single action, no more actions pop up for us to pick! This means that the hero's quest to win the affections is all for naught, unless.... unless... we give the hero the ability to take additional turns! And this is where that event we launched back in actionButtonClicked comes into play!
To take advantage of the dispatched event, add this line to your html file under your call to populateActionLists():
document.addEventListener("nextTurn", nextTurn);
Pretty easy, huh! All this is saying is that when we hear the "nextTurn" event (which you'll remember is the name we gave the custom event we dispatched), then we should call the nextTurn() function, which we haven't actually defined yet. So let's define it now! And let us define this function in our html file, just above our added event listener.
var nextTurn = function(){ gameVariables.turnNumber += 1; checkForEndConditions(); if(gameVariables.gameOver === true){ var endMessageArea = document.getElementById("statusMessage"); endMessageArea.innerHTML = gameVariables.endingText; }
The first thing we do is increment the turnNumber stored in our gameVariables array. We then call checkForEndConditions(), which checks to see if the game should be over; if so, we update the statusMessage to have the appropriate game over text (either "you win!" or "you lose!" as appropriate) Taking a brief aside to look at what is inside of checkForEndConditions, we see we have...
//Checks to see if the game is over! var checkForEndConditions = function(){ if(stateInformation.loveToRivalCloseness >= 90){ //uh oh, we lose! gameVariables.gameOver = true; gameVariables.endingText = "Game Over! Your Love is in the arms of your Rival!"; } if(stateInformation.loveToHeroCloseness >= 90 && stateInformation.heroToLoveCloseness >= 90){ gameVariables.gameOver = true; gameVariables.endingText = "Game Over! Your Love is sufficiently interested in you for you to feel good about yourself!"; } };
All this function does is checks to see the love's closeness value to the rival -- if 90 or greater, then you lose, the love loves the rival too much for you to ever have a chance! Conversely, if the love's closeness to the hero is 90 or more, AND the hero's closeness to the love is ALSO 90 or more, well, that's a whole 'nother story--in that case you win! Hooray!
We return to your regularly scheduled nextTurn(), already in progress.
else{ ensemble.setupNextTimeStep(); storedVolitions = ensemble.calculateVolition(cast); populateActionLists(storedVolitions, cast); cleanUpUIForNewTurn(); } };
We get inside of this else block if the game's ending conditions have not yet been met. The first thing we do is make a call to ensemble.setupNextTimeStep() -- this let's ensemble know that we're moving forward in time by advancing a step forward in the social record. This current time step is up for modification through future actions and trigger rules, but the results of the previous turn (namely that the hero's intelligence went up a little, and that the love's closeness for the rival increased) are etched into the social record as having happened at time step 0. Those same values can (and likely will) change at time step 1, 2, 3, etc., but turn 0 is in the past and untouchable!
ensemble.calculateVolition and populateActionLists are more old friends come back again; We re-calculate the volitions of the characters now that the social state has changed (e.g., now that the hero is more intelligent, maybe there are new, different things that they want to do!). Once the new volitions are formed, populateActionLists takes those volitions and translates them into the buttons that the player can click on to perform an action!
And last, but certainly not least, we call cleanUpUIForNewTurn() We'll define this bad boy back in our javascript file.
var cleanUpUIForNewTurn = function(){ var actionArea = document.getElementById("actionArea"); actionArea.style.visibility = "visible"; var turnNumberArea = document.getElementById("turnNumberPlace"); turnNumberArea.innerHTML = gameVariables.turnNumber; };
All we're doing here is making the action buttons visible again (we hid them earlier), and updating the turn number in the UI.
And with that, we're done! Try playing the game you just created and see if you can win the heart of your love!
We hope you enjoyed this tutorial! You should now have everything you need to start making ensemble games of your very own! We admit, it took a little bit of work to set everything up for this simple (though no less awesome for its simplicity) game. BUT, now that you have everything in place, adding new rules, actions, and social considerations is a snap! Lovers and Rivals already has smidges of procedural rhetoric embedded in it (studying anatomy is purely better than studying math in this game, for example! People want to be kissed after you write them a few love notes!), but you could alter it to purport a world view that you actually believe in.
In short, though using ensemble takes a bit of ramping up, we believe that it facilitates the creation of gameplay experiences untenable to create through other means. So please, let your imagination run rampant and create works of social-based gameplay hithertofore unseen! We know you can do it!
I mean, heck, if a \o/ can find true love, then anything is possible!


The OpenCV toolkit for IBM Streams depends upon the OpenCV (Open Computer Vision) library, which depends upon the FFmpeg (Fast Forward MPEG) library, which depends upon several other libraries. The toolkit must be installed on the machine where applications will be developed. The libraries must be installed on each machine where applications will be developed or executed.
This section contains instructions for installing several libraries from RHEL or CentOS repositories, then building the FFmpeg and OpenCV libraries from source code, and then finally building the toolkit.
Note: The libraries the toolkit depends upon are covered by a variety of ’open source’ licenses. You should read the license files and check with your legal department before downloading them to ensure you comply with their terms.
The OpenCV toolkit should work on any machine that supports IBM Streams. It has been tested with this environment:
RHEL or CentOS (64-bit), version 7.1
FFmpeg library, version 3.0.1
OpenCV library, version 3.1.0
IBM Streams, version 4.1.1
The OpenCV toolkit requires that you set Linux environment variables to identify the directory where the FFmpeg and OpenCV libraries will be installed. You can set them by copying these lines into your ’$HOME/.bashrc’ script:
export OPENCV_INSTALL_PATH=/usr/local
export LD_LIBRARY_PATH=$OPENCV_INSTALL_PATH/lib:$LD_LIBRARY_PATH
After changing your ’$HOME/.bashrc’ script, you should log off Linux and log back in, to ensure that the new environment variables are set in all shells, including your window manager.
The OpenCV toolkit depends upon many tools and libraries that are available as repository packages (RPMs) from RHEL or CentOS repositories. These packages can be installed with administrator tools such as ’yum’. This requires 'root' privileges, which can be acquired temporarily with administrator tools such as ’sudo’.
Most of the packages the toolkit depends upon are stored in the ’base’ repository, which administrator tools such as ’yum’ search by default. The remaining packages are stored in the ’epel (extra packages)’ repository, which is not searched by default.
The ’yum’ tool will include the ’epel’ repository when it searches for repository packages if you first install the ’epel’ package. This requires 'root' privileges. You can do this by entering these commands at a Linux command prompt:
wget http://download.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm
sudo rpm -ivh epel-release-7-5.noarch.rpm
You can install packages the OpenCV toolkit depends upon by entering this command at a Linux command prompt:
sudo yum install gcc-c++ bzip2-devel cmake libcurl-devel gtk2-devel jasper-devel libjpeg-devel libmicrohttpd-devel libpng-devel libsvm-devel libtiff-devel libv41-devel pkgconfig SDL-devel wget yasm zlib-devel pandoc
If your machine has a GPU, and you want OpenCV to use it, download device drivers for it from the manufacturer’s website and install them before proceeding. Then, when configuring OpenCV with ’cmake’ below, specify -D WITH\_OPENCL=ON
instead of -D WITH\_OPENCL=OFF
.
The FFmpeg library contains codecs (encoders and decoders) for many video formats, and can use other codecs that you may have installed separately.
The FFmpeg library is licensed under the GNU Lesser General Public License (LGPL) version 2.1 or later. However, FFmpeg incorporates several optional parts and optimizations that are covered by the GNU General Public License (GPL) version 2.
Please note: Some codecs included in FFmpeg may be the subject of patents for which licenses may be needed. Please be certain you have authorization to use any such codecs in your application. See http://ffmpeg.org/legal.html and the relevant audio/video websites for more information, or consult with your legal counsel. You may choose to include or exclude support for particular codecs when you configure the library, as described below.
The FFmpeg library must be built and installed from source code. You can download a package containing the source for the current release of the FFmpeg library from here:
After downloading the FFmpeg package you must unpack it, build the libraries, and install them. This requires 'root' privileges.
The FFmpeg library has many configuration options. In particular, support for various video codecs can be included or excluded by specifying additional options of the ’./configure’ command. You can display its options by entering these commands at a Linux prompt:
tar -xvf ffmpeg-3.0.1.tar.bz2
cd ffmpeg-3.0.1
./configure --help
After choosing configuration options for the FFmpeg library, you can build and install it by entering these commands at a Linux prompt:
cd ffmpeg-3.0.1
./configure --prefix=$OPENCV_INSTALL_PATH --enable-shared --enable-swscale --enable-fontconfig --enable-libfreetype ... more options ...
make
sudo make install
Please note: You should not configure FFmpeg with the '–enable-nonfree' or '--enable-gpl' options unless you have obtained licenses for the video codecs your applications will use.
After you have installed the FFmpeg library, you can verify that it was installed properly by typing the command ’ffmpeg’ without any arguments at a Linux prompt:
ffmpeg
The ’ffmpeg’ command should display its version, configuration and libraries, something like this:
ffmpeg version 3.0.1 Copyright (c) 2000-2016 the FFmpeg developers
built with gcc 4.8.3 (GCC) 20140911 (Red Hat 4.8.3-9)
configuration: --prefix=/usr/local --enable-shared --enable-swscale --enable-fontconfig --enable-libfreetype
libavutil 55. 17.103 / 55. 17.103
libavcodec 57. 24.102 / 57. 24.102
libavformat 57. 25.100 / 57. 25.100
libavdevice 57. 0.101 / 57. 0.101
libavfilter 6. 31.100 / 6. 31.100
libswscale 4. 0.100 / 4. 0.100
libswresample 2. 0.101 / 2. 0.101
libpostproc 54. 0.100 / 54. 0.100
Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...
Use -h to get full help or, even better, run 'man ffmpeg'
You can display a full list of the ’ffmpeg’ command’s arguments by entering this at a Linux prompt:
ffmpeg -help full
You can display the video formats and codecs ’ffmpeg’ has been configured to use by entering these commands at a Linux prompt:
ffmpeg -formats
ffmpeg -codecs
For further information, please refer to the ’ffmpeg’ man pages and the online FFmpeg documentation.
The OpenCV library contains many algorithms for processing images in computer vision applications.
The OpenCV library must be built and installed from source code. You can download a package containing the source for the current release of the OpenCV library from here:
After downloading the OpenCV package, you can build and install it by entering these commands at a Linux prompt:
unzip opencv-3.1.0.zip
mkdir opencv-3.1.0-build
cd opencv-3.1.0-build
export PKG_CONFIG_PATH=$OPENCV_INSTALL_PATH/lib/pkgconfig
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=$OPENCV_INSTALL_PATH -D OPENCV_EXTRA_C_FLAGS="-DHAVE_CAMV4L -DHAVE_CAMV4L2" -D WITH_OPENCL=OFF ../opencv-3.1.0
make
sudo make install
Note: If your machine has a GPU and you have installed its device drivers, configure ’cmake’ with '-D WITH_OPENCL=ON' instead of '-D WITH_OPENCL=OFF'.
You should confirm that the OpenCV library is configured to use the other libraries you installed above. For example, the ’cmake’ command should display something like this:
-- GUI:
-- QT: NO
-- GTK+ 2.x: YES (ver 2.24.28)
-- GThread : YES (ver 2.42.2)
-- GtkGlExt: NO
-- OpenGL support: NO
-- VTK support: NO
--
-- Media I/O:
-- ZLib: /lib64/libz.so (ver 1.2.7)
-- JPEG: /lib64/libjpeg.so (ver )
-- WEBP: build (ver 0.3.1)
-- PNG: /lib64/libpng.so (ver 1.5.13)
-- TIFF: /lib64/libtiff.so (ver 42 - 4.0.3)
-- JPEG 2000: /lib64/libjasper.so (ver 1.900.1)
-- OpenEXR: build (ver 1.7.1)
-- GDAL: NO
--
-- Video I/O:
-- DC1394 1.x: NO
-- DC1394 2.x: NO
-- FFMPEG: YES
-- codec: YES (ver 57.24.102)
-- format: YES (ver 57.25.100)
-- util: YES (ver 55.17.103)
-- swscale: YES (ver 4.0.100)
-- resample: NO
-- gentoo-style: YES
For further information, please refer to the PDF files installed in /usr/local/share/OpenCV/doc and the online OpenCV documentation.
The OpenCV toolkit contains operators for IBM Streams and sample Streams applications that illustrate the use of those operators. The toolkit also contains a contains a library that the operators use to invoke OpenCV algorithms and FFmpeg codecs. You must build the toolkit’s library, and you should build the sample applications so that you can verify that the operators work properly with the other libraries you have installed.
You can download a package containing the OpenCV toolkit from:
After downloading the OpenCV toolkit package you must unpack it and build its library and sample applications. You can do this by entering these commands at a Linux prompt:
unzip IBMStreams-streamsx.opencv-xxxxxxx.zip
mv streamsx.IBMStreams-streamsx.opencv-xxxxxxx streamsx.opencv
cd streamsx.opencv
make
After building the toolkit’s sample applications, you should execute some of them to verify that the operators work properly on your machine. For instructions on doing this, see Using the OpenCV Toolkit.
The OpenCV toolkit documentation is available in 'markdown' and HTML formats in these directories:
streamsx.opencv/com.ibm.streamsx.opencv/doc/md/index.md
© Copyright 2012, 2016, International Business Machines Corporation, All Rights Reserved


Air
public class Air
Air
handles interactions with a model of a specific Type called Rivet
.
This class is intentionally stateless.
Tasks
Save
Type
is converted to JSON and send as the body of a request
Retrieve
You can retreive a single instance or an array of objects
Handle response via ResponseController
The response controllers does the actual parsing. In theory you can parse any kind of reponse, for now we only support JSON.
Pass errors to the Mitigator
Any type can decide to handle error in a specific way that is suited for that Type
by conforming to protocol Mitigatable
.
You can inspect how error handling is expected to behave by looking at DefaultMitigatorSpec
in the tests of the Example project.
Mocking
You can also mock this class via its Type. Take a look at the GameScoreTest
in example to know how.
-
Save a single item of Type
Rivet
. Closures are called on a background queue!Throws
throws : Errors related to the request construction.Declaration
Swift
public class func save <Rivet: Rivetable> (entity: Rivet, session: NSURLSession = NSURLSession(configuration:NSURLSessionConfiguration.defaultSessionConfiguration()), responseController: ResponseController = ResponseController(), succeed:(response: Rivet)->(), fail:((ResponseError) ->())? = nil) throws
Parameters
entity
The
Rivet
is converted to JSON and send to the server.session
Default NSURLSession = NSURLSession(configuration:NSURLSessionConfiguration.defaultSessionConfiguration()
responseController
default is ResponseController = ResponseController(),
succeed
Closure is called when service request successfully returns - !_!
fail
Optional Closure called when something in the response fails. - !_!
-
Retreive all items of
Type
. Closures are called on a background queue!Throws
throws : Errors related to the request construction.Declaration
Swift
public class func retrieve<Rivet: Rivetable> (session: NSURLSession = NSURLSession(configuration:NSURLSessionConfiguration.defaultSessionConfiguration()), responseController: ResponseController = ResponseController(), succeed:(response: [Rivet])->(), fail:((ResponseError)->())? = nil) throws
Parameters
session
Default NSURLSession = NSURLSession(configuration:NSURLSessionConfiguration.defaultSessionConfiguration()
responseController
default is ResponseController = ResponseController(),
succeed
Closure is called when service request successfully returns - !_!
fail
Closure called when something in the response fails. - !_!
-
Retreive a single item of
Rivet
. Closures are called on a background queue!Throws
throws : Errors related to the request construction.Declaration
Swift
public class func retrieveWithUniqueId <Rivet: Rivetable> (uniqueId:String, session: NSURLSession = NSURLSession(configuration:NSURLSessionConfiguration.defaultSessionConfiguration()), responseController: ResponseController = ResponseController(), succeed:(response: Rivet)->(), fail:((ResponseError)->())? = nil) throws
Parameters
objectID
Something that uniquely defines the object you are asking for of
Rivet
succeed
Closure is called when service request successfully returns. Closures are called on a background queue!
fail
Closure called when something in the response fails.


--- layout: post title: Tracking Atlassian Confluence Server usage with Google Analytics date: 2009-03-18 18:45:56.000000000 +00:00 type: post published: true status: publish categories: - analytics - Uncategorised tags: - analytics - atlassian - confluence - google analytics - wiki meta: aktt_notify_twitter: 'no' _syntaxhighlighter_encoded: '1' _topsy_cache_timestamp: '1299703991' _topsy_long_url: /2009/03/18/tracking-atlassian-confluence-usage-with-google-analytics/ topsy_short_url: http://bit.ly/9e90vC _edit_last: '1' tmac_last_id: '618797412237193216' _thumbnail_id: '2119' _pingme: '1' _encloseme: '1' author: David Simpson excerpt_separator: ---
Updated 2020-03-03: Tracking Atlassian Confluence Cloud usage with Google Analytics
Updated 2014-08-14: Added Universal Analytics tracking code
Updated 2011-06-30: Changed to asynchronous Google Analytics tracking
You've chosen Confluence as your Enterprise wiki and got it installed. People are using it. But how many people?
You could have a look at the Global Activity page on Confluence, but this might confuse matters.
You'll get to see graphs, but what do they really mean? The Global Activity statistics are at best very basic.
Better still, install Google Analytics and you'll have a much more accurate idea of what's going on. Best of all, it's really easy to install.
I'm assuming (for my sake) that you already know your way around Google Analytics.
Login to Google Analytics and add a new website profile
The settings will roughly mirror those in the screenshot below
Make sure that you check "Do Track Site Search" against Site Search. Add queryString as the Query Parameter. This will allow you to monitor who is searching for what.
Update (2009-11-12)
Edit the Search Settings configuration like in the image to see search terms grouped by spaceKey in the internal search categories reports. Further details why can be seen here
The top search terms will suggest either content that's missing from the site, or something that is not easily found in the current information architecture. Either way, tracking this and acting on the findings should improve the user experience.
Login to Confluence as an administrator and add the GA tracking javascript code to the end of the page body...
Navigate to:
Dashboard | Administration | Look and Feel | Custom HTML
Click on the "Edit" button and add the javascript sample (with your tracker code) to the "At end of the HEAD" section:
Update 2014-08-14: Universal Analytics tracking code
With the changes for Universal Analytics, custom variables have been replaced by custom dimensions. Currently there is not way to migrate data stored in custom variable into custom dimensions, so you'll just have to bite the bullet and hope for the best. Additionally, unlike custom variables (which you could create on the fly with JavaScript) you now have to do some work in Google Analytics to set up a custom dimension. Browse to Google Analytics Administration. You now have a Custom Dimension named Confluence Space Key which is available for use within the Google Analytics interface. Next, you’ll need to populate this custom dimension with some data. Browse to Confluence Administration | Look and Feel | Custom HTML and paste this in At the END of the HEAD: This works nicely, particularly as the
Screenshot of Content by Title report:
Screenshot of Site Search Terms report: Zen Foundation overrides the At the end of the HEAD field, so adding the tracking code there will fail for Zen Foundation users. Instead, pop it at the end of the BODY. If you're using a plugin that tracks users names by sending the name to Google, you will be in violation of the Google Analytics Terms of Service. Find out more by reading Identifying your users in Google Analytics while complying with section 7 of the terms of service. If you are unsure of the plugin's compliance with the Google Analytics Terms of Service, ask the plugin vendor for more details of how they comply with comply with section 7 of the Google Analytics terms of service. To prevent you from falling foul of this, I recommend AppFusions' Google Analytics for Confluence add-on which is fully compliant with section 7 of the terms of service. This method is not possible for Confluence Cloud because Atlassian do not allow you to add JavaScript code into their cloud products Instead, the best option is to install an app which provides the same solutionIn Google Analytics
In Confluence
<script>
// Standard Google Universal Analytics code
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
AJS.toInit(function(){
ga('create', 'UA-XXXX-Y', 'auto');
// Add a page-level custom variable to record the space-key
if (typeof AJS.params.spaceKey === 'string') {
ga('set', 'dimension1', AJS.params.spaceKey); // Set a `spaceKey` dimension at page level
}
ga('send', 'pageview');
});
</script>
Results
custom variable custom dimension allows us to easily track all space related content separately, and thus facilitate the use of the (Google) Analytics reporting plugin for Confluence.
Additional Notes
Note for users of Zen Foundation
Note for users of Google Analytics plugins that track user's names
Tracking Atlassian Confluence Cloud usage with Google Analytics
Further reading


Course title
This is a training course aimed at (your target audience) to learn (your course).
Trainers
Have a list of the people delivering the course if it is needed. However, this is subject to change so might be a good idea to not specifiy.
Here’s an example list. This is a good place to define what your preferred name is if you have one.
- Nathaniel (Nate) Butterworth
- Darya Vanichkina
- Kristian Maras
Course pre-requisites and setup requirements
Provide some sort of general description of what you should know and who this course is for. For example:
No previous programming experience is required, but Session 1 is a pre-requisite for the other sessions. Training will be delivered online, so you will need access to a modern computer with a stable internet connection and around 5GB of storage space for data downloaded prior to the course. Participants are encouraged to setup a Python environment on their local computer (as per the Setup Instructions provided), but participation using other platforms/environments can be supported where necessary.
Venue
Specifiy where the training will be, whether it is in person, online, or hybrid.
Include a reminder about the location and time zone in which this course will be running. In almost all cases, our courses are delivered from Sydney and times are reported in AEDT (GMT+11).
Zoom etiquette and how we interact
Include some sort of descripter about what is expected from attendees in terms of participation, and what sort of interaction they should expect. This could also be moved to an about page.
Here’s an example for a zoom only online course:
Sessions will be recorded for attendees only, and it is set up to only record the host shared screen and host audio. We will try and get these uploaded to this site as soon as possible. Please interrupt whenever you want! Ideally, have your camera on and interact as much as possible. There will be someone monitoring the chat-window with any questions you would like to post there. Four hours is a long Zoom session so we have plenty of scheduled breaks combined with a mix of content to be delivered as demos, plus sections as independent exercises, but most of the course will be pretty-hands on with everyone writing their own code. We will use Zoom break-out rooms as needed with the Trainers and participants.
Code of Conduct
As a University of Sydney course, we also want to make sure peopele are aware of our code of conduct. Feel free to move this to an about page as needed.
Example standard Code of Conduct statement:
We expect all attendees of our training to follow our code of conduct, including bullying, harassment and discrimination prevention policies.
In order to foster a positive and professional learning environment we encourage the following kinds of behaviours at all our events and on our platforms:
- Use welcoming and inclusive language
- Be respectful of different viewpoints and experiences
- Gracefully accept constructive criticism
- Focus on what is best for the community
- Show courtesy and respect towards other community members
Our full CoC, with incident reporting guidelines, is available [here]https://sydney-informatics-hub.github.io/codeofconduct/).
Schedule
If your training includes multiple components, it is always nice to have a table with the schedule. With quarto we can make tables using markdown formating, like below.
| Day 1 | |
| Morning | Fundamentals |
| Example R Content | |
| Day 2 | |
| Morning | Example MD Content |
Setup Instructions
Link to the setup instructions if there are any, for example:
Please complete the Setup Instructions before the course. If you have any trouble, please get in contact with us ASAP.
All materials copyright Sydney Informatics Hub, University of Sydney


Notebooks
Story: Lightning which is black, it is that which kills us
Lightning which is black, it is that which kills us
Title
Lightning which is black, it is that which kills us
Collection
Summary
Black lightning kills people. It comes up on them without them seeing it.
Comments
1) This story is found in Book VIII-30
Contributors
|han≠kass'o (Klein Jantje) (VIII)
Date
July 1879
Categories
Keywords
lightning (that is feared) , lightning (that is black kills people) , lightning (that no-one sees coming) , lightning (that comes stealthily) , lightning (that resembles a gun) , lightning (the sound of) , lightning (and the clouds' thundering) , lightning (and clouds) , lightning (and thunder) , death (of people due to black lightning) , thunder (and black lightning which kills people) , clouds (that thunder, and black lightning which kills people) , weather (black lightning that kills people)
Story Pages
8644v


Lee's house was filled with uninvited guests that day, yet he could not resist these people, for they are with the police.
 "I will cut to the case." said him, "Recent half of the year, there has been fourteen murders occuring in the city."
Lee did not understand what that had to do with him, afterall, he stayed at home most of the time. So the head of police showed him the list.
Which Lee read through very carefully, and he found out that the last girl, Jana, had nothing to do with him.
"This girl Jana, was the girl you hit on that day when you were drunk, in the bar.  Police said, "Anyway, these people all have connections with you and somehow offended you, even in the slightest way."
But Lee know that this could never mean that he was the killer, after all, these are just small connections.
"It's me."
Everyone was shocked, mostly Lee. He would never thought sweet Ivey could do such things. But then Lee started to remember something strange..."You did not understand" Ivey said, "but you will very soon."
So Ivey was taken, leaving Lee in total shock and unprehension. But he soon understood.


Over the weekend I put together a guide to use the emonPi in WiFi access point mode for offline or 3G GSM installs. This would be perfect for installs at a site where there is no Wifi or Ethernet, a 3G dongle can be used to provide 3G connectively and and the emonPi can broadcast it's own Wifi AP to allow Internet access to local Emoncms and also interent via the 3G dongle! emonPi 3G router anyone?
https://github.com/openenergymonitor/emonpi/blob/master/docs/wifiAP.md
Also related development the emonPiLCD script will now display info from Huawei HiLink 3G dongles such as connection state and signal strength. This data is obtained directly via a huawei API (tested with E3231). Follow this guide to setup Huawei HiLink dongle:. Initial testing with this dongle is going well, I found I need to use a powered hub USB y-cable to provide extra power to the dongle.
https://github.com/openenergymonitor/huawei-hilink-status
Pulling all these developments together I want to improve our support for mobile connectivity
To do:
* Automate activating emonPi WiFi access point
*Build support for 3G dongles into emonPi image (plug n play)
* Test more dongles, can we find one that does not need a hub and has external antenna options?
* Test reliability and regaining GSM connection when dropped
* Test antenna options for poor reception areas
* Establish and optimize mobile data consumption, maybe emonPi autodetect mobile connection and turn on optimised data mode
* Investigate network operator options - eventually it would be great to be able to offer the emonPi with a 3G dongle + SIM card pre loaded with enough data for 12 months of logging
* Display data consumption on emonPi LCD from dongle APi
*Test how emonPi can be accessed remotely via 3G, reverse ssh?
Re: emonPi WiFi Access Point & 3G GSM USB dongle LCD
Following on from my exploration ino WiFi AP's I would like to improve the emonPi / emonBase setup process by having the unit broadcast it's own open-access wifi hotspot at first boot to allow the user to connect directly to it and enter their local WiFi network authentication details then save and reboot and the emonPi will then connect to users existing WiFi network as a client and turn off AP mode. Trystan previously made a start on this
I propose the following:
emonPi first boot:
1. AP setup Network interfaces file assigning a static IP to wlan0
2. Hostapd service broadcasting a Wifi hotspot
3. isc-dhcp-server running to allow user to connect to hotspot via DHCP
4. User connects to hotspot and get's directed to Emoncms (or a custom Wifi config service), enters WIfi network name and password (for the emonPi to be able to display Wifi networks we would need a Wifi adapter to support both client and AP mode, is this possible?). User saves config and reboots.
5. Unit reboots with standard Raspberry Pi network interfaces file
6. Hostapd and isc-dhcp-server services disabled
6. wlan0 gets assigned an IP via DHCP from client network (static IP could also be an option)
7. Unit operates as usual in client mode
To do
* Changing network interfaces file could be done via bash script using symlinks
* Emoncms Wifi module to be extended to add static IP config option
Questions
1. Can Edimax Wifi dongle an Pi3 integrated Wifi operate both in AP and client mode at the same time?
Re: emonPi WiFi Access Point & 3G GSM USB dongle LCD
Some discussion on this topic here, I think managed (client) + AP mode should be possible on most Wifi hardware:
http://superuser.com/questions/1035755/rtl8188-ap-and-client-mode-simult...
Re: emonPi WiFi Access Point & 3G GSM USB dongle LCD
Concerning emonPi / emonBase first boot in hotspot mode: would there be an option to re-enable this setting without doing a full factory reset? For those of us who use the system as a temporary installation and need to connect it to a different network on a semi-regular basis.
Re: emonPi WiFi Access Point & 3G GSM USB dongle LCD
Yes certainly, it could be activated by hitting the Reset button.
Re: emonPi WiFi Access Point & 3G GSM USB dongle LCD
"I found I need to use a powered hub USB y-cable to provide extra power to the dongle. "
By default the Pi's usb ports are restricted to 600mA, but the B+, 2B and 3B are capable of delivering up to 1.2A via the usb ports providing the supply to the Pi is up to it. if you haven't already try adding
max_usb_current=1
to the end of /boot/config.txt and reboot.
I use this for connecting spinning hard-drives directly to Pi's without a separate hub, power supply or Y-lead, 1200 mA is plenty for most hdd's and I would hope, way more than you need for the 3g dongle.
Paul
Re: emonPi WiFi Access Point & 3G GSM USB dongle LCD
Woo nice find. Are there any side effects to enabling max current? Why not have it enabled by default?
Re: emonPi WiFi Access Point & 3G GSM USB dongle LCD
I've answered my on question (thank you Internet!)
"All that max_usb_current=1 does is to set GPIO38 high, which in turn turns on a FET, which connects a second 39K resistor in parallel to an existing one, on pin 5 of U13, the AP2553W6 USB power manager, lifting the current limit from 0.6A to double that (1.2A), see no possible scenario there why the PI resets because of that, except in case the gate of the FET Q4 is somehow shorted to GND. Which could be caused by a production fault. Inspect Q4, as look if there is solder shorting pins together. Also R6 (resistor mounted between gate of Q4 and GND) should be 100K not 0 Ohm. U13, Q4 and R6 should be near the USB ports."
Reading the Pi forums is seems there are no negative impacts of having this turned on by default except the fact the Pi could potentially draw up to 2A from a PSU (if high power peripherals are plugged in) which could cause damage to cheap PSUs. The PSUs we ship with the emonPi are only 1.2A but high quality with dependable current limiting circuits. I see no problem powering a GSM USB stick, or USB HDD (maybe not both!).
Today I measured the power draw of a RasPi 3, I observed some peak current draws of 0.6A and idle around 0.3A. Pi2 is more like 0.4A peak and 0.26A idle. It would be interesting to measure Pi2 + USB wireless adapter to see if this is lower or higher then Pi3. Obviously the lower the better with regard to a 24/7 energy monitoring device!
Some official measurements:
http://raspberrypi.stackexchange.com/questions/43285/raspberry-pi-3-vs-p...
Re: emonPi WiFi Access Point & 3G GSM USB dongle LCD
Hi,
Facing issues when connecting emonbase to existing wifi/ethernet networks, I'm very interested by these new EmonPi dev.
Would it be possible to modify emonhub to reduce the amount of data uploaded/downloaded through the 3G network ?
Eric
Re: emonPi WiFi Access Point & 3G GSM USB dongle LCD
Hi Eric,
Wifi connectivity should be improved with this update.
I have just updated emonhub to allow setting the buffer interval for posting to Emoncms.org.
https://github.com/openenergymonitor/emonhub/commit/050b6139f3bf07b0930d...
After updating emonhub (with a git pull) you can set in emonhub.conf sendinterval= XX where XX is the time in seconds between posts to emoncms.org. Default is 30s. e.g 600 would be 10min
Re: emonPi WiFi Access Point & 3G GSM USB dongle LCD
Hi,
Do you have a rough idea how it will affect the amount of data downloaded/uploaded by emonhub ? In your example, can we expect a reduction by 600/30 = 20 ? More ? Less ?
Eric
Re: emonPi WiFi Access Point & 3G GSM USB dongle LCD
Probably less, since we are sending the same amount of data it's just being buffered for longer. However we will reduce the amount of data used in the HTTP header request by sending in bulk. We are undergoing testing at the moment to find out for sure.
Re: emonPi WiFi Access Point & 3G GSM USB dongle LCD
Bit of progress on Wifi AP setup, I've made a script to start and stop WiFi AP mode.
It works starting WiFi AP when emonPi is in normal Wifi mode without any rebooting and then when AP is stopped normal client mode is resumed.
The script also bridges eth1 (USB 3G dongle) to the WiFi AP. This will be useful when using emonPi with 3G dongle, this will allow a local user to connect to the emponPi via Wifi AP, to connect via SSH, view data locally and even get internet via the 3G dongle...an emonPi 3G router!
The script assumes hostpad and dhcp is setup as detailed in my guide. Script has only been tested on RasPi3 using standard version of hostapd. Using hostapd with Edimax dongle is a pain since it requires compiling a upstream version from source. For this reason all development in this topic will be done on RasPi3 / offical Broadcom Wifi dongle.
To install, git pull latest emonpi master and symlink the script:
cd emonpi
git pull
then run
This will start a Wifi AP with SSID emonPi and password 'raspberry'
Then to stop
The final piece to allow the AP to be used for fist boot setup is the ability to operate in both client+AP mode at the same time to allow scanning for networks while connected in AP mode. This is technically possible. The raspi3 supports AP+client mode at the same time (see output for $ lw list). I'm just not sure how to configure...I'm monitoring some topics on the RasPi forums for any info.
https://www.raspberrypi.org/forums/viewtopic.php?f=36&t=138730&p=931772#...
https://www.raspberrypi.org/forums/viewtopic.php?f=91&t=134614&p=931751#...
I think what's needed to to create a virtual interface. I've tried this method but am failing to get the virtual interface to bind to the physical adapter (driver issue?):
http://superuser.com/questions/615664/creating-wifi-access-point-on-a-si...


Computer-controlled cutting
.
The weekly assignment focuses on computer-controlled cutting. The first part of the description refers to the LASER CUTTER: a lamp will be designed using different software approaches and realized by means of a laser cutter. The second part refers to the VINYL CUTTER: a sticker will be designed and realized.
Part ONE: the LASER CUTTER and the "press-fit construction kit". The kit is basically composed of single parts that must be fitted together just by pressure: no glue, no screws, no bolts !
I started from the beginning with the idea to design a simple lamp, derived from a 360° revolve of polyline.One of the most basic design procedure ever. In reality this kind of design it’s not so easy: you have to take into account the present of light bulbs, their dimensions, how do they fit into the lamp, the presence of cables and so on.
Considering that I have to use paper board, I need to find an easy way to connect different slices. At the beginning I start using a free Grasshopper for Rhinoceros , definition, that was great (fast slicing and fast slice positioning on a plane) but it can only perform planar slicing, and that was not suitable for my lamp.
Then I import my shape into Autodesk 123D MAKE , that easily let you choose your type of slicing, angles, user paper and let you export your automatically created slices into a DXF file. Please note that all the design data are visible in the figure (number of slices, thickness, etc.)
My slices are ready. At this moment of the assignment, considering the lamp too small if compared to the paper size, I commit a great mistake: I scale the drawing with a factor: 3. I did not immediately realize the consequences.
The VREL laser cutter is waiting for me !
The VREL laser need several steps to start: air, exhaust, etc. . I don’t really like the procedure: you have to fix cardboard to the grid using adhesive tape ! It’s very boring. After a first test with adhesive tape we decide to use magnets to fix cardboard. It's an incredibly faster solution.
The DXF file is transformed into G-Code and then sent to the machine. Please note that both layers (text layer in red and cut layer in blu) are set to CUT, but in the first case the laser power is considerably lower (approximately 30%). Thus, text will be realized by a very light cut.
Despite the above mentioned problems, when it starts cutting, it’s a great experience. You should stay always close to the machine, it’s very dangerous to leave the laser working alone.
After a few minutes, I immediately note that the distance (named S) is too big. Note that it should be equal to the thickness of the paper… scaling 3 times the DXF produce a 3 times bigger S !
The error was fatal. Parts are no longer useful…
Let’s see the positive side !!! I try a second version of the lamp, coming back to the original scale and cutting it again !!!
Now the scale is correct, and all the parts fits together with a little pressure. I have used just one panel of cardboard, so, step by step, I start noticing that the mentioned parts are quite small and there's not enough space at the lamp interior to insert the hand and fix all the radial slices. SO, one of the future update will be the correct scaling (at least 2 times bigger).
LAMP CUTTING from antonio burrai on Vimeo.
Despite the dimensions, I could complete the lamp and test it in the final version. Enjoy the video !
Part TWO: the VINYL CUTTER
The machine used for the second part of the assignment is a STIKA.
In the picture you can see the logo of the Fab Lab Olbia. This will be the starting point of my vinyl cutting. The JPG file has been inported into the STIKA.
FINAL CONSIDERATION BEFORE/DURING CUTTING. At the beginning, prior to cutting, I started using Adobe Illustator, it'a very complete program with tons of features, but sometimes it's too RAM consuming even with basic command. I've switched to Adobe Photoshop and to Microsoft Paint for fast changes.
Once inported the JPG file, you just need to extract the lynes, that will be concretely the route that the STIKA will cut in the coloured paper.
As you can infer from the figure, is almost equivalent to a normal printer. Just press the command CUTTING and send to the printer your own logo.
This is the final result !
Design files download area
The following files are downloadable:
| Type of file |
Description |
Link (Type of file) |
| Fabrication files: vectors(s) / 3D model(s)- Laser cutting |
Grasshopper file (slicer) |
(ghx) |
| Fabrication files: vectors(s) / 3D model(s)- Laser cutting |
Rhinoceros file |
(3dm) |
| Fabrication files: vectors(s) / 3D model(s)- Laser cutting |
123D Make file |
(3dmk) |
| Fabrication files: vectors(s) / 3D model(s)- Laser cutting |
AutoCAD file |
(dxf) |
| Fabrication files: vectors(s) / 3D model(s)- Vinyl cutting |
Image file (FabLab Olbia logo) |
(bmp) |
| Fabrication files: vectors(s) / 3D model(s)- Vinyl cutting |
Photoshop file (FabLab Olbia logo) |
(psd) |


The Game Of Dares
Home
(current)
Events
Dares
Account
ScriptEd Hackathon SF BAY
Let The Dares BEGIN!
Try A Thrill
Go Skydiving
Visit A New City
Parachute Off A Cliff At Your Nearest Beach
Act Of Kindness
Give Food To Someone In Need
Donate Clothes To Someone Who Is Cold
Donate $20 To Refugees
Making A Change
Attend A Gun Control Rally/Protest
Attend The Stand Up for Women's Lives March
Something Fun
Eat a Corilina Reaper Pepper ;)
Spicy Noodle Challenge
Walk On Legos


Servos are cool but you can only move them from 0 to 180 degrees, what if you want to have precise continuous rotation? Stepper motor is the answer. A stepper motor is a very precise motor that you can instruct to rotate one step at a time. They are used in CNC machines, 3D printers and in robotics. The big ones can be really expensive. In this tutorial, we are going to use a super cheap stepper motor with a stepper driver. You can find them online for as cheap as $2 (motor + driver). The 28byj-48 is the one stepper we will work with and you can find lots of projects that use this motor just by googling it’s name. Thanks to its driver it’s super easy to connect it to the Arduino Uno board.
What we need:
- 1 x Arduino Uno board
- 1 x 28byj-48 stepper motor with driver
- Jumper wires
You will need 6 cables with female-male connectors, 4 of them from the Arduino digital pins to the stepper driver and 2 of them from the Arduino power pins to the stepper driver power pins. You can simply connect the motor to the driver with its connectors. Here is an image that shows what is found on the stepper driver.
Here is how you should connect the whole.
Last but not least the Arduino program. It uses a the SWITCH CASE command to shorten the its length.
Arduino stepper motor code
//we need this value to know which coil should be turned on in stepper motor int step_count; void setup() { //seting up pins as outputs for motor driver pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); } void loop() { //using switch and based on step_count we can perform each motor step //as you can see we are shifting high state every step switch(step_count){ case 0: digitalWrite(2, HIGH); digitalWrite(3, LOW); digitalWrite(4, LOW); digitalWrite(5, LOW); break; case 1: digitalWrite(2, LOW); digitalWrite(3, HIGH); digitalWrite(4, LOW); digitalWrite(5, LOW); break; case 2: digitalWrite(2, LOW); digitalWrite(3, LOW); digitalWrite(4, HIGH); digitalWrite(5, LOW); break; case 3: digitalWrite(2, LOW); digitalWrite(3, LOW); digitalWrite(4, LOW); digitalWrite(5, HIGH); break; } //incrementing step_count value step_count++; //if it is bigger than should set it to 0 if(step_count > 3){ step_count = 0; } //change the delay to change the speed for this motor 0.002 second is the smallest possible delay(3); }
I figured I should add a piece of tape on the rotating head of the motor to be able to easily see what is happening.


Image Converter
Pick file
Type
JPEG
PNG
WEBP
AVIF
Quality
Resize
Use "Pick file" button or dragging to add file.
Right click "Save as" or drag to save the output.


Class SystemException
PHPRender fast and simple to use PHP MVC framework
MVC Framework for PHP 5.2 + with PHP files views part of YMVC System SystemException Class work exception inside YMVC
PHP version 5
LICENSE: This source file is subject to version 3.01 of the PHP license that is available through the world-wide-web at the following URI: http://www.php.net/license/3_01.txt. If you did not receive a copy of the PHP License and are unable to obtain it through the web, please send a note to<EMAIL_ADDRESS>so we can mail you a copy immediately.
- Exception
- SystemException
Package: YMVC\SystemException
Category: Framework, MVC
Copyright: 1997-2016 ydk2.tk
License: PHP License 3.01
Author: ydk2<EMAIL_ADDRESS>Version: 2.0.1
Since: File available since Release 1.0.0
See: YMVC System
Link: http://ymvc.ydk2.tk
Located at libriares/core/systemexception.php
Category: Framework, MVC
Copyright: 1997-2016 ydk2.tk
License: PHP License 3.01
Author: ydk2<EMAIL_ADDRESS>Version: 2.0.1
Since: File available since Release 1.0.0
See: YMVC System
Link: http://ymvc.ydk2.tk
Located at libriares/core/systemexception.php
public
|
|
public
|
|
public
|
__construct(),
__toString(),
__wakeup(),
getCode(),
getFile(),
getLine(),
getMessage(),
getPrevious(),
getTrace(),
getTraceAsString()
|
$code,
$file,
$line,
$message
|


Lab 1: Using the Azure portals
Lab 2: Using Microsoft Azure management tools
Lab 4: Web Apps and cloud services
Lab 5: Create and configure virtual networks
Lab 6: Configure Azure Storage and Azure SQL Database
Lab 7: Implementing containers on Azure VMs
Lab 8: Create and manage Azure Active Directory tenants


Did you ever play with multi-dimensional arrays?
Did you ever try to perform some simple operations on them?
Did you feel annoyed by re-implementing the same
operations every time you start a new project?
What if you would have objects and a framework that does it for you?
Main concepts:
Did you ever suffer from simple calculation that didn't provide any information about actual unit of value that is used? What about error propagation? And what if some part of actual acquisition is not valid? all of these you get for free with tenosorics implementations.
kajetan arek Or go directly to our GitHub repositiry »


Actively participated in a Research Project Characteristics of Information Spreading across nations
Extracted, Processed and Analyzed the COVID-19 related data from Twitter to understand social view on COVID-19
Developed a python script to extract the data from Twitter API in Json Format and store the files in the project server
Wrote 50+ Python scripts and ran them in Linux server to retrieve the required information from the tweets
Created 100+ visualizations in Python and Tableau. Sampled the data from different time periods for Time series analysis.
Software Engineer-Intern
Diebold Nixdorf India Pvt Limited
May 2018 to October 2019
Worked as a software developer. Involved in product development and customization of Retail applications
Developed 150+ plugins in AngularJS, ASP.Net, ADO.Net and SQL to customize TP.Net for various Retail clients in Asia-Pacific region
Involved in frequent improvement of SQL stored procedures, Functions, Triggers and tables to generate customized reports
Designed and developed a windows application in C# which reads transaction files from database, corrects the CRN number of XML files and update them in the database
Worked in Agile methodology attending scrum meetings and updating the user stories in JIRA
System Analyst-Intern
Cognizant Technology Solutions
Dec 2016 to May 2018
Designed an SQL database integrated from different tables related to the client data with normalizations
Developed 200+ stored procedures, queries, views, triggers, and other database objects to support internally hosted applications
Analyzed the existing SQL queries and modified to improve the performance of client’s applications.
Designed and built 150+ workflows using Python scripts, Stored procedures, macros, user defined functions and views.
Communicated regularly with application developers to develop new tools and systems to support growing business needs.


QUIZ BOARD
how is the feeling
below are
questions
you are expected
to fill in
without leaving any blank spaces
which among this is a programming language
html
css
javascript
i dont know
what is programming
coding style
creating set of instructions
Am not sure
None the above
difference between bootstrap and css
a camp indeed
a programming language
used in webgraphics
None the above


Home
Clients
Categories
Products
Orders
Broadcasts
Messages
Users
Sign in
Logout
Id
Photo
Name
Category
Price
View
Delete
Id
Name
категория
Цена


---
layout: post
title: Mysterious Light in the Sky
date: '2012-06-02T12:59:00.000-04:00'
author: Bob Sica
tags:
- youtube
- ldnont
- operations
- video
- mystery
modified_time: '2012-06-02T13:11:38.297-04:00'
thumbnail: https://img.youtube.com/vi/UAGejaauWPE/default.jpg
blogger_id: tag:blogger.com,1999:blog-736339229338318027.post-476003101084688621
blogger_orig_url: http://blog.purplecrowlidar.ca/2012/06/mysterious-light-in-sky.html
---
How cool is this! Jay Brodie, walking his dog northwest of London saw our laser (I’m guessing from several km away) and made this video which he posted on youtube in hope that someone would explain what he saw.


I study Data Science, Chemistry, &
Computer Science at the University of Denver.
In my free time I
work in computational & in vitro biochemical research (With the
enzyme pictured above!). I also love playing & analyzing data, and I'm
currently working with my colleagues on starting a company (Atomata)
focused on IoT data sensors & analytics for indoor agriculture.
Check out the link below to get to the Atomata website:
Link to Atomata's
(temporary) landing page
(Just a temporary landing page while I build the backend for the
IoT backend infrastructure, our actual site is scheduled to launch March 25th)
Email me here!


-
SD CrowdFunding Round One
freedom.press
SecureDrop is an open-source whistleblower submission system any news organization can install to securely receive information and documents from ...
-
Terror laws clear Senate, enabling entire Australian web to be monitored ...
www.smh.com.au
Australian spies will soon have the power to monitor the entire Australian internet with just one warrant, and journalists and whistleblowers will ...
-
Euan Blair's mother, not his wife, is partner in marital home - Telegraph
www.telegraph.co.uk
Cherie Blair is joint owner of Euan Blair’s £3.6m home, with no room for his wife Suzanne on deeds
-
FBI blasts Apple, Google for locking police out of phones
www.washingtonpost.com
The agency director’s criticisms echo the frustrations of law enforcement officials nationwide.
-
Unreal exchange in House of Commons over Canada’s involvement in Iraq | ...
globalnews.ca
Watch Unreal exchange in House of Commons over Canada’s involvement in Iraq Video Online, on GlobalNews.ca
-
Apple Still Has Plenty of Your Data for the Feds - The Intercept
firstlook.org
Improved Apple encryption is a welcome step toward thwarting the surveillance state. But it seriously oversold Apple's commitment to privacy.
-
BuzzFeed’s Future Depends On Convincing Us Ads Aren’t Ads | TechCrunch
techcrunch.com
BuzzFeed makes the majority of its money on ads that pretend to be content, but can it keep up this charade? Or, is the Starbucks-sponsored "10 ...
-
ISIS and the future of the Tomahawk missile
www.marketplace.org
The U.S. launched at least 47 of them at militant strongholds in Syria Monday.
-
Glenn Greenwald in conversation with David Walmsley
www.eventbrite.ca
CJF J-TalkJournalism matters. #CJFjtalk Glenn Greenwald in conversation with David Walmsley Open source hero or every government's worst nightmare? ...
-
Defense Contractors Are Making a Killing - The Intercept
firstlook.org
Stock prices for Lockheed Martin, General Dynamics, Raytheon and Northrop Grumman set all-time record highs last week as it became increasingly clear ...
-
Managing a Nightmare: The CIA Reveals How It Watched Over the Destruction ...
firstlook.org
Freshly-released CIA documents show how the largest newspapers in the country helped the agency contain a groundbreaking exposé of cocaine ...
-
War without end: The U.S. may still be fighting in Syria in 2024, 2034, ...
blogs.reuters.com
In a Pentagon briefing yesterday, Army Lieutenant General Bill Mayville called the cruise missiles and bombs flung at targets in Syria "the beginning ...
-
The Angry Arab News Service/وكالة أنباء العربي الغاضب: Look how the murder ...
angryarab.blogspot.com
A source on politics, war, the Middle East, Arabic poetry, and art.
-
Pentagon: No evidence that airstrikes killed civilians despite reports
www.latimes.com
Despite claims by activists that U.S. and allied Arab airstrikes killed up to two dozen civilians this week in Syria, a Pentagon official said the ...
-
How Former Treasury Officials and the UAE Are Manipulating American ...
firstlook.org
A bizarre neocon/Israel/Gulf-dictator coalition is now driving not only U.S. policy but U.S. discourse, as well, aided by ex U.S. officials.
-
This is a complete list of Wall Street CEOs prosecuted for their role in ...
www.washingtonpost.com
This is why prosecutions of Wall Street CEO haven't happened.
-
Deadly Drone Strike on Muslims in the Southern Philippines
www.brookings.edu
Following the first U.S. drone strike in the Southern Philippines, which pushed hostilities between the centre and periphery in the Philippines in a ...
-
Lizza says Obama has bombed more nations than Bush
www.politifact.com
The irony of President Barack Obama, Nobel Prize winner and putative anti-war candidate, launching extensive airstrikes in Syria, quickly led to ...
-
Today in demonstrating contempt for Parliament
www.macleans.ca
Paul Calandra misunderstands Parliament as a place where he is free to talk about whatever he wants
-
Paul Calandra calls Glenn Greenwald a porn spy - Loonie Politics
looniepolitics.com
The Prime Minister's parliamentary secretary, Paul Calandra, rose in the House before Question Period to bemoan the CBC's journalistic integrity.
-
ESPN Suspends Bill Simmons 3 Weeks For Calling Roger Goodell A Liar In ...
thinkprogress.org
The popular ESPN personality called the NFL commissioner "a liar" over the handling of the Ray Rice case.
-
The Nation sur Twitter : "Entering the war in Syria unquestionably ...
twitter.com
Mot de passe oublié ? Vous utilisez déjà Twitter via SMS ?
-
The Angry Arab News Service/وكالة أنباء العربي الغاضب: Arab views on US ...
angryarab.blogspot.com
A source on politics, war, the Middle East, Arabic poetry, and art.
-
Snowden Honored With 'Alternative Nobel'
abcnews.go.com
Edward Snowden was among the winners Wednesday of a Swedish human rights award, sometimes referred to as the "alternative Nobel," for his disclosures ...
-
Israeli Government Eventually Admits that Mohammed Is the Top Baby Name - ...
firstlook.org
Are Palestinian babies actually babies? That's been a surprisingly thorny question for the Israeli government this week.
-
Is Obama Pulling A Bush?
dish.andrewsullivan.com
Tomasky insists no: The first and most important difference, plainly and simply: Obama didn’t lie us into this war. It’s worth emphasizing this ...
-
Stephen Hayes in WSJ: Cheney is our protective father
www.dailykos.com
http://online.wsj.com/article_print/SB118714334249198099.html This is the printable version; hopefully it's accessible. Stephen Hayes apparently ...
-
In Airstrikes, U.S. Targets Militant Cell Said to Plot an Attack Against ...
www.nytimes.com
American forces took advantage of the strikes against the Islamic State in Syria to try to also wipe out the leadership of an unrelated cell that the ...
-
Glenn Greenwald sur Twitter : "Unsurprisingly, Harry Reid's long-time ...
twitter.com
Mot de passe oublié ? Vous utilisez déjà Twitter via SMS ?
-
Fox News Contributor Stephen Hayes Is on the Terrorist Watch List
www.mediaite.com
Senior writer for the Weekly Standard and regular panelist on Fox News' Special Report Stephen Hayes just found out he's on the Department of ...


You'll miss a lot on this web site unless you enable Javascript
in your browser.
What is TLA+ Version 2? [show]
TLA+ Version 2, here called TLA+2
for short, is the current version of TLA+.
TLA+ now means TLA+2. The previous version is
referred to here as TLA+1. This page contains a brief description
of how TLA+2 differs from TLA+1, which is the language described in
the book Specifying Systems.
Features for Writing Specifications [show]Recursive Operator DefinitionsA RECURSIVE statement allows you to define operators recursively, including the use of mutual recursion. For example, here's a silly way to define both fact1(n) and fact2(n) to equal n factorial, for any natural number n:RECURSIVE fact1(_), fact2(_) fact1(n) == IF n = 0 THEN 1 ELSE n*fact2(n-1) fact2(n) == IF n = 0 THEN 1 ELSE n*fact1(n-1) LAMBDA ExpressionsTLA+ allows you to define a higher-order operator that takes an operator as an argument. In TLA+1, you could use only the name of an operator that has already been defined or declared as such an argument. TLA+2 allows the use of a LAMBDA expression as the argument. For example, if F is an operator that takes as its argument an operator with two arguments, then you can write the expressionLET Id(a, b) == a + 2*b IN F(Id)In TLA+2, you can write this as F(LAMBDA a, b : a + 2*b)You can also use a LAMBDA expression to substitute for an operator in the WITH clause of an INSTANCE statement. Writing Proofs [show]
The major new feature of TLA+2 is the introduction of constructs for
writing proofs. A checker for these proofs is
being built as part of a
project
at the
Microsoft Research–Inria Joint Centre.
It does not yet handle temporal-logic reasoning, but it can
check most other parts of a proof.
The language supports hierarchically structured proofs. The paper How to Write a Proof describes the basic hierarchical proof style and explains why it is much better than the way mathematicians and computer scientists now write proofs. The TLA+2 documentation describes the language features for writing structured proofs. The TLAPS project page contains a brief tutorial on writing TLA+ proofs.
Other Changes [show]
Other than introducing a few new keywords that can no longer be used
as identifiers, there are two changes in TLA+2 that may make a TLA+
specification no longer legal. The first is the handling of
instantiated infix operators. In TLA+1, if you wrote
Foo(x) == INSTANCE Mand module M defines the infix operator ++, then you had to write a weird expression like a Foo(42)!++ bto use the instantiated operator. In TLA+2, this is written Foo(42)!++(a,b). The second change is that certain operators can no longer be used to instantiate operator parameters in a constant module. You're unlikely to encounter it. However, if you get an error message of the form Error in instantiating module '...': A non-Leibniz operator substituted for '...'.then you should read Section 5.2 in the TLA+2 Preliminary Guide for an explanation. Documentation [show]
All current documentation written since 2008 describes
TLA+2. That include
the TLA+ Video Course
and the TLA+ Hyperbook.
Here is some more detailed documentation:
|
|||