Added: incubator/unomi/website/manual/1_3_x/configuration.html URL: http://svn.apache.org/viewvc/incubator/unomi/website/manual/1_3_x/configuration.html?rev=1845794&view=auto ============================================================================== --- incubator/unomi/website/manual/1_3_x/configuration.html (added) +++ incubator/unomi/website/manual/1_3_x/configuration.html Mon Nov 5 14:08:37 2018 @@ -0,0 +1,529 @@ +<!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>Configuration</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="#_configuration">Configuration</a></li> +<li><a href="#_important">Important !</a></li> +<li><a href="#_installation_steps">Installation steps</a></li> +</ul> +</div> +</div> +<div id="content"> +<div class="sect2"> +<h3 id="_configuration">Configuration</h3> +<div class="sect3"> +<h4 id="_changing_the_default_configuration">Changing the default configuration</h4> +<div class="paragraph"> +<p>If you want to change the default configuration, you can perform any modification you want in the $MY_KARAF_HOME/etc directory.</p> +</div> +<div class="paragraph"> +<p>The context server configuration is kept in the $MY_KARAF_HOME/etc/org.apache.unomi.cluster.cfg . It defines the +addresses where it can be found :</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>contextserver.publicAddress=https://localhost:9443 +contextserver.internalAddress=http://127.0.0.1:8181</code></pre> +</div> +</div> +<div class="paragraph"> +<p>If you need to specify an Elasticsearch cluster name, or a host and port that are different than the default, +it is recommended to do this BEFORE you start the server for the first time, or you will loose all the data +you have stored previously.</p> +</div> +<div class="paragraph"> +<p>To change these settings, you will need to modify a file called</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>$MY_KARAF_HOME/etc/org.apache.unomi.persistence.elasticsearch.cfg</code></pre> +</div> +</div> +<div class="paragraph"> +<p>with the following contents:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>cluster.name=contextElasticSearch +# The elasticSearchAddresses may be a comma seperated list of host names and ports such as +# hostA:9300,hostB:9300 +# Note: the port number must be repeated for each host. +elasticSearchAddresses=localhost:9300 +index.name=context</code></pre> +</div> +</div> +</div> +<div class="sect3"> +<h4 id="_secured_events_configuration">Secured events configuration</h4> +<div class="paragraph"> +<p>Unomi secures some events by default. You can find the default configuration in the following file (created after the +first server startup):</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>$MY_KARAF_HOME/etc/org.apache.unomi.thirdparty.cfg</code></pre> +</div> +</div> +<div class="paragraph"> +<p>Ususally, login events, which operate on profiles and do merge on protected properties, must be secured. For each +trusted third party server, you need to add these 3 lines :</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>thirdparty.provider1.key=secret-key +thirdparty.provider1.ipAddresses=127.0.0.1,::1 +thirdparty.provider1.allowedEvents=login,updateProperties</code></pre> +</div> +</div> +<div class="paragraph"> +<p>The events set in allowedEvents will be secured and will only be accepted if the call comes from the specified IP +address, and if the secret-key is passed in the X-Unomi-Peer header.</p> +</div> +</div> +<div class="sect3"> +<h4 id="_installing_the_maxmind_geoiplite2_ip_lookup_database">Installing the MaxMind GeoIPLite2 IP lookup database</h4> +<div class="paragraph"> +<p>The Context Server requires an IP database in order to resolve IP addresses to user location. +The GeoLite2 database can be downloaded from MaxMind here : +<a href="http://dev.maxmind.com/geoip/geoip2/geolite2/">http://dev.maxmind.com/geoip/geoip2/geolite2/</a></p> +</div> +<div class="paragraph"> +<p>Simply download the GeoLite2-City.mmdb file into the "etc" directory.</p> +</div> +</div> +<div class="sect3"> +<h4 id="_installing_geonames_database">Installing Geonames database</h4> +<div class="paragraph"> +<p>Context server includes a geocoding service based on the geonames database ( <a href="http://www.geonames.org/">http://www.geonames.org/</a> ). It can be +used to create conditions on countries or cities.</p> +</div> +<div class="paragraph"> +<p>In order to use it, you need to install the Geonames database into . Get the "allCountries.zip" database from here : +<a href="http://download.geonames.org/export/dump/">http://download.geonames.org/export/dump/</a></p> +</div> +<div class="paragraph"> +<p>Download it and put it in the "etc" directory, without unzipping it. +Edit $MY_KARAF_HOME/etc/org.apache.unomi.geonames.cfg and set request.geonamesDatabase.forceImport to true, import should start right away. +Otherwise, import should start at the next startup. Import runs in background, but can take about 15 minutes. +At the end, you should have about 4 million entries in the geonames index.</p> +</div> +</div> +<div class="sect3"> +<h4 id="_rest_api_security">REST API Security</h4> +<div class="paragraph"> +<p>The Context Server REST API is protected using JAAS authentication and using Basic or Digest HTTP auth. +By default, the login/password for the REST API full administrative access is "karaf/karaf".</p> +</div> +<div class="paragraph"> +<p>The generated package is also configured with a default SSL certificate. You can change it by following these steps :</p> +</div> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>Replace the existing keystore in $MY_KARAF_HOME/etc/keystore by your own certificate :</p> +</div> +<div class="paragraph"> +<p><a href="http://wiki.eclipse.org/Jetty/Howto/Configure_SSL">http://wiki.eclipse.org/Jetty/Howto/Configure_SSL</a></p> +</div> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>Update the keystore and certificate password in $MY_KARAF_HOME/etc/custom.properties file :</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code> org.osgi.service.http.secure.enabled = true + org.ops4j.pax.web.ssl.keystore=${karaf.etc}/keystore + org.ops4j.pax.web.ssl.password=changeme + org.ops4j.pax.web.ssl.keypassword=changeme + org.osgi.service.http.port.secure=9443</code></pre> +</div> +</div> +<div class="paragraph"> +<p>You should now have SSL setup on Karaf with your certificate, and you can test it by trying to access it on port 9443.</p> +</div> +<div class="olist arabic"> +<ol class="arabic"> +<li> +<p>Changing the default Karaf password can be done by modifying the etc/users.properties file</p> +</li> +</ol> +</div> +</div> +<div class="sect3"> +<h4 id="_automatic_profile_merging">Automatic profile merging</h4> +<div class="paragraph"> +<p>The context server is capable of merging profiles based on a common property value. In order to use this, you must +add the MergeProfileOnPropertyAction to a rule (such as a login rule for example), and configure it with the name + of the property that will be used to identify the profiles to be merged. An example could be the "email" property, + meaning that if two (or more) profiles are found to have the same value for the "email" property they will be merged + by this action.</p> +</div> +<div class="paragraph"> +<p>Upon merge, the old profiles are marked with a "mergedWith" property that will be used on next profile access to delete +the original profile and replace it with the merged profile (aka "master" profile). Once this is done, all cookie tracking +will use the merged profile.</p> +</div> +<div class="paragraph"> +<p>To test, simply configure the action in the "login" or "facebookLogin" rules and set it up on the "email" property. +Upon sending one of the events, all matching profiles will be merged.</p> +</div> +</div> +<div class="sect3"> +<h4 id="_securing_a_production_environment">Securing a production environment</h4> +<div class="paragraph"> +<p>Before going live with a project, you should <em>absolutely</em> read the following section that will help you setup a proper +secure environment for running your context server.</p> +</div> +<div class="paragraph"> +<p>Step 1: Install and configure a firewall</p> +</div> +<div class="paragraph"> +<p>You should setup a firewall around your cluster of context servers and/or Elasticsearch nodes. If you have an +application-level firewall you should only allow the following connections open to the whole world :</p> +</div> +<div class="ulist"> +<ul> +<li> +<p><a href="http://localhost:8181/context.js">http://localhost:8181/context.js</a></p> +</li> +<li> +<p><a href="http://localhost:8181/eventcollector">http://localhost:8181/eventcollector</a></p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>All other ports should not be accessible to the world.</p> +</div> +<div class="paragraph"> +<p>For your Context Server client applications (such as the Jahia CMS), you will need to make the following ports +accessible :</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>8181 (Context Server HTTP port) +9443 (Context Server HTTPS port)</code></pre> +</div> +</div> +<div class="paragraph"> +<p>The context server actually requires HTTP Basic Auth for access to the Context Server administration REST API, so it is +highly recommended that you design your client applications to use the HTTPS port for accessing the REST API.</p> +</div> +<div class="paragraph"> +<p>The user accounts to access the REST API are actually routed through Karaf’s JAAS support, which you may find the +documentation for here :</p> +</div> +<div class="ulist"> +<ul> +<li> +<p><a href="http://karaf.apache.org/manual/latest/users-guide/security.html">http://karaf.apache.org/manual/latest/users-guide/security.html</a></p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>The default username/password is</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>karaf/karaf</code></pre> +</div> +</div> +<div class="paragraph"> +<p>You should really change this default username/password as soon as possible. To do so, simply modify the following +file :</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>$MY_KARAF_HOME/etc/users.properties</code></pre> +</div> +</div> +<div class="paragraph"> +<p>For your context servers, and for any standalone Elasticsearch nodes you will need to open the following ports for proper +node-to-node communication : 9200 (Elasticsearch REST API), 9300 (Elasticsearch TCP transport)</p> +</div> +<div class="paragraph"> +<p>Of course any ports listed here are the default ports configured in each server, you may adjust them if needed.</p> +</div> +<div class="paragraph"> +<p>Step 2 : Follow industry recommended best practices for securing Elasticsearch</p> +</div> +<div class="paragraph"> +<p>You may find more valuable recommendations here :</p> +</div> +<div class="ulist"> +<ul> +<li> +<p><a href="https://www.elastic.co/blog/found-elasticsearch-security">https://www.elastic.co/blog/found-elasticsearch-security</a></p> +</li> +<li> +<p><a href="https://www.elastic.co/blog/scripting-security">https://www.elastic.co/blog/scripting-security</a></p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>Step 4 : Setup a proxy in front of the context server</p> +</div> +<div class="paragraph"> +<p>As an alternative to an application-level firewall, you could also route all traffic to the context server through +a proxy, and use it to filter any communication.</p> +</div> +</div> +<div class="sect3"> +<h4 id="_integrating_with_an_apache_http_web_server">Integrating with an Apache HTTP web server</h4> +<div class="paragraph"> +<p>If you want to setup an Apache HTTP web server in from of Apache Unomi, here is an example configuration using +mod_proxy.</p> +</div> +<div class="paragraph"> +<p>In your Unomi package directory, in /etc/org.apache.unomi.cluster.cfg for unomi.apache.org</p> +</div> +<div class="paragraph"> +<p>contextserver.publicAddress=https://unomi.apache.org/ + contextserver.internalAddress=http://192.168.1.1:8181</p> +</div> +<div class="paragraph"> +<p>and you will also need to change the contextserver.domain in the /etc/org.apache.unomi.web.cfg file</p> +</div> +<div class="paragraph"> +<p>contextserver.domain=apache.org</p> +</div> +<div class="paragraph"> +<p>Main virtual host config:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code><VirtualHost *:80> + Include /var/www/vhosts/unomi.apache.org/conf/common.conf +</VirtualHost> + +<IfModule mod_ssl.c> + <VirtualHost *:443> + Include /var/www/vhosts/unomi.apache.org/conf/common.conf + + SSLEngine on + + SSLCertificateFile /var/www/vhosts/unomi.apache.org/conf/ssl/24d5b9691e96eafa.crt + SSLCertificateKeyFile /var/www/vhosts/unomi.apache.org/conf/ssl/apache.org.key + SSLCertificateChainFile /var/www/vhosts/unomi.apache.org/conf/ssl/gd_bundle-g2-g1.crt + + <FilesMatch "\.(cgi|shtml|phtml|php)$"> + SSLOptions +StdEnvVars + </FilesMatch> + <Directory /usr/lib/cgi-bin> + SSLOptions +StdEnvVars + </Directory> + BrowserMatch "MSIE [2-6]" \ + nokeepalive ssl-unclean-shutdown \ + downgrade-1.0 force-response-1.0 + BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown + + </VirtualHost> +</IfModule></code></pre> +</div> +</div> +<div class="paragraph"> +<p>common.conf:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>ServerName unomi.apache.org +ServerAdmin webmas...@apache.org + +DocumentRoot /var/www/vhosts/unomi.apache.org/html +CustomLog /var/log/apache2/access-unomi.apache.org.log combined +<Directory /> + Options FollowSymLinks + AllowOverride None +</Directory> +<Directory /var/www/vhosts/unomi.apache.org/html> + Options FollowSymLinks MultiViews + AllowOverride None + Order allow,deny + allow from all +</Directory> +<Location /cxs> + Order deny,allow + deny from all + allow from 88.198.26.2 + allow from www.apache.org +</Location> + +RewriteEngine On +RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK) +RewriteRule .* - [F] +ProxyPreserveHost On +ProxyPass /server-status ! +ProxyPass /robots.txt ! + +RewriteCond %{HTTP_USER_AGENT} Googlebot [OR] +RewriteCond %{HTTP_USER_AGENT} msnbot [OR] +RewriteCond %{HTTP_USER_AGENT} Slurp +RewriteRule ^.* - [F,L] + +ProxyPass / http://localhost:8181/ connectiontimeout=20 timeout=300 ttl=120 +ProxyPassReverse / http://localhost:8181/</code></pre> +</div> +</div> +</div> +<div class="sect3"> +<h4 id="_changing_the_default_tracking_location">Changing the default tracking location</h4> +<div class="paragraph"> +<p>When performing localhost requests to Apache Unomi, a default location will be used to insert values into the session +to make the location-based personalization still work. You can find the default location settings in the file :</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>org.apache.unomi.plugins.request.cfg</code></pre> +</div> +</div> +<div class="paragraph"> +<p>that contains the following default settings:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code># The following settings represent the default position that is used for localhost requests +defaultSessionCountryCode=CH +defaultSessionCountryName=Switzerland +defaultSessionCity=Geneva +defaultSessionAdminSubDiv1=2660645 +defaultSessionAdminSubDiv2=6458783 +defaultSessionIsp=Cablecom +defaultLatitude=46.1884341 +defaultLongitude=6.1282508</code></pre> +</div> +</div> +<div class="paragraph"> +<p>You might want to change these for testing or for demonstration purposes.</p> +</div> +</div> +<div class="sect3"> +<h4 id="_apache_karaf_ssh_console">Apache Karaf SSH Console</h4> +<div class="paragraph"> +<p>The Apache Karaf SSH console is available inside Apache Unomi, but the port has been changed from the default value of +8101 to 8102 to avoid conflicts with other Karaf-based products. So to connect to the SSH console you should use:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>ssh -p 8102 karaf@localhost</code></pre> +</div> +</div> +<div class="paragraph"> +<p>or the user/password you have setup to protect the system if you have changed it.</p> +</div> +</div> +<div class="sect3"> +<h4 id="_elasticsearch_x_pack_support">ElasticSearch X-Pack Support</h4> +<div class="paragraph"> +<p>It is now possible to use X-Pack to connect to ElasticSearch. However, for licensing reasons this is not provided out +of the box. Here is the procedure to install X-Pack with Apache Unomi:</p> +</div> +</div> +</div> +<div class="sect2"> +<h3 id="_important">Important !</h3> +<div class="paragraph"> +<p>Do not start Unomi directly with unomi:start, perform the following steps below first !</p> +</div> +</div> +<div class="sect2"> +<h3 id="_installation_steps">Installation steps</h3> +<div class="olist arabic"> +<ol class="arabic"> +<li> +<p>Create a directory for all the JARs that you will download, we will call it XPACK_JARS_DIRECTORY</p> +</li> +<li> +<p>Download <a href="https://artifacts.elastic.co/maven/org/elasticsearch/client/x-pack-transport/5.6.3/x-pack-transport-5.6.3.jar">https://artifacts.elastic.co/maven/org/elasticsearch/client/x-pack-transport/5.6.3/x-pack-transport-5.6.3.jar</a> to XPACK_JARS_DIRECTORY</p> +</li> +<li> +<p>Download <a href="https://artifacts.elastic.co/maven/org/elasticsearch/plugin/x-pack-api/5.6.3/x-pack-api-5.6.3.jar">https://artifacts.elastic.co/maven/org/elasticsearch/plugin/x-pack-api/5.6.3/x-pack-api-5.6.3.jar</a> to XPACK_JARS_DIRECTORY</p> +</li> +<li> +<p>Download <a href="http://central.maven.org/maven2/com/unboundid/unboundid-ldapsdk/3.2.0/unboundid-ldapsdk-3.2.0.jar">http://central.maven.org/maven2/com/unboundid/unboundid-ldapsdk/3.2.0/unboundid-ldapsdk-3.2.0.jar</a> to XPACK_JARS_DIRECTORY</p> +</li> +<li> +<p>Download <a href="http://central.maven.org/maven2/org/bouncycastle/bcpkix-jdk15on/1.55/bcpkix-jdk15on-1.55.jar">http://central.maven.org/maven2/org/bouncycastle/bcpkix-jdk15on/1.55/bcpkix-jdk15on-1.55.jar</a> to XPACK_JARS_DIRECTORY</p> +</li> +<li> +<p>Download <a href="http://central.maven.org/maven2/org/bouncycastle/bcprov-jdk15on/1.55/bcprov-jdk15on-1.55.jar">http://central.maven.org/maven2/org/bouncycastle/bcprov-jdk15on/1.55/bcprov-jdk15on-1.55.jar</a> to XPACK_JARS_DIRECTORY</p> +</li> +<li> +<p>Download <a href="http://central.maven.org/maven2/com/sun/mail/javax.mail/1.5.3/javax.mail-1.5.3.jar">http://central.maven.org/maven2/com/sun/mail/javax.mail/1.5.3/javax.mail-1.5.3.jar</a> to XPACK_JARS_DIRECTORY +.</p> +</li> +</ol> +</div> +<div class="paragraph"> +<p>Edit etc/org.apache.unomi.persistence.elasticsearch.cfg to add the following settings:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>transportClientClassName=org.elasticsearch.xpack.client.PreBuiltXPackTransportClient +transportClientJarDirectory=XPACK_JARS_DIRECTORY +transportClientProperties=xpack.security.user=elastic:changeme</code></pre> +</div> +</div> +<div class="paragraph"> +<p>You can setup more properties (for example for SSL/TLS support) by seperating the properties with commas, +as in the following example:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>transportClientProperties=xpack.security.user=elastic:changeme,xpack.ssl.key=/home/user/elasticsearch-5.6.3/config/x-pack/localhost/localhost.key,xpack.ssl.certificate=/home/user/elasticsearch-5.6.3/config/x-pack/localhost/localhost.crt,xpack.ssl.certificate_authorities=/home/user/elasticsearch-5.6.3/config/x-pack/ca/ca.crt,xpack.security.transport.ssl.enabled=true</code></pre> +</div> +</div> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>Launch Karaf and launch unomi using the command from the shell :</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>unomi:start</code></pre> +</div> +</div> +<div class="paragraph"> +<p>Alternatively you could edit the configuration directly from the Karaf shell using the following commands:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>config:edit org.apache.unomi.persistence.elasticsearch +config:property-set transportClientClassName org.elasticsearch.xpack.client.PreBuiltXPackTransportClient +config:property-set transportClientJarDirectory XPACK_JARS_DIRECTORY +config:property-set transportClientProperties xpack.security.user=elastic:changeme +config:update +unomi:start</code></pre> +</div> +</div> +<div class="paragraph"> +<p>You can setup more properties (for example for SSL/TLS support) by seperating the properties with commas, +as in the following example:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>config:property-set transportClientProperties xpack.security.user=elastic:changeme,xpack.ssl.key=/home/user/elasticsearch-5.6.3/config/x-pack/localhost/localhost.key,xpack.ssl.certificate=/home/user/elasticsearch-5.6.3/config/x-pack/localhost/localhost.crt,xpack.ssl.certificate_authorities=/home/user/elasticsearch-5.6.3/config/x-pack/ca/ca.crt,xpack.security.transport.ssl.enabled=true</code></pre> +</div> +</div> +</div> +</div> +<div id="footer"> +<div id="footer-text"> +Last updated 2018-09-20 20:40:36 CEST +</div> +</div> +</body> +</html> \ No newline at end of file
Added: incubator/unomi/website/manual/1_3_x/connectors/apache.css URL: http://svn.apache.org/viewvc/incubator/unomi/website/manual/1_3_x/connectors/apache.css?rev=1845794&view=auto ============================================================================== --- incubator/unomi/website/manual/1_3_x/connectors/apache.css (added) +++ incubator/unomi/website/manual/1_3_x/connectors/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/1_3_x/connectors/connectors.html URL: http://svn.apache.org/viewvc/incubator/unomi/website/manual/1_3_x/connectors/connectors.html?rev=1845794&view=auto ============================================================================== --- incubator/unomi/website/manual/1_3_x/connectors/connectors.html (added) +++ incubator/unomi/website/manual/1_3_x/connectors/connectors.html Mon Nov 5 14:08:37 2018 @@ -0,0 +1,47 @@ +<!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>Connectors</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="#_connectors">Connectors</a></li> +</ul> +</div> +</div> +<div id="content"> +<div class="sect2"> +<h3 id="_connectors">Connectors</h3> +<div class="paragraph"> +<p>Apache Unomi provides the following connectors:</p> +</div> +<div class="ulist"> +<ul> +<li> +<p><a href="salesforce-connectors.html">Salesforce CRM connectors</a></p> +</li> +</ul> +</div> +<div class="sect3"> +<h4 id="_call_for_contributors">Call for contributors</h4> +<div class="paragraph"> +<p>We are looking for help with the development of additional connectors. Any contribution (large or small) is more than welcome. Feel free to discuss this in our <a href="../../mail-lists.html">mailing list</a>.</p> +</div> +</div> +</div> +</div> +<div id="footer"> +<div id="footer-text"> +Last updated 2018-09-20 20:40:36 CEST +</div> +</div> +</body> +</html> \ No newline at end of file Added: incubator/unomi/website/manual/1_3_x/connectors/salesforce-connector.html URL: http://svn.apache.org/viewvc/incubator/unomi/website/manual/1_3_x/connectors/salesforce-connector.html?rev=1845794&view=auto ============================================================================== --- incubator/unomi/website/manual/1_3_x/connectors/salesforce-connector.html (added) +++ incubator/unomi/website/manual/1_3_x/connectors/salesforce-connector.html Mon Nov 5 14:08:37 2018 @@ -0,0 +1,286 @@ +<!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>Apache Unomi Salesforce Connector</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="#_apache_unomi_salesforce_connector">Apache Unomi Salesforce Connector</a></li> +</ul> +</div> +</div> +<div id="content"> +<div class="sect2"> +<h3 id="_apache_unomi_salesforce_connector">Apache Unomi Salesforce Connector</h3> +<div class="paragraph"> +<p>This connectors makes it possible to push and pull data to/from the Salesforce CRM. It can copy information between +Apache Unomi profiles and Salesforce Leads.</p> +</div> +<div class="sect3"> +<h4 id="_getting_started">Getting started</h4> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>Create a new developer account here:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>https://developer.salesforce.com/signup</code></pre> +</div> +</div> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>Create a new Connected App, by going into Setup -> App Manager and click "Create Connected App"</p> +</div> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>In the settings, make sure you do the following:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>Enable OAuth settings -> Activated +Enable for device flow -> Activated (no need for a callback URL) +Add all the selected OAuth scopes you want (or put all of them) +Make sure Require Secret for Web Server flow is activated</code></pre> +</div> +</div> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>Make sure you retrieve the following information once you have created the app in the API (Enable OAuth Settings):</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>Consumer key +Consumer secret (click to see it)</code></pre> +</div> +</div> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>You must also retrieve your user’s security token, or create it if you don’t have one already. To do this simply +click on your user at the top right, select "Settings", the click on "Reset my security token". You will receive an email +with the security token.</p> +</div> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>You are now ready to configure the Apache Unomi Salesforce Connector. In the etc/org.apache.unomi.sfdc.cfg file +change the following settings:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>sfdc.user.username=YOUR_USER_NAME +sfdc.user.password=YOUR_PASSWORD +sfdc.user.securityToken=YOUR_USER_SECURITY_TOKEN +sfdc.consumer.key=CONNECTED_APP_CONSUMER_KEY +sfdc.consumer.secret=CONNECTED_APP_SECRET</code></pre> +</div> +</div> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>Connected to the Apache Unomi Karaf Shell using :</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>.</p> +</div> +<div class="paragraph"> +<p>Deploy into Apache Unomi using the following commands from the Apache Karaf shell:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>feature:repo-add mvn:org.apache.unomi/unomi-salesforce-connectors-karaf-kar/${project.version}/xml/features +feature:install unomi-salesforce-connectors-karaf-kar</code></pre> +</div> +</div> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>You can then test the connection to Salesforce by accessing the following URLs:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>https://localhost:9443/cxs/sfdc/version +https://localhost:9443/cxs/sfdc/limits</code></pre> +</div> +</div> +<div class="paragraph"> +<p>The first URL will give you information about the version of the connectors, so this makes it easy to check that the +plugin is properly deployed, started and the correct version. The second URL will actually make a request to the +Salesforce REST API to retrieve the limits of the Salesforce API.</p> +</div> +<div class="paragraph"> +<p>Both URLs are password protected by the Apache Unomi (Karaf) password. You can find this user and password information +in the etc/users.properties file.</p> +</div> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>You can now use the connectors’s defined actions in rules to push or pull data to/from the Salesforce CRM. You can +find more information about rules in the <a href="concepts.html">Concepts</a> and the <a href="getting-started.html">Getting Started</a> pages.</p> +</div> +</div> +<div class="sect3"> +<h4 id="_upgrading_the_salesforce_connectors">Upgrading the Salesforce connectors</h4> +<div class="paragraph"> +<p>If you followed all the steps in the Getting Started section, you can upgrade the Salesforce connectors by using the following steps:</p> +</div> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>Compile the connectors using:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>cd extensions/salesforce-connectors +mvn clean install</code></pre> +</div> +</div> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>Login to the Unomi Karaf Shell using:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>ssh -p 8102 karaf@localhost (password by default is karaf)</code></pre> +</div> +</div> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>Execute the following commands in the Karaf shell</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>feature:repo-refresh +feature:uninstall unomi-salesforce-connectors-karaf-feature +feature:install unomi-salesforce-connectors-karaf-feature</code></pre> +</div> +</div> +<div class="paragraph"> +<p>.</p> +</div> +<div class="paragraph"> +<p>You can then check that the new version is properly deployed by accessing the following URL and checking the build date:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>https://localhost:9443/cxs/sfdc/version</code></pre> +</div> +</div> +<div class="paragraph"> +<p>(if asked for a password it’s the same karaf/karaf default)</p> +</div> +</div> +<div class="sect3"> +<h4 id="_using_the_salesforce_workbench_for_testing_rest_api">Using the Salesforce Workbench for testing REST API</h4> +<div class="paragraph"> +<p>The Salesforce Workbench contains a REST API Explorer that is very useful to test requests. You may find it here :</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>https://workbench.developerforce.com/restExplorer.php</code></pre> +</div> +</div> +</div> +<div class="sect3"> +<h4 id="_setting_up_streaming_push_queries">Setting up Streaming Push queries</h4> +<div class="paragraph"> +<p>Using the Salesforce Workbench, you can setting streaming push queries (Queries->Streaming push topics) such as the +following example:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>Name: LeadUpdates +Query : SELECT Id,FirstName,LastName,Email,Company FROM Lead</code></pre> +</div> +</div> +</div> +<div class="sect3"> +<h4 id="_executing_the_unit_tests">Executing the unit tests</h4> +<div class="paragraph"> +<p>Before running the tests, make sure you have completed all the steps above, including the streaming push queries setup.</p> +</div> +<div class="paragraph"> +<p>By default the unit tests will not run as they need proper Salesforce credentials to run. To set this up create a +properties file like the following one:</p> +</div> +<div class="paragraph"> +<p>test.properties</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code># +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +sfdc.user.username=YOUR_USER_NAME +sfdc.user.password=YOUR_PASSWORD +sfdc.user.securityToken=YOUR_USER_SECURITY_TOKEN +sfdc.consumer.key=CONNECTED_APP_CONSUMER_KEY +sfdc.consumer.secret=CONNECTED_APP_SECRET</code></pre> +</div> +</div> +<div class="paragraph"> +<p>and then use the following command line to reference the file:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>cd extensions/salesforce-connectors +mvn clean install -DsfdcProperties=../test.properties</code></pre> +</div> +</div> +<div class="paragraph"> +<p>(in case you’re wondering the ../ is because the test is located in the services sub-directory)</p> +</div> +</div> +</div> +</div> +<div id="footer"> +<div id="footer-text"> +Last updated 2018-09-20 20:40:36 CEST +</div> +</div> +</body> +</html> \ No newline at end of file Added: incubator/unomi/website/manual/1_3_x/consent-api.html URL: http://svn.apache.org/viewvc/incubator/unomi/website/manual/1_3_x/consent-api.html?rev=1845794&view=auto ============================================================================== --- incubator/unomi/website/manual/1_3_x/consent-api.html (added) +++ incubator/unomi/website/manual/1_3_x/consent-api.html Mon Nov 5 14:08:37 2018 @@ -0,0 +1,185 @@ +<!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>Consent API</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="#_consent_api">Consent API</a></li> +</ul> +</div> +</div> +<div id="content"> +<div class="sect2"> +<h3 id="_consent_api">Consent API</h3> +<div class="paragraph"> +<p>Starting with Apache Unomi 1.3 (still in development), a new API for consent management is now available. This API +is designed to be able to store/retrieve/update visitor consents in order to comply with new +privacy regulations such as the <a href="https://en.wikipedia.org/wiki/General_Data_Protection_Regulation">GDPR</a>.</p> +</div> +<div class="sect3"> +<h4 id="_profiles_with_consents">Profiles with consents</h4> +<div class="paragraph"> +<p>Visitor profiles now contain a new Consent object that contains the following information:</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>a scope</p> +</li> +<li> +<p>a type identifier for the consent. This can be any key to reference a consent. Note that Unomi does not manage consent +definitions, it only stores/retrieves consents for each profile based on this type</p> +</li> +<li> +<p>a status : GRANT, DENY or REVOKED</p> +</li> +<li> +<p>a status date (the date at which the status was updated)</p> +</li> +<li> +<p>a revocation date, in order to comply with GDPR this is usually set at two years</p> +</li> +</ul> +</div> +<div class="paragraph"> +<p>Here is an example of a Profile with a consent attached to it:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>{ + "profileId": "8cbe380f-57bb-419d-97bf-24bf30178550", + "sessionId": "0d755f4e-154a-45c8-9169-e852e1d706d9", + "consents": { + "example/newsletter": { + "scope": "example", + "typeIdentifier": "newsletter", + "status": "GRANTED", + "statusDate": "2018-05-22T09:44:33Z", + "revokeDate": "2020-05-21T09:44:33Z" + } + } +}</code></pre> +</div> +</div> +<div class="paragraph"> +<p>It is of course possible to have multiple consents defined for a single visitor profile.</p> +</div> +</div> +<div class="sect3"> +<h4 id="_consent_type_definitions">Consent type definitions</h4> +<div class="paragraph"> +<p>Apache Unomi does not manage consent definitions, it leaves that to an external system (for example a CMS) so that it +can handle user-facing UIs to create, update, internationalize and present consent definitions to end users.</p> +</div> +<div class="paragraph"> +<p>The only thing that is import to Apache Unomi to manage visitor consents is a globally unique key, that is called the +consent type.</p> +</div> +</div> +<div class="sect3"> +<h4 id="_creating_update_a_visitor_consent">Creating / update a visitor consent</h4> +<div class="paragraph"> +<p>A new built-in event type called "modifyConsent" can be sent to Apache Unomi to update a consent for the current +profile.</p> +</div> +<div class="paragraph"> +<p>Here is an example of such an event:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>{ + "events": [ + { + "scope": "example", + "eventType": "modifyConsent", + "source": { + "itemType": "page", + "scope": "example", + "itemId": "anItemId" + }, + "target": { + "itemType": "anyType", + "scope": "example", + "itemId": "anyItemId" + }, + "properties": { + "consent": { + "typeIdentifier": "newsletter", + "scope": "example", + "status": "GRANTED", + "statusDate": "2018-05-22T09:27:09.473Z", + "revokeDate": "2020-05-21T09:27:09.473Z" + } + } + } + ] +}</code></pre> +</div> +</div> +<div class="paragraph"> +<p>You could send it using the following curl request:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>curl -H "Content-Type: application/json" -X POST -d '{"source":{"itemId":"homepage","itemType":"page","scope":"example"},"events":[{"scope":"example","eventType":"modifyConsent","source":{"itemType":"page","scope":"example","itemId":"anItemId"},"target":{"itemType":"anyType","scope":"example","itemId":"anyItemId"},"properties":{"consent":{"typeIdentifier":"newsletter","scope":"example","status":"GRANTED","statusDate":"2018-05-22T09:27:09.473Z","revokeDate":"2020-05-21T09:27:09.473Z"}}}]}' http://localhost:8181/context.json?sessionId=1234</code></pre> +</div> +</div> +</div> +<div class="sect3"> +<h4 id="_how_it_works_internally">How it works (internally)</h4> +<div class="paragraph"> +<p>Upon receiving this event, Apache Unomi will trigger the modifyAnyConsent rule that has the following definition:</p> +</div> +<div class="listingblock"> +<div class="content"> +<pre class="highlight"><code>{ + "metadata" : { + "id": "modifyAnyConsent", + "name": "Modify any consent", + "description" : "Modify any consent and sets the consent in the profile", + "readOnly":true + }, + + "condition" : { + "type": "modifyAnyConsentEventCondition", + "parameterValues": { + } + }, + + "actions" : [ + { + "type": "modifyConsentAction", + "parameterValues": { + } + } + ] + +}</code></pre> +</div> +</div> +<div class="paragraph"> +<p>As we can see this rule is pretty simple it will simply execute the modifyConsentAction that is implemented by the +<a href="https://github.com/apache/incubator-unomi/blob/9f1bab437fd93826dc54d318ed00d3b2e3161437/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/ModifyConsentAction.java">ModifyConsentAction Java class</a></p> +</div> +<div class="paragraph"> +<p>This class will update the current visitor profile to add/update/revoke any consents that are included in the event.</p> +</div> +</div> +</div> +</div> +<div id="footer"> +<div id="footer-text"> +Last updated 2018-09-20 20:40:36 CEST +</div> +</div> +</body> +</html> \ No newline at end of file