You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by xi...@apache.org on 2023/01/18 23:59:05 UTC

svn commit: r1906783 [5/20] - in /tinkerpop/site: docs/3.5.5/ docs/3.5.5/dev/ docs/3.5.5/dev/developer/ docs/3.5.5/dev/future/ docs/3.5.5/dev/io/ docs/3.5.5/dev/provider/ docs/3.5.5/images/ docs/3.5.5/images/icons/ docs/3.5.5/recipes/ docs/3.5.5/refere...

Added: tinkerpop/site/docs/3.5.5/dev/provider/index.html
URL: http://svn.apache.org/viewvc/tinkerpop/site/docs/3.5.5/dev/provider/index.html?rev=1906783&view=auto
==============================================================================
--- tinkerpop/site/docs/3.5.5/dev/provider/index.html (added)
+++ tinkerpop/site/docs/3.5.5/dev/provider/index.html Wed Jan 18 23:58:59 2023
@@ -0,0 +1,3439 @@
+<!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.8">
+<title>Provider Documentation</title>
+<style>
+/*
+ * 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.
+ */
+
+/*! normalize.css v2.1.2 | MIT License | git.io/normalize */
+/* ========================================================================== HTML5 display definitions ========================================================================== */
+/** Correct `block` display not defined in IE 8/9. */
+@import url(http://cdnjs.cloudflare.com/ajax/libs/font-awesome/3.2.1/css/font-awesome.css);
+article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { display: block; }
+
+/** Correct `inline-block` display not defined in IE 8/9. */
+audio, canvas, video { display: inline-block; }
+
+/** Prevent modern browsers from displaying `audio` without controls. Remove excess height in iOS 5 devices. */
+audio:not([controls]) { display: none; height: 0; }
+
+/** Address `[hidden]` styling not present in IE 8/9. Hide the `template` element in IE, Safari, and Firefox < 22. */
+[hidden], template { display: none; }
+
+script { display: none !important; }
+
+/* ========================================================================== Base ========================================================================== */
+/** 1. Set default font family to sans-serif. 2. Prevent iOS text size adjust after orientation change, without disabling user zoom. */
+html { font-family: sans-serif; /* 1 */ -ms-text-size-adjust: 100%; /* 2 */ -webkit-text-size-adjust: 100%; /* 2 */ }
+
+/** Remove default margin. */
+body { margin: 0; }
+
+/* ========================================================================== Links ========================================================================== */
+/** Remove the gray background color from active links in IE 10. */
+a { background: transparent; }
+
+/** Address `outline` inconsistency between Chrome and other browsers. */
+a:focus { outline: thin dotted; }
+
+/** Improve readability when focused and also mouse hovered in all browsers. */
+a:active, a:hover { outline: 0; }
+
+/* ========================================================================== Typography ========================================================================== */
+/** Address variable `h1` font-size and margin within `section` and `article` contexts in Firefox 4+, Safari 5, and Chrome. */
+h1 { font-size: 2em; margin: 0.67em 0; }
+
+/** Address styling not present in IE 8/9, Safari 5, and Chrome. */
+abbr[title] { border-bottom: 1px dotted; }
+
+/** Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. */
+b, strong { font-weight: bold; }
+
+/** Address styling not present in Safari 5 and Chrome. */
+dfn { font-style: italic; }
+
+/** Address differences between Firefox and other browsers. */
+hr { -moz-box-sizing: content-box; box-sizing: content-box; height: 0; }
+
+/** Address styling not present in IE 8/9. */
+mark { background: #ff0; color: #000; }
+
+/** Correct font family set oddly in Safari 5 and Chrome. */
+code, kbd, pre, samp { font-family: monospace, serif; font-size: 1em; }
+
+/** Improve readability of pre-formatted text in all browsers. */
+pre { white-space: pre-wrap; }
+
+/** Set consistent quote types. */
+q { quotes: "\201C" "\201D" "\2018" "\2019"; }
+
+/** Address inconsistent and variable font size in all browsers. */
+small { font-size: 80%; }
+
+/** Prevent `sub` and `sup` affecting `line-height` in all browsers. */
+sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
+
+sup { top: -0.5em; }
+
+sub { bottom: -0.25em; }
+
+/* ========================================================================== Embedded content ========================================================================== */
+/** Remove border when inside `a` element in IE 8/9. */
+img { border: 0; }
+
+/** Correct overflow displayed oddly in IE 9. */
+svg:not(:root) { overflow: hidden; }
+
+/* ========================================================================== Figures ========================================================================== */
+/** Address margin not present in IE 8/9 and Safari 5. */
+figure { margin: 0; }
+
+/* ========================================================================== Forms ========================================================================== */
+/** Define consistent border, margin, and padding. */
+fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; }
+
+/** 1. Correct `color` not being inherited in IE 8/9. 2. Remove padding so people aren't caught out if they zero out fieldsets. */
+legend { border: 0; /* 1 */ padding: 0; /* 2 */ }
+
+/** 1. Correct font family not being inherited in all browsers. 2. Correct font size not being inherited in all browsers. 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. */
+button, input, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 2 */ margin: 0; /* 3 */ }
+
+/** Address Firefox 4+ setting `line-height` on `input` using `!important` in the UA stylesheet. */
+button, input { line-height: normal; }
+
+/** Address inconsistent `text-transform` inheritance for `button` and `select`. All other form control elements do not inherit `text-transform` values. Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. Correct `select` style inheritance in Firefox 4+ and Opera. */
+button, select { text-transform: none; }
+
+/** 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. 2. Correct inability to style clickable `input` types in iOS. 3. Improve usability and consistency of cursor style between image-type `input` and others. */
+button, html input[type="button"], input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ }
+
+/** Re-set default cursor for disabled elements. */
+button[disabled], html input[disabled] { cursor: default; }
+
+/** 1. Address box sizing set to `content-box` in IE 8/9. 2. Remove excess padding in IE 8/9. */
+input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ }
+
+/** 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome (include `-moz` to future-proof). */
+input[type="search"] { -webkit-appearance: textfield; /* 1 */ -moz-box-sizing: content-box; -webkit-box-sizing: content-box; /* 2 */ box-sizing: content-box; }
+
+/** Remove inner padding and search cancel button in Safari 5 and Chrome on OS X. */
+input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; }
+
+/** Remove inner padding and border in Firefox 4+. */
+button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; }
+
+/** 1. Remove default vertical scrollbar in IE 8/9. 2. Improve readability and alignment in all browsers. */
+textarea { overflow: auto; /* 1 */ vertical-align: top; /* 2 */ }
+
+/* ========================================================================== Tables ========================================================================== */
+/** Remove most spacing between table cells. */
+table { border-collapse: collapse; border-spacing: 0; }
+
+meta.foundation-mq-small { font-family: "only screen and (min-width: 768px)"; width: 768px; }
+
+meta.foundation-mq-medium { font-family: "only screen and (min-width:1280px)"; width: 1280px; }
+
+meta.foundation-mq-large { font-family: "only screen and (min-width:1440px)"; width: 1440px; }
+
+*, *:before, *:after { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; }
+
+html, body { font-size: 100%; }
+
+body { background: white; color: #222222; padding: 0; margin: 0; font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; font-weight: normal; font-style: normal; line-height: 1; position: relative; cursor: auto; }
+
+a:hover { cursor: pointer; }
+
+img, object, embed { max-width: 100%; height: auto; }
+
+object, embed { height: 100%; }
+
+img { -ms-interpolation-mode: bicubic; }
+
+#map_canvas img, #map_canvas embed, #map_canvas object, .map_canvas img, .map_canvas embed, .map_canvas object { max-width: none !important; }
+
+.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; }
+
+.antialiased, body { -webkit-font-smoothing: antialiased; }
+
+img { display: inline-block; vertical-align: middle; }
+
+textarea { height: auto; min-height: 50px; }
+
+select { width: 100%; }
+
+p.lead, .paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { font-size: 1.21875em; line-height: 1.6; }
+
+.subheader, #content #toctitle, .admonitionblock td.content > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .mathblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, .sidebarblock > .title, .tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title, .tableblock > caption { line-height: 1.4; color: #6c818f; font-weight: 300; margin-top: 0.2em; margin-bottom: 0.5em; }
+
+/* Typography resets */
+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; }
+
+/* Default Link Styles */
+a { color: #444444; text-decoration: underline; line-height: inherit; }
+a:hover, a:focus { color: #111111; }
+a img { border: none; }
+
+/* Default paragraph styles */
+p { font-family: inherit; font-weight: normal; font-size: 1em; line-height: 1.5; margin-bottom: 1.25em; text-rendering: optimizeLegibility; }
+p aside { font-size: 0.875em; line-height: 1.35; font-style: italic; }
+
+/* Default header styles */
+h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, "Helvetica Neue", sans-serif; font-weight: bold; font-style: normal; color: #465158; text-rendering: optimizeLegibility; margin-top: 1em; margin-bottom: 0.5em; line-height: 1.2125em; }
+h1 small, h2 small, h3 small, #toctitle small, .sidebarblock > .content > .title small, h4 small, h5 small, h6 small { font-size: 60%; color: #909ea7; line-height: 0; }
+
+h1 { font-size: 2.125em; }
+
+h2 { font-size: 1.6875em; }
+
+h3, #toctitle, .sidebarblock > .content > .title { font-size: 1.375em; }
+
+h4 { font-size: 1.125em; }
+
+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; }
+
+/* Helpful Typography Defaults */
+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: "Consolas", "Deja Vu Sans Mono", "Bitstream Vera Sans Mono", monospace; font-weight: normal; color: #444444; }
+
+/* Lists */
+ul, ol, dl { font-size: 1em; line-height: 1.5; margin-bottom: 1.25em; list-style-position: outside; font-family: inherit; }
+
+ul, ol { margin-left: 0; }
+ul.no-bullet, ol.no-bullet { margin-left: 0; }
+
+/* Unordered Lists */
+ul li ul, ul li ol { margin-left: 1.25em; margin-bottom: 0; font-size: 1em; /* Override nested font-size change */ }
+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; }
+ul.no-bullet { list-style: none; }
+
+/* Ordered Lists */
+ol li ul, ol li ol { margin-left: 1.25em; margin-bottom: 0; }
+
+/* Definition Lists */
+dl dt { margin-bottom: 0.3em; font-weight: bold; }
+dl dd { margin-bottom: 0.75em; }
+
+/* Abbreviations */
+abbr, acronym { text-transform: uppercase; font-size: 90%; color: black; border-bottom: 1px dotted #dddddd; cursor: help; }
+
+abbr { text-transform: none; }
+
+/* Blockquotes */
+blockquote { margin: 0 0 1.25em; padding: 0.5625em 1.25em 0 1.1875em; border-left: 1px solid #dddddd; }
+blockquote cite { display: block; font-size: 0.8125em; color: #748590; }
+blockquote cite:before { content: "\2014 \0020"; }
+blockquote cite a, blockquote cite a:visited { color: #748590; }
+
+blockquote, blockquote p { line-height: 1.5; color: #909ea7; }
+
+/* Microformats */
+.vcard { display: inline-block; margin: 0 0 1.25em 0; border: 1px solid #dddddd; padding: 0.625em 0.75em; }
+.vcard li { margin: 0; display: block; }
+.vcard .fn { font-weight: bold; font-size: 0.9375em; }
+
+.vevent .summary { font-weight: bold; }
+.vevent abbr { cursor: auto; text-decoration: none; font-weight: bold; border: none; padding: 0 0.0625em; }
+
+@media only screen and (min-width: 768px) { h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { line-height: 1.4; }
+  h1 { font-size: 2.75em; }
+  h2 { font-size: 2.3125em; }
+  h3, #toctitle, .sidebarblock > .content > .title { font-size: 1.6875em; }
+  h4 { font-size: 1.4375em; } }
+/* Print styles.  Inlined to avoid required HTTP connection: www.phpied.com/delay-loading-your-print-css/ Credit to Paul Irish and HTML5 Boilerplate (html5boilerplate.com)
+*/
+.print-only { display: none !important; }
+
+@media print { * { background: transparent !important; color: #000 !important; /* Black prints faster: h5bp.com/s */ box-shadow: none !important; text-shadow: none !important; }
+  a, a:visited { text-decoration: underline; }
+  a[href]:after { content: " (" attr(href) ")"; }
+  abbr[title]:after { content: " (" attr(title) ")"; }
+  .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; }
+  pre, blockquote { border: 1px solid #999; page-break-inside: avoid; }
+  thead { display: table-header-group; /* h5bp.com/t */ }
+  tr, img { page-break-inside: avoid; }
+  img { max-width: 100% !important; }
+  @page { margin: 0.5cm; }
+  p, h2, h3, #toctitle, .sidebarblock > .content > .title { orphans: 3; widows: 3; }
+  h2, h3, #toctitle, .sidebarblock > .content > .title { page-break-after: avoid; }
+  .hide-on-print { display: none !important; }
+  .print-only { display: block !important; }
+  .hide-for-print { display: none !important; }
+  .show-for-print { display: inherit !important; } }
+/* Tables */
+table { background: white; margin-bottom: 1.25em; border: solid 0 #dddddd; }
+table thead, table tfoot { background: none; font-weight: bold; }
+table thead tr th, table thead tr td, table tfoot tr th, table tfoot tr td { padding: 1px 8px 1px 5px; font-size: 1em; color: #222222; text-align: left; }
+table tr th, table tr td { padding: 1px 8px 1px 5px; font-size: 1em; color: #222222; }
+table tr.even, table tr.alt, table tr:nth-of-type(even) { background: none; }
+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.5; }
+
+.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: 0.95em; padding: 0; white-space: nowrap; background-color: #f2f2f2; border: 0 solid #dddddd; -webkit-border-radius: 6px; border-radius: 6px; text-shadow: none; }
+
+pre, pre > code { line-height: 1.2; color: inherit; font-family: "Consolas", "Deja Vu Sans Mono", "Bitstream Vera Sans Mono", monospace; font-weight: normal; }
+
+.keyseq { color: #333333; }
+
+kbd:not(.keyseq) { display: inline-block; color: black; font-size: 0.75em; line-height: 1.4; background-color: #F7F7F7; border: 1px solid #ccc; -webkit-border-radius: 3px; border-radius: 3px; -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 2px white inset; box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 2px white inset; margin: -0.15em 0.15em 0 0.15em; padding: 0.2em 0.6em 0.2em 0.5em; vertical-align: middle; white-space: nowrap; }
+
+.keyseq kbd:first-child { margin-left: 0; }
+
+.keyseq kbd:last-child { margin-right: 0; }
+
+.menuseq, .menu { color: black; }
+
+b.button:before, b.button:after { position: relative; top: -1px; font-weight: normal; }
+
+b.button:before { content: "["; padding: 0 3px 0 2px; }
+
+b.button:after { content: "]"; padding: 0 2px 0 3px; }
+
+p a > code:hover { color: #373737; }
+
+#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: 0.9375em; padding-right: 0.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; }
+
+#header { margin-bottom: 2.5em; }
+#header > h1 { color: #111111; font-weight: bold; border-bottom: 1px solid #dddddd; margin-bottom: -28px; padding-bottom: 32px; }
+#header span { color: #909ea7; }
+#header #revnumber { text-transform: capitalize; }
+#header br { display: none; }
+#header br + span { padding-left: 3px; }
+#header br + span:before { content: "\2013 \0020"; }
+#header br + span.author { padding-left: 0; }
+#header br + span.author:before { content: ", "; }
+
+#toc { border-bottom: 1px solid #dddddd; padding-bottom: 1.25em; }
+#toc > ul { margin-left: 0.25em; }
+#toc ul.sectlevel0 > li > a { font-style: italic; }
+#toc ul.sectlevel0 ul.sectlevel1 { margin-left: 0; margin-top: 0.5em; margin-bottom: 0.5em; }
+#toc ul { list-style-type: none; }
+
+#toctitle { color: #6c818f; }
+
+@media only screen and (min-width: 768px) { body.toc2 { padding-left: 15em; padding-right: 0; }
+  #toc.toc2 { position: fixed; width: 15em; left: 0; top: 0; border-right: 1px solid #dddddd; border-bottom: 0; z-index: 1000; padding: 1em; height: 100%; overflow: auto; }
+  #toc.toc2 #toctitle { margin-top: 0; font-size: 1.2em; }
+  #toc.toc2 > ul { font-size: .90em; }
+  #toc.toc2 ul ul { margin-left: 0; padding-left: 1em; }
+  #toc.toc2 ul.sectlevel0 ul.sectlevel1 { padding-left: 0; margin-top: 0.5em; margin-bottom: 0.5em; }
+  body.toc2.toc-right { padding-left: 0; padding-right: 15em; }
+  body.toc2.toc-right #toc.toc2 { border-right: 0; border-left: 1px solid #dddddd; left: auto; right: 0; } }
+@media only 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: 0.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: #d9d9d9; margin-bottom: 1.25em; padding: 1.25em; background: #f2f2f2; border-width: 0; -webkit-border-radius: 6px; border-radius: 6px; }
+#content #toc > :first-child { margin-top: 0; }
+#content #toc > :last-child { margin-bottom: 0; }
+#content #toc a { text-decoration: none; }
+
+#content #toctitle { font-weight: bold; font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, "Helvetica Neue", sans-serif; font-size: 1em; padding-left: 0.125em; }
+
+#footer { max-width: 100%; background-color: black; padding: 1.25em; }
+
+#footer-text { color: white; line-height: 1.35; }
+
+.sect1 { padding-bottom: 1.25em; }
+
+.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; width: 1em; margin-left: -1em; display: block; text-decoration: none; visibility: hidden; text-align: center; font-weight: normal; }
+#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; vertical-align: text-top; display: block; margin-top: 0.05em; }
+#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: #465158; 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: #3b444a; }
+
+.imageblock, .literalblock, .listingblock, .mathblock, .verseblock, .videoblock { margin-bottom: 1.25em; }
+
+.admonitionblock td.content > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .mathblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, .sidebarblock > .title, .tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { text-align: left; font-weight: bold; }
+
+.tableblock > caption { text-align: left; font-weight: bold; white-space: nowrap; overflow: visible; max-width: 0; }
+
+table.tableblock #preamble > .sectionbody > .paragraph:first-of-type p { font-size: inherit; }
+
+.admonitionblock > table { 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; text-transform: uppercase; }
+.admonitionblock > table td.content { padding-left: 1.125em; padding-right: 1.25em; border-left: 1px solid #dddddd; color: #909ea7; }
+.admonitionblock > table td.content > :last-child > :last-child { margin-bottom: 0; }
+
+.exampleblock > .content { border-style: solid; border-width: 1px; border-color: #e6e6e6; margin-bottom: 1.25em; padding: 1.25em; background: white; -webkit-border-radius: 6px; border-radius: 6px; }
+.exampleblock > .content > :first-child { margin-top: 0; }
+.exampleblock > .content > :last-child { margin-bottom: 0; }
+.exampleblock > .content h1, .exampleblock > .content h2, .exampleblock > .content h3, .exampleblock > .content #toctitle, .sidebarblock.exampleblock > .content > .title, .exampleblock > .content h4, .exampleblock > .content h5, .exampleblock > .content h6, .exampleblock > .content p { color: #333333; }
+.exampleblock > .content h1, .exampleblock > .content h2, .exampleblock > .content h3, .exampleblock > .content #toctitle, .sidebarblock.exampleblock > .content > .title, .exampleblock > .content h4, .exampleblock > .content h5, .exampleblock > .content h6 { line-height: 1; margin-bottom: 0.625em; }
+.exampleblock > .content h1.subheader, .exampleblock > .content h2.subheader, .exampleblock > .content h3.subheader, .exampleblock > .content .subheader#toctitle, .sidebarblock.exampleblock > .content > .subheader.title, .exampleblock > .content h4.subheader, .exampleblock > .content h5.subheader, .exampleblock > .content h6.subheader { line-height: 1.4; }
+
+.exampleblock.result > .content { -webkit-box-shadow: 0 1px 8px #d9d9d9; box-shadow: 0 1px 8px #d9d9d9; }
+
+.sidebarblock { border-style: solid; border-width: 1px; border-color: #d9d9d9; margin-bottom: 1.25em; padding: 1.25em; background: #f2f2f2; -webkit-border-radius: 6px; border-radius: 6px; }
+.sidebarblock > :first-child { margin-top: 0; }
+.sidebarblock > :last-child { margin-bottom: 0; }
+.sidebarblock h1, .sidebarblock h2, .sidebarblock h3, .sidebarblock #toctitle, .sidebarblock > .content > .title, .sidebarblock h4, .sidebarblock h5, .sidebarblock h6, .sidebarblock p { color: #333333; }
+.sidebarblock h1, .sidebarblock h2, .sidebarblock h3, .sidebarblock #toctitle, .sidebarblock > .content > .title, .sidebarblock h4, .sidebarblock h5, .sidebarblock h6 { line-height: 1; margin-bottom: 0.625em; }
+.sidebarblock h1.subheader, .sidebarblock h2.subheader, .sidebarblock h3.subheader, .sidebarblock .subheader#toctitle, .sidebarblock > .content > .subheader.title, .sidebarblock h4.subheader, .sidebarblock h5.subheader, .sidebarblock h6.subheader { line-height: 1.4; }
+.sidebarblock > .content > .title { color: #6c818f; margin-top: 0; line-height: 1.5; }
+
+.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:not([class]), .listingblock pre:not([class]) { background: #eeeeee; }
+.literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { border-width: 1px; border-style: solid; border-color: #cccccc; -webkit-border-radius: 6px; border-radius: 6px; padding: 0.5em; word-wrap: break-word; }
+.literalblock pre.nowrap, .literalblock pre[class].nowrap, .listingblock pre.nowrap, .listingblock pre[class].nowrap { overflow-x: auto; white-space: pre; word-wrap: normal; }
+.literalblock pre > code, .literalblock pre[class] > code, .listingblock pre > code, .listingblock pre[class] > code { display: block; }
+@media only screen { .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { font-size: 0.76em; } }
+@media only screen and (min-width: 768px) { .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { font-size: 0.855em; } }
+@media only screen and (min-width: 1280px) { .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { font-size: 0.95em; } }
+
+.listingblock pre.highlight { padding: 0; }
+.listingblock pre.highlight > code { padding: 0.5em; }
+
+.listingblock > .content { position: relative; }
+
+.listingblock:hover code[class*=" language-"]:before { text-transform: uppercase; font-size: 0.9em; color: #999; position: absolute; top: 0.375em; right: 0.375em; }
+
+.listingblock:hover code.asciidoc:before { content: "asciidoc"; }
+.listingblock:hover code.clojure:before { content: "clojure"; }
+.listingblock:hover code.css:before { content: "css"; }
+.listingblock:hover code.groovy:before { content: "groovy"; }
+.listingblock:hover code.html:before { content: "html"; }
+.listingblock:hover code.java:before { content: "java"; }
+.listingblock:hover code.javascript:before { content: "javascript"; }
+.listingblock:hover code.python:before { content: "python"; }
+.listingblock:hover code.ruby:before { content: "ruby"; }
+.listingblock:hover code.sass:before { content: "sass"; }
+.listingblock:hover code.scss:before { content: "scss"; }
+.listingblock:hover code.xml:before { content: "xml"; }
+.listingblock:hover code.yaml:before { content: "yaml"; }
+
+.listingblock.terminal pre .command:before { content: attr(data-prompt); padding-right: 0.5em; color: #999; }
+
+.listingblock.terminal pre .command:not([data-prompt]):before { content: '$'; }
+
+table.pyhltable { border: 0; margin-bottom: 0; }
+
+table.pyhltable td { vertical-align: top; padding-top: 0; padding-bottom: 0; }
+
+table.pyhltable td.code { padding-left: .75em; padding-right: 0; }
+
+.highlight.pygments .lineno, table.pyhltable td:not(.code) { color: #999; padding-left: 0; padding-right: .5em; border-right: 1px solid #dddddd; }
+
+.highlight.pygments .lineno { display: inline-block; margin-right: .25em; }
+
+table.pyhltable .linenodiv { background-color: transparent !important; padding-right: 0 !important; }
+
+.quoteblock { margin: 0 0 1.25em; padding: 0.5625em 1.25em 0 1.1875em; border-left: 1px solid #dddddd; }
+.quoteblock blockquote { margin: 0 0 1.25em 0; padding: 0 0 0.5625em 0; border: 0; }
+.quoteblock blockquote > .paragraph:last-child p { margin-bottom: 0; }
+.quoteblock .attribution { margin-top: -.25em; padding-bottom: 0.5625em; font-size: 0.8125em; color: #748590; }
+.quoteblock .attribution br { display: none; }
+.quoteblock .attribution cite { display: block; margin-bottom: 0.625em; }
+
+table thead th, table tfoot th { font-weight: bold; }
+
+table.tableblock.grid-all { border-collapse: separate; border-spacing: 1px; -webkit-border-radius: 6px; border-radius: 6px; border-top: 0 solid #dddddd; border-bottom: 0 solid #dddddd; }
+
+table.tableblock.frame-topbot, table.tableblock.frame-none { border-left: 0; border-right: 0; }
+
+table.tableblock.frame-sides, table.tableblock.frame-none { border-top: 0; border-bottom: 0; }
+
+table.tableblock td .paragraph:last-child p > p:last-child, table.tableblock th > p:last-child, table.tableblock td > p:last-child { margin-bottom: 0; }
+
+th.tableblock.halign-left, td.tableblock.halign-left { text-align: left; }
+
+th.tableblock.halign-right, td.tableblock.halign-right { text-align: right; }
+
+th.tableblock.halign-center, td.tableblock.halign-center { text-align: center; }
+
+th.tableblock.valign-top, td.tableblock.valign-top { vertical-align: top; }
+
+th.tableblock.valign-bottom, td.tableblock.valign-bottom { vertical-align: bottom; }
+
+th.tableblock.valign-middle, td.tableblock.valign-middle { vertical-align: middle; }
+
+tbody tr th { display: table-cell; line-height: 1.5; background: none; }
+
+tbody tr th, tbody tr th p, tfoot tr th, tfoot tr th p { color: #222222; font-weight: bold; }
+
+td > div.verse { white-space: pre; }
+
+ol { margin-left: 0.25em; }
+
+ul li ol { margin-left: 0; }
+
+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: 0.625em; }
+
+ul.unstyled, ol.unnumbered, ul.checklist, ul.none { list-style-type: none; }
+
+ul.unstyled, ol.unnumbered, ul.checklist { margin-left: 0.625em; }
+
+ul.checklist li > p:first-child > i[class^="icon-check"]:first-child, ul.checklist li > p:first-child > input[type="checkbox"]:first-child { margin-right: 0.25em; }
+
+ul.checklist li > p:first-child > input[type="checkbox"]:first-child { position: relative; top: 1px; }
+
+ul.inline { margin: 0 auto 0.625em auto; margin-left: -1.375em; margin-right: 0; padding: 0; list-style: none; overflow: hidden; }
+ul.inline > li { list-style: none; float: left; margin-left: 1.375em; display: block; }
+ul.inline > li > * { display: block; }
+
+.unstyled dl dt { font-weight: normal; 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 { padding-right: .75em; font-weight: bold; }
+
+td.hdlist1, td.hdlist2 { vertical-align: top; }
+
+.literalblock + .colist, .listingblock + .colist { margin-top: -0.5em; }
+
+.colist > table tr > td:first-of-type { padding: 0 .75em; line-height: 1; }
+.colist > table tr > td:last-of-type { padding: 0.25em 0; }
+
+.qanda > ol > li > p > em:only-child { color: #373737; }
+
+.thumb, .th { line-height: 0; display: inline-block; border: solid 4px white; -webkit-box-shadow: 0 0 0 1px #dddddd; box-shadow: 0 0 0 1px #dddddd; }
+
+.imageblock.left, .imageblock[style*="float: left"] { margin: 0.25em 0.625em 1.25em 0; }
+.imageblock.right, .imageblock[style*="float: right"] { margin: 0.25em 0 1.25em 0.625em; }
+.imageblock > .title { margin-bottom: 0; }
+.imageblock.thumb, .imageblock.th { border-width: 6px; }
+.imageblock.thumb > .title, .imageblock.th > .title { padding: 0 0.125em; }
+
+.image.left, .image.right { margin-top: 0.25em; margin-bottom: 0.25em; display: inline-block; line-height: 0; }
+.image.left { margin-right: 0.625em; }
+.image.right { margin-left: 0.625em; }
+
+a.image { text-decoration: none; }
+
+span.footnote, span.footnoteref { vertical-align: super; font-size: 0.875em; }
+span.footnote a, span.footnoteref a { text-decoration: none; }
+
+#footnotes { padding-top: 0.75em; padding-bottom: 0.75em; margin-bottom: 0.625em; }
+#footnotes hr { width: 20%; min-width: 6.25em; margin: -.25em 0 .75em 0; border-width: 1px 0 0 0; }
+#footnotes .footnote { padding: 0 0.375em; line-height: 1.3; font-size: 0.875em; margin-left: 1.2em; text-indent: -1.2em; margin-bottom: .2em; }
+#footnotes .footnote a:first-of-type { font-weight: bold; text-decoration: none; }
+#footnotes .footnote:last-of-type { margin-bottom: 0; }
+
+#content #footnotes { margin-top: -0.625em; margin-bottom: 0; padding: 0.75em 0; }
+
+.gist .file-data > table { border: none; 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: black; }
+
+.black-background { background-color: black; }
+
+.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 > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
+
+.admonitionblock td.icon [class^="icon-"]:before { font-size: 2.5em; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); cursor: default; }
+.admonitionblock td.icon .icon-note:before { content: "\f05a"; color: #444444; color: #333333; }
+.admonitionblock td.icon .icon-tip:before { content: "\f0eb"; text-shadow: 1px 1px 2px rgba(155, 155, 0, 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 { display: inline-block; color: white !important; background-color: black; -webkit-border-radius: 100px; border-radius: 100px; text-align: center; width: 20px; height: 20px; font-size: 12px; font-weight: bold; line-height: 20px; font-family: Arial, sans-serif; font-style: normal; position: relative; top: -2px; letter-spacing: -1px; }
+.conum * { color: white !important; }
+.conum + b { display: none; }
+.conum:after { content: attr(data-value); }
+.conum:not([data-value]):empty { display: none; }
+
+.listingblock code { white-space: pre; overflow: auto; overflow-wrap: normal; /* needed for webkit browsers */ }
+
+#toc ul.sectlevel0 > li > a { font-style: normal; font-weight: bold; }
+
+h4 { color: #6c818f; }
+
+.literalblock > .content > pre, .listingblock > .content > pre { -webkit-border-radius: 6px; border-radius: 6px; margin-left: 2em; margin-right: 2em; }
+
+.admonitionblock { margin-left: 2em; margin-right: 2em; }
+.admonitionblock > table { border: 1px solid #609060; border-top-width: 1.5em; background-color: #e9ffe9; border-collapse: separate; -webkit-border-radius: 0; border-radius: 0; }
+.admonitionblock > table td.icon { padding-top: .5em; padding-bottom: .5em; }
+.admonitionblock > table td.content { padding: .5em 1em; color: black; font-size: .9em; border-left: none; }
+
+.sidebarblock { background-color: #e8ecef; border-color: #ccc; }
+.sidebarblock > .content > .title { color: #444444; }
+
+table.tableblock.grid-all { border-collapse: collapse; -webkit-border-radius: 0; border-radius: 0; }
+table.tableblock.grid-all th.tableblock, table.tableblock.grid-all td.tableblock { border-bottom: 1px solid #aaa; }
+
+#footer { background-color: #465158; padding: 2em; }
+
+#footer-text { color: #eee; font-size: 0.8em; text-align: center; }
+.tabs{position:relative;margin:40px auto;width:1024px;max-width:100%;overflow:hidden;padding-top:10px;margin-bottom:60px}.tabs input{position:absolute;z-index:1000;height:50px;left:0;top:0;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:alpha(opacity=0);cursor:pointer;margin:0}.tabs input:hover+label{background:#e08f24}.tabs label{background:#e9ffe9;color:#1a1a1a;font-size:15px;line-height:50px;height:60px;position:relative;top:0;padding:0 20px;float:left;display:block;letter-spacing:1px;text-transform:uppercase;font-weight:bold;text-align:center;box-shadow:2px 0 2px rgba(0,0,0,0.1),-2px 0 2px rgba(0,0,0,0.1);box-sizing:border-box;-webkit-transition:all 150ms ease 0s;transition:all 150ms ease 0s}.tabs label:hover{cursor:pointer}.tabs label:after{content:'';background:#609060;position:absolute;bottom:-2px;left:0;width:100%;height:2px;display:block}.tabs-2 input{width:50%}.tabs-2 input.tab-selector-1{left:0%}.tabs-2 input.tab-selector-2{left:50%}.tabs-
 2 label{width:50%}.tabs-3 input{width:33.33333%}.tabs-3 input.tab-selector-1{left:0%}.tabs-3 input.tab-selector-2{left:33.33333%}.tabs-3 input.tab-selector-3{left:66.66667%}.tabs-3 label{width:33.33333%}.tabs-4 input{width:25%}.tabs-4 input.tab-selector-1{left:0%}.tabs-4 input.tab-selector-2{left:25%}.tabs-4 input.tab-selector-3{left:50%}.tabs-4 input.tab-selector-4{left:75%}.tabs-4 label{width:25%}.tabs-5 input{width:20%}.tabs-5 input.tab-selector-1{left:0%}.tabs-5 input.tab-selector-2{left:20%}.tabs-5 input.tab-selector-3{left:40%}.tabs-5 input.tab-selector-4{left:60%}.tabs-5 input.tab-selector-5{left:80%}.tabs-5 label{width:20%}.tabs-6 input{width:16.66667%}.tabs-6 input.tab-selector-1{left:0%}.tabs-6 input.tab-selector-2{left:16.66667%}.tabs-6 input.tab-selector-3{left:33.33333%}.tabs-6 input.tab-selector-4{left:50%}.tabs-6 input.tab-selector-5{left:66.66667%}.tabs-6 input.tab-selector-6{left:83.33333%}.tabs-6 label{width:16.66667%}.tabs label:first-of-type{z-index:4}.tab-label-
 2{z-index:4}.tab-label-3{z-index:3}.tab-label-4{z-index:2}.tabs input:checked+label{background:#609060;color:#fefefe;z-index:6}.clear-shadow{clear:both}.tabcontent{height:auto;width:100%;float:left;position:relative;z-index:5;background:#eee;top:-10px;box-sizing:border-box}.tabcontent>div{position:relative;float:left;width:0;height:0;box-sizing:border-box;top:0;left:0;z-index:1;opacity:0;background:#eee}.tabcontent .CodeRay{background-color:#fefefe}.tabs .tab-selector-1:checked ~ .tabcontent .tabcontent-1{z-index:100;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";filter:alpha(opacity=100);opacity:1;width:100%;height:auto;width:100%;height:auto;padding-top:30px}.tabs .tab-selector-2:checked ~ .tabcontent .tabcontent-2{z-index:100;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";filter:alpha(opacity=100);opacity:1;width:100%;height:auto;width:100%;height:auto;padding-top:30px}.tabs .tab-selector-3:checked ~ .tabcontent .tabcontent-3{z-index:100;-ms-
 filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";filter:alpha(opacity=100);opacity:1;width:100%;height:auto;width:100%;height:auto;padding-top:30px}.tabs .tab-selector-4:checked ~ .tabcontent .tabcontent-4{z-index:100;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";filter:alpha(opacity=100);opacity:1;width:100%;height:auto;width:100%;height:auto;padding-top:30px}.tabs .tab-selector-5:checked ~ .tabcontent .tabcontent-5{z-index:100;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";filter:alpha(opacity=100);opacity:1;width:100%;height:auto;width:100%;height:auto;padding-top:30px}.tabs .tab-selector-6:checked ~ .tabcontent .tabcontent-6{z-index:100;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";filter:alpha(opacity=100);opacity:1;width:100%;height:auto;width:100%;height:auto;padding-top:30px}
+
+.invisible {color: rgba(0,0,0,0); font-size: 0;}
+</style>
+<style>
+/* Stylesheet for CodeRay to match GitHub theme | MIT License | http://foundation.zurb.com */
+/*pre.CodeRay {background-color:#f7f7f8;}*/
+.CodeRay .line-numbers{border-right:1px solid #d8d8d8;padding:0 0.5em 0 .25em}
+.CodeRay span.line-numbers{display:inline-block;margin-right:.5em;color:rgba(0,0,0,.3)}
+.CodeRay .line-numbers strong{color:rgba(0,0,0,.4)}
+table.CodeRay{border-collapse:separate;border-spacing:0;margin-bottom:0;border:0;background:none}
+table.CodeRay td{vertical-align: top;line-height:1.45}
+table.CodeRay td.line-numbers{text-align:right}
+table.CodeRay td.line-numbers>pre{padding:0;color:rgba(0,0,0,.3)}
+table.CodeRay td.code{padding:0 0 0 .5em}
+table.CodeRay td.code>pre{padding:0}
+.CodeRay .debug{color:#fff !important;background:#000080 !important}
+.CodeRay .annotation{color:#007}
+.CodeRay .attribute-name{color:#000080}
+.CodeRay .attribute-value{color:#700}
+.CodeRay .binary{color:#509}
+.CodeRay .comment{color:#998;font-style:italic}
+.CodeRay .char{color:#04d}
+.CodeRay .char .content{color:#04d}
+.CodeRay .char .delimiter{color:#039}
+.CodeRay .class{color:#458;font-weight:bold}
+.CodeRay .complex{color:#a08}
+.CodeRay .constant,.CodeRay .predefined-constant{color:#008080}
+.CodeRay .color{color:#099}
+.CodeRay .class-variable{color:#369}
+.CodeRay .decorator{color:#b0b}
+.CodeRay .definition{color:#099}
+.CodeRay .delimiter{color:#000}
+.CodeRay .doc{color:#970}
+.CodeRay .doctype{color:#34b}
+.CodeRay .doc-string{color:#d42}
+.CodeRay .escape{color:#666}
+.CodeRay .entity{color:#800}
+.CodeRay .error{color:#808}
+.CodeRay .exception{color:inherit}
+.CodeRay .filename{color:#099}
+.CodeRay .function{color:#900;font-weight:bold}
+.CodeRay .global-variable{color:#008080}
+.CodeRay .hex{color:#058}
+.CodeRay .integer,.CodeRay .float{color:#099}
+.CodeRay .include{color:#555}
+.CodeRay .inline{color:#000}
+.CodeRay .inline .inline{background:#ccc}
+.CodeRay .inline .inline .inline{background:#bbb}
+.CodeRay .inline .inline-delimiter{color:#d14}
+.CodeRay .inline-delimiter{color:#d14}
+.CodeRay .important{color:#555;font-weight:bold}
+.CodeRay .interpreted{color:#b2b}
+.CodeRay .instance-variable{color:#008080}
+.CodeRay .label{color:#970}
+.CodeRay .local-variable{color:#963}
+.CodeRay .octal{color:#40e}
+.CodeRay .predefined{color:#369}
+.CodeRay .preprocessor{color:#579}
+.CodeRay .pseudo-class{color:#555}
+.CodeRay .directive{font-weight:bold}
+.CodeRay .type{font-weight:bold}
+.CodeRay .predefined-type{color:inherit}
+.CodeRay .reserved,.CodeRay .keyword {color:#000;font-weight:bold}
+.CodeRay .key{color:#808}
+.CodeRay .key .delimiter{color:#606}
+.CodeRay .key .char{color:#80f}
+.CodeRay .value{color:#088}
+.CodeRay .regexp .delimiter{color:#808}
+.CodeRay .regexp .content{color:#808}
+.CodeRay .regexp .modifier{color:#808}
+.CodeRay .regexp .char{color:#d14}
+.CodeRay .regexp .function{color:#404;font-weight:bold}
+.CodeRay .string{color:#d20}
+.CodeRay .string .string .string{background:#ffd0d0}
+.CodeRay .string .content{color:#d14}
+.CodeRay .string .char{color:#d14}
+.CodeRay .string .delimiter{color:#d14}
+.CodeRay .shell{color:#d14}
+.CodeRay .shell .delimiter{color:#d14}
+.CodeRay .symbol{color:#990073}
+.CodeRay .symbol .content{color:#a60}
+.CodeRay .symbol .delimiter{color:#630}
+.CodeRay .tag{color:#008080}
+.CodeRay .tag-special{color:#d70}
+.CodeRay .variable{color:#036}
+.CodeRay .insert{background:#afa}
+.CodeRay .delete{background:#faa}
+.CodeRay .change{color:#aaf;background:#007}
+.CodeRay .head{color:#f8f;background:#505}
+.CodeRay .insert .insert{color:#080}
+.CodeRay .delete .delete{color:#800}
+.CodeRay .change .change{color:#66f}
+.CodeRay .head .head{color:#f4f}
+</style>
+</head>
+<body class="book toc2 toc-left">
+<div id="header">
+<div id="toc" class="toc2">
+<div id="toctitle">Table of Contents</div>
+<ul class="sectlevel0">
+<li><a href="#_provider_documentation">Provider Documentation</a>
+<ul class="sectlevel1">
+<li><a href="#graph-system-provider-requirements">Graph System Provider Requirements</a>
+<ul class="sectlevel2">
+<li><a href="#graph-structure-api">Graph Structure API</a></li>
+<li><a href="#_implementing_gremlin_core">Implementing Gremlin-Core</a>
+<ul class="sectlevel3">
+<li><a href="#oltp-implementations">OLTP Implementations</a></li>
+<li><a href="#olap-implementations">OLAP Implementations</a></li>
+<li><a href="#_hadoop_gremlin_usage">Hadoop-Gremlin Usage</a></li>
+<li><a href="#io-implementations">IO Implementations</a></li>
+<li><a href="#remoteconnection-implementations">RemoteConnection Implementations</a></li>
+<li><a href="#bulk-import-export">Bulk Import Export</a></li>
+</ul>
+</li>
+<li><a href="#validating-with-gremlin-test">Validating with Gremlin-Test</a>
+<ul class="sectlevel3">
+<li><a href="#_checking_resource_leak">Checking resource leak</a></li>
+</ul>
+</li>
+<li><a href="#_accessibility_via_gremlinplugin">Accessibility via GremlinPlugin</a></li>
+<li><a href="#_in_depth_implementations">In-Depth Implementations</a></li>
+</ul>
+</li>
+<li><a href="#_graph_driver_provider_requirements">Graph Driver Provider Requirements</a>
+<ul class="sectlevel2">
+<li><a href="#_opprocessors_arguments">OpProcessors Arguments</a>
+<ul class="sectlevel3">
+<li><a href="#_common">Common</a></li>
+<li><a href="#_standard_opprocessor">Standard OpProcessor</a></li>
+<li><a href="#_session_opprocessor">Session OpProcessor</a></li>
+<li><a href="#_traversal_opprocessor">Traversal OpProcessor</a></li>
+</ul>
+</li>
+<li><a href="#_authentication_and_authorization">Authentication and Authorization</a></li>
+</ul>
+</li>
+<li><a href="#gremlin-plugins">Gremlin Plugins</a></li>
+</ul>
+</li>
+</ul>
+</div>
+</div>
+<div id="content">
+<div id="preamble">
+<div class="sectionbody">
+<div class="imageblock">
+<div class="content">
+<a class="image" href="https://tinkerpop.apache.org"><img src="../../images/apache-tinkerpop-logo.png" alt="apache tinkerpop logo" width="500"></a>
+</div>
+</div>
+<div class="paragraph">
+<p><strong>3.5.5</strong></p>
+</div>
+</div>
+</div>
+<h1 id="_provider_documentation" class="sect0">Provider Documentation</h1>
+<div class="openblock partintro">
+<div class="content">
+<div class="paragraph">
+<p>Apache TinkerPop™ exposes a set of interfaces, protocols, and tests that make it possible for third-parties to build
+libraries and systems that plug-in to the TinkerPop stack.  TinkerPop refers to those third-parties as "providers" and
+this documentation is designed to help providers understand what is involved in developing code on these lower levels
+of the TinkerPop API.</p>
+</div>
+<div class="paragraph">
+<p>This document attempts to address the needs of the different providers that have been identified:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Graph System Provider</p>
+<div class="ulist">
+<ul>
+<li>
+<p>Graph Database Provider</p>
+</li>
+<li>
+<p>Graph Processor Provider</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>Graph Driver Provider
+* Graph Language Provider</p>
+</li>
+<li>
+<p>Graph Plugin Provider</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="graph-system-provider-requirements">Graph System Provider Requirements</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p><span class="image left"><img src="../../images/tinkerpop-enabled.png" alt="tinkerpop enabled" width="140"></span> At the core of TinkerPop 3.x is a Java API. The implementation of this
+core API and its validation via the <code>gremlin-test</code> suite is all that is required of a graph system provider wishing to
+provide a TinkerPop-enabled graph engine. Once a graph system has a valid implementation, then all the applications
+provided by TinkerPop (e.g. Gremlin Console, Gremlin Server, etc.) and 3rd-party developers (e.g. Gremlin-Scala,
+Gremlin-JS, etc.) will integrate properly. Finally, please feel free to use the logo on the left to promote your
+TinkerPop implementation.</p>
+</div>
+<div class="sect2">
+<h3 id="graph-structure-api">Graph Structure API</h3>
+<div class="paragraph">
+<p>The graph structure API of TinkerPop provides the interfaces necessary to create a TinkerPop enabled system and
+exposes the basic components of a property graph to include <code>Graph</code>, <code>Vertex</code>, <code>Edge</code>, <code>VertexProperty</code> and <code>Property</code>.
+The structure API can be used directly as follows:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="java">Graph graph = TinkerGraph.open(); <span class="invisible">//</span><b class="conum">1</b>
+Vertex marko = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">person</span><span class="delimiter">&quot;</span></span>, T.id, <span class="integer">1</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">marko</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">age</span><span class="delimiter">&quot;</span></span>, <span class="integer">29</span>); <span class="invisible">//</span><b class="conum">2</b>
+Vertex vadas = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">person</span><span class="delimiter">&quot;</span></span>, T.id, <span class="integer">2</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">vadas</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">age</span><span class="delimiter">&quot;</span></span>, <span class="integer">27</span>);
+Vertex lop = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">software</span><span class="delimiter">&quot;</span></span>, T.id, <span class="integer">3</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">lop</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">lang</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">java</span><span class="delimiter">&quot;</span></span>);
+Vertex josh = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">person</span><span class="delimiter">&quot;</span></span>, T.id, <span class="integer">4</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">josh</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">age</span><span class="delimiter">&quot;</span></span>, <span class="integer">32</span>);
+Vertex ripple = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">software</span><span class="delimiter">&quot;</span></span>, T.id, <span class="integer">5</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">ripple</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">lang</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">java</span><span class="delimiter">&quot;</span></span>);
+Vertex peter = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">person</span><span class="delimiter">&quot;</span></span>, T.id, <span class="integer">6</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">peter</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">age</span><span class="delimiter">&quot;</span></span>, <span class="integer">35</span>);
+marko.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">knows</span><span class="delimiter">&quot;</span></span>, vadas, T.id, <span class="integer">7</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>, <span class="float">0.5f</span>); <span class="invisible">//</span><b class="conum">3</b>
+marko.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">knows</span><span class="delimiter">&quot;</span></span>, josh, T.id, <span class="integer">8</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>, <span class="float">1.0f</span>);
+marko.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>, lop, T.id, <span class="integer">9</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>, <span class="float">0.4f</span>);
+josh.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>, ripple, T.id, <span class="integer">10</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>, <span class="float">1.0f</span>);
+josh.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>, lop, T.id, <span class="integer">11</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>, <span class="float">0.4f</span>);
+peter.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>, lop, T.id, <span class="integer">12</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">weight</span><span class="delimiter">&quot;</span></span>, <span class="float">0.2f</span>);</code></pre>
+</div>
+</div>
+<div class="colist arabic">
+<ol>
+<li>
+<p>Create a new in-memory <code>TinkerGraph</code> and assign it to the variable <code>graph</code>.</p>
+</li>
+<li>
+<p>Create a vertex along with a set of key/value pairs with <code>T.label</code> being the vertex label and <code>T.id</code> being the vertex id.</p>
+</li>
+<li>
+<p>Create an edge along with a  set of key/value pairs with the edge label being specified as the first argument.</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>In the above code all the vertices are created first and then their respective edges. There are two "accessor tokens":
+<code>T.id</code> and <code>T.label</code>. When any of these, along with a set of other key value pairs is provided to
+<code>Graph.addVertex(Object&#8230;&#8203;)</code> or <code>Vertex.addEdge(String,Vertex,Object&#8230;&#8203;)</code>, the respective element is created along
+with the provided key/value pair properties appended to it.</p>
+</div>
+<div class="paragraph">
+<p>Below is a sequence of basic graph mutation operations represented in Java:</p>
+</div>
+<div class="paragraph">
+<p><span class="image right"><img src="../../images/basic-mutation.png" alt="basic mutation" width="240"></span></p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// create a new graph</span>
+Graph graph = TinkerGraph.open();
+<span class="comment">// add a software vertex with a name property</span>
+Vertex gremlin = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">software</span><span class="delimiter">&quot;</span></span>,
+                             <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">gremlin</span><span class="delimiter">&quot;</span></span>); <span class="invisible">//</span><b class="conum">1</b>
+<span class="comment">// only one vertex should exist</span>
+<span class="keyword">assert</span>(IteratorUtils.count(graph.vertices()) == <span class="integer">1</span>)
+<span class="comment">// no edges should exist as none have been created</span>
+<span class="keyword">assert</span>(IteratorUtils.count(graph.edges()) == <span class="integer">0</span>)
+<span class="comment">// add a new property</span>
+gremlin.property(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>,<span class="integer">2009</span>) <span class="invisible">//</span><b class="conum">2</b>
+<span class="comment">// add a new software vertex to the graph</span>
+Vertex blueprints = graph.addVertex(T.label, <span class="string"><span class="delimiter">&quot;</span><span class="content">software</span><span class="delimiter">&quot;</span></span>,
+                                <span class="string"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">blueprints</span><span class="delimiter">&quot;</span></span>); <span class="invisible">//</span><b class="conum">3</b>
+<span class="comment">// connect gremlin to blueprints via a dependsOn-edge</span>
+gremlin.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">dependsOn</span><span class="delimiter">&quot;</span></span>,blueprints); <span class="invisible">//</span><b class="conum">4</b>
+<span class="comment">// now there are two vertices and one edge</span>
+<span class="keyword">assert</span>(IteratorUtils.count(graph.vertices()) == <span class="integer">2</span>)
+<span class="keyword">assert</span>(IteratorUtils.count(graph.edges()) == <span class="integer">1</span>)
+<span class="comment">// add a property to blueprints</span>
+blueprints.property(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>,<span class="integer">2010</span>) <span class="invisible">//</span><b class="conum">5</b>
+<span class="comment">// remove that property</span>
+blueprints.property(<span class="string"><span class="delimiter">&quot;</span><span class="content">created</span><span class="delimiter">&quot;</span></span>).remove() <span class="invisible">//</span><b class="conum">6</b>
+<span class="comment">// connect gremlin to blueprints via encapsulates</span>
+gremlin.addEdge(<span class="string"><span class="delimiter">&quot;</span><span class="content">encapsulates</span><span class="delimiter">&quot;</span></span>,blueprints) <span class="invisible">//</span><b class="conum">7</b>
+<span class="keyword">assert</span>(IteratorUtils.count(graph.vertices()) == <span class="integer">2</span>)
+<span class="keyword">assert</span>(IteratorUtils.count(graph.edges()) == <span class="integer">2</span>)
+<span class="comment">// removing a vertex removes all its incident edges as well</span>
+blueprints.remove() <span class="invisible">//</span><b class="conum">8</b>
+gremlin.remove() <span class="invisible">//</span><b class="conum">9</b>
+<span class="comment">// the graph is now empty</span>
+<span class="keyword">assert</span>(IteratorUtils.count(graph.vertices()) == <span class="integer">0</span>)
+<span class="keyword">assert</span>(IteratorUtils.count(graph.edges()) == <span class="integer">0</span>)
+<span class="comment">// tada!</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The above code samples are just examples of how the structure API can be used to access a graph. Those APIs are then
+used internally by the process API (i.e. Gremlin) to access any graph that implements those structure API interfaces
+to execute queries. Typically, the structure API methods are not used directly by end-users.</p>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_implementing_gremlin_core">Implementing Gremlin-Core</h3>
+<div class="paragraph">
+<p>The classes that a graph system provider should focus on implementing are itemized below. It is a good idea to study
+the <a href="https://tinkerpop.apache.org/docs/3.5.5/reference/#tinkergraph-gremlin">TinkerGraph</a> (in-memory OLTP and OLAP
+in <code>tinkergraph-gremlin</code>), <a href="https://tinkerpop.apache.org/docs/3.5.5/reference/#neo4j-gremlin">Neo4jGraph</a>
+(OLTP w/ transactions in <code>neo4j-gremlin</code>) and/or
+<a href="https://tinkerpop.apache.org/docs/3.5.5/reference/#hadoop-gremlin">HadoopGraph</a> (OLAP in <code>hadoop-gremlin</code>)
+implementations for ideas and patterns.</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>Online Transactional Processing Graph Systems (<strong>OLTP</strong>)</p>
+<div class="olist loweralpha">
+<ol class="loweralpha" type="a">
+<li>
+<p>Structure API: <code>Graph</code>, <code>Element</code>, <code>Vertex</code>, <code>Edge</code>, <code>Property</code> and <code>Transaction</code> (if transactions are supported).</p>
+</li>
+<li>
+<p>Process API: <code>TraversalStrategy</code> instances for optimizing Gremlin traversals to the provider&#8217;s graph system (i.e. <code>TinkerGraphStepStrategy</code>).</p>
+</li>
+</ol>
+</div>
+</li>
+<li>
+<p>Online Analytics Processing Graph Systems (<strong>OLAP</strong>)</p>
+<div class="olist loweralpha">
+<ol class="loweralpha" type="a">
+<li>
+<p>Everything required of OLTP is required of OLAP (but not vice versa).</p>
+</li>
+<li>
+<p>GraphComputer API: <code>GraphComputer</code>, <code>Messenger</code>, <code>Memory</code>.</p>
+</li>
+</ol>
+</div>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p>Please consider the following implementation notes:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Use <code>StringHelper</code> to ensuring that the <code>toString()</code> representation of classes are consistent with other
+implementations.</p>
+</li>
+<li>
+<p>Ensure that your implementation&#8217;s <code>Features</code> (Graph, Vertex, etc.) are correct so that test cases handle particulars
+accordingly.</p>
+</li>
+<li>
+<p>Use the numerous static method helper classes such as <code>ElementHelper</code>, <code>GraphComputerHelper</code>, <code>VertexProgramHelper</code>, etc.</p>
+</li>
+<li>
+<p>There are a number of default methods on the provided interfaces that are semantically correct. However, if they are
+not efficient for the implementation, override them.</p>
+</li>
+<li>
+<p>Implement the <code>structure/</code> package interfaces first and then, if desired, interfaces in the <code>process/</code> package
+interfaces.</p>
+</li>
+<li>
+<p><code>ComputerGraph</code> is a <code>Wrapper</code> system that ensure proper semantics during a GraphComputer computation.</p>
+</li>
+<li>
+<p>The <a href="https://tinkerpop.apache.org/javadocs/3.5.5/core/">javadoc</a> is often a good resource in understanding
+expectations from both the user&#8217;s perspective as well as the graph provider&#8217;s perspective. Also consider examining
+the javadoc of TinkerGraph which is often well annotated and the interfaces and classes of the test suite itself.</p>
+</li>
+</ul>
+</div>
+<div class="sect3">
+<h4 id="oltp-implementations">OLTP Implementations</h4>
+<div class="paragraph">
+<p><span class="image right"><img src="../../images/pipes-character-1.png" alt="pipes character 1" width="110"></span> The most important interfaces to implement are in the <code>structure/</code>
+package. These include interfaces like <code>Graph</code>, <code>Vertex</code>, <code>Edge</code>, <code>Property</code>, <code>Transaction</code>, etc. The
+<code>StructureStandardSuite</code> will ensure that the semantics of the methods implemented are correct. Moreover, there are
+numerous <code>Exceptions</code> classes with static exceptions that should be thrown by the graph system so that all the
+exceptions and their messages are consistent amongst all TinkerPop implementations.</p>
+</div>
+<div class="paragraph">
+<p>The following bullets provide some tips to consider when implementing the structure interfaces:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><code>Graph</code></p>
+<div class="ulist">
+<ul>
+<li>
+<p>Be sure the <code>Graph</code> implementation is named as <code>XXXGraph</code> (e.g. TinkerGraph, Neo4jGraph, HadoopGraph, etc.).</p>
+</li>
+<li>
+<p>This implementation needs to be <code>GraphFactory</code> compatible which means that the implementation should have a static
+<code>Graph open(Configuration)</code> method where the <code>Configuration</code> is an Apache Commons class of that name. Alternatively, the
+<code>Graph</code> implementation can have the <code>GraphFactoryClass</code> annotation which specifies a class with that static
+<code>Graph open(Configuration)</code> method.</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p><code>VertexProperty</code></p>
+<div class="ulist">
+<ul>
+<li>
+<p>This interface is both a <code>Property</code> and an <code>Element</code> as <code>VertexProperty</code> is a first-class graph element in that it
+can have its own properties (i.e. meta-properties). Even if the implementation does not intend to support
+meta-properties, the <code>VertexProperty</code> needs to be implemented as an <code>Element</code>.</p>
+</li>
+</ul>
+</div>
+</li>
+</ul>
+</div>
+</div>
+<div class="sect3">
+<h4 id="olap-implementations">OLAP Implementations</h4>
+<div class="paragraph">
+<p><span class="image right"><img src="../../images/furnace-character-1.png" alt="furnace character 1" width="110"></span> Implementing the OLAP interfaces may be a bit more complicated.
+Note that before OLAP interfaces are implemented, it is necessary for the OLTP interfaces to be, at minimal,
+implemented as specified in <a href="#oltp-implementations">OLTP Implementations</a>. A summary of each required interface
+implementation is presented below:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p><code>GraphComputer</code>: A fluent builder for specifying an isolation level, a VertexProgram, and any number of MapReduce jobs to be submitted.</p>
+</li>
+<li>
+<p><code>Memory</code>: A global blackboard for ANDing, ORing, INCRing, and SETing values for specified keys.</p>
+</li>
+<li>
+<p><code>Messenger</code>: The system that collects and distributes messages being propagated by vertices executing the VertexProgram application.</p>
+</li>
+<li>
+<p><code>MapReduce.MapEmitter</code>: The system that collects key/value pairs being emitted by the MapReduce applications map-phase.</p>
+</li>
+<li>
+<p><code>MapReduce.ReduceEmitter</code>: The system that collects key/value pairs being emitted by the MapReduce applications combine- and reduce-phases.</p>
+</li>
+</ol>
+</div>
+<div class="admonitionblock note">
+<table>
+<tr>
+<td class="icon">
+<div class="title">Note</div>
+</td>
+<td class="content">
+The VertexProgram and MapReduce interfaces in the <code>process/computer/</code> package are not required by the graph
+system. Instead, these are interfaces to be implemented by application developers writing VertexPrograms and MapReduce jobs.
+</td>
+</tr>
+</table>
+</div>
+<div class="admonitionblock important">
+<table>
+<tr>
+<td class="icon">
+<div class="title">Important</div>
+</td>
+<td class="content">
+TinkerPop provides two OLAP implementations:
+<a href="https://tinkerpop.apache.org/docs/3.5.5/reference/#tinkergraph-gremlin">TinkerGraphComputer</a> (TinkerGraph),
+and
+<a href="https://tinkerpop.apache.org/docs/3.5.5/reference/#sparkgraphcomputer">SparkGraphComputer</a> (Hadoop).
+Given the complexity of the OLAP system, it is good to study and copy many of the patterns used in these reference
+implementations.
+</td>
+</tr>
+</table>
+</div>
+<div class="sect4">
+<h5 id="_implementing_graphcomputer">Implementing GraphComputer</h5>
+<div class="paragraph">
+<p><span class="image right"><img src="../../images/furnace-character-3.png" alt="furnace character 3" width="150"></span> The most complex method in GraphComputer is the <code>submit()</code>-method. The method must do the following:</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>Ensure the GraphComputer has not already been executed.</p>
+</li>
+<li>
+<p>Ensure that at least there is a VertexProgram or 1 MapReduce job.</p>
+</li>
+<li>
+<p>If there is a VertexProgram, validate that it can execute on the GraphComputer given the respectively defined features.</p>
+</li>
+<li>
+<p>Create the Memory to be used for the computation.</p>
+</li>
+<li>
+<p>Execute the VertexProgram.setup() method once and only once.</p>
+</li>
+<li>
+<p>Execute the VertexProgram.execute() method for each vertex.</p>
+</li>
+<li>
+<p>Execute the VertexProgram.terminate() method once and if true, repeat VertexProgram.execute().</p>
+</li>
+<li>
+<p>When VertexProgram.terminate() returns true, move to MapReduce job execution.</p>
+</li>
+<li>
+<p>MapReduce jobs are not required to be executed in any specified order.</p>
+</li>
+<li>
+<p>For each Vertex, execute MapReduce.map(). Then (if defined) execute MapReduce.combine() and MapReduce.reduce().</p>
+</li>
+<li>
+<p>Update Memory with runtime information.</p>
+</li>
+<li>
+<p>Construct a new <code>ComputerResult</code> containing the compute Graph and Memory.</p>
+</li>
+</ol>
+</div>
+</div>
+<div class="sect4">
+<h5 id="_implementing_memory">Implementing Memory</h5>
+<div class="paragraph">
+<p><span class="image left"><img src="../../images/gremlin-brain.png" alt="gremlin brain" width="175"></span> The Memory object is initially defined by <code>VertexProgram.setup()</code>.
+The memory data is available in the first round of the <code>VertexProgram.execute()</code> method. Each Vertex, when executing
+the VertexProgram, can update the Memory in its round. However, the update is not seen by the other vertices until
+the next round. At the end of the first round, all the updates are aggregated and the new memory data is available
+on the second round. This process repeats until the VertexProgram terminates.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="_implementing_messenger">Implementing Messenger</h5>
+<div class="paragraph">
+<p>The Messenger object is similar to the Memory object in that a vertex can read and write to the Messenger. However,
+the data it reads are the messages sent to the vertex in the previous step and the data it writes are the messages
+that will be readable by the receiving vertices in the subsequent round.</p>
+</div>
+</div>
+<div class="sect4">
+<h5 id="_implementing_mapreduce_emitters">Implementing MapReduce Emitters</h5>
+<div class="paragraph">
+<p><span class="image left"><img src="../../images/hadoop-logo-notext.png" alt="hadoop logo notext" width="150"></span> The MapReduce framework in TinkerPop is similar to the model
+popularized by <a href="http://hadoop.apache.org">Hadoop</a>. The primary difference is that all Mappers process the vertices
+of the graph, not an arbitrary key/value pair. However, the vertices' edges can not be accessed&#8201;&#8212;&#8201;only their
+properties. This greatly reduces the amount of data needed to be pushed through the MapReduce engine as any edge
+information required, can be computed in the VertexProgram.execute() method. Moreover, at this stage, vertices can
+not be mutated, only their token and property data read. A Gremlin OLAP system needs to provide implementations for
+to particular classes: <code>MapReduce.MapEmitter</code> and <code>MapReduce.ReduceEmitter</code>. TinkerGraph&#8217;s implementation is provided
+below which demonstrates the simplicity of the algorithm (especially when the data is all within the same JVM).</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">TinkerMapEmitter</span>&lt;K, V&gt; <span class="directive">implements</span> MapReduce.MapEmitter&lt;K, V&gt; {
+
+    <span class="directive">public</span> <span class="predefined-type">Map</span>&lt;K, <span class="predefined-type">Queue</span>&lt;V&gt;&gt; reduceMap;
+    <span class="directive">public</span> <span class="predefined-type">Queue</span>&lt;KeyValue&lt;K, V&gt;&gt; mapQueue;
+    <span class="directive">private</span> <span class="directive">final</span> <span class="type">boolean</span> doReduce;
+
+    <span class="directive">public</span> TinkerMapEmitter(<span class="directive">final</span> <span class="type">boolean</span> doReduce) { <span class="invisible">//</span><b class="conum">1</b>
+        <span class="local-variable">this</span>.doReduce = doReduce;
+        <span class="keyword">if</span> (<span class="local-variable">this</span>.doReduce)
+            <span class="local-variable">this</span>.reduceMap = <span class="keyword">new</span> <span class="predefined-type">ConcurrentHashMap</span>&lt;&gt;();
+        <span class="keyword">else</span>
+            <span class="local-variable">this</span>.mapQueue = <span class="keyword">new</span> <span class="predefined-type">ConcurrentLinkedQueue</span>&lt;&gt;();
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">public</span> <span class="type">void</span> emit(K key, V value) {
+        <span class="keyword">if</span> (<span class="local-variable">this</span>.doReduce)
+            <span class="local-variable">this</span>.reduceMap.computeIfAbsent(key, k -&gt; <span class="keyword">new</span> <span class="predefined-type">ConcurrentLinkedQueue</span>&lt;&gt;()).add(value); <span class="invisible">//</span><b class="conum">2</b>
+        <span class="keyword">else</span>
+            <span class="local-variable">this</span>.mapQueue.add(<span class="keyword">new</span> KeyValue&lt;&gt;(key, value)); <span class="invisible">//</span><b class="conum">3</b>
+    }
+
+    <span class="directive">protected</span> <span class="type">void</span> complete(<span class="directive">final</span> MapReduce&lt;K, V, ?, ?, ?&gt; mapReduce) {
+        <span class="keyword">if</span> (!<span class="local-variable">this</span>.doReduce &amp;&amp; mapReduce.getMapKeySort().isPresent()) { <span class="invisible">//</span><b class="conum">4</b>
+            <span class="directive">final</span> <span class="predefined-type">Comparator</span>&lt;K&gt; comparator = mapReduce.getMapKeySort().get();
+            <span class="directive">final</span> <span class="predefined-type">List</span>&lt;KeyValue&lt;K, V&gt;&gt; list = <span class="keyword">new</span> <span class="predefined-type">ArrayList</span>&lt;&gt;(<span class="local-variable">this</span>.mapQueue);
+            <span class="predefined-type">Collections</span>.sort(list, <span class="predefined-type">Comparator</span>.comparing(KeyValue::getKey, comparator));
+            <span class="local-variable">this</span>.mapQueue.clear();
+            <span class="local-variable">this</span>.mapQueue.addAll(list);
+        } <span class="keyword">else</span> <span class="keyword">if</span> (mapReduce.getMapKeySort().isPresent()) {
+            <span class="directive">final</span> <span class="predefined-type">Comparator</span>&lt;K&gt; comparator = mapReduce.getMapKeySort().get();
+            <span class="directive">final</span> <span class="predefined-type">List</span>&lt;<span class="predefined-type">Map</span>.Entry&lt;K, <span class="predefined-type">Queue</span>&lt;V&gt;&gt;&gt; list = <span class="keyword">new</span> <span class="predefined-type">ArrayList</span>&lt;&gt;();
+            list.addAll(<span class="local-variable">this</span>.reduceMap.entrySet());
+            <span class="predefined-type">Collections</span>.sort(list, <span class="predefined-type">Comparator</span>.comparing(<span class="predefined-type">Map</span>.Entry::getKey, comparator));
+            <span class="local-variable">this</span>.reduceMap = <span class="keyword">new</span> <span class="predefined-type">LinkedHashMap</span>&lt;&gt;();
+            list.forEach(entry -&gt; <span class="local-variable">this</span>.reduceMap.put(entry.getKey(), entry.getValue()));
+        }
+    }
+}</code></pre>
+</div>
+</div>
+<div class="colist arabic">
+<ol>
+<li>
+<p>If the MapReduce job has a reduce, then use one data structure (<code>reduceMap</code>), else use another (<code>mapList</code>). The
+difference being that a reduction requires a grouping by key and therefore, the <code>Map&lt;K,Queue&lt;V&gt;&gt;</code> definition. If no
+reduction/grouping is required, then a simple <code>Queue&lt;KeyValue&lt;K,V&gt;&gt;</code> can be leveraged.</p>
+</li>
+<li>
+<p>If reduce is to follow, then increment the Map with a new value for the key. <code>MapHelper</code> is a TinkerPop class
+with static methods for adding data to a Map.</p>
+</li>
+<li>
+<p>If no reduce is to follow, then simply append a KeyValue to the queue.</p>
+</li>
+<li>
+<p>When the map phase is complete, any map-result sorting required can be executed at this point.</p>
+</li>
+</ol>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">TinkerReduceEmitter</span>&lt;OK, OV&gt; <span class="directive">implements</span> MapReduce.ReduceEmitter&lt;OK, OV&gt; {
+
+    <span class="directive">protected</span> <span class="predefined-type">Queue</span>&lt;KeyValue&lt;OK, OV&gt;&gt; reduceQueue = <span class="keyword">new</span> <span class="predefined-type">ConcurrentLinkedQueue</span>&lt;&gt;();
+
+    <span class="annotation">@Override</span>
+    <span class="directive">public</span> <span class="type">void</span> emit(<span class="directive">final</span> OK key, <span class="directive">final</span> OV value) {
+        <span class="local-variable">this</span>.reduceQueue.add(<span class="keyword">new</span> KeyValue&lt;&gt;(key, value));
+    }
+
+    <span class="directive">protected</span> <span class="type">void</span> complete(<span class="directive">final</span> MapReduce&lt;?, ?, OK, OV, ?&gt; mapReduce) {
+        <span class="keyword">if</span> (mapReduce.getReduceKeySort().isPresent()) {
+            <span class="directive">final</span> <span class="predefined-type">Comparator</span>&lt;OK&gt; comparator = mapReduce.getReduceKeySort().get();
+            <span class="directive">final</span> <span class="predefined-type">List</span>&lt;KeyValue&lt;OK, OV&gt;&gt; list = <span class="keyword">new</span> <span class="predefined-type">ArrayList</span>&lt;&gt;(<span class="local-variable">this</span>.reduceQueue);
+            <span class="predefined-type">Collections</span>.sort(list, <span class="predefined-type">Comparator</span>.comparing(KeyValue::getKey, comparator));
+            <span class="local-variable">this</span>.reduceQueue.clear();
+            <span class="local-variable">this</span>.reduceQueue.addAll(list);
+        }
+    }
+}</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>The method <code>MapReduce.reduce()</code> is defined as:</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">void</span> reduce(<span class="directive">final</span> OK key, <span class="directive">final</span> <span class="predefined-type">Iterator</span>&lt;OV&gt; values, <span class="directive">final</span> ReduceEmitter&lt;OK, OV&gt; emitter) { ... }</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>In other words, for the TinkerGraph implementation, iterate through the entrySet of the <code>reduceMap</code> and call the
+<code>reduce()</code> method on each entry. The <code>reduce()</code> method can emit key/value pairs which are simply aggregated into a
+<code>Queue&lt;KeyValue&lt;OK,OV&gt;&gt;</code> in an analogous fashion to <code>TinkerMapEmitter</code> when no reduce is to follow. These two emitters
+are tied together in <code>TinkerGraphComputer.submit()</code>.</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre class="CodeRay highlight"><code data-lang="java">...
+for (<span class="directive">final</span> MapReduce mapReduce : mapReducers) {
+    <span class="keyword">if</span> (mapReduce.doStage(MapReduce.Stage.MAP)) {
+        <span class="directive">final</span> TinkerMapEmitter&lt;?, ?&gt; mapEmitter = <span class="keyword">new</span> TinkerMapEmitter&lt;&gt;(mapReduce.doStage(MapReduce.Stage.REDUCE));
+        <span class="directive">final</span> SynchronizedIterator&lt;Vertex&gt; vertices = <span class="keyword">new</span> SynchronizedIterator&lt;&gt;(<span class="local-variable">this</span>.graph.vertices());
+        workers.setMapReduce(mapReduce);
+        workers.mapReduceWorkerStart(MapReduce.Stage.MAP);
+        workers.executeMapReduce(workerMapReduce -&gt; {
+            <span class="keyword">while</span> (<span class="predefined-constant">true</span>) {
+                <span class="directive">final</span> Vertex vertex = vertices.next();
+                <span class="keyword">if</span> (<span class="predefined-constant">null</span> == vertex) <span class="keyword">return</span>;
+                workerMapReduce.map(ComputerGraph.mapReduce(vertex), mapEmitter);
+            }
+        });
+        workers.mapReduceWorkerEnd(MapReduce.Stage.MAP);
+
+        <span class="comment">// sort results if a map output sort is defined</span>
+        mapEmitter.complete(mapReduce);
+
+        <span class="comment">// no need to run combiners as this is single machine</span>
+        <span class="keyword">if</span> (mapReduce.doStage(MapReduce.Stage.REDUCE)) {
+            <span class="directive">final</span> TinkerReduceEmitter&lt;?, ?&gt; reduceEmitter = <span class="keyword">new</span> TinkerReduceEmitter&lt;&gt;();
+            <span class="directive">final</span> SynchronizedIterator&lt;<span class="predefined-type">Map</span>.Entry&lt;?, <span class="predefined-type">Queue</span>&lt;?&gt;&gt;&gt; keyValues = <span class="keyword">new</span> SynchronizedIterator((<span class="predefined-type">Iterator</span>) mapEmitter.reduceMap.entrySet().iterator());
+            workers.mapReduceWorkerStart(MapReduce.Stage.REDUCE);
+            workers.executeMapReduce(workerMapReduce -&gt; {
+                <span class="keyword">while</span> (<span class="predefined-constant">true</span>) {
+                    <span class="directive">final</span> <span class="predefined-type">Map</span>.Entry&lt;?, <span class="predefined-type">Queue</span>&lt;?&gt;&gt; entry = keyValues.next();
+                    <span class="keyword">if</span> (<span class="predefined-constant">null</span> == entry) <span class="keyword">return</span>;
+                        workerMapReduce.reduce(entry.getKey(), entry.getValue().iterator(), reduceEmitter);
+                    }
+                });
+            workers.mapReduceWorkerEnd(MapReduce.Stage.REDUCE);
+            reduceEmitter.complete(mapReduce); <span class="comment">// sort results if a reduce output sort is defined</span>
+            mapReduce.addResultToMemory(<span class="local-variable">this</span>.memory, reduceEmitter.reduceQueue.iterator()); <span class="invisible">//</span><b class="conum">1</b>
+        } <span class="keyword">else</span> {
+            mapReduce.addResultToMemory(<span class="local-variable">this</span>.memory, mapEmitter.mapQueue.iterator()); <span class="invisible">//</span><b class="conum">2</b>
+        }
+    }
+}
+...</code></pre>
+</div>
+</div>
+<div class="colist arabic">
+<ol>
+<li>
+<p>Note that the final results of the reducer are provided to the Memory as specified by the application developer&#8217;s
+<code>MapReduce.addResultToMemory()</code> implementation.</p>
+</li>
+<li>
+<p>If there is no reduce stage, the map-stage results are inserted into Memory as specified by the application
+developer&#8217;s <code>MapReduce.addResultToMemory()</code> implementation.</p>
+</li>
+</ol>
+</div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_hadoop_gremlin_usage">Hadoop-Gremlin Usage</h4>
+<div class="paragraph">
+<p>Hadoop-Gremlin is centered around <code>InputFormats</code> and <code>OutputFormats</code>. If a 3rd-party graph system provider wishes to
+leverage Hadoop-Gremlin (and its respective <code>GraphComputer</code> engines), then they need to provide, at minimum, a
+Hadoop2 <code>InputFormat&lt;NullWritable,VertexWritable&gt;</code> for their graph system. If the provider wishes to persist computed
+results back to their graph system (and not just to HDFS via a <code>FileOutputFormat</code>), then a graph system specific
+<code>OutputFormat&lt;NullWritable,VertexWritable&gt;</code> must be developed as well.</p>
+</div>
+<div class="paragraph">
+<p>Conceptually, <code>HadoopGraph</code> is a wrapper around a <code>Configuration</code> object. There is no "data" in the <code>HadoopGraph</code> as
+the <code>InputFormat</code> specifies where and how to get the graph data at OLAP (and OLTP) runtime. Thus, <code>HadoopGraph</code> is a
+small object with little overhead. Graph system providers should realize <code>HadoopGraph</code> as the gateway to the OLAP
+features offered by Hadoop-Gremlin. For example, a graph system specific <code>Graph.compute(Class&lt;? extends GraphComputer&gt;
+graphComputerClass)</code>-method may look as follows:</p>
+</div>

[... 2013 lines stripped ...]