You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by sh...@apache.org on 2018/09/10 09:30:20 UTC

[6/8] incubator-unomi git commit: Add archives versions of documentation in asciidoc

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/b077d27b/manual/src/archives/1.1/asciidoc/getting-started.adoc
----------------------------------------------------------------------
diff --git a/manual/src/archives/1.1/asciidoc/getting-started.adoc b/manual/src/archives/1.1/asciidoc/getting-started.adoc
new file mode 100644
index 0000000..112d07b
--- /dev/null
+++ b/manual/src/archives/1.1/asciidoc/getting-started.adoc
@@ -0,0 +1,461 @@
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+=== Getting started with Unomi
+
+We will first get you up and running with an example. We will then lift the corner of the cover somewhat and explain in greater details what just happened.
+
+==== Prerequisites
+
+This document assumes that you are already familiar with Unomi's link:concepts.html[concepts]. On the technical side, we also assume working knowledge of https://git-scm.com/[git] to be able to retrieve the code for Unomi and the example. Additionnally, you will require a working Java 7 or above install. Refer to http://www.oracle.com/technetwork/java/javase/[http://www.oracle.com/technetwork/java/javase/] for details on how to download and install Java SE 7 or greater.
+
+==== Running Unomi
+
+===== Building Unomi
+
+. Get the code: `git clone https://git-wip-us.apache.org/repos/asf/incubator-unomi.git`
+. Build and install according to the link:building-and-deploying.html[instructions] and install Unomi.
+
+===== Start Unomi
+
+Start Unomi according to the link:building-and-deploying.html#Deploying_the_generated_package[instructions]. Once you have Karaf running,
+ you should wait until you see the following messages on the Karaf console:
+
+[source]
+----
+Initializing user list service endpoint...
+Initializing geonames service endpoint...
+Initializing segment service endpoint...
+Initializing scoring service endpoint...
+Initializing campaigns service endpoint...
+Initializing rule service endpoint...
+Initializing profile service endpoint...
+Initializing cluster service endpoint...
+----
+
+This indicates that all the Unomi services are started and ready to react to requests. You can then open a browser and go to `http://localhost:8181/cxs` to see the list of
+available RESTful services or retrieve an initial context at `http://localhost:8181/context.json` (which isn't very useful at this point).
+
+===== Building the tweet button sample
+
+In your local copy of the Unomi repository and run:
+
+[source]
+----
+cd samples/tweet-button-plugin
+mvn clean install
+----
+
+This will compile and create the OSGi bundle that can be deployed on Unomi to extend it.
+
+===== Deploying the tweet button sample
+
+In standard Karaf fashion, you will need to copy the sample bundle to your Karaf `deploy` directory.
+
+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 `samples/tweet-button-plugin` and that you uncompressed the archive in the directory it was created:
+
+[source]
+----
+cp target/tweet-button-plugin-1.0.0-incubating-SNAPSHOT.jar ../../package/target/unomi-1.0.0-incubating-SNAPSHOT/deploy
+----
+
+===== Testing the sample
+
+You can now go to http://localhost:8181/index.html[http://localhost:8181/index.html] to test the sample 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.
+
+We will now explain in greater details some concepts and see how the example works.
+
+==== Interacting with the context server
+
+There are essentially two modalities to interact with the context server, reflecting different types of Unomi users: context server clients and context server integrators.
+
+*Context server clients* 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 `ContextServlet`, requesting context for the current user and providing any triggered events along the way.
+
+On the other hand, *context server integrators* 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'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.
+
+For simplicity's sake, this document will focus solely on the first use case and will interact only with the context servlet.
+
+==== Retrieving context information from Unomi using the context servlet
+
+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 `<context server base URL>/context.json` or `<context server base URL>/context.js` URLs, respectively.
+
+Below is an example of asynchronously loading the initial context using the javascript version, assuming a default Unomi install running on `http://localhost:8181`:
+
+[source,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'));
+
+----
+
+This initial context results in a javascript file providing some functions to interact with the context server from javascript along with two objects: a `cxs` object containing
+information about the context for the current user and a `digitalData` object that is injected into the browser’s `window` object (leveraging the
+http://www.w3.org/2013/12/ceddl-201312.pdf[Customer Experience Digital Data Layer] 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.
+
+On the other hand, the `cxs` top level object contains interesting contextual information about the current user:
+
+[source,json]
+----
+{
+  "profileId":<identifier of the profile associated with the current user>,
+  "sessionId":<identifier of the current user session>,
+  "profileProperties":<requested profile properties, if any>,
+  "sessionProperties":<requested session properties, if any>,
+  "profileSegments":<segments the profile is part of if requested>,
+  "filteringResults":<result of the evaluation of personalization filters>,
+  "trackedConditions":<tracked conditions in the source page, if any>
+}
+----
+
+We will look at the details of the context request and response later.
+
+=== Example
+
+==== Overview
+
+We will examine how a simple HTML page can interact with Unomi to enrich a user's profile. The use case we will follow is a rather simple one: we want to react to Twitter events by associating information to their profile. We will record the number of times the user tweeted (as a `tweetNb` profile integer property) as well as the URLs they tweeted from (as a `tweetedFrom` multi-valued string profile property). We will accomplish this using a simple HTML page on which we position a standard "Tweet" button. A javascript script will use the Twitter API to react to clicks on this button and update the user profile using a `ContextServlet` 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.
+
+==== HTML page
+
+The code for the HTML page with our Tweet button can be found at 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].
+
+This HTML page is fairly straightforward: we create a tweet button using the Twitter API while a Javascript script performs the actual logic.
+
+==== Javascript
+
+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't look at it here. Using the Twitter API, we react to the `tweet` event and call the Unomi server to update the user's profile with the required information, triggering a custom `tweetEvent` event. This is accomplished using a `contextRequest` function which is an extended version of a classic `AJAX` request:
+
+[source,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 < 100;
+    if (isGet) {
+        xhr.withCredentials = true;
+        xhr.open("GET", url + "&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);
+    }
+}
+----
+
+There are a couple of things to note here:
+
+* If we specify a payload, it is expected to use the JSON format so we `stringify` it and encode it if passed as a URL parameter in a `GET` request.
+* We need to make a https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS[`CORS`] 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.
+* We need to either retrieve (from the initial context we retrieved previously using `cxs.sessionId`) or generate a session identifier for our request since Unomi currently requires one.
+* We're calling the `ContextServlet` using the default install URI, specifying the session identifier: `http://localhost:8181/context.json?sessionId=&#39; + sessionId`. This URI requests context from Unomi, resulting in an updated `cxs` 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 `context.json`. However, if the client requests `context.js` then useful functions to interact with Unomi are added to the `cxs` object in addition to the context information as depicted above.
+* We don'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.
+
+===== Context request and response structure
+
+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.
+
+Let's look at the context request structure:
+
+[source,json]
+----
+{
+    source: <Item source of the context request>,
+    events: <optional array of triggered events>,
+    requiredProfileProperties: <optional array of property identifiers>,
+    requiredSessionProperties: <optional array of property identifiers>,
+    filters: <optional array of filters to evaluate>,
+    profileOverrides: <optional profile containing segments,scores or profile properties to override>,
+        - segments: <optional array of segment identifiers>,
+        - profileProperties: <optional map of property name / value pairs>,
+        - scores: <optional map of score id / value pairs>
+    sessionPropertiesOverrides: <optional map of property name / value pairs>,
+    requireSegments: <boolean, whether to return the associated segments>
+}
+----
+
+We will now look at each part in greater details.
+
+====== Source
+
+A context request payload needs to at least specify some information about the source of the request in the form of an `Item` (meaning identifier, type and scope plus any additional properties we might have to provide), via the `source` property of the payload. Of course the more information can be provided about the source, the better.
+
+====== Filters
+
+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 `filters` field of the payload. If provided, the evaluation results will be provided in the `filteringResults` field of the resulting `cxs` object the context server will send.
+
+====== Overrides
+
+It is also possible for clients wishing to perform user impersonation to specify properties, segments or scores 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 `segments` (array of segment identifiers), `profileProperties` (maps of property name and associated object value) and `scores` (maps of score id and value) all wrapped in a profileOverrides object and the `sessionPropertiesOverrides` (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.
+
+====== Controlling the content of the response
+
+The clients can also specify which information to include in the response by setting the `requireSegments` property to true if segments the current profile matches should be returned or provide an array of property identifiers for `requiredProfileProperties` or `requiredSessionProperties` fields to ask the context server to return the values for the specified profile or session properties, respectively. This information is provided by the `profileProperties`, `sessionProperties` and `profileSegments` fields of the context server response.
+
+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 `trackedCondition` 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).
+
+====== Events
+
+Finally, the client can specify any events triggered by the user actions, so that the context server can process them, via the `events` field of the context request.
+
+====== Default response
+
+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.
+
+===== Context request for our example
+
+Now that we've seen the structure of the request and what we can expect from the context response, let's examine the request our component is doing.
+
+In our case, our `source` item looks as follows: we specify a scope for our application (`unomi-tweet-button-sample`), specify that the item type (i.e. the kind of element that is the source of our event) is a `page` (which corresponds, as would be expected, to a web page), provide an identifier (in our case, a Base-64 encoded version of the page's URL) and finally, specify extra properties (here, simply a `url` property corresponding to the page's URL that will be used when we process our event in our Unomi extension).
+
+[source,javascript]
+----
+var scope = 'unomi-tweet-button-sample';
+var itemId = btoa(window.location.href);
+var source = {
+    itemType: 'page',
+    scope: scope,
+    itemId: itemId,
+    properties: {
+        url: window.location.href
+    }
+};
+----
+
+We also specify that we want the context server to return the values of the `tweetNb` and `tweetedFrom` profile properties in its response. Finally, we provide a custom event of type `tweetEvent` with associated scope and source information, which matches the source of our context request in this case.
+
+[source,javascript]
+----
+var contextPayload = {
+    source: source,
+    events: [
+        {
+            eventType: 'tweetEvent',
+            scope: scope,
+            source: source
+        }
+    ],
+    requiredProfileProperties: [
+        'tweetNb',
+        'tweetedFrom'
+    ]
+};
+----
+
+The `tweetEvent` 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.
+
+===== Unomi plugin overview
+
+In order to react to `tweetEvent` 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
+ https://github.com/apache/incubator-unomi/blob/master/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/rules/incrementTweetNumber.json[`incrementTweetNumber`] rule to only react to `tweetEvent` events and
+ we want it to perform the profile update accordingly: create the property types for our custom properties if they don't exist and update them. To do so, we will create a
+ custom
+ https://github.com/apache/incubator-unomi/blob/master/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/actions/incrementTweetNumberAction.json[`incrementTweetNumberAction`] 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.
+
+===== Rule definition
+
+Let's look at how our custom https://github.com/apache/incubator-unomi/blob/master/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/rules/incrementTweetNumber.json[`incrementTweetNumber`] rule is defined:
+
+[source,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": {}
+    }
+  ]
+}
+----
+
+Rules define a metadata section where we specify the rule name, identifier and description.
+
+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 `raiseEventOnlyOnceForSession` to `false`, which is not strictly required since that is the default. A similar setting (`raiseEventOnlyOnceForProfile`) can be used to specify that the event should only be raised once per profile if needed.
+
+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 `priority` property. We're using the default priority here since we don't have other rules triggering on `tweetEvent`s and don't need any special ordering.
+
+We then tell Unomi which condition should trigger the rule via the `condition` property. Here, we specify that we want our rule to trigger on an `eventTypeCondition` 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's `eventTypeId` parameter value: `tweetEvent` here.
+
+Finally, we specify a list of actions that should be performed as consequences of the rule matching. We only need one action of type `incrementTweetNumberAction` that doesn't require any parameters.
+
+===== Action definition
+
+Let's now look at our custom https://github.com/apache/incubator-unomi/blob/master/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/actions/incrementTweetNumberAction.json[`incrementTweetNumberAction`] action type definition:
+
+[source,json]
+----
+{
+  "id": "incrementTweetNumberAction",
+  "actionExecutor": "incrementTweetNumber",
+  "tags": [
+    "event"
+  ],
+  "parameters": []
+}
+----
+
+We specify the identifier for the action type, a list of tags if needed: here we say that our action is a consequence of events using the `event` tag. Our actions does not require any parameters so we don't define any.
+
+Finally, we provide a mysterious `actionExecutor` identifier: `incrementTweetNumber`.
+
+===== Action executor definition
+
+The action executor references the actual implementation of the action as defined in our https://github.com/apache/incubator-unomi/blob/master/samples/tweet-button-plugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml[blueprint definition]:
+
+[source,xml]
+----
+<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">
+
+    <reference id="profileService" interface="org.apache.unomi.api.services.ProfileService"/>
+
+    <!-- Action executor -->
+    <service id="incrementTweetNumberAction" auto-export="interfaces">
+        <service-properties>
+            <entry key="actionExecutorId" value="incrementTweetNumber"/>
+        </service-properties>
+        <bean class="org.apache.unomi.examples.unomi_tweet_button_plugin.actions.IncrementTweetNumberAction">
+            <property name="profileService" ref="profileService"/>
+        </bean>
+    </service>
+</blueprint>
+----
+
+In standard Blueprint fashion, we specify that we will need the `profileService` defined by Unomi and then define a service of our own to be exported for Unomi to use. Our service specifies one property: `actionExecutorId` which matches the identifier we specified in our action definition. We then inject the profile service in our executor and we're done for the configuration side of things!
+
+===== Action executor implementation
+
+Our action executor definition specifies that the bean providing the service is implemented in the 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[`org.apache.unomi.samples.tweet_button_plugin.actions
+.IncrementTweetNumberAction`] class. This class implements the Unomi `ActionExecutor` interface which provides a single `int execute(Action action, Event event)` 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 `EventService` interface of Unomi: `NO_CHANGE`, `SESSION_UPDATED` or `PROFILE_UPDATED`.
+
+Let's now look at the implementation of the method:
+
+[source,java]
+----
+final Profile profile = event.getProfile();
+Integer tweetNb = (Integer) profile.getProperty(TWEET_NB_PROPERTY);
+List<String> tweetedFrom = (List<String>) 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<>();
+}
+
+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;
+----
+
+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.
+
+____
+
+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.
+
+____
+
+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 `extractSourceURL` method which uses our `url` property that we'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's it!
+
+For reference, here's the `extractSourceURL` method implementation:
+
+[source,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;
+}
+----
+
+=== Conclusion
+
+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.
+
+=== Annex
+
+Here is an overview of how Unomi processes incoming requests to the `ContextServlet`.
+image:../../images/unomi-request.png[Unomi request overview]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/b077d27b/manual/src/archives/1.1/asciidoc/images/asf_logo_url.png
----------------------------------------------------------------------
diff --git a/manual/src/archives/1.1/asciidoc/images/asf_logo_url.png b/manual/src/archives/1.1/asciidoc/images/asf_logo_url.png
new file mode 100644
index 0000000..5ad4544
Binary files /dev/null and b/manual/src/archives/1.1/asciidoc/images/asf_logo_url.png differ

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/b077d27b/manual/src/archives/1.1/asciidoc/images/incubator-logo.png
----------------------------------------------------------------------
diff --git a/manual/src/archives/1.1/asciidoc/images/incubator-logo.png b/manual/src/archives/1.1/asciidoc/images/incubator-logo.png
new file mode 100644
index 0000000..714dbd7
Binary files /dev/null and b/manual/src/archives/1.1/asciidoc/images/incubator-logo.png differ

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/b077d27b/manual/src/archives/1.1/asciidoc/images/unomi-request.png
----------------------------------------------------------------------
diff --git a/manual/src/archives/1.1/asciidoc/images/unomi-request.png b/manual/src/archives/1.1/asciidoc/images/unomi-request.png
new file mode 100755
index 0000000..fdba277
Binary files /dev/null and b/manual/src/archives/1.1/asciidoc/images/unomi-request.png differ

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/b077d27b/manual/src/archives/1.1/asciidoc/index.adoc
----------------------------------------------------------------------
diff --git a/manual/src/archives/1.1/asciidoc/index.adoc b/manual/src/archives/1.1/asciidoc/index.adoc
new file mode 100644
index 0000000..1246e46
--- /dev/null
+++ b/manual/src/archives/1.1/asciidoc/index.adoc
@@ -0,0 +1,55 @@
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+= Apache Unomi 1.1.x - Documentation
+Apache Software Foundation
+:doctype: article
+:toc: left
+:toclevels: 3
+:toc-position: left
+:toc-title: Table of Contents
+:numbered:
+:homepage: https://unomi.apache.org
+
+image::incubator-logo.png[pdfwidth=35%,align=center]
+
+== Concepts
+
+include::concepts.adoc[]
+
+== Quick start
+
+include::building-and-deploying.adoc[]
+
+include::getting-started.adoc[]
+
+include::configuration.adoc[]
+
+== Cluster setup
+
+include::clustering.adoc[]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/b077d27b/manual/src/archives/1.2/asciidoc/apache.css
----------------------------------------------------------------------
diff --git a/manual/src/archives/1.2/asciidoc/apache.css b/manual/src/archives/1.2/asciidoc/apache.css
new file mode 100644
index 0000000..e66d1fa
--- /dev/null
+++ b/manual/src/archives/1.2/asciidoc/apache.css
@@ -0,0 +1,2448 @@
+
+@import "https://fonts.googleapis.com/css?family=Source+Sans+Pro: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: "Source Sans Pro", "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: "Source Sans Pro", "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: "Source Sans Pro", "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: "Source Sans Pro", "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

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/b077d27b/manual/src/archives/1.2/asciidoc/building-and-deploying.adoc
----------------------------------------------------------------------
diff --git a/manual/src/archives/1.2/asciidoc/building-and-deploying.adoc b/manual/src/archives/1.2/asciidoc/building-and-deploying.adoc
new file mode 100644
index 0000000..64075e9
--- /dev/null
+++ b/manual/src/archives/1.2/asciidoc/building-and-deploying.adoc
@@ -0,0 +1,268 @@
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+=== Building
+
+==== Initial Setup
+
+1) Install J2SE 8.0 SDK (or later), which can be downloaded from
+ http://www.oracle.com/technetwork/java/javase/downloads/index.html[http://www.oracle.com/technetwork/java/javase/downloads/index.html]
+
+2) Make sure that your JAVA_HOME environment variable is set to the newly installed
+ JDK location, and that your PATH includes %JAVA_HOME%\bin (windows) or
+ $JAVA_HOME$/bin (unix).
+
+3) Install Maven 3.0.3 (or later), which can be downloaded from
+ http://maven.apache.org/download.html[http://maven.apache.org/download.html]. Make sure that your PATH includes
+ the MVN_HOME/bin directory.
+
+==== Building
+
+1) Change to the top level directory of Apache Unomi source distribution.
+2) Run
+
+[source]
+----
+     $> mvn clean install
+----
+
+This will compile Apache Unomi and run all of the tests in the
+ Apache Unomi source distribution. Alternatively, you can run
+
+[source]
+----
+     $> mvn -P \!integration-tests,\!performance-tests clean install
+----
+
+This will compile Apache Unomi without running the tests and takes less
+ time to build.
+
+3) The distributions will be available under "package/target" directory.
+
+==== Installing an ElasticSearch server
+
+Starting with version 1.2, Apache Unomi no longer embeds an ElasticSearch server as this is no longer supported by
+the developers of ElasticSearch. Therefore you will need to install a standalone ElasticSearch using the following steps:
+
+. 
+
+Download an ElasticSearch version. Here's the version you will need depending
+on your version of Apache Unomi.
+
+Apache Unomi &lt;= 1.2 : https://www.elastic.co/downloads/past-releases/elasticsearch-5-1-2[https://www.elastic.co/downloads/past-releases/elasticsearch-5-1-2]
+Apache Unomi &gt;= 1.3 : https://www.elastic.co/downloads/past-releases/elasticsearch-5-6-3[https://www.elastic.co/downloads/past-releases/elasticsearch-5-6-3]
+
+. 
+
+Uncompress the downloaded package into a directory
+
+. 
+
+In the config/elasticsearch.yml file, uncomment and modify the following line :
+
+[source]
+----
+cluster.name: contextElasticSearch
+----
+
+. 
+
+Launch the server using
+
+[source]
+----
+bin/elasticsearch (Mac, Linux)
+bin\elasticsearch.bat (Windows)
+----
+
+. 
+
+Check that the ElasticSearch is up and running by accessing the following URL : 
+
+http://localhost:9200[http://localhost:9200] 
+
+==== Deploying the generated binary package
+
+The "package" sub-project generates a pre-configured Apache Karaf installation that is the simplest way to get started.
+Simply uncompress the package/target/unomi-VERSION.tar.gz (for Linux or Mac OS X) or
+ package/target/unomi-VERSION.zip (for Windows) archive into the directory of your choice.
+
+You can then start the server simply by using the command on UNIX/Linux/MacOS X : 
+
+[source]
+----
+./bin/karaf    
+----
+
+or on Windows shell : 
+
+[source]
+----
+bin\karaf.bat
+----
+
+==== Deploying into an existing Karaf server
+
+This is only needed if you didn't use the generated package. Also, this is the preferred way to install a development
+environment if you intend to re-deploy the context server KAR iteratively.
+
+Additional requirements:
+* Apache Karaf 3.x, http://karaf.apache.org[http://karaf.apache.org]
+
+. 
+
+Before deploying, make sure that you have Apache Karaf properly installed. You will also have to increase the
+default maximum memory size and perm gen size by adjusting the following environment values in the bin/setenv(.bat)
+files (at the end of the file):
+
+[source]
+----
+   MY_DIRNAME=`dirname $0`
+   MY_KARAF_HOME=`cd "$MY_DIRNAME/.."; pwd`
+   export JAVA_MAX_MEM=3G
+   export JAVA_MAX_PERM_MEM=384M
+----
+
+. 
+
+Install the WAR support, CXF and Karaf Cellar into Karaf by doing the following in the Karaf command line:
+
+[source]
+----
+   feature:repo-add cxf 3.0.2
+   feature:repo-add cellar 3.0.3
+   feature:repo-add mvn:org.apache.unomi/unomi-kar/VERSION/xml/features
+   feature:install unomi-kar
+----
+
+. 
+
+Create a new $MY_KARAF_HOME/etc/org.apache.cxf.osgi.cfg file and put the following property inside :
+
+[source]
+----
+   org.apache.cxf.servlet.context=/cxs
+----
+
+. 
+
+If all went smoothly, you should be able to access the context script here : http://localhost:8181/cxs/cluster[http://localhost:8181/cxs/cluster] .
+ You should be able to login with karaf / karaf and see basic server information. If not something went wrong during the install.
+
+==== JDK Selection on Mac OS X
+
+You might need to select the JDK to run the tests in the itests subproject. In order to do so you can list the
+installed JDKs with the following command : 
+
+[source]
+----
+/usr/libexec/java_home -V
+----
+
+which will output something like this : 
+
+[source]
+----
+Matching Java Virtual Machines (7):
+    1.7.0_51, x86_64:   "Java SE 7"   /Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home
+    1.7.0_45, x86_64:   "Java SE 7"   /Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home
+    1.7.0_25, x86_64:   "Java SE 7"   /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home
+    1.6.0_65-b14-462, x86_64:   "Java SE 6"   /Library/Java/JavaVirtualMachines/1.6.0_65-b14-462.jdk/Contents/Home
+    1.6.0_65-b14-462, i386: "Java SE 6" /Library/Java/JavaVirtualMachines/1.6.0_65-b14-462.jdk/Contents/Home
+    1.6.0_65-b14-462, x86_64:   "Java SE 6"   /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
+    1.6.0_65-b14-462, i386: "Java SE 6" /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
+----
+
+You can then select the one you want using : 
+
+[source]
+----
+export JAVA_HOME=`/usr/libexec/java_home -v 1.7.0_51`
+----
+
+and then check that it was correctly referenced using: 
+
+[source]
+----
+java -version
+----
+
+which should give you a result such as this: 
+
+[source]
+----
+java version "1.7.0_51"
+Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
+Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)
+----
+
+==== Running the integration tests
+
+The integration tests are not executed by default to make build time minimal, but it is recommended to run the
+integration tests at least once before using the server to make sure that everything is ok in the build. Another way
+to use these tests is to run them from a continuous integration server such as Jenkins, Apache Gump, Atlassian Bamboo or
+ others. 
+
+Note : the integration tests require a JDK 7 or more recent !
+
+To run the tests simply activate the following profile : 
+
+[source]
+----
+mvn -P integration-tests clean install
+----
+
+==== Running the performance tests
+
+Performance tests are based on Gatling. You need to have a running context server or cluster of servers before
+executing the tests.
+
+Test parameteres are editable in the performance-tests/src/test/scala/unomi/Parameters.scala file. baseUrls should
+contains the URLs of all your cluster nodes
+
+Run the test by using the gatling.conf file in performance-tests/src/test/resources :
+
+[source]
+----
+    export GATLING_CONF=<path>/performance-tests/src/test/resources
+    gatling.sh
+----
+
+Reports are generated in performance-tests/target/results.
+
+==== Testing with an example page
+
+A default test page is provided at the following URL:
+
+[source]
+----
+   http://localhost:8181/index.html
+----
+
+This test page will trigger the loading of the /context.js script, which will try to retrieving the user context
+or create a new one if it doesn't exist yet. It also contains an experimental integration with Facebook Login, but it
+doesn't yet save the context back to the context server.
+
+==== Integrating onto a page
+
+Simply reference the context script in your HTML as in the following example:
+
+[source,javascript]
+----
+<script type="text/javascript">
+    (function(){ var u=(("https:" == document.location.protocol) ? "https://localhost:8181/" : "http://localhost:8181/");
+    var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript'; g.defer=true; g.async=true; g.src=u+'context.js';
+    s.parentNode.insertBefore(g,s); })();
+</script>
+----
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/b077d27b/manual/src/archives/1.2/asciidoc/clustering.adoc
----------------------------------------------------------------------
diff --git a/manual/src/archives/1.2/asciidoc/clustering.adoc b/manual/src/archives/1.2/asciidoc/clustering.adoc
new file mode 100644
index 0000000..cb0a1ef
--- /dev/null
+++ b/manual/src/archives/1.2/asciidoc/clustering.adoc
@@ -0,0 +1,84 @@
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+=== Cluster setup
+
+Apache Karaf relies on Apache Karaf Cellar, which in turn uses Hazelcast to discover and configure its cluster.
+You just need to install multiple context servers on the same network, and then (optionally) change the Hazelcast
+ configuration in the following file :
+
+[source]
+----
+etc/hazelcast.xml
+----
+
+All nodes on the same network, sharing the same cluster name will be part of the same cluster.
+
+For the actual ElasticSearch configuration however, this must be done using the following file:
+
+[source]
+----
+etc/org.apache.unomi.persistence.elasticsearch.cfg
+----
+
+Depending on the cluster size, you will want to adjust the following parameters to make sure your setup is optimal in
+terms of performance and safety.
+
+==== 2 nodes configuration
+
+One node dedicated to context server, 1 node for elasticsearch storage.
+
+Node A :
+
+[source]
+----
+numberOfReplicas=0
+monthlyIndex.numberOfReplicas=0
+----
+
+Node B :
+
+[source]
+----
+numberOfReplicas=0
+monthlyIndex.numberOfReplicas=0
+----
+
+==== 3 nodes configuration
+
+One node dedicated to context server, 2 nodes for elasticsearch storage with fault-tolerance
+
+Node A :
+
+[source]
+----
+numberOfReplicas=1
+monthlyIndex.numberOfReplicas=1
+----
+
+Node B :
+
+[source]
+----
+numberOfReplicas=1
+monthlyIndex.numberOfReplicas=1
+----
+
+Node C :
+
+[source]
+----
+numberOfReplicas=1
+monthlyIndex.numberOfReplicas=1
+----
\ No newline at end of file