diff --git a/.pylintrc b/.pylintrc
index be4cbe086b..b00f3ed384 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -412,7 +412,7 @@ max-attributes=20
max-bool-expr=5
# Maximum number of branch for function / method body
-max-branches=12
+max-branches=15
# Maximum number of locals for function / method body
max-locals=15
diff --git a/.pylintrc39 b/.pylintrc39
index 05d1d677b9..e3927edeab 100644
--- a/.pylintrc39
+++ b/.pylintrc39
@@ -513,7 +513,7 @@ max-attributes=20
max-bool-expr=5
# Maximum number of branch for function / method body.
-max-branches=12
+max-branches=15
# Maximum number of locals for function / method body.
max-locals=15
diff --git a/@plotly/dash-generator-test-component-typescript/package-lock.json b/@plotly/dash-generator-test-component-typescript/package-lock.json
index bf28ff7842..28cf26e996 100644
--- a/@plotly/dash-generator-test-component-typescript/package-lock.json
+++ b/@plotly/dash-generator-test-component-typescript/package-lock.json
@@ -3364,9 +3364,9 @@
"dev": true
},
"node_modules/c8": {
- "version": "7.11.3",
- "resolved": "https://registry.npmjs.org/c8/-/c8-7.11.3.tgz",
- "integrity": "sha512-6YBmsaNmqRm9OS3ZbIiL2EZgi1+Xc4O24jL3vMYGE6idixYuGdy76rIfIdltSKDj9DpLNrcXSonUTR1miBD0wA==",
+ "version": "7.13.0",
+ "resolved": "https://registry.npmjs.org/c8/-/c8-7.13.0.tgz",
+ "integrity": "sha512-/NL4hQTv1gBL6J6ei80zu3IiTrmePDKXKXOTLpHvcIWZTVYQlDhVWjjWvkhICylE8EwwnMVzDZugCvdx0/DIIA==",
"dev": true,
"dependencies": {
"@bcoe/v8-coverage": "^0.2.3",
@@ -8174,9 +8174,9 @@
}
},
"node_modules/tslib": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
- "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+ "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
"dev": true
},
"node_modules/type-detect": {
@@ -11146,9 +11146,9 @@
"dev": true
},
"c8": {
- "version": "7.11.3",
- "resolved": "https://registry.npmjs.org/c8/-/c8-7.11.3.tgz",
- "integrity": "sha512-6YBmsaNmqRm9OS3ZbIiL2EZgi1+Xc4O24jL3vMYGE6idixYuGdy76rIfIdltSKDj9DpLNrcXSonUTR1miBD0wA==",
+ "version": "7.13.0",
+ "resolved": "https://registry.npmjs.org/c8/-/c8-7.13.0.tgz",
+ "integrity": "sha512-/NL4hQTv1gBL6J6ei80zu3IiTrmePDKXKXOTLpHvcIWZTVYQlDhVWjjWvkhICylE8EwwnMVzDZugCvdx0/DIIA==",
"dev": true,
"requires": {
"@bcoe/v8-coverage": "^0.2.3",
@@ -14690,9 +14690,9 @@
}
},
"tslib": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
- "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+ "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
"dev": true
},
"type-detect": {
diff --git a/@plotly/dash-generator-test-component-typescript/src/components/MemoTypeScriptComponent.tsx b/@plotly/dash-generator-test-component-typescript/src/components/MemoTypeScriptComponent.tsx
index d8074b48c9..a5baf40707 100644
--- a/@plotly/dash-generator-test-component-typescript/src/components/MemoTypeScriptComponent.tsx
+++ b/@plotly/dash-generator-test-component-typescript/src/components/MemoTypeScriptComponent.tsx
@@ -14,4 +14,4 @@ const MemoTypeScriptComponent = (props: TypescriptComponentProps) => (
{props.required_string}
);
-export default React.memo(MemoTypeScriptComponent);
+export default React.memo(MemoTypeScriptComponent, () => true);
diff --git a/@plotly/dash-generator-test-component-typescript/src/components/StandardComponent.react.js b/@plotly/dash-generator-test-component-typescript/src/components/StandardComponent.react.js
index 5396f04712..e676dc2d06 100644
--- a/@plotly/dash-generator-test-component-typescript/src/components/StandardComponent.react.js
+++ b/@plotly/dash-generator-test-component-typescript/src/components/StandardComponent.react.js
@@ -17,4 +17,4 @@ StandardComponent.propTypes = {
children: PropTypes.node,
}
-export default StandardComponent
+export default React.memo(StandardComponent, (prevProps,nextProps) => true)
diff --git a/@plotly/dash-jupyterlab/.prettierrc b/@plotly/dash-jupyterlab/.prettierrc
new file mode 100644
index 0000000000..92cde390ac
--- /dev/null
+++ b/@plotly/dash-jupyterlab/.prettierrc
@@ -0,0 +1,3 @@
+{
+ "singleQuote": true
+}
\ No newline at end of file
diff --git a/@plotly/dash-jupyterlab/lib/index.d.ts b/@plotly/dash-jupyterlab/lib/index.d.ts
new file mode 100644
index 0000000000..0b7e1f8c96
--- /dev/null
+++ b/@plotly/dash-jupyterlab/lib/index.d.ts
@@ -0,0 +1,7 @@
+import { JupyterFrontEndPlugin } from '@jupyterlab/application';
+import '../style/index.css';
+/**
+ * Initialization data for the jupyterlab-dash extension.
+ */
+declare const extension: JupyterFrontEndPlugin;
+export default extension;
diff --git a/@plotly/dash-jupyterlab/lib/index.js b/@plotly/dash-jupyterlab/lib/index.js
new file mode 100644
index 0000000000..109b9ee851
--- /dev/null
+++ b/@plotly/dash-jupyterlab/lib/index.js
@@ -0,0 +1,115 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+const application_1 = require("@jupyterlab/application");
+const coreutils_1 = require("@jupyterlab/coreutils");
+const notebook_1 = require("@jupyterlab/notebook");
+const console_1 = require("@jupyterlab/console");
+const widgets_1 = require("@lumino/widgets");
+require("../style/index.css");
+class DashIFrameWidget extends widgets_1.Widget {
+ /**
+ * Construct a new DashIFrameWidget.
+ */
+ constructor(port, url) {
+ super();
+ this.id = port;
+ this.title.label = `Dash (port: ${port})`;
+ this.title.closable = true;
+ this.addClass('jp-dashWidget');
+ // Add jp-IFrame class to keep drag events from being lost to the iframe
+ // See https://github.com/phosphorjs/phosphor/issues/305
+ // See https://github.com/jupyterlab/jupyterlab/blob/master/packages/apputils/style/iframe.css#L17-L35
+ this.addClass('jp-IFrame');
+ const serviceUrl = url;
+ const iframeElement = document.createElement('iframe');
+ iframeElement.setAttribute('baseURI', serviceUrl);
+ this.iframe = iframeElement;
+ this.iframe.src = serviceUrl;
+ this.iframe.id = 'iframe-' + this.id;
+ this.node.appendChild(this.iframe);
+ }
+ /**
+ * Handle update requests for the widget.
+ */
+ onUpdateRequest(msg) {
+ this.iframe.src += '';
+ }
+}
+function activate(app, restorer, notebooks, consoles) {
+ // Declare a widget variable
+ let widgets = new Map();
+ // Watch notebook creation
+ notebooks.widgetAdded.connect((sender, nbPanel) => {
+ // const session = nbPanel.session;
+ const sessionContext = nbPanel.sessionContext;
+ sessionContext.ready.then(() => {
+ const session = sessionContext.session;
+ let kernel = session.kernel;
+ registerCommTarget(kernel, widgets, app);
+ });
+ });
+ // Watch console creation
+ consoles.widgetAdded.connect((sender, consolePanel) => {
+ const sessionContext = consolePanel.sessionContext;
+ sessionContext.ready.then(() => {
+ const session = sessionContext.session;
+ let kernel = session.kernel;
+ registerCommTarget(kernel, widgets, app);
+ });
+ });
+}
+function registerCommTarget(kernel, widgets, app) {
+ kernel.registerCommTarget('dash', (comm, msg) => {
+ comm.onMsg = (msg) => {
+ let msgData = msg.content.data;
+ if (msgData.type === 'show') {
+ let widget;
+ if (!widgets.has(msgData.port)) {
+ // Create a new widget
+ widget = new DashIFrameWidget(msgData.port, msgData.url);
+ widget.update();
+ widgets.set(msgData.port, widget);
+ // Add instance tracker stuff
+ }
+ else {
+ widget = widgets.get(msgData.port);
+ }
+ if (!widget.isAttached) {
+ // Attach the widget to the main work area
+ // if it's not there
+ app.shell.add(widget, 'main');
+ widget.update();
+ }
+ else {
+ // Refresh the widget
+ widget.update();
+ }
+ // Activate the widget
+ app.shell.activateById(widget.id);
+ }
+ else if (msgData.type === 'base_url_request') {
+ // Build server url and base subpath.
+ const baseUrl = coreutils_1.PageConfig.getBaseUrl();
+ const baseSubpath = coreutils_1.PageConfig.getOption('baseUrl');
+ const n = baseUrl.lastIndexOf(baseSubpath);
+ const serverUrl = baseUrl.slice(0, n);
+ comm.send({
+ type: 'base_url_response',
+ server_url: serverUrl,
+ base_subpath: baseSubpath,
+ frontend: "jupyterlab",
+ });
+ }
+ };
+ });
+}
+/**
+ * Initialization data for the jupyterlab-dash extension.
+ */
+const extension = {
+ id: 'jupyterlab_dash',
+ autoStart: true,
+ requires: [application_1.ILayoutRestorer, notebook_1.INotebookTracker, console_1.IConsoleTracker],
+ activate: activate
+};
+exports.default = extension;
diff --git a/@plotly/dash-jupyterlab/package.json b/@plotly/dash-jupyterlab/package.json
new file mode 100644
index 0000000000..d81245ad2a
--- /dev/null
+++ b/@plotly/dash-jupyterlab/package.json
@@ -0,0 +1,48 @@
+{
+ "name": "@plotly/dash-jupyterlab",
+ "version": "0.4.3",
+ "description": "A JupyterLab extension for rendering Plotly Dash apps",
+ "keywords": [
+ "jupyter",
+ "jupyterlab",
+ "jupyterlab-extension"
+ ],
+ "homepage": "https://github.com/plotly/dash",
+ "bugs": {
+ "url": "https://github.com/plotly/dash/issues"
+ },
+ "license": "MIT",
+ "author": "Plotly",
+ "files": [
+ "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
+ "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}"
+ ],
+ "main": "lib/index.js",
+ "types": "lib/index.d.ts",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/plotly/dash.git"
+ },
+ "scripts": {
+ "build": "tsc",
+ "build:pack": "jlpm run prepare && jlpm pack --filename ../../dash/labextension/dist/dash-jupyterlab.tgz && jlpm run build:copy",
+ "build:copy": "cp package.json ../../dash/labextension/dist/package.json",
+ "clean": "rimraf lib",
+ "prepare": "mkdir -p ../../dash/labextension/dist && jlpm run clean && jlpm run build",
+ "prettier": "prettier --write '{!(package),src/**,!(lib)/**}{.js,.jsx,.ts,.tsx,.css,.json,.md}'",
+ "watch": "tsc -w"
+ },
+ "dependencies": {
+ "@jupyterlab/application": "^2.0.0 || ^3.0.0",
+ "@jupyterlab/notebook": "^2.0.0 || ^3.0.0",
+ "@jupyterlab/console": "^2.0.0 || ^3.0.0"
+ },
+ "devDependencies": {
+ "prettier": "2.0.5",
+ "rimraf": "3.0.2",
+ "typescript": "3.9.3"
+ },
+ "jupyterlab": {
+ "extension": true
+ }
+}
diff --git a/@plotly/dash-jupyterlab/src/index.ts b/@plotly/dash-jupyterlab/src/index.ts
new file mode 100644
index 0000000000..5dc58fd2db
--- /dev/null
+++ b/@plotly/dash-jupyterlab/src/index.ts
@@ -0,0 +1,163 @@
+import {
+ ILayoutRestorer,
+ JupyterFrontEnd,
+ JupyterFrontEndPlugin
+} from '@jupyterlab/application';
+
+import { PageConfig } from '@jupyterlab/coreutils';
+
+import { INotebookTracker, NotebookPanel } from '@jupyterlab/notebook';
+
+import { KernelMessage, Kernel } from '@jupyterlab/services';
+
+import { IConsoleTracker } from '@jupyterlab/console';
+
+import { Message } from '@lumino/messaging';
+
+import { Widget } from '@lumino/widgets';
+
+import '../style/index.css';
+
+class DashIFrameWidget extends Widget {
+ /**
+ * Construct a new DashIFrameWidget.
+ */
+ constructor(port: string, url: string) {
+ super();
+
+ this.id = port;
+ this.title.label = `Dash (port: ${port})`;
+ this.title.closable = true;
+ this.addClass('jp-dashWidget');
+
+ // Add jp-IFrame class to keep drag events from being lost to the iframe
+ // See https://github.com/phosphorjs/phosphor/issues/305
+ // See https://github.com/jupyterlab/jupyterlab/blob/master/packages/apputils/style/iframe.css#L17-L35
+ this.addClass('jp-IFrame');
+
+ const serviceUrl = url;
+ const iframeElement = document.createElement('iframe');
+ iframeElement.setAttribute('baseURI', serviceUrl);
+ this.iframe = iframeElement;
+ this.iframe.src = serviceUrl;
+ this.iframe.id = 'iframe-' + this.id;
+
+ this.node.appendChild(this.iframe);
+ }
+
+ /**
+ * The image element associated with the widget.
+ */
+ readonly iframe: HTMLIFrameElement;
+
+ /**
+ * Handle update requests for the widget.
+ */
+ onUpdateRequest(msg: Message): void {
+ this.iframe.src += '';
+ }
+}
+
+interface DashMessageData {
+ type: string;
+ port: string;
+ url: string;
+}
+
+function activate(
+ app: JupyterFrontEnd,
+ restorer: ILayoutRestorer,
+ notebooks: INotebookTracker,
+ consoles: IConsoleTracker
+) {
+
+ // Declare a widget variable
+ let widgets = new Map();
+
+ // Watch notebook creation
+ notebooks.widgetAdded.connect((sender, nbPanel: NotebookPanel) => {
+ // const session = nbPanel.session;
+ const sessionContext = nbPanel.sessionContext;
+ sessionContext.ready.then(() => {
+ const session = sessionContext.session;
+ let kernel = session.kernel;
+ registerCommTarget(kernel, widgets, app);
+ })
+ });
+
+ // Watch console creation
+ consoles.widgetAdded.connect((sender, consolePanel) => {
+ const sessionContext = consolePanel.sessionContext;
+ sessionContext.ready.then(() => {
+ const session = sessionContext.session;
+ let kernel = session.kernel;
+ registerCommTarget(kernel, widgets, app);
+ })
+ });
+}
+
+function registerCommTarget(
+ kernel: Kernel.IKernelConnection,
+ widgets: Map,
+ app: JupyterFrontEnd
+) {
+ kernel.registerCommTarget(
+ 'dash',
+ (comm: Kernel.IComm, msg: KernelMessage.ICommOpenMsg) => {
+ comm.onMsg = (msg: KernelMessage.ICommMsgMsg) => {
+ let msgData = (msg.content.data as unknown) as DashMessageData;
+ if (msgData.type === 'show') {
+ let widget: DashIFrameWidget;
+ if (!widgets.has(msgData.port)) {
+ // Create a new widget
+ widget = new DashIFrameWidget(msgData.port, msgData.url);
+ widget.update();
+ widgets.set(msgData.port, widget);
+
+ // Add instance tracker stuff
+ } else {
+ widget = widgets.get(msgData.port);
+ }
+
+ if (!widget.isAttached) {
+ // Attach the widget to the main work area
+ // if it's not there
+ app.shell.add(widget, 'main');
+ widget.update();
+ } else {
+ // Refresh the widget
+ widget.update();
+ }
+
+ // Activate the widget
+ app.shell.activateById(widget.id);
+ } else if (msgData.type === 'base_url_request') {
+
+ // Build server url and base subpath.
+ const baseUrl = PageConfig.getBaseUrl();
+ const baseSubpath = PageConfig.getOption('baseUrl');
+ const n = baseUrl.lastIndexOf(baseSubpath)
+ const serverUrl = baseUrl.slice(0, n)
+ comm.send({
+ type: 'base_url_response',
+ server_url: serverUrl,
+ base_subpath: baseSubpath,
+ frontend: "jupyterlab",
+ });
+ }
+ };
+ }
+ );
+}
+
+/**
+ * Initialization data for the jupyterlab-dash extension.
+ */
+const extension: JupyterFrontEndPlugin = {
+ id: 'jupyterlab_dash',
+ autoStart: true,
+ requires: [ILayoutRestorer, INotebookTracker, IConsoleTracker],
+ activate: activate
+};
+
+export default extension;
diff --git a/@plotly/dash-jupyterlab/style/index.css b/@plotly/dash-jupyterlab/style/index.css
new file mode 100644
index 0000000000..898111f52e
--- /dev/null
+++ b/@plotly/dash-jupyterlab/style/index.css
@@ -0,0 +1,6 @@
+.jp-dashWidget iframe {
+ height: 100%;
+ width: 100%;
+ padding: 20px;
+ box-sizing: border-box;
+}
diff --git a/@plotly/dash-jupyterlab/tsconfig.json b/@plotly/dash-jupyterlab/tsconfig.json
new file mode 100644
index 0000000000..6a6738ea31
--- /dev/null
+++ b/@plotly/dash-jupyterlab/tsconfig.json
@@ -0,0 +1,18 @@
+{
+ "compilerOptions": {
+ "declaration": true,
+ "lib": ["es2015", "dom"],
+ "module": "commonjs",
+ "moduleResolution": "node",
+ "noEmitOnError": true,
+ "noUnusedLocals": true,
+ "outDir": "lib",
+ "rootDir": "src",
+ "strict": true,
+ "strictNullChecks": false,
+ "target": "es2015",
+ "types": [],
+ "esModuleInterop": true
+ },
+ "include": ["src/*"]
+}
diff --git a/@plotly/dash-jupyterlab/yarn.lock b/@plotly/dash-jupyterlab/yarn.lock
new file mode 100644
index 0000000000..ffed6f6902
--- /dev/null
+++ b/@plotly/dash-jupyterlab/yarn.lock
@@ -0,0 +1,1310 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@babel/runtime@^7.1.2":
+ version "7.9.2"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06"
+ integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==
+ dependencies:
+ regenerator-runtime "^0.13.4"
+
+"@blueprintjs/core@^3.36.0", "@blueprintjs/core@^3.38.0":
+ version "3.38.0"
+ resolved "https://registry.yarnpkg.com/@blueprintjs/core/-/core-3.38.0.tgz#9b8eb086e22b424153fa0e1483c4c8abd9e6c8e0"
+ integrity sha512-U4yf6B+SbCspNDuvSU2/pl+a80hr9iQgyf2cJ2cOz5It+RV8M+dg9BgB1WaZgqdWgxx/4+A425X5zt2Jw9xalw==
+ dependencies:
+ "@blueprintjs/icons" "^3.24.0"
+ "@types/dom4" "^2.0.1"
+ classnames "^2.2"
+ dom4 "^2.1.5"
+ normalize.css "^8.0.1"
+ popper.js "^1.16.1"
+ react-lifecycles-compat "^3.0.4"
+ react-popper "^1.3.7"
+ react-transition-group "^2.9.0"
+ resize-observer-polyfill "^1.5.1"
+ tslib "~1.13.0"
+
+"@blueprintjs/icons@^3.24.0":
+ version "3.24.0"
+ resolved "https://registry.yarnpkg.com/@blueprintjs/icons/-/icons-3.24.0.tgz#aa7e6042e40806d22f85da8d62990ff0296adcf2"
+ integrity sha512-OvDDI5EUueS1Y3t594iS8LAGoHhLhYjC2GuN/01a85n+ASLSp0jf0/+uix2JeCOj41iTdRRCINbWuRwVQNNGPw==
+ dependencies:
+ classnames "^2.2"
+ tslib "~1.13.0"
+
+"@blueprintjs/select@^3.15.0":
+ version "3.15.2"
+ resolved "https://registry.yarnpkg.com/@blueprintjs/select/-/select-3.15.2.tgz#89237fb129076277be98535a4e3c0e053ad4f83a"
+ integrity sha512-3uY89fSxH4zrvZObDx1SEr/K3KizjgY7Z/005/acFkSN+2GFSD9GU5rmwEQfBDdHk5VjqHEWykD5c8YySH1nDA==
+ dependencies:
+ "@blueprintjs/core" "^3.38.0"
+ classnames "^2.2"
+ tslib "~1.13.0"
+
+"@fortawesome/fontawesome-free@^5.12.0":
+ version "5.13.0"
+ resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.13.0.tgz#fcb113d1aca4b471b709e8c9c168674fbd6e06d9"
+ integrity sha512-xKOeQEl5O47GPZYIMToj6uuA2syyFlq9EMSl2ui0uytjY9xbe8XS0pexNWmxrdcCyNGyDmLyYw5FtKsalBUeOg==
+
+"@jupyterlab/application@^2.0.0 || ^3.0.0":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/application/-/application-3.0.3.tgz#9fc6fe9873842d5a16b205ff9a8bedf76b4456e5"
+ integrity sha512-aJDG5A/Rc1bWnKtoMM77k6hmjZrf0jRioYYFSbZrJ63k0KG27lCYR7EK1XNucRPMw2qz3IolfYJFPf+quYW9Iw==
+ dependencies:
+ "@fortawesome/fontawesome-free" "^5.12.0"
+ "@jupyterlab/apputils" "^3.0.2"
+ "@jupyterlab/coreutils" "^5.0.1"
+ "@jupyterlab/docregistry" "^3.0.3"
+ "@jupyterlab/rendermime" "^3.0.3"
+ "@jupyterlab/rendermime-interfaces" "^3.0.2"
+ "@jupyterlab/services" "^6.0.2"
+ "@jupyterlab/statedb" "^3.0.1"
+ "@jupyterlab/translation" "^3.0.2"
+ "@jupyterlab/ui-components" "^3.0.2"
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/application" "^1.13.1"
+ "@lumino/commands" "^1.12.0"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/messaging" "^1.4.3"
+ "@lumino/polling" "^1.3.3"
+ "@lumino/properties" "^1.2.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/widgets" "^1.16.1"
+
+"@jupyterlab/apputils@^3.0.2":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/apputils/-/apputils-3.0.2.tgz#e45e6b65c9d9dea0d0cbc8074a809ecc960e8bbe"
+ integrity sha512-nTXwpRUPSVR3yevQyGZH6kKsl41Df3nkKCjp8nAqwAPjcwv+nuxLIwnBQP1BFZ+JfIKn18aoZ8ULoH79qasKNg==
+ dependencies:
+ "@jupyterlab/coreutils" "^5.0.1"
+ "@jupyterlab/services" "^6.0.2"
+ "@jupyterlab/settingregistry" "^3.0.1"
+ "@jupyterlab/statedb" "^3.0.1"
+ "@jupyterlab/translation" "^3.0.2"
+ "@jupyterlab/ui-components" "^3.0.2"
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/commands" "^1.12.0"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/domutils" "^1.2.3"
+ "@lumino/messaging" "^1.4.3"
+ "@lumino/properties" "^1.2.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/virtualdom" "^1.8.0"
+ "@lumino/widgets" "^1.16.1"
+ "@types/react" "^17.0.0"
+ buffer "^5.6.0"
+ react "^17.0.1"
+ react-dom "^17.0.1"
+ sanitize-html "~1.27.4"
+ url "^0.11.0"
+
+"@jupyterlab/attachments@^3.0.3":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/attachments/-/attachments-3.0.3.tgz#63294c9bc05fa17bec0144a6ce5e4c575b251fb9"
+ integrity sha512-U6d6NHXcujCefnQuSY/X0cwPpxRDzMzQbHci5uixdWpgt3wJbmTm5tVahgEUZdsTj2ne0gcEsUOeQBeDy6KjBg==
+ dependencies:
+ "@jupyterlab/nbformat" "^3.0.1"
+ "@jupyterlab/observables" "^4.0.1"
+ "@jupyterlab/rendermime" "^3.0.3"
+ "@jupyterlab/rendermime-interfaces" "^3.0.2"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/signaling" "^1.4.3"
+
+"@jupyterlab/cells@^3.0.3":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/cells/-/cells-3.0.3.tgz#ad9508ce4438f18a92d1af1cc1ffeca0b89f632c"
+ integrity sha512-NufBnb7y3BiuXZTckj9U6ZOe0gBRMAaSpLXnC04XqtHHrJziZDc0PuiZHEZS7umMdoB04HKui/7/G9y6zjpN3A==
+ dependencies:
+ "@jupyterlab/apputils" "^3.0.2"
+ "@jupyterlab/attachments" "^3.0.3"
+ "@jupyterlab/codeeditor" "^3.0.2"
+ "@jupyterlab/codemirror" "^3.0.2"
+ "@jupyterlab/coreutils" "^5.0.1"
+ "@jupyterlab/filebrowser" "^3.0.3"
+ "@jupyterlab/nbformat" "^3.0.1"
+ "@jupyterlab/observables" "^4.0.1"
+ "@jupyterlab/outputarea" "^3.0.3"
+ "@jupyterlab/rendermime" "^3.0.3"
+ "@jupyterlab/services" "^6.0.2"
+ "@jupyterlab/ui-components" "^3.0.2"
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/dragdrop" "^1.7.1"
+ "@lumino/messaging" "^1.4.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/virtualdom" "^1.8.0"
+ "@lumino/widgets" "^1.16.1"
+ react "^17.0.1"
+
+"@jupyterlab/codeeditor@^3.0.2":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/codeeditor/-/codeeditor-3.0.2.tgz#45d88eb229f1a57177dc9865f92dcf9cb7f70263"
+ integrity sha512-0pF/B1G+8l87QRcBCOFWieXGVyuJnTYO2Vp8R/jBKV0hqHljAgao40o1mInt1xGGSkTOcAydETbXEt1J4OCWuA==
+ dependencies:
+ "@jupyterlab/coreutils" "^5.0.1"
+ "@jupyterlab/nbformat" "^3.0.1"
+ "@jupyterlab/observables" "^4.0.1"
+ "@jupyterlab/translation" "^3.0.2"
+ "@jupyterlab/ui-components" "^3.0.2"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/dragdrop" "^1.7.1"
+ "@lumino/messaging" "^1.4.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/widgets" "^1.16.1"
+
+"@jupyterlab/codemirror@^3.0.2":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/codemirror/-/codemirror-3.0.2.tgz#931bfb8c68aa3daa08cee5f5335c177878b86298"
+ integrity sha512-i6IhCHDTcTCrNK58I4OjNX9S4erkKu285c47hiJTHxO03YFHOjLtl+i0Ly76R8Qc1+3rpyQxztXve0ZA/K+apQ==
+ dependencies:
+ "@jupyterlab/apputils" "^3.0.2"
+ "@jupyterlab/codeeditor" "^3.0.2"
+ "@jupyterlab/coreutils" "^5.0.1"
+ "@jupyterlab/nbformat" "^3.0.1"
+ "@jupyterlab/observables" "^4.0.1"
+ "@jupyterlab/statusbar" "^3.0.2"
+ "@jupyterlab/translation" "^3.0.2"
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/commands" "^1.12.0"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/polling" "^1.3.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/widgets" "^1.16.1"
+ codemirror "~5.57.0"
+ react "^17.0.1"
+
+"@jupyterlab/console@^2.0.0 || ^3.0.0":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/console/-/console-3.0.3.tgz#f041af90d798258de8e6cd1199173e5e0195268e"
+ integrity sha512-Pk5eLlsDHppEGRXmvbhUdAByFizU8vxue3CNmmLW1dqBulCoCLMRVdBv+MlbMKhrrKQwvRshQ5u1zz8OMDSBkQ==
+ dependencies:
+ "@jupyterlab/apputils" "^3.0.2"
+ "@jupyterlab/cells" "^3.0.3"
+ "@jupyterlab/codeeditor" "^3.0.2"
+ "@jupyterlab/coreutils" "^5.0.1"
+ "@jupyterlab/nbformat" "^3.0.1"
+ "@jupyterlab/observables" "^4.0.1"
+ "@jupyterlab/rendermime" "^3.0.3"
+ "@jupyterlab/services" "^6.0.2"
+ "@jupyterlab/translation" "^3.0.2"
+ "@jupyterlab/ui-components" "^3.0.2"
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/dragdrop" "^1.7.1"
+ "@lumino/messaging" "^1.4.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/widgets" "^1.16.1"
+
+"@jupyterlab/coreutils@^5.0.1":
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/coreutils/-/coreutils-5.0.1.tgz#f50305be93d2e0f1e60546f816d103229a92ba24"
+ integrity sha512-eYjEtZAgoRx0UJY/wfdm7Og+Z1dkcmEjTL5J6MfTROe164F6OCodEFbKECIyVfGt+hoAOiqs3Jg9cPqMw+DA3Q==
+ dependencies:
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/signaling" "^1.4.3"
+ minimist "~1.2.0"
+ moment "^2.24.0"
+ path-browserify "^1.0.0"
+ url-parse "~1.4.7"
+
+"@jupyterlab/docmanager@^3.0.3":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/docmanager/-/docmanager-3.0.3.tgz#41e89a8857500501f4e15679fd8fb0379c4db1dd"
+ integrity sha512-6zId9EWd/X/wlJ7Bhppsdn/5BVuAvMWFSGmv0FtjVPXbPoGN2jZviPwlux4o8cUFS6uj8s0U9eaFfwM5juh9qA==
+ dependencies:
+ "@jupyterlab/apputils" "^3.0.2"
+ "@jupyterlab/coreutils" "^5.0.1"
+ "@jupyterlab/docregistry" "^3.0.3"
+ "@jupyterlab/services" "^6.0.2"
+ "@jupyterlab/statusbar" "^3.0.2"
+ "@jupyterlab/translation" "^3.0.2"
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/messaging" "^1.4.3"
+ "@lumino/properties" "^1.2.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/widgets" "^1.16.1"
+ react "^17.0.1"
+
+"@jupyterlab/docregistry@^3.0.3":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/docregistry/-/docregistry-3.0.3.tgz#7a99ae8ef7f815e4fe07cf457d83c4ee3ca6589f"
+ integrity sha512-9qs8suB5fWpzfR4uUemR2lbEvOH9ROuSWNGZxuO8+mN6XEnI+PLbGDO2WuctGxXsWgkg/6foOxIl6xoceCo9vg==
+ dependencies:
+ "@jupyterlab/apputils" "^3.0.2"
+ "@jupyterlab/codeeditor" "^3.0.2"
+ "@jupyterlab/codemirror" "^3.0.2"
+ "@jupyterlab/coreutils" "^5.0.1"
+ "@jupyterlab/observables" "^4.0.1"
+ "@jupyterlab/rendermime" "^3.0.3"
+ "@jupyterlab/rendermime-interfaces" "^3.0.2"
+ "@jupyterlab/services" "^6.0.2"
+ "@jupyterlab/translation" "^3.0.2"
+ "@jupyterlab/ui-components" "^3.0.2"
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/messaging" "^1.4.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/widgets" "^1.16.1"
+
+"@jupyterlab/filebrowser@^3.0.3":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/filebrowser/-/filebrowser-3.0.3.tgz#ca00522719542324136fae3bc83645c8e0004989"
+ integrity sha512-XlOqvk7XinLadd23W45jI9QqRSpPetxwItyatvMqosR+jtSAuUJBBcFpYfu/TiSItBzKwZ8JuDJYlTJ399O7Wg==
+ dependencies:
+ "@jupyterlab/apputils" "^3.0.2"
+ "@jupyterlab/coreutils" "^5.0.1"
+ "@jupyterlab/docmanager" "^3.0.3"
+ "@jupyterlab/docregistry" "^3.0.3"
+ "@jupyterlab/services" "^6.0.2"
+ "@jupyterlab/statedb" "^3.0.1"
+ "@jupyterlab/statusbar" "^3.0.2"
+ "@jupyterlab/translation" "^3.0.2"
+ "@jupyterlab/ui-components" "^3.0.2"
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/domutils" "^1.2.3"
+ "@lumino/dragdrop" "^1.7.1"
+ "@lumino/messaging" "^1.4.3"
+ "@lumino/polling" "^1.3.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/virtualdom" "^1.8.0"
+ "@lumino/widgets" "^1.16.1"
+ react "^17.0.1"
+
+"@jupyterlab/nbformat@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/nbformat/-/nbformat-3.0.1.tgz#56c18449fb6100dd85f22ee73e252ab27eb17dcd"
+ integrity sha512-cojRKJPoCPei8XiHqGx9IwjMI5llOumrSSYzyBR5qm/NYGOG1mgFwNW2aTf+MoUrZwhpQo8oW27p/W2k2zQAbQ==
+ dependencies:
+ "@lumino/coreutils" "^1.5.3"
+
+"@jupyterlab/notebook@^2.0.0 || ^3.0.0":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/notebook/-/notebook-3.0.3.tgz#c6ad8091650cee226830c5392b6dd7a62186c04d"
+ integrity sha512-ennnJaO+fW4Bk6ibotHIYSkb3M3G8NEr+BvrSfIQizlagcuquvk+INO5m2fVL1G623dRaR+2WqNE0UkxK0dBJw==
+ dependencies:
+ "@jupyterlab/apputils" "^3.0.2"
+ "@jupyterlab/cells" "^3.0.3"
+ "@jupyterlab/codeeditor" "^3.0.2"
+ "@jupyterlab/coreutils" "^5.0.1"
+ "@jupyterlab/docregistry" "^3.0.3"
+ "@jupyterlab/nbformat" "^3.0.1"
+ "@jupyterlab/observables" "^4.0.1"
+ "@jupyterlab/rendermime" "^3.0.3"
+ "@jupyterlab/services" "^6.0.2"
+ "@jupyterlab/statusbar" "^3.0.2"
+ "@jupyterlab/translation" "^3.0.2"
+ "@jupyterlab/ui-components" "^3.0.2"
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/domutils" "^1.2.3"
+ "@lumino/dragdrop" "^1.7.1"
+ "@lumino/messaging" "^1.4.3"
+ "@lumino/properties" "^1.2.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/virtualdom" "^1.8.0"
+ "@lumino/widgets" "^1.16.1"
+ react "^17.0.1"
+
+"@jupyterlab/observables@^4.0.1":
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/observables/-/observables-4.0.1.tgz#d767fc0831a2ae32ef772492fffc77dd0ffaabe9"
+ integrity sha512-f+y7w/eBQfw2AWe9cwa6wj5sqKxJMJYlzjUuSlXfSehKp7SR9s+L3d+JOBmfbBF5WHvaF9XA4cGkZM/HZt8ARQ==
+ dependencies:
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/messaging" "^1.4.3"
+ "@lumino/signaling" "^1.4.3"
+
+"@jupyterlab/outputarea@^3.0.3":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/outputarea/-/outputarea-3.0.3.tgz#4ca2f3857db3611c7ab208a5fef28b35c5b5f53a"
+ integrity sha512-NBB0aJE0IVPNAEiLj8shLKAX9oAsl1oreKcfd/cfYYQFflKHpWTxlzA25NNv7xcfVqT78i704FemW/k/9kPozA==
+ dependencies:
+ "@jupyterlab/apputils" "^3.0.2"
+ "@jupyterlab/nbformat" "^3.0.1"
+ "@jupyterlab/observables" "^4.0.1"
+ "@jupyterlab/rendermime" "^3.0.3"
+ "@jupyterlab/rendermime-interfaces" "^3.0.2"
+ "@jupyterlab/services" "^6.0.2"
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/messaging" "^1.4.3"
+ "@lumino/properties" "^1.2.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/widgets" "^1.16.1"
+ resize-observer-polyfill "^1.5.1"
+
+"@jupyterlab/rendermime-interfaces@^3.0.2":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/rendermime-interfaces/-/rendermime-interfaces-3.0.2.tgz#0af6022045a12286ceb6cd732c2a84e322d26d5f"
+ integrity sha512-BxGXIrGziW+9fvzDF57F4kebJz9p1SWH7Id6VNI21JzCZxJkz7wZpbeUfHzpUiXIh+qogEXEESKKuQg9CzNyqw==
+ dependencies:
+ "@jupyterlab/translation" "^3.0.2"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/widgets" "^1.16.1"
+
+"@jupyterlab/rendermime@^3.0.3":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/rendermime/-/rendermime-3.0.3.tgz#f4a213e7d42e253dc02dcb536b00843690adaf92"
+ integrity sha512-s72CajNpj0UEe4rJVnm5pVbf/jZXc3c5YuXF39BTxpGtsg0uqSysPpYtc1/VjsBoS3R5Bc73P3NIEvOzl6G5cA==
+ dependencies:
+ "@jupyterlab/apputils" "^3.0.2"
+ "@jupyterlab/codemirror" "^3.0.2"
+ "@jupyterlab/coreutils" "^5.0.1"
+ "@jupyterlab/nbformat" "^3.0.1"
+ "@jupyterlab/observables" "^4.0.1"
+ "@jupyterlab/rendermime-interfaces" "^3.0.2"
+ "@jupyterlab/services" "^6.0.2"
+ "@jupyterlab/translation" "^3.0.2"
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/messaging" "^1.4.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/widgets" "^1.16.1"
+ lodash.escape "^4.0.1"
+ marked "^1.1.1"
+
+"@jupyterlab/services@^6.0.2":
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/services/-/services-6.0.2.tgz#ca9f5f8b6c69013d9d52a15e034eb8b7935fdc5e"
+ integrity sha512-J0wghVeqMlG71VXkOhlh3ZcyG787wzz9hSFHMGu/1ATlIDtn9z8dbdCAn92rd12jD1nDX1L2KcyjH5pLT+CKeA==
+ dependencies:
+ "@jupyterlab/coreutils" "^5.0.1"
+ "@jupyterlab/nbformat" "^3.0.1"
+ "@jupyterlab/observables" "^4.0.1"
+ "@jupyterlab/settingregistry" "^3.0.1"
+ "@jupyterlab/statedb" "^3.0.1"
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/polling" "^1.3.3"
+ "@lumino/signaling" "^1.4.3"
+ node-fetch "^2.6.0"
+ ws "^7.2.0"
+
+"@jupyterlab/settingregistry@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/settingregistry/-/settingregistry-3.0.1.tgz#8462a3a142f31641e45ed45cd5b1712fcd5fa99e"
+ integrity sha512-Em/gDygAojndYo7qR4jG0EKCInVQEhTRAnTE/sOYXhwD74Ib3ppFl67N8CvJSr8+jSFhDrLyyVaevI1o6fep9w==
+ dependencies:
+ "@jupyterlab/statedb" "^3.0.1"
+ "@lumino/commands" "^1.12.0"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/signaling" "^1.4.3"
+ ajv "^6.12.3"
+ json5 "^2.1.1"
+
+"@jupyterlab/statedb@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/statedb/-/statedb-3.0.1.tgz#8b6c757e20a8072c5276019a07c65725a9829aa9"
+ integrity sha512-+00qBVlboCz945o2CFXrCUJ9oyKcAviA7+dlnE92N5UWBelp8dulMAgWNIW8Uew5O0mvbb1dVAcN9bnbLphGfw==
+ dependencies:
+ "@lumino/commands" "^1.12.0"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/properties" "^1.2.3"
+ "@lumino/signaling" "^1.4.3"
+
+"@jupyterlab/statusbar@^3.0.2":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/statusbar/-/statusbar-3.0.2.tgz#135ea22d62b79de3e29657abd9569297bbe39203"
+ integrity sha512-71sx7GRR4FGJExBjBB8TMD63h5wv09aRLO+cQj3xMygG47EX9TaW2Q8zAq4ZQM400UNAh/NGVmr7P7EBdH8jhg==
+ dependencies:
+ "@jupyterlab/apputils" "^3.0.2"
+ "@jupyterlab/codeeditor" "^3.0.2"
+ "@jupyterlab/coreutils" "^5.0.1"
+ "@jupyterlab/services" "^6.0.2"
+ "@jupyterlab/translation" "^3.0.2"
+ "@jupyterlab/ui-components" "^3.0.2"
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/messaging" "^1.4.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/widgets" "^1.16.1"
+ csstype "~3.0.3"
+ react "^17.0.1"
+ typestyle "^2.0.4"
+
+"@jupyterlab/translation@^3.0.2":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/translation/-/translation-3.0.2.tgz#478c1eb70c0f730cf1061a92443e5371a823295c"
+ integrity sha512-OAA3+aD5pxXroB2z3M0xXWRJn246aooAXiPV7lQFFN1IR2Aovb+sBB61TQr+sjqDpHfVA9qADC65RIsr3XOmoA==
+ dependencies:
+ "@jupyterlab/coreutils" "^5.0.1"
+ "@jupyterlab/services" "^6.0.2"
+ "@jupyterlab/statedb" "^3.0.1"
+ "@lumino/coreutils" "^1.5.3"
+
+"@jupyterlab/ui-components@^3.0.2":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@jupyterlab/ui-components/-/ui-components-3.0.2.tgz#f6b87e352446a143d5d76c69d3c7796787605e65"
+ integrity sha512-QfTMwAMDfHNtJZ0+zCeW8EXPlcPyGKooiMCmZXd1onFIxSpg/mdwV231uiakwARt3on+XBT8JrMgoSf03ywV6w==
+ dependencies:
+ "@blueprintjs/core" "^3.36.0"
+ "@blueprintjs/select" "^3.15.0"
+ "@jupyterlab/coreutils" "^5.0.1"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/virtualdom" "^1.8.0"
+ "@lumino/widgets" "^1.16.1"
+ react "^17.0.1"
+ react-dom "^17.0.1"
+ typestyle "^2.0.4"
+
+"@lumino/algorithm@^1.3.3":
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/@lumino/algorithm/-/algorithm-1.3.3.tgz#fdf4daa407a1ce6f233e173add6a2dda0c99eef4"
+ integrity sha512-I2BkssbOSLq3rDjgAC3fzf/zAIwkRUnAh60MO0lYcaFdSGyI15w4K3gwZHGIO0p9cKEiNHLXKEODGmOjMLOQ3g==
+
+"@lumino/application@^1.13.1":
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/@lumino/application/-/application-1.15.0.tgz#8b7e5142bc6d38d1300164507e0a214a55ea6d05"
+ integrity sha512-W/12+UFk1oBdJ793L3NegQvt0T355k64fPmDVzPhM48TW8vM/0tDc+zBx1KShn52eRMTrVBDc2cG5t6C5/XF1w==
+ dependencies:
+ "@lumino/commands" "^1.12.0"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/widgets" "^1.18.0"
+
+"@lumino/collections@^1.3.3":
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/@lumino/collections/-/collections-1.3.3.tgz#fa95c826b93ee6e24b3c4b07c8f595312525f8cc"
+ integrity sha512-vN3GSV5INkgM6tMLd+WqTgaPnQNTY7L/aFUtTOC8TJQm+vg1eSmR4fNXsoGHM3uA85ctSJThvdZr5triu1Iajg==
+ dependencies:
+ "@lumino/algorithm" "^1.3.3"
+
+"@lumino/commands@^1.12.0":
+ version "1.12.0"
+ resolved "https://registry.yarnpkg.com/@lumino/commands/-/commands-1.12.0.tgz#63a744d034d8bc524455e47f06c0ac5f2eb6ec38"
+ integrity sha512-5TFlhDzZk1X8rCBjhh0HH3j6CcJ03mx2Pd/1rGa7MB5R+3+yYYk+gTlfHRqsxdehNRmiISaHRSrMnW8bynW7ZQ==
+ dependencies:
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/domutils" "^1.2.3"
+ "@lumino/keyboard" "^1.2.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/virtualdom" "^1.8.0"
+
+"@lumino/coreutils@^1.5.3":
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/@lumino/coreutils/-/coreutils-1.5.3.tgz#89dd7b7f381642a1bf568910c5b62c7bde705d71"
+ integrity sha512-G72jJ6sgOwAUuilz+cri7LpHIJxllK+qz+YZUC3fyyWHK7oRlZemcc43jZAVE+tagTdMxKYSQWNIVzM5lI8sWw==
+
+"@lumino/disposable@^1.4.3":
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/@lumino/disposable/-/disposable-1.4.3.tgz#0a69b15cc5a1e506f93bb390ac44aae338da3c36"
+ integrity sha512-zKQ9N2AEGcYpG6PJkeMWQXvoXU9w1ocji78z+fboM/SmSgtOIVGeQt3fZeldymf0XrlOPpNXs1ZFg54yWUMnXA==
+ dependencies:
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/signaling" "^1.4.3"
+
+"@lumino/domutils@^1.2.3":
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/@lumino/domutils/-/domutils-1.2.3.tgz#7e8e549a97624bfdbd4dd95ae4d1e30b87799822"
+ integrity sha512-SEi8WZSy+DWMkL5CfAY78MHbi3x83AVmRFxjs9+A6qsFPde+Hr1I4DNtLsSDmfAWsobHHgBnjyNp2ZkQEq0IEA==
+
+"@lumino/dragdrop@^1.7.1":
+ version "1.7.1"
+ resolved "https://registry.yarnpkg.com/@lumino/dragdrop/-/dragdrop-1.7.1.tgz#1466206d43a64dadca383e0b9a87cc8a14c8c59b"
+ integrity sha512-IeSSOTmpqBSWz+EVsbGVeHe/KIaHaUsQXZ4BJCEbCKgNGHbqMfUOtlneiKq7rEhZGF4wYs7gWWjNhMVZbUGO9Q==
+ dependencies:
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+
+"@lumino/keyboard@^1.2.3":
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/@lumino/keyboard/-/keyboard-1.2.3.tgz#594c73233636d85ed035b1a37a095acf956cfe8c"
+ integrity sha512-ibS0sz0VABeuJXx2JVSz36sUBMUOcQNCNPybVhwzN/GkJFs0dnDKluMu+3Px0tkB2y33bGPZU/RLZY1Xj/faEA==
+
+"@lumino/messaging@^1.4.3":
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/@lumino/messaging/-/messaging-1.4.3.tgz#75a1901f53086c7c0e978a63cb784eae5cc59f3f"
+ integrity sha512-wa2Pj2KOuLNLS2n0wVBzUVFGbvjL1FLbuCOAUEYfN6xXVleqqtGGzd08uTF7ebu01KCO3VQ38+dkvoaM/C2qPw==
+ dependencies:
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/collections" "^1.3.3"
+
+"@lumino/polling@^1.3.3":
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/@lumino/polling/-/polling-1.3.3.tgz#6336638cb9ba2f4f4c3ef2529c7f260abbd25148"
+ integrity sha512-uMRi6sPRnKW8m38WUY3qox1jxwzpvceafUbDJATCwyrZ48+YoY5Fxfmd9dqwioHS1aq9np5c6L35a9ZGuS0Maw==
+ dependencies:
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/signaling" "^1.4.3"
+
+"@lumino/properties@^1.2.3":
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/@lumino/properties/-/properties-1.2.3.tgz#10675e554e4a9dcc4022de01875fd51f33e2c785"
+ integrity sha512-dbS9V/L+RpQoRjxHMAGh1JYoXaLA6F7xkVbg/vmYXqdXZ7DguO5C3Qteu9tNp7Z7Q31TqFWUCrniTI9UJiJCoQ==
+
+"@lumino/signaling@^1.4.3":
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/@lumino/signaling/-/signaling-1.4.3.tgz#d29f7f542fdcd70b91ca275d3ca793ae21cebf6a"
+ integrity sha512-6clc8SMcH0tyKXIX31xw6sxjxJl5hj4YRd1DTHTS62cegQ0FkO8JjJeuv+Nc1pgTg6nEAf65aSOHpUdsFHDAvQ==
+ dependencies:
+ "@lumino/algorithm" "^1.3.3"
+
+"@lumino/virtualdom@^1.8.0":
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/@lumino/virtualdom/-/virtualdom-1.8.0.tgz#42ea5778e3870e4961ea36697b28aab997c75fa6"
+ integrity sha512-X/1b8b7TxB9tb4+xQiS8oArcA/AK7NBZrsg2dzu/gHa3JC45R8nzQ+0tObD8Nd0gF/e9w9Ps9M62rLfefcbbKw==
+ dependencies:
+ "@lumino/algorithm" "^1.3.3"
+
+"@lumino/widgets@^1.16.1", "@lumino/widgets@^1.18.0":
+ version "1.18.0"
+ resolved "https://registry.yarnpkg.com/@lumino/widgets/-/widgets-1.18.0.tgz#fa8ce727126a1e91b9f3ba78e08425115046e3ac"
+ integrity sha512-8i10njkGjctuXrbaoV2dRI2rVUaL7eA5djtHj36pX9cALwciEPHNecF6hoZXmQ4ODv6LTwhr87Uz8LT4Aan77A==
+ dependencies:
+ "@lumino/algorithm" "^1.3.3"
+ "@lumino/commands" "^1.12.0"
+ "@lumino/coreutils" "^1.5.3"
+ "@lumino/disposable" "^1.4.3"
+ "@lumino/domutils" "^1.2.3"
+ "@lumino/dragdrop" "^1.7.1"
+ "@lumino/keyboard" "^1.2.3"
+ "@lumino/messaging" "^1.4.3"
+ "@lumino/properties" "^1.2.3"
+ "@lumino/signaling" "^1.4.3"
+ "@lumino/virtualdom" "^1.8.0"
+
+"@types/dom4@^2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@types/dom4/-/dom4-2.0.1.tgz#506d5781b9bcab81bd9a878b198aec7dee2a6033"
+ integrity sha512-kSkVAvWmMZiCYtvqjqQEwOmvKwcH+V4uiv3qPQ8pAh1Xl39xggGEo8gHUqV4waYGHezdFw0rKBR8Jt0CrQSDZA==
+
+"@types/prop-types@*":
+ version "15.7.3"
+ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
+ integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
+
+"@types/react@^17.0.0":
+ version "17.0.0"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.0.tgz#5af3eb7fad2807092f0046a1302b7823e27919b8"
+ integrity sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw==
+ dependencies:
+ "@types/prop-types" "*"
+ csstype "^3.0.2"
+
+ajv@^6.12.3:
+ version "6.12.6"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+ dependencies:
+ fast-deep-equal "^3.1.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
+ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+ dependencies:
+ color-convert "^1.9.0"
+
+balanced-match@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+ integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+
+base64-js@^1.3.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
+ integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+buffer@^5.6.0:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
+ integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
+ dependencies:
+ base64-js "^1.3.1"
+ ieee754 "^1.1.13"
+
+chalk@^2.4.2:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+ integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+classnames@^2.2:
+ version "2.2.6"
+ resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
+ integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
+
+codemirror@~5.57.0:
+ version "5.57.0"
+ resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.57.0.tgz#d26365b72f909f5d2dbb6b1209349ca1daeb2d50"
+ integrity sha512-WGc6UL7Hqt+8a6ZAsj/f1ApQl3NPvHY/UQSzG6fB6l4BjExgVdhFaxd7mRTw1UCiYe/6q86zHP+kfvBQcZGvUg==
+
+color-convert@^1.9.0:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+ dependencies:
+ color-name "1.1.3"
+
+color-name@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+ integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+
+create-react-context@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.3.0.tgz#546dede9dc422def0d3fc2fe03afe0bc0f4f7d8c"
+ integrity sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==
+ dependencies:
+ gud "^1.0.0"
+ warning "^4.0.3"
+
+csstype@2.6.9:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.9.tgz#05141d0cd557a56b8891394c1911c40c8a98d098"
+ integrity sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==
+
+csstype@^3.0.2, csstype@~3.0.3:
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.6.tgz#865d0b5833d7d8d40f4e5b8a6d76aea3de4725ef"
+ integrity sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw==
+
+deep-equal@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a"
+ integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==
+ dependencies:
+ is-arguments "^1.0.4"
+ is-date-object "^1.0.1"
+ is-regex "^1.0.4"
+ object-is "^1.0.1"
+ object-keys "^1.1.1"
+ regexp.prototype.flags "^1.2.0"
+
+define-properties@^1.1.2, define-properties@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
+ integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
+ dependencies:
+ object-keys "^1.0.12"
+
+dom-helpers@^3.4.0:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8"
+ integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+
+dom-serializer@^1.0.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.2.0.tgz#3433d9136aeb3c627981daa385fc7f32d27c48f1"
+ integrity sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==
+ dependencies:
+ domelementtype "^2.0.1"
+ domhandler "^4.0.0"
+ entities "^2.0.0"
+
+dom4@^2.1.5:
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/dom4/-/dom4-2.1.5.tgz#f98a94eb67b340f0fa5b42b0ee9c38cda035428e"
+ integrity sha512-gJbnVGq5zaBUY0lUh0LUEVGYrtN75Ks8ZwpwOYvnVFrKy/qzXK4R/1WuLIFExWj/tBxbRAkTzZUGJHXmqsBNjQ==
+
+domelementtype@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d"
+ integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==
+
+domelementtype@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.1.0.tgz#a851c080a6d1c3d94344aed151d99f669edf585e"
+ integrity sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==
+
+domhandler@^3.0.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.3.0.tgz#6db7ea46e4617eb15cf875df68b2b8524ce0037a"
+ integrity sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==
+ dependencies:
+ domelementtype "^2.0.1"
+
+domhandler@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.0.0.tgz#01ea7821de996d85f69029e81fa873c21833098e"
+ integrity sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==
+ dependencies:
+ domelementtype "^2.1.0"
+
+domutils@^2.0.0:
+ version "2.4.4"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.4.4.tgz#282739c4b150d022d34699797369aad8d19bbbd3"
+ integrity sha512-jBC0vOsECI4OMdD0GC9mGn7NXPLb+Qt6KW1YDQzeQYRUFKmNG8lh7mO5HiELfr+lLQE7loDVI4QcAxV80HS+RA==
+ dependencies:
+ dom-serializer "^1.0.1"
+ domelementtype "^2.0.1"
+ domhandler "^4.0.0"
+
+entities@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4"
+ integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==
+
+es-abstract@^1.17.0-next.1, es-abstract@^1.17.5:
+ version "1.17.5"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9"
+ integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==
+ dependencies:
+ es-to-primitive "^1.2.1"
+ function-bind "^1.1.1"
+ has "^1.0.3"
+ has-symbols "^1.0.1"
+ is-callable "^1.1.5"
+ is-regex "^1.0.5"
+ object-inspect "^1.7.0"
+ object-keys "^1.1.1"
+ object.assign "^4.1.0"
+ string.prototype.trimleft "^2.1.1"
+ string.prototype.trimright "^2.1.1"
+
+es-to-primitive@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
+ integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
+ dependencies:
+ is-callable "^1.1.4"
+ is-date-object "^1.0.1"
+ is-symbol "^1.0.2"
+
+escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+
+fast-deep-equal@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4"
+ integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==
+
+fast-json-stable-stringify@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+ integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+free-style@3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/free-style/-/free-style-3.1.0.tgz#4e2996029534e6b1731611d843437b9e2f473f08"
+ integrity sha512-vJujYSIyT30iDoaoeigNAxX4yB1RUrh+N2ZMhIElMr3BvCuGXOw7XNJMEEJkDUeamK2Rnb/IKFGKRKlTWIGRWA==
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+
+function-bind@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+ integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+
+glob@^7.1.3:
+ version "7.1.6"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
+ integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+gud@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
+ integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
+
+has-symbols@^1.0.0, has-symbols@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
+ integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
+
+has@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+ integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+ dependencies:
+ function-bind "^1.1.1"
+
+htmlparser2@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-4.1.0.tgz#9a4ef161f2e4625ebf7dfbe6c0a2f52d18a59e78"
+ integrity sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==
+ dependencies:
+ domelementtype "^2.0.1"
+ domhandler "^3.0.0"
+ domutils "^2.0.0"
+ entities "^2.0.0"
+
+ieee754@^1.1.13:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
+ integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+is-arguments@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3"
+ integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==
+
+is-callable@^1.1.4, is-callable@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab"
+ integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==
+
+is-date-object@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
+ integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
+
+is-regex@^1.0.4, is-regex@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae"
+ integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==
+ dependencies:
+ has "^1.0.3"
+
+is-symbol@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
+ integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
+ dependencies:
+ has-symbols "^1.0.1"
+
+"js-tokens@^3.0.0 || ^4.0.0":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+ integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+ integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json5@^2.1.1:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43"
+ integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==
+ dependencies:
+ minimist "^1.2.5"
+
+lodash.escape@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98"
+ integrity sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=
+
+lodash@^4.17.15:
+ version "4.17.20"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
+ integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
+
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+ integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+ dependencies:
+ js-tokens "^3.0.0 || ^4.0.0"
+
+marked@^1.1.1:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/marked/-/marked-1.2.7.tgz#6e14b595581d2319cdcf033a24caaf41455a01fb"
+ integrity sha512-No11hFYcXr/zkBvL6qFmAp1z6BKY3zqLMHny/JN/ey+al7qwCM2+CMBL9BOgqMxZU36fz4cCWfn2poWIf7QRXA==
+
+minimatch@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+ integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimist@^1.2.5, minimist@~1.2.0:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
+ integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+
+moment@^2.24.0:
+ version "2.24.0"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
+ integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
+
+node-fetch@^2.6.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
+ integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
+
+normalize.css@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-8.0.1.tgz#9b98a208738b9cc2634caacbc42d131c97487bf3"
+ integrity sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==
+
+object-assign@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
+
+object-inspect@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67"
+ integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==
+
+object-is@^1.0.1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6"
+ integrity sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.5"
+
+object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+ integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
+
+object.assign@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
+ integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
+ dependencies:
+ define-properties "^1.1.2"
+ function-bind "^1.1.1"
+ has-symbols "^1.0.0"
+ object-keys "^1.0.11"
+
+once@^1.3.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+ dependencies:
+ wrappy "1"
+
+parse-srcset@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1"
+ integrity sha1-8r0iH2zJcKk42IVWq8WJyqqiveE=
+
+path-browserify@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
+ integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+
+popper.js@^1.14.4, popper.js@^1.16.1:
+ version "1.16.1"
+ resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
+ integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==
+
+postcss@^7.0.27:
+ version "7.0.35"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.35.tgz#d2be00b998f7f211d8a276974079f2e92b970e24"
+ integrity sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==
+ dependencies:
+ chalk "^2.4.2"
+ source-map "^0.6.1"
+ supports-color "^6.1.0"
+
+prettier@2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4"
+ integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==
+
+prop-types@^15.6.1, prop-types@^15.6.2:
+ version "15.7.2"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
+ integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
+ dependencies:
+ loose-envify "^1.4.0"
+ object-assign "^4.1.1"
+ react-is "^16.8.1"
+
+punycode@1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+ integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=
+
+punycode@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+ integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+
+querystring@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+ integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
+
+querystringify@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
+ integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==
+
+react-dom@^17.0.1:
+ version "17.0.1"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.1.tgz#1de2560474ec9f0e334285662ede52dbc5426fc6"
+ integrity sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug==
+ dependencies:
+ loose-envify "^1.1.0"
+ object-assign "^4.1.1"
+ scheduler "^0.20.1"
+
+react-is@^16.8.1:
+ version "16.13.1"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
+ integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+
+react-lifecycles-compat@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
+ integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
+
+react-popper@^1.3.7:
+ version "1.3.7"
+ resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.3.7.tgz#f6a3471362ef1f0d10a4963673789de1baca2324"
+ integrity sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+ create-react-context "^0.3.0"
+ deep-equal "^1.1.1"
+ popper.js "^1.14.4"
+ prop-types "^15.6.1"
+ typed-styles "^0.0.7"
+ warning "^4.0.2"
+
+react-transition-group@^2.9.0:
+ version "2.9.0"
+ resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
+ integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==
+ dependencies:
+ dom-helpers "^3.4.0"
+ loose-envify "^1.4.0"
+ prop-types "^15.6.2"
+ react-lifecycles-compat "^3.0.4"
+
+react@^17.0.1:
+ version "17.0.1"
+ resolved "https://registry.yarnpkg.com/react/-/react-17.0.1.tgz#6e0600416bd57574e3f86d92edba3d9008726127"
+ integrity sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==
+ dependencies:
+ loose-envify "^1.1.0"
+ object-assign "^4.1.1"
+
+regenerator-runtime@^0.13.4:
+ version "0.13.5"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
+ integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==
+
+regexp.prototype.flags@^1.2.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75"
+ integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.0-next.1"
+
+requires-port@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
+ integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
+
+resize-observer-polyfill@^1.5.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
+ integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
+
+rimraf@3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+ dependencies:
+ glob "^7.1.3"
+
+sanitize-html@~1.27.4:
+ version "1.27.5"
+ resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.27.5.tgz#6c8149462adb23e360e1bb71cc0bae7f08c823c7"
+ integrity sha512-M4M5iXDAUEcZKLXkmk90zSYWEtk5NH3JmojQxKxV371fnMh+x9t1rqdmXaGoyEHw3z/X/8vnFhKjGL5xFGOJ3A==
+ dependencies:
+ htmlparser2 "^4.1.0"
+ lodash "^4.17.15"
+ parse-srcset "^1.0.2"
+ postcss "^7.0.27"
+
+scheduler@^0.20.1:
+ version "0.20.1"
+ resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.1.tgz#da0b907e24026b01181ecbc75efdc7f27b5a000c"
+ integrity sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw==
+ dependencies:
+ loose-envify "^1.1.0"
+ object-assign "^4.1.1"
+
+source-map@^0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+string.prototype.trimend@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
+ integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.5"
+
+string.prototype.trimleft@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc"
+ integrity sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.5"
+ string.prototype.trimstart "^1.0.0"
+
+string.prototype.trimright@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3"
+ integrity sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.5"
+ string.prototype.trimend "^1.0.0"
+
+string.prototype.trimstart@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54"
+ integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.5"
+
+supports-color@^5.3.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+ dependencies:
+ has-flag "^3.0.0"
+
+supports-color@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3"
+ integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==
+ dependencies:
+ has-flag "^3.0.0"
+
+tslib@~1.13.0:
+ version "1.13.0"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
+ integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
+
+typed-styles@^0.0.7:
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9"
+ integrity sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==
+
+typescript@3.9.3:
+ version "3.9.3"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.3.tgz#d3ac8883a97c26139e42df5e93eeece33d610b8a"
+ integrity sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==
+
+typestyle@^2.0.4:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/typestyle/-/typestyle-2.1.0.tgz#7c5cc567de72cd8bfb686813150b92791aaa7636"
+ integrity sha512-6uCYPdG4xWLeEcl9O0GtNFnNGhami+irKiLsXSuvWHC/aTS7wdj49WeikWAKN+xHN3b1hm+9v0svwwgSBhCsNA==
+ dependencies:
+ csstype "2.6.9"
+ free-style "3.1.0"
+
+uri-js@^4.2.2:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
+ integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+ dependencies:
+ punycode "^2.1.0"
+
+url-parse@~1.4.7:
+ version "1.4.7"
+ resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278"
+ integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==
+ dependencies:
+ querystringify "^2.1.1"
+ requires-port "^1.0.0"
+
+url@^0.11.0:
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
+ integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=
+ dependencies:
+ punycode "1.3.2"
+ querystring "0.2.0"
+
+warning@^4.0.2, warning@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
+ integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
+ dependencies:
+ loose-envify "^1.0.0"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+
+ws@^7.2.0:
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46"
+ integrity sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 24832c71cf..71307a3240 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,12 @@ This project adheres to [Semantic Versioning](https://semver.org/).
## [UNRELEASED]
+## Added
+
+- [#2530](https://github.com/plotly/dash/pull/2530) Merge JupyterDash repository with Dash.
+ - Add `jupyter_mode` argument to `app.run`, defaults to `inline` and configurable via `jupyter_dash.default_mode`.
+ - Add prefixed arguments from `JupyterDash` to `app.run`: `jupyter_width`, `jupyter_height`, `jupyter_server_url`.
+
## Fixed
- [#2555](https://github.com/plotly/dash/pull/2555) Fix browser back button when removing one of multiple location components from layout, fix [#1312](https://github.com/plotly/dash/issues/1312)
diff --git a/MANIFEST.in b/MANIFEST.in
index 0389382d65..960033c813 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -10,3 +10,5 @@ include dash/html/*
include dash/dash_table/*
include dash/dash-renderer/build/*.js
include dash/dash-renderer/build/*.map
+include dash/labextension/dist/dash-jupyterlab.tgz
+include dash/labextension/package.json
diff --git a/dash/__init__.py b/dash/__init__.py
index 871da672d0..f46d6f77e1 100644
--- a/dash/__init__.py
+++ b/dash/__init__.py
@@ -39,5 +39,17 @@
page_container,
)
from ._patch import Patch # noqa: F401,E402
+from ._jupyter import jupyter_dash # noqa: F401,E402
ctx = callback_context
+
+
+def _jupyter_nbextension_paths():
+ return [
+ {
+ "section": "notebook",
+ "src": "nbextension",
+ "dest": "dash",
+ "require": "dash/main",
+ }
+ ]
diff --git a/dash/_jupyter.py b/dash/_jupyter.py
new file mode 100644
index 0000000000..44a582b6b2
--- /dev/null
+++ b/dash/_jupyter.py
@@ -0,0 +1,495 @@
+import asyncio
+import io
+import inspect
+import logging
+import os
+import queue
+import uuid
+import re
+import sys
+import threading
+import time
+import traceback
+
+from typing_extensions import Literal
+
+from werkzeug.serving import make_server
+
+
+try:
+ from IPython import get_ipython
+ from IPython.display import IFrame, display, Javascript
+ from IPython.core.display import HTML
+ from IPython.core.ultratb import FormattedTB
+ from retrying import retry
+ from ansi2html import Ansi2HTMLConverter
+ from ipykernel.comm import Comm
+ import nest_asyncio
+
+ import requests
+
+ _dash_comm = Comm(target_name="dash")
+ _dep_installed = True
+except ImportError:
+ _dep_installed = False
+ _dash_comm = None
+ get_ipython = lambda: None
+
+JupyterDisplayMode = Literal["inline", "external", "jupyterlab", "tab", "_none"]
+
+
+def _get_skip(error: Exception):
+ tb = traceback.format_exception(type(error), error, error.__traceback__)
+ skip = 0
+ for i, line in enumerate(tb):
+ if "%% callback invoked %%" in line:
+ skip = i + 1
+ break
+ return skip
+
+
+def _custom_formatargvalues(
+ args,
+ varargs,
+ varkw,
+ locals, # pylint: disable=W0622
+ formatarg=str,
+ formatvarargs=lambda name: "*" + name,
+ formatvarkw=lambda name: "**" + name,
+ formatvalue=lambda value: "=" + repr(value),
+):
+
+ """Copied from inspect.formatargvalues, modified to place function
+ arguments on separate lines"""
+
+ # pylint: disable=W0622
+ def convert(name, locals=locals, formatarg=formatarg, formatvalue=formatvalue):
+ return formatarg(name) + formatvalue(locals[name])
+
+ specs = []
+
+ # pylint: disable=C0200
+ for i in range(len(args)):
+ specs.append(convert(args[i]))
+ if varargs:
+ specs.append(formatvarargs(varargs) + formatvalue(locals[varargs]))
+ if varkw:
+ specs.append(formatvarkw(varkw) + formatvalue(locals[varkw]))
+
+ result = "(" + ", ".join(specs) + ")"
+
+ if len(result) < 40:
+ return result
+ # Put each arg on a separate line
+ return "(\n " + ",\n ".join(specs) + "\n)"
+
+
+_jupyter_config = {}
+
+_caller = {}
+
+
+def _send_jupyter_config_comm_request():
+ # If running in an ipython kernel,
+ # request that the front end extension send us the notebook server base URL
+ if get_ipython() is not None:
+ if _dash_comm.kernel is not None:
+ _caller["parent"] = _dash_comm.kernel.get_parent()
+ _dash_comm.send({"type": "base_url_request"})
+
+
+def _jupyter_comm_response_received():
+ return bool(_jupyter_config)
+
+
+def _request_jupyter_config(timeout=2):
+ # Heavily inspired by implementation of CaptureExecution in the
+ if _dash_comm.kernel is None:
+ # Not in jupyter setting
+ return
+
+ _send_jupyter_config_comm_request()
+
+ # Get shell and kernel
+ shell = get_ipython()
+ kernel = shell.kernel
+
+ # Start capturing shell events to replay later
+ captured_events = []
+
+ def capture_event(stream, ident, parent):
+ captured_events.append((stream, ident, parent))
+
+ kernel.shell_handlers["execute_request"] = capture_event
+
+ # increment execution count to avoid collision error
+ shell.execution_count += 1
+
+ # Allow kernel to execute comms until we receive the jupyter configuration comm
+ # response
+ t0 = time.time()
+ while True:
+ if (time.time() - t0) > timeout:
+ # give up
+ raise EnvironmentError(
+ "Unable to communicate with the jupyter_dash notebook or JupyterLab \n"
+ "extension required to infer Jupyter configuration."
+ )
+ if _jupyter_comm_response_received():
+ break
+
+ if asyncio.iscoroutinefunction(kernel.do_one_iteration):
+ loop = asyncio.get_event_loop()
+ nest_asyncio.apply(loop)
+ loop.run_until_complete(kernel.do_one_iteration())
+ else:
+ kernel.do_one_iteration()
+
+ # Stop capturing events, revert the kernel shell handler to the default
+ # execute_request behavior
+ kernel.shell_handlers["execute_request"] = kernel.execute_request
+
+ # Replay captured events
+ # need to flush before replaying so messages show up in current cell not
+ # replay cells
+ sys.stdout.flush()
+ sys.stderr.flush()
+
+ for stream, ident, parent in captured_events:
+ # Using kernel.set_parent is the key to getting the output of the replayed
+ # events to show up in the cells that were captured instead of the current cell
+ kernel.set_parent(ident, parent)
+ kernel.execute_request(stream, ident, parent)
+
+
+class JupyterDash:
+ """
+ Interact with dash apps inside jupyter notebooks.
+ """
+
+ default_mode: JupyterDisplayMode = "inline"
+ alive_token = str(uuid.uuid4())
+ inline_exceptions: bool = True
+
+ _servers = {}
+
+ def infer_jupyter_proxy_config(self):
+ """
+ Infer the current Jupyter server configuration. This will detect
+ the proper request_pathname_prefix and server_url values to use when
+ displaying Dash apps.Dash requests will be routed through the proxy.
+
+ Requirements:
+
+ In the classic notebook, this method requires the `dash` nbextension
+ which should be installed automatically with the installation of the
+ jupyter-dash Python package. You can see what notebook extensions are installed
+ by running the following command:
+ $ jupyter nbextension list
+
+ In JupyterLab, this method requires the `@plotly/dash-jupyterlab` labextension. This
+ extension should be installed automatically with the installation of the
+ jupyter-dash Python package, but JupyterLab must be allowed to rebuild before
+ the extension is activated (JupyterLab should automatically detect the
+ extension and produce a popup dialog asking for permission to rebuild). You can
+ see what JupyterLab extensions are installed by running the following command:
+ $ jupyter labextension list
+ """
+ if not self.in_ipython or self.in_colab:
+ # No op when not running in a Jupyter context or when in Colab
+ return
+ # Assume classic notebook or JupyterLab
+ _request_jupyter_config()
+
+ def __init__(self):
+ self.in_ipython = get_ipython() is not None
+ self.in_colab = "google.colab" in sys.modules
+
+ if _dep_installed and self.in_ipython and _dash_comm:
+
+ @_dash_comm.on_msg
+ def _receive_message(msg):
+ prev_parent = _caller.get("parent")
+ if prev_parent and prev_parent != _dash_comm.kernel.get_parent():
+ _dash_comm.kernel.set_parent(
+ [prev_parent["header"]["session"]], prev_parent
+ )
+ del _caller["parent"]
+
+ msg_data = msg.get("content").get("data")
+ msg_type = msg_data.get("type", None)
+ if msg_type == "base_url_response":
+ _jupyter_config.update(msg_data)
+
+ # pylint: disable=too-many-locals, too-many-branches, too-many-statements
+ def run_app(
+ self,
+ app,
+ mode: JupyterDisplayMode = None,
+ width="100%",
+ height=650,
+ host="127.0.0.1",
+ port=8050,
+ server_url=None,
+ ):
+ """
+ :type app: dash.Dash
+ :param mode: How to display the app on the notebook. One Of:
+ ``"external"``: The URL of the app will be displayed in the notebook
+ output cell. Clicking this URL will open the app in the default
+ web browser.
+ ``"inline"``: The app will be displayed inline in the notebook output cell
+ in an iframe.
+ ``"jupyterlab"``: The app will be displayed in a dedicate tab in the
+ JupyterLab interface. Requires JupyterLab and the `jupyterlab-dash`
+ extension.
+ :param width: Width of app when displayed using mode="inline"
+ :param height: Height of app when displayed using mode="inline"
+ :param host: Host of the server
+ :param port: Port used by the server
+ :param server_url: Use if a custom url is required to display the app.
+ """
+ # Validate / infer display mode
+ if self.in_colab:
+ valid_display_values = ["inline", "external"]
+ else:
+ valid_display_values = ["jupyterlab", "inline", "external", "tab", "_none"]
+
+ if mode is None:
+ mode = self.default_mode
+ elif not isinstance(mode, str):
+ raise ValueError(
+ f"The mode argument must be a string\n"
+ f" Received value of type {type(mode)}: {repr(mode)}"
+ )
+ else:
+ mode = mode.lower()
+ if mode not in valid_display_values:
+ raise ValueError(
+ f"Invalid display argument {mode}\n"
+ f" Valid arguments: {valid_display_values}"
+ )
+
+ # Terminate any existing server using this port
+ old_server = self._servers.get((host, port))
+ if old_server:
+ old_server.shutdown()
+ del self._servers[(host, port)]
+
+ # Configure pathname prefix
+ if "base_subpath" in _jupyter_config:
+ requests_pathname_prefix = (
+ _jupyter_config["base_subpath"].rstrip("/") + "/proxy/{port}/"
+ )
+ else:
+ requests_pathname_prefix = app.config.get("requests_pathname_prefix", None)
+
+ if requests_pathname_prefix is not None:
+ requests_pathname_prefix = requests_pathname_prefix.format(port=port)
+ else:
+ requests_pathname_prefix = "/"
+
+ # FIXME Move config initialization to main dash __init__
+ # low-level setter to circumvent Dash's config locking
+ # normally it's unsafe to alter requests_pathname_prefix this late, but
+ # Jupyter needs some unusual behavior.
+ dict.__setitem__(
+ app.config, "requests_pathname_prefix", requests_pathname_prefix
+ )
+
+ # # Compute server_url url
+ if server_url is None:
+ if "server_url" in _jupyter_config:
+ server_url = _jupyter_config["server_url"].rstrip("/")
+ else:
+ domain_base = os.environ.get("DASH_DOMAIN_BASE", None)
+ if domain_base:
+ # Dash Enterprise sets DASH_DOMAIN_BASE environment variable
+ server_url = "https://" + domain_base
+ else:
+ server_url = f"http://{host}:{port}"
+ else:
+ server_url = server_url.rstrip("/")
+
+ # server_url = "http://{host}:{port}".format(host=host, port=port)
+
+ dashboard_url = f"{server_url}{requests_pathname_prefix}"
+
+ # prevent partial import of orjson when it's installed and mode=jupyterlab
+ # TODO: why do we need this? Why only in this mode? Importing here in
+ # all modes anyway, in case there's a way it can pop up in another mode
+ try:
+ # pylint: disable=C0415,W0611
+ import orjson # noqa: F401
+ except ImportError:
+ pass
+
+ err_q = queue.Queue()
+
+ server = make_server(host, port, app.server, threaded=True, processes=0)
+ logging.getLogger("werkzeug").setLevel(logging.ERROR)
+
+ @retry(
+ stop_max_attempt_number=15,
+ wait_exponential_multiplier=100,
+ wait_exponential_max=1000,
+ )
+ def run():
+ try:
+ server.serve_forever()
+ except SystemExit:
+ pass
+ except Exception as error:
+ err_q.put(error)
+ raise error
+
+ thread = threading.Thread(target=run)
+ thread.daemon = True
+ thread.start()
+
+ self._servers[(host, port)] = server
+
+ # Wait for server to start up
+ alive_url = f"http://{host}:{port}/_alive_{JupyterDash.alive_token}"
+
+ def _get_error():
+ try:
+ err = err_q.get_nowait()
+ if err:
+ raise err
+ except queue.Empty:
+ pass
+
+ # Wait for app to respond to _alive endpoint
+ @retry(
+ stop_max_attempt_number=15,
+ wait_exponential_multiplier=10,
+ wait_exponential_max=1000,
+ )
+ def wait_for_app():
+ _get_error()
+ try:
+ req = requests.get(alive_url)
+ res = req.content.decode()
+ if req.status_code != 200:
+ raise Exception(res)
+
+ if res != "Alive":
+ url = f"http://{host}:{port}"
+ raise OSError(
+ f"Address '{url}' already in use.\n"
+ " Try passing a different port to run_server."
+ )
+ except requests.ConnectionError as err:
+ _get_error()
+ raise err
+
+ try:
+ wait_for_app()
+
+ if self.in_colab:
+ JupyterDash._display_in_colab(dashboard_url, port, mode, width, height)
+ else:
+ JupyterDash._display_in_jupyter(
+ dashboard_url, port, mode, width, height
+ )
+ except Exception as final_error: # pylint: disable=broad-except
+ msg = str(final_error)
+ if msg.startswith("", ''
+ )
+
+ # Remove explicit background color so Dash dev-tools can set background
+ # color
+ html_str = re.sub("background-color:[^;]+;", "", html_str)
+
+ return html_str, 500
+
+ @property
+ def active(self):
+ return _dep_installed and (self.in_ipython or self.in_colab)
+
+
+jupyter_dash = JupyterDash()
diff --git a/dash/dash.py b/dash/dash.py
index 8fee670b08..e3415e6294 100644
--- a/dash/dash.py
+++ b/dash/dash.py
@@ -68,6 +68,7 @@
_path_to_page,
_import_layouts_from_pages,
)
+from ._jupyter import jupyter_dash, JupyterDisplayMode
# Add explicit mapping for map files
mimetypes.add_type("application/json", ".map", True)
@@ -575,19 +576,7 @@ def _handle_error(_):
# add a handler for components suites errors to return 404
self.server.errorhandler(InvalidResourceError)(self._invalid_resources_handler)
- self._add_url(
- "_dash-component-suites//",
- self.serve_component_suites,
- )
- self._add_url("_dash-layout", self.serve_layout)
- self._add_url("_dash-dependencies", self.dependencies)
- self._add_url("_dash-update-component", self.dispatch, ["POST"])
- self._add_url("_reload-hash", self.serve_reload_hash)
- self._add_url("_favicon.ico", self._serve_default_favicon)
- self._add_url("", self.index)
-
- # catch-all for front-end routes, used by dcc.Location
- self._add_url("", self.index)
+ self._setup_routes()
_get_app.APP = self
self.enable_pages()
@@ -603,6 +592,26 @@ def _add_url(self, name, view_func, methods=("GET",)):
# e.g. for adding authentication with flask_login
self.routes.append(full_name)
+ def _setup_routes(self):
+ self._add_url(
+ "_dash-component-suites//",
+ self.serve_component_suites,
+ )
+ self._add_url("_dash-layout", self.serve_layout)
+ self._add_url("_dash-dependencies", self.dependencies)
+ self._add_url("_dash-update-component", self.dispatch, ["POST"])
+ self._add_url("_reload-hash", self.serve_reload_hash)
+ self._add_url("_favicon.ico", self._serve_default_favicon)
+ self._add_url("", self.index)
+
+ if jupyter_dash.active:
+ self._add_url(
+ "_alive_" + jupyter_dash.alive_token, jupyter_dash.serve_alive
+ )
+
+ # catch-all for front-end routes, used by dcc.Location
+ self._add_url("", self.index)
+
@property
def layout(self):
return self._layout
@@ -1674,18 +1683,23 @@ def enable_dev_tools(
_reload.watch_thread.daemon = True
_reload.watch_thread.start()
- if debug and dev_tools.prune_errors:
-
- secret = gen_salt(20)
+ if debug:
- @self.server.errorhandler(Exception)
- def _wrap_errors(error):
- # find the callback invocation, if the error is from a callback
- # and skip the traceback up to that point
- # if the error didn't come from inside a callback, we won't
- # skip anything.
- tb = _get_traceback(secret, error)
- return tb, 500
+ if jupyter_dash.active:
+ jupyter_dash.configure_callback_exception_handling(
+ self, dev_tools.prune_errors
+ )
+ elif dev_tools.prune_errors:
+ secret = gen_salt(20)
+
+ @self.server.errorhandler(Exception)
+ def _wrap_errors(error):
+ # find the callback invocation, if the error is from a callback
+ # and skip the traceback up to that point
+ # if the error didn't come from inside a callback, we won't
+ # skip anything.
+ tb = _get_traceback(secret, error)
+ return tb, 500
if debug and dev_tools.ui:
@@ -1792,6 +1806,10 @@ def run(
port=os.getenv("PORT", "8050"),
proxy=os.getenv("DASH_PROXY", None),
debug=None,
+ jupyter_mode: JupyterDisplayMode = None,
+ jupyter_width="100%",
+ jupyter_height=650,
+ jupyter_server_url=None,
dev_tools_ui=None,
dev_tools_props_check=None,
dev_tools_serve_dev_bundles=None,
@@ -1878,6 +1896,20 @@ def run(
env: ``DASH_PRUNE_ERRORS``
:type dev_tools_prune_errors: bool
+ :param jupyter_mode: How to display the application when running
+ inside a jupyter notebook.
+
+ :param jupyter_width: Determine the width of the output cell
+ when displaying inline in jupyter notebooks.
+ :type jupyter_width: str
+
+ :param jupyter_height: Height of app when displayed using
+ jupyter_mode="inline"
+ :type jupyter_height: int
+
+ :param jupyter_server_url: Custom server url to display
+ the app in jupyter notebook.
+
:param flask_run_options: Given to `Flask.run`
:return:
@@ -1940,7 +1972,8 @@ def verify_url_part(served_part, url_part, part_name):
else:
display_url = (protocol, host, f":{port}", path)
- self.logger.info("Dash is running on %s://%s%s%s\n", *display_url)
+ if not jupyter_dash or not jupyter_dash.in_ipython:
+ self.logger.info("Dash is running on %s://%s%s%s\n", *display_url)
if self.config.extra_hot_reload_paths:
extra_files = flask_run_options["extra_files"] = []
@@ -1952,7 +1985,18 @@ def verify_url_part(served_part, url_part, part_name):
elif os.path.isfile(path):
extra_files.append(path)
- self.server.run(host=host, port=port, debug=debug, **flask_run_options)
+ if jupyter_dash.active:
+ jupyter_dash.run_app(
+ self,
+ mode=jupyter_mode,
+ width=jupyter_width,
+ height=jupyter_height,
+ host=host,
+ port=port,
+ server_url=jupyter_server_url,
+ )
+ else:
+ self.server.run(host=host, port=port, debug=debug, **flask_run_options)
def enable_pages(self):
if not self.use_pages:
diff --git a/dash/labextension/package.json b/dash/labextension/package.json
new file mode 100644
index 0000000000..2a7a80a8c8
--- /dev/null
+++ b/dash/labextension/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "@plotly/dash-jupyterlab",
+ "version": "0.4.3",
+ "description": "A JupyterLab extensions for rendering Plotly Dash apps",
+ "keywords": [
+ "jupyter",
+ "jupyterlab",
+ "jupyterlab-extension"
+ ],
+ "homepage": "https://github.com/plotly/dash",
+ "bugs": {
+ "url": "https://github.com/plotly/dash/issues"
+ },
+ "license": "MIT",
+ "author": "Plotly",
+ "files": [
+ "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
+ "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}"
+ ],
+ "main": "lib/index.js",
+ "types": "lib/index.d.ts",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/plotly/dash.git"
+ },
+ "scripts": {
+ "build": "tsc",
+ "clean": "rimraf lib",
+ "prepare": "jlpm run clean && jlpm run build",
+ "prettier": "prettier --write '{!(package),src/**,!(lib)/**}{.js,.jsx,.ts,.tsx,.css,.json,.md}'",
+ "watch": "tsc -w"
+ },
+ "dependencies": {
+ "@jupyterlab/application": "^2.0.0 || ^3.0.0",
+ "@jupyterlab/notebook": "^2.0.0 || ^3.0.0",
+ "@jupyterlab/console": "^2.0.0 || ^3.0.0"
+ },
+ "devDependencies": {
+ "prettier": "2.0.5",
+ "rimraf": "3.0.2",
+ "typescript": "3.9.3"
+ },
+ "jupyterlab": {
+ "extension": true
+ }
+}
diff --git a/dash/nbextension/README.md b/dash/nbextension/README.md
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/dash/nbextension/__init__.py b/dash/nbextension/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/dash/nbextension/dash.json b/dash/nbextension/dash.json
new file mode 100644
index 0000000000..6e28ddcf08
--- /dev/null
+++ b/dash/nbextension/dash.json
@@ -0,0 +1,5 @@
+{
+ "load_extensions": {
+ "dash/main": true
+ }
+}
diff --git a/dash/nbextension/description.yaml b/dash/nbextension/description.yaml
new file mode 100644
index 0000000000..909e9d7a73
--- /dev/null
+++ b/dash/nbextension/description.yaml
@@ -0,0 +1,9 @@
+Type: Jupyter Notebook Extension
+Compatibility: 3.x, 4.x, 5.x, 6.x
+Name: Jupyter Dash
+Main: main.js
+Link: README.md
+Description: |
+ Jupyer Dash support
+Parameters:
+- none
diff --git a/dash/nbextension/main.js b/dash/nbextension/main.js
new file mode 100644
index 0000000000..436e371bc5
--- /dev/null
+++ b/dash/nbextension/main.js
@@ -0,0 +1,42 @@
+// file my_extension/main.js
+
+define([
+ 'base/js/namespace',
+ 'base/js/utils',
+], function(Jupyter, utils){
+
+ function load_ipython_extension(){
+ var notebookUrl = window.location.href
+ var baseUrl = utils.get_body_data('baseUrl');
+ var baseNotebooks = baseUrl + "notebooks"
+ var n = notebookUrl.search(baseNotebooks)
+ var jupyterServerUrl = notebookUrl.slice(0, n)
+
+ var register_comm = function() {
+ Jupyter.notebook.kernel.comm_manager.register_target('dash',
+ function (comm, msg) {
+ // Register handlers for later messages:
+ comm.on_msg(function (msg) {
+ console.log("Dash message", msg);
+ var msgData = msg.content.data;
+ if (msgData.type === 'base_url_request') {
+ comm.send({
+ type: 'base_url_response',
+ server_url: jupyterServerUrl,
+ base_subpath: baseUrl,
+ frontend: "notebook"
+ });
+ } else if (msgData.type === 'show') {
+
+ }
+ });
+ });
+ };
+
+ Jupyter.notebook.events.on('kernel_ready.Kernel', register_comm)
+ }
+
+ return {
+ load_ipython_extension: load_ipython_extension
+ };
+});
diff --git a/package.json b/package.json
index b1966c10cc..f5644f3601 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
"private::build.components": "python dash/development/update_components.py 'all'",
"private::cibuild.renderer": "cd dash/dash-renderer && renderer build",
"private::build.renderer": "cd dash/dash-renderer && renderer build",
+ "private::build.jupyterlab": "cd \\@plotly/dash-jupyterlab && jlpm install && jlpm build:pack",
"private::lint.black": "node -e \"if ((process.env.PYVERSION || 'python39') !== 'python36'){process.exit(1)} \" || black dash tests --exclude metadata_test.py --check",
"private::lint.flake8": "flake8 --exclude=metadata_test.py dash tests",
"private::lint.pylint-dash": "PYLINTRC=${PYLINTRC:=.pylintrc39} && pylint dash setup.py --rcfile=$PYLINTRC",
@@ -33,7 +34,7 @@
"private::test.integration-dash-import": "cd tests/integration/dash && python dash_import_test.py",
"cibuild": "run-s private::cibuild.*",
"build": "run-s private::build.*",
- "build.sequential": "npm run private::build.renderer && npm run private::build.components -- --concurrency 1",
+ "build.sequential": "npm run private::build.jupyterlab && npm run private::build.renderer && npm run private::build.components -- --concurrency 1",
"format": "run-s private::format.*",
"initialize": "run-s private::initialize.*",
"prepare": "husky install",
diff --git a/requires-ci.txt b/requires-ci.txt
index 117008fb71..3bf72c85e7 100644
--- a/requires-ci.txt
+++ b/requires-ci.txt
@@ -24,3 +24,4 @@ pytest-sugar==0.9.6
xlrd>=2.0.1;python_version>="3.8"
xlrd<2;python_version<"3.8"
pytest-rerunfailures
+jupyterlab<4.0.0
diff --git a/requires-install.txt b/requires-install.txt
index 8730b6d6ea..f92ceb759b 100644
--- a/requires-install.txt
+++ b/requires-install.txt
@@ -6,3 +6,8 @@ dash_core_components==2.0.0
dash_table==5.0.0
importlib-metadata==4.8.3;python_version<"3.7"
contextvars==2.4;python_version<"3.7"
+typing_extensions>=4.1.1
+requests
+retrying
+ansi2html
+nest-asyncio
diff --git a/setup.py b/setup.py
index 2063caca8a..9a99e22641 100644
--- a/setup.py
+++ b/setup.py
@@ -33,7 +33,7 @@ def read_req_file(req_type):
"testing": read_req_file("testing"),
"celery": read_req_file("celery"),
"diskcache": read_req_file("diskcache"),
- "compress": read_req_file("compress"),
+ "compress": read_req_file("compress")
},
entry_points={
"console_scripts": [
@@ -74,4 +74,18 @@ def read_req_file(req_type):
"Topic :: Software Development :: Libraries :: Application Frameworks",
"Topic :: Software Development :: Widget Sets",
],
+ data_files=[
+ # like `jupyter nbextension install --sys-prefix`
+ ("share/jupyter/nbextensions/dash", [
+ "dash/nbextension/main.js",
+ ]),
+ # like `jupyter nbextension enable --sys-prefix`
+ ("etc/jupyter/nbconfig/notebook.d", [
+ "dash/nbextension/dash.json"
+ ]),
+ # Place jupyterlab extension in extension directory
+ ("share/jupyter/lab/extensions", [
+ "dash/labextension/dist/dash-jupyterlab.tgz"
+ ]),
+ ],
)