Added: incubator/unomi/website/manual/latest/installing-tracker.html
URL: 
http://svn.apache.org/viewvc/incubator/unomi/website/manual/latest/installing-tracker.html?rev=1845794&view=auto
==============================================================================
--- incubator/unomi/website/manual/latest/installing-tracker.html (added)
+++ incubator/unomi/website/manual/latest/installing-tracker.html Mon Nov  5 
14:08:37 2018
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta name="generator" content="Asciidoctor 1.5.6.1">
+<title>Web Tracker</title>
+<link rel="stylesheet" href="./apache.css">
+</head>
+<body class="article">
+<div id="header">
+<div id="toc" class="toc">
+<div id="toctitle">Table of Contents</div>
+<ul class="sectlevel3">
+<li><a href="#_web_tracker">Web Tracker</a></li>
+</ul>
+</div>
+</div>
+<div id="content">
+<div class="sect3">
+<h4 id="_web_tracker">Web Tracker</h4>
+<div class="paragraph">
+<p>This extension is providing the web tracker to start collecting visitors 
data on your website.
+The tracker is implemented as an integration of <a 
href="https://github.com/segmentio/analytics.js";>analytics.js</a> for Unomi.</p>
+</div>
+<div class="sect4">
+<h5 id="_getting_started">Getting started</h5>
+<div class="paragraph">
+<p>Extension can be tested at : <code><a 
href="http://localhost:8181/tracker/index.html"; 
class="bare">http://localhost:8181/tracker/index.html</a></code></p>
+</div>
+<div class="paragraph">
+<p>In your page include unomiOptions and include code snippet from 
<code>snippet.min.js</code> :</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code>&lt;script type="text/javascript"&gt;
+        var unomiOption = {
+            scope: 'realEstateManager',
+            url: 'http://localhost:8181'
+        };
+        window.unomiTracker||(window.unomiTracker={}),function(){function 
e(e){for(unomiTracker.initialize({"Apache 
Unomi":unomiOption});n.length&gt;0;){var 
r=n.shift(),t=r.shift();unomiTracker[t]&amp;&amp;unomiTracker[t].apply(unomiTracker,r)}}for(var
 
n=[],r=["trackSubmit","trackClick","trackLink","trackForm","initialize","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","personalize"],t=0;t&lt;r.length;t++){var
 i=r[t];window.unomiTracker[i]=function(e){return function(){var 
r=Array.prototype.slice.call(arguments);return 
r.unshift(e),n.push(r),window.unomiTracker}}(i)}unomiTracker.load=function(){var
 
n=document.createElement("script");n.type="text/javascript",n.async=!0,n.src=unomiOption.url+"/tracker/unomi-tracker.min.js",n.addEventListener?n.addEventListener("load",function(n){"function"==typeof
 
e&amp;&amp;e(n)},!1):n.onreadystatechange=function(){"complete"!==this.readyState&amp;&amp;"loaded"!==this.readyState||e(window.event)};var
 r=
 
document.getElementsByTagName("script")[0];r.parentNode.insertBefore(n,r)},document.addEventListener("DOMContentLoaded",unomiTracker.load),unomiTracker.page()}();
+&lt;/script&gt;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p><code>window.unomiTracker</code> can be used to send additional events when 
needed.</p>
+</div>
+<div class="paragraph">
+<p>Check analytics.js API <a 
href="https://segment.com/docs/sources/website/analytics.js/";>here</a>.
+All methods can be used on <code>unomiTracker</code> object, although not all 
event types are supported by Unomi intergation.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="_how_to_contribute">How to contribute</h5>
+<div class="paragraph">
+<p>The source code is in the folder javascript with a package.json, the file 
to update is <code>analytics.js-integration-apache-unomi.js</code> apply your 
modification in this file then use the command <code>yarn build</code> to 
compile a new JS file.
+Then you can use the test page to try your changes <code><a 
href="http://localhost:8181/tracker/index.html"; 
class="bare">http://localhost:8181/tracker/index.html</a></code>.</p>
+</div>
+</div>
+</div>
+</div>
+<div id="footer">
+<div id="footer-text">
+Last updated 2018-11-02 16:10:48 CET
+</div>
+</div>
+</body>
+</html>
\ No newline at end of file

Added: incubator/unomi/website/manual/latest/patches.html
URL: 
http://svn.apache.org/viewvc/incubator/unomi/website/manual/latest/patches.html?rev=1845794&view=auto
==============================================================================
--- incubator/unomi/website/manual/latest/patches.html (added)
+++ incubator/unomi/website/manual/latest/patches.html Mon Nov  5 14:08:37 2018
@@ -0,0 +1,156 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta name="generator" content="Asciidoctor 1.5.6.1">
+<title>Migration patches</title>
+<link rel="stylesheet" href="./apache.css">
+</head>
+<body class="article">
+<div id="header">
+<div id="toc" class="toc">
+<div id="toctitle">Table of Contents</div>
+<ul class="sectlevel3">
+<li><a href="#_migration_patches">Migration patches</a></li>
+</ul>
+</div>
+</div>
+<div id="content">
+<div class="sect3">
+<h4 id="_migration_patches">Migration patches</h4>
+<div class="paragraph">
+<p>You may provide patches on any predefined items by simply adding a JSON 
file in :</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre 
class="highlight"><code>src/main/resources/META-INF/cxs/patches</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>These patches will be applied when the module will be deployed the first 
time.
+They allow to modify an item, that would have been previously deployed on 
unomi by a previous version of the extension or by something else.</p>
+</div>
+<div class="paragraph">
+<p>Each patch must have a unique id - unomi will use this id to remember that 
the patch has already been applied. It can also be used to reapply the patch 
when need by using the karaf command <code>unomi:deploy-definition</code></p>
+</div>
+<div class="paragraph">
+<p>A patch also need to reference the item to patch by setting 
<code>patchedItemId</code> and <code>patchedItemType</code>, and an operation 
that tells what the patch should do.</p>
+</div>
+<div class="ulist">
+<div class="title"><code>patchedItemType</code> can take one of the following 
value:</div>
+<ul>
+<li>
+<p>condition</p>
+</li>
+<li>
+<p>action</p>
+</li>
+<li>
+<p>goal</p>
+</li>
+<li>
+<p>campaign</p>
+</li>
+<li>
+<p>persona</p>
+</li>
+<li>
+<p>propertyType</p>
+</li>
+<li>
+<p>rule</p>
+</li>
+<li>
+<p>segment</p>
+</li>
+<li>
+<p>scoring</p>
+</li>
+</ul>
+</div>
+<div class="ulist">
+<div class="title"><code>operation</code> can take one of the following 
value:</div>
+<ul>
+<li>
+<p>patch</p>
+</li>
+<li>
+<p>override</p>
+</li>
+<li>
+<p>remove</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>You can apply a patch in <a href="http://jsonpatch.com/";>json-patch</a> 
format in the <code>data</code> field, and by specifying operation 
<code>patch</code> like in this example :</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code>{
+  "itemId": "firstName-patch1",
+  "patchedItemId": "firstName",
+  "patchedItemType": "propertyType",
+  "operation": "patch",
+  "data": [
+    {
+      "op": "replace", "path": "/defaultValue", "value": "foo"
+    }
+  ]
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>If you need to completely redeploy a definition, you can use the 
<code>override</code> operation and put the definition in <code>data</code></p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code>{
+  "itemId": "gender-patch1",
+  "patchedItemId": "gender",
+  "patchedItemType": "propertyType",
+  "operation": "override",
+  "data": {
+    "metadata": {
+      "id": "gender",
+      "name": "Gender",
+      "systemTags": [
+        "properties",
+        "profileProperties"
+      ]
+    },
+    "type": "string",
+    "defaultValue": "foo",
+    "automaticMappingsFrom": [ ],
+    "rank": "105.0"
+  }
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>It is also possible to simply remove an item by using the operation 
<code>remove</code> :</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code>{
+  "itemId": "firstName-patch2",
+  "patchedItemId": "firstName",
+  "patchedItemType": "propertyType",
+  "operation": "remove"
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Patches can also be deployed at runtime by using the REST endpoint 
/patch/apply .</p>
+</div>
+</div>
+</div>
+<div id="footer">
+<div id="footer-text">
+Last updated 2018-11-02 16:10:48 CET
+</div>
+</div>
+</body>
+</html>
\ No newline at end of file

Added: incubator/unomi/website/manual/latest/samples/apache.css
URL: 
http://svn.apache.org/viewvc/incubator/unomi/website/manual/latest/samples/apache.css?rev=1845794&view=auto
==============================================================================
--- incubator/unomi/website/manual/latest/samples/apache.css (added)
+++ incubator/unomi/website/manual/latest/samples/apache.css Mon Nov  5 
14:08:37 2018
@@ -0,0 +1,2448 @@
+
+@import 
"https://fonts.googleapis.com/css?family=Open+Sans:400,700%7cDroid+Serif:400,700";;
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+nav,
+section,
+summary {
+    display: block
+}
+
+audio,
+canvas,
+video {
+    display: inline-block
+}
+
+audio:not([controls]) {
+    display: none;
+    height: 0
+}
+
+script {
+    display: none !important
+}
+
+html {
+    font-family: "Droid Serif";
+    -ms-text-size-adjust: 100%;
+    -webkit-text-size-adjust: 100%;
+}
+
+a {
+    background: transparent
+}
+
+a:focus {
+    outline: thin dotted
+}
+
+a:active,
+a:hover {
+    outline: 0
+}
+
+h1 {
+    font-size: 2em;
+    margin: .67em 0
+}
+
+abbr[title] {
+    border-bottom: 1px dotted
+}
+
+b,
+strong {
+    font-weight: bold
+}
+
+dfn {
+    font-style: italic
+}
+
+hr {
+    -moz-box-sizing: content-box;
+    box-sizing: content-box;
+    height: 0
+}
+
+mark {
+    background: #ff0;
+    color: #000
+}
+
+code,
+kbd,
+pre,
+samp {
+    font-family: monospace;
+    font-size: 1em
+}
+
+pre {
+    white-space: pre-wrap
+}
+
+q {
+    quotes: "\201C" "\201D" "\2018" "\2019"
+}
+
+small {
+    font-size: 80%
+}
+
+sub,
+sup {
+    font-size: 75%;
+    line-height: 0;
+    position: relative;
+    vertical-align: baseline
+}
+
+sup {
+    top: -.5em
+}
+
+sub {
+    bottom: -.25em
+}
+
+img {
+    border: 0
+}
+
+svg:not(:root) {
+    overflow: hidden
+}
+
+figure {
+    margin: 0
+}
+
+fieldset {
+    border: 1px solid silver;
+    margin: 0 2px;
+    padding: .35em .625em .75em
+}
+
+legend {
+    border: 0;
+    padding: 0
+}
+
+button,
+input,
+select,
+textarea {
+    font-family: inherit;
+    font-size: 100%;
+    margin: 0
+}
+
+button,
+input {
+    line-height: normal
+}
+
+button,
+select {
+    text-transform: none
+}
+
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+    -webkit-appearance: button;
+    cursor: pointer
+}
+
+button[disabled],
+html input[disabled] {
+    cursor: default
+}
+
+input[type="checkbox"],
+input[type="radio"] {
+    box-sizing: border-box;
+    padding: 0
+}
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+    border: 0;
+    padding: 0
+}
+
+textarea {
+    overflow: auto;
+    vertical-align: top
+}
+
+table {
+    border-collapse: collapse;
+    border-spacing: 0
+}
+
+*,
+*::before,
+*::after {
+    -moz-box-sizing: border-box;
+    -webkit-box-sizing: border-box;
+    box-sizing: border-box
+}
+
+html,
+body {
+    /*font-size: 100%*/
+}
+
+body {
+    background: #fff;
+    color: #333;
+    padding: 0;
+    margin: 0;
+    font-family: "Droid Serif", "DejaVu Serif", serif;
+    font-size: 14px;
+    font-style: normal;
+    line-height: 1.42857143;
+    position: relative;
+    cursor: auto;
+    tab-size: 4;
+    -moz-osx-font-smoothing: grayscale;
+    -webkit-font-smoothing: antialiased
+}
+
+a:hover {
+    cursor: pointer
+}
+
+img,
+object,
+embed {
+    max-width: 100%;
+    height: auto
+}
+
+object,
+embed {
+    height: 100%
+}
+
+img {
+    -ms-interpolation-mode: bicubic
+}
+
+.left {
+    float: left !important
+}
+
+.right {
+    float: right !important
+}
+
+.text-left {
+    text-align: left !important
+}
+
+.text-right {
+    text-align: right !important
+}
+
+.text-center {
+    text-align: center !important
+}
+
+.text-justify {
+    text-align: justify !important
+}
+
+.hide {
+    display: none
+}
+
+img,
+object,
+svg {
+    display: inline-block;
+    vertical-align: middle
+}
+
+textarea {
+    height: auto;
+    min-height: 50px
+}
+
+select {
+    width: 100%
+}
+
+.center {
+    margin-left: auto;
+    margin-right: auto
+}
+
+.stretch {
+    width: 100%
+}
+
+.subheader,
+.admonitionblock td.content>.title,
+.audioblock>.title,
+.exampleblock>.title,
+.imageblock>.title,
+.listingblock>.title,
+.literalblock>.title,
+.stemblock>.title,
+.openblock>.title,
+.paragraph>.title,
+.quoteblock>.title,
+table.tableblock>.title,
+.verseblock>.title,
+.videoblock>.title,
+.dlist>.title,
+.olist>.title,
+.ulist>.title,
+.qlist>.title,
+.hdlist>.title {
+    line-height: 1.45;
+    color: #585ac2;
+    font-weight: 400;
+    margin-top: 0;
+    margin-bottom: .25em
+}
+
+div,
+dl,
+dt,
+dd,
+ul,
+ol,
+li,
+h1,
+h2,
+h3,
+#toctitle,
+.sidebarblock>.content>.title,
+h4,
+h5,
+h6,
+pre,
+form,
+p,
+blockquote,
+th,
+td {
+    margin: 0;
+    padding: 0;
+    direction: ltr
+}
+
+a {
+    color: #585ac2;
+    text-decoration: underline;
+    line-height: inherit
+}
+
+a:hover,
+a:focus {
+    color: #373997;
+}
+
+a img {
+    border: none
+}
+
+p {
+    font-family: inherit;
+    font-weight: 400;
+    font-size: 1em;
+    line-height: 1.6;
+    margin-bottom: 1.25em;
+    text-rendering: optimizeLegibility
+}
+
+p aside {
+    font-size: .875em;
+    line-height: 1.35;
+    font-style: italic
+}
+
+h1,
+h2,
+h3,
+#toctitle,
+.sidebarblock>.content>.title,
+h4,
+h5,
+h6 {
+    font-family: "Open Sans", "DejaVu Sans", sans-serif;
+    font-weight: bold;
+    /*font-style: bold;*/
+    color: #303284;
+    text-rendering: optimizeLegibility;
+    margin-top: 1em;
+    margin-bottom: .5em;
+    line-height: 1.0125em;
+    text-transform: uppercase;
+}
+
+h1 small,
+h2 small,
+h3 small,
+#toctitle small,
+.sidebarblock>.content>.title small,
+h4 small,
+h5 small,
+h6 small {
+    font-size: 60%;
+    color: #303284;
+    line-height: 0
+}
+
+h1 {
+    font-size: 2.125em
+}
+
+h2 {
+    font-size: 1.6875em
+}
+
+h3,
+#toctitle,
+.sidebarblock>.content>.title {
+    font-size: 1.375em
+}
+
+h4,
+h5 {
+    font-size: 1.125em
+}
+
+h6 {
+    font-size: 1em
+}
+
+hr {
+    border: solid #dddddd;
+    border-width: 1px 0 0;
+    clear: both;
+    margin: 1.25em 0 1.1875em;
+    height: 0
+}
+
+em,
+i {
+    font-style: italic;
+    line-height: inherit
+}
+
+strong,
+b {
+    font-weight: bold;
+    line-height: inherit
+}
+
+small {
+    font-size: 60%;
+    line-height: inherit
+}
+
+code {
+    font-family: "Droid Sans Mono", "DejaVu Sans Mono", monospace;
+    font-weight: 400;
+    color: #585ac2;
+}
+
+ul,
+ol,
+dl {
+    font-size: 1em;
+    line-height: 1.6;
+    margin-bottom: 1.25em;
+    list-style-position: outside;
+    font-family: inherit
+}
+
+ul,
+ol {
+    margin-left: 1.5em
+}
+
+ul li ul,
+ul li ol {
+    margin-left: 1.25em;
+    margin-bottom: 0;
+    font-size: 1em
+}
+
+ul.square li ul,
+ul.circle li ul,
+ul.disc li ul {
+    list-style: inherit
+}
+
+ul.square {
+    list-style-type: square
+}
+
+ul.circle {
+    list-style-type: circle
+}
+
+ul.disc {
+    list-style-type: disc
+}
+
+ol li ul,
+ol li ol {
+    margin-left: 1.25em;
+    margin-bottom: 0
+}
+
+dl dt {
+    margin-bottom: .3125em;
+    font-weight: bold
+}
+
+dl dd {
+    margin-bottom: 1.25em
+}
+
+abbr,
+acronym {
+    text-transform: uppercase;
+    font-size: 90%;
+    color: rgba(0, 0, 0, .8);
+    border-bottom: 1px dotted #ddd;
+    cursor: help
+}
+
+abbr {
+    text-transform: none
+}
+
+blockquote {
+    margin: 0 0 1.25em;
+    padding: .5625em 1.25em 0 1.1875em;
+    border-left: 1px solid #ddd
+}
+
+blockquote cite {
+    display: block;
+    font-size: .9375em;
+    color: rgba(0, 0, 0, .6)
+}
+
+blockquote cite::before {
+    content: "\2014 \0020"
+}
+
+blockquote cite a,
+blockquote cite a:visited {
+    color: rgba(0, 0, 0, .6)
+}
+
+blockquote,
+blockquote p {
+    line-height: 1.6;
+    color: rgba(0, 0, 0, .85)
+}
+
+@media screen and (min-width:768px) {
+    h1,
+    h2,
+    h3,
+    #toctitle,
+    .sidebarblock>.content>.title,
+    h4,
+    h5,
+    h6 {
+        line-height: 1.2
+    }
+
+    h1 {
+        font-size: 2.75em
+    }
+
+    h2 {
+        font-size: 2.3125em
+    }
+
+    h3,
+    #toctitle,
+    .sidebarblock>.content>.title {
+        font-size: 1.6875em
+    }
+
+    h4 {
+        font-size: 1.4375em
+    }
+
+}
+
+table {
+    background: #fff;
+    margin-bottom: 1.25em;
+    border: solid 1px #dddddd;
+}
+
+table thead,
+table tfoot {
+    background: #f7f8f7
+}
+
+table thead tr th,
+table thead tr td,
+table tfoot tr th,
+table tfoot tr td {
+    padding: .5em .625em .625em;
+    font-size: inherit;
+    color: rgba(0, 0, 0, .8);
+    text-align: left
+}
+
+table tr th,
+table tr td {
+    padding: .5625em .625em;
+    font-size: inherit;
+    color: rgba(0, 0, 0, .8)
+}
+
+table tr.even,
+table tr.alt,
+table tr:nth-of-type(even) {
+    background: #f8f8f7
+}
+
+table thead tr th,
+table tfoot tr th,
+table tbody tr td,
+table tr td,
+table tfoot tr td {
+    display: table-cell;
+    line-height: 1.6
+}
+
+h1,
+h2,
+h3,
+#toctitle,
+.sidebarblock>.content>.title,
+h4,
+h5,
+h6 {
+    line-height: 1.2;
+    word-spacing: -.05em
+}
+
+h1 strong,
+h2 strong,
+h3 strong,
+#toctitle strong,
+.sidebarblock>.content>.title strong,
+h4 strong,
+h5 strong,
+h6 strong {
+    font-weight: 400
+}
+
+.clearfix::before,
+.clearfix::after,
+.float-group::before,
+.float-group::after {
+    content: " ";
+    display: table
+}
+
+.clearfix::after,
+.float-group::after {
+    clear: both
+}
+
+*:not(pre)>code {
+    font-size: .9375em;
+    font-style: normal !important;
+    letter-spacing: 0;
+    padding: .1em .5ex;
+    word-spacing: -.15em;
+    background-color: #f7f7f8;
+    -webkit-border-radius: 4px;
+    border-radius: 4px;
+    line-height: 1.45;
+    text-rendering: optimizeSpeed;
+    word-wrap: break-word
+}
+
+*:not(pre)>code.nobreak {
+    word-wrap: normal
+}
+
+*:not(pre)>code.nowrap {
+    white-space: nowrap
+}
+
+pre,
+pre>code {
+    line-height: 1.45;
+    color: #585ac2;
+    font-family: "Droid Sans Mono", "DejaVu Sans Mono", monospace;
+    font-weight: 400;
+    text-rendering: optimizeSpeed
+}
+
+em em {
+    font-style: normal
+}
+
+strong strong {
+    font-weight: 400
+}
+
+.keyseq {
+    color: rgba(51, 51, 51, .8)
+}
+
+kbd {
+    font-family: "Droid Sans Mono", "DejaVu Sans Mono", monospace;
+    display: inline-block;
+    color: rgba(0, 0, 0, .8);
+    font-size: .65em;
+    line-height: 1.45;
+    background-color: #f7f7f7;
+    border: 1px solid #dddddd;
+    -webkit-border-radius: 3px;
+    border-radius: 3px;
+    -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, .2), 0 0 0 .1em white inset;
+    box-shadow: 0 1px 0 rgba(0, 0, 0, .2), 0 0 0 .1em #fff inset;
+    margin: 0 .15em;
+    padding: .2em .5em;
+    vertical-align: middle;
+    position: relative;
+    top: -.1em;
+    white-space: nowrap
+}
+
+.keyseq kbd:first-child {
+    margin-left: 0
+}
+
+.keyseq kbd:last-child {
+    margin-right: 0
+}
+
+.menuseq,
+.menuref {
+    color: #000
+}
+
+.menuseq b:not(.caret),.menuref {
+    font-weight: inherit
+}
+
+.menuseq {
+    word-spacing: -.02em
+}
+
+.menuseq b.caret {
+    font-size: 1.25em;
+    line-height: .8
+}
+
+.menuseq i.caret {
+    font-weight: bold;
+    text-align: center;
+    width: .45em
+}
+
+b.button::before,
+b.button::after {
+    position: relative;
+    top: -1px;
+    font-weight: 400
+}
+
+b.button::before {
+    content: "[";
+    padding: 0 3px 0 2px
+}
+
+b.button::after {
+    content: "]";
+    padding: 0 2px 0 3px
+}
+
+p a>code:hover {
+    color: #585ac2;
+}
+
+#header,
+#content,
+#footnotes,
+#footer {
+    width: 100%;
+    margin-left: auto;
+    margin-right: auto;
+    margin-top: 0;
+    margin-bottom: 0;
+    max-width: 62.5em;
+    *zoom: 1;
+    position: relative;
+    padding-left: .9375em;
+    padding-right: .9375em
+}
+
+#header::before,
+#header::after,
+#content::before,
+#content::after,
+#footnotes::before,
+#footnotes::after,
+#footer::before,
+#footer::after {
+    content: " ";
+    display: table
+}
+
+#header::after,
+#content::after,
+#footnotes::after,
+#footer::after {
+    clear: both
+}
+
+#content {
+    margin-top: 1.25em
+}
+
+#content::before {
+    content: none
+}
+
+#header>h1:first-child {
+    color: #303284;
+    margin-top: 2.25rem;
+    margin-bottom: 0
+}
+
+#header>h1:first-child+#toc {
+    margin-top: 8px;
+    border-top: 1px solid #dddddd
+}
+
+#header>h1:only-child,
+body.toc2 #header>h1:nth-last-child(2) {
+    border-bottom: 1px solid #dddddd;
+    padding-bottom: 8px
+}
+
+#header .details {
+    border-bottom: 1px solid #dddddd;
+    line-height: 1.45;
+    padding-top: .25em;
+    padding-bottom: .25em;
+    padding-left: .25em;
+    color: rgba(0, 0, 0, .6);
+    display: -ms-flexbox;
+    display: -webkit-flex;
+    display: flex;
+    -ms-flex-flow: row wrap;
+    -webkit-flex-flow: row wrap;
+    flex-flow: row wrap
+}
+
+#header .details span:first-child {
+    margin-left: -.125em
+}
+
+#header .details span.email a {
+    color: rgba(0, 0, 0, .85)
+}
+
+#header .details br {
+    display: none
+}
+
+#header .details br+span::before {
+    content: "\00a0\2013\00a0"
+}
+
+#header .details br+span.author::before {
+    content: "\00a0\22c5\00a0";
+    color: rgba(0, 0, 0, .85)
+}
+
+#header .details br+span#revremark::before {
+    content: "\00a0|\00a0"
+}
+
+#header #revnumber {
+    text-transform: capitalize
+}
+
+#header #revnumber::after {
+    content: "\00a0"
+}
+
+#content>h1:first-child:not([class]) {
+    color: rgba(0, 0, 0, .85);
+    border-bottom: 1px solid #dddddd
+;
+    padding-bottom: 8px;
+    margin-top: 0;
+    padding-top: 1rem;
+    margin-bottom: 1.25rem
+}
+
+#toc {
+    border-bottom: 1px solid #dddddd;
+    padding-bottom: .5em
+}
+
+#toc>ul {
+    margin-left: .125em
+}
+
+#toc ul.sectlevel0>li>a {
+    font-style: italic
+}
+
+#toc ul.sectlevel0 ul.sectlevel1 {
+    margin: .5em 0
+}
+
+#toc ul {
+    font-family: "Droid Serif", "DejaVu Sans", sans-serif;
+    list-style-type: none
+}
+
+#toc li {
+    line-height: 1.3334;
+    margin-top: .3334em
+}
+
+#toc a {
+    text-decoration: none
+}
+
+#toc a:active {
+    text-decoration: underline
+}
+
+#toctitle {
+    color: #303284;
+    font-size: 1.2em
+}
+
+@media screen and (min-width:768px) {
+    #toctitle {
+        font-size: 1.375em
+    }
+
+    body.toc2 {
+        padding-left: 15em;
+        padding-right: 0
+    }
+
+    #toc.toc2 {
+        margin-top: 0 !important;
+        background-color: #eee;
+        position: fixed;
+        width: 15em;
+        left: 0;
+        top: 0;
+        border-right: 1px solid #dddddd;
+        border-top-width: 0 !important;
+        border-bottom-width: 0 !important;
+        z-index: 1000;
+        padding: 1.25em 1em;
+        height: 100%;
+        overflow: auto
+    }
+
+    #toc.toc2 #toctitle {
+        margin-top: 0;
+        margin-bottom: .8rem;
+        font-size: 1.2em
+    }
+
+    #toc.toc2>ul {
+        font-size: .9em;
+        margin-bottom: 0
+    }
+
+    #toc.toc2 ul ul {
+        margin-left: 0;
+        padding-left: 1em
+    }
+
+    #toc.toc2 ul.sectlevel0 ul.sectlevel1 {
+        padding-left: 0;
+        margin-top: .5em;
+        margin-bottom: .5em
+    }
+
+    body.toc2.toc-right {
+        padding-left: 0;
+        padding-right: 15em
+    }
+
+    body.toc2.toc-right #toc.toc2 {
+        border-right-width: 0;
+        border-left: 1px solid #dddddd;
+        left: auto;
+        right: 0
+    }
+
+}
+
+@media screen and (min-width:1280px) {
+    body.toc2 {
+        padding-left: 20em;
+        padding-right: 0
+    }
+
+    #toc.toc2 {
+        width: 20em
+    }
+
+    #toc.toc2 #toctitle {
+        font-size: 1.375em
+    }
+
+    #toc.toc2>ul {
+        font-size: .95em
+    }
+
+    #toc.toc2 ul ul {
+        padding-left: 1.25em
+    }
+
+    body.toc2.toc-right {
+        padding-left: 0;
+        padding-right: 20em
+    }
+
+}
+
+#content #toc {
+    border-style: solid;
+    border-width: 1px;
+    border-color: #dddddd;
+    margin-bottom: 1.25em;
+    padding: 1.25em;
+    background: #f8f8f7;
+    -webkit-border-radius: 4px;
+    border-radius: 4px
+}
+
+#content #toc>:first-child {
+    margin-top: 0
+}
+
+#content #toc>:last-child {
+    margin-bottom: 0
+}
+
+#footer {
+    max-width: 100%;
+    background-color: #303284;
+    padding: 1.25em
+}
+
+#footer-text {
+    color: #fff;
+    line-height: 1.44
+}
+
+#content {
+    margin-bottom: .625em
+}
+
+.sect1 {
+    padding-bottom: .625em
+}
+
+@media screen and (min-width:768px) {
+    #content {
+        margin-bottom: 1.25em
+    }
+
+    .sect1 {
+        padding-bottom: 1.25em
+    }
+
+}
+
+.sect1:last-child {
+    padding-bottom: 0
+}
+
+.sect1+.sect1 {
+    border-top: 1px solid #dddddd;
+}
+
+#content h1>a.anchor,
+h2>a.anchor,
+h3>a.anchor,
+#toctitle>a.anchor,
+.sidebarblock>.content>.title>a.anchor,
+h4>a.anchor,
+h5>a.anchor,
+h6>a.anchor {
+    position: absolute;
+    z-index: 1001;
+    width: 1.5ex;
+    margin-left: -1.5ex;
+    display: block;
+    text-decoration: none !important;
+    visibility: hidden;
+    text-align: center;
+    font-weight: 400
+}
+
+#content h1>a.anchor::before,
+h2>a.anchor::before,
+h3>a.anchor::before,
+#toctitle>a.anchor::before,
+.sidebarblock>.content>.title>a.anchor::before,
+h4>a.anchor::before,
+h5>a.anchor::before,
+h6>a.anchor::before {
+    content: "\00A7";
+    font-size: .85em;
+    display: block;
+    padding-top: .1em
+}
+
+#content h1:hover>a.anchor,
+#content h1>a.anchor:hover,
+h2:hover>a.anchor,
+h2>a.anchor:hover,
+h3:hover>a.anchor,
+#toctitle:hover>a.anchor,
+.sidebarblock>.content>.title:hover>a.anchor,
+h3>a.anchor:hover,
+#toctitle>a.anchor:hover,
+.sidebarblock>.content>.title>a.anchor:hover,
+h4:hover>a.anchor,
+h4>a.anchor:hover,
+h5:hover>a.anchor,
+h5>a.anchor:hover,
+h6:hover>a.anchor,
+h6>a.anchor:hover {
+    visibility: visible
+}
+
+#content h1>a.link,
+h2>a.link,
+h3>a.link,
+#toctitle>a.link,
+.sidebarblock>.content>.title>a.link,
+h4>a.link,
+h5>a.link,
+h6>a.link {
+    color: #ba3925;
+    text-decoration: none
+}
+
+#content h1>a.link:hover,
+h2>a.link:hover,
+h3>a.link:hover,
+#toctitle>a.link:hover,
+.sidebarblock>.content>.title>a.link:hover,
+h4>a.link:hover,
+h5>a.link:hover,
+h6>a.link:hover {
+    color: #a53221
+}
+
+.audioblock,
+.imageblock,
+.literalblock,
+.listingblock,
+.stemblock,
+.videoblock {
+    margin-bottom: 1.25em
+}
+
+.admonitionblock td.content>.title,
+.audioblock>.title,
+.exampleblock>.title,
+.imageblock>.title,
+.listingblock>.title,
+.literalblock>.title,
+.stemblock>.title,
+.openblock>.title,
+.paragraph>.title,
+.quoteblock>.title,
+table.tableblock>.title,
+.verseblock>.title,
+.videoblock>.title,
+.dlist>.title,
+.olist>.title,
+.ulist>.title,
+.qlist>.title,
+.hdlist>.title {
+    text-rendering: optimizeLegibility;
+    text-align: left;
+    font-family: "Droid Serif", "DejaVu Serif", serif;
+    font-size: 1rem;
+    font-style: italic
+}
+
+table.tableblock.fit-content>caption.title {
+    white-space: nowrap;
+    width: 0
+}
+
+.paragraph.lead>p,
+#preamble>.sectionbody>[class="paragraph"]:first-of-type p {
+    font-size: 1.21875em;
+    line-height: 1.6;
+    color: rgba(0, 0, 0, .85)
+}
+
+table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p {
+    font-size: inherit
+}
+
+.admonitionblock>table {
+    border-collapse: separate;
+    border: 0;
+    background: none;
+    width: 100%
+}
+
+.admonitionblock>table td.icon {
+    text-align: center;
+    width: 80px
+}
+
+.admonitionblock>table td.icon img {
+    max-width: none
+}
+
+.admonitionblock>table td.icon .title {
+    font-weight: bold;
+    font-family: "Open Sans", "DejaVu Sans", sans-serif;
+    text-transform: uppercase
+}
+
+.admonitionblock>table td.content {
+    padding-left: 1.125em;
+    padding-right: 1.25em;
+    border-left: 1px solid #dddddd;
+    color: rgba(0, 0, 0, .6)
+}
+
+.admonitionblock>table td.content>:last-child>:last-child {
+    margin-bottom: 0
+}
+
+.exampleblock>.content {
+    border-style: solid;
+    border-width: 1px;
+    border-color: #dddddd;
+    margin-bottom: 1.25em;
+    padding: 1.25em;
+    background: #fff;
+    -webkit-border-radius: 4px;
+    border-radius: 4px
+}
+
+.exampleblock>.content>:first-child {
+    margin-top: 0
+}
+
+.exampleblock>.content>:last-child {
+    margin-bottom: 0
+}
+
+.sidebarblock {
+    border-style: solid;
+    border-width: 1px;
+    border-color: #dddddd;
+    margin-bottom: 1.25em;
+    padding: 1.25em;
+    background: #f8f8f7;
+    -webkit-border-radius: 4px;
+    border-radius: 4px
+}
+
+.sidebarblock>:first-child {
+    margin-top: 0
+}
+
+.sidebarblock>:last-child {
+    margin-bottom: 0
+}
+
+.sidebarblock>.content>.title {
+    color: #303284;
+    margin-top: 0;
+    text-align: center
+}
+
+.exampleblock>.content>:last-child>:last-child,
+.exampleblock>.content .olist>ol>li:last-child>:last-child,
+.exampleblock>.content .ulist>ul>li:last-child>:last-child,
+.exampleblock>.content .qlist>ol>li:last-child>:last-child,
+.sidebarblock>.content>:last-child>:last-child,
+.sidebarblock>.content .olist>ol>li:last-child>:last-child,
+.sidebarblock>.content .ulist>ul>li:last-child>:last-child,
+.sidebarblock>.content .qlist>ol>li:last-child>:last-child {
+    margin-bottom: 0
+}
+
+.literalblock pre,
+.listingblock pre:not(.highlight),.listingblock 
pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock 
pre.CodeRay,.listingblock pre.prettyprint {
+    background: #f7f7f8
+}
+
+.sidebarblock .literalblock pre,
+.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock 
pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight 
"],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock 
pre.prettyprint {
+    background: #f2f1f1
+}
+
+.literalblock pre,
+.literalblock pre[class],
+.listingblock pre,
+.listingblock pre[class] {
+    -webkit-border-radius: 4px;
+    border-radius: 4px;
+    word-wrap: break-word;
+    padding: 1em;
+    font-size: .8125em
+}
+
+.literalblock pre.nowrap,
+.literalblock pre[class].nowrap,
+.listingblock pre.nowrap,
+.listingblock pre[class].nowrap {
+    overflow-x: auto;
+    white-space: pre;
+    word-wrap: normal
+}
+
+@media screen and (min-width:768px) {
+    .literalblock pre,
+    .literalblock pre[class],
+    .listingblock pre,
+    .listingblock pre[class] {
+        font-size: .90625em
+    }
+
+}
+
+@media screen and (min-width:1280px) {
+    .literalblock pre,
+    .literalblock pre[class],
+    .listingblock pre,
+    .listingblock pre[class] {
+        font-size: 1em
+    }
+
+}
+
+.literalblock.output pre {
+    color: #f7f7f8;
+    background-color: rgba(0, 0, 0, .9)
+}
+
+.listingblock pre.highlightjs {
+    padding: 0
+}
+
+.listingblock pre.highlightjs>code {
+    padding: 1em;
+    -webkit-border-radius: 4px;
+    border-radius: 4px
+}
+
+.listingblock pre.prettyprint {
+    border-width: 0
+}
+
+.listingblock>.content {
+    position: relative
+}
+
+.listingblock code[data-lang]::before {
+    display: none;
+    content: attr(data-lang);
+    position: absolute;
+    font-size: .75em;
+    top: .425rem;
+    right: .5rem;
+    line-height: 1;
+    text-transform: uppercase;
+    color: #999
+}
+
+.listingblock:hover code[data-lang]::before {
+    display: block
+}
+
+.listingblock.terminal pre .command::before {
+    content: attr(data-prompt);
+    padding-right: .5em;
+    color: #999
+}
+
+.listingblock.terminal pre .command:not([data-prompt])::before {
+    content: "$"
+}
+
+table.pyhltable {
+    border-collapse: separate;
+    border: 0;
+    margin-bottom: 0;
+    background: none
+}
+
+table.pyhltable td {
+    vertical-align: top;
+    padding-top: 0;
+    padding-bottom: 0;
+    line-height: 1.45
+}
+
+table.pyhltable td.code {
+    padding-left: .75em;
+    padding-right: 0
+}
+
+pre.pygments .lineno,
+table.pyhltable td:not(.code) {
+    color: #999;
+    padding-left: 0;
+    padding-right: .5em;
+    border-right: 1px solid #dddddd;
+}
+
+pre.pygments .lineno {
+    display: inline-block;
+    margin-right: .25em
+}
+
+table.pyhltable .linenodiv {
+    background: none !important;
+    padding-right: 0 !important
+}
+
+.quoteblock {
+    margin: 0 1em 1.25em 1.5em;
+    display: table
+}
+
+.quoteblock>.title {
+    margin-left: -1.5em;
+    margin-bottom: .75em
+}
+
+.quoteblock blockquote,
+.quoteblock blockquote p {
+    color: rgba(0, 0, 0, .85);
+    font-size: 1.05rem;
+    line-height: 1.75;
+    word-spacing: .1em;
+    letter-spacing: 0;
+    font-style: italic;
+    text-align: justify
+}
+
+.quoteblock blockquote {
+    margin: 0;
+    padding: 0;
+    border: 0
+}
+
+.quoteblock blockquote::before {
+    content: "\201c";
+    float: left;
+    font-size: 2.75em;
+    font-weight: bold;
+    line-height: .6em;
+    margin-left: -.6em;
+    color: #303284;
+    text-shadow: 0 1px 2px rgba(0, 0, 0, .1)
+}
+
+.quoteblock blockquote>.paragraph:last-child p {
+    margin-bottom: 0
+}
+
+.quoteblock .attribution {
+    margin-top: .5em;
+    margin-right: .5ex;
+    text-align: right
+}
+
+.quoteblock .quoteblock {
+    margin-left: 0;
+    margin-right: 0;
+    padding: .5em 0;
+    border-left: 3px solid rgba(0, 0, 0, .6)
+}
+
+.quoteblock .quoteblock blockquote {
+    padding: 0 0 0 .75em
+}
+
+.quoteblock .quoteblock blockquote::before {
+    display: none
+}
+
+.verseblock {
+    margin: 0 1em 1.25em
+}
+
+.verseblock pre {
+    font-family: "Open Sans", "DejaVu Sans", sans;
+    font-size: 1.15rem;
+    color: rgba(0, 0, 0, .85);
+    font-weight: 300;
+    text-rendering: optimizeLegibility
+}
+
+.verseblock pre strong {
+    font-weight: 400
+}
+
+.verseblock .attribution {
+    margin-top: 1.25rem;
+    margin-left: .5ex
+}
+
+.quoteblock .attribution,
+.verseblock .attribution {
+    font-size: .9375em;
+    line-height: 1.45;
+    font-style: italic
+}
+
+.quoteblock .attribution br,
+.verseblock .attribution br {
+    display: none
+}
+
+.quoteblock .attribution cite,
+.verseblock .attribution cite {
+    display: block;
+    letter-spacing: -.025em;
+    color: rgba(0, 0, 0, .6)
+}
+
+.quoteblock.abstract {
+    margin: 0 1em 1.25em;
+    display: block
+}
+
+.quoteblock.abstract>.title {
+    margin: 0 0 .375em;
+    font-size: 1.15em;
+    text-align: center
+}
+
+.quoteblock.abstract blockquote,
+.quoteblock.abstract blockquote p {
+    word-spacing: 0;
+    line-height: 1.6
+}
+
+.quoteblock.abstract blockquote::before,
+.quoteblock.abstract p::before {
+    display: none
+}
+
+table.tableblock {
+    max-width: 100%;
+    border-collapse: separate
+}
+
+p.tableblock:last-child {
+    margin-bottom: 0
+}
+
+td.tableblock>.content {
+    margin-bottom: -1.25em
+}
+
+table.tableblock,
+th.tableblock,
+td.tableblock {
+    border: 0 solid #dddddd;
+}
+
+table.grid-all>thead>tr>.tableblock,
+table.grid-all>tbody>tr>.tableblock {
+    border-width: 0 1px 1px 0
+}
+
+table.grid-all>tfoot>tr>.tableblock {
+    border-width: 1px 1px 0 0
+}
+
+table.grid-cols>*>tr>.tableblock {
+    border-width: 0 1px 0 0
+}
+
+table.grid-rows>thead>tr>.tableblock,
+table.grid-rows>tbody>tr>.tableblock {
+    border-width: 0 0 1px
+}
+
+table.grid-rows>tfoot>tr>.tableblock {
+    border-width: 1px 0 0
+}
+
+table.grid-all>*>tr>.tableblock:last-child,
+table.grid-cols>*>tr>.tableblock:last-child {
+    border-right-width: 0
+}
+
+table.grid-all>tbody>tr:last-child>.tableblock,
+table.grid-all>thead:last-child>tr>.tableblock,
+table.grid-rows>tbody>tr:last-child>.tableblock,
+table.grid-rows>thead:last-child>tr>.tableblock {
+    border-bottom-width: 0
+}
+
+table.frame-all {
+    border-width: 1px
+}
+
+table.frame-sides {
+    border-width: 0 1px
+}
+
+table.frame-topbot,
+table.frame-ends {
+    border-width: 1px 0
+}
+
+table.stripes-all tr,
+table.stripes-odd tr:nth-of-type(odd) {
+    background: #f8f8f7
+}
+
+table.stripes-none tr,
+table.stripes-odd tr:nth-of-type(even) {
+    background: none
+}
+
+th.halign-left,
+td.halign-left {
+    text-align: left
+}
+
+th.halign-right,
+td.halign-right {
+    text-align: right
+}
+
+th.halign-center,
+td.halign-center {
+    text-align: center
+}
+
+th.valign-top,
+td.valign-top {
+    vertical-align: top
+}
+
+th.valign-bottom,
+td.valign-bottom {
+    vertical-align: bottom
+}
+
+th.valign-middle,
+td.valign-middle {
+    vertical-align: middle
+}
+
+table thead th,
+table tfoot th {
+    font-weight: bold
+}
+
+tbody tr th {
+    display: table-cell;
+    line-height: 1.6;
+    background: #f7f8f7
+}
+
+tbody tr th,
+tbody tr th p,
+tfoot tr th,
+tfoot tr th p {
+    color: rgba(0, 0, 0, .8);
+    font-weight: bold
+}
+
+p.tableblock>code:only-child {
+    background: none;
+    padding: 0
+}
+
+p.tableblock {
+    font-size: 1em
+}
+
+td>div.verse {
+    white-space: pre
+}
+
+ol {
+    margin-left: 1.75em
+}
+
+ul li ol {
+    margin-left: 1.5em
+}
+
+dl dd {
+    margin-left: 1.125em
+}
+
+dl dd:last-child,
+dl dd:last-child>:last-child {
+    margin-bottom: 0
+}
+
+ol>li p,
+ul>li p,
+ul dd,
+ol dd,
+.olist .olist,
+.ulist .ulist,
+.ulist .olist,
+.olist .ulist {
+    margin-bottom: .625em
+}
+
+ul.checklist,
+ul.none,
+ol.none,
+ul.no-bullet,
+ol.no-bullet,
+ol.unnumbered,
+ul.unstyled,
+ol.unstyled {
+    list-style-type: none
+}
+
+ul.no-bullet,
+ol.no-bullet,
+ol.unnumbered {
+    margin-left: .625em
+}
+
+ul.unstyled,
+ol.unstyled {
+    margin-left: 0
+}
+
+ul.checklist {
+    margin-left: .625em
+}
+
+ul.checklist li>p:first-child>.fa-square-o:first-child,
+ul.checklist li>p:first-child>.fa-check-square-o:first-child {
+    width: 1.25em;
+    font-size: .8em;
+    position: relative;
+    bottom: .125em
+}
+
+ul.checklist li>p:first-child>input[type="checkbox"]:first-child {
+    margin-right: .25em
+}
+
+ul.inline {
+    display: -ms-flexbox;
+    display: -webkit-box;
+    display: flex;
+    -ms-flex-flow: row wrap;
+    -webkit-flex-flow: row wrap;
+    flex-flow: row wrap;
+    list-style: none;
+    margin: 0 0 .625em -1.25em
+}
+
+ul.inline>li {
+    margin-left: 1.25em
+}
+
+.unstyled dl dt {
+    font-weight: 400;
+    font-style: normal
+}
+
+ol.arabic {
+    list-style-type: decimal
+}
+
+ol.decimal {
+    list-style-type: decimal-leading-zero
+}
+
+ol.loweralpha {
+    list-style-type: lower-alpha
+}
+
+ol.upperalpha {
+    list-style-type: upper-alpha
+}
+
+ol.lowerroman {
+    list-style-type: lower-roman
+}
+
+ol.upperroman {
+    list-style-type: upper-roman
+}
+
+ol.lowergreek {
+    list-style-type: lower-greek
+}
+
+.hdlist>table,
+.colist>table {
+    border: 0;
+    background: none
+}
+
+.hdlist>table>tbody>tr,
+.colist>table>tbody>tr {
+    background: none
+}
+
+td.hdlist1,
+td.hdlist2 {
+    vertical-align: top;
+    padding: 0 .625em
+}
+
+td.hdlist1 {
+    font-weight: bold;
+    padding-bottom: 1.25em
+}
+
+.literalblock+.colist,
+.listingblock+.colist {
+    margin-top: -.5em
+}
+
+.colist td:not([class]):first-child {
+    padding: .4em .75em 0;
+    line-height: 1;
+    vertical-align: top
+}
+
+.colist td:not([class]):first-child img {
+    max-width: none
+}
+
+.colist td:not([class]):last-child {
+    padding: .25em 0
+}
+
+.thumb,
+.th {
+    line-height: 0;
+    display: inline-block;
+    border: solid 4px #fff;
+    -webkit-box-shadow: 0 0 0 1px #ddd;
+    box-shadow: 0 0 0 1px #ddd
+}
+
+.imageblock.left,
+.imageblock[style*="float:left"] {
+    margin: .25em .625em 1.25em 0
+}
+
+.imageblock.right,
+.imageblock[style*="float:right"] {
+    margin: .25em 0 1.25em .625em
+}
+
+.imageblock>.title {
+    margin-bottom: 0
+}
+
+.imageblock.thumb,
+.imageblock.th {
+    border-width: 6px
+}
+
+.imageblock.thumb>.title,
+.imageblock.th>.title {
+    padding: 0 .125em
+}
+
+.image.left,
+.image.right {
+    margin-top: .25em;
+    margin-bottom: .25em;
+    display: inline-block;
+    line-height: 0
+}
+
+.image.left {
+    margin-right: .625em
+}
+
+.image.right {
+    margin-left: .625em
+}
+
+a.image {
+    text-decoration: none;
+    display: inline-block
+}
+
+a.image object {
+    pointer-events: none
+}
+
+sup.footnote,
+sup.footnoteref {
+    font-size: .875em;
+    position: static;
+    vertical-align: super
+}
+
+sup.footnote a,
+sup.footnoteref a {
+    text-decoration: none
+}
+
+sup.footnote a:active,
+sup.footnoteref a:active {
+    text-decoration: underline
+}
+
+#footnotes {
+    padding-top: .75em;
+    padding-bottom: .75em;
+    margin-bottom: .625em
+}
+
+#footnotes hr {
+    width: 20%;
+    min-width: 6.25em;
+    margin: -.25em 0 .75em;
+    border-width: 1px 0 0
+}
+
+#footnotes .footnote {
+    padding: 0 .375em 0 .225em;
+    line-height: 1.3334;
+    font-size: .875em;
+    margin-left: 1.2em;
+    margin-bottom: .2em
+}
+
+#footnotes .footnote a:first-of-type {
+    font-weight: bold;
+    text-decoration: none;
+    margin-left: -1.05em
+}
+
+#footnotes .footnote:last-of-type {
+    margin-bottom: 0
+}
+
+#content #footnotes {
+    margin-top: -.625em;
+    margin-bottom: 0;
+    padding: .75em 0
+}
+
+.gist .file-data>table {
+    border: 0;
+    background: #fff;
+    width: 100%;
+    margin-bottom: 0
+}
+
+.gist .file-data>table td.line-data {
+    width: 99%
+}
+
+div.unbreakable {
+    page-break-inside: avoid
+}
+
+.big {
+    font-size: larger
+}
+
+.small {
+    font-size: smaller
+}
+
+.underline {
+    text-decoration: underline
+}
+
+.overline {
+    text-decoration: overline
+}
+
+.line-through {
+    text-decoration: line-through
+}
+
+.aqua {
+    color: #00bfbf
+}
+
+.aqua-background {
+    background-color: #00fafa
+}
+
+.black {
+    color: #000
+}
+
+.black-background {
+    background-color: #000
+}
+
+.blue {
+    color: #0000bf
+}
+
+.blue-background {
+    background-color: #0000fa
+}
+
+.fuchsia {
+    color: #bf00bf
+}
+
+.fuchsia-background {
+    background-color: #fa00fa
+}
+
+.gray {
+    color: #606060
+}
+
+.gray-background {
+    background-color: #7d7d7d
+}
+
+.green {
+    color: #006000
+}
+
+.green-background {
+    background-color: #007d00
+}
+
+.lime {
+    color: #00bf00
+}
+
+.lime-background {
+    background-color: #00fa00
+}
+
+.maroon {
+    color: #600000
+}
+
+.maroon-background {
+    background-color: #7d0000
+}
+
+.navy {
+    color: #000060
+}
+
+.navy-background {
+    background-color: #00007d
+}
+
+.olive {
+    color: #606000
+}
+
+.olive-background {
+    background-color: #7d7d00
+}
+
+.purple {
+    color: #600060
+}
+
+.purple-background {
+    background-color: #7d007d
+}
+
+.red {
+    color: #bf0000
+}
+
+.red-background {
+    background-color: #fa0000
+}
+
+.silver {
+    color: #909090
+}
+
+.silver-background {
+    background-color: #bcbcbc
+}
+
+.teal {
+    color: #006060
+}
+
+.teal-background {
+    background-color: #007d7d
+}
+
+.white {
+    color: #bfbfbf
+}
+
+.white-background {
+    background-color: #fafafa
+}
+
+.yellow {
+    color: #bfbf00
+}
+
+.yellow-background {
+    background-color: #fafa00
+}
+
+span.icon>.fa {
+    cursor: default
+}
+
+a span.icon>.fa {
+    cursor: inherit
+}
+
+.admonitionblock td.icon [class^="fa icon-"] {
+    font-size: 2.5em;
+    text-shadow: 1px 1px 2px rgba(0, 0, 0, .5);
+    cursor: default
+}
+
+.admonitionblock td.icon .icon-note::before {
+    content: "\f05a";
+    color: #19407c
+}
+
+.admonitionblock td.icon .icon-tip::before {
+    content: "\f0eb";
+    text-shadow: 1px 1px 2px rgba(155, 155, 0, .8);
+    color: #111
+}
+
+.admonitionblock td.icon .icon-warning::before {
+    content: "\f071";
+    color: #bf6900
+}
+
+.admonitionblock td.icon .icon-caution::before {
+    content: "\f06d";
+    color: #bf3400
+}
+
+.admonitionblock td.icon .icon-important::before {
+    content: "\f06a";
+    color: #bf0000
+}
+
+.conum[data-value] {
+    display: inline-block;
+    color: #fff !important;
+    background-color: rgba(0, 0, 0, .8);
+    -webkit-border-radius: 100px;
+    border-radius: 100px;
+    text-align: center;
+    font-size: .75em;
+    width: 1.67em;
+    height: 1.67em;
+    line-height: 1.67em;
+    font-family: "Open Sans", "DejaVu Sans", sans-serif;
+    font-style: normal;
+    font-weight: bold
+}
+
+.conum[data-value] * {
+    color: #fff !important
+}
+
+.conum[data-value]+b {
+    display: none
+}
+
+.conum[data-value]::after {
+    content: attr(data-value)
+}
+
+pre .conum[data-value] {
+    position: relative;
+    top: -.125em
+}
+
+b.conum * {
+    color: inherit !important
+}
+
+.conum:not([data-value]):empty {
+    display: none
+}
+
+dt,
+th.tableblock,
+td.content,
+div.footnote {
+    text-rendering: optimizeLegibility
+}
+
+h1,
+h2,
+p,
+td.content,
+span.alt {
+    letter-spacing: -.01em
+}
+
+p strong,
+td.content strong,
+div.footnote strong {
+    letter-spacing: -.005em
+}
+
+p,
+blockquote,
+dt,
+td.content,
+span.alt {
+    /*font-size: 1.0625rem*/
+}
+
+p {
+    margin-bottom: 1.25rem
+}
+
+.sidebarblock p,
+.sidebarblock dt,
+.sidebarblock td.content,
+p.tableblock {
+    font-size: 1em
+}
+
+.exampleblock>.content {
+    background-color: #fffef7;
+    border-color: #dddddd;
+    -webkit-box-shadow: 0 1px 4px #e0e0dc;
+    box-shadow: 0 1px 4px #e0e0dc
+}
+
+.print-only {
+    display: none !important
+}
+
+@page {
+    margin: 1.25cm .75cm
+}
+
+@media print {
+    * {
+        -webkit-box-shadow: none !important;
+        box-shadow: none !important;
+        text-shadow: none !important
+    }
+
+    html {
+        font-size: 80%
+    }
+
+    a {
+        color: inherit !important;
+        text-decoration: underline !important
+    }
+
+    a.bare,
+    a[href^="#"],
+    a[href^="mailto:";] {
+        text-decoration: none !important
+    }
+
+    a[href^="http:"]:not(.bare)::after,
+    a[href^="https:"]:not(.bare)::after {
+        content: "("attr(href) ")";
+        display: inline-block;
+        font-size: .875em;
+        padding-left: .25em
+    }
+
+    abbr[title]::after {
+        content: " ("attr(title) ")"
+    }
+
+    pre,
+    blockquote,
+    tr,
+    img,
+    object,
+    svg {
+        page-break-inside: avoid
+    }
+
+    thead {
+        display: table-header-group
+    }
+
+    svg {
+        max-width: 100%
+    }
+
+    p,
+    blockquote,
+    dt,
+    td.content {
+        font-size: 1em;
+        orphans: 3;
+        widows: 3
+    }
+
+    h2,
+    h3,
+    #toctitle,
+    .sidebarblock>.content>.title {
+        page-break-after: avoid
+    }
+
+    #toc,
+    .sidebarblock,
+    .exampleblock>.content {
+        background: none !important
+    }
+
+    #toc {
+        border-bottom: 1px solid #dddddd !important;
+        padding-bottom: 0 !important
+    }
+
+    body.book #header {
+        text-align: center
+    }
+
+    body.book #header>h1:first-child {
+        border: 0 !important;
+        margin: 2.5em 0 1em
+    }
+
+    body.book #header .details {
+        border: 0 !important;
+        display: block;
+        padding: 0 !important
+    }
+
+    body.book #header .details span:first-child {
+        margin-left: 0 !important
+    }
+
+    body.book #header .details br {
+        display: block
+    }
+
+    body.book #header .details br+span::before {
+        content: none !important
+    }
+
+    body.book #toc {
+        border: 0 !important;
+        text-align: left !important;
+        padding: 0 !important;
+        margin: 0 !important
+    }
+
+    body.book #toc,
+    body.book #preamble,
+    body.book h1.sect0,
+    body.book .sect1>h2 {
+        page-break-before: always
+    }
+
+    .listingblock code[data-lang]::before {
+        display: block
+    }
+
+    #footer {
+        padding: 0 .9375em
+    }
+
+    .hide-on-print {
+        display: none !important
+    }
+
+    .print-only {
+        display: block !important
+    }
+
+    .hide-for-print {
+        display: none !important
+    }
+
+    .show-for-print {
+        display: inherit !important
+    }
+
+}
+
+@media print, amzn-kf8 {
+    #header>h1:first-child {
+        margin-top: 1.25rem
+    }
+
+    .sect1 {
+        padding: 0 !important
+    }
+
+    .sect1+.sect1 {
+        border: 0
+    }
+
+    #footer {
+        background: none
+    }
+
+    #footer-text {
+        color: rgba(0, 0, 0, .6);
+        font-size: .9em
+    }
+
+}
+
+@media amzn-kf8 {
+    #header,
+    #content,
+    #footnotes,
+    #footer {
+        padding: 0
+    }
+
+}
\ No newline at end of file

Added: incubator/unomi/website/manual/latest/samples/login-sample.html
URL: 
http://svn.apache.org/viewvc/incubator/unomi/website/manual/latest/samples/login-sample.html?rev=1845794&view=auto
==============================================================================
--- incubator/unomi/website/manual/latest/samples/login-sample.html (added)
+++ incubator/unomi/website/manual/latest/samples/login-sample.html Mon Nov  5 
14:08:37 2018
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta name="generator" content="Asciidoctor 1.5.6.1">
+<title>Login samples</title>
+<link rel="stylesheet" href="./apache.css">
+</head>
+<body class="article">
+<div id="header">
+<div id="toc" class="toc">
+<div id="toctitle">Table of Contents</div>
+<ul class="sectlevel2">
+<li><a href="#_login_samples">Login samples</a></li>
+</ul>
+</div>
+</div>
+<div id="content">
+<div class="sect2">
+<h3 id="_login_samples">Login samples</h3>
+<div class="paragraph">
+<p>This samples is an example of what is involved in integrated a login with 
Apache Unomi.</p>
+</div>
+<div class="sect3">
+<h4 id="_warning">Warning !</h4>
+<div class="paragraph">
+<p>The example code uses client-side Javascript code to send the login event. 
This is only
+done this way for the sake of samples simplicity but if should NEVER BE DONE 
THIS WAY in real cases.</p>
+</div>
+<div class="paragraph">
+<p>The login event should always be sent from the server performing the actual 
login since it must
+only be sent if the user has authenticated properly, and only the 
authentication server can validate this.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_installing_the_samples">Installing the samples</h4>
+<div class="paragraph">
+<p>Login into the Unomi Karaf SSH shell using something like this :</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code>ssh -p 8102 karaf@localhost (default password is 
karaf)</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Install the login samples using the following command:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code>bundle:install 
mvn:org.apache.unomi/login-integration-samples/${project.version}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>when the bundle is successfully install you will get an bundle ID back we 
will call it BUNDLE_ID.</p>
+</div>
+<div class="paragraph">
+<p>You can then do:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code>bundle:start BUNDLE_ID</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>If all went well you can access the login samples HTML page here :</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre 
class="highlight"><code>http://localhost:8181/login/index.html</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>You can fill in the form to test it. Note that the hardcoded password 
is:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code>test1234</code></pre>
+</div>
+</div>
+</div>
+</div>
+</div>
+<div id="footer">
+<div id="footer-text">
+Last updated 2018-11-02 16:24:36 CET
+</div>
+</div>
+</body>
+</html>
\ No newline at end of file

Added: incubator/unomi/website/manual/latest/samples/samples.html
URL: 
http://svn.apache.org/viewvc/incubator/unomi/website/manual/latest/samples/samples.html?rev=1845794&view=auto
==============================================================================
--- incubator/unomi/website/manual/latest/samples/samples.html (added)
+++ incubator/unomi/website/manual/latest/samples/samples.html Mon Nov  5 
14:08:37 2018
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta name="generator" content="Asciidoctor 1.5.6.1">
+<title>Samples</title>
+<link rel="stylesheet" href="./apache.css">
+</head>
+<body class="article">
+<div id="header">
+<div id="toc" class="toc">
+<div id="toctitle">Table of Contents</div>
+<ul class="sectlevel2">
+<li><a href="#_samples">Samples</a></li>
+</ul>
+</div>
+</div>
+<div id="content">
+<div class="sect2">
+<h3 id="_samples">Samples</h3>
+<div class="paragraph">
+<p>Apache Unomi provides the following samples:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><a href="twitter-samples.html">Twitter integration</a></p>
+</li>
+<li>
+<p><a href="login-samples.html">Login integration</a></p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div id="footer">
+<div id="footer-text">
+Last updated 2018-09-10 11:30:03 CEST
+</div>
+</div>
+</body>
+</html>
\ No newline at end of file

Added: incubator/unomi/website/manual/latest/samples/twitter-sample.html
URL: 
http://svn.apache.org/viewvc/incubator/unomi/website/manual/latest/samples/twitter-sample.html?rev=1845794&view=auto
==============================================================================
--- incubator/unomi/website/manual/latest/samples/twitter-sample.html (added)
+++ incubator/unomi/website/manual/latest/samples/twitter-sample.html Mon Nov  
5 14:08:37 2018
@@ -0,0 +1,542 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta name="generator" content="Asciidoctor 1.5.6.1">
+<title>Twitter samples</title>
+<link rel="stylesheet" href="./apache.css">
+</head>
+<body class="article">
+<div id="header">
+<div id="toc" class="toc">
+<div id="toctitle">Table of Contents</div>
+<ul class="sectlevel2">
+<li><a href="#_twitter_samples">Twitter samples</a></li>
+<li><a href="#_example">Example</a></li>
+<li><a href="#_conclusion">Conclusion</a></li>
+<li><a href="#_annex">Annex</a></li>
+</ul>
+</div>
+</div>
+<div id="content">
+<div class="sect2">
+<h3 id="_twitter_samples">Twitter samples</h3>
+<div class="sect3">
+<h4 id="_overview">Overview</h4>
+<div class="paragraph">
+<p>We will examine how a simple HTML page can interact with Unomi to enrich a 
user&#8217;s profile. The use case we will follow
+is a rather simple one: we use a Twitter button to record the number of times 
the visitor tweeted (as a <code>tweetNb</code> profile
+integer property) as well as the URLs they tweeted from (as a 
<code>tweetedFrom</code> multi-valued string profile property).
+A javascript script will use the Twitter API to react to clicks on this button
+and update the user profile using a <code>ContextServlet</code> request 
triggering a custom event. This event will, in turn,
+trigger a Unomi action on the server implemented using a Unomi plugin, a 
standard extension point for the server.</p>
+</div>
+<div class="sect4">
+<h5 id="_building_the_tweet_button_samples">Building the tweet button 
samples</h5>
+<div class="paragraph">
+<p>In your local copy of the Unomi repository and run:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code>cd samples/tweet-button-plugin
+mvn clean install</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This will compile and create the OSGi bundle that can be deployed on Unomi 
to extend it.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="_deploying_the_tweet_button_samples">Deploying the tweet button 
samples</h5>
+<div class="paragraph">
+<p>In standard Karaf fashion, you will need to copy the samples bundle to your 
Karaf <code>deploy</code> directory.</p>
+</div>
+<div class="paragraph">
+<p>If you are using the packaged version of Unomi (as opposed to deploying it 
to your own Karaf version), you can simply run, assuming your current directory 
is <code>samples/tweet-button-plugin</code> and that you uncompressed the 
archive in the directory it was created:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code>cp 
target/tweet-button-plugin-1.0.0-incubating-SNAPSHOT.jar 
../../package/target/unomi-1.0.0-incubating-SNAPSHOT/deploy</code></pre>
+</div>
+</div>
+</div>
+<div class="sect4">
+<h5 id="_testing_the_samples">Testing the samples</h5>
+<div class="paragraph">
+<p>You can now go to <a 
href="http://localhost:8181/index.html";>http://localhost:8181/index.html</a> to 
test the samples code. The page is very simple, you will see a Twitter button, 
which, once clicked, will open a new window to tweet about the current page. 
The original page should be updated with the new values of the properties 
coming from Unomi. Additionnally, the raw JSON response is displayed.</p>
+</div>
+<div class="paragraph">
+<p>We will now explain in greater details some concepts and see how the 
example works.</p>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_interacting_with_the_context_server">Interacting with the context 
server</h4>
+<div class="paragraph">
+<p>There are essentially two modalities to interact with the context server, 
reflecting different types of Unomi users: context server clients and context 
server integrators.</p>
+</div>
+<div class="paragraph">
+<p><strong>Context server clients</strong> are usually web applications or 
content management systems. They interact with Unomi by providing raw, 
uninterpreted contextual data in the form of events and associated metadata. 
That contextual data is then processed by the context server to be fed to 
clients once actionable. In that sense context server clients are both 
consumers and producers of contextual data. Context server clients will mostly 
interact with Unomi using a single entry point called the 
<code>ContextServlet</code>, requesting context for the current user and 
providing any triggered events along the way.</p>
+</div>
+<div class="paragraph">
+<p>On the other hand, <strong>context server integrators</strong> provide ways 
to feed more structured data to the context server either to integrate with 
third party services or to provide analysis of the uninterpreted data provided 
by context server clients. Such integration will mostly be done using 
Unomi&#8217;s API either directly using Unomi plugins or via the provided REST 
APIs. However, access to REST APIs is restricted due for security reasons, 
requiring privileged access to the Unomi server, making things a little more 
complex to set up.</p>
+</div>
+<div class="paragraph">
+<p>For simplicity&#8217;s sake, this document will focus solely on the first 
use case and will interact only with the context servlet.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 
id="_retrieving_context_information_from_unomi_using_the_context_servlet">Retrieving
 context information from Unomi using the context servlet</h4>
+<div class="paragraph">
+<p>Unomi provides two ways to retrieve context: either as a pure JSON object 
containing strictly context information or as a couple of JSON objects 
augmented with javascript functions that can be used to interact with the Unomi 
server using the <code>&lt;context server base URL&gt;/context.json</code> or 
<code>&lt;context server base URL&gt;/context.js</code> URLs, respectively.</p>
+</div>
+<div class="paragraph">
+<p>Below is an example of asynchronously loading the initial context using the 
javascript version, assuming a default Unomi install running on <code><a 
href="http://localhost:8181"; class="bare">http://localhost:8181</a></code>:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-javascript" 
data-lang="javascript">// Load context from Unomi asynchronously
+(function (document, elementToCreate, id) {
+    var js, fjs = document.getElementsByTagName(elementToCreate)[0];
+    if (document.getElementById(id)) return;
+    js = document.createElement(elementToCreate);
+    js.id = id;
+    js.src = 'http://localhost:8181/context.js';
+    fjs.parentNode.insertBefore(js, fjs);
+}(document, 'script', 'context'));</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>This initial context results in a javascript file providing some functions 
to interact with the context server from javascript along with two objects: a 
<code>cxs</code> object containing
+information about the context for the current user and a 
<code>digitalData</code> object that is injected into the browser’s 
<code>window</code> object (leveraging the
+<a href="http://www.w3.org/2013/12/ceddl-201312.pdf";>Customer Experience 
Digital Data Layer</a> standard). Note that this last object is not under 
control of the context server and clients
+ are free to use it or not. Our example will not make use of it.</p>
+</div>
+<div class="paragraph">
+<p>On the other hand, the <code>cxs</code> top level object contains 
interesting contextual information about the current user:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-json" data-lang="json">{
+  "profileId":&lt;identifier of the profile associated with the current 
user&gt;,
+  "sessionId":&lt;identifier of the current user session&gt;,
+  "profileProperties":&lt;requested profile properties, if any&gt;,
+  "sessionProperties":&lt;requested session properties, if any&gt;,
+  "profileSegments":&lt;segments the profile is part of if requested&gt;,
+  "filteringResults":&lt;result of the evaluation of personalization 
filters&gt;,
+  "trackedConditions":&lt;tracked conditions in the source page, if any&gt;
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>We will look at the details of the context request and response later.</p>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_example">Example</h3>
+<div class="sect3">
+<h4 id="_html_page">HTML page</h4>
+<div class="paragraph">
+<p>The code for the HTML page with our Tweet button can be found at <a 
href="https://github.com/apache/incubator-unomi/blob/master/wab/src/main/webapp/index.html";>https://github.com/apache/incubator-unomi/blob/master/wab/src/main/webapp/index.html</a>.</p>
+</div>
+<div class="paragraph">
+<p>This HTML page is fairly straightforward: we create a tweet button using 
the Twitter API while a Javascript script performs the actual logic.</p>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_javascript">Javascript</h4>
+<div class="paragraph">
+<p>Globally, the script loads both the twitter widget and the initial context 
asynchronously (as shown previously). This is accomplished using fairly 
standard javascript code and we won&#8217;t look at it here. Using the Twitter 
API, we react to the <code>tweet</code> event and call the Unomi server to 
update the user&#8217;s profile with the required information, triggering a 
custom <code>tweetEvent</code> event. This is accomplished using a 
<code>contextRequest</code> function which is an extended version of a classic 
<code>AJAX</code> request:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-javascript" 
data-lang="javascript">function contextRequest(successCallback, errorCallback, 
payload) {
+    var data = JSON.stringify(payload);
+    // if we don't already have a session id, generate one
+    var sessionId = cxs.sessionId || generateUUID();
+    var url = 'http://localhost:8181/context.json?sessionId=' + sessionId;
+    var xhr = new XMLHttpRequest();
+    var isGet = data.length &lt; 100;
+    if (isGet) {
+        xhr.withCredentials = true;
+        xhr.open("GET", url + "&amp;payload=" + encodeURIComponent(data), 
true);
+    } else if ("withCredentials" in xhr) {
+        xhr.open("POST", url, true);
+        xhr.withCredentials = true;
+    } else if (typeof XDomainRequest != "undefined") {
+        xhr = new XDomainRequest();
+        xhr.open("POST", url);
+    }
+    xhr.onreadystatechange = function () {
+        if (xhr.readyState != 4) {
+            return;
+        }
+        if (xhr.status ==== 200) {
+            var response = xhr.responseText ? JSON.parse(xhr.responseText) : 
undefined;
+            if (response) {
+                cxs.sessionId = response.sessionId;
+                successCallback(response);
+            }
+        } else {
+            console.log("contextserver: " + xhr.status + " ERROR: " + 
xhr.statusText);
+            if (errorCallback) {
+                errorCallback(xhr);
+            }
+        }
+    };
+    xhr.setRequestHeader("Content-Type", "text/plain;charset=UTF-8"); // Use 
text/plain to avoid CORS preflight
+    if (isGet) {
+        xhr.send();
+    } else {
+        xhr.send(data);
+    }
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>There are a couple of things to note here:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>If we specify a payload, it is expected to use the JSON format so we 
<code>stringify</code> it and encode it if passed as a URL parameter in a 
<code>GET</code> request.</p>
+</li>
+<li>
+<p>We need to make a <a 
href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS";><code>CORS</code></a>
 request since the Unomi server is most likely not running on the same host 
than the one from which the request originates. The specific details are fairly 
standard and we will not explain them here.</p>
+</li>
+<li>
+<p>We need to either retrieve (from the initial context we retrieved 
previously using <code>cxs.sessionId</code>) or generate a session identifier 
for our request since Unomi currently requires one.</p>
+</li>
+<li>
+<p>We&#8217;re calling the <code>ContextServlet</code> using the default 
install URI, specifying the session identifier: <code><a 
href="http://localhost:8181/context.json?sessionId=&#39"; 
class="bare">http://localhost:8181/context.json?sessionId=&#39</a>; + 
sessionId</code>. This URI requests context from Unomi, resulting in an updated 
<code>cxs</code> object in the javascript global scope. The context server can 
reply to this request either by returning a JSON-only object containing solely 
the context information as is the case when the requested URI is 
<code>context.json</code>. However, if the client requests 
<code>context.js</code> then useful functions to interact with Unomi are added 
to the <code>cxs</code> object in addition to the context information as 
depicted above.</p>
+</li>
+<li>
+<p>We don&#8217;t need to provide any authentication at all to interact with 
this part of Unomi since we only have access to read-only data (as well as 
providing events as we shall see later on). If we had been using the REST API, 
we would have needed to provide authentication information as well.</p>
+</li>
+</ul>
+</div>
+<div class="sect4">
+<h5 id="_context_request_and_response_structure">Context request and response 
structure</h5>
+<div class="paragraph">
+<p>The interesting part, though, is the payload. This is where we provide 
Unomi with contextual information as well as ask for data in return. This 
allows clients to specify which type of information they are interested in 
getting from the context server as well as specify incoming events or content 
filtering or property/segment overrides for personalization or impersonation. 
This conditions what the context server will return with its response.</p>
+</div>
+<div class="paragraph">
+<p>Let&#8217;s look at the context request structure:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-json" data-lang="json">{
+    source: &lt;Item source of the context request&gt;,
+    events: &lt;optional array of triggered events&gt;,
+    requiredProfileProperties: &lt;optional array of property identifiers&gt;,
+    requiredSessionProperties: &lt;optional array of property identifiers&gt;,
+    filters: &lt;optional array of filters to evaluate&gt;,
+    profileOverrides: &lt;optional profile containing segments,scores or 
profile properties to override&gt;,
+            - segments: &lt;optional array of segment identifiers&gt;,
+            - profileProperties: &lt;optional map of property name / value 
pairs&gt;,
+            - scores: &lt;optional map of score id / value pairs&gt;
+    sessionPropertiesOverrides: &lt;optional map of property name / value 
pairs&gt;,
+    requireSegments: &lt;boolean, whether to return the associated segments&gt;
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>We will now look at each part in greater details.</p>
+</div>
+<div class="sect5">
+<h6 id="_source">Source</h6>
+<div class="paragraph">
+<p>A context request payload needs to at least specify some information about 
the source of the request in the form of an <code>Item</code> (meaning 
identifier, type and scope plus any additional properties we might have to 
provide), via the <code>source</code> property of the payload. Of course the 
more information can be provided about the source, the better.</p>
+</div>
+</div>
+<div class="sect5">
+<h6 id="_filters">Filters</h6>
+<div class="paragraph">
+<p>A client wishing to perform content personalization might also specify 
filtering conditions to be evaluated by the context server so that it can tell 
the client whether the content associated with the filter should be activated 
for this profile/session. This is accomplished by providing a list of filter 
definitions to be evaluated by the context server via the <code>filters</code> 
field of the payload. If provided, the evaluation results will be provided in 
the <code>filteringResults</code> field of the resulting <code>cxs</code> 
object the context server will send.</p>
+</div>
+</div>
+<div class="sect5">
+<h6 id="_overrides">Overrides</h6>
+<div class="paragraph">
+<p>It is also possible for clients wishing to perform user impersonation to 
specify properties or segments to override the proper ones so as to emulate a 
specific profile, in which case the overridden value will temporarily replace 
the proper values so that all rules will be evaluated with these values instead 
of the proper ones. The <code>segments</code> (array of segment identifiers), 
<code>profileProperties</code> (maps of property name and associated object 
value) and <code>scores</code> (maps of score id and value) all wrapped in a 
profileOverrides object and the <code>sessionPropertiesOverrides</code> (maps 
of property name and associated object value) fields allow to provide such 
information. Providing such overrides will, of course, impact content filtering 
results and segments matching for this specific request.</p>
+</div>
+</div>
+<div class="sect5">
+<h6 id="_controlling_the_content_of_the_response">Controlling the content of 
the response</h6>
+<div class="paragraph">
+<p>The clients can also specify which information to include in the response 
by setting the <code>requireSegments</code> property to true if segments the 
current profile matches should be returned or provide an array of property 
identifiers for <code>requiredProfileProperties</code> or 
<code>requiredSessionProperties</code> fields to ask the context server to 
return the values for the specified profile or session properties, 
respectively. This information is provided by the 
<code>profileProperties</code>, <code>sessionProperties</code> and 
<code>profileSegments</code> fields of the context server response.</p>
+</div>
+<div class="paragraph">
+<p>Additionally, the context server will also returns any tracked conditions 
associated with the source of the context request. Upon evaluating the incoming 
request, the context server will determine if there are any rules marked with 
the <code>trackedCondition</code> tag and which source condition matches the 
source of the incoming request and return these tracked conditions to the 
client. The client can use these tracked conditions to learn that the context 
server can react to events matching the tracked condition and coming from that 
source. This is, in particular, used to implement form mapping (a solution that 
allows clients to update user profiles based on values provided when a form is 
submitted).</p>
+</div>
+</div>
+<div class="sect5">
+<h6 id="_events">Events</h6>
+<div class="paragraph">
+<p>Finally, the client can specify any events triggered by the user actions, 
so that the context server can process them, via the <code>events</code> field 
of the context request.</p>
+</div>
+</div>
+<div class="sect5">
+<h6 id="_default_response">Default response</h6>
+<div class="paragraph">
+<p>If no payload is specified, the context server will simply return the 
minimal information deemed necessary for client applications to properly 
function: profile identifier, session identifier and any tracked conditions 
that might exist for the source of the request.</p>
+</div>
+</div>
+</div>
+<div class="sect4">
+<h5 id="_context_request_for_our_example">Context request for our example</h5>
+<div class="paragraph">
+<p>Now that we&#8217;ve seen the structure of the request and what we can 
expect from the context response, let&#8217;s examine the request our component 
is doing.</p>
+</div>
+<div class="paragraph">
+<p>In our case, our <code>source</code> item looks as follows: we specify a 
scope for our application (<code>unomi-tweet-button-samples</code>), specify 
that the item type (i.e. the kind of element that is the source of our event) 
is a <code>page</code> (which corresponds, as would be expected, to a web 
page), provide an identifier (in our case, a Base-64 encoded version of the 
page&#8217;s URL) and finally, specify extra properties (here, simply a 
<code>url</code> property corresponding to the page&#8217;s URL that will be 
used when we process our event in our Unomi extension).</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-javascript" 
data-lang="javascript">var scope = 'unomi-tweet-button-samples';
+var itemId = btoa(window.location.href);
+var source = {
+    itemType: 'page',
+    scope: scope,
+    itemId: itemId,
+    properties: {
+        url: window.location.href
+    }
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>We also specify that we want the context server to return the values of the 
<code>tweetNb</code> and <code>tweetedFrom</code> profile properties in its 
response. Finally, we provide a custom event of type <code>tweetEvent</code> 
with associated scope and source information, which matches the source of our 
context request in this case.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-javascript" 
data-lang="javascript">var contextPayload = {
+    source: source,
+    events: [
+        {
+            eventType: 'tweetEvent',
+            scope: scope,
+            source: source
+        }
+    ],
+    requiredProfileProperties: [
+        'tweetNb',
+        'tweetedFrom'
+    ]
+};</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The <code>tweetEvent</code> event type is not defined by default in Unomi. 
This is where our Unomi plugin comes into play since we need to tell Unomi how 
to react when it encounters such events.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="_unomi_plugin_overview">Unomi plugin overview</h5>
+<div class="paragraph">
+<p>In order to react to <code>tweetEvent</code> events, we will define a new 
Unomi rule since this is exactly what Unomi rules are supposed to do. Rules are 
guarded by conditions and if these
+ conditions match, the associated set of actions will be executed. In our 
case, we want our new
+ <a 
href="https://github.com/apache/incubator-unomi/blob/master/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/rules/incrementTweetNumber.json";><code>incrementTweetNumber</code></a>
 rule to only react to <code>tweetEvent</code> events and
+ we want it to perform the profile update accordingly: create the property 
types for our custom properties if they don&#8217;t exist and update them. To 
do so, we will create a
+ custom
+ <a 
href="https://github.com/apache/incubator-unomi/blob/master/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/actions/incrementTweetNumberAction.json";><code>incrementTweetNumberAction</code></a>
 action that will be triggered any time our rule matches. An action is some 
custom code that is deployed in the context server and can access the
+ Unomi API to perform what it is that it needs to do.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="_rule_definition">Rule definition</h5>
+<div class="paragraph">
+<p>Let&#8217;s look at how our custom <a 
href="https://github.com/apache/incubator-unomi/blob/master/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/rules/incrementTweetNumber.json";><code>incrementTweetNumber</code></a>
 rule is defined:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-json" data-lang="json">{
+  "metadata": {
+    "id": "smp:incrementTweetNumber",
+    "name": "Increment tweet number",
+    "description": "Increments the number of times a user has tweeted after 
they click on a tweet button"
+  },
+  "raiseEventOnlyOnceForSession": false,
+  "condition": {
+    "type": "eventTypeCondition",
+    "parameterValues": {
+      "eventTypeId": "tweetEvent"
+    }
+  },
+  "actions": [
+    {
+      "type": "incrementTweetNumberAction",
+      "parameterValues": {}
+    }
+  ]
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>Rules define a metadata section where we specify the rule name, identifier 
and description.</p>
+</div>
+<div class="paragraph">
+<p>When rules trigger, a specific event is raised so that other parts of Unomi 
can react to it accordingly. We can control how that event should be raised. 
Here we specify that the event should be raised each time the rule triggers and 
not only once per session by setting <code>raiseEventOnlyOnceForSession</code> 
to <code>false</code>, which is not strictly required since that is the 
default. A similar setting (<code>raiseEventOnlyOnceForProfile</code>) can be 
used to specify that the event should only be raised once per profile if 
needed.</p>
+</div>
+<div class="paragraph">
+<p>We could also specify a priority for our rule in case it needs to be 
executed before other ones when similar conditions match. This is accomplished 
using the <code>priority</code> property. We&#8217;re using the default 
priority here since we don&#8217;t have other rules triggering on `tweetEvent`s 
and don&#8217;t need any special ordering.</p>
+</div>
+<div class="paragraph">
+<p>We then tell Unomi which condition should trigger the rule via the 
<code>condition</code> property. Here, we specify that we want our rule to 
trigger on an <code>eventTypeCondition</code> condition. Unomi can be extended 
by adding new condition types that can enrich how matching or querying is 
performed. The condition type definition file specifies which parameters are 
expected for our condition to be complete. In our case, we use the built-in 
event type condition that will match if Unomi receives an event of the type 
specified in the condition&#8217;s <code>eventTypeId</code> parameter value: 
<code>tweetEvent</code> here.</p>
+</div>
+<div class="paragraph">
+<p>Finally, we specify a list of actions that should be performed as 
consequences of the rule matching. We only need one action of type 
<code>incrementTweetNumberAction</code> that doesn&#8217;t require any 
parameters.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="_action_definition">Action definition</h5>
+<div class="paragraph">
+<p>Let&#8217;s now look at our custom <a 
href="https://github.com/apache/incubator-unomi/blob/master/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/actions/incrementTweetNumberAction.json";><code>incrementTweetNumberAction</code></a>
 action type definition:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-json" data-lang="json">{
+  "id": "incrementTweetNumberAction",
+  "actionExecutor": "incrementTweetNumber",
+  "systemTags": [
+    "event"
+  ],
+  "parameters": []
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>We specify the identifier for the action type, a list of systemTags if 
needed: here we say that our action is a consequence of events using the 
<code>event</code> tag. Our actions does not require any parameters so we 
don&#8217;t define any.</p>
+</div>
+<div class="paragraph">
+<p>Finally, we provide a mysterious <code>actionExecutor</code> identifier: 
<code>incrementTweetNumber</code>.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="_action_executor_definition">Action executor definition</h5>
+<div class="paragraph">
+<p>The action executor references the actual implementation of the action as 
defined in our <a 
href="https://github.com/apache/incubator-unomi/blob/master/samples/tweet-button-plugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml";>blueprint
 definition</a>:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-xml" 
data-lang="xml">&lt;blueprint 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+           xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0";
+           xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 
http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"&gt;
+
+    &lt;reference id="profileService" 
interface="org.apache.unomi.api.services.ProfileService"/&gt;
+
+    &lt;!-- Action executor --&gt;
+    &lt;service id="incrementTweetNumberAction" 
interface="org.apache.unomi.api.actions.ActionExecutor"&gt;
+        &lt;service-properties&gt;
+            &lt;entry key="actionExecutorId" value="incrementTweetNumber"/&gt;
+        &lt;/service-properties&gt;
+        &lt;bean 
class="org.apache.unomi.examples.unomi_tweet_button_plugin.actions.IncrementTweetNumberAction"&gt;
+            &lt;property name="profileService" ref="profileService"/&gt;
+        &lt;/bean&gt;
+    &lt;/service&gt;
+&lt;/blueprint&gt;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>In standard Blueprint fashion, we specify that we will need the 
<code>profileService</code> defined by Unomi and then define a service of our 
own to be exported for Unomi to use. Our service specifies one property: 
<code>actionExecutorId</code> which matches the identifier we specified in our 
action definition. We then inject the profile service in our executor and 
we&#8217;re done for the configuration side of things!</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="_action_executor_implementation">Action executor implementation</h5>
+<div class="paragraph">
+<p>Our action executor definition specifies that the bean providing the 
service is implemented in the <a 
href="https://github.com/apache/incubator-unomi/blob/master/samples/tweet-button-plugin/src/main/java/org/apache/unomi/samples/tweet_button_plugin/actions/IncrementTweetNumberAction.java";><code>org.apache.unomi.samples.tweet_button_plugin.actions
+.IncrementTweetNumberAction</code></a> class. This class implements the Unomi 
<code>ActionExecutor</code> interface which provides a single <code>int 
execute(Action action, Event event)</code> method: the executor gets the action 
instance to execute along with the event that triggered it, performs its work 
and returns an integer status corresponding to what happened as defined by 
public constants of the <code>EventService</code> interface of Unomi: 
<code>NO_CHANGE</code>, <code>SESSION_UPDATED</code> or 
<code>PROFILE_UPDATED</code>.</p>
+</div>
+<div class="paragraph">
+<p>Let&#8217;s now look at the implementation of the method:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-java" data-lang="java">final 
Profile profile = event.getProfile();
+Integer tweetNb = (Integer) profile.getProperty(TWEET_NB_PROPERTY);
+List&lt;String&gt; tweetedFrom = (List&lt;String&gt;) 
profile.getProperty(TWEETED_FROM_PROPERTY);
+
+if (tweetNb ==== null || tweetedFrom ==== null) {
+    // create tweet number property type
+    PropertyType propertyType = new PropertyType(new 
Metadata(event.getScope(), TWEET_NB_PROPERTY, TWEET_NB_PROPERTY, "Number of 
times a user tweeted"));
+    propertyType.setValueTypeId("integer");
+    service.createPropertyType(propertyType);
+
+    // create tweeted from property type
+    propertyType = new PropertyType(new Metadata(event.getScope(), 
TWEETED_FROM_PROPERTY, TWEETED_FROM_PROPERTY, "The list of pages a user tweeted 
from"));
+    propertyType.setValueTypeId("string");
+    propertyType.setMultivalued(true);
+    service.createPropertyType(propertyType);
+
+    tweetNb = 0;
+    tweetedFrom = new ArrayList&lt;&gt;();
+}
+
+profile.setProperty(TWEET_NB_PROPERTY, tweetNb + 1);
+final String sourceURL = extractSourceURL(event);
+if (sourceURL != null) {
+    tweetedFrom.add(sourceURL);
+}
+profile.setProperty(TWEETED_FROM_PROPERTY, tweetedFrom);
+
+return EventService.PROFILE_UPDATED;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>It is fairly straightforward: we retrieve the profile associated with the 
event that triggered the rule and check whether it already has the properties 
we are interested in. If not, we create the associated property types and 
initialize the property values.</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>Note that it is not an issue to attempt to create the same property type 
multiple times as Unomi will not add a new property type if an identical type 
already exists.</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>Once this is done, we update our profile with the new property values based 
on the previous values and the metadata extracted from the event using the 
<code>extractSourceURL</code> method which uses our <code>url</code> property 
that we&#8217;ve specified for our event source. We then return that the 
profile was updated as a result of our action and Unomi will properly save it 
for us when appropriate. That&#8217;s it!</p>
+</div>
+<div class="paragraph">
+<p>For reference, here&#8217;s the <code>extractSourceURL</code> method 
implementation:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="highlight"><code class="language-java" data-lang="java">private 
String extractSourceURL(Event event) {
+    final Item sourceAsItem = event.getSource();
+    if (sourceAsItem instanceof CustomItem) {
+        CustomItem source = (CustomItem) sourceAsItem;
+        final String url = (String) source.getProperties().get("url");
+        if (url != null) {
+            return url;
+        }
+    }
+
+    return null;
+}</code></pre>
+</div>
+</div>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_conclusion">Conclusion</h3>
+<div class="paragraph">
+<p>We have seen a simple example how to interact with Unomi using a 
combination of client-side code and Unomi plugin. Hopefully, this provided an 
introduction to the power of what Unomi can do and how it can be extended to 
suit your needs.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_annex">Annex</h3>
+<div class="paragraph">
+<p>Here is an overview of how Unomi processes incoming requests to the 
<code>ContextServlet</code>.
+image: images/unomi-request.png[Unomi request overview]</p>
+</div>
+</div>
+</div>
+<div id="footer">
+<div id="footer-text">
+Last updated 2018-09-10 11:30:03 CEST
+</div>
+</div>
+</body>
+</html>
\ No newline at end of file


Reply via email to