├── .drone.yml ├── .editorconfig ├── .gitignore ├── README.md ├── jupyterlab_dotscience ├── .gitignore ├── README.md ├── package-docker.json ├── package-host.json ├── package-lock.json ├── package.json ├── src │ └── index.ts ├── style │ └── index.css └── tsconfig.json ├── jupyterlab_dotscience_backend ├── .bumpversion.cfg ├── .gitattributes ├── MANIFEST.in ├── README.md ├── jupyterlab_dotscience_backend │ ├── README.md │ └── __init__.py ├── setup.cfg └── setup.py ├── package.json ├── renovate.json └── scripts └── release.sh /.drone.yml: -------------------------------------------------------------------------------- 1 | kind: pipeline 2 | name: default 3 | 4 | steps: 5 | # don't have any tests yet so just check it builds 6 | - name: install 7 | image: python:3.8.0-alpine3.10 8 | commands: 9 | - cd jupyterlab_dotscience_backend && pip install -e . 10 | # ideally we'd use the drone plugin, but that won't work until 11 | # https://github.com/drone-plugins/drone-pypi/issues/23 is fixed. 12 | - name: pypi_publish 13 | image: python:3.8.0-slim-buster 14 | depends_on: 15 | - install 16 | when: 17 | event: [ tag ] 18 | environment: 19 | TWINE_USERNAME: 20 | from_secret: pypi_username 21 | TWINE_PASSWORD: 22 | from_secret: pypi_password 23 | commands: 24 | - python -m venv /tmp/venv 25 | - cd jupyterlab_dotscience_backend 26 | - /tmp/venv/bin/pip install twine setuptools wheel 27 | - /tmp/venv/bin/python setup.py sdist bdist_wheel 28 | - /tmp/venv/bin/twine upload dist/* 29 | - name: npm_build 30 | image: node:10-alpine 31 | commands: 32 | - cd jupyterlab_dotscience 33 | - npm install 34 | - npm run build 35 | - name: npm 36 | image: plugins/npm 37 | when: 38 | event: [ tag ] 39 | depends_on: 40 | - npm_build 41 | settings: 42 | token: 43 | from_secret: npm_token 44 | folder: jupyterlab_dotscience 45 | - name: slack 46 | image: plugins/slack 47 | when: 48 | event: [ push, pull_request ] 49 | status: [ success, failure ] 50 | depends_on: 51 | - install 52 | settings: 53 | webhook: 54 | from_secret: slack_url 55 | channel: ci 56 | username: drone 57 | icon_url: https://i.pinimg.com/originals/51/29/a4/5129a48ddad9e8408d2757dd10eb836f.jpg 58 | - name: slack-tag 59 | image: plugins/slack 60 | when: 61 | event: [ tag ] 62 | status: [ success, failure ] 63 | depends_on: 64 | - npm 65 | - pypi_publish 66 | settings: 67 | webhook: 68 | from_secret: slack_url 69 | channel: ci 70 | username: drone 71 | icon_url: https://i.pinimg.com/originals/51/29/a4/5129a48ddad9e8408d2757dd10eb836f.jpg 72 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.ts] 2 | indent_size = 2 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.bundle.* 2 | lib/ 3 | node_modules/ 4 | *.egg-info/ 5 | .ipynb_checkpoints 6 | **/__pycache__ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jupyterlab-dotscience plugin 2 | 3 | A JupyterLab extension which enables data & model versioning and summary statistics tracking. 4 | 5 | See [dotscience](https://dotscience.com) for more details. 6 | 7 | ## Deployment 8 | This plugin is in two parts - the frontend and the backend. 9 | The frontend is deployed to npm, the backend to pypi. 10 | 11 | To deploy the components automatically you should generally just follow: 12 | ``` 13 | pip3 install bump2version # if you don't have this installed already 14 | ./scripts/release.sh $VERSION 15 | ``` 16 | 17 | This will release itself using drone, then later renovate should pick up the change from npm/pypi and suggest a pull request on the `jupyterlab-tensorflow` repo. You can override this by doing that PR manually. 18 | 19 | If you for any reason need to manually deploy to only npm and pypi, you need to have the following variables in your environment: 20 | 21 | | Name | Example | Description | 22 | |-------------------------- |--------------------- |--------------------- | 23 | | `PYPI_USER` | fred | the username we use to access pypi. Should be in gitlab-ci. | 24 | | `PYPI_PASSWORD` | passw0rd | the password for pypi | 25 | | `NPM_TOKEN` | something-separated-by-dashes | the token for npm. Get it from gitlab-ci or set up your own account and ping Charlotte to add you | 26 | | `CI_COMMIT_TAG` | 0.0.5 | the version to use when releasing the npm package. This should match to a tag in git - if you don't match them then the versions may differ between what's released on pypi and what's released on npm, as the pypi release process pulls the tag from git. Also note this _must_ be a semantic version, otherwise the release will fail :/ | 27 | 28 | then run 29 | ``` 30 | ./shipit-pypi.sh -u $PYPI_USER -p $PYPI_PASSWORD 31 | ./shipit-npm.sh $NPM_TOKEN 32 | ``` 33 | 34 | You will then need to trigger the docker image repo manually if necessary (see `.gitlab-ci.yml`) 35 | 36 | 37 | # Run Jupyter lab on your host 38 | 39 | ``` 40 | source ~/miniconda/bin/activate jupyterlab-ext 41 | jupyter lab --watch 42 | ``` 43 | 44 | # installing backend 45 | 46 | To install the backend, assuming you've followed the conda based setup [xkcd example](http://jupyterlab.readthedocs.io/en/stable/developer/xkcd_extension_tutorial.html): 47 | ``` 48 | conda install pip 49 | pip install -e jupyterlab_dotscience_backend 50 | jupyter serverextension enable --py jupyterlab_dotscience_backend --sys-prefix 51 | ``` 52 | 53 | [More details](http://jupyter-notebook.readthedocs.io/en/stable/examples/Notebook/Distributing%20Jupyter%20Extensions%20as%20Python%20Packages.html#Enable-a-Server-Extension) 54 | 55 | # installing frontend 56 | ``` 57 | jupyter labextension install jupyterlab_dotscience --no-build 58 | ``` 59 | 60 | ## Summary statistics 61 | 62 | For python applications look at the [dotscience-python](https://pypi.org/project/dotscience/) library. For other languages we do not yet have a library, but this [specification](https://docs.dotscience.com/references/run-metadata-format/#basic-structure) should give you some idea what is expected. 63 | -------------------------------------------------------------------------------- /jupyterlab_dotscience/.gitignore: -------------------------------------------------------------------------------- 1 | *.bundle.* 2 | lib/ 3 | node_modules/ 4 | *.egg-info/ 5 | .ipynb_checkpoints 6 | -------------------------------------------------------------------------------- /jupyterlab_dotscience/README.md: -------------------------------------------------------------------------------- 1 | # jupyterlab_dotscience 2 | 3 | A JupyterLab extension which enables data & model versioning and summary statistics tracking. 4 | 5 | 6 | ## Prerequisites 7 | 8 | * JupyterLab 9 | 10 | ## Installation 11 | 12 | ```bash 13 | jupyter labextension install jupyterlab_dotscience 14 | ``` 15 | 16 | ## Development 17 | 18 | For a development install (requires npm version 4 or later), do the following in the repository directory: 19 | 20 | ```bash 21 | npm install 22 | npm run build 23 | jupyter labextension link . 24 | ``` 25 | 26 | To rebuild the package and the JupyterLab app: 27 | 28 | ```bash 29 | npm run build 30 | jupyter lab build 31 | ``` 32 | 33 | -------------------------------------------------------------------------------- /jupyterlab_dotscience/package-docker.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jupyterlab_dotscience", 3 | "version": "0.1.0", 4 | "description": "A JupyterLab extension which enables data & model versioning and summary statistics tracking.", 5 | "keywords": [ 6 | "jupyter", 7 | "jupyterlab", 8 | "jupyterlab-extension" 9 | ], 10 | "homepage": "https://github.com/dotmesh-io/jupyterlab-plugin", 11 | "bugs": { 12 | "url": "https://github.com/dotmesh-io/jupyterlab-plugin/issues" 13 | }, 14 | "license": "BSD-3-Clause", 15 | "author": "dotmesh", 16 | "files": [ 17 | "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", 18 | "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}" 19 | ], 20 | "main": "lib/index.js", 21 | "types": "lib/index.d.ts", 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/dotmesh-io/jupyterlab-plugin.git" 25 | }, 26 | "scripts": { 27 | "build": "tsc", 28 | "clean": "rimraf lib", 29 | "watch": "tsc -w" 30 | }, 31 | "dependencies": { 32 | "@jupyterlab/application": "^0.15.4", 33 | "@jupyterlab/apputils": "^0.15.4", 34 | "@phosphor/widgets": "^1.6.0" 35 | }, 36 | "devDependencies": { 37 | "rimraf": "^2.6.1", 38 | "typescript": "~2.6.0" 39 | }, 40 | "jupyterlab": { 41 | "extension": true 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jupyterlab_dotscience/package-host.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jupyterlab_dotscience", 3 | "version": "0.1.0", 4 | "description": "A JupyterLab extension which enables data & model versioning and summary statistics tracking.", 5 | "keywords": [ 6 | "jupyter", 7 | "jupyterlab", 8 | "jupyterlab-extension" 9 | ], 10 | "homepage": "https://github.com/dotmesh-io/jupyterlab-plugin", 11 | "bugs": { 12 | "url": "https://github.com/dotmesh-io/jupyterlab-plugin/issues" 13 | }, 14 | "license": "BSD-3-Clause", 15 | "author": "dotmesh", 16 | "files": [ 17 | "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", 18 | "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}" 19 | ], 20 | "main": "lib/index.js", 21 | "types": "lib/index.d.ts", 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/dotmesh-io/jupyterlab-plugin.git" 25 | }, 26 | "scripts": { 27 | "build": "tsc", 28 | "clean": "rimraf lib", 29 | "watch": "tsc -w" 30 | }, 31 | "dependencies": { 32 | "@jupyterlab/application": "^0.16.3", 33 | "@jupyterlab/apputils": "^0.16.4", 34 | "@phosphor/widgets": "^1.6.0" 35 | }, 36 | "devDependencies": { 37 | "rimraf": "^2.6.1", 38 | "typescript": "~2.6.0" 39 | }, 40 | "jupyterlab": { 41 | "extension": true 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jupyterlab_dotscience/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dotscience/jupyterlab-plugin", 3 | "version": "0.2.30", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/runtime": { 8 | "version": "7.5.4", 9 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.4.tgz", 10 | "integrity": "sha512-Na84uwyImZZc3FKf4aUF1tysApzwf3p2yuFBIyBfbzT5glzKTdvYI4KVW4kcgjrzoGUjC7w3YyCHcJKaRxsr2Q==", 11 | "requires": { 12 | "regenerator-runtime": "^0.13.2" 13 | } 14 | }, 15 | "@blueprintjs/core": { 16 | "version": "3.17.1", 17 | "resolved": "https://registry.npmjs.org/@blueprintjs/core/-/core-3.17.1.tgz", 18 | "integrity": "sha512-VROTlhBaNaRN9kfscTQwZqRvGZmZYGfPkzcP8w50+wF/XMiK0xNEF4mRNQKXLNIduIZta5uPagZgIh68UG5dTg==", 19 | "requires": { 20 | "@blueprintjs/icons": "^3.8.0", 21 | "@types/dom4": "^2.0.1", 22 | "classnames": "^2.2", 23 | "dom4": "^2.0.1", 24 | "normalize.css": "^8.0.0", 25 | "popper.js": "^1.14.1", 26 | "react-popper": "^1.0.0", 27 | "react-transition-group": "^2.2.1", 28 | "resize-observer-polyfill": "^1.5.0", 29 | "tslib": "^1.9.0" 30 | } 31 | }, 32 | "@blueprintjs/icons": { 33 | "version": "3.9.1", 34 | "resolved": "https://registry.npmjs.org/@blueprintjs/icons/-/icons-3.9.1.tgz", 35 | "integrity": "sha512-2EU9Xot0lkztDp8xVnBi5/71jgG1Rmsfz0LycBX/T16H0qGO7i+XEbZbpJjSvmr/UzhTpxQ/Yh5XGBc2U2zG4w==", 36 | "requires": { 37 | "classnames": "^2.2", 38 | "tslib": "^1.9.0" 39 | } 40 | }, 41 | "@blueprintjs/select": { 42 | "version": "3.9.0", 43 | "resolved": "https://registry.npmjs.org/@blueprintjs/select/-/select-3.9.0.tgz", 44 | "integrity": "sha512-TmInLtGFc3My78KTmf9JUw5gawxdO7oxn3bEQDQbWPuvb/1K0u0et+dTVlwGTk9GiNopQ2NtoCj+GQ75miF9QA==", 45 | "requires": { 46 | "@blueprintjs/core": "^3.17.0", 47 | "classnames": "^2.2", 48 | "tslib": "^1.9.0" 49 | } 50 | }, 51 | "@jupyterlab/application": { 52 | "version": "1.0.1", 53 | "resolved": "https://registry.npmjs.org/@jupyterlab/application/-/application-1.0.1.tgz", 54 | "integrity": "sha512-rcEIrcjWMukeM23GZ9WJYnS1+JPYCClyfM07qhyIbDIdm7afQs6oIFegeeuo/6Or/AJ+lYMpVAW9vTpLLQluKQ==", 55 | "requires": { 56 | "@jupyterlab/apputils": "^1.0.1", 57 | "@jupyterlab/coreutils": "^3.0.0", 58 | "@jupyterlab/docregistry": "^1.0.1", 59 | "@jupyterlab/rendermime": "^1.0.1", 60 | "@jupyterlab/rendermime-interfaces": "^1.3.0", 61 | "@jupyterlab/services": "^4.0.1", 62 | "@phosphor/algorithm": "^1.1.3", 63 | "@phosphor/application": "^1.6.3", 64 | "@phosphor/commands": "^1.6.3", 65 | "@phosphor/coreutils": "^1.3.1", 66 | "@phosphor/disposable": "^1.2.0", 67 | "@phosphor/messaging": "^1.2.3", 68 | "@phosphor/properties": "^1.1.3", 69 | "@phosphor/signaling": "^1.2.3", 70 | "@phosphor/widgets": "^1.8.0", 71 | "font-awesome": "~4.7.0" 72 | } 73 | }, 74 | "@jupyterlab/apputils": { 75 | "version": "1.0.1", 76 | "resolved": "https://registry.npmjs.org/@jupyterlab/apputils/-/apputils-1.0.1.tgz", 77 | "integrity": "sha512-crY5PjndVrspFdo/k8JchaC+OU7aOYIXmYhcYGLD7uwt/G6CpZgHSEA/4YuoxulmL0mG9bu0GD19ARSROxISkQ==", 78 | "requires": { 79 | "@jupyterlab/coreutils": "^3.0.0", 80 | "@jupyterlab/services": "^4.0.1", 81 | "@jupyterlab/ui-components": "^1.0.0", 82 | "@phosphor/algorithm": "^1.1.3", 83 | "@phosphor/commands": "^1.6.3", 84 | "@phosphor/coreutils": "^1.3.1", 85 | "@phosphor/disposable": "^1.2.0", 86 | "@phosphor/domutils": "^1.1.3", 87 | "@phosphor/messaging": "^1.2.3", 88 | "@phosphor/properties": "^1.1.3", 89 | "@phosphor/signaling": "^1.2.3", 90 | "@phosphor/virtualdom": "^1.1.3", 91 | "@phosphor/widgets": "^1.8.0", 92 | "@types/react": "~16.8.18", 93 | "react": "~16.8.4", 94 | "react-dom": "~16.8.4", 95 | "sanitize-html": "~1.20.1" 96 | } 97 | }, 98 | "@jupyterlab/codeeditor": { 99 | "version": "1.0.0", 100 | "resolved": "https://registry.npmjs.org/@jupyterlab/codeeditor/-/codeeditor-1.0.0.tgz", 101 | "integrity": "sha512-unv4RmDCXsWCW+ieL8je3X6sJValYQNVoHNWA1/RD6mOydh4G9sDmCZ6WM1DboG1OHnMr6pzz0HmA/jvA/JO1w==", 102 | "requires": { 103 | "@jupyterlab/coreutils": "^3.0.0", 104 | "@jupyterlab/observables": "^2.2.0", 105 | "@phosphor/coreutils": "^1.3.1", 106 | "@phosphor/disposable": "^1.2.0", 107 | "@phosphor/dragdrop": "^1.3.3", 108 | "@phosphor/messaging": "^1.2.3", 109 | "@phosphor/signaling": "^1.2.3", 110 | "@phosphor/widgets": "^1.8.0" 111 | } 112 | }, 113 | "@jupyterlab/codemirror": { 114 | "version": "1.0.1", 115 | "resolved": "https://registry.npmjs.org/@jupyterlab/codemirror/-/codemirror-1.0.1.tgz", 116 | "integrity": "sha512-v/ncOhVA9EgDRCIT0Ry5Ze1l8VsEtC+5ewKY2Oz1cUkvfwoEFcppFPQuUxHR8K7Ib9IsbVtM6L21dG4O1XGZrg==", 117 | "requires": { 118 | "@jupyterlab/apputils": "^1.0.1", 119 | "@jupyterlab/codeeditor": "^1.0.0", 120 | "@jupyterlab/coreutils": "^3.0.0", 121 | "@jupyterlab/observables": "^2.2.0", 122 | "@jupyterlab/statusbar": "^1.0.1", 123 | "@phosphor/algorithm": "^1.1.3", 124 | "@phosphor/commands": "^1.6.3", 125 | "@phosphor/coreutils": "^1.3.1", 126 | "@phosphor/disposable": "^1.2.0", 127 | "@phosphor/signaling": "^1.2.3", 128 | "@phosphor/widgets": "^1.8.0", 129 | "codemirror": "~5.47.0", 130 | "react": "~16.8.4" 131 | } 132 | }, 133 | "@jupyterlab/coreutils": { 134 | "version": "3.0.0", 135 | "resolved": "https://registry.npmjs.org/@jupyterlab/coreutils/-/coreutils-3.0.0.tgz", 136 | "integrity": "sha512-l48G1qhff4CZpsxjje92S6caLUixzfDMAD5vjNZL9obexUAMF+344cpVWsm2r2CQROUW7bPB8wjAtFbp8nK/QQ==", 137 | "requires": { 138 | "@phosphor/commands": "^1.6.3", 139 | "@phosphor/coreutils": "^1.3.1", 140 | "@phosphor/disposable": "^1.2.0", 141 | "@phosphor/properties": "^1.1.3", 142 | "@phosphor/signaling": "^1.2.3", 143 | "ajv": "^6.5.5", 144 | "json5": "^2.1.0", 145 | "minimist": "~1.2.0", 146 | "moment": "^2.24.0", 147 | "path-posix": "~1.0.0", 148 | "url-parse": "~1.4.3" 149 | } 150 | }, 151 | "@jupyterlab/docregistry": { 152 | "version": "1.0.1", 153 | "resolved": "https://registry.npmjs.org/@jupyterlab/docregistry/-/docregistry-1.0.1.tgz", 154 | "integrity": "sha512-2BXJl2SBGSXcPN0uLEAZJs2ZdGzXTjB6/NFO2UUjRf4Ixcj6OqqX+S4ys37Yag3/5csUabcrM+/vazRFqza5xQ==", 155 | "requires": { 156 | "@jupyterlab/apputils": "^1.0.1", 157 | "@jupyterlab/codeeditor": "^1.0.0", 158 | "@jupyterlab/codemirror": "^1.0.1", 159 | "@jupyterlab/coreutils": "^3.0.0", 160 | "@jupyterlab/observables": "^2.2.0", 161 | "@jupyterlab/rendermime": "^1.0.1", 162 | "@jupyterlab/rendermime-interfaces": "^1.3.0", 163 | "@jupyterlab/services": "^4.0.1", 164 | "@phosphor/algorithm": "^1.1.3", 165 | "@phosphor/coreutils": "^1.3.1", 166 | "@phosphor/disposable": "^1.2.0", 167 | "@phosphor/messaging": "^1.2.3", 168 | "@phosphor/signaling": "^1.2.3", 169 | "@phosphor/widgets": "^1.8.0" 170 | } 171 | }, 172 | "@jupyterlab/observables": { 173 | "version": "2.2.0", 174 | "resolved": "https://registry.npmjs.org/@jupyterlab/observables/-/observables-2.2.0.tgz", 175 | "integrity": "sha512-/oi7vl70yAX5QTXmZafyDSwU8fT1Oa/MdpDDYGkc5IklW0kU3NDqSoawfLovkdgGZvCOCM+6JQqUPRdhn8VZqg==", 176 | "requires": { 177 | "@phosphor/algorithm": "^1.1.3", 178 | "@phosphor/coreutils": "^1.3.1", 179 | "@phosphor/disposable": "^1.2.0", 180 | "@phosphor/messaging": "^1.2.3", 181 | "@phosphor/signaling": "^1.2.3" 182 | } 183 | }, 184 | "@jupyterlab/rendermime": { 185 | "version": "1.0.1", 186 | "resolved": "https://registry.npmjs.org/@jupyterlab/rendermime/-/rendermime-1.0.1.tgz", 187 | "integrity": "sha512-/ZwhIZ5nbv5AqMxZj6wTpZGfdqcBkVeHcQGAKvqD9MjICw+tlziE9M6kvzlkWZ3B8aW1kLas1fXDJTtQ0HCgbQ==", 188 | "requires": { 189 | "@jupyterlab/apputils": "^1.0.1", 190 | "@jupyterlab/codemirror": "^1.0.1", 191 | "@jupyterlab/coreutils": "^3.0.0", 192 | "@jupyterlab/observables": "^2.2.0", 193 | "@jupyterlab/rendermime-interfaces": "^1.3.0", 194 | "@jupyterlab/services": "^4.0.1", 195 | "@phosphor/algorithm": "^1.1.3", 196 | "@phosphor/coreutils": "^1.3.1", 197 | "@phosphor/messaging": "^1.2.3", 198 | "@phosphor/signaling": "^1.2.3", 199 | "@phosphor/widgets": "^1.8.0", 200 | "lodash.escape": "^4.0.1", 201 | "marked": "0.6.2" 202 | } 203 | }, 204 | "@jupyterlab/rendermime-interfaces": { 205 | "version": "1.3.0", 206 | "resolved": "https://registry.npmjs.org/@jupyterlab/rendermime-interfaces/-/rendermime-interfaces-1.3.0.tgz", 207 | "integrity": "sha512-04ohT/xdTcdp/TKuNMqY1MLwh7IWyjbMrQXiuwanE8xo52fIe6OIK0DENwc6VDMej1+8NVSU7rX42urLCex0sA==", 208 | "requires": { 209 | "@phosphor/coreutils": "^1.3.1", 210 | "@phosphor/widgets": "^1.8.0" 211 | } 212 | }, 213 | "@jupyterlab/services": { 214 | "version": "4.0.1", 215 | "resolved": "https://registry.npmjs.org/@jupyterlab/services/-/services-4.0.1.tgz", 216 | "integrity": "sha512-gsErfZra65U3xh2jQu652/8mAb/LwAAYHVVybthTgZfh+ffWES04P80RDfq3nYBGIp8swXo/LFMKJEUGjaczyg==", 217 | "requires": { 218 | "@jupyterlab/coreutils": "^3.0.0", 219 | "@jupyterlab/observables": "^2.2.0", 220 | "@phosphor/algorithm": "^1.1.3", 221 | "@phosphor/coreutils": "^1.3.1", 222 | "@phosphor/disposable": "^1.2.0", 223 | "@phosphor/signaling": "^1.2.3", 224 | "node-fetch": "^2.6.0", 225 | "ws": "^7.0.0" 226 | } 227 | }, 228 | "@jupyterlab/statusbar": { 229 | "version": "1.0.1", 230 | "resolved": "https://registry.npmjs.org/@jupyterlab/statusbar/-/statusbar-1.0.1.tgz", 231 | "integrity": "sha512-cmE38ejzCaFDS5ikpHN8Ucu9YjYyXSX6omFlz9Xn3Z+ERTCBhhZ4cXYh+mKmyXPy6z5cJmHBGw9X5w7zxKEn0w==", 232 | "requires": { 233 | "@jupyterlab/apputils": "^1.0.1", 234 | "@jupyterlab/codeeditor": "^1.0.0", 235 | "@jupyterlab/coreutils": "^3.0.0", 236 | "@jupyterlab/services": "^4.0.1", 237 | "@phosphor/algorithm": "^1.1.3", 238 | "@phosphor/coreutils": "^1.3.1", 239 | "@phosphor/disposable": "^1.2.0", 240 | "@phosphor/messaging": "^1.2.3", 241 | "@phosphor/signaling": "^1.2.3", 242 | "@phosphor/widgets": "^1.8.0", 243 | "react": "~16.8.4", 244 | "typestyle": "^2.0.1" 245 | } 246 | }, 247 | "@jupyterlab/ui-components": { 248 | "version": "1.0.0", 249 | "resolved": "https://registry.npmjs.org/@jupyterlab/ui-components/-/ui-components-1.0.0.tgz", 250 | "integrity": "sha512-rR9I/wsznbuOj09gYvEWQo0fnze3ehK2dPWLY6ToE4k8qj9s39ViY48/jOoaQSaLLRaMD8M8B8ZWY0Cf+400bA==", 251 | "requires": { 252 | "@blueprintjs/core": "^3.9.0", 253 | "@blueprintjs/icons": "^3.3.0", 254 | "@blueprintjs/select": "^3.3.0", 255 | "react": "~16.8.4" 256 | } 257 | }, 258 | "@phosphor/algorithm": { 259 | "version": "1.1.3", 260 | "resolved": "https://registry.npmjs.org/@phosphor/algorithm/-/algorithm-1.1.3.tgz", 261 | "integrity": "sha512-+dkdYTBglR+qGnLVQdCvYojNZMGxf+xSl1Jeksha3pm7niQktSFz2aR5gEPu/nI5LM8T8slTpqE4Pjvq8P+IVA==" 262 | }, 263 | "@phosphor/application": { 264 | "version": "1.6.4", 265 | "resolved": "https://registry.npmjs.org/@phosphor/application/-/application-1.6.4.tgz", 266 | "integrity": "sha512-cGSC6JWxW3BmTzHRIjS8x/p3nC9IXWdeS0HiO/iZvmT6NbTEMBreEGM6No+2KWqr2VkyQ7l03cCB3h9mMeyvMw==", 267 | "requires": { 268 | "@phosphor/commands": "^1.6.3", 269 | "@phosphor/coreutils": "^1.3.1", 270 | "@phosphor/widgets": "^1.8.1" 271 | } 272 | }, 273 | "@phosphor/collections": { 274 | "version": "1.1.3", 275 | "resolved": "https://registry.npmjs.org/@phosphor/collections/-/collections-1.1.3.tgz", 276 | "integrity": "sha512-J2U1xd2e5LtqoOJt4kynrjDNeHhVpJjuY2/zA0InS5kyOuWmvy79pt/KJ22n0LBNcU/fjkImqtQmbrC2Z4q2xQ==", 277 | "requires": { 278 | "@phosphor/algorithm": "^1.1.3" 279 | } 280 | }, 281 | "@phosphor/commands": { 282 | "version": "1.6.3", 283 | "resolved": "https://registry.npmjs.org/@phosphor/commands/-/commands-1.6.3.tgz", 284 | "integrity": "sha512-PYNHWv6tbXAfAtKiqXuT0OBJvwbJ+RRTV60MBykMF7Vqz9UaZ9n2e/eB2EAGEFccF0PnjTCvBEZgarwwMVi8Hg==", 285 | "requires": { 286 | "@phosphor/algorithm": "^1.1.3", 287 | "@phosphor/coreutils": "^1.3.1", 288 | "@phosphor/disposable": "^1.2.0", 289 | "@phosphor/domutils": "^1.1.3", 290 | "@phosphor/keyboard": "^1.1.3", 291 | "@phosphor/signaling": "^1.2.3" 292 | } 293 | }, 294 | "@phosphor/coreutils": { 295 | "version": "1.3.1", 296 | "resolved": "https://registry.npmjs.org/@phosphor/coreutils/-/coreutils-1.3.1.tgz", 297 | "integrity": "sha512-9OHCn8LYRcPU/sbHm5v7viCA16Uev3gbdkwqoQqlV+EiauDHl70jmeL7XVDXdigl66Dz0LI11C99XOxp+s3zOA==" 298 | }, 299 | "@phosphor/disposable": { 300 | "version": "1.2.0", 301 | "resolved": "https://registry.npmjs.org/@phosphor/disposable/-/disposable-1.2.0.tgz", 302 | "integrity": "sha512-4PoWoffdrLyWOW5Qv7I8//owvZmv57YhaxetAMWeJl13ThXc901RprL0Gxhtue2ZxL2PtUjM1207HndKo2FVjA==", 303 | "requires": { 304 | "@phosphor/algorithm": "^1.1.3", 305 | "@phosphor/signaling": "^1.2.3" 306 | } 307 | }, 308 | "@phosphor/domutils": { 309 | "version": "1.1.3", 310 | "resolved": "https://registry.npmjs.org/@phosphor/domutils/-/domutils-1.1.3.tgz", 311 | "integrity": "sha512-5CtLAhURQXXHhNXfQydDk/luG1cDVnhlu/qw7gz8/9pht0KXIAmNg/M0LKxx2oJ9+YMNCLVWxAnHAU0yrDpWSA==" 312 | }, 313 | "@phosphor/dragdrop": { 314 | "version": "1.3.3", 315 | "resolved": "https://registry.npmjs.org/@phosphor/dragdrop/-/dragdrop-1.3.3.tgz", 316 | "integrity": "sha512-+SrlGsVQwY8OHCWxE/Zvihpk6Rc6bytJDqOUUTZqdL8hvM9QZeopAFioPDxuo1pTj87Um6cR4ekvbTU4KZ/90w==", 317 | "requires": { 318 | "@phosphor/coreutils": "^1.3.1", 319 | "@phosphor/disposable": "^1.2.0" 320 | } 321 | }, 322 | "@phosphor/keyboard": { 323 | "version": "1.1.3", 324 | "resolved": "https://registry.npmjs.org/@phosphor/keyboard/-/keyboard-1.1.3.tgz", 325 | "integrity": "sha512-dzxC/PyHiD6mXaESRy6PZTd9JeK+diwG1pyngkyUf127IXOEzubTIbu52VSdpGBklszu33ws05BAGDa4oBE4mQ==" 326 | }, 327 | "@phosphor/messaging": { 328 | "version": "1.2.3", 329 | "resolved": "https://registry.npmjs.org/@phosphor/messaging/-/messaging-1.2.3.tgz", 330 | "integrity": "sha512-89Ps4uSRNOEQoepB/0SDoyPpNUWd6VZnmbMetmeXZJHsuJ1GLxtnq3WBdl7UCVNsw3W9NC610pWaDCy/BafRlg==", 331 | "requires": { 332 | "@phosphor/algorithm": "^1.1.3", 333 | "@phosphor/collections": "^1.1.3" 334 | } 335 | }, 336 | "@phosphor/properties": { 337 | "version": "1.1.3", 338 | "resolved": "https://registry.npmjs.org/@phosphor/properties/-/properties-1.1.3.tgz", 339 | "integrity": "sha512-GiglqzU77s6+tFVt6zPq9uuyu/PLQPFcqZt914ZhJ4cN/7yNI/SLyMzpYZ56IRMXvzK9TUgbRna6URE3XAwFUg==" 340 | }, 341 | "@phosphor/signaling": { 342 | "version": "1.2.3", 343 | "resolved": "https://registry.npmjs.org/@phosphor/signaling/-/signaling-1.2.3.tgz", 344 | "integrity": "sha512-DMwS0m9OgfY5ljpTsklRQPUQpTyg4obz85FyImRDacUVxUVbas95djIDEbU4s1TMzdHBBO+gfki3V4giXUvXzw==", 345 | "requires": { 346 | "@phosphor/algorithm": "^1.1.3" 347 | } 348 | }, 349 | "@phosphor/virtualdom": { 350 | "version": "1.1.3", 351 | "resolved": "https://registry.npmjs.org/@phosphor/virtualdom/-/virtualdom-1.1.3.tgz", 352 | "integrity": "sha512-V8PHhhnZCRa5esrC4q5VthqlLtxTo9ZV1mZ6b4YEloapca1S1nggZSQhrSlltXQjtYNUaWJZUZ/BlFD8wFtIEQ==", 353 | "requires": { 354 | "@phosphor/algorithm": "^1.1.3" 355 | } 356 | }, 357 | "@phosphor/widgets": { 358 | "version": "1.8.1", 359 | "resolved": "https://registry.npmjs.org/@phosphor/widgets/-/widgets-1.8.1.tgz", 360 | "integrity": "sha512-OY5T0nAioYTitPks/lCHm7a6QpjRB/XviIT2j6WtYm5J1U8MluIPpClqZ/NQbZfm23BYpmJeiQQyZA+5YphsDA==", 361 | "requires": { 362 | "@phosphor/algorithm": "^1.1.3", 363 | "@phosphor/commands": "^1.6.3", 364 | "@phosphor/coreutils": "^1.3.1", 365 | "@phosphor/disposable": "^1.2.0", 366 | "@phosphor/domutils": "^1.1.3", 367 | "@phosphor/dragdrop": "^1.3.3", 368 | "@phosphor/keyboard": "^1.1.3", 369 | "@phosphor/messaging": "^1.2.3", 370 | "@phosphor/properties": "^1.1.3", 371 | "@phosphor/signaling": "^1.2.3", 372 | "@phosphor/virtualdom": "^1.1.3" 373 | } 374 | }, 375 | "@types/dom4": { 376 | "version": "2.0.1", 377 | "resolved": "https://registry.npmjs.org/@types/dom4/-/dom4-2.0.1.tgz", 378 | "integrity": "sha512-kSkVAvWmMZiCYtvqjqQEwOmvKwcH+V4uiv3qPQ8pAh1Xl39xggGEo8gHUqV4waYGHezdFw0rKBR8Jt0CrQSDZA==" 379 | }, 380 | "@types/node": { 381 | "version": "10.12.15", 382 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.15.tgz", 383 | "integrity": "sha512-9kROxduaN98QghwwHmxXO2Xz3MaWf+I1sLVAA6KJDF5xix+IyXVhds0MAfdNwtcpSrzhaTsNB0/jnL86fgUhqA==" 384 | }, 385 | "@types/prop-types": { 386 | "version": "15.7.1", 387 | "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.1.tgz", 388 | "integrity": "sha512-CFzn9idOEpHrgdw8JsoTkaDDyRWk1jrzIV8djzcgpq0y9tG4B4lFT+Nxh52DVpDXV+n4+NPNv7M1Dj5uMp6XFg==" 389 | }, 390 | "@types/react": { 391 | "version": "16.8.23", 392 | "resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.23.tgz", 393 | "integrity": "sha512-abkEOIeljniUN9qB5onp++g0EY38h7atnDHxwKUFz1r3VH1+yG1OKi2sNPTyObL40goBmfKFpdii2lEzwLX1cA==", 394 | "requires": { 395 | "@types/prop-types": "*", 396 | "csstype": "^2.2.0" 397 | } 398 | }, 399 | "ajv": { 400 | "version": "6.10.1", 401 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.1.tgz", 402 | "integrity": "sha512-w1YQaVGNC6t2UCPjEawK/vo/dG8OOrVtUmhBT1uJJYxbl5kU2Tj3v6LGqBcsysN1yhuCStJCCA3GqdvKY8sqXQ==", 403 | "requires": { 404 | "fast-deep-equal": "^2.0.1", 405 | "fast-json-stable-stringify": "^2.0.0", 406 | "json-schema-traverse": "^0.4.1", 407 | "uri-js": "^4.2.2" 408 | } 409 | }, 410 | "ansi-styles": { 411 | "version": "3.2.1", 412 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 413 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 414 | "requires": { 415 | "color-convert": "^1.9.0" 416 | } 417 | }, 418 | "array-uniq": { 419 | "version": "1.0.3", 420 | "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", 421 | "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" 422 | }, 423 | "asap": { 424 | "version": "2.0.6", 425 | "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", 426 | "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" 427 | }, 428 | "async-limiter": { 429 | "version": "1.0.0", 430 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", 431 | "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" 432 | }, 433 | "balanced-match": { 434 | "version": "1.0.0", 435 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 436 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 437 | "dev": true 438 | }, 439 | "brace-expansion": { 440 | "version": "1.1.11", 441 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 442 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 443 | "dev": true, 444 | "requires": { 445 | "balanced-match": "^1.0.0", 446 | "concat-map": "0.0.1" 447 | } 448 | }, 449 | "chalk": { 450 | "version": "2.4.2", 451 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 452 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 453 | "requires": { 454 | "ansi-styles": "^3.2.1", 455 | "escape-string-regexp": "^1.0.5", 456 | "supports-color": "^5.3.0" 457 | } 458 | }, 459 | "classnames": { 460 | "version": "2.2.6", 461 | "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", 462 | "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" 463 | }, 464 | "codemirror": { 465 | "version": "5.47.0", 466 | "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.47.0.tgz", 467 | "integrity": "sha512-kV49Fr+NGFHFc/Imsx6g180hSlkGhuHxTSDDmDHOuyln0MQYFLixDY4+bFkBVeCEiepYfDimAF/e++9jPJk4QA==" 468 | }, 469 | "color-convert": { 470 | "version": "1.9.3", 471 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 472 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 473 | "requires": { 474 | "color-name": "1.1.3" 475 | } 476 | }, 477 | "color-name": { 478 | "version": "1.1.3", 479 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 480 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 481 | }, 482 | "concat-map": { 483 | "version": "0.0.1", 484 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 485 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 486 | "dev": true 487 | }, 488 | "core-js": { 489 | "version": "1.2.7", 490 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", 491 | "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" 492 | }, 493 | "create-react-context": { 494 | "version": "0.2.2", 495 | "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.2.2.tgz", 496 | "integrity": "sha512-KkpaLARMhsTsgp0d2NA/R94F/eDLbhXERdIq3LvX2biCAXcDvHYoOqHfWCHf1+OLj+HKBotLG3KqaOOf+C1C+A==", 497 | "requires": { 498 | "fbjs": "^0.8.0", 499 | "gud": "^1.0.0" 500 | } 501 | }, 502 | "csstype": { 503 | "version": "2.6.6", 504 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.6.tgz", 505 | "integrity": "sha512-RpFbQGUE74iyPgvr46U9t1xoQBM8T4BL8SxrN66Le2xYAPSaDJJKeztV3awugusb3g3G9iL8StmkBBXhcbbXhg==" 506 | }, 507 | "dom-helpers": { 508 | "version": "3.4.0", 509 | "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", 510 | "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", 511 | "requires": { 512 | "@babel/runtime": "^7.1.2" 513 | } 514 | }, 515 | "dom-serializer": { 516 | "version": "0.1.1", 517 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", 518 | "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", 519 | "requires": { 520 | "domelementtype": "^1.3.0", 521 | "entities": "^1.1.1" 522 | } 523 | }, 524 | "dom4": { 525 | "version": "2.1.5", 526 | "resolved": "https://registry.npmjs.org/dom4/-/dom4-2.1.5.tgz", 527 | "integrity": "sha512-gJbnVGq5zaBUY0lUh0LUEVGYrtN75Ks8ZwpwOYvnVFrKy/qzXK4R/1WuLIFExWj/tBxbRAkTzZUGJHXmqsBNjQ==" 528 | }, 529 | "domelementtype": { 530 | "version": "1.3.1", 531 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", 532 | "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" 533 | }, 534 | "domhandler": { 535 | "version": "2.4.2", 536 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", 537 | "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", 538 | "requires": { 539 | "domelementtype": "1" 540 | } 541 | }, 542 | "domutils": { 543 | "version": "1.7.0", 544 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", 545 | "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", 546 | "requires": { 547 | "dom-serializer": "0", 548 | "domelementtype": "1" 549 | } 550 | }, 551 | "encoding": { 552 | "version": "0.1.12", 553 | "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", 554 | "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", 555 | "requires": { 556 | "iconv-lite": "~0.4.13" 557 | } 558 | }, 559 | "entities": { 560 | "version": "1.1.2", 561 | "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", 562 | "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" 563 | }, 564 | "escape-string-regexp": { 565 | "version": "1.0.5", 566 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 567 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 568 | }, 569 | "fast-deep-equal": { 570 | "version": "2.0.1", 571 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", 572 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" 573 | }, 574 | "fast-json-stable-stringify": { 575 | "version": "2.0.0", 576 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 577 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" 578 | }, 579 | "fbjs": { 580 | "version": "0.8.17", 581 | "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", 582 | "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", 583 | "requires": { 584 | "core-js": "^1.0.0", 585 | "isomorphic-fetch": "^2.1.1", 586 | "loose-envify": "^1.0.0", 587 | "object-assign": "^4.1.0", 588 | "promise": "^7.1.1", 589 | "setimmediate": "^1.0.5", 590 | "ua-parser-js": "^0.7.18" 591 | } 592 | }, 593 | "font-awesome": { 594 | "version": "4.7.0", 595 | "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", 596 | "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=" 597 | }, 598 | "free-style": { 599 | "version": "2.6.1", 600 | "resolved": "https://registry.npmjs.org/free-style/-/free-style-2.6.1.tgz", 601 | "integrity": "sha512-uaVA8e57tvhrFKAl6x32SGIrGFBoeTAFtfHDzWxjPhiXQiUxOI6EEdEReRkjNO2H9XcdMJXXEnMHw8Q7iMYLbw==" 602 | }, 603 | "fs.realpath": { 604 | "version": "1.0.0", 605 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 606 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 607 | "dev": true 608 | }, 609 | "glob": { 610 | "version": "7.1.2", 611 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 612 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 613 | "dev": true, 614 | "requires": { 615 | "fs.realpath": "^1.0.0", 616 | "inflight": "^1.0.4", 617 | "inherits": "2", 618 | "minimatch": "^3.0.4", 619 | "once": "^1.3.0", 620 | "path-is-absolute": "^1.0.0" 621 | } 622 | }, 623 | "gud": { 624 | "version": "1.0.0", 625 | "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", 626 | "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" 627 | }, 628 | "has-flag": { 629 | "version": "3.0.0", 630 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 631 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" 632 | }, 633 | "htmlparser2": { 634 | "version": "3.10.1", 635 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", 636 | "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", 637 | "requires": { 638 | "domelementtype": "^1.3.1", 639 | "domhandler": "^2.3.0", 640 | "domutils": "^1.5.1", 641 | "entities": "^1.1.1", 642 | "inherits": "^2.0.1", 643 | "readable-stream": "^3.1.1" 644 | } 645 | }, 646 | "iconv-lite": { 647 | "version": "0.4.24", 648 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 649 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 650 | "requires": { 651 | "safer-buffer": ">= 2.1.2 < 3" 652 | } 653 | }, 654 | "inflight": { 655 | "version": "1.0.6", 656 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 657 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 658 | "dev": true, 659 | "requires": { 660 | "once": "^1.3.0", 661 | "wrappy": "1" 662 | } 663 | }, 664 | "inherits": { 665 | "version": "2.0.3", 666 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 667 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 668 | }, 669 | "is-stream": { 670 | "version": "1.1.0", 671 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 672 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" 673 | }, 674 | "isomorphic-fetch": { 675 | "version": "2.2.1", 676 | "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", 677 | "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", 678 | "requires": { 679 | "node-fetch": "^1.0.1", 680 | "whatwg-fetch": ">=0.10.0" 681 | }, 682 | "dependencies": { 683 | "node-fetch": { 684 | "version": "1.7.3", 685 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", 686 | "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", 687 | "requires": { 688 | "encoding": "^0.1.11", 689 | "is-stream": "^1.0.1" 690 | } 691 | } 692 | } 693 | }, 694 | "js-tokens": { 695 | "version": "4.0.0", 696 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 697 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 698 | }, 699 | "json-schema-traverse": { 700 | "version": "0.4.1", 701 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 702 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 703 | }, 704 | "json5": { 705 | "version": "2.1.0", 706 | "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", 707 | "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", 708 | "requires": { 709 | "minimist": "^1.2.0" 710 | } 711 | }, 712 | "lodash.clonedeep": { 713 | "version": "4.5.0", 714 | "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", 715 | "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" 716 | }, 717 | "lodash.escape": { 718 | "version": "4.0.1", 719 | "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz", 720 | "integrity": "sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=" 721 | }, 722 | "lodash.escaperegexp": { 723 | "version": "4.1.2", 724 | "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", 725 | "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=" 726 | }, 727 | "lodash.isplainobject": { 728 | "version": "4.0.6", 729 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 730 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" 731 | }, 732 | "lodash.isstring": { 733 | "version": "4.0.1", 734 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", 735 | "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" 736 | }, 737 | "lodash.mergewith": { 738 | "version": "4.6.2", 739 | "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", 740 | "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==" 741 | }, 742 | "loose-envify": { 743 | "version": "1.4.0", 744 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 745 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 746 | "requires": { 747 | "js-tokens": "^3.0.0 || ^4.0.0" 748 | } 749 | }, 750 | "marked": { 751 | "version": "0.6.2", 752 | "resolved": "https://registry.npmjs.org/marked/-/marked-0.6.2.tgz", 753 | "integrity": "sha512-LqxwVH3P/rqKX4EKGz7+c2G9r98WeM/SW34ybhgNGhUQNKtf1GmmSkJ6cDGJ/t6tiyae49qRkpyTw2B9HOrgUA==" 754 | }, 755 | "minimatch": { 756 | "version": "3.0.4", 757 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 758 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 759 | "dev": true, 760 | "requires": { 761 | "brace-expansion": "^1.1.7" 762 | } 763 | }, 764 | "minimist": { 765 | "version": "1.2.0", 766 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 767 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" 768 | }, 769 | "moment": { 770 | "version": "2.24.0", 771 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", 772 | "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" 773 | }, 774 | "node-fetch": { 775 | "version": "2.6.0", 776 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", 777 | "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" 778 | }, 779 | "normalize.css": { 780 | "version": "8.0.1", 781 | "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz", 782 | "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==" 783 | }, 784 | "number-is-nan": { 785 | "version": "1.0.1", 786 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 787 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" 788 | }, 789 | "object-assign": { 790 | "version": "4.1.1", 791 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 792 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 793 | }, 794 | "once": { 795 | "version": "1.4.0", 796 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 797 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 798 | "dev": true, 799 | "requires": { 800 | "wrappy": "1" 801 | } 802 | }, 803 | "path-is-absolute": { 804 | "version": "1.0.1", 805 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 806 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 807 | "dev": true 808 | }, 809 | "path-posix": { 810 | "version": "1.0.0", 811 | "resolved": "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz", 812 | "integrity": "sha1-BrJhE/Vr6rBCVFojv6iAA8ysJg8=" 813 | }, 814 | "popper.js": { 815 | "version": "1.15.0", 816 | "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.15.0.tgz", 817 | "integrity": "sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA==" 818 | }, 819 | "postcss": { 820 | "version": "7.0.17", 821 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", 822 | "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", 823 | "requires": { 824 | "chalk": "^2.4.2", 825 | "source-map": "^0.6.1", 826 | "supports-color": "^6.1.0" 827 | }, 828 | "dependencies": { 829 | "supports-color": { 830 | "version": "6.1.0", 831 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", 832 | "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", 833 | "requires": { 834 | "has-flag": "^3.0.0" 835 | } 836 | } 837 | } 838 | }, 839 | "pretty-bytes": { 840 | "version": "5.1.0", 841 | "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.1.0.tgz", 842 | "integrity": "sha512-wa5+qGVg9Yt7PB6rYm3kXlKzgzgivYTLRandezh43jjRqgyDyP+9YxfJpJiLs9yKD1WeU8/OvtToWpW7255FtA==" 843 | }, 844 | "promise": { 845 | "version": "7.3.1", 846 | "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", 847 | "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", 848 | "requires": { 849 | "asap": "~2.0.3" 850 | } 851 | }, 852 | "prop-types": { 853 | "version": "15.7.2", 854 | "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", 855 | "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", 856 | "requires": { 857 | "loose-envify": "^1.4.0", 858 | "object-assign": "^4.1.1", 859 | "react-is": "^16.8.1" 860 | } 861 | }, 862 | "punycode": { 863 | "version": "2.1.1", 864 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 865 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 866 | }, 867 | "querystringify": { 868 | "version": "2.1.1", 869 | "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", 870 | "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" 871 | }, 872 | "react": { 873 | "version": "16.8.6", 874 | "resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz", 875 | "integrity": "sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==", 876 | "requires": { 877 | "loose-envify": "^1.1.0", 878 | "object-assign": "^4.1.1", 879 | "prop-types": "^15.6.2", 880 | "scheduler": "^0.13.6" 881 | } 882 | }, 883 | "react-dom": { 884 | "version": "16.8.6", 885 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.6.tgz", 886 | "integrity": "sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==", 887 | "requires": { 888 | "loose-envify": "^1.1.0", 889 | "object-assign": "^4.1.1", 890 | "prop-types": "^15.6.2", 891 | "scheduler": "^0.13.6" 892 | } 893 | }, 894 | "react-is": { 895 | "version": "16.8.6", 896 | "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", 897 | "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==" 898 | }, 899 | "react-lifecycles-compat": { 900 | "version": "3.0.4", 901 | "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", 902 | "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" 903 | }, 904 | "react-popper": { 905 | "version": "1.3.3", 906 | "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.3.tgz", 907 | "integrity": "sha512-ynMZBPkXONPc5K4P5yFWgZx5JGAUIP3pGGLNs58cfAPgK67olx7fmLp+AdpZ0+GoQ+ieFDa/z4cdV6u7sioH6w==", 908 | "requires": { 909 | "@babel/runtime": "^7.1.2", 910 | "create-react-context": "<=0.2.2", 911 | "popper.js": "^1.14.4", 912 | "prop-types": "^15.6.1", 913 | "typed-styles": "^0.0.7", 914 | "warning": "^4.0.2" 915 | } 916 | }, 917 | "react-transition-group": { 918 | "version": "2.9.0", 919 | "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", 920 | "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", 921 | "requires": { 922 | "dom-helpers": "^3.4.0", 923 | "loose-envify": "^1.4.0", 924 | "prop-types": "^15.6.2", 925 | "react-lifecycles-compat": "^3.0.4" 926 | } 927 | }, 928 | "readable-stream": { 929 | "version": "3.4.0", 930 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", 931 | "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", 932 | "requires": { 933 | "inherits": "^2.0.3", 934 | "string_decoder": "^1.1.1", 935 | "util-deprecate": "^1.0.1" 936 | } 937 | }, 938 | "regenerator-runtime": { 939 | "version": "0.13.2", 940 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", 941 | "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==" 942 | }, 943 | "requires-port": { 944 | "version": "1.0.0", 945 | "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", 946 | "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" 947 | }, 948 | "resize-observer-polyfill": { 949 | "version": "1.5.1", 950 | "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", 951 | "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" 952 | }, 953 | "rimraf": { 954 | "version": "2.6.2", 955 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", 956 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", 957 | "dev": true, 958 | "requires": { 959 | "glob": "^7.0.5" 960 | } 961 | }, 962 | "safe-buffer": { 963 | "version": "5.1.2", 964 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 965 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 966 | }, 967 | "safer-buffer": { 968 | "version": "2.1.2", 969 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 970 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 971 | }, 972 | "sanitize-html": { 973 | "version": "1.20.1", 974 | "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-1.20.1.tgz", 975 | "integrity": "sha512-txnH8TQjaQvg2Q0HY06G6CDJLVYCpbnxrdO0WN8gjCKaU5J0KbyGYhZxx5QJg3WLZ1lB7XU9kDkfrCXUozqptA==", 976 | "requires": { 977 | "chalk": "^2.4.1", 978 | "htmlparser2": "^3.10.0", 979 | "lodash.clonedeep": "^4.5.0", 980 | "lodash.escaperegexp": "^4.1.2", 981 | "lodash.isplainobject": "^4.0.6", 982 | "lodash.isstring": "^4.0.1", 983 | "lodash.mergewith": "^4.6.1", 984 | "postcss": "^7.0.5", 985 | "srcset": "^1.0.0", 986 | "xtend": "^4.0.1" 987 | } 988 | }, 989 | "scheduler": { 990 | "version": "0.13.6", 991 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", 992 | "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", 993 | "requires": { 994 | "loose-envify": "^1.1.0", 995 | "object-assign": "^4.1.1" 996 | } 997 | }, 998 | "setimmediate": { 999 | "version": "1.0.5", 1000 | "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", 1001 | "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" 1002 | }, 1003 | "source-map": { 1004 | "version": "0.6.1", 1005 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1006 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 1007 | }, 1008 | "srcset": { 1009 | "version": "1.0.0", 1010 | "resolved": "https://registry.npmjs.org/srcset/-/srcset-1.0.0.tgz", 1011 | "integrity": "sha1-pWad4StC87HV6D7QPHEEb8SPQe8=", 1012 | "requires": { 1013 | "array-uniq": "^1.0.2", 1014 | "number-is-nan": "^1.0.0" 1015 | } 1016 | }, 1017 | "string_decoder": { 1018 | "version": "1.2.0", 1019 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", 1020 | "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", 1021 | "requires": { 1022 | "safe-buffer": "~5.1.0" 1023 | } 1024 | }, 1025 | "supports-color": { 1026 | "version": "5.5.0", 1027 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1028 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1029 | "requires": { 1030 | "has-flag": "^3.0.0" 1031 | } 1032 | }, 1033 | "tslib": { 1034 | "version": "1.10.0", 1035 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", 1036 | "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" 1037 | }, 1038 | "typed-styles": { 1039 | "version": "0.0.7", 1040 | "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz", 1041 | "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==" 1042 | }, 1043 | "typescript": { 1044 | "version": "3.2.2", 1045 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.2.tgz", 1046 | "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg==", 1047 | "dev": true 1048 | }, 1049 | "typestyle": { 1050 | "version": "2.0.3", 1051 | "resolved": "https://registry.npmjs.org/typestyle/-/typestyle-2.0.3.tgz", 1052 | "integrity": "sha512-F50kKkqIjK5PWyalj3xaqAIopjzCp/MIBD7BW3Hkc2PQhVhRcy/KX0l1uv3+KNGy3xAOIWUxzr8ZibTChp88Ww==", 1053 | "requires": { 1054 | "csstype": "^2.4.0", 1055 | "free-style": "2.6.1" 1056 | } 1057 | }, 1058 | "ua-parser-js": { 1059 | "version": "0.7.20", 1060 | "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.20.tgz", 1061 | "integrity": "sha512-8OaIKfzL5cpx8eCMAhhvTlft8GYF8b2eQr6JkCyVdrgjcytyOmPCXrqXFcUnhonRpLlh5yxEZVohm6mzaowUOw==" 1062 | }, 1063 | "uri-js": { 1064 | "version": "4.2.2", 1065 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 1066 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 1067 | "requires": { 1068 | "punycode": "^2.1.0" 1069 | } 1070 | }, 1071 | "url-parse": { 1072 | "version": "1.4.7", 1073 | "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", 1074 | "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", 1075 | "requires": { 1076 | "querystringify": "^2.1.1", 1077 | "requires-port": "^1.0.0" 1078 | } 1079 | }, 1080 | "util-deprecate": { 1081 | "version": "1.0.2", 1082 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1083 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 1084 | }, 1085 | "warning": { 1086 | "version": "4.0.3", 1087 | "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", 1088 | "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", 1089 | "requires": { 1090 | "loose-envify": "^1.0.0" 1091 | } 1092 | }, 1093 | "whatwg-fetch": { 1094 | "version": "3.0.0", 1095 | "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", 1096 | "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" 1097 | }, 1098 | "wrappy": { 1099 | "version": "1.0.2", 1100 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1101 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1102 | "dev": true 1103 | }, 1104 | "ws": { 1105 | "version": "7.1.0", 1106 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.1.0.tgz", 1107 | "integrity": "sha512-Swie2C4fs7CkwlHu1glMePLYJJsWjzhl1vm3ZaLplD0h7OMkZyZ6kLTB/OagiU923bZrPFXuDTeEqaEN4NWG4g==", 1108 | "requires": { 1109 | "async-limiter": "^1.0.0" 1110 | } 1111 | }, 1112 | "xtend": { 1113 | "version": "4.0.2", 1114 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 1115 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" 1116 | } 1117 | } 1118 | } 1119 | -------------------------------------------------------------------------------- /jupyterlab_dotscience/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dotscience/jupyterlab-plugin", 3 | "version": "0.2.30", 4 | "description": "A JupyterLab extension which enables data & model versioning and summary statistics tracking.", 5 | "keywords": [ 6 | "jupyter", 7 | "jupyterlab", 8 | "jupyterlab-extension" 9 | ], 10 | "homepage": "https://github.com/dotmesh-io/jupyterlab-plugin", 11 | "bugs": { 12 | "url": "https://github.com/dotmesh-io/jupyterlab-plugin/issues" 13 | }, 14 | "license": "BSD-3-Clause", 15 | "author": "dotscience", 16 | "files": [ 17 | "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", 18 | "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}" 19 | ], 20 | "main": "lib/index.js", 21 | "types": "lib/index.d.ts", 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/dotmesh-io/jupyterlab-plugin.git" 25 | }, 26 | "scripts": { 27 | "build": "tsc", 28 | "clean": "rimraf lib", 29 | "watch": "tsc -w" 30 | }, 31 | "dependencies": { 32 | "@jupyterlab/application": "^1.0.0", 33 | "@jupyterlab/apputils": "^1.0.0", 34 | "@phosphor/widgets": "^1.8.1", 35 | "@types/node": "^10.12.15", 36 | "pretty-bytes": "^5.1.0" 37 | }, 38 | "devDependencies": { 39 | "rimraf": "2.6.2", 40 | "typescript": "3.2.2" 41 | }, 42 | "jupyterlab": { 43 | "extension": true 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /jupyterlab_dotscience/src/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ILayoutRestorer, JupyterLab, JupyterFrontEndPlugin 3 | } from '@jupyterlab/application'; 4 | import { PageConfig } from '@jupyterlab/coreutils'; 5 | 6 | /* 7 | import { 8 | each 9 | } from '@phosphor/algorithm'; 10 | */ 11 | 12 | import { 13 | Widget, //TabBar, Title 14 | } from '@phosphor/widgets'; 15 | 16 | // import * as prettyBytes from 'pretty-bytes' 17 | 18 | import '../style/index.css'; 19 | 20 | //const API_URL = 'http://127.0.0.1:8000/example.json' 21 | 22 | const COMMITS_API_URL = PageConfig.getBaseUrl() + 'dotscience/commits' 23 | const STATUS_API_URL = PageConfig.getBaseUrl() + 'dotscience/status' 24 | const COMMITNPUSH_API_URL = PageConfig.getBaseUrl() + 'dotscience/commit' 25 | const WIDGET_ID = 'dotscience-manager' 26 | 27 | type GenericObject = { [key: string]: any }; 28 | 29 | type Commit = { 30 | Id: string; 31 | Metadata: GenericObject; 32 | } 33 | 34 | var COMMIT_DATA: Commit[] = [] 35 | var COMMIT_TOGGLE_STATES: GenericObject = {} 36 | var CURRENT_FETCH_DATA_TIMEOUT_ID: any = null 37 | var STATUS_DATA: any = {} 38 | var LAST_STATUS_JSON_STRING: any = '' 39 | 40 | 41 | const plugin: JupyterFrontEndPlugin = { 42 | id: 'jupyterlab_dotscience_plugin', 43 | activate: (app: JupyterLab, restorer: ILayoutRestorer): void => { 44 | const { shell } = app; 45 | 46 | // make the root widget that will be added to the Jupyter UI 47 | const rootWidget = new Widget() 48 | rootWidget.id = WIDGET_ID 49 | rootWidget.title.label = 'Dotscience' 50 | 51 | const rootContainer = document.createElement('div') 52 | 53 | const fullStoryScript = document.createElement("script") 54 | const fullStoryCode = "window['_fs_run_in_iframe'] = true;window['_fs_debug'] = false;window['_fs_host'] = 'fullstory.com';window['_fs_org'] = '7SVRH';window['_fs_namespace'] = 'FS';(function(m,n,e,t,l,o,g,y){ if (e in m) {if(m.console && m.console.log) { m.console.log('FullStory namespace conflict. Please set window[\"_fs_namespace\"].');} return;} g=m[e]=function(a,b,s){g.q?g.q.push([a,b,s]):g._api(a,b,s);};g.q=[]; o=n.createElement(t);o.async=1;o.src='https://'+_fs_host+'/s/fs.js'; y=n.getElementsByTagName(t)[0];y.parentNode.insertBefore(o,y); g.identify=function(i,v,s){g(l,{uid:i},s);if(v)g(l,v,s)};g.setUserVars=function(v,s){g(l,v,s)};g.event=function(i,v,s){g('event',{n:i,p:v},s)}; g.shutdown=function(){g(\"rec\",!1)};g.restart=function(){g(\"rec\",!0)}; g.consent=function(a){g(\"consent\",!arguments.length||a)}; g.identifyAccount=function(i,v){o='account';v=v||{};v.acctId=i;g(o,v)}; g.clearUserCookie=function(){};})(window,document,window['_fs_namespace'],'script','user');" 55 | const fullStoryCodeNode = document.createTextNode(fullStoryCode) 56 | fullStoryScript.appendChild(fullStoryCodeNode) 57 | rootContainer.appendChild(fullStoryScript) 58 | 59 | rootContainer.className = 'dotscience-root-container' 60 | 61 | // make the actions header and content elements 62 | const actionsHeader = document.createElement('header') 63 | const actionsContent = document.createElement('div') 64 | 65 | actionsHeader.className = 'dotscience-header' 66 | actionsContent.className = 'dotscience-status-content' 67 | 68 | actionsHeader.textContent = 'Actions' 69 | 70 | const inputField = document.createElement('input') 71 | inputField.placeholder = "Describe your commit" 72 | inputField.id = "commitDescription" 73 | inputField.className = 'jp-mod-styled' 74 | 75 | const saveButton = document.createElement('button') 76 | saveButton.textContent = "Save and push data" 77 | const xsrfTokenCookieMatch = document.cookie.match('\\b_xsrf=([^;]*)\\b') 78 | const xsrfToken = xsrfTokenCookieMatch && xsrfTokenCookieMatch.length > 1 ? xsrfTokenCookieMatch[1] : '' 79 | saveButton.addEventListener("click", () => { 80 | let input = document.getElementById("commitDescription") as HTMLInputElement 81 | let text = encodeURIComponent(input.value) 82 | input.value = "" 83 | fetch(COMMITNPUSH_API_URL + "?_xsrf=" + xsrfToken + "&description=" + text, {"method": "PUT"}) 84 | .then(response => { 85 | return response.json() 86 | }) 87 | }) 88 | saveButton.className = "jp-Button" 89 | actionsContent.appendChild(inputField) 90 | actionsContent.appendChild(document.createElement('br')) 91 | actionsContent.appendChild(saveButton) 92 | actionsContent.appendChild(document.createElement('br')) 93 | actionsContent.appendChild(document.createElement('br')) 94 | let help = document.createElement('p') 95 | help.innerHTML = ` 96 | Note: If you run ds.publish() that 97 | will automatically save and push as well.` 98 | actionsContent.appendChild(help) 99 | 100 | // make the status header and content elements 101 | const statusHeader = document.createElement('header') 102 | const statusContent = document.createElement('div') 103 | 104 | statusHeader.className = 'dotscience-header' 105 | statusContent.className = 'dotscience-status-content' 106 | 107 | statusHeader.textContent = 'Status' 108 | statusContent.textContent = 'loading' 109 | 110 | // make the commits header and content elements 111 | const commitsHeader = document.createElement('header') 112 | const commitsContent = document.createElement('div') 113 | 114 | commitsHeader.className = 'dotscience-header' 115 | commitsContent.className = 'dotscience-commits-content' 116 | 117 | commitsHeader.textContent = 'Runs' 118 | commitsContent.innerHTML = ` 119 |
120 | No runs recorded yet for this project. 121 | Create runs with: 122 |

123 | 124 | import dotscience as ds
125 | ds.interactive()
126 | ds.start()
127 | #ds.input(file)
128 | #ds.label("label", value)
129 | #ds.parameter("param", value)
130 | #ds.summary("statistic", value)
131 | #ds.output(output_file)
132 | ds.publish("run message") 133 |
134 |

135 | More info: 136 | 137 | Dotscience Python library docs 138 | 139 |
140 | ` 141 | 142 | // build up the tree of elements 143 | rootContainer.appendChild(actionsHeader) 144 | rootContainer.appendChild(actionsContent) 145 | rootContainer.appendChild(statusHeader) 146 | rootContainer.appendChild(statusContent) 147 | rootContainer.appendChild(commitsHeader) 148 | rootContainer.appendChild(commitsContent) 149 | 150 | rootWidget.node.appendChild(rootContainer) 151 | 152 | shell.add(rootWidget, "right", { rank: 50 }); 153 | 154 | const fetchCommitData = () => { 155 | return fetch(COMMITS_API_URL) 156 | .then(response => { 157 | return response.json() 158 | }) 159 | } 160 | 161 | const fetchStatusData = () => { 162 | return fetch(STATUS_API_URL) 163 | .then(response => { 164 | return response.json() 165 | }) 166 | } 167 | 168 | const fetchData = () => { 169 | if (CURRENT_FETCH_DATA_TIMEOUT_ID) { 170 | clearTimeout(CURRENT_FETCH_DATA_TIMEOUT_ID) 171 | CURRENT_FETCH_DATA_TIMEOUT_ID = null 172 | } 173 | 174 | Promise.all([ 175 | fetchCommitData(), 176 | fetchStatusData(), 177 | ]).then(results => { 178 | // update the commit list if it has changed 179 | const commitData = results[0] 180 | 181 | if (commitData) { 182 | // remove the initial commit (not interesting/relevant to users) and reverse the 183 | // list (so that more recent commits are shown at the top) 184 | commitData.shift() 185 | commitData.reverse() 186 | if(commitData.length!=COMMIT_DATA.length) { 187 | COMMIT_DATA = commitData 188 | populateCommits() 189 | } 190 | } 191 | 192 | // update the status if it has changed 193 | const statusData = results[1] 194 | const stringifiedStatusData = JSON.stringify(statusData) 195 | 196 | if(stringifiedStatusData != LAST_STATUS_JSON_STRING) { 197 | LAST_STATUS_JSON_STRING = stringifiedStatusData 198 | STATUS_DATA = statusData 199 | populateStatus() 200 | } 201 | 202 | CURRENT_FETCH_DATA_TIMEOUT_ID = setTimeout(fetchData, 1000) 203 | }).catch(error => { 204 | console.log('an error occured loading the data from the committer') 205 | console.log(error) 206 | STATUS_DATA = {status: "error", 207 | error_detail: [{ 208 | message: "An error has occurred and changes are not being saved in Dotscience. Restarting Jupyter may fix this issue: " + String(error) 209 | }]} 210 | populateStatus() 211 | // reset the "last status" cache so that success -> error -> success 212 | // doesn't get status stuck on error 213 | LAST_STATUS_JSON_STRING = JSON.stringify(STATUS_DATA) 214 | // do retry on error 215 | CURRENT_FETCH_DATA_TIMEOUT_ID = setTimeout(fetchData, 1000) 216 | }) 217 | } 218 | 219 | const datePadding = (st: any) => { 220 | var stringSt = st.toString() 221 | return stringSt.length == 2 ? stringSt : '0' + stringSt 222 | } 223 | 224 | const getCommitTitle = (commit: any, id: any, includeCommitMessage: boolean) => { 225 | const timestampNumber = Number(commit.Metadata.timestamp) / 1000000 226 | const timestampDate = new Date(timestampNumber) 227 | const timestampDateTitle = // 2019-07-21 07:35:04 228 | timestampDate.getFullYear() + "-" + 229 | datePadding(timestampDate.getMonth()+1) + "-" + 230 | datePadding(timestampDate.getDate()) + " " + 231 | datePadding(timestampDate.getHours()) + ":" + 232 | datePadding(timestampDate.getMinutes()) + ":" + 233 | datePadding(timestampDate.getSeconds()) 234 | 235 | const titleContainer = document.createElement('div') 236 | titleContainer.className = 'dotscience-commit-title' 237 | 238 | const dateContainer = document.createElement('div') 239 | dateContainer.className = 'date' 240 | dateContainer.textContent = timestampDateTitle 241 | 242 | const messageContainer = document.createElement('div') 243 | messageContainer.className = 'message' 244 | 245 | messageContainer.textContent = commit.Metadata.message 246 | 247 | titleContainer.appendChild(dateContainer) 248 | if (includeCommitMessage) { 249 | titleContainer.appendChild(messageContainer) 250 | } 251 | 252 | return titleContainer 253 | } 254 | 255 | const getCommitToggleButton = (commit: any, id: any) => { 256 | const toggleContainer = document.createElement('div') 257 | toggleContainer.className = 'dotscience-commit-toggle' 258 | 259 | const toggleButton = document.createElement('button') 260 | 261 | toggleButton.textContent = COMMIT_TOGGLE_STATES[commit.Id] ? '- hide' : '+ raw' 262 | 263 | toggleButton.addEventListener('click', () => { 264 | const existingValue = COMMIT_TOGGLE_STATES[commit.Id] || false 265 | COMMIT_TOGGLE_STATES[commit.Id] = !existingValue 266 | populateCommits() 267 | }) 268 | 269 | toggleContainer.appendChild(toggleButton) 270 | 271 | return toggleContainer 272 | } 273 | 274 | const getCommitMetadata = (commit: any, id: any) => { 275 | const metadataContainer = document.createElement('div') 276 | metadataContainer.className = 'dotscience-commit-metadata' 277 | 278 | if(!COMMIT_TOGGLE_STATES[commit.Id]) return metadataContainer 279 | 280 | const metadataList = document.createElement('ul') 281 | metadataContainer.appendChild(metadataList) 282 | 283 | Object.keys(commit.Metadata || {}).sort().forEach((key) => { 284 | const metadataItem = document.createElement('li') 285 | metadataItem.textContent = `${key}: ${commit.Metadata[key]}` 286 | metadataList.appendChild(metadataItem) 287 | }) 288 | 289 | return metadataContainer 290 | } 291 | 292 | const getRunIds = (commit: any) => { 293 | return JSON.parse((commit.Metadata || {}).runs || "[]") 294 | } 295 | 296 | const getRunElement = (commit: any, runId: string) => { 297 | const runElement = document.createElement('div') 298 | runElement.className = "dotscience-run-container" 299 | 300 | var authority = "" 301 | var description = "" 302 | var workloadFile = "" 303 | var parameters = {} 304 | var summary = {} 305 | var labels = {} 306 | var inputFiles = [] 307 | var outputFiles = [] 308 | var datasetInputFiles = [] 309 | 310 | Object.keys(commit.Metadata || {}).sort().forEach((key) => { 311 | const value = commit.Metadata[key] 312 | // parsing 313 | if (key == "run."+runId+".description") { 314 | description = value 315 | } 316 | if (key == "run."+runId+".authority") { 317 | authority = value 318 | } 319 | if (key == "run."+runId+".workload-file") { 320 | workloadFile = value 321 | } 322 | if (key.startsWith("run."+runId+".parameters.")) { 323 | parameters[key.substring(("run."+runId+".parameters.").length)] = value 324 | } 325 | if (key.startsWith("run."+runId+".summary.")) { 326 | summary[key.substring(("run."+runId+".summary.").length)] = value 327 | } 328 | if (key.startsWith("run."+runId+".labels.")) { 329 | labels[key.substring(("run."+runId+".labels.").length)] = value 330 | } 331 | if (key == "run."+runId+".input-files") { 332 | try { 333 | inputFiles = JSON.parse(value) 334 | } catch(e) { 335 | console.error(`tried to parse JSON string of input files:`) 336 | console.error(value) 337 | console.error(e) 338 | } 339 | } 340 | if (key == "run."+runId+".output-files") { 341 | try { 342 | outputFiles = JSON.parse(value) 343 | } catch(e) { 344 | console.error(`tried to parse JSON string of output files:`) 345 | console.error(value) 346 | console.error(e) 347 | } 348 | } 349 | if (key.startsWith("run."+runId+".dataset-input-files.")) { 350 | var datasetName = key.substring(("run."+runId+".dataset-input-files.").length) 351 | var singleDatasetFiles = [] 352 | try { 353 | singleDatasetFiles = JSON.parse(value) 354 | } catch(e) { 355 | console.error(`tried to parse JSON string of dataset input files:`) 356 | console.error(value) 357 | console.error(e) 358 | } 359 | singleDatasetFiles = singleDatasetFiles.map(filename => { 360 | return datasetName + ' / ' + filename 361 | }) 362 | datasetInputFiles = datasetInputFiles.concat(singleDatasetFiles) 363 | } 364 | }) 365 | 366 | // rendering 367 | const addNote = (html: string) => { 368 | const runItem = document.createElement('div') 369 | runItem.className = "dotscience-run-element" 370 | runItem.innerHTML = html 371 | runElement.appendChild(runItem) 372 | } 373 | if (authority == "correction") { 374 | addNote("Extra files detected, please tag them with ds.input or ds.output") 375 | } 376 | if (description) { 377 | addNote("Message: "+description) 378 | } 379 | if (workloadFile) { 380 | addNote("File: "+workloadFile) 381 | } 382 | Object.keys(parameters).forEach((key) => { 383 | const value = parameters[key] 384 | addNote("Param: "+key+" = "+value) 385 | }) 386 | Object.keys(summary).forEach((key) => { 387 | const value = summary[key] 388 | addNote("Summary: "+key+" = "+value) 389 | }) 390 | Object.keys(labels).forEach((key) => { 391 | const value = labels[key] 392 | addNote("Label: "+key+" = "+value) 393 | }) 394 | const MAX = 10 395 | inputFiles.slice(0, MAX).forEach((inputFile) => { 396 | addNote("Input: "+inputFile) 397 | }) 398 | if (inputFiles.length > MAX) { 399 | addNote(`... and ${inputFiles.length - MAX} more input files`) 400 | } 401 | outputFiles.slice(0, MAX).forEach((outputFile) => { 402 | addNote("Output: "+outputFile) 403 | }) 404 | if (outputFiles.length > MAX) { 405 | addNote(`... and ${outputFiles.length - MAX} more output files`) 406 | } 407 | datasetInputFiles.slice(0, MAX).forEach((datasetInputFile) => { 408 | addNote("Dataset Input: "+datasetInputFile) 409 | }) 410 | if (datasetInputFiles.length > MAX) { 411 | addNote(`... and ${datasetInputFiles.length - MAX} more dataset input files`) 412 | } 413 | 414 | return runElement 415 | 416 | } 417 | 418 | const getCommitContainer = (commit: any, id: any) => { 419 | const toggleContainer = getCommitToggleButton(commit, id) 420 | const metadataContainer = getCommitMetadata(commit, id) 421 | 422 | const commitContainer = document.createElement('div') 423 | commitContainer.className = 'dotscience-commit-container' 424 | 425 | const runIds = getRunIds(commit) 426 | if (runIds.length > 0) { 427 | // false == don't include commit message 428 | const titleContainer = getCommitTitle(commit, id, false) 429 | commitContainer.appendChild(titleContainer) 430 | 431 | runIds.forEach((runId) => { 432 | commitContainer.appendChild(getRunElement(commit, runId)) 433 | }) 434 | } else { 435 | // only add the title (commit-level message) if there are no runs (true 436 | // = include commit message) 437 | const titleContainer = getCommitTitle(commit, id, true) 438 | commitContainer.appendChild(titleContainer) 439 | } 440 | 441 | commitContainer.appendChild(toggleContainer) 442 | commitContainer.appendChild(metadataContainer) 443 | 444 | return commitContainer 445 | } 446 | 447 | const getStatusFilesChanged = (changedFiles, moreChangedFiles) => { 448 | if(changedFiles.length <= 0) return '' 449 | const parts = changedFiles.map((changedFile) => { 450 | return ` 451 |
  • ${ changedFile.filename } (${ changedFile.file_status })
  • 452 | ` 453 | }).join("\n") + (moreChangedFiles == 0 ? '' : (' and ' + moreChangedFiles + ' more')) 454 | 455 | return ` 456 |
    457 |

    ${ changedFiles.length + moreChangedFiles } changed file${ changedFiles.length == 1 ? '' : 's' }:

    458 | 459 |
    460 | ` 461 | } 462 | 463 | const getStatusUnknownFiles = (unknownFiles, moreUnknownFiles) => { 464 | if(unknownFiles.length <= 0) return '' 465 | 466 | const parts = unknownFiles.map((unknownFile) => { 467 | return ` 468 |
  • ${ unknownFile }
  • 469 | ` 470 | }).join("\n") + (moreUnknownFiles == 0 ? '' : (' and ' + moreUnknownFiles + ' more')) 471 | 472 | return ` 473 |
    474 |

    ${ unknownFiles.length + moreUnknownFiles } unknown file${ unknownFiles.length == 1 ? '' : 's' }:

    475 | 476 |
    477 |

    Please use the Dotscience Python Library to annotate these files!

    478 |
    479 | ` 480 | } 481 | 482 | const getStatusSummary = (status, errorDetails) => { 483 | let statusClassname = '' 484 | let errorString = `` 485 | errorDetails = errorDetails || [] 486 | if(status == 'error') { 487 | statusClassname = "dotscience-error-text" 488 | } 489 | if(errorDetails.length > 0) { 490 | for(let error in errorDetails) { 491 | let errorMsg = 'Something went wrong on your runner - please contact support@dotscience.com or restart Jupyter' 492 | if(errorDetails[error].type == 'json') { 493 | if(errorDetails[error].cell != undefined) { 494 | errorMsg = `Dotscience has output invalid JSON in ${ errorDetails[error].notebook }, cell ${ errorDetails[error].cell }. This is an error, please contact support@dotscience.com` 495 | } else { 496 | errorMsg = `We couldn't read the notebook ${ errorDetails[error].notebook }, please check it is saved in the correct JSON format.` 497 | 498 | // clear this error message after 10 seconds 499 | setTimeout(function() { 500 | document.querySelector('.dotscience-error-text').innerHTML = '' 501 | }, 10 * 1000) 502 | } 503 | 504 | errorString += ` 505 |
    506 |

    ${errorMsg}

    507 |
    508 |
    ` 509 | } else { 510 | errorString += ` 511 |
    512 |

    ${errorDetails[error].message}

    513 |
    514 |
    ` 515 | } 516 | } 517 | } 518 | 519 | return ` 520 |
    521 |

    Status: ${ status }

    522 | ${ errorString } 523 |
    524 | ` 525 | } 526 | 527 | const populateStatus = () => { 528 | const statusSummary = getStatusSummary(STATUS_DATA.status, STATUS_DATA.error_detail) 529 | const changedFileHTML = getStatusFilesChanged(STATUS_DATA.changed_files || [], STATUS_DATA.more_changed_files || 0) 530 | const unknownFileHTML = getStatusUnknownFiles(STATUS_DATA.unclaimed_files || [], STATUS_DATA.more_unclaimed_files || 0) 531 | 532 | statusContent.innerHTML = ` 533 |
    534 | ${statusSummary} 535 | ${changedFileHTML} 536 | ${unknownFileHTML} 537 |
    538 | ` 539 | 540 | } 541 | 542 | const populateCommits = () => { 543 | commitsContent.innerHTML = '' 544 | 545 | COMMIT_DATA.forEach((commit, id) => { 546 | const commitContainer = getCommitContainer(commit, id) 547 | commitsContent.appendChild(commitContainer) 548 | }) 549 | 550 | const gapContainer = document.createElement('div') 551 | gapContainer.className = 'dotscience-bottom-gap' 552 | 553 | commitsContent.appendChild(gapContainer) 554 | } 555 | 556 | app.restored.then(() => { 557 | app.shell.activateById(WIDGET_ID) 558 | shell.layoutModified.connect(() => { fetchData() }); 559 | fetchData() 560 | }); 561 | }, 562 | autoStart: true, 563 | requires: [ILayoutRestorer] 564 | }; 565 | 566 | export default plugin; 567 | -------------------------------------------------------------------------------- /jupyterlab_dotscience/style/index.css: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------- 2 | | Copyright (c) Jupyter Development Team. 3 | | Distributed under the terms of the Modified BSD License. 4 | |----------------------------------------------------------------------------*/ 5 | 6 | /*----------------------------------------------------------------------------- 7 | | Variables 8 | |----------------------------------------------------------------------------*/ 9 | 10 | :root { 11 | --jp-private-tab-manager-active-top-border: 2px; 12 | --jp-private-tab-manager-tab-height: 24px; 13 | --jp-private-tab-manager-tab-padding-top: 8px; 14 | } 15 | 16 | 17 | /*----------------------------------------------------------------------------- 18 | | Tabs in the dock panel 19 | |----------------------------------------------------------------------------*/ 20 | 21 | #dotscience-manager { 22 | background: var(--jp-layout-color1); 23 | overflow: visible; 24 | color: var(--jp-ui-font-color1); 25 | /* This is needed so that all font sizing of children done in ems is 26 | * relative to this base size */ 27 | font-size: var(--jp-ui-font-size1); 28 | height: 100%; 29 | } 30 | 31 | #dotscience-manager .dotscience-root-container { 32 | height: 100%; 33 | display: flex; 34 | flex-direction: column; 35 | } 36 | 37 | #dotscience-manager .dotscience-header { 38 | flex: 0 1 auto; 39 | background: var(--jp-layout-color2); 40 | } 41 | 42 | #dotscience-manager .dotscience-actions-content { 43 | flex: 0 1 auto; 44 | padding-left: 10px; 45 | padding-right: 10px; 46 | padding-top: 5px; 47 | padding-bottom: 5px; 48 | text-align: center; 49 | } 50 | 51 | #dotscience-manager .dotscience-status-content { 52 | flex: 0 1 auto; 53 | padding-left: 10px; 54 | padding-right: 10px; 55 | padding-top: 5px; 56 | padding-bottom: 5px; 57 | } 58 | 59 | #dotscience-manager .dotscience-commits-content { 60 | flex: 1 1 auto; 61 | overflow-y: auto; 62 | } 63 | 64 | #dotscience-manager header { 65 | border-bottom: var(--jp-border-width) solid var(--jp-border-color2); 66 | border-top: var(--jp-border-width) solid var(--jp-border-color2); 67 | font-size: var(--jp-ui-font-size0); 68 | font-weight: 600; 69 | letter-spacing: 1px; 70 | margin: 0px; 71 | padding: 12px; 72 | text-transform: uppercase; 73 | } 74 | 75 | /* 76 | 77 | status cell classes 78 | 79 | */ 80 | 81 | #dotscience-manager .dotscience-error-text { 82 | color: red; 83 | } 84 | 85 | #dotscience-manager .dotscience-summary-ul { 86 | padding-left: 25px; 87 | } 88 | 89 | /* 90 | 91 | single commit classes 92 | 93 | */ 94 | #dotscience-manager .dotscience-commit-container { 95 | padding: 12px 12px; 96 | border: none; 97 | border-bottom: 1px solid #e5e5e5; 98 | position: relative; 99 | overflow: visible; 100 | } 101 | 102 | #dotscience-manager .dotscience-run-container { 103 | border: none; 104 | border-bottom: 1px solid #e5e5e5; 105 | margin-bottom: 5px; 106 | position: relative; 107 | overflow: visible; 108 | clear: both; 109 | } 110 | 111 | #dotscience-manager .dotscience-run-element { 112 | padding: 2px 2px; 113 | margin: 3px 3px 0 0; 114 | border: 1px solid gray; 115 | background-color: #eeeeee; 116 | display: inline-block; 117 | } 118 | 119 | #dotscience-manager>strong { 120 | font-weight:bold; 121 | } 122 | 123 | #dotscience-manager .dotscience-bottom-gap { 124 | height: 50px; 125 | } 126 | 127 | #dotscience-manager .dotscience-commit-container:hover { 128 | background: var(--jp-layout-color2); 129 | } 130 | 131 | #dotscience-manager .dotscience-commit-container .dotscience-commit-title { 132 | float: left; 133 | } 134 | 135 | #dotscience-manager .dotscience-commit-container .dotscience-commit-title .date { 136 | font-weight: bold; 137 | color: #999; 138 | font-size: 0.8em; 139 | } 140 | 141 | #dotscience-manager .dotscience-commit-container .dotscience-commit-title .message { 142 | 143 | } 144 | 145 | #dotscience-manager .dotscience-commit-container .dotscience-commit-toggle { 146 | float: right; 147 | } 148 | 149 | #dotscience-manager .dotscience-commit-container .dotscience-commit-toggle button { 150 | color: #ffffff; 151 | background-color: #999999; 152 | font-size: 0.8em; 153 | font-weight: bold; 154 | } 155 | 156 | #dotscience-manager .dotscience-commit-container .dotscience-commit-metadata { 157 | clear: left; 158 | color: #999; 159 | padding-top: 8px; 160 | } 161 | 162 | 163 | #dotscience-manager .p-TabBar-tab { 164 | height: var(--jp-private-tab-manager-tab-height); 165 | padding: 0px 12px; 166 | border: none; 167 | position: relative; 168 | overflow: visible; 169 | } 170 | 171 | 172 | #dotscience-manager .p-TabBar-tab:hover:not(.jp-mod-active) { 173 | background: var(--jp-layout-color2); 174 | } 175 | 176 | 177 | #dotscience-manager .p-TabBar-tab:first-child { 178 | margin-left: 0; 179 | } 180 | 181 | 182 | #dotscience-manager .p-TabBar-tab.jp-mod-active { 183 | color: white; 184 | background: var(--jp-brand-color1); 185 | } 186 | 187 | 188 | #dotscience-manager .p-TabBar-tabIcon, 189 | #dotscience-manager .p-TabBar-tabLabel, 190 | #dotscience-manager .p-TabBar-tabCloseIcon { 191 | display: inline-block; 192 | } 193 | 194 | 195 | #dotscience-manager .p-TabBar-tabLabel { 196 | line-height: var(--jp-private-tab-manager-tab-height); 197 | padding-left: 4px; 198 | } 199 | 200 | 201 | #dotscience-manager .p-TabBar-tab .p-TabBar-tabIcon { 202 | width: 14px; 203 | background-position: left center; 204 | background-repeat: no-repeat; 205 | margin-right: 2px; 206 | } 207 | 208 | 209 | #dotscience-manager .p-TabBar-tab.p-mod-closable > .p-TabBar-tabCloseIcon { 210 | padding: 4px 0px 4px 4px; 211 | background-size: 16px; 212 | height: 16px; 213 | width: 16px; 214 | background-image: var(--jp-icon-close); 215 | background-position: center; 216 | background-repeat: no-repeat; 217 | } 218 | 219 | 220 | #dotscience-manager .p-TabBar-tab.p-mod-closable.jp-mod-dirty > .p-TabBar-tabCloseIcon { 221 | background-size: 10px; 222 | background-image: var(--jp-icon-circle); 223 | } 224 | 225 | 226 | #dotscience-manager .p-TabBar-tab.p-mod-closable.jp-mod-dirty.jp-mod-active > .p-TabBar-tabCloseIcon { 227 | background-size: 10px; 228 | background-image: var(--jp-icon-inverse-circle); 229 | } 230 | 231 | 232 | #dotscience-manager .p-TabBar-tab.p-mod-closable.jp-mod-active > .p-TabBar-tabCloseIcon { 233 | background-image: var(--jp-icon-inverse-close); 234 | } 235 | 236 | #dotscience-manager .p-TabBar-tab.p-mod-closable > .p-TabBar-tabCloseIcon:hover { 237 | background-size: 16px; 238 | background-image: var(--jp-icon-close-circle); 239 | } 240 | 241 | #dotscience-manager .p-TabBar-tab.p-mod-closable.jp-mod-active > .p-TabBar-tabCloseIcon:hover { 242 | background-size: 16px; 243 | background-image: var(--jp-icon-inverse-close-circle); 244 | } 245 | -------------------------------------------------------------------------------- /jupyterlab_dotscience/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "noImplicitAny": false, 5 | "noEmitOnError": true, 6 | "noUnusedLocals": true, 7 | "allowSyntheticDefaultImports": true, 8 | "module": "commonjs", 9 | "moduleResolution": "node", 10 | "target": "ES5", 11 | "outDir": "./lib", 12 | "lib": ["ES5", "ES2015.Promise", "DOM", "es2015", "es2015.iterable"], 13 | "types": [] 14 | }, 15 | "include": ["src/*"] 16 | } 17 | -------------------------------------------------------------------------------- /jupyterlab_dotscience_backend/.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.2.30 3 | commit = False 4 | tag = False 5 | tag_name = {new_version} 6 | 7 | [bumpversion:file:jupyterlab_dotscience_backend/__init__.py] 8 | 9 | [bumpversion:file:setup.py] 10 | 11 | -------------------------------------------------------------------------------- /jupyterlab_dotscience_backend/.gitattributes: -------------------------------------------------------------------------------- 1 | jupyterlab_dotscience_backend/_version.py export-subst 2 | -------------------------------------------------------------------------------- /jupyterlab_dotscience_backend/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include jupyterlab_dotscience_backend -------------------------------------------------------------------------------- /jupyterlab_dotscience_backend/README.md: -------------------------------------------------------------------------------- 1 | # jupyterlab-dotscience plugin 2 | 3 | A JupyterLab extension which enables data & model versioning and summary statistics tracking. 4 | 5 | See [dotscience](https://github.com/dotmesh-io/dotscience) for more details. 6 | -------------------------------------------------------------------------------- /jupyterlab_dotscience_backend/jupyterlab_dotscience_backend/README.md: -------------------------------------------------------------------------------- 1 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2 | 3 | newer versions of this code are now being maintained in github.com/dotmesh-io/jupyterlab-tensorflow/argh 4 | 5 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 6 | -------------------------------------------------------------------------------- /jupyterlab_dotscience_backend/jupyterlab_dotscience_backend/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | JupyterLab dotscience: proxy through to local dotscience instance 3 | """ 4 | 5 | from notebook.utils import url_path_join 6 | 7 | __version__ = '0.2.30' 8 | 9 | import os, json 10 | from tornado import web 11 | from notebook.base.handlers import APIHandler 12 | import requests 13 | 14 | # TODO pip3 install datadots-api==0.1.2 15 | from dotmesh.client import DotmeshClient, DotName 16 | 17 | import logging 18 | logging.getLogger('jsonrpcclient.client.request').setLevel(logging.ERROR) 19 | logging.getLogger('jsonrpcclient.client.response').setLevel(logging.ERROR) 20 | 21 | # XXX is this right??? 22 | path_regex = r'(?P(?:(?:/[^/]+)+|/?))' 23 | 24 | import socket, struct 25 | def get_default_gateway_linux(): 26 | """Read the default gateway directly from /proc.""" 27 | with open("/proc/net/route") as fh: 28 | for line in fh: 29 | fields = line.strip().split() 30 | if fields[1] != '00000000' or not int(fields[3], 16) & 2: 31 | continue 32 | 33 | return socket.inet_ntoa(struct.pack("=0.2.4'], 17 | classifiers=( 18 | "Programming Language :: Python :: 3", 19 | "License :: OSI Approved :: MIT License", 20 | "Operating System :: OS Independent", 21 | ), 22 | ) 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dotscience/jupyterlab-plugin", 3 | "version": "0.0.2", 4 | "description": "jupyterlab plugin for using dotscience", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/dotmesh-io/jupyterlab-plugin.git" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/dotmesh-io/jupyterlab-plugin/issues" 17 | }, 18 | "homepage": "https://github.com/dotmesh-io/jupyterlab-plugin#readme" 19 | } 20 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["github>dotmesh-io/renovate-config"] 3 | } 4 | -------------------------------------------------------------------------------- /scripts/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | VERSION=$1 4 | cd jupyterlab_dotscience_backend && bump2version --new-version $VERSION patch 5 | cd ../jupyterlab_dotscience && npm --no-git-tag-version version $VERSION 6 | git commit -am "Bump to version ${VERSION}" && git tag $VERSION 7 | git push && git push --tags 8 | --------------------------------------------------------------------------------