├── .gitignore
└── explora
├── Explora.ipynb
├── LICENSE
├── README.md
├── artifacts
└── init_mlp_model_with_w.h5
├── docs
├── Makefile
├── build
│ ├── doctrees
│ │ ├── environment.pickle
│ │ ├── index.doctree
│ │ ├── main.doctree
│ │ └── modules.doctree
│ └── html
│ │ ├── .buildinfo
│ │ ├── _sources
│ │ ├── index.rst.txt
│ │ ├── main.rst.txt
│ │ └── modules.rst.txt
│ │ ├── _static
│ │ ├── basic.css
│ │ ├── doctools.js
│ │ ├── documentation_options.js
│ │ ├── file.png
│ │ ├── jquery-3.4.1.js
│ │ ├── jquery.js
│ │ ├── language_data.js
│ │ ├── minus.png
│ │ ├── nature.css
│ │ ├── plus.png
│ │ ├── pygments.css
│ │ ├── searchtools.js
│ │ ├── underscore-1.3.1.js
│ │ └── underscore.js
│ │ ├── genindex.html
│ │ ├── index.html
│ │ ├── main.html
│ │ ├── modules.html
│ │ ├── objects.inv
│ │ ├── py-modindex.html
│ │ ├── search.html
│ │ └── searchindex.js
├── make.bat
├── readthedocs.yml
├── requirements.txt
└── source
│ ├── conf.py
│ ├── index.rst
│ ├── main.rst
│ └── modules.rst
├── environment.yml
├── images
└── DA_nowords.png
├── main.py
├── model
├── my_model.h5
├── my_model.mlmodel
└── my_model2.h5
├── requirements.txt
└── utils
├── keras_utils.py
├── validation.py
└── websocket_utils.py
/.gitignore:
--------------------------------------------------------------------------------
1 | new-env/
2 | MNIST-data
3 | logs
4 | core/configuration.ini
5 | *.pyc
6 | *.egg-info/
7 | .DS_Store
8 | .ipynb_checkpoints/
9 | __pycache__/
10 | .pytest_cache/
11 | .cache/
12 | core/__pycache__/
13 | datasets/shakespeare
14 |
15 | core/utils/weights
16 |
--------------------------------------------------------------------------------
/explora/Explora.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "Import any other necessary packages here."
8 | ]
9 | },
10 | {
11 | "cell_type": "code",
12 | "execution_count": null,
13 | "metadata": {},
14 | "outputs": [],
15 | "source": [
16 | "import numpy as np\n",
17 | "import keras\n",
18 | "from keras.models import load_model\n",
19 | "from core import Explora"
20 | ]
21 | },
22 | {
23 | "cell_type": "markdown",
24 | "metadata": {},
25 | "source": [
26 | "Initialize an instance of Explora."
27 | ]
28 | },
29 | {
30 | "cell_type": "code",
31 | "execution_count": null,
32 | "metadata": {},
33 | "outputs": [],
34 | "source": [
35 | "explora = Explora()"
36 | ]
37 | },
38 | {
39 | "cell_type": "markdown",
40 | "metadata": {},
41 | "source": [
42 | "Set up the model."
43 | ]
44 | },
45 | {
46 | "cell_type": "code",
47 | "execution_count": null,
48 | "metadata": {},
49 | "outputs": [],
50 | "source": [
51 | "model = load_model(\"core/artifacts/init_mlp_model_with_w.h5\")"
52 | ]
53 | },
54 | {
55 | "cell_type": "markdown",
56 | "metadata": {},
57 | "source": [
58 | "Set the repo id to the variable here:"
59 | ]
60 | },
61 | {
62 | "cell_type": "code",
63 | "execution_count": null,
64 | "metadata": {},
65 | "outputs": [],
66 | "source": [
67 | "repo_id = # REPO ID HERE"
68 | ]
69 | },
70 | {
71 | "cell_type": "markdown",
72 | "metadata": {},
73 | "source": [
74 | "Set the library type."
75 | ]
76 | },
77 | {
78 | "cell_type": "code",
79 | "execution_count": null,
80 | "metadata": {},
81 | "outputs": [],
82 | "source": [
83 | "library_type = \"Python\" # Or \"Javascript\""
84 | ]
85 | },
86 | {
87 | "cell_type": "markdown",
88 | "metadata": {},
89 | "source": [
90 | "Set the hyperparameters."
91 | ]
92 | },
93 | {
94 | "cell_type": "code",
95 | "execution_count": null,
96 | "metadata": {},
97 | "outputs": [],
98 | "source": [
99 | "hyperparams = {\n",
100 | " \"batch_size\": 100,\n",
101 | " \"epochs\": 5,\n",
102 | " \"shuffle\": True,\n",
103 | "}\n",
104 | "\n",
105 | "if library_type == 'Python':\n",
106 | " hyperparams[\"label_column_name\"] = \"label\"\n",
107 | "else:\n",
108 | " hyperparams[\"label_index\"] = 0"
109 | ]
110 | },
111 | {
112 | "cell_type": "markdown",
113 | "metadata": {},
114 | "source": [
115 | "Set the percentage of nodes that should be averaged before moving on to the next round."
116 | ]
117 | },
118 | {
119 | "cell_type": "code",
120 | "execution_count": null,
121 | "metadata": {},
122 | "outputs": [],
123 | "source": [
124 | "percentage_averaged = 0.75"
125 | ]
126 | },
127 | {
128 | "cell_type": "markdown",
129 | "metadata": {},
130 | "source": [
131 | "Set the maximum amount of rounds to train for."
132 | ]
133 | },
134 | {
135 | "cell_type": "code",
136 | "execution_count": null,
137 | "metadata": {},
138 | "outputs": [],
139 | "source": [
140 | "max_rounds = 5"
141 | ]
142 | },
143 | {
144 | "cell_type": "markdown",
145 | "metadata": {},
146 | "source": [
147 | "Set how often checkpoints should be generated during training (once every `checkpoint_frequency` rounds)"
148 | ]
149 | },
150 | {
151 | "cell_type": "code",
152 | "execution_count": null,
153 | "metadata": {},
154 | "outputs": [],
155 | "source": [
156 | "checkpoint_frequency = 1"
157 | ]
158 | },
159 | {
160 | "cell_type": "markdown",
161 | "metadata": {},
162 | "source": [
163 | "Now run the following line to start a new session and begin training."
164 | ]
165 | },
166 | {
167 | "cell_type": "code",
168 | "execution_count": null,
169 | "metadata": {},
170 | "outputs": [],
171 | "source": [
172 | "await explora.start_new_session(repo_id, model, hyperparams, percentage_averaged, max_rounds, checkpoint_frequency)"
173 | ]
174 | }
175 | ],
176 | "metadata": {
177 | "kernelspec": {
178 | "display_name": "Python 3",
179 | "language": "python",
180 | "name": "python3"
181 | },
182 | "language_info": {
183 | "codemirror_mode": {
184 | "name": "ipython",
185 | "version": 3
186 | },
187 | "file_extension": ".py",
188 | "mimetype": "text/x-python",
189 | "name": "python",
190 | "nbconvert_exporter": "python",
191 | "pygments_lexer": "ipython3",
192 | "version": "3.7.4"
193 | }
194 | },
195 | "nbformat": 4,
196 | "nbformat_minor": 2
197 | }
198 |
--------------------------------------------------------------------------------
/explora/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Neelesh Dodda
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/explora/README.md:
--------------------------------------------------------------------------------
1 | # explora
2 |
--------------------------------------------------------------------------------
/explora/artifacts/init_mlp_model_with_w.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DiscreetAI/explora/36a0c05181530a5103109a1f5d0458ea64c26ca9/explora/artifacts/init_mlp_model_with_w.h5
--------------------------------------------------------------------------------
/explora/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = source
9 | BUILDDIR = build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/explora/docs/build/doctrees/environment.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DiscreetAI/explora/36a0c05181530a5103109a1f5d0458ea64c26ca9/explora/docs/build/doctrees/environment.pickle
--------------------------------------------------------------------------------
/explora/docs/build/doctrees/index.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DiscreetAI/explora/36a0c05181530a5103109a1f5d0458ea64c26ca9/explora/docs/build/doctrees/index.doctree
--------------------------------------------------------------------------------
/explora/docs/build/doctrees/main.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DiscreetAI/explora/36a0c05181530a5103109a1f5d0458ea64c26ca9/explora/docs/build/doctrees/main.doctree
--------------------------------------------------------------------------------
/explora/docs/build/doctrees/modules.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DiscreetAI/explora/36a0c05181530a5103109a1f5d0458ea64c26ca9/explora/docs/build/doctrees/modules.doctree
--------------------------------------------------------------------------------
/explora/docs/build/html/.buildinfo:
--------------------------------------------------------------------------------
1 | # Sphinx build info version 1
2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
3 | config: 88d1dbe8dbe674fa561762124e38f89d
4 | tags: 645f666f9bcd5a90fca523b33c5a78b7
5 |
--------------------------------------------------------------------------------
/explora/docs/build/html/_sources/index.rst.txt:
--------------------------------------------------------------------------------
1 | .. explora documentation master file, created by
2 | sphinx-quickstart on Tue Nov 19 15:38:31 2019.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to explora's documentation!
7 | ===================================
8 |
9 | Explora is a customized Jupyter Notebook used for starting decentralized training sessions.
10 |
11 | .. toctree::
12 | :maxdepth: 2
13 | :caption: Contents:
14 |
15 | modules
16 |
17 |
18 |
19 | Indices and tables
20 | ==================
21 |
22 | * :ref:`genindex`
23 | * :ref:`modindex`
24 | * :ref:`search`
25 |
--------------------------------------------------------------------------------
/explora/docs/build/html/_sources/main.rst.txt:
--------------------------------------------------------------------------------
1 | main module
2 | ===========
3 |
4 | .. automodule:: main
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/explora/docs/build/html/_sources/modules.rst.txt:
--------------------------------------------------------------------------------
1 | explora
2 | =======
3 |
4 | .. toctree::
5 | :maxdepth: 4
6 |
7 | main
8 |
--------------------------------------------------------------------------------
/explora/docs/build/html/_static/basic.css:
--------------------------------------------------------------------------------
1 | /*
2 | * basic.css
3 | * ~~~~~~~~~
4 | *
5 | * Sphinx stylesheet -- basic theme.
6 | *
7 | * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | /* -- main layout ----------------------------------------------------------- */
13 |
14 | div.clearer {
15 | clear: both;
16 | }
17 |
18 | /* -- relbar ---------------------------------------------------------------- */
19 |
20 | div.related {
21 | width: 100%;
22 | font-size: 90%;
23 | }
24 |
25 | div.related h3 {
26 | display: none;
27 | }
28 |
29 | div.related ul {
30 | margin: 0;
31 | padding: 0 0 0 10px;
32 | list-style: none;
33 | }
34 |
35 | div.related li {
36 | display: inline;
37 | }
38 |
39 | div.related li.right {
40 | float: right;
41 | margin-right: 5px;
42 | }
43 |
44 | /* -- sidebar --------------------------------------------------------------- */
45 |
46 | div.sphinxsidebarwrapper {
47 | padding: 10px 5px 0 10px;
48 | }
49 |
50 | div.sphinxsidebar {
51 | float: left;
52 | width: 230px;
53 | margin-left: -100%;
54 | font-size: 90%;
55 | word-wrap: break-word;
56 | overflow-wrap : break-word;
57 | }
58 |
59 | div.sphinxsidebar ul {
60 | list-style: none;
61 | }
62 |
63 | div.sphinxsidebar ul ul,
64 | div.sphinxsidebar ul.want-points {
65 | margin-left: 20px;
66 | list-style: square;
67 | }
68 |
69 | div.sphinxsidebar ul ul {
70 | margin-top: 0;
71 | margin-bottom: 0;
72 | }
73 |
74 | div.sphinxsidebar form {
75 | margin-top: 10px;
76 | }
77 |
78 | div.sphinxsidebar input {
79 | border: 1px solid #98dbcc;
80 | font-family: sans-serif;
81 | font-size: 1em;
82 | }
83 |
84 | div.sphinxsidebar #searchbox form.search {
85 | overflow: hidden;
86 | }
87 |
88 | div.sphinxsidebar #searchbox input[type="text"] {
89 | float: left;
90 | width: 80%;
91 | padding: 0.25em;
92 | box-sizing: border-box;
93 | }
94 |
95 | div.sphinxsidebar #searchbox input[type="submit"] {
96 | float: left;
97 | width: 20%;
98 | border-left: none;
99 | padding: 0.25em;
100 | box-sizing: border-box;
101 | }
102 |
103 |
104 | img {
105 | border: 0;
106 | max-width: 100%;
107 | }
108 |
109 | /* -- search page ----------------------------------------------------------- */
110 |
111 | ul.search {
112 | margin: 10px 0 0 20px;
113 | padding: 0;
114 | }
115 |
116 | ul.search li {
117 | padding: 5px 0 5px 20px;
118 | background-image: url(file.png);
119 | background-repeat: no-repeat;
120 | background-position: 0 7px;
121 | }
122 |
123 | ul.search li a {
124 | font-weight: bold;
125 | }
126 |
127 | ul.search li div.context {
128 | color: #888;
129 | margin: 2px 0 0 30px;
130 | text-align: left;
131 | }
132 |
133 | ul.keywordmatches li.goodmatch a {
134 | font-weight: bold;
135 | }
136 |
137 | /* -- index page ------------------------------------------------------------ */
138 |
139 | table.contentstable {
140 | width: 90%;
141 | margin-left: auto;
142 | margin-right: auto;
143 | }
144 |
145 | table.contentstable p.biglink {
146 | line-height: 150%;
147 | }
148 |
149 | a.biglink {
150 | font-size: 1.3em;
151 | }
152 |
153 | span.linkdescr {
154 | font-style: italic;
155 | padding-top: 5px;
156 | font-size: 90%;
157 | }
158 |
159 | /* -- general index --------------------------------------------------------- */
160 |
161 | table.indextable {
162 | width: 100%;
163 | }
164 |
165 | table.indextable td {
166 | text-align: left;
167 | vertical-align: top;
168 | }
169 |
170 | table.indextable ul {
171 | margin-top: 0;
172 | margin-bottom: 0;
173 | list-style-type: none;
174 | }
175 |
176 | table.indextable > tbody > tr > td > ul {
177 | padding-left: 0em;
178 | }
179 |
180 | table.indextable tr.pcap {
181 | height: 10px;
182 | }
183 |
184 | table.indextable tr.cap {
185 | margin-top: 10px;
186 | background-color: #f2f2f2;
187 | }
188 |
189 | img.toggler {
190 | margin-right: 3px;
191 | margin-top: 3px;
192 | cursor: pointer;
193 | }
194 |
195 | div.modindex-jumpbox {
196 | border-top: 1px solid #ddd;
197 | border-bottom: 1px solid #ddd;
198 | margin: 1em 0 1em 0;
199 | padding: 0.4em;
200 | }
201 |
202 | div.genindex-jumpbox {
203 | border-top: 1px solid #ddd;
204 | border-bottom: 1px solid #ddd;
205 | margin: 1em 0 1em 0;
206 | padding: 0.4em;
207 | }
208 |
209 | /* -- domain module index --------------------------------------------------- */
210 |
211 | table.modindextable td {
212 | padding: 2px;
213 | border-collapse: collapse;
214 | }
215 |
216 | /* -- general body styles --------------------------------------------------- */
217 |
218 | div.body {
219 | min-width: 450px;
220 | max-width: 800px;
221 | }
222 |
223 | div.body p, div.body dd, div.body li, div.body blockquote {
224 | -moz-hyphens: auto;
225 | -ms-hyphens: auto;
226 | -webkit-hyphens: auto;
227 | hyphens: auto;
228 | }
229 |
230 | a.headerlink {
231 | visibility: hidden;
232 | }
233 |
234 | a.brackets:before,
235 | span.brackets > a:before{
236 | content: "[";
237 | }
238 |
239 | a.brackets:after,
240 | span.brackets > a:after {
241 | content: "]";
242 | }
243 |
244 | h1:hover > a.headerlink,
245 | h2:hover > a.headerlink,
246 | h3:hover > a.headerlink,
247 | h4:hover > a.headerlink,
248 | h5:hover > a.headerlink,
249 | h6:hover > a.headerlink,
250 | dt:hover > a.headerlink,
251 | caption:hover > a.headerlink,
252 | p.caption:hover > a.headerlink,
253 | div.code-block-caption:hover > a.headerlink {
254 | visibility: visible;
255 | }
256 |
257 | div.body p.caption {
258 | text-align: inherit;
259 | }
260 |
261 | div.body td {
262 | text-align: left;
263 | }
264 |
265 | .first {
266 | margin-top: 0 !important;
267 | }
268 |
269 | p.rubric {
270 | margin-top: 30px;
271 | font-weight: bold;
272 | }
273 |
274 | img.align-left, .figure.align-left, object.align-left {
275 | clear: left;
276 | float: left;
277 | margin-right: 1em;
278 | }
279 |
280 | img.align-right, .figure.align-right, object.align-right {
281 | clear: right;
282 | float: right;
283 | margin-left: 1em;
284 | }
285 |
286 | img.align-center, .figure.align-center, object.align-center {
287 | display: block;
288 | margin-left: auto;
289 | margin-right: auto;
290 | }
291 |
292 | img.align-default, .figure.align-default {
293 | display: block;
294 | margin-left: auto;
295 | margin-right: auto;
296 | }
297 |
298 | .align-left {
299 | text-align: left;
300 | }
301 |
302 | .align-center {
303 | text-align: center;
304 | }
305 |
306 | .align-default {
307 | text-align: center;
308 | }
309 |
310 | .align-right {
311 | text-align: right;
312 | }
313 |
314 | /* -- sidebars -------------------------------------------------------------- */
315 |
316 | div.sidebar {
317 | margin: 0 0 0.5em 1em;
318 | border: 1px solid #ddb;
319 | padding: 7px 7px 0 7px;
320 | background-color: #ffe;
321 | width: 40%;
322 | float: right;
323 | }
324 |
325 | p.sidebar-title {
326 | font-weight: bold;
327 | }
328 |
329 | /* -- topics ---------------------------------------------------------------- */
330 |
331 | div.topic {
332 | border: 1px solid #ccc;
333 | padding: 7px 7px 0 7px;
334 | margin: 10px 0 10px 0;
335 | }
336 |
337 | p.topic-title {
338 | font-size: 1.1em;
339 | font-weight: bold;
340 | margin-top: 10px;
341 | }
342 |
343 | /* -- admonitions ----------------------------------------------------------- */
344 |
345 | div.admonition {
346 | margin-top: 10px;
347 | margin-bottom: 10px;
348 | padding: 7px;
349 | }
350 |
351 | div.admonition dt {
352 | font-weight: bold;
353 | }
354 |
355 | div.admonition dl {
356 | margin-bottom: 0;
357 | }
358 |
359 | p.admonition-title {
360 | margin: 0px 10px 5px 0px;
361 | font-weight: bold;
362 | }
363 |
364 | div.body p.centered {
365 | text-align: center;
366 | margin-top: 25px;
367 | }
368 |
369 | /* -- tables ---------------------------------------------------------------- */
370 |
371 | table.docutils {
372 | border: 0;
373 | border-collapse: collapse;
374 | }
375 |
376 | table.align-center {
377 | margin-left: auto;
378 | margin-right: auto;
379 | }
380 |
381 | table.align-default {
382 | margin-left: auto;
383 | margin-right: auto;
384 | }
385 |
386 | table caption span.caption-number {
387 | font-style: italic;
388 | }
389 |
390 | table caption span.caption-text {
391 | }
392 |
393 | table.docutils td, table.docutils th {
394 | padding: 1px 8px 1px 5px;
395 | border-top: 0;
396 | border-left: 0;
397 | border-right: 0;
398 | border-bottom: 1px solid #aaa;
399 | }
400 |
401 | table.footnote td, table.footnote th {
402 | border: 0 !important;
403 | }
404 |
405 | th {
406 | text-align: left;
407 | padding-right: 5px;
408 | }
409 |
410 | table.citation {
411 | border-left: solid 1px gray;
412 | margin-left: 1px;
413 | }
414 |
415 | table.citation td {
416 | border-bottom: none;
417 | }
418 |
419 | th > p:first-child,
420 | td > p:first-child {
421 | margin-top: 0px;
422 | }
423 |
424 | th > p:last-child,
425 | td > p:last-child {
426 | margin-bottom: 0px;
427 | }
428 |
429 | /* -- figures --------------------------------------------------------------- */
430 |
431 | div.figure {
432 | margin: 0.5em;
433 | padding: 0.5em;
434 | }
435 |
436 | div.figure p.caption {
437 | padding: 0.3em;
438 | }
439 |
440 | div.figure p.caption span.caption-number {
441 | font-style: italic;
442 | }
443 |
444 | div.figure p.caption span.caption-text {
445 | }
446 |
447 | /* -- field list styles ----------------------------------------------------- */
448 |
449 | table.field-list td, table.field-list th {
450 | border: 0 !important;
451 | }
452 |
453 | .field-list ul {
454 | margin: 0;
455 | padding-left: 1em;
456 | }
457 |
458 | .field-list p {
459 | margin: 0;
460 | }
461 |
462 | .field-name {
463 | -moz-hyphens: manual;
464 | -ms-hyphens: manual;
465 | -webkit-hyphens: manual;
466 | hyphens: manual;
467 | }
468 |
469 | /* -- hlist styles ---------------------------------------------------------- */
470 |
471 | table.hlist td {
472 | vertical-align: top;
473 | }
474 |
475 |
476 | /* -- other body styles ----------------------------------------------------- */
477 |
478 | ol.arabic {
479 | list-style: decimal;
480 | }
481 |
482 | ol.loweralpha {
483 | list-style: lower-alpha;
484 | }
485 |
486 | ol.upperalpha {
487 | list-style: upper-alpha;
488 | }
489 |
490 | ol.lowerroman {
491 | list-style: lower-roman;
492 | }
493 |
494 | ol.upperroman {
495 | list-style: upper-roman;
496 | }
497 |
498 | li > p:first-child {
499 | margin-top: 0px;
500 | }
501 |
502 | li > p:last-child {
503 | margin-bottom: 0px;
504 | }
505 |
506 | dl.footnote > dt,
507 | dl.citation > dt {
508 | float: left;
509 | }
510 |
511 | dl.footnote > dd,
512 | dl.citation > dd {
513 | margin-bottom: 0em;
514 | }
515 |
516 | dl.footnote > dd:after,
517 | dl.citation > dd:after {
518 | content: "";
519 | clear: both;
520 | }
521 |
522 | dl.field-list {
523 | display: grid;
524 | grid-template-columns: fit-content(30%) auto;
525 | }
526 |
527 | dl.field-list > dt {
528 | font-weight: bold;
529 | word-break: break-word;
530 | padding-left: 0.5em;
531 | padding-right: 5px;
532 | }
533 |
534 | dl.field-list > dt:after {
535 | content: ":";
536 | }
537 |
538 | dl.field-list > dd {
539 | padding-left: 0.5em;
540 | margin-top: 0em;
541 | margin-left: 0em;
542 | margin-bottom: 0em;
543 | }
544 |
545 | dl {
546 | margin-bottom: 15px;
547 | }
548 |
549 | dd > p:first-child {
550 | margin-top: 0px;
551 | }
552 |
553 | dd ul, dd table {
554 | margin-bottom: 10px;
555 | }
556 |
557 | dd {
558 | margin-top: 3px;
559 | margin-bottom: 10px;
560 | margin-left: 30px;
561 | }
562 |
563 | dt:target, span.highlighted {
564 | background-color: #fbe54e;
565 | }
566 |
567 | rect.highlighted {
568 | fill: #fbe54e;
569 | }
570 |
571 | dl.glossary dt {
572 | font-weight: bold;
573 | font-size: 1.1em;
574 | }
575 |
576 | .optional {
577 | font-size: 1.3em;
578 | }
579 |
580 | .sig-paren {
581 | font-size: larger;
582 | }
583 |
584 | .versionmodified {
585 | font-style: italic;
586 | }
587 |
588 | .system-message {
589 | background-color: #fda;
590 | padding: 5px;
591 | border: 3px solid red;
592 | }
593 |
594 | .footnote:target {
595 | background-color: #ffa;
596 | }
597 |
598 | .line-block {
599 | display: block;
600 | margin-top: 1em;
601 | margin-bottom: 1em;
602 | }
603 |
604 | .line-block .line-block {
605 | margin-top: 0;
606 | margin-bottom: 0;
607 | margin-left: 1.5em;
608 | }
609 |
610 | .guilabel, .menuselection {
611 | font-family: sans-serif;
612 | }
613 |
614 | .accelerator {
615 | text-decoration: underline;
616 | }
617 |
618 | .classifier {
619 | font-style: oblique;
620 | }
621 |
622 | .classifier:before {
623 | font-style: normal;
624 | margin: 0.5em;
625 | content: ":";
626 | }
627 |
628 | abbr, acronym {
629 | border-bottom: dotted 1px;
630 | cursor: help;
631 | }
632 |
633 | /* -- code displays --------------------------------------------------------- */
634 |
635 | pre {
636 | overflow: auto;
637 | overflow-y: hidden; /* fixes display issues on Chrome browsers */
638 | }
639 |
640 | span.pre {
641 | -moz-hyphens: none;
642 | -ms-hyphens: none;
643 | -webkit-hyphens: none;
644 | hyphens: none;
645 | }
646 |
647 | td.linenos pre {
648 | padding: 5px 0px;
649 | border: 0;
650 | background-color: transparent;
651 | color: #aaa;
652 | }
653 |
654 | table.highlighttable {
655 | margin-left: 0.5em;
656 | }
657 |
658 | table.highlighttable td {
659 | padding: 0 0.5em 0 0.5em;
660 | }
661 |
662 | div.code-block-caption {
663 | padding: 2px 5px;
664 | font-size: small;
665 | }
666 |
667 | div.code-block-caption code {
668 | background-color: transparent;
669 | }
670 |
671 | div.code-block-caption + div > div.highlight > pre {
672 | margin-top: 0;
673 | }
674 |
675 | div.code-block-caption span.caption-number {
676 | padding: 0.1em 0.3em;
677 | font-style: italic;
678 | }
679 |
680 | div.code-block-caption span.caption-text {
681 | }
682 |
683 | div.literal-block-wrapper {
684 | padding: 1em 1em 0;
685 | }
686 |
687 | div.literal-block-wrapper div.highlight {
688 | margin: 0;
689 | }
690 |
691 | code.descname {
692 | background-color: transparent;
693 | font-weight: bold;
694 | font-size: 1.2em;
695 | }
696 |
697 | code.descclassname {
698 | background-color: transparent;
699 | }
700 |
701 | code.xref, a code {
702 | background-color: transparent;
703 | font-weight: bold;
704 | }
705 |
706 | h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
707 | background-color: transparent;
708 | }
709 |
710 | .viewcode-link {
711 | float: right;
712 | }
713 |
714 | .viewcode-back {
715 | float: right;
716 | font-family: sans-serif;
717 | }
718 |
719 | div.viewcode-block:target {
720 | margin: -1px -10px;
721 | padding: 0 10px;
722 | }
723 |
724 | /* -- math display ---------------------------------------------------------- */
725 |
726 | img.math {
727 | vertical-align: middle;
728 | }
729 |
730 | div.body div.math p {
731 | text-align: center;
732 | }
733 |
734 | span.eqno {
735 | float: right;
736 | }
737 |
738 | span.eqno a.headerlink {
739 | position: relative;
740 | left: 0px;
741 | z-index: 1;
742 | }
743 |
744 | div.math:hover a.headerlink {
745 | visibility: visible;
746 | }
747 |
748 | /* -- printout stylesheet --------------------------------------------------- */
749 |
750 | @media print {
751 | div.document,
752 | div.documentwrapper,
753 | div.bodywrapper {
754 | margin: 0 !important;
755 | width: 100%;
756 | }
757 |
758 | div.sphinxsidebar,
759 | div.related,
760 | div.footer,
761 | #top-link {
762 | display: none;
763 | }
764 | }
--------------------------------------------------------------------------------
/explora/docs/build/html/_static/doctools.js:
--------------------------------------------------------------------------------
1 | /*
2 | * doctools.js
3 | * ~~~~~~~~~~~
4 | *
5 | * Sphinx JavaScript utilities for all documentation.
6 | *
7 | * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | /**
13 | * select a different prefix for underscore
14 | */
15 | $u = _.noConflict();
16 |
17 | /**
18 | * make the code below compatible with browsers without
19 | * an installed firebug like debugger
20 | if (!window.console || !console.firebug) {
21 | var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
22 | "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
23 | "profile", "profileEnd"];
24 | window.console = {};
25 | for (var i = 0; i < names.length; ++i)
26 | window.console[names[i]] = function() {};
27 | }
28 | */
29 |
30 | /**
31 | * small helper function to urldecode strings
32 | */
33 | jQuery.urldecode = function(x) {
34 | return decodeURIComponent(x).replace(/\+/g, ' ');
35 | };
36 |
37 | /**
38 | * small helper function to urlencode strings
39 | */
40 | jQuery.urlencode = encodeURIComponent;
41 |
42 | /**
43 | * This function returns the parsed url parameters of the
44 | * current request. Multiple values per key are supported,
45 | * it will always return arrays of strings for the value parts.
46 | */
47 | jQuery.getQueryParameters = function(s) {
48 | if (typeof s === 'undefined')
49 | s = document.location.search;
50 | var parts = s.substr(s.indexOf('?') + 1).split('&');
51 | var result = {};
52 | for (var i = 0; i < parts.length; i++) {
53 | var tmp = parts[i].split('=', 2);
54 | var key = jQuery.urldecode(tmp[0]);
55 | var value = jQuery.urldecode(tmp[1]);
56 | if (key in result)
57 | result[key].push(value);
58 | else
59 | result[key] = [value];
60 | }
61 | return result;
62 | };
63 |
64 | /**
65 | * highlight a given string on a jquery object by wrapping it in
66 | * span elements with the given class name.
67 | */
68 | jQuery.fn.highlightText = function(text, className) {
69 | function highlight(node, addItems) {
70 | if (node.nodeType === 3) {
71 | var val = node.nodeValue;
72 | var pos = val.toLowerCase().indexOf(text);
73 | if (pos >= 0 &&
74 | !jQuery(node.parentNode).hasClass(className) &&
75 | !jQuery(node.parentNode).hasClass("nohighlight")) {
76 | var span;
77 | var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
78 | if (isInSVG) {
79 | span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
80 | } else {
81 | span = document.createElement("span");
82 | span.className = className;
83 | }
84 | span.appendChild(document.createTextNode(val.substr(pos, text.length)));
85 | node.parentNode.insertBefore(span, node.parentNode.insertBefore(
86 | document.createTextNode(val.substr(pos + text.length)),
87 | node.nextSibling));
88 | node.nodeValue = val.substr(0, pos);
89 | if (isInSVG) {
90 | var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
91 | var bbox = node.parentElement.getBBox();
92 | rect.x.baseVal.value = bbox.x;
93 | rect.y.baseVal.value = bbox.y;
94 | rect.width.baseVal.value = bbox.width;
95 | rect.height.baseVal.value = bbox.height;
96 | rect.setAttribute('class', className);
97 | addItems.push({
98 | "parent": node.parentNode,
99 | "target": rect});
100 | }
101 | }
102 | }
103 | else if (!jQuery(node).is("button, select, textarea")) {
104 | jQuery.each(node.childNodes, function() {
105 | highlight(this, addItems);
106 | });
107 | }
108 | }
109 | var addItems = [];
110 | var result = this.each(function() {
111 | highlight(this, addItems);
112 | });
113 | for (var i = 0; i < addItems.length; ++i) {
114 | jQuery(addItems[i].parent).before(addItems[i].target);
115 | }
116 | return result;
117 | };
118 |
119 | /*
120 | * backward compatibility for jQuery.browser
121 | * This will be supported until firefox bug is fixed.
122 | */
123 | if (!jQuery.browser) {
124 | jQuery.uaMatch = function(ua) {
125 | ua = ua.toLowerCase();
126 |
127 | var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
128 | /(webkit)[ \/]([\w.]+)/.exec(ua) ||
129 | /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
130 | /(msie) ([\w.]+)/.exec(ua) ||
131 | ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
132 | [];
133 |
134 | return {
135 | browser: match[ 1 ] || "",
136 | version: match[ 2 ] || "0"
137 | };
138 | };
139 | jQuery.browser = {};
140 | jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
141 | }
142 |
143 | /**
144 | * Small JavaScript module for the documentation.
145 | */
146 | var Documentation = {
147 |
148 | init : function() {
149 | this.fixFirefoxAnchorBug();
150 | this.highlightSearchWords();
151 | this.initIndexTable();
152 | if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) {
153 | this.initOnKeyListeners();
154 | }
155 | },
156 |
157 | /**
158 | * i18n support
159 | */
160 | TRANSLATIONS : {},
161 | PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; },
162 | LOCALE : 'unknown',
163 |
164 | // gettext and ngettext don't access this so that the functions
165 | // can safely bound to a different name (_ = Documentation.gettext)
166 | gettext : function(string) {
167 | var translated = Documentation.TRANSLATIONS[string];
168 | if (typeof translated === 'undefined')
169 | return string;
170 | return (typeof translated === 'string') ? translated : translated[0];
171 | },
172 |
173 | ngettext : function(singular, plural, n) {
174 | var translated = Documentation.TRANSLATIONS[singular];
175 | if (typeof translated === 'undefined')
176 | return (n == 1) ? singular : plural;
177 | return translated[Documentation.PLURALEXPR(n)];
178 | },
179 |
180 | addTranslations : function(catalog) {
181 | for (var key in catalog.messages)
182 | this.TRANSLATIONS[key] = catalog.messages[key];
183 | this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
184 | this.LOCALE = catalog.locale;
185 | },
186 |
187 | /**
188 | * add context elements like header anchor links
189 | */
190 | addContextElements : function() {
191 | $('div[id] > :header:first').each(function() {
192 | $('').
193 | attr('href', '#' + this.id).
194 | attr('title', _('Permalink to this headline')).
195 | appendTo(this);
196 | });
197 | $('dt[id]').each(function() {
198 | $('').
199 | attr('href', '#' + this.id).
200 | attr('title', _('Permalink to this definition')).
201 | appendTo(this);
202 | });
203 | },
204 |
205 | /**
206 | * workaround a firefox stupidity
207 | * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
208 | */
209 | fixFirefoxAnchorBug : function() {
210 | if (document.location.hash && $.browser.mozilla)
211 | window.setTimeout(function() {
212 | document.location.href += '';
213 | }, 10);
214 | },
215 |
216 | /**
217 | * highlight the search words provided in the url in the text
218 | */
219 | highlightSearchWords : function() {
220 | var params = $.getQueryParameters();
221 | var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
222 | if (terms.length) {
223 | var body = $('div.body');
224 | if (!body.length) {
225 | body = $('body');
226 | }
227 | window.setTimeout(function() {
228 | $.each(terms, function() {
229 | body.highlightText(this.toLowerCase(), 'highlighted');
230 | });
231 | }, 10);
232 | $('
' + _('Hide Search Matches') + '
')
234 | .appendTo($('#searchbox'));
235 | }
236 | },
237 |
238 | /**
239 | * init the domain index toggle buttons
240 | */
241 | initIndexTable : function() {
242 | var togglers = $('img.toggler').click(function() {
243 | var src = $(this).attr('src');
244 | var idnum = $(this).attr('id').substr(7);
245 | $('tr.cg-' + idnum).toggle();
246 | if (src.substr(-9) === 'minus.png')
247 | $(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
248 | else
249 | $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
250 | }).css('display', '');
251 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
252 | togglers.click();
253 | }
254 | },
255 |
256 | /**
257 | * helper function to hide the search marks again
258 | */
259 | hideSearchWords : function() {
260 | $('#searchbox .highlight-link').fadeOut(300);
261 | $('span.highlighted').removeClass('highlighted');
262 | },
263 |
264 | /**
265 | * make the url absolute
266 | */
267 | makeURL : function(relativeURL) {
268 | return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
269 | },
270 |
271 | /**
272 | * get the current relative url
273 | */
274 | getCurrentURL : function() {
275 | var path = document.location.pathname;
276 | var parts = path.split(/\//);
277 | $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
278 | if (this === '..')
279 | parts.pop();
280 | });
281 | var url = parts.join('/');
282 | return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
283 | },
284 |
285 | initOnKeyListeners: function() {
286 | $(document).keyup(function(event) {
287 | var activeElementType = document.activeElement.tagName;
288 | // don't navigate when in search box or textarea
289 | if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') {
290 | switch (event.keyCode) {
291 | case 37: // left
292 | var prevHref = $('link[rel="prev"]').prop('href');
293 | if (prevHref) {
294 | window.location.href = prevHref;
295 | return false;
296 | }
297 | case 39: // right
298 | var nextHref = $('link[rel="next"]').prop('href');
299 | if (nextHref) {
300 | window.location.href = nextHref;
301 | return false;
302 | }
303 | }
304 | }
305 | });
306 | }
307 | };
308 |
309 | // quick alias for translations
310 | _ = Documentation.gettext;
311 |
312 | $(document).ready(function() {
313 | Documentation.init();
314 | });
315 |
--------------------------------------------------------------------------------
/explora/docs/build/html/_static/documentation_options.js:
--------------------------------------------------------------------------------
1 | var DOCUMENTATION_OPTIONS = {
2 | URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
3 | VERSION: '1.0.0',
4 | LANGUAGE: 'None',
5 | COLLAPSE_INDEX: false,
6 | FILE_SUFFIX: '.html',
7 | HAS_SOURCE: true,
8 | SOURCELINK_SUFFIX: '.txt',
9 | NAVIGATION_WITH_KEYS: false
10 | };
--------------------------------------------------------------------------------
/explora/docs/build/html/_static/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DiscreetAI/explora/36a0c05181530a5103109a1f5d0458ea64c26ca9/explora/docs/build/html/_static/file.png
--------------------------------------------------------------------------------
/explora/docs/build/html/_static/language_data.js:
--------------------------------------------------------------------------------
1 | /*
2 | * language_data.js
3 | * ~~~~~~~~~~~~~~~~
4 | *
5 | * This script contains the language-specific data used by searchtools.js,
6 | * namely the list of stopwords, stemmer, scorer and splitter.
7 | *
8 | * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
9 | * :license: BSD, see LICENSE for details.
10 | *
11 | */
12 |
13 | var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
14 |
15 |
16 | /* Non-minified version JS is _stemmer.js if file is provided */
17 | /**
18 | * Porter Stemmer
19 | */
20 | var Stemmer = function() {
21 |
22 | var step2list = {
23 | ational: 'ate',
24 | tional: 'tion',
25 | enci: 'ence',
26 | anci: 'ance',
27 | izer: 'ize',
28 | bli: 'ble',
29 | alli: 'al',
30 | entli: 'ent',
31 | eli: 'e',
32 | ousli: 'ous',
33 | ization: 'ize',
34 | ation: 'ate',
35 | ator: 'ate',
36 | alism: 'al',
37 | iveness: 'ive',
38 | fulness: 'ful',
39 | ousness: 'ous',
40 | aliti: 'al',
41 | iviti: 'ive',
42 | biliti: 'ble',
43 | logi: 'log'
44 | };
45 |
46 | var step3list = {
47 | icate: 'ic',
48 | ative: '',
49 | alize: 'al',
50 | iciti: 'ic',
51 | ical: 'ic',
52 | ful: '',
53 | ness: ''
54 | };
55 |
56 | var c = "[^aeiou]"; // consonant
57 | var v = "[aeiouy]"; // vowel
58 | var C = c + "[^aeiouy]*"; // consonant sequence
59 | var V = v + "[aeiou]*"; // vowel sequence
60 |
61 | var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
62 | var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
63 | var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
64 | var s_v = "^(" + C + ")?" + v; // vowel in stem
65 |
66 | this.stemWord = function (w) {
67 | var stem;
68 | var suffix;
69 | var firstch;
70 | var origword = w;
71 |
72 | if (w.length < 3)
73 | return w;
74 |
75 | var re;
76 | var re2;
77 | var re3;
78 | var re4;
79 |
80 | firstch = w.substr(0,1);
81 | if (firstch == "y")
82 | w = firstch.toUpperCase() + w.substr(1);
83 |
84 | // Step 1a
85 | re = /^(.+?)(ss|i)es$/;
86 | re2 = /^(.+?)([^s])s$/;
87 |
88 | if (re.test(w))
89 | w = w.replace(re,"$1$2");
90 | else if (re2.test(w))
91 | w = w.replace(re2,"$1$2");
92 |
93 | // Step 1b
94 | re = /^(.+?)eed$/;
95 | re2 = /^(.+?)(ed|ing)$/;
96 | if (re.test(w)) {
97 | var fp = re.exec(w);
98 | re = new RegExp(mgr0);
99 | if (re.test(fp[1])) {
100 | re = /.$/;
101 | w = w.replace(re,"");
102 | }
103 | }
104 | else if (re2.test(w)) {
105 | var fp = re2.exec(w);
106 | stem = fp[1];
107 | re2 = new RegExp(s_v);
108 | if (re2.test(stem)) {
109 | w = stem;
110 | re2 = /(at|bl|iz)$/;
111 | re3 = new RegExp("([^aeiouylsz])\\1$");
112 | re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
113 | if (re2.test(w))
114 | w = w + "e";
115 | else if (re3.test(w)) {
116 | re = /.$/;
117 | w = w.replace(re,"");
118 | }
119 | else if (re4.test(w))
120 | w = w + "e";
121 | }
122 | }
123 |
124 | // Step 1c
125 | re = /^(.+?)y$/;
126 | if (re.test(w)) {
127 | var fp = re.exec(w);
128 | stem = fp[1];
129 | re = new RegExp(s_v);
130 | if (re.test(stem))
131 | w = stem + "i";
132 | }
133 |
134 | // Step 2
135 | re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
136 | if (re.test(w)) {
137 | var fp = re.exec(w);
138 | stem = fp[1];
139 | suffix = fp[2];
140 | re = new RegExp(mgr0);
141 | if (re.test(stem))
142 | w = stem + step2list[suffix];
143 | }
144 |
145 | // Step 3
146 | re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
147 | if (re.test(w)) {
148 | var fp = re.exec(w);
149 | stem = fp[1];
150 | suffix = fp[2];
151 | re = new RegExp(mgr0);
152 | if (re.test(stem))
153 | w = stem + step3list[suffix];
154 | }
155 |
156 | // Step 4
157 | re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
158 | re2 = /^(.+?)(s|t)(ion)$/;
159 | if (re.test(w)) {
160 | var fp = re.exec(w);
161 | stem = fp[1];
162 | re = new RegExp(mgr1);
163 | if (re.test(stem))
164 | w = stem;
165 | }
166 | else if (re2.test(w)) {
167 | var fp = re2.exec(w);
168 | stem = fp[1] + fp[2];
169 | re2 = new RegExp(mgr1);
170 | if (re2.test(stem))
171 | w = stem;
172 | }
173 |
174 | // Step 5
175 | re = /^(.+?)e$/;
176 | if (re.test(w)) {
177 | var fp = re.exec(w);
178 | stem = fp[1];
179 | re = new RegExp(mgr1);
180 | re2 = new RegExp(meq1);
181 | re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
182 | if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
183 | w = stem;
184 | }
185 | re = /ll$/;
186 | re2 = new RegExp(mgr1);
187 | if (re.test(w) && re2.test(w)) {
188 | re = /.$/;
189 | w = w.replace(re,"");
190 | }
191 |
192 | // and turn initial Y back to y
193 | if (firstch == "y")
194 | w = firstch.toLowerCase() + w.substr(1);
195 | return w;
196 | }
197 | }
198 |
199 |
200 |
201 |
202 |
203 | var splitChars = (function() {
204 | var result = {};
205 | var singles = [96, 180, 187, 191, 215, 247, 749, 885, 903, 907, 909, 930, 1014, 1648,
206 | 1748, 1809, 2416, 2473, 2481, 2526, 2601, 2609, 2612, 2615, 2653, 2702,
207 | 2706, 2729, 2737, 2740, 2857, 2865, 2868, 2910, 2928, 2948, 2961, 2971,
208 | 2973, 3085, 3089, 3113, 3124, 3213, 3217, 3241, 3252, 3295, 3341, 3345,
209 | 3369, 3506, 3516, 3633, 3715, 3721, 3736, 3744, 3748, 3750, 3756, 3761,
210 | 3781, 3912, 4239, 4347, 4681, 4695, 4697, 4745, 4785, 4799, 4801, 4823,
211 | 4881, 5760, 5901, 5997, 6313, 7405, 8024, 8026, 8028, 8030, 8117, 8125,
212 | 8133, 8181, 8468, 8485, 8487, 8489, 8494, 8527, 11311, 11359, 11687, 11695,
213 | 11703, 11711, 11719, 11727, 11735, 12448, 12539, 43010, 43014, 43019, 43587,
214 | 43696, 43713, 64286, 64297, 64311, 64317, 64319, 64322, 64325, 65141];
215 | var i, j, start, end;
216 | for (i = 0; i < singles.length; i++) {
217 | result[singles[i]] = true;
218 | }
219 | var ranges = [[0, 47], [58, 64], [91, 94], [123, 169], [171, 177], [182, 184], [706, 709],
220 | [722, 735], [741, 747], [751, 879], [888, 889], [894, 901], [1154, 1161],
221 | [1318, 1328], [1367, 1368], [1370, 1376], [1416, 1487], [1515, 1519], [1523, 1568],
222 | [1611, 1631], [1642, 1645], [1750, 1764], [1767, 1773], [1789, 1790], [1792, 1807],
223 | [1840, 1868], [1958, 1968], [1970, 1983], [2027, 2035], [2038, 2041], [2043, 2047],
224 | [2070, 2073], [2075, 2083], [2085, 2087], [2089, 2307], [2362, 2364], [2366, 2383],
225 | [2385, 2391], [2402, 2405], [2419, 2424], [2432, 2436], [2445, 2446], [2449, 2450],
226 | [2483, 2485], [2490, 2492], [2494, 2509], [2511, 2523], [2530, 2533], [2546, 2547],
227 | [2554, 2564], [2571, 2574], [2577, 2578], [2618, 2648], [2655, 2661], [2672, 2673],
228 | [2677, 2692], [2746, 2748], [2750, 2767], [2769, 2783], [2786, 2789], [2800, 2820],
229 | [2829, 2830], [2833, 2834], [2874, 2876], [2878, 2907], [2914, 2917], [2930, 2946],
230 | [2955, 2957], [2966, 2968], [2976, 2978], [2981, 2983], [2987, 2989], [3002, 3023],
231 | [3025, 3045], [3059, 3076], [3130, 3132], [3134, 3159], [3162, 3167], [3170, 3173],
232 | [3184, 3191], [3199, 3204], [3258, 3260], [3262, 3293], [3298, 3301], [3312, 3332],
233 | [3386, 3388], [3390, 3423], [3426, 3429], [3446, 3449], [3456, 3460], [3479, 3481],
234 | [3518, 3519], [3527, 3584], [3636, 3647], [3655, 3663], [3674, 3712], [3717, 3718],
235 | [3723, 3724], [3726, 3731], [3752, 3753], [3764, 3772], [3774, 3775], [3783, 3791],
236 | [3802, 3803], [3806, 3839], [3841, 3871], [3892, 3903], [3949, 3975], [3980, 4095],
237 | [4139, 4158], [4170, 4175], [4182, 4185], [4190, 4192], [4194, 4196], [4199, 4205],
238 | [4209, 4212], [4226, 4237], [4250, 4255], [4294, 4303], [4349, 4351], [4686, 4687],
239 | [4702, 4703], [4750, 4751], [4790, 4791], [4806, 4807], [4886, 4887], [4955, 4968],
240 | [4989, 4991], [5008, 5023], [5109, 5120], [5741, 5742], [5787, 5791], [5867, 5869],
241 | [5873, 5887], [5906, 5919], [5938, 5951], [5970, 5983], [6001, 6015], [6068, 6102],
242 | [6104, 6107], [6109, 6111], [6122, 6127], [6138, 6159], [6170, 6175], [6264, 6271],
243 | [6315, 6319], [6390, 6399], [6429, 6469], [6510, 6511], [6517, 6527], [6572, 6592],
244 | [6600, 6607], [6619, 6655], [6679, 6687], [6741, 6783], [6794, 6799], [6810, 6822],
245 | [6824, 6916], [6964, 6980], [6988, 6991], [7002, 7042], [7073, 7085], [7098, 7167],
246 | [7204, 7231], [7242, 7244], [7294, 7400], [7410, 7423], [7616, 7679], [7958, 7959],
247 | [7966, 7967], [8006, 8007], [8014, 8015], [8062, 8063], [8127, 8129], [8141, 8143],
248 | [8148, 8149], [8156, 8159], [8173, 8177], [8189, 8303], [8306, 8307], [8314, 8318],
249 | [8330, 8335], [8341, 8449], [8451, 8454], [8456, 8457], [8470, 8472], [8478, 8483],
250 | [8506, 8507], [8512, 8516], [8522, 8525], [8586, 9311], [9372, 9449], [9472, 10101],
251 | [10132, 11263], [11493, 11498], [11503, 11516], [11518, 11519], [11558, 11567],
252 | [11622, 11630], [11632, 11647], [11671, 11679], [11743, 11822], [11824, 12292],
253 | [12296, 12320], [12330, 12336], [12342, 12343], [12349, 12352], [12439, 12444],
254 | [12544, 12548], [12590, 12592], [12687, 12689], [12694, 12703], [12728, 12783],
255 | [12800, 12831], [12842, 12880], [12896, 12927], [12938, 12976], [12992, 13311],
256 | [19894, 19967], [40908, 40959], [42125, 42191], [42238, 42239], [42509, 42511],
257 | [42540, 42559], [42592, 42593], [42607, 42622], [42648, 42655], [42736, 42774],
258 | [42784, 42785], [42889, 42890], [42893, 43002], [43043, 43055], [43062, 43071],
259 | [43124, 43137], [43188, 43215], [43226, 43249], [43256, 43258], [43260, 43263],
260 | [43302, 43311], [43335, 43359], [43389, 43395], [43443, 43470], [43482, 43519],
261 | [43561, 43583], [43596, 43599], [43610, 43615], [43639, 43641], [43643, 43647],
262 | [43698, 43700], [43703, 43704], [43710, 43711], [43715, 43738], [43742, 43967],
263 | [44003, 44015], [44026, 44031], [55204, 55215], [55239, 55242], [55292, 55295],
264 | [57344, 63743], [64046, 64047], [64110, 64111], [64218, 64255], [64263, 64274],
265 | [64280, 64284], [64434, 64466], [64830, 64847], [64912, 64913], [64968, 65007],
266 | [65020, 65135], [65277, 65295], [65306, 65312], [65339, 65344], [65371, 65381],
267 | [65471, 65473], [65480, 65481], [65488, 65489], [65496, 65497]];
268 | for (i = 0; i < ranges.length; i++) {
269 | start = ranges[i][0];
270 | end = ranges[i][1];
271 | for (j = start; j <= end; j++) {
272 | result[j] = true;
273 | }
274 | }
275 | return result;
276 | })();
277 |
278 | function splitQuery(query) {
279 | var result = [];
280 | var start = -1;
281 | for (var i = 0; i < query.length; i++) {
282 | if (splitChars[query.charCodeAt(i)]) {
283 | if (start !== -1) {
284 | result.push(query.slice(start, i));
285 | start = -1;
286 | }
287 | } else if (start === -1) {
288 | start = i;
289 | }
290 | }
291 | if (start !== -1) {
292 | result.push(query.slice(start));
293 | }
294 | return result;
295 | }
296 |
297 |
298 |
--------------------------------------------------------------------------------
/explora/docs/build/html/_static/minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DiscreetAI/explora/36a0c05181530a5103109a1f5d0458ea64c26ca9/explora/docs/build/html/_static/minus.png
--------------------------------------------------------------------------------
/explora/docs/build/html/_static/nature.css:
--------------------------------------------------------------------------------
1 | /*
2 | * nature.css_t
3 | * ~~~~~~~~~~~~
4 | *
5 | * Sphinx stylesheet -- nature theme.
6 | *
7 | * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | @import url("basic.css");
13 |
14 | /* -- page layout ----------------------------------------------------------- */
15 |
16 | body {
17 | font-family: Arial, sans-serif;
18 | font-size: 100%;
19 | background-color: #fff;
20 | color: #555;
21 | margin: 0;
22 | padding: 0;
23 | }
24 |
25 | div.documentwrapper {
26 | float: left;
27 | width: 100%;
28 | }
29 |
30 | div.bodywrapper {
31 | margin: 0 0 0 230px;
32 | }
33 |
34 | hr {
35 | border: 1px solid #B1B4B6;
36 | }
37 |
38 | div.document {
39 | background-color: #eee;
40 | }
41 |
42 | div.body {
43 | background-color: #ffffff;
44 | color: #3E4349;
45 | padding: 0 30px 30px 30px;
46 | font-size: 0.9em;
47 | }
48 |
49 | div.footer {
50 | color: #555;
51 | width: 100%;
52 | padding: 13px 0;
53 | text-align: center;
54 | font-size: 75%;
55 | }
56 |
57 | div.footer a {
58 | color: #444;
59 | text-decoration: underline;
60 | }
61 |
62 | div.related {
63 | background-color: #6BA81E;
64 | line-height: 32px;
65 | color: #fff;
66 | text-shadow: 0px 1px 0 #444;
67 | font-size: 0.9em;
68 | }
69 |
70 | div.related a {
71 | color: #E2F3CC;
72 | }
73 |
74 | div.sphinxsidebar {
75 | font-size: 0.75em;
76 | line-height: 1.5em;
77 | }
78 |
79 | div.sphinxsidebarwrapper{
80 | padding: 20px 0;
81 | }
82 |
83 | div.sphinxsidebar h3,
84 | div.sphinxsidebar h4 {
85 | font-family: Arial, sans-serif;
86 | color: #222;
87 | font-size: 1.2em;
88 | font-weight: normal;
89 | margin: 0;
90 | padding: 5px 10px;
91 | background-color: #ddd;
92 | text-shadow: 1px 1px 0 white
93 | }
94 |
95 | div.sphinxsidebar h4{
96 | font-size: 1.1em;
97 | }
98 |
99 | div.sphinxsidebar h3 a {
100 | color: #444;
101 | }
102 |
103 |
104 | div.sphinxsidebar p {
105 | color: #888;
106 | padding: 5px 20px;
107 | }
108 |
109 | div.sphinxsidebar p.topless {
110 | }
111 |
112 | div.sphinxsidebar ul {
113 | margin: 10px 20px;
114 | padding: 0;
115 | color: #000;
116 | }
117 |
118 | div.sphinxsidebar a {
119 | color: #444;
120 | }
121 |
122 | div.sphinxsidebar input {
123 | border: 1px solid #ccc;
124 | font-family: sans-serif;
125 | font-size: 1em;
126 | }
127 |
128 | div.sphinxsidebar .searchformwrapper {
129 | margin-left: 20px;
130 | margin-right: 20px;
131 | }
132 |
133 | /* -- body styles ----------------------------------------------------------- */
134 |
135 | a {
136 | color: #005B81;
137 | text-decoration: none;
138 | }
139 |
140 | a:hover {
141 | color: #E32E00;
142 | text-decoration: underline;
143 | }
144 |
145 | div.body h1,
146 | div.body h2,
147 | div.body h3,
148 | div.body h4,
149 | div.body h5,
150 | div.body h6 {
151 | font-family: Arial, sans-serif;
152 | background-color: #BED4EB;
153 | font-weight: normal;
154 | color: #212224;
155 | margin: 30px 0px 10px 0px;
156 | padding: 5px 0 5px 10px;
157 | text-shadow: 0px 1px 0 white
158 | }
159 |
160 | div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; }
161 | div.body h2 { font-size: 150%; background-color: #C8D5E3; }
162 | div.body h3 { font-size: 120%; background-color: #D8DEE3; }
163 | div.body h4 { font-size: 110%; background-color: #D8DEE3; }
164 | div.body h5 { font-size: 100%; background-color: #D8DEE3; }
165 | div.body h6 { font-size: 100%; background-color: #D8DEE3; }
166 |
167 | a.headerlink {
168 | color: #c60f0f;
169 | font-size: 0.8em;
170 | padding: 0 4px 0 4px;
171 | text-decoration: none;
172 | }
173 |
174 | a.headerlink:hover {
175 | background-color: #c60f0f;
176 | color: white;
177 | }
178 |
179 | div.body p, div.body dd, div.body li {
180 | line-height: 1.5em;
181 | }
182 |
183 | div.admonition p.admonition-title + p {
184 | display: inline;
185 | }
186 |
187 | div.highlight{
188 | background-color: white;
189 | }
190 |
191 | div.note {
192 | background-color: #eee;
193 | border: 1px solid #ccc;
194 | }
195 |
196 | div.seealso {
197 | background-color: #ffc;
198 | border: 1px solid #ff6;
199 | }
200 |
201 | div.topic {
202 | background-color: #eee;
203 | }
204 |
205 | div.warning {
206 | background-color: #ffe4e4;
207 | border: 1px solid #f66;
208 | }
209 |
210 | p.admonition-title {
211 | display: inline;
212 | }
213 |
214 | p.admonition-title:after {
215 | content: ":";
216 | }
217 |
218 | pre {
219 | padding: 10px;
220 | background-color: White;
221 | color: #222;
222 | line-height: 1.2em;
223 | border: 1px solid #C6C9CB;
224 | font-size: 1.1em;
225 | margin: 1.5em 0 1.5em 0;
226 | -webkit-box-shadow: 1px 1px 1px #d8d8d8;
227 | -moz-box-shadow: 1px 1px 1px #d8d8d8;
228 | }
229 |
230 | code {
231 | background-color: #ecf0f3;
232 | color: #222;
233 | /* padding: 1px 2px; */
234 | font-size: 1.1em;
235 | font-family: monospace;
236 | }
237 |
238 | .viewcode-back {
239 | font-family: Arial, sans-serif;
240 | }
241 |
242 | div.viewcode-block:target {
243 | background-color: #f4debf;
244 | border-top: 1px solid #ac9;
245 | border-bottom: 1px solid #ac9;
246 | }
247 |
248 | div.code-block-caption {
249 | background-color: #ddd;
250 | color: #222;
251 | border: 1px solid #C6C9CB;
252 | }
--------------------------------------------------------------------------------
/explora/docs/build/html/_static/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DiscreetAI/explora/36a0c05181530a5103109a1f5d0458ea64c26ca9/explora/docs/build/html/_static/plus.png
--------------------------------------------------------------------------------
/explora/docs/build/html/_static/pygments.css:
--------------------------------------------------------------------------------
1 | .highlight .hll { background-color: #ffffcc }
2 | .highlight { background: #f8f8f8; }
3 | .highlight .c { color: #8f5902; font-style: italic } /* Comment */
4 | .highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */
5 | .highlight .g { color: #000000 } /* Generic */
6 | .highlight .k { color: #204a87; font-weight: bold } /* Keyword */
7 | .highlight .l { color: #000000 } /* Literal */
8 | .highlight .n { color: #000000 } /* Name */
9 | .highlight .o { color: #ce5c00; font-weight: bold } /* Operator */
10 | .highlight .x { color: #000000 } /* Other */
11 | .highlight .p { color: #000000; font-weight: bold } /* Punctuation */
12 | .highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */
13 | .highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */
14 | .highlight .cp { color: #8f5902; font-style: italic } /* Comment.Preproc */
15 | .highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */
16 | .highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */
17 | .highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */
18 | .highlight .gd { color: #a40000 } /* Generic.Deleted */
19 | .highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */
20 | .highlight .gr { color: #ef2929 } /* Generic.Error */
21 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
22 | .highlight .gi { color: #00A000 } /* Generic.Inserted */
23 | .highlight .go { color: #000000; font-style: italic } /* Generic.Output */
24 | .highlight .gp { color: #8f5902 } /* Generic.Prompt */
25 | .highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */
26 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
27 | .highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */
28 | .highlight .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */
29 | .highlight .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */
30 | .highlight .kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */
31 | .highlight .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */
32 | .highlight .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */
33 | .highlight .kt { color: #204a87; font-weight: bold } /* Keyword.Type */
34 | .highlight .ld { color: #000000 } /* Literal.Date */
35 | .highlight .m { color: #0000cf; font-weight: bold } /* Literal.Number */
36 | .highlight .s { color: #4e9a06 } /* Literal.String */
37 | .highlight .na { color: #c4a000 } /* Name.Attribute */
38 | .highlight .nb { color: #204a87 } /* Name.Builtin */
39 | .highlight .nc { color: #000000 } /* Name.Class */
40 | .highlight .no { color: #000000 } /* Name.Constant */
41 | .highlight .nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */
42 | .highlight .ni { color: #ce5c00 } /* Name.Entity */
43 | .highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */
44 | .highlight .nf { color: #000000 } /* Name.Function */
45 | .highlight .nl { color: #f57900 } /* Name.Label */
46 | .highlight .nn { color: #000000 } /* Name.Namespace */
47 | .highlight .nx { color: #000000 } /* Name.Other */
48 | .highlight .py { color: #000000 } /* Name.Property */
49 | .highlight .nt { color: #204a87; font-weight: bold } /* Name.Tag */
50 | .highlight .nv { color: #000000 } /* Name.Variable */
51 | .highlight .ow { color: #204a87; font-weight: bold } /* Operator.Word */
52 | .highlight .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */
53 | .highlight .mb { color: #0000cf; font-weight: bold } /* Literal.Number.Bin */
54 | .highlight .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */
55 | .highlight .mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */
56 | .highlight .mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */
57 | .highlight .mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */
58 | .highlight .sa { color: #4e9a06 } /* Literal.String.Affix */
59 | .highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */
60 | .highlight .sc { color: #4e9a06 } /* Literal.String.Char */
61 | .highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */
62 | .highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */
63 | .highlight .s2 { color: #4e9a06 } /* Literal.String.Double */
64 | .highlight .se { color: #4e9a06 } /* Literal.String.Escape */
65 | .highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */
66 | .highlight .si { color: #4e9a06 } /* Literal.String.Interpol */
67 | .highlight .sx { color: #4e9a06 } /* Literal.String.Other */
68 | .highlight .sr { color: #4e9a06 } /* Literal.String.Regex */
69 | .highlight .s1 { color: #4e9a06 } /* Literal.String.Single */
70 | .highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */
71 | .highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */
72 | .highlight .fm { color: #000000 } /* Name.Function.Magic */
73 | .highlight .vc { color: #000000 } /* Name.Variable.Class */
74 | .highlight .vg { color: #000000 } /* Name.Variable.Global */
75 | .highlight .vi { color: #000000 } /* Name.Variable.Instance */
76 | .highlight .vm { color: #000000 } /* Name.Variable.Magic */
77 | .highlight .il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */
--------------------------------------------------------------------------------
/explora/docs/build/html/_static/searchtools.js:
--------------------------------------------------------------------------------
1 | /*
2 | * searchtools.js
3 | * ~~~~~~~~~~~~~~~~
4 | *
5 | * Sphinx JavaScript utilities for the full-text search.
6 | *
7 | * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | if (!Scorer) {
13 | /**
14 | * Simple result scoring code.
15 | */
16 | var Scorer = {
17 | // Implement the following function to further tweak the score for each result
18 | // The function takes a result array [filename, title, anchor, descr, score]
19 | // and returns the new score.
20 | /*
21 | score: function(result) {
22 | return result[4];
23 | },
24 | */
25 |
26 | // query matches the full name of an object
27 | objNameMatch: 11,
28 | // or matches in the last dotted part of the object name
29 | objPartialMatch: 6,
30 | // Additive scores depending on the priority of the object
31 | objPrio: {0: 15, // used to be importantResults
32 | 1: 5, // used to be objectResults
33 | 2: -5}, // used to be unimportantResults
34 | // Used when the priority is not in the mapping.
35 | objPrioDefault: 0,
36 |
37 | // query found in title
38 | title: 15,
39 | partialTitle: 7,
40 | // query found in terms
41 | term: 5,
42 | partialTerm: 2
43 | };
44 | }
45 |
46 | if (!splitQuery) {
47 | function splitQuery(query) {
48 | return query.split(/\s+/);
49 | }
50 | }
51 |
52 | /**
53 | * Search Module
54 | */
55 | var Search = {
56 |
57 | _index : null,
58 | _queued_query : null,
59 | _pulse_status : -1,
60 |
61 | htmlToText : function(htmlString) {
62 | var htmlElement = document.createElement('span');
63 | htmlElement.innerHTML = htmlString;
64 | $(htmlElement).find('.headerlink').remove();
65 | docContent = $(htmlElement).find('[role=main]')[0];
66 | return docContent.textContent || docContent.innerText;
67 | },
68 |
69 | init : function() {
70 | var params = $.getQueryParameters();
71 | if (params.q) {
72 | var query = params.q[0];
73 | $('input[name="q"]')[0].value = query;
74 | this.performSearch(query);
75 | }
76 | },
77 |
78 | loadIndex : function(url) {
79 | $.ajax({type: "GET", url: url, data: null,
80 | dataType: "script", cache: true,
81 | complete: function(jqxhr, textstatus) {
82 | if (textstatus != "success") {
83 | document.getElementById("searchindexloader").src = url;
84 | }
85 | }});
86 | },
87 |
88 | setIndex : function(index) {
89 | var q;
90 | this._index = index;
91 | if ((q = this._queued_query) !== null) {
92 | this._queued_query = null;
93 | Search.query(q);
94 | }
95 | },
96 |
97 | hasIndex : function() {
98 | return this._index !== null;
99 | },
100 |
101 | deferQuery : function(query) {
102 | this._queued_query = query;
103 | },
104 |
105 | stopPulse : function() {
106 | this._pulse_status = 0;
107 | },
108 |
109 | startPulse : function() {
110 | if (this._pulse_status >= 0)
111 | return;
112 | function pulse() {
113 | var i;
114 | Search._pulse_status = (Search._pulse_status + 1) % 4;
115 | var dotString = '';
116 | for (i = 0; i < Search._pulse_status; i++)
117 | dotString += '.';
118 | Search.dots.text(dotString);
119 | if (Search._pulse_status > -1)
120 | window.setTimeout(pulse, 500);
121 | }
122 | pulse();
123 | },
124 |
125 | /**
126 | * perform a search for something (or wait until index is loaded)
127 | */
128 | performSearch : function(query) {
129 | // create the required interface elements
130 | this.out = $('#search-results');
131 | this.title = $('' + _('Searching') + ' ').appendTo(this.out);
132 | this.dots = $(' ').appendTo(this.title);
133 | this.status = $('
').appendTo(this.out);
134 | this.output = $('').appendTo(this.out);
135 |
136 | $('#search-progress').text(_('Preparing search...'));
137 | this.startPulse();
138 |
139 | // index already loaded, the browser was quick!
140 | if (this.hasIndex())
141 | this.query(query);
142 | else
143 | this.deferQuery(query);
144 | },
145 |
146 | /**
147 | * execute search (requires search index to be loaded)
148 | */
149 | query : function(query) {
150 | var i;
151 |
152 | // stem the searchterms and add them to the correct list
153 | var stemmer = new Stemmer();
154 | var searchterms = [];
155 | var excluded = [];
156 | var hlterms = [];
157 | var tmp = splitQuery(query);
158 | var objectterms = [];
159 | for (i = 0; i < tmp.length; i++) {
160 | if (tmp[i] !== "") {
161 | objectterms.push(tmp[i].toLowerCase());
162 | }
163 |
164 | if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) ||
165 | tmp[i] === "") {
166 | // skip this "word"
167 | continue;
168 | }
169 | // stem the word
170 | var word = stemmer.stemWord(tmp[i].toLowerCase());
171 | // prevent stemmer from cutting word smaller than two chars
172 | if(word.length < 3 && tmp[i].length >= 3) {
173 | word = tmp[i];
174 | }
175 | var toAppend;
176 | // select the correct list
177 | if (word[0] == '-') {
178 | toAppend = excluded;
179 | word = word.substr(1);
180 | }
181 | else {
182 | toAppend = searchterms;
183 | hlterms.push(tmp[i].toLowerCase());
184 | }
185 | // only add if not already in the list
186 | if (!$u.contains(toAppend, word))
187 | toAppend.push(word);
188 | }
189 | var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
190 |
191 | // console.debug('SEARCH: searching for:');
192 | // console.info('required: ', searchterms);
193 | // console.info('excluded: ', excluded);
194 |
195 | // prepare search
196 | var terms = this._index.terms;
197 | var titleterms = this._index.titleterms;
198 |
199 | // array of [filename, title, anchor, descr, score]
200 | var results = [];
201 | $('#search-progress').empty();
202 |
203 | // lookup as object
204 | for (i = 0; i < objectterms.length; i++) {
205 | var others = [].concat(objectterms.slice(0, i),
206 | objectterms.slice(i+1, objectterms.length));
207 | results = results.concat(this.performObjectSearch(objectterms[i], others));
208 | }
209 |
210 | // lookup as search terms in fulltext
211 | results = results.concat(this.performTermsSearch(searchterms, excluded, terms, titleterms));
212 |
213 | // let the scorer override scores with a custom scoring function
214 | if (Scorer.score) {
215 | for (i = 0; i < results.length; i++)
216 | results[i][4] = Scorer.score(results[i]);
217 | }
218 |
219 | // now sort the results by score (in opposite order of appearance, since the
220 | // display function below uses pop() to retrieve items) and then
221 | // alphabetically
222 | results.sort(function(a, b) {
223 | var left = a[4];
224 | var right = b[4];
225 | if (left > right) {
226 | return 1;
227 | } else if (left < right) {
228 | return -1;
229 | } else {
230 | // same score: sort alphabetically
231 | left = a[1].toLowerCase();
232 | right = b[1].toLowerCase();
233 | return (left > right) ? -1 : ((left < right) ? 1 : 0);
234 | }
235 | });
236 |
237 | // for debugging
238 | //Search.lastresults = results.slice(); // a copy
239 | //console.info('search results:', Search.lastresults);
240 |
241 | // print the results
242 | var resultCount = results.length;
243 | function displayNextItem() {
244 | // results left, load the summary and display it
245 | if (results.length) {
246 | var item = results.pop();
247 | var listItem = $(' ');
248 | if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') {
249 | // dirhtml builder
250 | var dirname = item[0] + '/';
251 | if (dirname.match(/\/index\/$/)) {
252 | dirname = dirname.substring(0, dirname.length-6);
253 | } else if (dirname == 'index/') {
254 | dirname = '';
255 | }
256 | listItem.append($(' ').attr('href',
257 | DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
258 | highlightstring + item[2]).html(item[1]));
259 | } else {
260 | // normal html builders
261 | listItem.append($(' ').attr('href',
262 | item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
263 | highlightstring + item[2]).html(item[1]));
264 | }
265 | if (item[3]) {
266 | listItem.append($(' (' + item[3] + ') '));
267 | Search.output.append(listItem);
268 | listItem.slideDown(5, function() {
269 | displayNextItem();
270 | });
271 | } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
272 | $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX,
273 | dataType: "text",
274 | complete: function(jqxhr, textstatus) {
275 | var data = jqxhr.responseText;
276 | if (data !== '' && data !== undefined) {
277 | listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
278 | }
279 | Search.output.append(listItem);
280 | listItem.slideDown(5, function() {
281 | displayNextItem();
282 | });
283 | }});
284 | } else {
285 | // no source available, just display title
286 | Search.output.append(listItem);
287 | listItem.slideDown(5, function() {
288 | displayNextItem();
289 | });
290 | }
291 | }
292 | // search finished, update title and status message
293 | else {
294 | Search.stopPulse();
295 | Search.title.text(_('Search Results'));
296 | if (!resultCount)
297 | Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
298 | else
299 | Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
300 | Search.status.fadeIn(500);
301 | }
302 | }
303 | displayNextItem();
304 | },
305 |
306 | /**
307 | * search for object names
308 | */
309 | performObjectSearch : function(object, otherterms) {
310 | var filenames = this._index.filenames;
311 | var docnames = this._index.docnames;
312 | var objects = this._index.objects;
313 | var objnames = this._index.objnames;
314 | var titles = this._index.titles;
315 |
316 | var i;
317 | var results = [];
318 |
319 | for (var prefix in objects) {
320 | for (var name in objects[prefix]) {
321 | var fullname = (prefix ? prefix + '.' : '') + name;
322 | var fullnameLower = fullname.toLowerCase()
323 | if (fullnameLower.indexOf(object) > -1) {
324 | var score = 0;
325 | var parts = fullnameLower.split('.');
326 | // check for different match types: exact matches of full name or
327 | // "last name" (i.e. last dotted part)
328 | if (fullnameLower == object || parts[parts.length - 1] == object) {
329 | score += Scorer.objNameMatch;
330 | // matches in last name
331 | } else if (parts[parts.length - 1].indexOf(object) > -1) {
332 | score += Scorer.objPartialMatch;
333 | }
334 | var match = objects[prefix][name];
335 | var objname = objnames[match[1]][2];
336 | var title = titles[match[0]];
337 | // If more than one term searched for, we require other words to be
338 | // found in the name/title/description
339 | if (otherterms.length > 0) {
340 | var haystack = (prefix + ' ' + name + ' ' +
341 | objname + ' ' + title).toLowerCase();
342 | var allfound = true;
343 | for (i = 0; i < otherterms.length; i++) {
344 | if (haystack.indexOf(otherterms[i]) == -1) {
345 | allfound = false;
346 | break;
347 | }
348 | }
349 | if (!allfound) {
350 | continue;
351 | }
352 | }
353 | var descr = objname + _(', in ') + title;
354 |
355 | var anchor = match[3];
356 | if (anchor === '')
357 | anchor = fullname;
358 | else if (anchor == '-')
359 | anchor = objnames[match[1]][1] + '-' + fullname;
360 | // add custom score for some objects according to scorer
361 | if (Scorer.objPrio.hasOwnProperty(match[2])) {
362 | score += Scorer.objPrio[match[2]];
363 | } else {
364 | score += Scorer.objPrioDefault;
365 | }
366 | results.push([docnames[match[0]], fullname, '#'+anchor, descr, score, filenames[match[0]]]);
367 | }
368 | }
369 | }
370 |
371 | return results;
372 | },
373 |
374 | /**
375 | * search for full-text terms in the index
376 | */
377 | performTermsSearch : function(searchterms, excluded, terms, titleterms) {
378 | var docnames = this._index.docnames;
379 | var filenames = this._index.filenames;
380 | var titles = this._index.titles;
381 |
382 | var i, j, file;
383 | var fileMap = {};
384 | var scoreMap = {};
385 | var results = [];
386 |
387 | // perform the search on the required terms
388 | for (i = 0; i < searchterms.length; i++) {
389 | var word = searchterms[i];
390 | var files = [];
391 | var _o = [
392 | {files: terms[word], score: Scorer.term},
393 | {files: titleterms[word], score: Scorer.title}
394 | ];
395 | // add support for partial matches
396 | if (word.length > 2) {
397 | for (var w in terms) {
398 | if (w.match(word) && !terms[word]) {
399 | _o.push({files: terms[w], score: Scorer.partialTerm})
400 | }
401 | }
402 | for (var w in titleterms) {
403 | if (w.match(word) && !titleterms[word]) {
404 | _o.push({files: titleterms[w], score: Scorer.partialTitle})
405 | }
406 | }
407 | }
408 |
409 | // no match but word was a required one
410 | if ($u.every(_o, function(o){return o.files === undefined;})) {
411 | break;
412 | }
413 | // found search word in contents
414 | $u.each(_o, function(o) {
415 | var _files = o.files;
416 | if (_files === undefined)
417 | return
418 |
419 | if (_files.length === undefined)
420 | _files = [_files];
421 | files = files.concat(_files);
422 |
423 | // set score for the word in each file to Scorer.term
424 | for (j = 0; j < _files.length; j++) {
425 | file = _files[j];
426 | if (!(file in scoreMap))
427 | scoreMap[file] = {}
428 | scoreMap[file][word] = o.score;
429 | }
430 | });
431 |
432 | // create the mapping
433 | for (j = 0; j < files.length; j++) {
434 | file = files[j];
435 | if (file in fileMap)
436 | fileMap[file].push(word);
437 | else
438 | fileMap[file] = [word];
439 | }
440 | }
441 |
442 | // now check if the files don't contain excluded terms
443 | for (file in fileMap) {
444 | var valid = true;
445 |
446 | // check if all requirements are matched
447 | var filteredTermCount = // as search terms with length < 3 are discarded: ignore
448 | searchterms.filter(function(term){return term.length > 2}).length
449 | if (
450 | fileMap[file].length != searchterms.length &&
451 | fileMap[file].length != filteredTermCount
452 | ) continue;
453 |
454 | // ensure that none of the excluded terms is in the search result
455 | for (i = 0; i < excluded.length; i++) {
456 | if (terms[excluded[i]] == file ||
457 | titleterms[excluded[i]] == file ||
458 | $u.contains(terms[excluded[i]] || [], file) ||
459 | $u.contains(titleterms[excluded[i]] || [], file)) {
460 | valid = false;
461 | break;
462 | }
463 | }
464 |
465 | // if we have still a valid result we can add it to the result list
466 | if (valid) {
467 | // select one (max) score for the file.
468 | // for better ranking, we should calculate ranking by using words statistics like basic tf-idf...
469 | var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]}));
470 | results.push([docnames[file], titles[file], '', null, score, filenames[file]]);
471 | }
472 | }
473 | return results;
474 | },
475 |
476 | /**
477 | * helper function to return a node containing the
478 | * search summary for a given text. keywords is a list
479 | * of stemmed words, hlwords is the list of normal, unstemmed
480 | * words. the first one is used to find the occurrence, the
481 | * latter for highlighting it.
482 | */
483 | makeSearchSummary : function(htmlText, keywords, hlwords) {
484 | var text = Search.htmlToText(htmlText);
485 | var textLower = text.toLowerCase();
486 | var start = 0;
487 | $.each(keywords, function() {
488 | var i = textLower.indexOf(this.toLowerCase());
489 | if (i > -1)
490 | start = i;
491 | });
492 | start = Math.max(start - 120, 0);
493 | var excerpt = ((start > 0) ? '...' : '') +
494 | $.trim(text.substr(start, 240)) +
495 | ((start + 240 - text.length) ? '...' : '');
496 | var rv = $('
').text(excerpt);
497 | $.each(hlwords, function() {
498 | rv = rv.highlightText(this, 'highlighted');
499 | });
500 | return rv;
501 | }
502 | };
503 |
504 | $(document).ready(function() {
505 | Search.init();
506 | });
507 |
--------------------------------------------------------------------------------
/explora/docs/build/html/_static/underscore-1.3.1.js:
--------------------------------------------------------------------------------
1 | // Underscore.js 1.3.1
2 | // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
3 | // Underscore is freely distributable under the MIT license.
4 | // Portions of Underscore are inspired or borrowed from Prototype,
5 | // Oliver Steele's Functional, and John Resig's Micro-Templating.
6 | // For all details and documentation:
7 | // http://documentcloud.github.com/underscore
8 |
9 | (function() {
10 |
11 | // Baseline setup
12 | // --------------
13 |
14 | // Establish the root object, `window` in the browser, or `global` on the server.
15 | var root = this;
16 |
17 | // Save the previous value of the `_` variable.
18 | var previousUnderscore = root._;
19 |
20 | // Establish the object that gets returned to break out of a loop iteration.
21 | var breaker = {};
22 |
23 | // Save bytes in the minified (but not gzipped) version:
24 | var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
25 |
26 | // Create quick reference variables for speed access to core prototypes.
27 | var slice = ArrayProto.slice,
28 | unshift = ArrayProto.unshift,
29 | toString = ObjProto.toString,
30 | hasOwnProperty = ObjProto.hasOwnProperty;
31 |
32 | // All **ECMAScript 5** native function implementations that we hope to use
33 | // are declared here.
34 | var
35 | nativeForEach = ArrayProto.forEach,
36 | nativeMap = ArrayProto.map,
37 | nativeReduce = ArrayProto.reduce,
38 | nativeReduceRight = ArrayProto.reduceRight,
39 | nativeFilter = ArrayProto.filter,
40 | nativeEvery = ArrayProto.every,
41 | nativeSome = ArrayProto.some,
42 | nativeIndexOf = ArrayProto.indexOf,
43 | nativeLastIndexOf = ArrayProto.lastIndexOf,
44 | nativeIsArray = Array.isArray,
45 | nativeKeys = Object.keys,
46 | nativeBind = FuncProto.bind;
47 |
48 | // Create a safe reference to the Underscore object for use below.
49 | var _ = function(obj) { return new wrapper(obj); };
50 |
51 | // Export the Underscore object for **Node.js**, with
52 | // backwards-compatibility for the old `require()` API. If we're in
53 | // the browser, add `_` as a global object via a string identifier,
54 | // for Closure Compiler "advanced" mode.
55 | if (typeof exports !== 'undefined') {
56 | if (typeof module !== 'undefined' && module.exports) {
57 | exports = module.exports = _;
58 | }
59 | exports._ = _;
60 | } else {
61 | root['_'] = _;
62 | }
63 |
64 | // Current version.
65 | _.VERSION = '1.3.1';
66 |
67 | // Collection Functions
68 | // --------------------
69 |
70 | // The cornerstone, an `each` implementation, aka `forEach`.
71 | // Handles objects with the built-in `forEach`, arrays, and raw objects.
72 | // Delegates to **ECMAScript 5**'s native `forEach` if available.
73 | var each = _.each = _.forEach = function(obj, iterator, context) {
74 | if (obj == null) return;
75 | if (nativeForEach && obj.forEach === nativeForEach) {
76 | obj.forEach(iterator, context);
77 | } else if (obj.length === +obj.length) {
78 | for (var i = 0, l = obj.length; i < l; i++) {
79 | if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
80 | }
81 | } else {
82 | for (var key in obj) {
83 | if (_.has(obj, key)) {
84 | if (iterator.call(context, obj[key], key, obj) === breaker) return;
85 | }
86 | }
87 | }
88 | };
89 |
90 | // Return the results of applying the iterator to each element.
91 | // Delegates to **ECMAScript 5**'s native `map` if available.
92 | _.map = _.collect = function(obj, iterator, context) {
93 | var results = [];
94 | if (obj == null) return results;
95 | if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
96 | each(obj, function(value, index, list) {
97 | results[results.length] = iterator.call(context, value, index, list);
98 | });
99 | if (obj.length === +obj.length) results.length = obj.length;
100 | return results;
101 | };
102 |
103 | // **Reduce** builds up a single result from a list of values, aka `inject`,
104 | // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
105 | _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
106 | var initial = arguments.length > 2;
107 | if (obj == null) obj = [];
108 | if (nativeReduce && obj.reduce === nativeReduce) {
109 | if (context) iterator = _.bind(iterator, context);
110 | return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
111 | }
112 | each(obj, function(value, index, list) {
113 | if (!initial) {
114 | memo = value;
115 | initial = true;
116 | } else {
117 | memo = iterator.call(context, memo, value, index, list);
118 | }
119 | });
120 | if (!initial) throw new TypeError('Reduce of empty array with no initial value');
121 | return memo;
122 | };
123 |
124 | // The right-associative version of reduce, also known as `foldr`.
125 | // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
126 | _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
127 | var initial = arguments.length > 2;
128 | if (obj == null) obj = [];
129 | if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
130 | if (context) iterator = _.bind(iterator, context);
131 | return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
132 | }
133 | var reversed = _.toArray(obj).reverse();
134 | if (context && !initial) iterator = _.bind(iterator, context);
135 | return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator);
136 | };
137 |
138 | // Return the first value which passes a truth test. Aliased as `detect`.
139 | _.find = _.detect = function(obj, iterator, context) {
140 | var result;
141 | any(obj, function(value, index, list) {
142 | if (iterator.call(context, value, index, list)) {
143 | result = value;
144 | return true;
145 | }
146 | });
147 | return result;
148 | };
149 |
150 | // Return all the elements that pass a truth test.
151 | // Delegates to **ECMAScript 5**'s native `filter` if available.
152 | // Aliased as `select`.
153 | _.filter = _.select = function(obj, iterator, context) {
154 | var results = [];
155 | if (obj == null) return results;
156 | if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
157 | each(obj, function(value, index, list) {
158 | if (iterator.call(context, value, index, list)) results[results.length] = value;
159 | });
160 | return results;
161 | };
162 |
163 | // Return all the elements for which a truth test fails.
164 | _.reject = function(obj, iterator, context) {
165 | var results = [];
166 | if (obj == null) return results;
167 | each(obj, function(value, index, list) {
168 | if (!iterator.call(context, value, index, list)) results[results.length] = value;
169 | });
170 | return results;
171 | };
172 |
173 | // Determine whether all of the elements match a truth test.
174 | // Delegates to **ECMAScript 5**'s native `every` if available.
175 | // Aliased as `all`.
176 | _.every = _.all = function(obj, iterator, context) {
177 | var result = true;
178 | if (obj == null) return result;
179 | if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
180 | each(obj, function(value, index, list) {
181 | if (!(result = result && iterator.call(context, value, index, list))) return breaker;
182 | });
183 | return result;
184 | };
185 |
186 | // Determine if at least one element in the object matches a truth test.
187 | // Delegates to **ECMAScript 5**'s native `some` if available.
188 | // Aliased as `any`.
189 | var any = _.some = _.any = function(obj, iterator, context) {
190 | iterator || (iterator = _.identity);
191 | var result = false;
192 | if (obj == null) return result;
193 | if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
194 | each(obj, function(value, index, list) {
195 | if (result || (result = iterator.call(context, value, index, list))) return breaker;
196 | });
197 | return !!result;
198 | };
199 |
200 | // Determine if a given value is included in the array or object using `===`.
201 | // Aliased as `contains`.
202 | _.include = _.contains = function(obj, target) {
203 | var found = false;
204 | if (obj == null) return found;
205 | if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
206 | found = any(obj, function(value) {
207 | return value === target;
208 | });
209 | return found;
210 | };
211 |
212 | // Invoke a method (with arguments) on every item in a collection.
213 | _.invoke = function(obj, method) {
214 | var args = slice.call(arguments, 2);
215 | return _.map(obj, function(value) {
216 | return (_.isFunction(method) ? method || value : value[method]).apply(value, args);
217 | });
218 | };
219 |
220 | // Convenience version of a common use case of `map`: fetching a property.
221 | _.pluck = function(obj, key) {
222 | return _.map(obj, function(value){ return value[key]; });
223 | };
224 |
225 | // Return the maximum element or (element-based computation).
226 | _.max = function(obj, iterator, context) {
227 | if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
228 | if (!iterator && _.isEmpty(obj)) return -Infinity;
229 | var result = {computed : -Infinity};
230 | each(obj, function(value, index, list) {
231 | var computed = iterator ? iterator.call(context, value, index, list) : value;
232 | computed >= result.computed && (result = {value : value, computed : computed});
233 | });
234 | return result.value;
235 | };
236 |
237 | // Return the minimum element (or element-based computation).
238 | _.min = function(obj, iterator, context) {
239 | if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
240 | if (!iterator && _.isEmpty(obj)) return Infinity;
241 | var result = {computed : Infinity};
242 | each(obj, function(value, index, list) {
243 | var computed = iterator ? iterator.call(context, value, index, list) : value;
244 | computed < result.computed && (result = {value : value, computed : computed});
245 | });
246 | return result.value;
247 | };
248 |
249 | // Shuffle an array.
250 | _.shuffle = function(obj) {
251 | var shuffled = [], rand;
252 | each(obj, function(value, index, list) {
253 | if (index == 0) {
254 | shuffled[0] = value;
255 | } else {
256 | rand = Math.floor(Math.random() * (index + 1));
257 | shuffled[index] = shuffled[rand];
258 | shuffled[rand] = value;
259 | }
260 | });
261 | return shuffled;
262 | };
263 |
264 | // Sort the object's values by a criterion produced by an iterator.
265 | _.sortBy = function(obj, iterator, context) {
266 | return _.pluck(_.map(obj, function(value, index, list) {
267 | return {
268 | value : value,
269 | criteria : iterator.call(context, value, index, list)
270 | };
271 | }).sort(function(left, right) {
272 | var a = left.criteria, b = right.criteria;
273 | return a < b ? -1 : a > b ? 1 : 0;
274 | }), 'value');
275 | };
276 |
277 | // Groups the object's values by a criterion. Pass either a string attribute
278 | // to group by, or a function that returns the criterion.
279 | _.groupBy = function(obj, val) {
280 | var result = {};
281 | var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
282 | each(obj, function(value, index) {
283 | var key = iterator(value, index);
284 | (result[key] || (result[key] = [])).push(value);
285 | });
286 | return result;
287 | };
288 |
289 | // Use a comparator function to figure out at what index an object should
290 | // be inserted so as to maintain order. Uses binary search.
291 | _.sortedIndex = function(array, obj, iterator) {
292 | iterator || (iterator = _.identity);
293 | var low = 0, high = array.length;
294 | while (low < high) {
295 | var mid = (low + high) >> 1;
296 | iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
297 | }
298 | return low;
299 | };
300 |
301 | // Safely convert anything iterable into a real, live array.
302 | _.toArray = function(iterable) {
303 | if (!iterable) return [];
304 | if (iterable.toArray) return iterable.toArray();
305 | if (_.isArray(iterable)) return slice.call(iterable);
306 | if (_.isArguments(iterable)) return slice.call(iterable);
307 | return _.values(iterable);
308 | };
309 |
310 | // Return the number of elements in an object.
311 | _.size = function(obj) {
312 | return _.toArray(obj).length;
313 | };
314 |
315 | // Array Functions
316 | // ---------------
317 |
318 | // Get the first element of an array. Passing **n** will return the first N
319 | // values in the array. Aliased as `head`. The **guard** check allows it to work
320 | // with `_.map`.
321 | _.first = _.head = function(array, n, guard) {
322 | return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
323 | };
324 |
325 | // Returns everything but the last entry of the array. Especcialy useful on
326 | // the arguments object. Passing **n** will return all the values in
327 | // the array, excluding the last N. The **guard** check allows it to work with
328 | // `_.map`.
329 | _.initial = function(array, n, guard) {
330 | return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
331 | };
332 |
333 | // Get the last element of an array. Passing **n** will return the last N
334 | // values in the array. The **guard** check allows it to work with `_.map`.
335 | _.last = function(array, n, guard) {
336 | if ((n != null) && !guard) {
337 | return slice.call(array, Math.max(array.length - n, 0));
338 | } else {
339 | return array[array.length - 1];
340 | }
341 | };
342 |
343 | // Returns everything but the first entry of the array. Aliased as `tail`.
344 | // Especially useful on the arguments object. Passing an **index** will return
345 | // the rest of the values in the array from that index onward. The **guard**
346 | // check allows it to work with `_.map`.
347 | _.rest = _.tail = function(array, index, guard) {
348 | return slice.call(array, (index == null) || guard ? 1 : index);
349 | };
350 |
351 | // Trim out all falsy values from an array.
352 | _.compact = function(array) {
353 | return _.filter(array, function(value){ return !!value; });
354 | };
355 |
356 | // Return a completely flattened version of an array.
357 | _.flatten = function(array, shallow) {
358 | return _.reduce(array, function(memo, value) {
359 | if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value));
360 | memo[memo.length] = value;
361 | return memo;
362 | }, []);
363 | };
364 |
365 | // Return a version of the array that does not contain the specified value(s).
366 | _.without = function(array) {
367 | return _.difference(array, slice.call(arguments, 1));
368 | };
369 |
370 | // Produce a duplicate-free version of the array. If the array has already
371 | // been sorted, you have the option of using a faster algorithm.
372 | // Aliased as `unique`.
373 | _.uniq = _.unique = function(array, isSorted, iterator) {
374 | var initial = iterator ? _.map(array, iterator) : array;
375 | var result = [];
376 | _.reduce(initial, function(memo, el, i) {
377 | if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) {
378 | memo[memo.length] = el;
379 | result[result.length] = array[i];
380 | }
381 | return memo;
382 | }, []);
383 | return result;
384 | };
385 |
386 | // Produce an array that contains the union: each distinct element from all of
387 | // the passed-in arrays.
388 | _.union = function() {
389 | return _.uniq(_.flatten(arguments, true));
390 | };
391 |
392 | // Produce an array that contains every item shared between all the
393 | // passed-in arrays. (Aliased as "intersect" for back-compat.)
394 | _.intersection = _.intersect = function(array) {
395 | var rest = slice.call(arguments, 1);
396 | return _.filter(_.uniq(array), function(item) {
397 | return _.every(rest, function(other) {
398 | return _.indexOf(other, item) >= 0;
399 | });
400 | });
401 | };
402 |
403 | // Take the difference between one array and a number of other arrays.
404 | // Only the elements present in just the first array will remain.
405 | _.difference = function(array) {
406 | var rest = _.flatten(slice.call(arguments, 1));
407 | return _.filter(array, function(value){ return !_.include(rest, value); });
408 | };
409 |
410 | // Zip together multiple lists into a single array -- elements that share
411 | // an index go together.
412 | _.zip = function() {
413 | var args = slice.call(arguments);
414 | var length = _.max(_.pluck(args, 'length'));
415 | var results = new Array(length);
416 | for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
417 | return results;
418 | };
419 |
420 | // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
421 | // we need this function. Return the position of the first occurrence of an
422 | // item in an array, or -1 if the item is not included in the array.
423 | // Delegates to **ECMAScript 5**'s native `indexOf` if available.
424 | // If the array is large and already in sort order, pass `true`
425 | // for **isSorted** to use binary search.
426 | _.indexOf = function(array, item, isSorted) {
427 | if (array == null) return -1;
428 | var i, l;
429 | if (isSorted) {
430 | i = _.sortedIndex(array, item);
431 | return array[i] === item ? i : -1;
432 | }
433 | if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
434 | for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;
435 | return -1;
436 | };
437 |
438 | // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
439 | _.lastIndexOf = function(array, item) {
440 | if (array == null) return -1;
441 | if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
442 | var i = array.length;
443 | while (i--) if (i in array && array[i] === item) return i;
444 | return -1;
445 | };
446 |
447 | // Generate an integer Array containing an arithmetic progression. A port of
448 | // the native Python `range()` function. See
449 | // [the Python documentation](http://docs.python.org/library/functions.html#range).
450 | _.range = function(start, stop, step) {
451 | if (arguments.length <= 1) {
452 | stop = start || 0;
453 | start = 0;
454 | }
455 | step = arguments[2] || 1;
456 |
457 | var len = Math.max(Math.ceil((stop - start) / step), 0);
458 | var idx = 0;
459 | var range = new Array(len);
460 |
461 | while(idx < len) {
462 | range[idx++] = start;
463 | start += step;
464 | }
465 |
466 | return range;
467 | };
468 |
469 | // Function (ahem) Functions
470 | // ------------------
471 |
472 | // Reusable constructor function for prototype setting.
473 | var ctor = function(){};
474 |
475 | // Create a function bound to a given object (assigning `this`, and arguments,
476 | // optionally). Binding with arguments is also known as `curry`.
477 | // Delegates to **ECMAScript 5**'s native `Function.bind` if available.
478 | // We check for `func.bind` first, to fail fast when `func` is undefined.
479 | _.bind = function bind(func, context) {
480 | var bound, args;
481 | if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
482 | if (!_.isFunction(func)) throw new TypeError;
483 | args = slice.call(arguments, 2);
484 | return bound = function() {
485 | if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
486 | ctor.prototype = func.prototype;
487 | var self = new ctor;
488 | var result = func.apply(self, args.concat(slice.call(arguments)));
489 | if (Object(result) === result) return result;
490 | return self;
491 | };
492 | };
493 |
494 | // Bind all of an object's methods to that object. Useful for ensuring that
495 | // all callbacks defined on an object belong to it.
496 | _.bindAll = function(obj) {
497 | var funcs = slice.call(arguments, 1);
498 | if (funcs.length == 0) funcs = _.functions(obj);
499 | each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
500 | return obj;
501 | };
502 |
503 | // Memoize an expensive function by storing its results.
504 | _.memoize = function(func, hasher) {
505 | var memo = {};
506 | hasher || (hasher = _.identity);
507 | return function() {
508 | var key = hasher.apply(this, arguments);
509 | return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
510 | };
511 | };
512 |
513 | // Delays a function for the given number of milliseconds, and then calls
514 | // it with the arguments supplied.
515 | _.delay = function(func, wait) {
516 | var args = slice.call(arguments, 2);
517 | return setTimeout(function(){ return func.apply(func, args); }, wait);
518 | };
519 |
520 | // Defers a function, scheduling it to run after the current call stack has
521 | // cleared.
522 | _.defer = function(func) {
523 | return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
524 | };
525 |
526 | // Returns a function, that, when invoked, will only be triggered at most once
527 | // during a given window of time.
528 | _.throttle = function(func, wait) {
529 | var context, args, timeout, throttling, more;
530 | var whenDone = _.debounce(function(){ more = throttling = false; }, wait);
531 | return function() {
532 | context = this; args = arguments;
533 | var later = function() {
534 | timeout = null;
535 | if (more) func.apply(context, args);
536 | whenDone();
537 | };
538 | if (!timeout) timeout = setTimeout(later, wait);
539 | if (throttling) {
540 | more = true;
541 | } else {
542 | func.apply(context, args);
543 | }
544 | whenDone();
545 | throttling = true;
546 | };
547 | };
548 |
549 | // Returns a function, that, as long as it continues to be invoked, will not
550 | // be triggered. The function will be called after it stops being called for
551 | // N milliseconds.
552 | _.debounce = function(func, wait) {
553 | var timeout;
554 | return function() {
555 | var context = this, args = arguments;
556 | var later = function() {
557 | timeout = null;
558 | func.apply(context, args);
559 | };
560 | clearTimeout(timeout);
561 | timeout = setTimeout(later, wait);
562 | };
563 | };
564 |
565 | // Returns a function that will be executed at most one time, no matter how
566 | // often you call it. Useful for lazy initialization.
567 | _.once = function(func) {
568 | var ran = false, memo;
569 | return function() {
570 | if (ran) return memo;
571 | ran = true;
572 | return memo = func.apply(this, arguments);
573 | };
574 | };
575 |
576 | // Returns the first function passed as an argument to the second,
577 | // allowing you to adjust arguments, run code before and after, and
578 | // conditionally execute the original function.
579 | _.wrap = function(func, wrapper) {
580 | return function() {
581 | var args = [func].concat(slice.call(arguments, 0));
582 | return wrapper.apply(this, args);
583 | };
584 | };
585 |
586 | // Returns a function that is the composition of a list of functions, each
587 | // consuming the return value of the function that follows.
588 | _.compose = function() {
589 | var funcs = arguments;
590 | return function() {
591 | var args = arguments;
592 | for (var i = funcs.length - 1; i >= 0; i--) {
593 | args = [funcs[i].apply(this, args)];
594 | }
595 | return args[0];
596 | };
597 | };
598 |
599 | // Returns a function that will only be executed after being called N times.
600 | _.after = function(times, func) {
601 | if (times <= 0) return func();
602 | return function() {
603 | if (--times < 1) { return func.apply(this, arguments); }
604 | };
605 | };
606 |
607 | // Object Functions
608 | // ----------------
609 |
610 | // Retrieve the names of an object's properties.
611 | // Delegates to **ECMAScript 5**'s native `Object.keys`
612 | _.keys = nativeKeys || function(obj) {
613 | if (obj !== Object(obj)) throw new TypeError('Invalid object');
614 | var keys = [];
615 | for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
616 | return keys;
617 | };
618 |
619 | // Retrieve the values of an object's properties.
620 | _.values = function(obj) {
621 | return _.map(obj, _.identity);
622 | };
623 |
624 | // Return a sorted list of the function names available on the object.
625 | // Aliased as `methods`
626 | _.functions = _.methods = function(obj) {
627 | var names = [];
628 | for (var key in obj) {
629 | if (_.isFunction(obj[key])) names.push(key);
630 | }
631 | return names.sort();
632 | };
633 |
634 | // Extend a given object with all the properties in passed-in object(s).
635 | _.extend = function(obj) {
636 | each(slice.call(arguments, 1), function(source) {
637 | for (var prop in source) {
638 | obj[prop] = source[prop];
639 | }
640 | });
641 | return obj;
642 | };
643 |
644 | // Fill in a given object with default properties.
645 | _.defaults = function(obj) {
646 | each(slice.call(arguments, 1), function(source) {
647 | for (var prop in source) {
648 | if (obj[prop] == null) obj[prop] = source[prop];
649 | }
650 | });
651 | return obj;
652 | };
653 |
654 | // Create a (shallow-cloned) duplicate of an object.
655 | _.clone = function(obj) {
656 | if (!_.isObject(obj)) return obj;
657 | return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
658 | };
659 |
660 | // Invokes interceptor with the obj, and then returns obj.
661 | // The primary purpose of this method is to "tap into" a method chain, in
662 | // order to perform operations on intermediate results within the chain.
663 | _.tap = function(obj, interceptor) {
664 | interceptor(obj);
665 | return obj;
666 | };
667 |
668 | // Internal recursive comparison function.
669 | function eq(a, b, stack) {
670 | // Identical objects are equal. `0 === -0`, but they aren't identical.
671 | // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
672 | if (a === b) return a !== 0 || 1 / a == 1 / b;
673 | // A strict comparison is necessary because `null == undefined`.
674 | if (a == null || b == null) return a === b;
675 | // Unwrap any wrapped objects.
676 | if (a._chain) a = a._wrapped;
677 | if (b._chain) b = b._wrapped;
678 | // Invoke a custom `isEqual` method if one is provided.
679 | if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b);
680 | if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a);
681 | // Compare `[[Class]]` names.
682 | var className = toString.call(a);
683 | if (className != toString.call(b)) return false;
684 | switch (className) {
685 | // Strings, numbers, dates, and booleans are compared by value.
686 | case '[object String]':
687 | // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
688 | // equivalent to `new String("5")`.
689 | return a == String(b);
690 | case '[object Number]':
691 | // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
692 | // other numeric values.
693 | return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
694 | case '[object Date]':
695 | case '[object Boolean]':
696 | // Coerce dates and booleans to numeric primitive values. Dates are compared by their
697 | // millisecond representations. Note that invalid dates with millisecond representations
698 | // of `NaN` are not equivalent.
699 | return +a == +b;
700 | // RegExps are compared by their source patterns and flags.
701 | case '[object RegExp]':
702 | return a.source == b.source &&
703 | a.global == b.global &&
704 | a.multiline == b.multiline &&
705 | a.ignoreCase == b.ignoreCase;
706 | }
707 | if (typeof a != 'object' || typeof b != 'object') return false;
708 | // Assume equality for cyclic structures. The algorithm for detecting cyclic
709 | // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
710 | var length = stack.length;
711 | while (length--) {
712 | // Linear search. Performance is inversely proportional to the number of
713 | // unique nested structures.
714 | if (stack[length] == a) return true;
715 | }
716 | // Add the first object to the stack of traversed objects.
717 | stack.push(a);
718 | var size = 0, result = true;
719 | // Recursively compare objects and arrays.
720 | if (className == '[object Array]') {
721 | // Compare array lengths to determine if a deep comparison is necessary.
722 | size = a.length;
723 | result = size == b.length;
724 | if (result) {
725 | // Deep compare the contents, ignoring non-numeric properties.
726 | while (size--) {
727 | // Ensure commutative equality for sparse arrays.
728 | if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break;
729 | }
730 | }
731 | } else {
732 | // Objects with different constructors are not equivalent.
733 | if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false;
734 | // Deep compare objects.
735 | for (var key in a) {
736 | if (_.has(a, key)) {
737 | // Count the expected number of properties.
738 | size++;
739 | // Deep compare each member.
740 | if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break;
741 | }
742 | }
743 | // Ensure that both objects contain the same number of properties.
744 | if (result) {
745 | for (key in b) {
746 | if (_.has(b, key) && !(size--)) break;
747 | }
748 | result = !size;
749 | }
750 | }
751 | // Remove the first object from the stack of traversed objects.
752 | stack.pop();
753 | return result;
754 | }
755 |
756 | // Perform a deep comparison to check if two objects are equal.
757 | _.isEqual = function(a, b) {
758 | return eq(a, b, []);
759 | };
760 |
761 | // Is a given array, string, or object empty?
762 | // An "empty" object has no enumerable own-properties.
763 | _.isEmpty = function(obj) {
764 | if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
765 | for (var key in obj) if (_.has(obj, key)) return false;
766 | return true;
767 | };
768 |
769 | // Is a given value a DOM element?
770 | _.isElement = function(obj) {
771 | return !!(obj && obj.nodeType == 1);
772 | };
773 |
774 | // Is a given value an array?
775 | // Delegates to ECMA5's native Array.isArray
776 | _.isArray = nativeIsArray || function(obj) {
777 | return toString.call(obj) == '[object Array]';
778 | };
779 |
780 | // Is a given variable an object?
781 | _.isObject = function(obj) {
782 | return obj === Object(obj);
783 | };
784 |
785 | // Is a given variable an arguments object?
786 | _.isArguments = function(obj) {
787 | return toString.call(obj) == '[object Arguments]';
788 | };
789 | if (!_.isArguments(arguments)) {
790 | _.isArguments = function(obj) {
791 | return !!(obj && _.has(obj, 'callee'));
792 | };
793 | }
794 |
795 | // Is a given value a function?
796 | _.isFunction = function(obj) {
797 | return toString.call(obj) == '[object Function]';
798 | };
799 |
800 | // Is a given value a string?
801 | _.isString = function(obj) {
802 | return toString.call(obj) == '[object String]';
803 | };
804 |
805 | // Is a given value a number?
806 | _.isNumber = function(obj) {
807 | return toString.call(obj) == '[object Number]';
808 | };
809 |
810 | // Is the given value `NaN`?
811 | _.isNaN = function(obj) {
812 | // `NaN` is the only value for which `===` is not reflexive.
813 | return obj !== obj;
814 | };
815 |
816 | // Is a given value a boolean?
817 | _.isBoolean = function(obj) {
818 | return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
819 | };
820 |
821 | // Is a given value a date?
822 | _.isDate = function(obj) {
823 | return toString.call(obj) == '[object Date]';
824 | };
825 |
826 | // Is the given value a regular expression?
827 | _.isRegExp = function(obj) {
828 | return toString.call(obj) == '[object RegExp]';
829 | };
830 |
831 | // Is a given value equal to null?
832 | _.isNull = function(obj) {
833 | return obj === null;
834 | };
835 |
836 | // Is a given variable undefined?
837 | _.isUndefined = function(obj) {
838 | return obj === void 0;
839 | };
840 |
841 | // Has own property?
842 | _.has = function(obj, key) {
843 | return hasOwnProperty.call(obj, key);
844 | };
845 |
846 | // Utility Functions
847 | // -----------------
848 |
849 | // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
850 | // previous owner. Returns a reference to the Underscore object.
851 | _.noConflict = function() {
852 | root._ = previousUnderscore;
853 | return this;
854 | };
855 |
856 | // Keep the identity function around for default iterators.
857 | _.identity = function(value) {
858 | return value;
859 | };
860 |
861 | // Run a function **n** times.
862 | _.times = function (n, iterator, context) {
863 | for (var i = 0; i < n; i++) iterator.call(context, i);
864 | };
865 |
866 | // Escape a string for HTML interpolation.
867 | _.escape = function(string) {
868 | return (''+string).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g,'/');
869 | };
870 |
871 | // Add your own custom functions to the Underscore object, ensuring that
872 | // they're correctly added to the OOP wrapper as well.
873 | _.mixin = function(obj) {
874 | each(_.functions(obj), function(name){
875 | addToWrapper(name, _[name] = obj[name]);
876 | });
877 | };
878 |
879 | // Generate a unique integer id (unique within the entire client session).
880 | // Useful for temporary DOM ids.
881 | var idCounter = 0;
882 | _.uniqueId = function(prefix) {
883 | var id = idCounter++;
884 | return prefix ? prefix + id : id;
885 | };
886 |
887 | // By default, Underscore uses ERB-style template delimiters, change the
888 | // following template settings to use alternative delimiters.
889 | _.templateSettings = {
890 | evaluate : /<%([\s\S]+?)%>/g,
891 | interpolate : /<%=([\s\S]+?)%>/g,
892 | escape : /<%-([\s\S]+?)%>/g
893 | };
894 |
895 | // When customizing `templateSettings`, if you don't want to define an
896 | // interpolation, evaluation or escaping regex, we need one that is
897 | // guaranteed not to match.
898 | var noMatch = /.^/;
899 |
900 | // Within an interpolation, evaluation, or escaping, remove HTML escaping
901 | // that had been previously added.
902 | var unescape = function(code) {
903 | return code.replace(/\\\\/g, '\\').replace(/\\'/g, "'");
904 | };
905 |
906 | // JavaScript micro-templating, similar to John Resig's implementation.
907 | // Underscore templating handles arbitrary delimiters, preserves whitespace,
908 | // and correctly escapes quotes within interpolated code.
909 | _.template = function(str, data) {
910 | var c = _.templateSettings;
911 | var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
912 | 'with(obj||{}){__p.push(\'' +
913 | str.replace(/\\/g, '\\\\')
914 | .replace(/'/g, "\\'")
915 | .replace(c.escape || noMatch, function(match, code) {
916 | return "',_.escape(" + unescape(code) + "),'";
917 | })
918 | .replace(c.interpolate || noMatch, function(match, code) {
919 | return "'," + unescape(code) + ",'";
920 | })
921 | .replace(c.evaluate || noMatch, function(match, code) {
922 | return "');" + unescape(code).replace(/[\r\n\t]/g, ' ') + ";__p.push('";
923 | })
924 | .replace(/\r/g, '\\r')
925 | .replace(/\n/g, '\\n')
926 | .replace(/\t/g, '\\t')
927 | + "');}return __p.join('');";
928 | var func = new Function('obj', '_', tmpl);
929 | if (data) return func(data, _);
930 | return function(data) {
931 | return func.call(this, data, _);
932 | };
933 | };
934 |
935 | // Add a "chain" function, which will delegate to the wrapper.
936 | _.chain = function(obj) {
937 | return _(obj).chain();
938 | };
939 |
940 | // The OOP Wrapper
941 | // ---------------
942 |
943 | // If Underscore is called as a function, it returns a wrapped object that
944 | // can be used OO-style. This wrapper holds altered versions of all the
945 | // underscore functions. Wrapped objects may be chained.
946 | var wrapper = function(obj) { this._wrapped = obj; };
947 |
948 | // Expose `wrapper.prototype` as `_.prototype`
949 | _.prototype = wrapper.prototype;
950 |
951 | // Helper function to continue chaining intermediate results.
952 | var result = function(obj, chain) {
953 | return chain ? _(obj).chain() : obj;
954 | };
955 |
956 | // A method to easily add functions to the OOP wrapper.
957 | var addToWrapper = function(name, func) {
958 | wrapper.prototype[name] = function() {
959 | var args = slice.call(arguments);
960 | unshift.call(args, this._wrapped);
961 | return result(func.apply(_, args), this._chain);
962 | };
963 | };
964 |
965 | // Add all of the Underscore functions to the wrapper object.
966 | _.mixin(_);
967 |
968 | // Add all mutator Array functions to the wrapper.
969 | each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
970 | var method = ArrayProto[name];
971 | wrapper.prototype[name] = function() {
972 | var wrapped = this._wrapped;
973 | method.apply(wrapped, arguments);
974 | var length = wrapped.length;
975 | if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0];
976 | return result(wrapped, this._chain);
977 | };
978 | });
979 |
980 | // Add all accessor Array functions to the wrapper.
981 | each(['concat', 'join', 'slice'], function(name) {
982 | var method = ArrayProto[name];
983 | wrapper.prototype[name] = function() {
984 | return result(method.apply(this._wrapped, arguments), this._chain);
985 | };
986 | });
987 |
988 | // Start chaining a wrapped Underscore object.
989 | wrapper.prototype.chain = function() {
990 | this._chain = true;
991 | return this;
992 | };
993 |
994 | // Extracts the result from a wrapped and chained object.
995 | wrapper.prototype.value = function() {
996 | return this._wrapped;
997 | };
998 |
999 | }).call(this);
1000 |
--------------------------------------------------------------------------------
/explora/docs/build/html/_static/underscore.js:
--------------------------------------------------------------------------------
1 | // Underscore.js 1.3.1
2 | // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
3 | // Underscore is freely distributable under the MIT license.
4 | // Portions of Underscore are inspired or borrowed from Prototype,
5 | // Oliver Steele's Functional, and John Resig's Micro-Templating.
6 | // For all details and documentation:
7 | // http://documentcloud.github.com/underscore
8 | (function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
9 | c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,
10 | h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each=
11 | b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e2;a==
12 | null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=
13 | function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e=
14 | e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
15 | function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;bd?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,
17 | c,d){d||(d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};
24 | b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments,
25 | 1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};
26 | b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};
27 | b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e /g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a),
28 | function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+
29 | u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]=
30 | function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=
31 | true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);
32 |
--------------------------------------------------------------------------------
/explora/docs/build/html/genindex.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Index — explora-dataagora 1.0.0 documentation
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
Index
39 |
40 |
41 |
M
42 | |
S
43 |
44 |
45 |
M
46 |
52 |
53 |
S
54 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
80 |
81 |
82 |
94 |
98 |
99 |
--------------------------------------------------------------------------------
/explora/docs/build/html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Welcome to explora’s documentation! — explora-dataagora 1.0.0 documentation
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
Welcome to explora’s documentation!
42 |
Explora is a customized Jupyter Notebook used for starting decentralized training sessions.
43 |
52 |
53 |
54 |
Indices and tables
55 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
96 |
97 |
98 |
113 |
117 |
118 |
--------------------------------------------------------------------------------
/explora/docs/build/html/main.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | main module — explora-dataagora 1.0.0 documentation
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
main module
43 |
44 |
45 | async main.
start_new_session
( self , repo_id , model , hyperparameters , percentage_averaged=0.75 , max_rounds=5 , library_type='PYTHON' , checkpoint_frequency=1 )
46 | Validate arguments and then start a new session by sending a message to
47 | the server with the given configuration. Designed to be called in
48 | Explora.ipynb .
49 |
50 | Parameters
51 |
52 | repo_id (str ) – The repo ID associated with the current dataset.
53 | model (keras.engine.Model ) – The initial Keras model to train with. The
54 | model must be compiled!
55 | hyperparams (dict ) – The hyperparameters to be used during training.
56 | Must include batch_size !
57 | percentage_averaged (float ) – Percentage of nodes to be averaged before
58 | moving on to the next round.
59 | max_rounds (int ) – Maximum number of rounds to train for.
60 | library_type (str ) – The type of library to train with. Must be either
61 | PYTHON or JAVASCRIPT .
62 | checkpoint_frequency (int ) – Save the model in S3 every
63 | checkpoint_frequency rounds.
64 |
65 |
66 |
67 | Examples
68 | >>> start_new_session (
69 | ... repo_id = "c9bf9e57-1685-4c89-bafb-ff5af830be8a" ,
70 | ... model = keras . models . load_model ( "model.h5" ),
71 | ... hyperparameters = { "batch_size" : 100 },
72 | ... percentage_averaged = 0.75 ,
73 | ... max_rounds = 5 ,
74 | ... library_type = "PYTHON" ,
75 | ... checkpoint_frequency = 1 ,
76 | ... )
77 | Starting session!
78 | Waiting...
79 | Session complete! Check dashboard for final model!
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
114 |
115 |
116 |
132 |
136 |
137 |
--------------------------------------------------------------------------------
/explora/docs/build/html/modules.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | explora — explora-dataagora 1.0.0 documentation
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
38 |
39 |
86 |
104 |
108 |
109 |
--------------------------------------------------------------------------------
/explora/docs/build/html/objects.inv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DiscreetAI/explora/36a0c05181530a5103109a1f5d0458ea64c26ca9/explora/docs/build/html/objects.inv
--------------------------------------------------------------------------------
/explora/docs/build/html/py-modindex.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Python Module Index — explora-dataagora 1.0.0 documentation
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
24 |
25 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
Python Module Index
45 |
46 |
49 |
50 |
51 |
52 |
53 | m
54 |
55 |
56 |
57 | main
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
79 |
80 |
81 |
93 |
97 |
98 |
--------------------------------------------------------------------------------
/explora/docs/build/html/search.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Search — explora-dataagora 1.0.0 documentation
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
Search
42 |
43 |
44 |
45 | Please activate JavaScript to enable the search
46 | functionality.
47 |
48 |
49 |
50 | From here you can search these documents. Enter your search
51 | words into the box below and click "search". Note that the search
52 | function will automatically search for all of the words. Pages
53 | containing fewer words won't appear in the result list.
54 |
55 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
72 |
73 |
74 |
86 |
90 |
91 |
--------------------------------------------------------------------------------
/explora/docs/build/html/searchindex.js:
--------------------------------------------------------------------------------
1 | Search.setIndex({docnames:["index","main","modules"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,sphinx:56},filenames:["index.rst","main.rst","modules.rst"],objects:{"":{main:[1,0,0,"-"]},main:{start_new_session:[1,1,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:function"},terms:{"4c89":1,"final":1,"float":1,"int":1,"new":1,The:1,argument:1,associ:1,async:1,averag:1,bafb:1,batch_siz:1,befor:1,c9bf9e57:1,call:1,check:1,checkpoint_frequ:1,compil:1,complet:1,configur:1,content:0,current:1,custom:0,dashboard:1,dataset:1,decentr:0,design:1,dict:1,dure:1,either:1,engin:1,everi:1,exampl:1,explora:1,ff5af830be8a:1,given:1,hyperparam:1,hyperparamet:1,includ:1,index:0,initi:1,ipynb:1,javascript:1,jupyt:0,kera:1,librari:1,library_typ:1,load_model:1,main:[0,2],max_round:1,maximum:1,messag:1,model:1,modul:[0,2],move:1,must:1,next:1,node:1,notebook:0,number:1,page:0,paramet:1,percentag:1,percentage_averag:1,python:1,repo:1,repo_id:1,round:1,save:1,search:0,self:1,send:1,server:1,session:[0,1],start:[0,1],start_new_sess:1,str:1,train:[0,1],type:1,used:[0,1],valid:1,wait:1},titles:["Welcome to explora\u2019s documentation!","main module","explora"],titleterms:{document:0,explora:[0,2],indic:0,main:1,modul:1,tabl:0,welcom:0}})
--------------------------------------------------------------------------------
/explora/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=source
11 | set BUILDDIR=build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/explora/docs/readthedocs.yml:
--------------------------------------------------------------------------------
1 | python:
2 | version: 3.6
3 | install:
4 | - requirements: docs/requirements.txt
5 | - method: pip
6 | path: .
7 | extra_requirements:
8 | - docs
9 | - method: setuptools
10 | path: another/package
11 | system_packages: true
--------------------------------------------------------------------------------
/explora/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | absl-py==0.8.1
2 | alabaster==0.7.12
3 | appnope==0.1.0
4 | asn1crypto==1.0.1
5 | astor==0.8.0
6 | asyncio==3.4.3
7 | attrs==19.2.0
8 | Automat==0.7.0
9 | Babel==2.7.0
10 | backcall==0.1.0
11 | bleach==3.1.0
12 | certifi==2019.9.11
13 | cffi==1.12.3
14 | chardet==3.0.4
15 | commonmark==0.9.1
16 | constantly==15.1.0
17 | coremltools==3.1
18 | cryptography==2.7
19 | decorator==4.4.0
20 | defusedxml==0.6.0
21 | docutils==0.15.2
22 | entrypoints==0.3
23 | gast==0.2.2
24 | google-pasta==0.1.7
25 | grpcio==1.24.1
26 | h5py==2.10.0
27 | hyperlink==19.0.0
28 | idna==2.8
29 | imagesize==1.1.0
30 | importlib-metadata==0.23
31 | incremental==17.5.0
32 | intel-openmp==2019.0
33 | ipykernel==5.1.2
34 | ipython==7.8.0
35 | ipython-genutils==0.2.0
36 | ipywidgets==7.5.1
37 | jedi==0.15.1
38 | Jinja2==2.10.3
39 | jsonschema==3.1.1
40 | jupyter==1.0.0
41 | jupyter-client==5.3.4
42 | jupyter-console==6.0.0
43 | jupyter-core==4.6.0
44 | Keras==2.3.1
45 | Keras-Applications==1.0.8
46 | Keras-Preprocessing==1.1.0
47 | Markdown==3.1.1
48 | MarkupSafe==1.1.1
49 | mistune==0.8.4
50 | more-itertools==7.2.0
51 | nbconvert==5.6.0
52 | nbformat==4.4.0
53 | notebook==6.0.1
54 | numpy==1.17.2
55 | opt-einsum==3.1.0
56 | packaging==19.2
57 | pandocfilters==1.4.2
58 | parso==0.5.1
59 | pexpect==4.7.0
60 | pickleshare==0.7.5
61 | prometheus-client==0.7.1
62 | prompt-toolkit==2.0.10
63 | protobuf==3.10.0
64 | ptyprocess==0.6.0
65 | pyasn1==0.4.7
66 | pyasn1-modules==0.2.7
67 | pycparser==2.19
68 | Pygments==2.4.2
69 | PyHamcrest==1.9.0
70 | pyparsing==2.4.5
71 | pyrsistent==0.15.4
72 | python-dateutil==2.8.0
73 | pytz==2019.3
74 | PyYAML==5.1.2
75 | pyzmq==18.1.0
76 | qtconsole==4.5.5
77 | recommonmark==0.6.0
78 | requests==2.22.0
79 | scipy==1.3.1
80 | Send2Trash==1.5.0
81 | service-identity==18.1.0
82 | six==1.12.0
83 | snowballstemmer==2.0.0
84 | Sphinx==2.2.1
85 | sphinxcontrib-applehelp==1.0.1
86 | sphinxcontrib-devhelp==1.0.1
87 | sphinxcontrib-htmlhelp==1.0.2
88 | sphinxcontrib-jsmath==1.0.1
89 | sphinxcontrib-qthelp==1.0.2
90 | sphinxcontrib-serializinghtml==1.1.3
91 | termcolor==1.1.0
92 | terminado==0.8.2
93 | testpath==0.4.2
94 | tfcoreml==1.1
95 | tornado==6.0.3
96 | traitlets==4.3.3
97 | txaio==18.8.1
98 | urllib3==1.25.7
99 | wcwidth==0.1.7
100 | webencodings==0.5.1
101 | websockets==8.0.2
102 | Werkzeug==0.16.0
103 | widgetsnbextension==3.5.1
104 | wrapt==1.11.2
105 | zipp==0.6.0
106 | zope.interface==4.6.0
107 |
--------------------------------------------------------------------------------
/explora/docs/source/conf.py:
--------------------------------------------------------------------------------
1 | # Configuration file for the Sphinx documentation builder.
2 | #
3 | # This file only contains a selection of the most common options. For a full
4 | # list see the documentation:
5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html
6 |
7 | # -- Path setup --------------------------------------------------------------
8 |
9 | # If extensions (or modules to document with autodoc) are in another directory,
10 | # add these directories to sys.path here. If the directory is relative to the
11 | # documentation root, use os.path.abspath to make it absolute, like shown here.
12 | #
13 | import os
14 | import sys
15 | sys.path.insert(0, os.path.abspath('../..'))
16 |
17 |
18 | # -- Project information -----------------------------------------------------
19 |
20 | project = 'explora-dataagora'
21 | copyright = '2019, Neelesh Dodda'
22 | author = 'Neelesh Dodda'
23 |
24 | # The full version, including alpha/beta/rc tags
25 | release = '1.0.0'
26 |
27 |
28 | # -- General configuration ---------------------------------------------------
29 |
30 | # Add any Sphinx extension module names here, as strings. They can be
31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
32 | # ones.
33 | extensions = [
34 | 'sphinx.ext.autodoc',
35 | 'sphinx.ext.napoleon',
36 | ]
37 |
38 | # Add any paths that contain templates here, relative to this directory.
39 | templates_path = ['_templates']
40 |
41 | # List of patterns, relative to source directory, that match files and
42 | # directories to ignore when looking for source files.
43 | # This pattern also affects html_static_path and html_extra_path.
44 | exclude_patterns = []
45 |
46 |
47 | # -- Options for HTML output -------------------------------------------------
48 |
49 | # The theme to use for HTML and HTML Help pages. See the documentation for
50 | # a list of builtin themes.
51 | #
52 | html_theme = 'nature'
53 |
54 | # Add any paths that contain custom static files (such as style sheets) here,
55 | # relative to this directory. They are copied after the builtin static files,
56 | # so a file named "default.css" will overwrite the builtin "default.css".
57 | html_static_path = ['_static']
--------------------------------------------------------------------------------
/explora/docs/source/index.rst:
--------------------------------------------------------------------------------
1 | .. explora documentation master file, created by
2 | sphinx-quickstart on Tue Nov 19 15:38:31 2019.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to explora's documentation!
7 | ===================================
8 |
9 | Explora is a customized Jupyter Notebook used for starting decentralized training sessions.
10 |
11 | .. toctree::
12 | :maxdepth: 2
13 | :caption: Contents:
14 |
15 | modules
16 |
17 |
18 |
19 | Indices and tables
20 | ==================
21 |
22 | * :ref:`genindex`
23 | * :ref:`modindex`
24 | * :ref:`search`
25 |
--------------------------------------------------------------------------------
/explora/docs/source/main.rst:
--------------------------------------------------------------------------------
1 | main module
2 | ===========
3 |
4 | .. automodule:: main
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/explora/docs/source/modules.rst:
--------------------------------------------------------------------------------
1 | explora
2 | =======
3 |
4 | .. toctree::
5 | :maxdepth: 4
6 |
7 | main
8 |
--------------------------------------------------------------------------------
/explora/environment.yml:
--------------------------------------------------------------------------------
1 | name: explora-env
2 | channels:
3 | - defaults
4 | dependencies:
5 | - _tflow_select=2.3.0=mkl
6 | - appnope=0.1.0=py36hf537a9a_0
7 | - asn1crypto=1.0.1=py36_0
8 | - astor=0.8.0=py36_0
9 | - attrs=19.2.0=py_0
10 | - automat=0.7.0=py36_0
11 | - backcall=0.1.0=py36_0
12 | - blas=1.0=mkl
13 | - bleach=3.1.0=py36_0
14 | - c-ares=1.15.0=h1de35cc_1001
15 | - ca-certificates=2019.10.16=0
16 | - certifi=2019.9.11=py36_0
17 | - cffi=1.12.3=py36hb5b8e2f_0
18 | - constantly=15.1.0=py36h28b3542_0
19 | - cryptography=2.7=py36ha12b0ac_0
20 | - dbus=1.13.12=h90a0687_0
21 | - decorator=4.4.0=py36_1
22 | - defusedxml=0.6.0=py_0
23 | - entrypoints=0.3=py36_0
24 | - expat=2.2.6=h0a44026_0
25 | - gast=0.2.2=py36_0
26 | - gettext=0.19.8.1=h15daf44_3
27 | - glib=2.56.2=hd9629dc_0
28 | - google-pasta=0.1.7=py_0
29 | - hdf5=1.10.4=hfa1e0ec_0
30 | - hyperlink=19.0.0=py_0
31 | - icu=58.2=h4b95b61_1
32 | - idna=2.8=py36_0
33 | - importlib_metadata=0.23=py36_0
34 | - incremental=17.5.0=py36_0
35 | - intel-openmp=2019.4=233
36 | - ipykernel=5.1.2=py36h39e3cac_0
37 | - ipython=7.8.0=py36h39e3cac_0
38 | - ipython_genutils=0.2.0=py36h241746c_0
39 | - ipywidgets=7.5.1=py_0
40 | - jedi=0.15.1=py36_0
41 | - jinja2=2.10.3=py_0
42 | - jpeg=9b=he5867d9_2
43 | - jsonschema=3.1.1=py36_0
44 | - jupyter=1.0.0=py36_7
45 | - jupyter_client=5.3.4=py36_0
46 | - jupyter_console=6.0.0=py36_0
47 | - jupyter_core=4.6.0=py36_0
48 | - keras-applications=1.0.8=py_0
49 | - keras-preprocessing=1.1.0=py_1
50 | - libcxx=4.0.1=hcfea43d_1
51 | - libcxxabi=4.0.1=hcfea43d_1
52 | - libedit=3.1.20181209=hb402a30_0
53 | - libffi=3.2.1=h475c297_4
54 | - libgfortran=3.0.1=h93005f0_2
55 | - libiconv=1.15=hdd342a3_7
56 | - libpng=1.6.37=ha441bb4_0
57 | - libprotobuf=3.9.2=hd9629dc_0
58 | - libsodium=1.0.16=h3efe00b_0
59 | - markdown=3.1.1=py36_0
60 | - markupsafe=1.1.1=py36h1de35cc_0
61 | - mistune=0.8.4=py36h1de35cc_0
62 | - mkl=2019.4=233
63 | - mkl-service=2.3.0=py36hfbe908c_0
64 | - mkl_fft=1.0.14=py36h5e564d8_0
65 | - mkl_random=1.1.0=py36ha771720_0
66 | - more-itertools=7.2.0=py36_0
67 | - nbconvert=5.6.0=py36_1
68 | - nbformat=4.4.0=py36h827af21_0
69 | - ncurses=6.1=h0a44026_1
70 | - notebook=6.0.1=py36_0
71 | - numpy=1.17.2=py36h99e6662_0
72 | - numpy-base=1.17.2=py36h6575580_0
73 | - openssl=1.1.1d=h1de35cc_3
74 | - opt_einsum=3.1.0=py_0
75 | - pandoc=2.2.3.2=0
76 | - pandocfilters=1.4.2=py36_1
77 | - parso=0.5.1=py_0
78 | - pcre=8.43=h0a44026_0
79 | - pexpect=4.7.0=py36_0
80 | - pickleshare=0.7.5=py36_0
81 | - pip=19.3.1=py36_0
82 | - prometheus_client=0.7.1=py_0
83 | - prompt_toolkit=2.0.10=py_0
84 | - ptyprocess=0.6.0=py36_0
85 | - pyasn1=0.4.7=py_0
86 | - pycparser=2.19=py36_0
87 | - pygments=2.4.2=py_0
88 | - pyhamcrest=1.9.0=py36_2
89 | - pyqt=5.9.2=py36h655552a_2
90 | - pyrsistent=0.15.4=py36h1de35cc_0
91 | - python=3.6.9=h359304d_0
92 | - python-dateutil=2.8.0=py36_0
93 | - pyyaml=5.1.2=py36h1de35cc_0
94 | - pyzmq=18.1.0=py36h0a44026_0
95 | - qt=5.9.7=h468cd18_1
96 | - qtconsole=4.5.5=py_0
97 | - readline=7.0=h1de35cc_5
98 | - scipy=1.3.1=py36h1410ff5_0
99 | - send2trash=1.5.0=py36_0
100 | - setuptools=41.4.0=py36_0
101 | - sip=4.19.8=py36h0a44026_0
102 | - six=1.12.0=py36_0
103 | - sqlite=3.30.1=ha441bb4_0
104 | - tensorboard=2.0.0=pyhb230dea_0
105 | - tensorflow=2.0.0=mkl_py36ha38f243_0
106 | - tensorflow-base=2.0.0=mkl_py36h66b1bf0_0
107 | - tensorflow-estimator=2.0.0=pyh2649769_0
108 | - termcolor=1.1.0=py36_1
109 | - terminado=0.8.2=py36_0
110 | - testpath=0.4.2=py36_0
111 | - tk=8.6.8=ha441bb4_0
112 | - tornado=6.0.3=py36h1de35cc_0
113 | - traitlets=4.3.3=py36_0
114 | - wcwidth=0.1.7=py36h8c6ec74_0
115 | - webencodings=0.5.1=py36_1
116 | - werkzeug=0.16.0=py_0
117 | - wheel=0.33.6=py36_0
118 | - widgetsnbextension=3.5.1=py36_0
119 | - wrapt=1.11.2=py36h1de35cc_0
120 | - xz=5.2.4=h1de35cc_4
121 | - yaml=0.1.7=hc338f04_2
122 | - zeromq=4.3.1=h0a44026_3
123 | - zipp=0.6.0=py_0
124 | - zlib=1.2.11=h1de35cc_3
125 | - zope=1.0=py36_1
126 | - zope.interface=4.6.0=py36h1de35cc_0
127 | - pip:
128 | - absl-py==0.8.1
129 | - grpcio==1.24.1
130 | - h5py==2.10.0
131 | - keras==2.3.1
132 | - protobuf==3.10.0
133 | - pyasn1-modules==0.2.7
134 | - service-identity==18.1.0
135 | - txaio==18.8.1
136 | - websockets==8.0.2
137 | prefix: /Users/ndodda/opt/anaconda3/envs/explora-env
138 |
139 |
--------------------------------------------------------------------------------
/explora/images/DA_nowords.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DiscreetAI/explora/36a0c05181530a5103109a1f5d0458ea64c26ca9/explora/images/DA_nowords.png
--------------------------------------------------------------------------------
/explora/main.py:
--------------------------------------------------------------------------------
1 | from utils.validation import validate_repo_id, validate_model, \
2 | validate_and_prepare_hyperparameters, validate_percentage_averaged, \
3 | validate_max_rounds, validate_library_type, \
4 | validate_checkpoint_frequency
5 | from utils.keras_utils import get_h5_model
6 | from utils.websocket_utils import connect
7 |
8 |
9 | async def start_new_session(self, repo_id, model, hyperparameters, \
10 | percentage_averaged=0.75, max_rounds=5, library_type="PYTHON", \
11 | checkpoint_frequency=1):
12 | """
13 | Validate arguments and then start a new session by sending a message to
14 | the server with the given configuration. Designed to be called in
15 | `Explora.ipynb`.
16 |
17 | Args:
18 | repo_id (str): The repo ID associated with the current dataset.
19 | model (keras.engine.Model): The initial Keras model to train with. The
20 | model must be compiled!
21 | hyperparams (dict): The hyperparameters to be used during training.
22 | Must include `batch_size`!
23 | percentage_averaged (float): Percentage of nodes to be averaged before
24 | moving on to the next round.
25 | max_rounds (int): Maximum number of rounds to train for.
26 | library_type (str): The type of library to train with. Must be either
27 | `PYTHON` or `JAVASCRIPT`.
28 | checkpoint_frequency (int): Save the model in S3 every
29 | `checkpoint_frequency` rounds.
30 |
31 | Examples:
32 | >>> start_new_session(
33 | ... repo_id="c9bf9e57-1685-4c89-bafb-ff5af830be8a",
34 | ... model=keras.models.load_model("model.h5"),
35 | ... hyperparameters={"batch_size": 100},
36 | ... percentage_averaged=0.75,
37 | ... max_rounds=5,
38 | ... library_type="PYTHON",
39 | ... checkpoint_frequency=1,
40 | ... )
41 | Starting session!
42 | Waiting...
43 | Session complete! Check dashboard for final model!
44 | """
45 | cloud_node_host = 'ws://' + repo_id + self.CLOUD_BASE_URL
46 |
47 | if not validate_repo_id(repo_id):
48 | print("Repo ID is not in a valid format!")
49 | return
50 |
51 | if not validate_model(model):
52 | print("Provided model is not a Keras model!")
53 | return
54 |
55 | if not validate_and_prepare_hyperparameters(hyperparameters):
56 | print("Hyperparameters must include batch size!")
57 | return
58 |
59 | if not validate_percentage_averaged(percentage_averaged):
60 | print("Percentage averaged must be float and between 0 and 1!")
61 | return
62 |
63 | if not validate_max_rounds(max_rounds):
64 | print("Max rounds must be int and at least 1!")
65 | return
66 |
67 | if not validate_library_type(library_type):
68 | print("Library type must be either PYTHON or JAVASCRIPT")
69 | return
70 |
71 | if not validate_checkpoint_frequency(checkpoint_frequency):
72 | print("Checkpoint frequency must be int and between 0 and max rounds!")
73 | return
74 |
75 | new_message = {
76 | "type": "NEW_SESSION",
77 | "repo_id": repo_id,
78 | "h5_model": h5_model,
79 | "hyperparams": hyperparams,
80 | "checkpoint_frequency": checkpoint_frequency,
81 | "selection_criteria": {
82 | "type": "ALL_NODES",
83 | },
84 | "continuation_criteria": {
85 | "type": "PERCENTAGE_AVERAGED",
86 | "value": percentage_averaged
87 | },
88 | "termination_criteria": {
89 | "type": "MAX_ROUND",
90 | "value": max_rounds
91 | },
92 | "library_type": library_type
93 | }
94 |
95 | await self._connect(new_message)
--------------------------------------------------------------------------------
/explora/model/my_model.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DiscreetAI/explora/36a0c05181530a5103109a1f5d0458ea64c26ca9/explora/model/my_model.h5
--------------------------------------------------------------------------------
/explora/model/my_model.mlmodel:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DiscreetAI/explora/36a0c05181530a5103109a1f5d0458ea64c26ca9/explora/model/my_model.mlmodel
--------------------------------------------------------------------------------
/explora/model/my_model2.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DiscreetAI/explora/36a0c05181530a5103109a1f5d0458ea64c26ca9/explora/model/my_model2.h5
--------------------------------------------------------------------------------
/explora/requirements.txt:
--------------------------------------------------------------------------------
1 | absl-py==0.8.1
2 | alabaster==0.7.12
3 | appnope==0.1.0
4 | asn1crypto==1.0.1
5 | astor==0.8.0
6 | asyncio==3.4.3
7 | attrs==19.2.0
8 | Automat==0.7.0
9 | Babel==2.7.0
10 | backcall==0.1.0
11 | bleach==3.1.0
12 | certifi==2019.9.11
13 | cffi==1.12.3
14 | chardet==3.0.4
15 | commonmark==0.9.1
16 | constantly==15.1.0
17 | coremltools==3.1
18 | cryptography==2.7
19 | decorator==4.4.0
20 | defusedxml==0.6.0
21 | docutils==0.15.2
22 | entrypoints==0.3
23 | gast==0.2.2
24 | google-pasta==0.1.7
25 | grpcio==1.24.1
26 | h5py==2.10.0
27 | hyperlink==19.0.0
28 | idna==2.8
29 | imagesize==1.1.0
30 | importlib-metadata==0.23
31 | incremental==17.5.0
32 | intel-openmp==2019.0
33 | ipykernel==5.1.2
34 | ipython==7.8.0
35 | ipython-genutils==0.2.0
36 | ipywidgets==7.5.1
37 | jedi==0.15.1
38 | Jinja2==2.10.3
39 | jsonschema==3.1.1
40 | jupyter==1.0.0
41 | jupyter-client==5.3.4
42 | jupyter-console==6.0.0
43 | jupyter-core==4.6.0
44 | Keras==2.3.1
45 | Keras-Applications==1.0.8
46 | Keras-Preprocessing==1.1.0
47 | Markdown==3.1.1
48 | MarkupSafe==1.1.1
49 | mistune==0.8.4
50 | more-itertools==7.2.0
51 | nbconvert==5.6.0
52 | nbformat==4.4.0
53 | notebook==6.0.1
54 | numpy==1.17.2
55 | opt-einsum==3.1.0
56 | packaging==19.2
57 | pandocfilters==1.4.2
58 | parso==0.5.1
59 | pexpect==4.7.0
60 | pickleshare==0.7.5
61 | prometheus-client==0.7.1
62 | prompt-toolkit==2.0.10
63 | protobuf==3.10.0
64 | ptyprocess==0.6.0
65 | pyasn1==0.4.7
66 | pyasn1-modules==0.2.7
67 | pycparser==2.19
68 | Pygments==2.4.2
69 | PyHamcrest==1.9.0
70 | pyparsing==2.4.5
71 | pyrsistent==0.15.4
72 | python-dateutil==2.8.0
73 | pytz==2019.3
74 | PyYAML==5.1.2
75 | pyzmq==18.1.0
76 | qtconsole==4.5.5
77 | recommonmark==0.6.0
78 | requests==2.22.0
79 | scipy==1.3.1
80 | Send2Trash==1.5.0
81 | service-identity==18.1.0
82 | six==1.12.0
83 | snowballstemmer==2.0.0
84 | Sphinx==2.2.1
85 | sphinxcontrib-applehelp==1.0.1
86 | sphinxcontrib-devhelp==1.0.1
87 | sphinxcontrib-htmlhelp==1.0.2
88 | sphinxcontrib-jsmath==1.0.1
89 | sphinxcontrib-qthelp==1.0.2
90 | sphinxcontrib-serializinghtml==1.1.3
91 | tensorboard==1.15.0
92 | tensorflow==1.15.0
93 | tensorflow-estimator==1.15.1
94 | termcolor==1.1.0
95 | terminado==0.8.2
96 | testpath==0.4.2
97 | tfcoreml==1.1
98 | tornado==6.0.3
99 | traitlets==4.3.3
100 | txaio==18.8.1
101 | urllib3==1.25.7
102 | wcwidth==0.1.7
103 | webencodings==0.5.1
104 | websockets==8.0.2
105 | Werkzeug==0.16.0
106 | widgetsnbextension==3.5.1
107 | wrapt==1.11.2
108 | zipp==0.6.0
109 | zope.interface==4.6.0
110 |
--------------------------------------------------------------------------------
/explora/utils/keras_utils.py:
--------------------------------------------------------------------------------
1 | import base64
2 |
3 | import keras
4 |
5 |
6 | def get_h5_model(model):
7 | """
8 | Saves a Keras model as an .h5 file and then reads the file as a string
9 | so that it can be transmitted to the server via WebSocket
10 | Args:
11 | model (keras.engine.Model): The model to be converted
12 | Returns:
13 | str: A string that represents the Keras model
14 | """
15 | model.save("core/model/my_model.h5")
16 | with open("core/model/my_model.h5", mode='rb') as file:
17 | file_content = file.read()
18 | encoded_content = base64.b64encode(file_content)
19 | h5_model = encoded_content.decode('ascii')
20 | return h5_model
--------------------------------------------------------------------------------
/explora/utils/validation.py:
--------------------------------------------------------------------------------
1 | import uuid
2 |
3 | def validate_repo_id(repo_id):
4 | """
5 | Check that repo ID is in the uuid4 format.
6 | Args:
7 | repo_id (str): The repo ID associated with the current dataset.
8 | Returns:
9 | bool: True if in valid format, False otherwise
10 | """
11 | try:
12 | uuid_obj = uuid.UUID(repo_id, version=4)
13 | except ValueError:
14 | return False
15 |
16 | return str(uuid_obj) == repo_id
17 |
18 | def validate_model(model):
19 | """
20 | Check that the model is a Keras model and is compiled.
21 | Args:
22 | model (keras.engine.Model): The initial Keras model to train with. The
23 | model must be compiled!
24 | Returns:
25 | bool: True if Keras model and compiled, False otherwise
26 | """
27 | return isinstance(model, keras.engine.Model) and model.optimizer
28 |
29 | def validate_and_prepare_hyperparameters(hyperparams):
30 | """
31 | Check that hyperparams has `batch_size` entry and that it is an
32 | appropriate number. Then add default entries for `epochs` and `shuffle`.
33 | Args:
34 | hyperparams (dict): The hyperparameters to be used during training.
35 | Must include `batch_size`!
36 | """
37 | if not isinstance(hyperparams, dict) \
38 | or hyperparams.get('batch_size', 0) < 1:
39 | return False
40 | hyperparams['epochs'] = hyperparams.get('epochs', 5)
41 | hyperparams['shuffle'] = hyperparams.get('shuffle', True)
42 | return True
43 |
44 | def validate_percentage_averaged(percentage_averaged):
45 | """
46 | Check that percentage averaged is float and between 0 and 1.
47 | Args:
48 | percentage_averaged (float): Percentage of nodes to be averaged before
49 | moving on to the next round.
50 | """
51 | return isinstance(percentage_averaged, float) \
52 | and percentage_averaged > 0 \
53 | and percentage_averaged < 1
54 |
55 | def validate_max_rounds(max_rounds):
56 | """
57 | Check that max rounds is int and at least 1.
58 | Args:
59 | max_rounds (int): Maximum number of rounds to train for.
60 | """
61 | return isinstance(max_rounds, int) and max_rounds >= 1
62 |
63 | def validate_library_type(library_type):
64 | """
65 | Check that library_type is PYTHON or JAVASCRIPT.
66 | Args:
67 | library_type (str): The type of library to train with. Must be either
68 | `PYTHON` or `JAVASCRIPT`.
69 | """
70 | return library_type in ("PYTHON", "JAVASCRIPT")
71 |
72 | def validate_checkpoint_frequency(checkpoint_frequency):
73 | """
74 | Check that checkpoint frequency is int and between 0 and max rounds.
75 | Args:
76 | checkpoint_frequency (int): Save the model in S3 every
77 | `checkpoint_frequency` rounds.
78 | """
79 | return isinstance(checkpoint_frequency, int) \
80 | and checkpoint_frequency >= 1 \
81 | and checkpoint_frequency <= max_rounds
--------------------------------------------------------------------------------
/explora/utils/websocket_utils.py:
--------------------------------------------------------------------------------
1 | import json
2 | import socket
3 |
4 | from websockets import connect
5 |
6 |
7 | CLOUD_BASE_URL = ".au4c4pd2ch.us-west-1.elasticbeanstalk.com"
8 |
9 | NEW_CONNECTION_MESSAGE = {
10 | "type": "REGISTER",
11 | "node_type": "dashboard",
12 | }
13 |
14 | async def connect(self, cloud_node_host, new_message, max_size=2**22, \
15 | num_reconnections=3):
16 | """
17 | Connect to server, register and start new session.
18 | Args:
19 | cloud_node_host (str): Server to connect to.
20 | new_message (dict): New session message to be sent to server.
21 | max_size (int): Maximum size in bytes for websocket transmission.
22 | num_reconnections (int): Number of consecutive reconnections allowed
23 | for some arbitrary failure to connect.
24 | """
25 | while True:
26 | try:
27 | async with connect(cloud_node_host, max_size=2**22) as websocket:
28 | print("Starting session!\nWaiting...")
29 | await websocket.send(json.dumps(NEW_CONNECTION_MESSAGE))
30 | await websocket.send(json.dumps(new_message))
31 | response = await websocket.recv()
32 | json_response = json.loads(response)
33 | if json_response.get("action", None) == 'STOP':
34 | print("Session complete! Check dashboard for final model!")
35 | else:
36 | print("Unknown response received:")
37 | print(json_response)
38 | print("Stopping...")
39 | return
40 | except socket.gaierror as e:
41 | print("Server not found!")
42 | except:
43 | num_reconnections -= 1
44 | if not num_reconnections:
45 | print("Failed to connect!")
46 | return
--------------------------------------------------------------------------------