D3.js is a JavaScript library for manipulating documents based on data. D3 helps you bring data to life using HTML, SVG and CSS. D3’s emphasis on web standards gives you the full capabilities of modern browsers without tying yourself to a proprietary framework, combining powerful visualization components and a data-driven approach to DOM manipulation.
These are the assets that are given to you together with this labsheet.
lab5/
javascripts/
d3.min.js
jquery.min.js
task3.js
css/
task1.css
task3.css
task1.html
task2.html
task3.html
The javascript
folder contains both the d3
and jquery
libraries. d3
is essential for all the tasks. jquery
is essential for task 3 only.
<svg>
. For example, you may draw a circle using following markup:<svg width="500" height="500" style="border:1px solid black;">
<circle cx="50" cy="100" r="25" fill="green"/>
</svg>
The markup above creates a 500px x 500px canvas with black border. Within the canvas, it draws a green color circle with radius of 25px. The circle resides at point (100, 25) on the canvas. It looks something like this:
HTML5 allows us to "draw" on a web page easily, however, it will be extremely tedious if we have to use markup language to create such shapes all the time. A data visualization diagram sometimes involves hundreds or even thousands of shapes and paths. To make things worse, the data are usually dynamic - they change over time.
Why not generate them using JavaScript? That's what D3 is made for. It is designed to help us to create complex graphs - such as a bar chart of Singapore's fertility rate in the 21st century.
At the end of the this task, you will be able to make following graph using D3.
As D3 is a web-based data visualization library, we will need to have a web page before drawing anything with D3.
task1.html
is an empty web page skeleton. To inlcude D3, you need to include following code within the ...

The completed code:

<title> D3 Tutorial </title>

<link rel="stylesheet" type="text/css" href="./css/task1.css">

Before we get our hands dirty, let's think about the requirements - What kind of donuts chart are we creating? How many segments? What is the color of each segment? How big is the donut chart? What is the outer radius and inner radius of the donut?
How about this?
| Property | Value |
|---|---|
| Segments | 3 |
| Color | red, blue, orange |
| Data | 10, 50, 80 |
| Inner Radius | 200 |
| Outer Radius | 300 |
In JavaScript:
var color = ["red", "blue", "orange"];
var data = [10, 50, 80];
var innerRadius = 200;
var outerRadius = 300;
Hence we have:

<title> D3 Tutorial </title>

<link rel="stylesheet" type="text/css" href="./css/task1.css">

All shapes are drawn on canvas. Therefore, we have to create a canvas object in javascript.
var canvas = d3.select("body").append("svg")
.attr("width", 600)
.attr("height", 600);
d3.select("body")
will select the
container in the DOM. The method .append("svg")
will create an <svg></svg>
element within the
. .attr()
specifies the properties (height and width) of the <svg>
element.
To show that the canvas is really on the page, it is styled with a grey border (defined in task1.css
). You should be seeing something like this:
A group is a container of multiple DOM elements. As we are going to make a donut chart with multiple segments, it is better for us group all segments together.
To create a group:
var group = canvas.append("g")
.attr("transform", "translate(300, 300)");
translate(300, 300)
translates the group towards right by 300px
and towards bottom by 300px
so that our donut chart will not appear that the edge of the canvas.
You won't be able to see any difference at this point of time. However, if you use Developer Tools to inspect element, you will find a <g></g>
element residing at (300, 300) on the canvas.
A donut chart is made of multiple segments. Each segment is an arc. Our arc has an inner radius of 200px
and outer radius of 300px
. Let's define an arc generator object. It works like a speical type of brush that only draw arcs with specific radius.
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
Donut charts are similar to pie chart. In each segment, its arc angle is proportional to the quantity it represents. To map our data into arc angles, let's use the native pie chart data model in D3, as they work in the same way.
var pie = d3.layout.pie()
.value(function (d) { return d; });
d3.layout.pie()
specifies the data model that we are using to visualize our data.
We pass a "do-nothing" function into .value()
, as we are not going to process our data any further before visualising it.
How D3 creates new elements may not be intuitive for beginners.
To create the arcs, we will first build a selector to select all the DOM elements with the class arc
. If there are some arc
elements in the group
, the selector will return those elements.
var group = canvas.append("g")
.attr("transform", "translate(300, 300)");
...
group.selectAll(".arc")
We then bind our data with the selector by appending .data(pie(data))
after the selector:
var pie = d3.layout.pie()
.value(function (d) { return d; });
...
group.selectAll(".arc").data(pie(data))
And for each data entry, we should create an .arc
element as a container:
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
...
group.selectAll(".arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc")
.append("path")
.attr("d", arc);
.enter()
means that as long as there is an unused data entry, D3 will create an <g class="arc"></g>
. A <path></path>
will be created in each <g class="arc"></g>
, using the arc
generator that we defined earlier.
You will see something like this:
Lastly, let's use different colors to represent different segments.
ordinal()
means that color will be determined by order.
color
is a function that takes in data value and returns a corresponding color.
var color = d3.scale.ordinal()
.range(["red", "blue", "orange"])
...
group.selectAll(".arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc")
.append("path")
.attr("d", arc);
.attr("fill", function (d) { return color(d.data) })
This is the completed code for creating a donut chart using D3.

<title> D3 Tutorial </title>

<link rel="stylesheet" type="text/css" href="./css/task1.css">

As you have learnt how to make a dount chart using D3.js, you may wonder how to draw axes in your visualizations - for example, in a bar chart.
In this task, we will be modifying task2.html
.
task2.html
is no different from task1.html
, except that d3.js
has already been included and there is no additional CSS to be loaded.

<title> D3 Tutorial </title>

Drawing a bar chart is pretty similar to drawing a donut chart. In fact, it is much easier.
Firstly, let's define the data and the canvas size.
var dataArray = [20, 40, 50, 60];
var width = 500;
var height = 500;
Then, we should set the maximum and minimum length of the bar. The following code sets the maximum length of the bar to be as same as the width of the canvas.
.domain([0, 60])
declares that the domain of the graph will be from 0 to 60.
.range([0, width])
declares that the actual length of each bar will be between 0 to the width of the canvas (500). That means that a bar that represents data value of 60 will be 500px long.
.scale.linear()
means that the length of each bar will be linearly propotional to the data value.
var widthScale = d3.scale.linear()
.domain([0, 60])
.range([0, width]);
After defining the scale, let's define the color. The color of each bar is linearly proportional to the data. A bar will appear more bluish if it has a larger corresponding value.
var color = d3.scale.linear()
.domain([0, 60])
.range(["red", "blue"]);
Lastly, let's create the canvas and draw each bar using following code.
var canvas = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(20, 0)");
var bars = canvas.selectAll("rect")
.data(dataArray)
.enter()
.append("rect")
.attr("width", function (d) { return widthScale(d); })
.attr("height", 50)
.attr("fill", function (d) { return color(d) })
.attr("y", function(d, i) { return i * 100; });
That completes the code for drawing a bar chart.
The bar chart that you have drawn looks nice. However, there is still one thing missing - The Axis.
Firstly, Let's create an axis generator by calling d3.svg.axis()
.
var axis = d3.svg.axis()
.ticks(5)
.scale(widthScale);
ticks(5)
defines the number of ticks in the axis. In this case, we will have 5 ticks, representing 10, 20, 30, 40, 50.
The scale of ticks is set to be as same as the widthScale
that we defined previously
To make the axis appear, we have to append the axis into the canvas, and place it below the bars that we have drawn earlier.
canvas.append("g")
.attr("transform", "translate(0, 400)")
.call(axis);
This is the completed code for creating a bar chart with axis using D3

<title> D3 Tutorial </title>

A chord diagram is a graphical method of displaying the inter-relationships between data in a matrix. The data is arranged radially around a circle with the relationships between the points typically drawn as arcs connecting the data together.
Example of a chord diagram
In this Task, we are going to make an interactive chord diagram. Here is the snapshot of this chord diagram
When you hover on one of the external arcs, its connecting chords are highlighted to show the relationship between different arcs.
It also includes some storytelling component to guide user through the interactive experience.
The completed visualization can be accessed using following link:
http://bl.ocks.org/nbremer/raw/94db779237655907b907/
A basic HTML page has been made for you in task3.html
. You are only required to modify task3.js
.
In a Global Mobile Consumer Survey, 2000 residents of the Netherlands were surveyed about their mobile phone behaviour. The respondents gave them information about the brand of their current main phone, and the brand of their previous main phone.
| Currrent | Apple | HTC | Huawei | LG | Nokia | Samsung | Sony | Other |
|---|---|---|---|---|---|---|---|---|
| Apple | 9.6899% | 0.8859% | 0.0554% | 0.443% | 2.5471% | 2.4363% | 0.5537% | |
| HTC | 0.1107% | 1.8272% | 0% | 0.4983% | 1.1074% | 1.052% | 0.2215% | 0.4983% |
| Huawei | 0.0554% | 0.2769% | 0.2215% | 0.2215% | 0.3876% | 0.8306% | 0.0554% | 0.3322 |
| LG | 0.0554% | 0.1107% | 0.0554% | 1.2182% | 1.1628% | 0.6645% | 0.4983% | 1.052% |
| Nokia | 0.2215% | 0.443% | 0% | 0.2769% | 10.4097% | 1.2182% | 0.4983% | 2.8239% |
| Samsung | 1.1628% | 2.6024% | 0% | 1.3843% | 8.7486% | 16.8328% | 1.7165% | 5.5925% |
| Sony | 0.0554% | 0.4983% | 0% | 0.3322% | 0.443% | 0.8859% | 1.7719% | 0.443% |
| Other | 0.2215% | 0.7198% | 0% | 0.3322% | 1.6611% | 1.495% | 0.1107% | 5.4264% |
Let's put the table data into two variables. One stores the names of the phone brands. The other stores the actual data. We also have another array that defines the group of colors that we will be using in our graph.
var NameProvider = ["Apple","HTC","Huawei","LG","Nokia","Samsung","Sony","Other"];
var matrix = [
[9.6899,0.8859,0.0554,0.443,2.5471,2.4363,0.5537,2.5471], // Apple 19.1584
[0.1107,1.8272,0,0.4983,1.1074,1.052,0.2215,0.4983], // HTC 5.3154
[0.0554,0.2769,0.2215,0.2215,0.3876,0.8306,0.0554,0.3322], // Huawei 2.3811
[0.0554,0.1107,0.0554,1.2182,1.1628,0.6645,0.4983,1.052], // LG 4.8173
[0.2215,0.443,0,0.2769,10.4097,1.2182,0.4983,2.8239], // Nokia 15.8915
[1.1628,2.6024,0,1.3843,8.7486,16.8328,1.7165,5.5925], // Samsung 38.0399
[0.0554,0.4983,0,0.3322,0.443,0.8859,1.7719,0.443], // Sony 4.4297
[0.2215,0.7198,0,0.3322,1.6611,1.495,0.1107,5.4264] // Other 9.9667
];
// Sums up to exactly 100
var colors = ["#C4C4C4","#69B40F","#EC1D25","#C8125C","#008FC8","#10218B","#134B24","#737373"];
Then, we have to initialise the colour scale. The following code binds each color with a phone brand. For example, all data related to Apple will be using "#C4C4C4"
.
// Initialize the colour scale
var fill = d3.scale.ordinal()
.domain(d3.range(NameProvider.length))
.range(colors);
After setting up the data, we need to create our canvas. We firstly define some constants that we are going to use later.
var width = 650,
height = 600,
hPad = 20
innerRadius = Math.min(width, height) * .39,
outerRadius = innerRadius * 1.04;
Our graph will be contained inside a <svg>
element. The following code appends the <svg>
element inside

. It also defines the width and height of the canvas.
// Initialize the SVG
var svg = d3.select("#chart").append("svg:svg")
.attr("width", width+50)
.attr("height", height+20)
.append("svg:g")
.attr("transform", "translate(" + width / 2 + "," + (height / 2 + hPad) + ")");
We also need to initialize a chord generator. The generator will be used later to draw various chords. .matrix(matrix)
will allow the chord generator to use the data from the matrix
variable that we defined earlier.
var chord = d3.layout.chord()
.padding(.04)
.sortSubgroups(d3.descending) // Sort the chords inside an arc from high to low
.sortChords(d3.descending) // Which chord should be shown on top when chords cross. Now the biggest chord is at the bottom
.matrix(matrix);
Last but not the least, we need to have an arc generator. It will be used to create external arcs.
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
So far, what you can see is a plain canvas with a button and two links on it.
Let's draw the arcs using following code.
One thing to take note, chord.groups
is a function that returns the computed group objects, given the layout's current configuration and associated matrix. In this case, it will return the current market share of each brand.
var g = svg.selectAll("g.group")
.data(chord.groups)
.enter()
.append("svg:g")
.attr("class", function(d) {return "group " + NameProvider[d.index];});
g.append("svg:path")
.attr("class", "arc")
.style("stroke", function(d) { return fill(d.index); })
.style("fill", function(d) { return fill(d.index); })
.attr("d", arc)
The arcs look like this:
Drawing chords is no different from drawing arcs.
var chords = svg.selectAll("path.chord")
.data(chord.chords)
.enter()
.append("svg:path")
.attr("class", "chord")
.style("stroke", function(d) { return d3.rgb(fill(d.source.index)).darker(); })
.style("fill", function(d) { return fill(d.source.index); })
.attr("d", d3.svg.chord().radius(innerRadius))
At this point, you will be seeing a static chord diagram.
It is not nice to have a graph without label.
To add brand names to the diagram, we need to append a text element after every arc. Each text element is created with certain degree of rotation and translation.
g.append("svg:text")
.each(function(d) { d.angle = (d.startAngle + d.endAngle) / 2; })
.attr("dy", ".35em")
.attr("class", "titles")
.attr("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
.attr("transform", function(d) {
return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
+ "translate(" + (innerRadius + 55) + ")"
+ (d.angle > Math.PI ? "rotate(180)" : "");
})
.text(function(d,i) { return NameProvider[i]; });
We also need to draw ticks around the arcs to show the scale of our data. A tick includes a text element, indicating the percentage value, and a few helping lines showing the intermediate value.
var ticks = svg.selectAll("g.group").append("svg:g")
.attr("class", function(d) {return "ticks " + NameProvider[d.index];})
.selectAll("g.ticks")
.attr("class", "ticks")
.data(groupTicks)
.enter().append("svg:g")
.attr("transform", function(d) {
return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
+ "translate(" + outerRadius+40 + ",0)";
});
// Append the tick around the arcs
ticks.append("svg:line")
.attr("x1", 1)
.attr("y1", 0)
.attr("x2", 5)
.attr("y2", 0)
.attr("class", "ticks")
.style("stroke", "#AAA");
// Add the labels for the %'s
ticks.append("svg:text")
.attr("x", 8)
.attr("dy", ".35em")
.attr("class", "tickLabels")
.attr("transform", function(d) { return d.angle > Math.PI ? "rotate(180)translate(-16)" : null; })
.style("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
.text(function(d) { return d.label; })
.attr('opacity', 1);
// Returns an array of tick angles and labels, given a group
function groupTicks(d) {
var k = (d.endAngle - d.startAngle) / d.value;
return d3.range(0, d.value, 1).map(function(v, i) {
return {
angle: v * k + d.startAngle,
label: i % 5 ? null : v + "%"
};
});
};// groupTicks
You should be seeing labels and ticks like this:
We have drawn a nice chrod diagram. Let's take another step further to make the visualization more interactive.
First of all, we can add some explaination text on top of the diagram. wrap(text, width)
function will help us the wrap the text within a specific area.
//////////////////////////////////////////////////////////
///////// Initialize Explaination Text ////////////////////
//////////////////////////////////////////////////////////
// Create wrapper for center text
var textCenter = svg.append("g")
.attr("class", "explanationWrapper");
// Starting text middle top
var middleTextTop = textCenter.append("text")
.attr("class", "explanation")
.attr("text-anchor", "middle")
.attr("x", 0 + "px")
.attr("y", -24*10/2 + "px")
.attr("dy", "1em")
.attr("opacity", 1)
.text("For the Dutch version of the Deloitte Global Mobile Consumer Survey, Deloitte asked 2000 residents of the Netherlands about their mobile phone behavior")
.call(wrap, 350);
// Starting text middle bottom
var middleTextBottom = textCenter.append("text")
.attr("class", "explanation")
.attr("text-anchor", "middle")
.attr("x", 0 + "px")
.attr("y", 24*3/2 + "px")
.attr("dy", "1em")
.attr('opacity', 1)
.text("The respondents gave us information about the brand of their current main phone, and the brand of their previous main phone")
.call(wrap, 350);
// Wraps SVG text
function wrap(text, width) {
var text = d3.select(this)[0][0],
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.4,
y = text.attr("y"),
x = text.attr("x"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", x).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", x).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
};
};
};
//////////////////////////////////////////////////////////
///////////// Initialize Progress Bar //////////////////////
//////////////////////////////////////////////////////////
// Initialize variables for bar
var progressColor = ["#D1D1D1","#949494"],
progressClass = ["prgsBehind","prgsFront"],
prgsWidth = 0.4*650,
prgsHeight = 3;
// Create SVG to visualize bar in
var progressBar = d3.select("#progress").append("svg")
.attr("width", prgsWidth)
.attr("height", 3*prgsHeight);
// Create two bars of which one has a width of zero
progressBar.selectAll("rect")
.data([prgsWidth, 0])
.enter()
.append("rect")
.attr("class", function(d,i) {return progressClass[i];})
.attr("x", 0)
.attr("y", 0)
.attr("width", function (d) {return d;})
.attr("height", prgsHeight)
.attr("fill", function(d,i) {return progressColor[i];});
To make the text more visible, you may want to modify the visibility of the other elements. eg. chords, ticks, etc.
Let's hide chord, ticks and labels, and make the arcs semi-transparent.
g.append("svg:path")
...
.style("opacity", 0.4);
var chords = svg.selectAll("path.chord")
...
.attr('opacity', 0);
g.append("svg:text")
...
.attr('opacity', 0)
.text(function(d,i) { return NameProvider[i]; });
// Append the tick around the arcs
ticks.append("svg:line")
...
.style("stroke", "#FFF");
// Add the labels for the %'s
ticks.append("svg:text")
...
.attr('opacity', 0);
That's what you are going to see when you added in the code above.
In this visualization, we will be having 16 scenes (including the first one). We need a few functions to handle the interaction.
Let's define some important variables. counter
stores the current scene index. buttonTexts
stores all the texts on the button. As you can see, there are 15 entires in the buttonTexts
array. This means that each scene will have a button. When the button is clicked, the visualization will proceed to next scene.
opacityValueBase
defines an element's opacity value when it is active. opacityValue
defines an element's opacity value when it is inactive.
var counter = 1,
buttonTexts = ["Ok","Go on","Continue","Okay","Go on","Continue","Okay","Continue",
"Continue","Continue","Continue","Continue","Continue","Finish"],
opacityValueBase = 0.8,
opacityValue = 0.4;
We also need to bind actions with respective buttons. When

button is clicked, the page will be reloaded. When

button is clicked. We will jump to the final scene directly.
Last but not the least, when

button is clicked, the visualization will proceed to the next scene and increase the counter
by 1.
// Reload page
d3.select("#reset")
.on("click", function(e) {location.reload();});
// Skip to final visual right away
d3.select("#skip")
.on("click", finalChord);
// Order of steps when clicking button
d3.select("#clicker")
.on("click", function(e){
if(counter == 1) Draw1();
else if(counter == 2) Draw2();
else if(counter == 3) Draw3();
else if(counter == 4) Draw4();
else if(counter == 5) Draw5();
else if(counter == 6) Draw6();
else if(counter == 7) Draw7();
else if(counter == 8) Draw8();
else if(counter == 9) Draw9();
else if(counter == 10) Draw10();
else if(counter == 11) Draw11();
else if(counter == 12) Draw12();
else if(counter == 13) Draw13();
else if(counter == 14) Draw14();
else if(counter == 15) finalChord();
counter = counter + 1;
});
function Draw1() {};
function Draw2() {};
function Draw3() {};
function Draw4() {};
function Draw5() {};
function Draw6() {};
function Draw7() {};
function Draw8() {};
function Draw9() {};
function Draw10() {};
function Draw11() {};
function Draw12() {};
function Draw13() {};
function Draw14() {};
function finalChord() {};
Before defining those draw functions, we will need some helper functions.
fade(opacity)
fades the chord into certain opacity level. endall(transition, callback)
will call the callback function when a transition ends. changeTopText
and changeBottonText
will update the content of the explaination text. stopClicker
will disable the clicker button. runProgressBar
will display a progress bar when animation is ongoing.
// Returns an event handler for fading a given chord group
function fade(opacity) {
return function(d, i) {
svg.selectAll("path.chord")
.filter(function(d) { return d.source.index != i && d.target.index != i; })
.transition()
.style("stroke-opacity", opacity)
.style("fill-opacity", opacity);
};
}; // fade
// Calls a function only after the total transition ends
function endall(transition, callback) {
var n = 0;
transition
.each(function() { ++n; })
.each("end", function() { if (!--n) callback.apply(this, arguments); });
}; // endall
// Transition the top circle text
function changeTopText (newText, loc, delayDisappear, delayAppear, finalText, xloc, w) {
// If finalText is not provided, it is not the last text of the Draw step
if(typeof(finalText)==='undefined') finalText = false;
if(typeof(xloc)==='undefined') xloc = 0;
if(typeof(w)==='undefined') w = 350;
middleTextTop
// Current text disappear
.transition().delay(700 * delayDisappear).duration(700)
.attr('opacity', 0)
// New text appear
.call(endall, function() {
middleTextTop.text(newText)
.attr("y", -24*loc + "px")
.attr("x", xloc + "px")
.call(wrap, w);
})
.transition().delay(700 * delayAppear).duration(700)
.attr('opacity', 1)
.call(endall, function() {
if (finalText == true) {
d3.select("#clicker")
.text(buttonTexts[counter-2])
.style("pointer-events", "auto")
.transition().duration(400)
.style("border-color", "#363636")
.style("color", "#363636");
};
});
}; // changeTopText
// Transition the bottom circle text
function changeBottomText (newText, loc, delayDisappear, delayAppear) {
middleTextBottom
// Current text disappear
.transition().delay(700 * delayDisappear).duration(700)
.attr('opacity', 0)
// New text appear
.call(endall, function() {
middleTextBottom.text(newText)
.attr("y", 24*loc + "px")
.call(wrap, 350);
})
.transition().delay(700 * delayAppear).duration(700)
.attr('opacity', 1);
;} // changeTopText
// Stop clicker from working
function stopClicker() {
d3.select("#clicker")
.style("pointer-events", "none")
.transition().duration(400)
.style("border-color", "#D3D3D3")
.style("color", "#D3D3D3");
};// stopClicker
// Run the progress bar during an animation
function runProgressBar(time) {
// Make the progress div visible
d3.selectAll("#progress")
.style("visibility", "visible");
// Linearly increase the width of the bar
// After it is done, hide div again
d3.selectAll(".prgsFront")
.transition().duration(time).ease("linear")
.attr("width", prgsWidth)
.call(endall, function() {
d3.selectAll("#progress")
.style("visibility", "hidden");
});
// Reset to zero width
d3.selectAll(".prgsFront")
.attr("width", 0);
}; // runProgressBar
In the first scene, we will fade away the arc and update the explaination text.
At the end of scene 1, we can see that the text on the main button has been changed to "OK".
First of all, we will have to disable the click button and start the progress bar. This can be achieved by calling stopClicker()
and runProgressBar(time=700*11)
. time
parameter in runProgressBar
should be as same as the duration of the animation.
To update the explaination text, we will need to call changeTopText
and changeBottomText
To fade away the arcs, we modify their opacity to 0 and then remove them when the transition has ended.
function Draw1(){
// First disable click event on clicker button
stopClicker();
// Show and run the progressBar
runProgressBar(time=700*11);
changeTopText(newText = "These days most people switch phones every few years. " +
"Some people stay loyal, but many also switch to a different phone brand...",
loc = 4/2, delayDisappear = 0, delayAppear = 1);
changeTopText(newText = "In the next few steps I would like to introduce you to the flows of people between the phone brands ",
loc = 8/2, delayDisappear = 9, delayAppear = 10, finalText = true);
changeBottomText(newText = "Let's start by drawing out the division of the 1846 respondents, that have had at least 2 phones, among the biggest 7 brands ",
loc = 1/2, delayDisappear = 0, delayAppear = 10);
// Remove arcs again
d3.selectAll(".arc")
.transition().delay(9*700).duration(2100)
.style("opacity", 0)
.each("end", function() {d3.selectAll(".arc").remove();});
}; // Draw1
Other scenes can be implemented in similar way.
//////////////////////////////////////////////////////////
//Introduction
///////////////////////////////////////////////////////////
function Draw1(){
// First disable click event on clicker button
stopClicker();
// Show and run the progressBar
runProgressBar(time=700*11);
changeTopText(newText = "These days most people switch phones every few years. " +
"Some people stay loyal, but many also switch to a different phone brand...",
loc = 4/2, delayDisappear = 0, delayAppear = 1);
changeTopText(newText = "In the next few steps I would like to introduce you to the flows of people between the phone brands ",
loc = 8/2, delayDisappear = 9, delayAppear = 10, finalText = true);
changeBottomText(newText = "Let's start by drawing out the division of the 1846 respondents, that have had at least 2 phones, among the biggest 7 brands ",
loc = 1/2, delayDisappear = 0, delayAppear = 10);
// Remove arcs again
d3.selectAll(".arc")
.transition().delay(9*700).duration(2100)
.style("opacity", 0)
.each("end", function() {d3.selectAll(".arc").remove();});
}; // Draw1
//////////////////////////////////////////////////////////
//Show Arc of Apple
//////////////////////////////////////////////////////////
function Draw2(){
// First disable click event on clicker button
stopClicker();
// Show and run the progressBar
runProgressBar(time=700*2);
// Initialize all arcs but only show the Apple arc (d.index = 0)
g.append("svg:path")
.style("stroke", function(d) { return fill(d.index); })
.style("fill", function(d) { return fill(d.index); })
.transition().duration(700)
.attr("d", arc)
.attrTween("d", function(d) {
if(d.index == 0) {
var i = d3.interpolate(d.startAngle, d.endAngle);
return function(t) {
d.endAngle = i(t);
return arc(d);
}
}
});
// Show the tick around the Apple arc
d3.selectAll("g.group").selectAll("line")
.transition().delay(700).duration(1000)
.style("stroke", function(d, i, j) {return j ? 0 : "#000"; });
// Add the labels for the %'s at Apple
d3.selectAll("g.group").selectAll(".tickLabels")
.transition().delay(700).duration(2000)
.attr("opacity", function(d, i, j) {return j ? 0 : 1; });
// Show the Apple name
d3.selectAll(".titles")
.transition().duration(2000)
.attr("opacity", function(d, i) {return d.index ? 0 : 1; });
// Switch text
changeTopText(newText = "According to the survey 19% owns an iPhone as their main phone",
loc = 1/2, delayDisappear = 0, delayAppear = 1, finalText = true);
changeBottomText(newText = "",
loc = 0/2, delayDisappear = 0, delayAppear = 1) ;
}; // Draw2
///////////////////////////////////////////////////////////
//Draw the other arcs as well
//////////////////////////////////////////////////////////
function Draw3(){
// First disable click event on clicker button
stopClicker();
var arcDelay = [0,1,2,12,13,23,33,34,35,40,47];
// Show and run the progressBar
runProgressBar(time=700*(arcDelay[(arcDelay.length-1)]+1));
// Fill in the other arcs
svg.selectAll("g.group").select("path")
.transition().delay(function(d, i) { return 700*arcDelay[i];}).duration(1000)
.attrTween("d", function(d) {
if(d.index != 0) {
var i = d3.interpolate(d.startAngle, d.endAngle);
return function(t) {
d.endAngle = i(t);
return arc(d);
}
}
});
// Make the other strokes black as well
svg.selectAll("g.group")
.transition().delay(function(d,i) { return 700*arcDelay[i]; }).duration(700)
.selectAll("g").selectAll("line").style("stroke", "#000");
// Same for the %'s
svg.selectAll("g.group")
.transition().delay(function(d,i) { return 700*arcDelay[i]; }).duration(700)
.selectAll("g").selectAll("text").style("opacity", 1);
// And the Names of each Arc
svg.selectAll("g.group")
.transition().delay(function(d,i) { return 700*arcDelay[i]; }).duration(700)
.selectAll("text").style("opacity", 1);
// Change the text of the top section inside the circle accordingly
// HTC
changeTopText(newText = "HTC has 5% of the market share",
loc = 6/2, delayDisappear = 0, delayAppear = arcDelay[2]);
// LG
changeTopText(newText = "LG has almost 5% of the market",
loc = 6/2, delayDisappear = arcDelay[3], delayAppear = arcDelay[4]);
// Samsung
changeTopText(newText = "Samsung has the biggest share by far, with 38% of respondents using a Samsung as their main phone",
loc = 3/2, delayDisappear = (arcDelay[5]-1), delayAppear = arcDelay[5]);
// Sony
changeTopText(newText = "Sony has slightly more than 4% share",
loc = 4/2, delayDisappear = arcDelay[6], delayAppear = (arcDelay[8]-1));
// 100%
changeTopText(newText = "Together that sums up to 100%",
loc = 1/2, delayDisappear = (arcDelay[9]-1), delayAppear = arcDelay[9]);
// Chord intro
changeTopText(newText = "This circle shows how the respondents are currently divided between the brands",
loc = 8/2, delayDisappear = (arcDelay[10]-1), delayAppear = arcDelay[10], finalText = true);
// Change the text of the bottom section inside the circle accordingly
// Huawei
changeBottomText(newText = "Huawei came from practically no share in 2013 to 2.4% in 2014 thereby taking its place in the biggest 7 brands in the Netherlands",
loc = -2/2, delayDisappear = 0, delayAppear = arcDelay[2]);
// Nokia
changeBottomText(newText = "Nokia is still owned by 15% of the respondents. However practically all of these phones are ordinary phones, not smartphones",
loc = -1/2, delayDisappear = arcDelay[3], delayAppear = arcDelay[4]);
// Other
changeBottomText(newText = "Brands combined in \"Other\" are Blackberry, Motorola, Google Nexus and Operator branded",
loc = -1/2, delayDisappear = (arcDelay[5]-1), delayAppear = (arcDelay[8]-1));
// Chord intro
changeBottomText(newText = "Now we're going to look at how these respondents flowed from their previous phone to their present one",
loc = 1/2, delayDisappear = (arcDelay[9]-1), delayAppear = arcDelay[10]);
}; // Draw3
///////////////////////////////////////////////////////////
//Show the chord between Samsung and Nokia
//////////////////////////////////////////////////////////
function Draw4(){
// First disable click event on clicker button
stopClicker();
// Show and run the progressBar
runProgressBar(time=700*2);
// Samsung and Nokia intro text
changeTopText(newText = "First, let's only look at the respondents that now own a Samsung, but whose previous phone was a Nokia and vice versa",
loc = 5, delayDisappear = 0, delayAppear = 1, finalText = true);
// Bottom text disappear
changeBottomText(newText = "",
loc = 0, delayDisappear = 0, delayAppear = 1);
// Make the non Samsung & Nokia arcs less visible
svg.selectAll("g.group").select("path")
.transition().duration(1000)
.style("opacity", function(d) {
if(d.index != 4 && d.index != 5) {return opacityValue;}
});
// Make the other strokes less visible
d3.selectAll("g.group").selectAll("line")
.transition().duration(700)
.style("stroke",function(d,i,j) {if (j == 5 || j == 4) {return "#000";} else {return "#DBDBDB";}});
// Same for the %'s
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".tickLabels").style("opacity",function(d,i,j) {if (j == 5 || j == 4) {return 1;} else {return opacityValue;}});
// And the Names of each Arc
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".titles").style("opacity", function(d) { if(d.index == 4 || d.index == 5) {return 1;} else {return opacityValue;}});
// Show only the Samsung Nokia chord
chords.transition().duration(2000)
.attr("opacity", function(d, i) {
if(d.source.index == 5 && d.target.index == 4)
{return opacityValueBase;}
else {return 0;}
});
};// Draw4
//////////////////////////////////////////////////////////////////////////
function Draw5(){
// First disable click event on clicker button
stopClicker();
// Show and run the progressBar
runProgressBar(time=700*2);
// Samsung and Nokia text
changeTopText(newText = "On the left, touching the arc of Samsung, we can see that the chord runs from 17% to almost 26%. Which is a thickness spanning 9%",
loc = 5, delayDisappear = 0, delayAppear = 1, finalText = true);
// Make the non Samsung & Nokia arcs less visible
svg.selectAll("g.group").select("path")
.transition().duration(1000)
.style("opacity", opacityValue);
// Show only the Samsung Nokia part at Samsung
var arcSamsung = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.startAngle(4.040082626337902)
.endAngle(4.561777856121815);
svg.append("path")
.attr("class","SamsungToNokiaArc")
.attr("d", arcSamsung)
.attr("fill", colors[5])
.style('stroke', colors[5]);
repeat();
// Repeatedly let an arc change colour
function repeat() {
d3.selectAll(".SamsungToNokiaArc")
.transition().duration(700)
.attr("fill", "#9FA6D0")
.style('stroke', "#9FA6D0")
.transition().duration(700)
.attr("fill", colors[5])
.style('stroke', colors[5])
.each("end", repeat)
;
};
};// Draw5
//////////////////////////////////////////////////////////////////////////
function Draw6(){
// First disable click event on clicker button
stopClicker();
// Show and run the progressBar
runProgressBar(time=700*2);
// Samsung and Nokia text
changeTopText(newText = "These 9% of the respondents now own a Samsung and by following the chord we can see what brand they used to own, which in this case, is Nokia",
loc = 5, delayDisappear = 0, delayAppear = 1, finalText = true);
// Show only the Samsung Nokia part at Nokia
var arcNokia = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.startAngle(2.837816067671451)
.endAngle(2.9104595910835127);
svg.append("path")
.attr("class","NokiaToSamsungArc")
.attr("d", arcNokia)
.attr("opacity", 0)
.attr("fill", colors[4])
.transition().duration(700)
.attr("opacity", 1)
.attr("stroke", colors[4]);
};// Draw6
//////////////////////////////////////////////////////////////////////////
function Draw7(){
// First disable click event on clicker button
stopClicker();
// Show and run the progressBar
runProgressBar(time=700*11);
// Samsung and Nokia text
changeTopText(newText = "At the Nokia side, the arc is much thinner, only spanning 1.2% (of respondents)",
loc = 4, delayDisappear = 0, delayAppear = 1);
changeTopText(newText = "These 1.2% now own a Nokia, but by following the chord we can see that they had a Samsung before",
loc = 4, delayDisappear = 9, delayAppear = 10, finalText = true);
// Stop the color changing on the Samsung side
d3.selectAll(".SamsungToNokiaArc")
.transition().duration(700)
.attr("fill", colors[5])
.style("stroke", colors[5]);
// Repeatedly let an arc change colour
repeat();
function repeat() {
d3.selectAll(".NokiaToSamsungArc")
.transition().duration(700)
.attr("fill", "#99D2E9")
.style('stroke', "#99D2E9")
.transition().duration(700)
.attr("fill", colors[4])
.style("stroke", colors[4])
.each("end", repeat)
;
};
};// Draw7
//////////////////////////////////////////////////////////////////////////
function Draw8(){
// First disable click event on clicker button
stopClicker();
// Show and run the progressBar
runProgressBar(time=700*11);
// Samsung and Nokia text
changeTopText(newText = "Since the chord is much wider at the Samsung side, Samsung has taken a lot more clients from Nokia than Nokia managed to take from Samsung",
loc = 5, delayDisappear = 0, delayAppear = 1);
changeTopText(newText = "Therefore, the chord is the color of Samsung blue, since Samsung has the net gain from the exchange of people between Nokia and Samsung",
loc = 5, delayDisappear = 9, delayAppear = 10, finalText = true);
// Stop the colour changing on the Nokia side
d3.selectAll(".NokiaToSamsungArc")
.transition().duration(700)
.attr("fill", colors[4])
.style("stroke", colors[4]);
};// Draw8
///////////////////////////////////////////////////////////
//Show Loyalty hills
//////////////////////////////////////////////////////////
function Draw9(){
// First disable click event on clicker button
stopClicker();
// Show and run the progressBar
runProgressBar(time=700*20);
// Samsung Loyal text
changeTopText(newText = "There are also people that stay loyal and did not switch brands between their previous and current phone",
loc = 4/2, delayDisappear = 0, delayAppear = 1, finalText = false, xloc=-50, w=300);
changeTopText(newText = "These loyal respondents are represented by the hills at each brand",
loc = 3/2, delayDisappear = 9, delayAppear = 10, finalText = false, xloc=-50, w=300);
changeTopText(newText = "You can also envision this as a chord beginning and ending on itself",
loc = 2/2, delayDisappear = 18, delayAppear = 19, finalText = true, xloc=-50, w=300);
// Remove the arcs
d3.selectAll(".NokiaToSamsungArc")
.transition().duration(2000)
.attr("opacity", 0)
.each("end", function() {d3.selectAll(".NokiaToSamsungArc").remove();});
d3.selectAll(".SamsungToNokiaArc")
.transition().duration(2000)
.attr("opacity", 0)
.each("end", function() {d3.selectAll(".SamsungToNokiaArc").remove();});
// Show only the loyal chords
chords.transition().duration(2000)
.attr("opacity", function(d, i) {
if(d.source.index == 0 && d.target.index == 0) {return opacityValueBase;}
else if(d.source.index == 1 && d.target.index == 1) {return opacityValueBase;}
else if(d.source.index == 2 && d.target.index == 2) {return opacityValueBase;}
else if(d.source.index == 3 && d.target.index == 3) {return opacityValueBase;}
else if(d.source.index == 4 && d.target.index == 4) {return opacityValueBase;}
else if(d.source.index == 5 && d.target.index == 5) {return opacityValueBase;}
else if(d.source.index == 6 && d.target.index == 6) {return opacityValueBase;}
else if(d.source.index == 7 && d.target.index == 7) {return opacityValueBase;}
else {return 0;}
});
// Show all ticks and texts again
// Ticks
d3.selectAll("g.group").selectAll("line")
.transition().duration(700)
.style("stroke", "#000");
// Same for the %'s
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".tickLabels").style("opacity", 1);
// And the Names of each Arc
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".titles").style("opacity", 1);
};// Draw9
//////////////////////////////////////////////////////////////////////////
function Draw10(){
// First disable click event on clicker button
stopClicker();
// Show and run the progressBar
runProgressBar(time=700*11);
changeTopText(newText = "10% of respondents have a Nokia right now, but also used to own a Nokia before that",
loc = 7/2, delayDisappear = 0, delayAppear = 1);
changeTopText(newText = "Seeing that currently Nokia is owned by almost 16% of respondents, this means "+
"that about 2/3 of current Nokia owners are people who stayed loyal",
loc = 7/2, delayDisappear = 9, delayAppear = 10, finalText = true);
// Show only the Nokia Loyal arc
var arcNokia = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius)
.startAngle(2.048671976860533)
.endAngle(2.6694216777820063);
svg.append("path")
.attr("class","NokiaLoyalArc")
.attr("d", arcNokia)
.attr("opacity", 1)
.attr("stroke", colors[4])
.attr("fill", colors[4]);
// Repeatedly let an arc change colour
repeat();
function repeat() {
d3.selectAll(".NokiaLoyalArc")
.transition().duration(700)
.attr("fill", "#99D2E9")
.style('stroke', "#99D2E9")
.transition().duration(700)
.attr("fill", colors[4])
.style("stroke", colors[4])
.each("end", repeat);
};
// Show only the Nokia loyal chord
chords.transition().duration(2000)
.attr("opacity", function(d, i) {
if(d.source.index == 4 && d.target.index == 4) {return opacityValueBase;}
else {return 0;}
});
// Make the other strokes less visible
d3.selectAll("g.group").selectAll("line")
.transition().duration(700)
.style("stroke",function(d,i,j) {if (j == 4) {return "#000";} else {return "#DBDBDB";}});
// Same for the %'s
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".tickLabels").style("opacity",function(d,i,j) {if (j == 4) {return 1;} else {return opacityValue;}});
// And the Names of each Arc
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".titles").style("opacity", function(d) { if(d.index == 4) {return 1;} else {return opacityValue;}});
};// Draw10
//////////////////////////////////////////////////////////
//Show all chords that are connected to Apple
//////////////////////////////////////////////////////////
function Draw11(){
// First disable click event on clicker button
stopClicker();
// Show and run the progressBar
runProgressBar(time=700*2);
changeTopText(newText = "Here are all the chords for those respondents that currently own "+
"an iPhone or that used to own an iPhone",
loc = 3/2, delayDisappear = 0, delayAppear = 1, finalText = true, xloc=-80, w=200);
// Remove the Nokia arc
d3.selectAll(".NokiaLoyalArc")
.transition().duration(1000)
.attr("opacity", 0)
.each("end", function() {d3.selectAll(".NokiaLoyalArc").remove();});
// Only show the chords of Apple
chords.transition().duration(2000)
.attr("opacity", function(d, i) {
if(d.source.index == 0 || d.target.index == 0) {return opacityValueBase;}
else {return 0;}
});
// Highlight arc of Apple
svg.selectAll("g.group").select("path")
.transition().duration(2000)
.style("opacity", function(d) {
if(d.index != 0) {return opacityValue;}
});
// Show only the ticks and text at Apple
// Make the other strokes less visible
d3.selectAll("g.group").selectAll("line")
.transition().duration(700)
.style("stroke",function(d,i,j) {if (j == 0) {return "#000";} else {return "#DBDBDB";}});
// Same for the %'s
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".tickLabels").style("opacity",function(d,i,j) {if (j == 0) {return 1;} else {return opacityValue;}});
// And the Names of each Arc
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".titles").style("opacity", function(d) { if(d.index == 0) {return 1;} else {return opacityValue;}});
};// Draw11
function Draw12(){
// First disable click event on clicker button
stopClicker();
// Show and run the progressBar
runProgressBar(time=700*11);
changeTopText(newText = "One thing that stands out for Apple is that all chords connected to " +
"Apple are the color of the Apple arc: grey",
loc = 3/2, delayDisappear = 0, delayAppear = 1, finalText = false, xloc=-80, w=210);
changeTopText(newText = "This means that Apple has always had the net gain. " +
"They received more customers from other brands than they lost to them",
loc = 3/2, delayDisappear = 9, delayAppear = 10, finalText = true, xloc=-80, w=210);
};// Draw12
function Draw13(){
// First disable click event on clicker button
stopClicker();
// Show and run the progressBar
runProgressBar(time=700*11);
changeTopText(newText = "Even more so, apart from the chord to Samsung, all other chords are extremely narrow at the other end from Apple",
loc = 3/2, delayDisappear = 0, delayAppear = 1, finalText = false, xloc=-80, w=200);
changeTopText(newText = "This means that Apple has lost virtually nobody to any other brand",
loc = 3/2, delayDisappear = 9, delayAppear = 10, finalText = true, xloc=-80, w=200);
// Repeatedly let specific chords change colour
repeat();
function repeat() {
chords
.transition().duration(1000)
.style("opacity",function (d){
if(d.source.index == 0) {
if(d.target.index == 0 || d.target.index == 5) {return opacityValueBase;}
else {return 0.2;}
} else {return 0;}
})
.transition().duration(1000)
.style("opacity",function (d){
if(d.source.index == 0) {return opacityValueBase;}
else {return 0;}
})
.each("end", repeat);
};
};// Draw13
function Draw14(){
// First disable click event on clicker button
stopClicker();
// Show and run the progressBar
// runProgressBar(time=700*2);
changeTopText(newText = "Thank you for staying with me so far! After these examples I think you're absolutely " +
"ready to face the full impact of all chords simultaneously",
loc = 8/2, delayDisappear = 0, delayAppear = 1, finalText = true);
changeBottomText(newText = "I'm looking forward to hearing about the insights that you have discovered on your own",
loc = 3/2, delayDisappear = 0, delayAppear = 1);
// Only show the chords of Apple
chords.transition().duration(1000)
.style("opacity", 0.1);
// Hide all the text
d3.selectAll("g.group").selectAll("line")
.transition().duration(700)
.style("stroke","#DBDBDB");
// Same for the %'s
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".tickLabels").style("opacity",0.4);
// And the Names of each Arc
svg.selectAll("g.group")
.transition().duration(700)
.selectAll(".titles").style("opacity",0.4);
};// Draw14
///////////////////////////////////////////////////////////
//Draw the original Chord diagram
///////////////////////////////////////////////////////////
// Go to the final bit
function finalChord() {
// Remove button
d3.select("#clicker")
.style("visibility", "hidden");
d3.select("#skip")
.style("visibility", "hidden");
d3.select("#progress")
.style("visibility", "hidden");
// Remove texts
changeTopText(newText = "",
loc = 0, delayDisappear = 0, delayAppear = 1);
changeBottomText(newText = "",
loc = 0, delayDisappear = 0, delayAppear = 1);
// Create arcs or show them, depending on the point in the visual
if (counter <= 4 ) {
g.append("svg:path")
.style("stroke", function(d) { return fill(d.index); })
.style("fill", function(d) { return fill(d.index); })
.attr("d", arc)
.style("opacity", 0)
.transition().duration(1000)
.style("opacity", 1);
} else {
// Make all arc visible
svg.selectAll("g.group").select("path")
.transition().duration(1000)
.style("opacity", 1);
};
// Make mouse over and out possible
d3.selectAll(".group")
.on("mouseover", fade(.02))
.on("mouseout", fade(.80));
// Show all chords
chords.transition().duration(1000)
.style("opacity", opacityValueBase);
// Show all the text
d3.selectAll("g.group").selectAll("line")
.transition().duration(100)
.style("stroke","#000");
// Same for the %'s
svg.selectAll("g.group")
.transition().duration(100)
.selectAll(".tickLabels").style("opacity",1);
// And the Names of each Arc
svg.selectAll("g.group")
.transition().duration(100)
.selectAll(".titles").style("opacity",1);
};// finalChord
At this point, if you see something similar to the visualization in the link below:
http://bl.ocks.org/nbremer/raw/94db779237655907b907/
Congratulations, you have completed the last task!


Filled Artichoke
May 9, 2020
This is an improved version of my mom’s recipe. I’ve never had this recipe in a restaurant, hence the post. Artichokes are so flavorful, you can do few other magical stuff with them, I hope I’ll have time to write those recipes as well. Enjoy!
Step 0: Ingredients
Below is the standard recipe, but you can be more creative with the filling and the broth.
- 4 artichokes (the leaves on, duh!)
- 4 cloves of garlic
- 2 lemons
- A handful of chopped dill
- 1 cup of your favorite kind of rice
- 1 white onion
- Half tablespoon red pepper paste
- Half tablespoon tomato paste
- 2 tablespoon olive oil
- Salt, pepper, thyme or oregano, cumin.
Step 1: Simmering
When you take the artichokes out do not forget to wash them with cold water so that you do not burn your hands.
Boil water, add a juice of a lemon and simmer artichokes lid on in this mix for 30 minutes.
Step 2: Cleaning
The center has baby leaves that are more like spikes or thorn.
Be careful do not put a whole there.
Using a spoon, we cut the centerpiece of the artichoke. . Carve this area with your spoon.
Step 3: Preparing Filling
In a bowl, mix rice, chopped onion, dill (save some for dressing), spices, the pastes, and olive oil. This is where you can be creative. If you are an omnivore you can add ground meat.
Step 4: Filling the Artichoke
You can add more tomato paste to the broth.
Fill the inside of each leave and the heart of the artichoke with the filling. But a clove of garlic and lemon ring on top of the heart.
Add (prefarebly boiling) water and a juice of a half lemon to the bowl, stir it well. Pour this water/lemon juice/paste broth on top of each artichoke.
Step 5: Cooking
Put them on high heat when the broth starts boiling turn it on low and simmer it for 20 minutes. If the rice is soft, they should be ready.
Step 6: Serving
Serve with yogurt and extra plate for the leave wastes. Use leaves as spoons to eat the filling. Use your lower teeth to bite off the meaty part of each leaves.


To get started, add other users below. When you add a user, SpotiMatch loads their public playlists and adds the songs and artists they like to the list below. The progress indicator above shows what's currently being processed.
Click a user to select which of their playlists are included in the artist and track matches below.
| Users |
You can find someone's Profile Link by going to their profile on Spotify, clicking the ... button below their name, and clicking Copy Profile Link.
These are the artists whose tracks are in the public playlists of the users in the list above. Click an artist to see which users like them, and which tracks those users like.
| Artist | Tracks | Users |


Objects as Services
Sometimes you will want to create an object yourself and register that in the container for use as a particular service type.
This is done either by creating an ObjectTarget and registering it in a target container, or via the extension method(s) RegisterObject.
This type of registration is often thought of as a singleton, but it's more accurate to think of it as a 'constant' service - because, from the moment the registration is created, the object reference is already known and doesn't change. Singletons are different because the container creates the instance for you.
We don't need many examples for this, first - this is how you'd register an object against its runtime type:
var container = new Container();
var service = new MyService();
container.RegisterObject(service);
Assert.Same(service, container.Resolve<MyService>());
And if you want to register it against a different type, the following example shows one way, with another shown in comments:
var container = new Container();
var service = new MyService();
container.RegisterObject<IMyService>(service);
// NOTE: Could also use:
// container.RegisterObject(service, typeof(IMyService)
Assert.Same(service, container.Resolve<IMyService>());
That's all there is to it, really. Although before we move on, we should take a quick look at how object-based services interact with scopes.
Objects in Scopes
A scope (obtained either by using ScopedContainer or through a IContainerScope returned from a container's CreateScope method) will by default dispose of any disposable objects it creates when it is disposed.
If those objects are obtained from an ObjectTarget, however, then no scope will ever touch them - because you created them, therefore you will also typically dispose them.
Here's an example, using the aforementioned ScopedContainer:
var disposableObj = new DisposableType();
using (var container = new ScopedContainer())
{
container.RegisterObject(disposableObj);
var result = container.Resolve<DisposableType>();
Assert.Same(disposableObj, result);
}
// Should NOT be disposed
Assert.False(disposableObj.Disposed);
As the last assertion proves - the supplied object is left untouched by the scoped container.
You can change this behaviour, however, by providing a different ScopeBehaviour when creating the target (directly registering with
the RegisterObject
method):
var disposableObj = new DisposableType();
using (var container = new ScopedContainer())
{
container.RegisterObject(disposableObj, scopeBehaviour: ScopeBehaviour.Explicit);
var result = container.Resolve<DisposableType>();
Assert.Same(disposableObj, result);
}
// Should be disposed
Assert.True(disposableObj.Disposed);
Notice the scopeBehaviour:
named argument on the 4th line. To enable the correct disposal behaviour, you must use Explicit
because you need the scope to know that only one instance should ever be tracked per scope.
Warning
If you pass Implicit
then disposal will still work, although there's a risk that the object will be tracked by the scope multiple times
and, therefore, could be disposed multiple times.
This behaviour is unintentional and will be prevented in a future release by raising an exception if the Implicit
behaviour is set on an ObjectTarget.
Child scopes
For the seasoned IOC container-user the last phrase of the previous section - 'one instance should ever be tracked per scope' - will likely be setting alarm bells ringing.
As with Singletons, Rezolver knows that a service implemented by a constant object should only ever be tracked in the root-most scope so that the disposal of a child scope does not also cause the disposal of the object.
To demonstrate this, another test, which uses a ScopedContainer as before, but which resolves the object only through a child scope which is then immediately disposed. The test shows that the object, however, is not disposed of until the root-most scope - the ScopedContainer - is disposed:
var disposableObj = new DisposableType();
using (var container = new ScopedContainer())
{
container.RegisterObject(disposableObj, scopeBehaviour: ScopeBehaviour.Explicit);
var result = container.Resolve<DisposableType>();
Assert.Same(disposableObj, result);
}
// Should be disposed
Assert.True(disposableObj.Disposed);
Next steps
Feel free to explore the table of contents or head back to the main service registration overview to explore more features of Rezolver.


In the words of Fabian Dattner:
"The aim of Homeward Bound has always been to identify and foster outstanding leadership potential in STEMM... It is no accident that we end up in Antarctica, as it is part of the vision. It is where we can see the impact of our crisis of leadership and inaction first-hand. It is sensitive and challenging, awe-inspiring and motivating, and I can think of no more fitting experience for a group of leaders."
Laubeuf Fjord with Webb Island by Vincent van Zeijst.


This is a research study about how people make energy-related decisions.
It will last no more than 60 minutes.
You will get paid for every segment that you complete:
- Participation pay ($0.50)
- Quiz (up to $0.30 depending on how many quiz questions you'll answer correctly).
- Game (up t0 $2.00, but your pay will vary depending on your and other's decisions).
- Survey ($0.20)
Please LEAVE THIS PAGE OPEN!
Please note, this game will require your FULL ATTENTION, as the game rules are complex. Also, the game has validity checks to make sure you are not a robot.
You will receive a COMPLETION CODE at the end of the game. Copy and paste it here before you close this page. It is needed for you to receive your payment.
Please click here to proceed to our consent form and game: link.


{% extends 'layout.html' %} {% set pageHeading = "You may be eligible" %} {% block pageTitle %} {{pageHeading}} | {{serviceName}} {% endblock %} {% block beforeContent %} {% endblock %} {% block content %}
Based on your answers, you may be eligible for a Test and Trace Support Payment or a discretionary payment from your local authority.
Your local authority will confirm whether you are eligible when you apply.
If you are caught committing fraud to claim this payment, you will face prosecution and the money will be recovered from you.
Examples of fraud could include deliberately giving false information, failing to self-isolate or claiming the payment more than once for the same self-isolation period.


HEADER
HERO
CLIENTS
ABOUT MYSELF
ACHIEVEMENTS
SKILLS
LATEST WORKS
JOB HISTORY
SERVICE OFFERS
TESTIMONIALS
CONTACT ME
BACK TO TOP


|
141. Jumping Joe Time Limit: 0.1 sec, Memory Limit: 1 MB Joe is a frog who likes to jump a lot. In fact, that's all he does: he jumps forwards and backwards on the integer axis (a straight line on which all the integer numbers, both positive and negative are marked). At first, Joe sits next to the point marked with 0. From here, he can jump in the positive or the negative direction a distance equal to either x1 or x2. From the point where he arrived, he can jump again a distance equal to x1 or x2, in the positive or the negative direction and so on.. Joe wants to arrive next to the point marked with the number P, after exactly K jumps.  Input The input will contain four integers: x1, x2 (0 < x1 , x2 < 40 000), P (-40 000 < P < 40 000) and K (0 <= K < 2 000 000 000), separated by blanks. Output The first line of output will contain the word "YES", in case Joe can reach the point marked with P after exactly K jumps, or "NO", otherwise. In case the answer is "YES", the next line should contain four integers, separated by blanks: P1 , N1 , P2 and N2. P1 is the number of times Joe jumped in the positive direction a distance equal to x1. N1 is the number of times Joe jumped in the negative direction a distance equal to x1. P2 is the number of times Joe jumped in the positive direction a distance equal to x2. N2 is the number of times Joe jumped in the negative direction a distance equal to x2. In other words, you should find four non-negative integers, so that: P1*x1 - N1*x1 +
P2*x2 - N2*x2 = P
In case there are more quadruples (P1,N1,P2,N2) which are solutions for the problem, you may print any of them. Sample Input 2 3 -1 12 Sample Output YES 1 0 5 6 | ||||||
|


I Started Rap Music 22 Years Ago Not To Be Famous, But To Be Heard By all – Okyeame Kwame Discloses
by vanessa nordziGhanaian musician, songwriter, creative director and entrepreneur Kwame Nsiah-Apau, known by his stage name Okyeame Kwame and nicknamed Rap Doctor, has shared some insight on how he entered into the music industry 22 years ago.
According to Okyeame Kwame in an Instagram post , he started with the Hip life genre of music because he had passion to share his talent with the world.
Okyeame Kwame explained that, he didn’t want to be a celebrity, an icon or a star but all he wanted was for his music to be played on the radio even if it’s just once.
But as fate would have it, he has gotten more attention and awards than he had anticipated.
Okyeame Kwame further stated that, by just doing what he loves best, he has impacted Ghanaians in ways he didn’t think was possible. He also thanked his fans for appreciating him, criticising his style of music and helping him reach where he is now.
The “rap doctor” also appreciated the squad he started with. He mentioned the likes of Dasebere Dwamena, OmanHene Pozo, Michael Dwamena amongst others for helping him discover himself.
In his final statement, Okyeame Kwame said that as his voice has been heard by millions of Ghanaians, he now wants to be part of anything that will promote Ghana to the world.
Read his full post below;


from __future__ import annotations
import asyncio
from datetime import datetime
from typing import (
TYPE_CHECKING,
Union,
Optional,
List,
Dict,
Any
)
import discord
from .Base import DatabaseChecker
from .Punishments import Punisher
if TYPE_CHECKING:
from .Punishments import Punishment
from discord.ext import commands
__all__ = ("UnbanFailure", "BanManager")
[docs]class UnbanFailure(Exception):
"""Raises an exception when the user tries to unban a discord.User without passing the guild."""
[docs]class BanManager(DatabaseChecker, Punisher):
"""
A BanManager that manages guild bans.
"""
__slots__ = ("bot",)
def __init__(self, bot: commands.Bot):
super().__init__([{'guild': "snowflake", 'member': "snowflake", 'reason': "string", 'timestamp': "snowflake"}],
['bans'])
self.bot = bot
self.add_event(self.on_database_connect)
[docs] async def on_database_connect(self):
self.bot.loop.create_task(self.__check_bans())
[docs] async def get_banned_members(self) -> List[Dict[str, Any]]:
"""
|coro|
This function returns all the members that are supposed to be unbanned but are banned.
:return: The list of unbanned members.
:rtype: List[Dict[str, Any]]
"""
return [x for x in await self.database.select(self.tables['bans'], [], fetchall=True)
if x["timestamp"] <= datetime.utcnow().timestamp()]
async def __check_bans(self) -> None:
"""
|coro|
A loop that ensures that members are unbanned when they need to.
:return: None
:rtype: None
"""
await self.bot.wait_until_ready()
while not self.bot.is_closed():
for banned_member in await self.get_banned_members():
guild = self.bot.get_guild(banned_member['guild'])
if guild is None:
continue
user = await self.bot.fetch_user(banned_member['member'])
if await self.unban(user, guild):
await self.call_event("on_unban", user, banned_member['reason'])
await asyncio.sleep(300)
[docs] async def punish(self, ctx: commands.Context, member: discord.Member, punishment: Punishment) -> None:
try:
self.bot.loop.create_task(
self.ban(member, punishment.punishment_reason, punishment.punishment_time.total_seconds())
)
except discord.errors.Forbidden as e:
raise e
else:
await self.call_event("on_punishment", ctx, member, punishment)
[docs] @staticmethod
async def get_ban(member: Union[discord.Member, discord.User], guild: discord.Guild) -> Optional[discord.User]:
"""
|coro|
This function returns the user object of the member if he is banned from the guild.
:param member: The banned member.
:type member: discord.Member
:param guild: The guild.
:type guild: discord.Guild
:return: The user object if found.
:rtype: Optional[discord.User]
"""
banned = await guild.bans()
for x in banned:
if x.user.id == member.id:
return x.user
[docs] async def unban(self, member: Union[discord.Member, discord.User], guild: discord.Guild = None) -> bool:
self._check_database()
if isinstance(member, discord.User) and not guild:
raise UnbanFailure("Cannot unban a discord.User without a guild.")
guild = guild if guild is not None else member.guild
await self.database.delete(self.tables['bans'], {'guild': guild.id, 'member': member.id})
if user := await self.get_ban(member, guild):
await guild.unban(user)
return True
[docs] async def ban(self,
member: discord.Member,
reason: str = "No reason provided.",
time_of_ban: Union[int, float] = 0) -> None:
"""
|coro|
Bans the member from the guild.
:param member: The member to ban.
:type member: discord.Member
:param reason: The reason of the ban.
:type reason: str
:param time_of_ban: The time of ban.
:type time_of_ban: Union[int, float]
:return: None
:rtype: None
"""
self._check_database()
await member.ban(reason=reason)
if time_of_ban <= 0:
return
await self.database.insert(self.tables['bans'], {'guild': member.guild.id,
'member': member.id,
'reason': reason,
'timestamp': datetime.utcnow().timestamp() + time_of_ban})
await asyncio.sleep(time_of_ban)
if await self.unban(member):
await self.call_event("on_unban", member, reason)


MotoGP, Lorenzo: "After the last crash I became shorter"
Jorge has ironically answered the most frequently asked questions that fans make on Google about the Mallorcan: from his favorite dish to how many hypercars he owns
by GPoneJorge has ironically answered the most frequently asked questions that fans make on Google about the Mallorcan: from his favorite dish to how many hypercars he owns


[:page partOf="features"] [:dart] final infos = { "fruits": ["apple", "orange", "lemon"], "cars": ["bmw", "audi", "honda"] }; [/dart]
Passed from the includer for showing [=infos]
[/var] [:var footer]It also includes another page:
[:include "/frag.html"/] [/var] [/include]


Password Length Inspector Settings
!Basic
!Advanced
!Export / Import
!Indicator Placement
!Inside of the password field
!Outside of the password field
!Indicator Position
!Left side
!Right side
!Attach indicator to dynamically added fields
!Enable dragging of indicator
!Enable custom password length indicator for the listed URLs?
!Adjust max-length property for password fields in HTML DOM accordingly?
!URL
!RegularExpression
1
2
!Password Length
!Add
!Notice
!Saving succeeded
!Save Settings
!Reset Settings
!Import succeeded
!Export Settings
!Import Settings


Creating and using a container
Using Rezolver is the same as with all other IOC containers:
- Create and configure the root container
- Register the services which your application needs
- Resolve services from the container
All of this setup is ultimately conducted through just a few primary types, which we'll take a brief look at now.
Core types
For all the built-in container types, Rezolver splits registration and resolving responsibilities between two interfaces:
ITargetContainer
Note
You'll notice that the constructors for the Container and ScopedContainer types (see next)
actually accept an instance of IRootTargetContainer. This is a new interface added in v1.3.2 which
marks a target container as a 'top-level' one - and supports functionality such as
covariance. IRootTargetContainer
also implies the ITargetContainer
interface.
This interface describes a registry of ITarget objects, keyed by type, describing the type of object that is to be created (and how) when a given type is requested.
It is through this interface that you setup your container with registrations, which are then later used when resolving objects.
Tip
The primary implementation of this interface that you will use in your application is TargetContainer - either created implicitly by the framework or explicitly in your own code.
IContainer
This is the interface through which we resolve objects. The interface does not expose any registration mechanisms at all (even if the classes providing the 'standard' implementations all do) - only the ability to request objects from the container.
This interface does not mandate that a container has an IRootTargetContainer
, it's simply the case
that all the provided implementations which we will discuss in the rest of this documentation do
use that interface as the source of their service registrations.
Tip
The primary implementation of this interface is ContainerBase, an abstract class which also implements the ITargetContainer interface by wrapping around the Targets property that it exposes.
As a consumer of Rezolver, however, you will be using the Container and ScopedContainer classes most of the time - which derive most of their functionality from this abstract class.
Creating a container
There are numerous ways to create an IContainer instance. The easiest, from the point of view of registering services and then resolving them, is to create an instance of the Container type. Or, if you want your root container to act as a global lifetime scope for explicitly scoped objects then you can also use ScopedContainer:
// create a standard non-scoping container
var container = new Container();
// or create a scoped container:
var container = new ScopedContainer();
All code samples assume you have added a using
statement (imports
in VB) for the Rezolver
namespace.
Once you have a local reference to either of these classes, you can start registering services via the container's ITargetContainer implementation, and resolving objects from it.
Registering services
As mentioned above, with our default implementations of IContainer, registration of services ultimately means adding targets to the container's Targets target container, associating them with service types which we will later resolve.
The core registration method for this is the Register method, which accepts an ITarget and an optional type against which the registration is to be made.
Here's an example where we register the type Foo
to be created whenever an instance of IFoo
is requested,
directly via a container's own implementation of ITargetContainer:
var container = new Container();
container.RegisterType<Foo, IFoo>();
Or, if you create a dedicated ITargetContainer that you specifically want the Container to use, only a small change is required:
var targets = new TargetContainer();
targets.RegisterType<Foo, IFoo>();
var container = new Container(targets);
Tip
The RegisterType overload instructs the container to build an instance via constructor injection.
There's too many types of registrations to cover in a few sub headings here for this - the service registration topic has more detail, with links to all the other different types of registration you can perform.
Moreover, you can browse the different topics from the table of contents on the left (or top on mobile).
Resolving services
Resolving objects from your container is done through the Resolve method which, you'll
notice, accepts an IResolveContext as its single parameter, and returns an Object
. Again, if
you're familiar with IOC containers then you're probably wondering where your strongly-typed Resolve<TService>()
method is!
Well, fear not. As with the many extension methods available on ITargetContainer, the IContainer interface (through which all resolving of objects is done) has extension methods to provide a more traditional IOC API, and these are found on the ContainerResolveExtensions static class.
The one you'll use most frequently, of course, is the Resolve<TObject>(IContainer)
method, which provides the aforementioned Resolve<TService>()
API.
So, assuming we have the container
that we've been using up till now, we would resolve an instance of MyService
simply by doing one of the following:
MyService service = container.Resolve<MyService>();
//or
MyServiceBase service = container.Resolve<MyServiceBase>();
//or
IMyService service = container.Resolve<IMyService>();
Note
The IResolveContext interface captures the context of a call to the Resolve
method, tracking the
container on which the call is originally made, whether there is an IContainerScope active for the call,
and other things besides. You will rarely use it directly in application code unless you are extending Rezolver.
These Resolve
extension methods create the IResolveContext
for a given operation on your behalf, so you never
have to worry about it.
Assuming the container can locate the service registration for the type you request, it will fetch/produce an instance of the associated object type according to the behaviour described by the ITarget which we previously registered.
If no registration is found, then an InvalidOperationException
is raised by the container.
Tip
IContainer also implements the System.IServiceProvider
interface from the .Net framework, which requires
that missing services yield a null
result instead of throwing an exception.
CanResolve/TryResolve
Sometimes you might want to attempt to resolve an object from the container, but not have an exception raised
if it cannot be found. In this case you can use the TryResolve method, which returns the
object via an out
parameter and returns a bool
indicating whether the operation succeeds.
Naturally, as with the Resolve
operation, this method has a generic overload
(TryResolve<TObject>(IContainer, out TObject)) to avoid the need for a
temporary Object
reference:
MyService result;
bool success = container.TryResolve(out result);
//success == true or false depending on registrations.
Similarly we can also introspect a container to find out if it can resolve an instance of a given type by using the CanResolve method. This method also has friendly overloads via extension methods (e.g. CanResolve<TObject>(IContainer))):
bool canResolve = container.CanResolve<MyService>();
Container Configurations and Options
For those looking to customise or extend Rezolver, many of the types are overridable. However, the ITargetContainer and IContainer implementations mentioned above also use another mechanism that provides extensibility without having to subclass them.
Note
This is an advanced topic and not one that you should have to worry about most of the time. The examples in this guide will highlight where you can use the functionality described below - this section is intended to be a high-level overview only.
There are two primary types of container configuration in Rezolver:
- Target container configuration (via implementations of ITargetContainerConfig)
- Container configuration (via implementations of IContainerConfig)
Both are very similar in that they define a method called Configure
(see
ITargetContainerConfig.Configure and
IContainerConfig.Configure) to
which is passed an ITargetContainer and, in the case of IContainerConfig, also an
IContainer.
Implementations of the interfaces can add/modify service registrations which are then used either directly by the container, or which provide more advanced registration functionality.
For example, Rezolver's automatic enumerable injection is enabled by the InjectEnumerables configuration when it configures an ITargetContainer. This configuration is actually applied to all instances of TargetContainer by default (via the DefaultConfig configuration collection) - but you can also control whether enumerable injection is enabled without having to remove the configuration from that collection, as is shown in the last enumerable example.
There is much more to be covered about configuration and options. For now - use them where this guide shows you can (e.g. to control contravariance or member binding behaviour etc), and if you want to be able to control something else this way, and can't, then just open an issue on Github.
Next Steps
- Read up on how to register services in the container.
- Alternatively, if you haven't already, take a look Rezolver's understanding of object lifetimes.


---
layout: post
title: High Noon Saloon - Wednesday April 5, 2006
date: '2006-04-05T21:00:00.000-05:00'
author: Tom Ray
tags:
modified_time: '2006-04-03T16:06:40.360-05:00'
blogger_id: tag:blogger.com,1999:blog-11319466.post-114409840034573847
blogger_orig_url: http://www.lorenzosmusic.com/2006/04/high-noon-saloon-wednesday-april-5.html
---
Dane101 Anniversary Party!
with
Dietrich Gosser
Pale Young Gentlemen
at the High Noon Saloon in Madison
9:00 pm / $5 cover 21 AND UP


Research and analysis
This study looks at issues that Gypsy, Roma and Traveller pupils face and how to improve their educational outcomes.
Ref: DFE-RR043 PDF , 2.09MB , 138 pages
If you use assistive technology (such as a screen reader) and need a version of this document in a more accessible format, please email<EMAIL_ADDRESS>. Please tell us what format you need. It will help us if you say what assistive technology you use.
PDF , 157KB , 6 pages
If you use assistive technology (such as a screen reader) and need a version of this document in a more accessible format, please email<EMAIL_ADDRESS>. Please tell us what format you need. It will help us if you say what assistive technology you use.
PDF , 457KB , 73 pages
If you use assistive technology (such as a screen reader) and need a version of this document in a more accessible format, please email<EMAIL_ADDRESS>. Please tell us what format you need. It will help us if you say what assistive technology you use.
PDF , 495KB , 10 pages
If you use assistive technology (such as a screen reader) and need a version of this document in a more accessible format, please email<EMAIL_ADDRESS>. Please tell us what format you need. It will help us if you say what assistive technology you use.
The study involves 4 strands of research activity:
Published: 28 October 2010
From: Department for Education
Part of: Education of disadvantaged children


Uses of Package
org.apache.shiro.session.mgt
-
Packages that use org.apache.shiro.session.mgt Package Description org.apache.shiro.guice org.apache.shiro.guice.web org.apache.shiro.mgt Provides the masterSecurityManager
interface and a default implementation hierarchy for managing all aspects of Shiro's functionality in an application.org.apache.shiro.session.mgt SessionManager
components supporting enterprise session management.org.apache.shiro.session.mgt.quartz Quartz-based implementations of components that help SessionManager implementations maintain sessions (timed expiration, orphan cleanup, etc).org.apache.shiro.spring.boot.autoconfigure org.apache.shiro.spring.config org.apache.shiro.spring.config.web.autoconfigure org.apache.shiro.spring.web.config org.apache.shiro.subject.support Concrete support implementations of most of theorg.apache.shiro.subject
interfaces.org.apache.shiro.web.mgt Components supporting web-specificSecurityManager
implementations.org.apache.shiro.web.session.mgt org.apache.shiro.web.subject.support Supporting implementations oforg.apache.shiro.web.subject
package interfaces. -
Classes in org.apache.shiro.session.mgt used by org.apache.shiro.guice Class Description SessionManager A SessionManager manages the creation, maintenance, and clean-up of all applicationSession
s. -
Classes in org.apache.shiro.session.mgt used by org.apache.shiro.guice.web Class Description SessionManager A SessionManager manages the creation, maintenance, and clean-up of all applicationSession
s. -
Classes in org.apache.shiro.session.mgt used by org.apache.shiro.mgt Class Description SessionContext ASessionContext
is a 'bucket' of data presented to aSessionFactory
which interprets this data to constructSession
instances.SessionKey ASessionKey
is a key that allows look-up of any particularSession
instance.SessionManager A SessionManager manages the creation, maintenance, and clean-up of all applicationSession
s. -
Classes in org.apache.shiro.session.mgt used by org.apache.shiro.session.mgt Class Description AbstractNativeSessionManager Abstract implementation supporting theNativeSessionManager
interface, supportingSessionListener
s and application of theglobalSessionTimeout
.AbstractSessionManager Base abstract class of theSessionManager
interface, enabling configuration of an application-wideglobalSessionTimeout
.AbstractValidatingSessionManager Default business-tier implementation of theValidatingSessionManager
interface.NativeSessionManager ANative
session manager is one that manages sessions natively - that is, it is directly responsible for the creation, persistence and removal ofSession
instances and their lifecycles.SessionContext ASessionContext
is a 'bucket' of data presented to aSessionFactory
which interprets this data to constructSession
instances.SessionFactory A simple factory class that instantiates concreteSession
instances.SessionKey ASessionKey
is a key that allows look-up of any particularSession
instance.SessionManager A SessionManager manages the creation, maintenance, and clean-up of all applicationSession
s.SessionValidationScheduler Interface that should be implemented by classes that can control validating sessions on a regular basis.SimpleSession SimpleSession
JavaBeans-compatible POJO implementation, intended to be used on the business/server tier.ValidatingSession AValidatingSession
is aSession
that is capable of determining it is valid or not and is able to validate itself if necessary.ValidatingSessionManager A ValidatingSessionManager is a SessionManager that can proactively validate any or all sessions that may be expired. -
Classes in org.apache.shiro.session.mgt used by org.apache.shiro.session.mgt.quartz Class Description SessionValidationScheduler Interface that should be implemented by classes that can control validating sessions on a regular basis.ValidatingSessionManager A ValidatingSessionManager is a SessionManager that can proactively validate any or all sessions that may be expired. -
Classes in org.apache.shiro.session.mgt used by org.apache.shiro.spring.boot.autoconfigure Class Description SessionFactory A simple factory class that instantiates concreteSession
instances.SessionManager A SessionManager manages the creation, maintenance, and clean-up of all applicationSession
s. -
Classes in org.apache.shiro.session.mgt used by org.apache.shiro.spring.config Class Description SessionFactory A simple factory class that instantiates concreteSession
instances.SessionManager A SessionManager manages the creation, maintenance, and clean-up of all applicationSession
s. -
Classes in org.apache.shiro.session.mgt used by org.apache.shiro.spring.config.web.autoconfigure Class Description SessionFactory A simple factory class that instantiates concreteSession
instances.SessionManager A SessionManager manages the creation, maintenance, and clean-up of all applicationSession
s. -
Classes in org.apache.shiro.session.mgt used by org.apache.shiro.spring.web.config Class Description SessionFactory A simple factory class that instantiates concreteSession
instances.SessionManager A SessionManager manages the creation, maintenance, and clean-up of all applicationSession
s. -
Classes in org.apache.shiro.session.mgt used by org.apache.shiro.subject.support Class Description SessionContext ASessionContext
is a 'bucket' of data presented to aSessionFactory
which interprets this data to constructSession
instances. -
Classes in org.apache.shiro.session.mgt used by org.apache.shiro.web.mgt Class Description SessionContext ASessionContext
is a 'bucket' of data presented to aSessionFactory
which interprets this data to constructSession
instances.SessionKey ASessionKey
is a key that allows look-up of any particularSession
instance.SessionManager A SessionManager manages the creation, maintenance, and clean-up of all applicationSession
s. -
Classes in org.apache.shiro.session.mgt used by org.apache.shiro.web.session.mgt Class Description AbstractNativeSessionManager Abstract implementation supporting theNativeSessionManager
interface, supportingSessionListener
s and application of theglobalSessionTimeout
.AbstractSessionManager Base abstract class of theSessionManager
interface, enabling configuration of an application-wideglobalSessionTimeout
.AbstractValidatingSessionManager Default business-tier implementation of theValidatingSessionManager
interface.DefaultSessionContext Default implementation of theSessionContext
interface which provides getters and setters that wrap interaction with the underlying backing context map.DefaultSessionKey Default implementation of theSessionKey
interface, which allows setting and retrieval of a concretesessionId
that theSessionManager
implementation can use to look up aSession
instance.DefaultSessionManager Default business-tier implementation of aValidatingSessionManager
.NativeSessionManager ANative
session manager is one that manages sessions natively - that is, it is directly responsible for the creation, persistence and removal ofSession
instances and their lifecycles.SessionContext ASessionContext
is a 'bucket' of data presented to aSessionFactory
which interprets this data to constructSession
instances.SessionKey ASessionKey
is a key that allows look-up of any particularSession
instance.SessionManager A SessionManager manages the creation, maintenance, and clean-up of all applicationSession
s.ValidatingSessionManager A ValidatingSessionManager is a SessionManager that can proactively validate any or all sessions that may be expired. -
Classes in org.apache.shiro.session.mgt used by org.apache.shiro.web.subject.support Class Description SessionContext ASessionContext
is a 'bucket' of data presented to aSessionFactory
which interprets this data to constructSession
instances.


Overview
Package
Class
Use
Tree
Deprecated
Index
Help
PREV LETTER
NEXT LETTER
FRAMES
NO FRAMES
All Classes
A
B
C
D
E
F
G
H
I
M
N
O
P
R
S
T
U
V
A
AiCalConfig
- Class in
com.mcc.ul
This class provides methods to get or set calibration settings of an analog input subsystem on a DAQ device.
AiChanConfig
- Class in
com.mcc.ul
This class provides methods to get or set configuration settings of an analog input subsystem on a DAQ device.
AiChanInfo
- Class in
com.mcc.ul
This class provides methods to retrieve information that describe the analog input subsystem on a DAQ device.
AiChanMode
- Enum in
com.mcc.ul
A/D channel input modes.
AiChanQueueLimitation
- Enum in
com.mcc.ul
Limitations imposed by the queue type.
AiChanType
- Enum in
com.mcc.ul
A/D channel types.
AiConfig
- Class in
com.mcc.ul
This class provides methods to get or set configuration of an analog input subsystem on a DAQ device.
AiDevice
- Class in
com.mcc.ul
This class represents an analog input subsystem on a DAQ device.
AiExpConfig
- Class in
com.mcc.ul
This class provides methods to get or set configuration of an analog input subsystem on an expansion device.
AiExpInfo
- Class in
com.mcc.ul
This class provides methods to retrieve information that describe the capabilities of the analog input subsystem on an Expansion device.
AiInfo
- Class in
com.mcc.ul
This class provides methods to retrieve information that describe the capabilities of the analog input subsystem on a DAQ device.
aIn(int, AiChanMode, Range, AiUnit)
- Method in class com.mcc.ul.
AiDevice
Returns the value read from an A/D channel.
aInScan(int, int, AiChanMode, Range, int, double, EnumSet<AiScanOption>, AiUnit, double[][])
- Method in class com.mcc.ul.
AiDevice
Scans a range of A/D channels and stores the samples in an array in the background.
AiPacerConfig
- Class in
com.mcc.ul
This class provides methods to configure the pacer settings of an analog input subsystem on a DAQ device.
AiQueueType
- Enum in
com.mcc.ul
Queue types supported by the AI subsystem.
AiScanOption
- Enum in
com.mcc.ul
Scan options for paced analog input functions.
AiUnit
- Enum in
com.mcc.ul
A/D data units.
alarmStateOutput
- Variable in class com.mcc.ul.
AoAlarmSettings
The D/A output value when an alarm is triggered.
alarmStateOutput
- Variable in class com.mcc.ul.
DoAlarmSettings
The value of the digital output bits when an alarm is triggered.
AlarmType
- Enum in
com.mcc.ul
Alarm types.
aLoadQueue(AQueueElement[])
- Method in class com.mcc.ul.
AiDevice
Loads the A/D board's channel-gain queue.
AoAlarmConfig
- Class in
com.mcc.ul
This class represents the alarm configuration of an analog output channel on a DAQ device.
AoAlarmSettings
- Class in
com.mcc.ul
This class represents the alarm settings of an analog output channel on a DAQ device.
AoCalConfig
- Class in
com.mcc.ul
This class provides methods to get or set calibration settings of an analog output subsystem on a DAQ device.
AoChanInfo
- Class in
com.mcc.ul
This class provides methods to retrieve information that describe the analog output subsystem on a DAQ device.
AoChanType
- Enum in
com.mcc.ul
D/A channel types
AoConfig
- Class in
com.mcc.ul
This class provides methods to get or set configuration of an analog output subsystem on a DAQ device.
AoDevice
- Class in
com.mcc.ul
This class represents an analog output subsystem on a DAQ device.
AoInfo
- Class in
com.mcc.ul
This class provides methods to retrieve information that describe the capabilities of the analog output subsystem on a DAQ device.
AoScanOption
- Enum in
com.mcc.ul
Scan options for analog output functions.
AoUnit
- Enum in
com.mcc.ul
D/A data units.
AoUsbConfig
- Class in
com.mcc.ul
This class represents the USB configuration of an analog output subsystem.
aOut(int, Range, AoUnit, double)
- Method in class com.mcc.ul.
AoDevice
Writes the value of a D/A output.
aOutScan(int, int, Range, int, double, EnumSet<AoScanOption>, AoUnit, double[][])
- Method in class com.mcc.ul.
AoDevice
Writes values to a range of D/A channels.
AQueueElement
- Class in
com.mcc.ul
This class represents a gain queue element.
AQueueElement()
- Constructor for class com.mcc.ul.
AQueueElement
AutoShutdownConfig
- Class in
com.mcc.ul
This class provides methods to get or set the auto shutdown configuration of a DAQ device.
AutoShutdownCriteria
- Enum in
com.mcc.ul
Overview
Package
Class
Use
Tree
Deprecated
Index
Help
PREV LETTER
NEXT LETTER
FRAMES
NO FRAMES
All Classes
A
B
C
D
E
F
G
H
I
M
N
O
P
R
S
T
U
V


title = "Department Sponsered Project" url = "/dept/:perma/projects-sponsered" layout = "department" description = "Sponsered Projects under Department" is_hidden = 0 == function onStart() { $this['sponsered'] = $this['dept']->sponsered_pros; $this['navtitle'] = 'Sponsered Projects'; $this['active'] = 'sponsered'; } ==
| S.No. | Title | Duration | Amount Received | Funding Agency | Status | Faculties |
|---|---|---|---|---|---|---|
| {{ loop.index }} | {{ pro.title }} | {{ pro.duration }} | {{ pro.amount }} | {{ pro.funder }} | {{ pro.status }} | {{ pro.faculties }} |


Website Analytics
Metrics to understand your website visitors.
Website Visitors
Bounceback Rate
Visitor Information
Website Visitors
Monthly Visitors: 1931
Visitors Today: 42
Bounceback Rate
Visitor Information


Date: 2018-10-29
BufferEntry {
U32 m_offset;
U32 m_size;
U32 m_maxSize;
};
// A buffer that is on the GPU & holds mappings of the data it stores
GPUBuffer {
// Size of the buffer
U32 m_byteSize;
};
// A buffer that is mapped between CPU & GPU. Also, it holds mappings of the data it stores
MappedGPUBuffer : GPUBuffer {
// Memory ptrs
U8* p_dataCur;
U8* p_dataBeg;
U8* p_dataEnd;
// Entry storage
Vector<BufferEntry> m_entries;
}
StructuredGPUBuffer : GPUBuffer {
// Stride of structured buffer
U32 m_stride;
}
// APIs to write to MappedGPUBuffer, as they are the only ones available on CPU side
namespace GPUBufferWriter {
U32 AppendRaw(MappedGPUBuffer& buffer, void* data, U32 byteSize, U32 alignment, const Log& log);
U32 AppendRaw(MappedGPUBuffer& buffer, U8* data, U32 byteSize, U32 alignment, const Log& log);
// also maxSize extensions - That will allow us to reserve some space for data that changes but has a max limit to it.
U32 AppendTexture(MappedGPUBuffer& buffer, U8* data, U32 byteSize, U32 alignment, U32 currentRowPitch, U32 requiredRowPitch, const Log& log);
// also maxSize extensions - That will allow us to reserve some space for data that changes but has a max limit to it.
};
A buffer that maps to the GPU and stores relevant buffer informations. (Like Constant Buffers, Structured Buffers, Textures etc.)
VkGPUBuffer and D3D12GPUBuffer are some relevant derivations that will hold other api specific information. Especially the process of creating such a buffer.
Certain descriptors could be:
We need a way to avoid duplicating the data if it is shared at a particular level. This should be on a granularity of Descriptor Sets and not individual entries. 1 set has 1 place of update either at the renderer level, pass level (compute or render), pool level etc.
Pros:
UsageScope
there itselfCons
Notes / Foreseeable Changes:


Describes a 3D transformation as a 4x4 homogeneous matrix. Matrix Mathematically, a matrix is a set of numbers arranged in uniform rows and columns OpenGL understands column-primary layout for matrices: in a 4x4 matrix, the first four elements of an array provide the first column of the matrix, followed by second column, and so on.
4x4 matrix float matrix4x4[] = { a, e, i, 0, // 1st column b, f, j, 0, // 2nd column c, g, k, 0, // 3rd column d, h, l, 1 // 4th column };
Matrix and vector math In 2D we use a lot of trigonometry In 3D we use a lot of linear algebra In physics calculation for 3D games we begin to use calculus A matrix can: Translate (move) a vertex Rotate a vertex Scale a vertex Math libraries cover up these details, but we need to learn matrix math to understand 3D modeling and animation.
Matrix by vector multiplication We can multiply a matrix by a vector, which yields another vector: Matrix by vector multiplication step-by-step We could take 4 steps to find the solution: | cos(90) -sin(90) 0 0 | | 1 | | 0 | cos(90)*1 + -sin(90)*0 + 0*0 + 0*1 | sin(90) cos(90) 0 0 | . | 0 | = | ? | | 0 0 1 0 | | 0 | | ? | | 0 0 0 1 | | 1 | | ? | | cos(90) -sin(90) 0 0 | | 1 | | 0 | | sin(90) cos(90) 0 0 | . | 0 | = | 1 | sin(90)*1 + cos(90)*0 + 0*0 + 0*1 | 0 0 1 0 | | 0 | | ? | | 0 0 0 1 | | 1 | | ? | | cos(90) -sin(90) 0 0 | | 1 | | 0 | | sin(90) cos(90) 0 0 | . | 0 | = | 1 | | 0 0 1 0 | | 0 | | 0 | 0*1 + 0*0 + 1*0 + 0*1 | 0 0 0 1 | | 1 | | ? | | cos(90) -sin(90) 0 0 | | 1 | | 0 | | sin(90) cos(90) 0 0 | . | 0 | = | 1 | | 0 0 1 0 | | 0 | | 0 | | 0 0 0 1 | | 1 | | 1 | 0*1 + 0*0 + 0*0 + 1*1 Answer: | cos(90) -sin(90) 0 0 | | 1 | | 0 | | sin(90) cos(90) 0 0 | . | 0 | = | 1 | | 0 0 1 0 | | 0 | | 0 | | 0 0 0 1 | | 1 | | 1 |
View Space (Camera Space) We shall now decide where the observer of our world is positioned. For this we can scale, rotate, and move around the entire world. OpenGL view volume Projection matrix places all visible objects in a perfect view volume cube (shown on the right) with coordinates between -1 and 1 on all axes: This cube defines our view volume. Projection transformation yields (x, y, z, w) coordinates such that -1.0 <= x/w <= +1.0 -1.0 <= y/w <= +1.0 -1.0 <= z/w <= +1.0 These coordinates are called homogeneous clip coordinates, which define the clip space. NDC transformation Projection from eye coordinates to clip space, followed by the normalized device space: Note that most lighting calculations are done in eye space (camera space) -- that is -- before projection transformation Window space (viewport transformation) Before NDC volume is projected to a window, positions of the vertices are adjusted in proportion to the window on the computer screen, and the final image is rendered: OpenGL coordinate systems and transformations
Excercise: You are free to do math on 3D vector matrix as noted above.
Solutions can be found at the links provided below
Read more:Best derivation of 3D Origins to application in state of the art imaging The Official Guide to Learning OpenGL Online Matric Math Math Matrices Tutorial Matrices OpenGL Tutorial Intro to CSS 3D Transformations Opera CSS 3D Transformations W3 CSS Transforms Module Level 1 Editor’s Draft, 1 June 2018 Moz://a Devellopers Network web docs 3D JavaScript CSS properties 3D CSS Transforms


Token normalization is the process of canonicalizing
tokens so that matches occur despite superficial
differences in the character sequences of the tokens.
See also d03.
See also d04.
See also d01.
See also d05.


A few years ago, I decided to stop drinking alcohol after a bad experience and thought I try instead a 'legal high'. Having read a little bit about yohimbe and finding a local seller, I figured a drug that could enhance sex even more sounded like fun, so I sent off for the raw grounded bark.
Early one morning, pre-dawn, nervous and not quite knowing what to expect, I decided to try it and spend the day in bed with my wife. I had read somewhere to use 6 Tblspoons(!!), but figured I play it safe and used only 4 tspoons, boiled it up for 30 mins with vitamin C powder. Straining and adding lots of honey, I drank it slowly over 20 minutes while sucking on a grapefruit to cover its awful flavour.
At first I thought nothing was going to happen, but by the time I'd finished the cup, I started feeling funny body sensations and thought it was pretty good. Then things got really bad. I started to shake and tremor, my eyes turned blood red and my heart pounded and raced, as though it was going to jump out of my chest. I was terrified, but I resisted the temptation to go to hospital, instead deciding to ride it through. I stayed in that state for 3 hours, before my heart started to calm down a bit, feeling mildly nauseated all the while. I couldn't lie still without shaking and listening to my heart, so I spent most of that time pacing and walking around agitated, wondering if I was going to die.
My wife was unhappy and offered to ring for an ambulance, but I did convince her to try sex after 2 hours with me in that state. I was hard to get aroused, which is not normal for me, and even harder to finish. Far from fun.
My heart was flighty for the rest of the day and I felt like I'd been through a trauma. However, finally, late that night (16hours later?), I had sex again, and the finish was prolonged and spectacular, and made me gasp, also not normal for me!
I read up on the topic some more and worked out I had overdosed. But when I tried much smaller quanities in the weeks that followed, my body went into terror mode as soon as it touched my lips. My heart starting pounding, my head felt light headed and shaky and I couldn't go through with it. I chucked it all out.
After that, I developed panic attacks, going into the some heart racing mode in response to sometimes eating food, sometimes for no reason whatsoever. I was determined not to let it conquer me and after a personal battle with it, which I won't get into here, I eventually got over the irratic attacks after 3 months.
Part of truly conquering it, however, I realized I had to try yohimbe again. A year later, I sent off for some more and drank a teaspoon prepared as before. I half panicked, but faced down that fear and realized it was my mind, not the tea that was making my heart race.
I was always a 'nervous' sort of guy and panic attacks run in my family, so in retrospect, I'm not surprised it triggered the response in me. But I'm glad of it, because instead of developing it later in my life, like my mother who ever since was hooked on Valium, Zantac, etc, it happened in a more controlled way and ultimately allowed me to conquer it.
Since then, I have continued to occasionally drink yohimbe tea, best dosage 1 1/2 teaspoons. I don't get a racing heart anymore, but can get light headedness if I have high tyromine foods (chocolate, high MSG, etc), so I avoid them the day before and after. It doesn't taste that bad at that dose and boiled with a little bit of grapefruit juice and sipped over 40 minutes while sucking on an orange. At the right dose, it gives me an interesting rush of body sensations and high energy state. I wouldn't say it makes me horny so much as it makes the experience of sex more intense, especially the finish. Including the second and third times! :)
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.