You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beam.apache.org by pa...@apache.org on 2020/10/01 18:03:58 UTC

[beam] branch master updated: [BEAM-10545] Add 2 show options

This is an automated email from the ASF dual-hosted git repository.

pabloem pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git


The following commit(s) were added to refs/heads/master by this push:
     new 98bb062  [BEAM-10545] Add 2 show options
     new 5626c8a  Merge pull request #12979 from [BEAM-10545] Add 2 show options
98bb062 is described below

commit 98bb062fbeb8bd165ce3fb657fa72987d813c557
Author: Ning Kang <ni...@google.com>
AuthorDate: Wed Sep 30 14:32:50 2020 -0700

    [BEAM-10545] Add 2 show options
    
    1. Added 2 show API options in the side panel: duration and n.
    2. Added an `apply` button to alter the behavior of setting show API
       options: now the configuration change only takes effect after
       clicking the button; previously, the configuration is automatically
       applied when clicking a checkbox, but this behavior does not apply
       when the configuration now has text inputs.
    3. Added `interruptKernelIfNotDone` to the InspectableViewModel and
       always execute it when querying the kernel from such model. This made
       switching selected item and applying new show API options very
       snappy.
---
 .../apache-beam-jupyterlab-sidepanel/package.json  |   2 +
 .../__tests__/inspector/InspectableView.test.tsx   |  19 +-
 .../inspector/InspectableViewModel.test.ts         | 114 ++++++++-
 .../src/inspector/InspectableView.tsx              | 120 ++++++++-
 .../src/inspector/InspectableViewModel.ts          |  33 +++
 .../style/mdc-theme.css                            |   9 +
 .../apache-beam-jupyterlab-sidepanel/yarn.lock     | 270 ++++++++++++++++++++-
 7 files changed, 547 insertions(+), 20 deletions(-)

diff --git a/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/package.json b/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/package.json
index c70eb79..193e5be 100644
--- a/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/package.json
+++ b/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/package.json
@@ -40,6 +40,8 @@
     "@rmwc/checkbox": "^6.1.3",
     "@rmwc/drawer": "^6.0.14",
     "@rmwc/list": "^6.1.3",
+    "@rmwc/textfield": "^6.1.4",
+    "@rmwc/tooltip": "^6.1.4",
     "@rmwc/top-app-bar": "^6.1.3",
     "material-design-icons": "^3.0.1"
   },
diff --git a/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/__tests__/inspector/InspectableView.test.tsx b/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/__tests__/inspector/InspectableView.test.tsx
index 473cfe6..1309ebb 100644
--- a/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/__tests__/inspector/InspectableView.test.tsx
+++ b/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/__tests__/inspector/InspectableView.test.tsx
@@ -73,26 +73,39 @@ it('renders options if inspecting a pcollection', () => {
     );
     const inspectableView = inspectableViewRef.current;
     if (inspectableView) {
-      inspectableView.updateRender();
+      inspectableView.setState({
+        options: fakeModel.options
+      });
     }
   });
   const inspectableViewElement: Element = container.firstElementChild;
   const optionsElement: Element = inspectableViewElement.firstElementChild;
   expect(optionsElement.tagName).toBe('DIV');
-  const includeWindowInfoCheckbox: Element = optionsElement.firstElementChild;
+  const includeWindowInfoCheckbox: Element =
+    optionsElement.firstElementChild.firstElementChild;
   expect(
     includeWindowInfoCheckbox.firstElementChild.getAttribute('class')
   ).toContain('mdc-checkbox');
   expect(
     includeWindowInfoCheckbox.firstElementChild.getAttribute('class')
   ).not.toContain('mdc-checkbox--selected');
-  const visualizeInFacetsCheckbox: Element = optionsElement.children[1];
+  const visualizeInFacetsCheckbox: Element =
+    optionsElement.firstElementChild.children[1];
   expect(
     visualizeInFacetsCheckbox.firstElementChild.getAttribute('class')
   ).toContain('mdc-checkbox');
   expect(
     visualizeInFacetsCheckbox.firstElementChild.getAttribute('class')
   ).toContain('mdc-checkbox--selected');
+  const durationTextField: Element =
+    optionsElement.firstElementChild.children[2];
+  expect(durationTextField.getAttribute('class')).toContain(
+    'mdc-text-field--outlined'
+  );
+  const nTextField: Element = optionsElement.firstElementChild.children[3];
+  expect(nTextField.getAttribute('class')).toContain(
+    'mdc-text-field--outlined'
+  );
 });
 
 it('renders an html view', () => {
diff --git a/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/__tests__/inspector/InspectableViewModel.test.ts b/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/__tests__/inspector/InspectableViewModel.test.ts
index 540e746..fe624b7 100644
--- a/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/__tests__/inspector/InspectableViewModel.test.ts
+++ b/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/__tests__/inspector/InspectableViewModel.test.ts
@@ -42,18 +42,128 @@ it('builds show_graph query correctly', () => {
   );
 });
 
-it('builds show query correctly', () => {
+it('builds show query correctly with default values', () => {
+  const inspectableViewModel = new InspectableViewModel(
+    fakeSessionContext as any
+  );
+  inspectableViewModel.queryKernel('pcollection', 'id');
+  expect(inspectableViewModel.buildShowQuery({} as IShowOptions)).toBe(
+    "ib.show(ie.current_env().inspector.get_val('id')," +
+      'include_window_info=False, visualize_data=False, ' +
+      "duration='inf', n='inf')"
+  );
+});
+
+it('builds show query with given checkbox values correctly', () => {
   const inspectableViewModel = new InspectableViewModel(
     fakeSessionContext as any
   );
   inspectableViewModel.queryKernel('pcollection', 'id');
   expect(
     inspectableViewModel.buildShowQuery({
+      includeWindowInfo: true,
       visualizeInFacets: true
     } as IShowOptions)
   ).toBe(
     "ib.show(ie.current_env().inspector.get_val('id')," +
-      'include_window_info=False, visualize_data=True)'
+      'include_window_info=True, visualize_data=True, ' +
+      "duration='inf', n='inf')"
+  );
+});
+
+it('builds show query with string duration', () => {
+  const inspectableViewModel = new InspectableViewModel(
+    fakeSessionContext as any
+  );
+  inspectableViewModel.queryKernel('pcollection', 'id');
+  expect(
+    inspectableViewModel.buildShowQuery({
+      duration: '60s'
+    } as IShowOptions)
+  ).toBe(
+    "ib.show(ie.current_env().inspector.get_val('id')," +
+      'include_window_info=False, visualize_data=False, ' +
+      "duration='60s', n='inf')"
+  );
+});
+
+it('builds show query with negative duration as inf', () => {
+  const inspectableViewModel = new InspectableViewModel(
+    fakeSessionContext as any
+  );
+  inspectableViewModel.queryKernel('pcollection', 'id');
+  expect(
+    inspectableViewModel.buildShowQuery({
+      duration: '-1'
+    } as IShowOptions)
+  ).toBe(
+    "ib.show(ie.current_env().inspector.get_val('id')," +
+      'include_window_info=False, visualize_data=False, ' +
+      "duration='inf', n='inf')"
+  );
+});
+
+it('builds show query with positive duration as int', () => {
+  const inspectableViewModel = new InspectableViewModel(
+    fakeSessionContext as any
+  );
+  inspectableViewModel.queryKernel('pcollection', 'id');
+  expect(
+    inspectableViewModel.buildShowQuery({
+      duration: '5.5'
+    } as IShowOptions)
+  ).toBe(
+    "ib.show(ie.current_env().inspector.get_val('id')," +
+      'include_window_info=False, visualize_data=False, ' +
+      "duration=5, n='inf')"
+  );
+});
+
+it('builds show query with string n as inf', () => {
+  const inspectableViewModel = new InspectableViewModel(
+    fakeSessionContext as any
+  );
+  inspectableViewModel.queryKernel('pcollection', 'id');
+  expect(
+    inspectableViewModel.buildShowQuery({
+      n: 'abcd'
+    } as IShowOptions)
+  ).toBe(
+    "ib.show(ie.current_env().inspector.get_val('id')," +
+      'include_window_info=False, visualize_data=False, ' +
+      "duration='inf', n='inf')"
+  );
+});
+
+it('builds show query with negative n as inf', () => {
+  const inspectableViewModel = new InspectableViewModel(
+    fakeSessionContext as any
+  );
+  inspectableViewModel.queryKernel('pcollection', 'id');
+  expect(
+    inspectableViewModel.buildShowQuery({
+      n: '-1'
+    } as IShowOptions)
+  ).toBe(
+    "ib.show(ie.current_env().inspector.get_val('id')," +
+      'include_window_info=False, visualize_data=False, ' +
+      "duration='inf', n='inf')"
+  );
+});
+
+it('builds show query with positive n as int', () => {
+  const inspectableViewModel = new InspectableViewModel(
+    fakeSessionContext as any
+  );
+  inspectableViewModel.queryKernel('pcollection', 'id');
+  expect(
+    inspectableViewModel.buildShowQuery({
+      n: '5.5'
+    } as IShowOptions)
+  ).toBe(
+    "ib.show(ie.current_env().inspector.get_val('id')," +
+      'include_window_info=False, visualize_data=False, ' +
+      "duration='inf', n=5)"
   );
 });
 
diff --git a/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/inspector/InspectableView.tsx b/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/inspector/InspectableView.tsx
index aead0e7..c04c457 100644
--- a/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/inspector/InspectableView.tsx
+++ b/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/inspector/InspectableView.tsx
@@ -12,7 +12,10 @@
 
 import * as React from 'react';
 
+import { Button } from '@rmwc/button';
 import { Checkbox } from '@rmwc/checkbox';
+import { TextField } from '@rmwc/textfield';
+import { Tooltip } from '@rmwc/tooltip';
 
 import {
   InspectableViewModel,
@@ -23,7 +26,10 @@ import { HtmlView } from '../common/HtmlView';
 import { IHtmlProvider } from '../common/HtmlView';
 import { InterruptKernelButton } from '../kernel/InterruptKernelButton';
 
+import '@rmwc/button/styles';
 import '@rmwc/checkbox/styles';
+import '@rmwc/textfield/styles';
+import '@rmwc/tooltip/styles';
 
 interface IInspectableViewProps {
   model: InspectableViewModel;
@@ -31,6 +37,7 @@ interface IInspectableViewProps {
 
 interface IInspectableViewState {
   inspectableType: string;
+  identifier: string;
   // options used in kernel messaging.
   options: IOptions;
 }
@@ -38,9 +45,9 @@ interface IInspectableViewState {
 /**
  * The display area of the InteractiveInspector parent component.
  *
- * The react component is composed with a top checkbox section of display
- * options and a main HtmlView area that displays HTML from IOPub messaging of
- * its kernel model.
+ * The react component is composed with a top section of display options and a
+ * main HtmlView area that displays HTML from IOPub messaging of its kernel
+ * model.
  */
 export class InspectableView extends React.Component<
   IInspectableViewProps,
@@ -49,13 +56,15 @@ export class InspectableView extends React.Component<
   constructor(props: IInspectableViewProps) {
     super(props);
     this.state = {
-      inspectableType: 'pipeline',
+      inspectableType: props.model.inspectableType,
+      identifier: props.model.identifier,
       options: props.model.options
     };
+    this.applyShowOptions = this.applyShowOptions.bind(this);
   }
 
   componentDidMount(): void {
-    this._updateRenderTimerId = setInterval(() => this.updateRender(), 1500);
+    this._updateRenderTimerId = setInterval(() => this.updateRender(), 1000);
   }
 
   componentWillUnmount(): void {
@@ -63,14 +72,20 @@ export class InspectableView extends React.Component<
   }
 
   updateRender(): void {
+    // Only self update when there is change in the selected item.
+    if (this.props.model.identifier === this.state.identifier) {
+      return;
+    }
     if (this.props.model.inspectableType === 'pcollection') {
       this.setState({
         inspectableType: 'pcollection',
+        identifier: this.props.model.identifier,
         options: this._buildShowOptions(this.props.model.options)
       });
     } else {
       this.setState({
         inspectableType: 'pipeline',
+        identifier: this.props.model.identifier,
         options: {}
       });
     }
@@ -81,28 +96,105 @@ export class InspectableView extends React.Component<
       return <span />;
     }
     const showOptions = this._buildShowOptions(this.state.options);
+    const includeWindowInfo = this._renderIncludeWindowInfo(showOptions);
+    const visualizeInFacets = this._renderVisualizeInFacets(showOptions);
+    const duration = this._renderDuration(showOptions);
+    const n = this._renderN(showOptions);
+    return (
+      <div
+        style={{
+          padding: '5px'
+        }}
+      >
+        {includeWindowInfo}
+        {visualizeInFacets}
+        {duration}
+        {n}
+        <Button
+          label="apply"
+          onClick={(): void => this.applyShowOptions(showOptions)}
+          raised
+        />
+      </div>
+    );
+  }
+
+  applyShowOptions(showOptions: IShowOptions): void {
+    this.setState({ options: showOptions });
+    // Back store the new state to the model.
+    this.props.model.options = showOptions;
+  }
+
+  private _renderIncludeWindowInfo(showOptions: IShowOptions): React.ReactNode {
     return (
-      <React.Fragment>
+      <Tooltip content="Whether to include window info.">
         <Checkbox
-          label="window info"
+          label="Include Window Info"
           checked={showOptions.includeWindowInfo}
           onChange={(e): void => {
             showOptions.includeWindowInfo = !!e.currentTarget.checked;
             this.setState({ options: showOptions });
-            // Back store the new state to the model.
-            this.props.model.options = showOptions;
           }}
         />
+      </Tooltip>
+    );
+  }
+
+  private _renderVisualizeInFacets(showOptions: IShowOptions): React.ReactNode {
+    return (
+      <Tooltip content="Whether to visualize the data in Facets.">
         <Checkbox
-          label="facets"
+          label="Visualize in Facets"
           checked={showOptions.visualizeInFacets}
           onChange={(e): void => {
             showOptions.visualizeInFacets = !!e.currentTarget.checked;
             this.setState({ options: showOptions });
-            this.props.model.options = showOptions;
           }}
         />
-      </React.Fragment>
+      </Tooltip>
+    );
+  }
+
+  private _renderDuration(showOptions: IShowOptions): React.ReactNode {
+    const tooltip =
+      'Max duration of elements to read in integer seconds or ' +
+      'a string duration that is parsable by pandas.to_timedelta, such as 1m ' +
+      'or 60s. Otherwise, default value `inf` is used: the visualization ' +
+      'will never end until manually stopped by interrupting the kernel or ' +
+      'reaches a hard cap set by ib.options.capture_size_limit.';
+    return (
+      <Tooltip content={tooltip}>
+        <TextField
+          outlined
+          label="Duration"
+          floatLabel
+          placeholder={showOptions.duration}
+          onChange={(e): void => {
+            showOptions.duration = e.currentTarget.value;
+          }}
+        />
+      </Tooltip>
+    );
+  }
+
+  private _renderN(showOptions: IShowOptions): React.ReactNode {
+    const tooltip =
+      'Max number of elements to visualize. Please fill in a ' +
+      'positive integer. Otherwise, default value `inf` is used: the ' +
+      'visualization will never end until manually stopped by interrupting ' +
+      'the kernel or reaches a hard cap set by ib.options.capture_duration.';
+    return (
+      <Tooltip content={tooltip}>
+        <TextField
+          outlined
+          label="Element Number"
+          floatLabel
+          placeholder={showOptions.n}
+          onChange={(e): void => {
+            showOptions.n = e.currentTarget.value;
+          }}
+        />
+      </Tooltip>
     );
   }
 
@@ -122,7 +214,9 @@ export class InspectableView extends React.Component<
     const optionsInput = options as IShowOptions;
     return {
       includeWindowInfo: !!optionsInput?.includeWindowInfo,
-      visualizeInFacets: !!optionsInput?.visualizeInFacets
+      visualizeInFacets: !!optionsInput?.visualizeInFacets,
+      duration: optionsInput?.duration,
+      n: optionsInput?.n
     } as IShowOptions;
   }
 
diff --git a/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/inspector/InspectableViewModel.ts b/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/inspector/InspectableViewModel.ts
index fea9720..4dd115b 100644
--- a/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/inspector/InspectableViewModel.ts
+++ b/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/src/inspector/InspectableViewModel.ts
@@ -19,6 +19,8 @@ import { KernelModel } from '../kernel/KernelModel';
 export interface IShowOptions {
   includeWindowInfo?: boolean;
   visualizeInFacets?: boolean;
+  duration?: string;
+  n?: string;
 }
 
 // Options depend on the inspectableType. Currently only one variation of
@@ -63,6 +65,30 @@ export class InspectableViewModel implements IHtmlProvider {
     } else {
       optionsAsString += 'visualize_data=False';
     }
+    optionsAsString += ', ';
+    if (!options.duration) {
+      options.duration = 'inf';
+    }
+    const durationNum = Number(options.duration);
+    if (isNaN(durationNum)) {
+      optionsAsString += `duration='${options.duration}'`;
+    } else if (durationNum <= 0) {
+      options.duration = 'inf';
+      optionsAsString += "duration='inf'";
+    } else {
+      options.duration = Math.floor(durationNum).toString(10);
+      optionsAsString += 'duration=' + Math.floor(durationNum);
+    }
+    optionsAsString += ', ';
+    const nNum = Number(options.n);
+    const nInt = Math.floor(nNum);
+    if (isNaN(nNum) || nInt <= 0) {
+      options.n = 'inf';
+      optionsAsString += "n='inf'";
+    } else {
+      options.n = nInt.toString(10);
+      optionsAsString += 'n=' + nInt;
+    }
     return (
       'ib.show(' +
       `ie.current_env().inspector.get_val('${this._identifier}'),` +
@@ -75,11 +101,18 @@ export class InspectableViewModel implements IHtmlProvider {
     return this._model;
   }
 
+  interruptKernelIfNotDone(): void {
+    if (!this._model.isDone) {
+      this._model.interruptKernel();
+    }
+  }
+
   queryKernel(
     inspectableType: string,
     identifier: string,
     options: IOptions = {}
   ): void {
+    this.interruptKernelIfNotDone();
     this._inspectableType = inspectableType.toLowerCase();
     this._identifier = identifier;
     this._options = options;
diff --git a/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/style/mdc-theme.css b/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/style/mdc-theme.css
index f3f009c..b6383f9 100644
--- a/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/style/mdc-theme.css
+++ b/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/style/mdc-theme.css
@@ -48,3 +48,12 @@
 .mdc-drawer li.mdc-list-item--activated {
   color: var(--jp-ui-font-color1);
 }
+
+.mdc-form-field > label {
+  margin-bottom: 0;
+}
+
+.mdc-text-field {
+  margin-left: 4px;
+  margin-right: 4px;
+}
diff --git a/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/yarn.lock b/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/yarn.lock
index 277ed70..7e4f530 100644
--- a/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/yarn.lock
+++ b/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/yarn.lock
@@ -1105,6 +1105,20 @@
   resolved "https://registry.yarnpkg.com/@material/feature-targeting/-/feature-targeting-5.1.0.tgz#49265bbd4ff59b1cd20a385b5547f7c246cb1955"
   integrity sha512-z3JNWF7lP9WOzw1xBwul/HAOu4qC6EpK/8MkhjLNI9APvdYML82PWS1V0k0MiqA6Jk6uxm8DiVAk9VUqBa9/YA==
 
+"@material/floating-label@^5.1.0":
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/@material/floating-label/-/floating-label-5.1.0.tgz#8d654b3f2ca98248e5a73a63feec8f4523c5ab4f"
+  integrity sha512-5EwPiBa5A4Q678tNWdkkBGDdSCDzudhVgBtRiA/7xRo4dHXiBxX5bhE+RHrF3ZQyEf6fsShspqwAFkTA1EaplQ==
+  dependencies:
+    "@material/animation" "^5.1.0"
+    "@material/base" "^5.1.0"
+    "@material/dom" "^5.1.0"
+    "@material/feature-targeting" "^5.1.0"
+    "@material/rtl" "^5.1.0"
+    "@material/theme" "^5.1.0"
+    "@material/typography" "^5.1.0"
+    tslib "^1.9.3"
+
 "@material/form-field@^5.1.0":
   version "5.1.0"
   resolved "https://registry.yarnpkg.com/@material/form-field/-/form-field-5.1.0.tgz#91bf81cb4647d655b7459df0aa19060189f55564"
@@ -1130,6 +1144,17 @@
     "@material/theme" "^5.1.0"
     tslib "^1.9.3"
 
+"@material/line-ripple@^5.1.0":
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/@material/line-ripple/-/line-ripple-5.1.0.tgz#86cb1b8a91bf010231109211b8eb38ad059f5f23"
+  integrity sha512-esf2/ROZl1eVpyGCWPvxMSGVkuIOG5Fm6qufOLp7XIx5IL1O0bsm+bV6cVC4JCCtmNOag4GOBgkKKbkOvp/R6g==
+  dependencies:
+    "@material/animation" "^5.1.0"
+    "@material/base" "^5.1.0"
+    "@material/feature-targeting" "^5.1.0"
+    "@material/theme" "^5.1.0"
+    tslib "^1.9.3"
+
 "@material/list@^5.1.0":
   version "5.1.0"
   resolved "https://registry.yarnpkg.com/@material/list/-/list-5.1.0.tgz#04c010e393c88c7da2091426fd12b8206585c37e"
@@ -1146,6 +1171,19 @@
     "@material/typography" "^5.1.0"
     tslib "^1.9.3"
 
+"@material/notched-outline@^5.1.0":
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/@material/notched-outline/-/notched-outline-5.1.0.tgz#4ec97001ed6bbb66f04100b7745ae99d19a4d16e"
+  integrity sha512-mQ3NjJR1jLXnJi6jhs20ftTf0yU1gWpYlyx1GizU0f7pLEqcIrFnw6G+pavcnKqP+JXNkzAQeGbmZvYBQnxokA==
+  dependencies:
+    "@material/base" "^5.1.0"
+    "@material/feature-targeting" "^5.1.0"
+    "@material/floating-label" "^5.1.0"
+    "@material/rtl" "^5.1.0"
+    "@material/shape" "^5.1.0"
+    "@material/theme" "^5.1.0"
+    tslib "^1.9.3"
+
 "@material/ripple@^5.1.0":
   version "5.1.0"
   resolved "https://registry.yarnpkg.com/@material/ripple/-/ripple-5.1.0.tgz#6624e0ff7718d6bfa65fecd0bca4c03d2696c07b"
@@ -1171,6 +1209,26 @@
     "@material/feature-targeting" "^5.1.0"
     "@material/rtl" "^5.1.0"
 
+"@material/textfield@^5.1.0":
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/@material/textfield/-/textfield-5.1.0.tgz#75f68c62dc916116330a4c958ba3866c87bd6002"
+  integrity sha512-Vipvw75AXj4G/BGXv3DyrGozbvHxGtcNGig1e5pz1ERvcmZN5epLyGStznxEIZYNf0Q+6O/NwSRxZGgrdI2w8w==
+  dependencies:
+    "@material/animation" "^5.1.0"
+    "@material/base" "^5.1.0"
+    "@material/density" "^5.1.0"
+    "@material/dom" "^5.1.0"
+    "@material/feature-targeting" "^5.1.0"
+    "@material/floating-label" "^5.1.0"
+    "@material/line-ripple" "^5.1.0"
+    "@material/notched-outline" "^5.1.0"
+    "@material/ripple" "^5.1.0"
+    "@material/rtl" "^5.1.0"
+    "@material/shape" "^5.1.0"
+    "@material/theme" "^5.1.0"
+    "@material/typography" "^5.1.0"
+    tslib "^1.9.3"
+
 "@material/theme@^5.1.0":
   version "5.1.0"
   resolved "https://registry.yarnpkg.com/@material/theme/-/theme-5.1.0.tgz#013c37d055afc5d4045c77e44c9fd1f940ff865b"
@@ -1222,6 +1280,19 @@
     mutation-observer "^1.0.3"
     tslib "^1.10.0"
 
+"@rmwc/base@^6.1.4":
+  version "6.1.4"
+  resolved "https://registry.yarnpkg.com/@rmwc/base/-/base-6.1.4.tgz#0e6a132eee28e0f0e1dd409fc917b8b035754a02"
+  integrity sha512-8HOKn+Dt+lVCat0Ug9aY0EorshuvM2gG1tQqT6+/m2IzqGhCL0mN5swxnOMWH0RD0K/XVa2CM1NyEd558/RvTA==
+  dependencies:
+    "@material/dom" "^5.1.0"
+    "@rmwc/types" "^6.0.5"
+    "@types/classnames" "^2.2.7"
+    classnames "^2.2.6"
+    hyperform "^0.11.0"
+    mutation-observer "^1.0.3"
+    tslib "^1.10.0"
+
 "@rmwc/button@^6.1.3":
   version "6.1.3"
   resolved "https://registry.yarnpkg.com/@rmwc/button/-/button-6.1.3.tgz#87e84b32e706dd986b1b56f32c19beac09aab06c"
@@ -1256,6 +1327,15 @@
     "@rmwc/base" "^6.0.14"
     "@rmwc/types" "^6.0.5"
 
+"@rmwc/floating-label@^6.1.4":
+  version "6.1.4"
+  resolved "https://registry.yarnpkg.com/@rmwc/floating-label/-/floating-label-6.1.4.tgz#02976c4685f8425e72c8a1725a5343ca2cde934a"
+  integrity sha512-X0FZGlh81VetIdiDapdSdB6JAhZRPBGXfHIzBd6F4y7ta4/V0kQo+Nv1kaq88jRMY/ROr6XwG7sMWDiM2joRrQ==
+  dependencies:
+    "@material/floating-label" "^5.1.0"
+    "@rmwc/base" "^6.1.4"
+    "@rmwc/types" "^6.0.5"
+
 "@rmwc/formfield@^6.0.14":
   version "6.0.14"
   resolved "https://registry.yarnpkg.com/@rmwc/formfield/-/formfield-6.0.14.tgz#0ce4a091b1b2851f60340874793e5336de8d1ab5"
@@ -1285,6 +1365,24 @@
     "@rmwc/provider" "^6.1.3"
     "@rmwc/types" "^6.0.5"
 
+"@rmwc/icon@^6.1.4":
+  version "6.1.4"
+  resolved "https://registry.yarnpkg.com/@rmwc/icon/-/icon-6.1.4.tgz#59ecfe641228b2f5d5d3ada7f22ff255bb9f9418"
+  integrity sha512-y+qhbXqHsuXYa1kQPrkSlMG/0S6GIlEpT/nQwKpGjz2FXiwxikeiYZ6siXLVK6Y3uFiOCA7gbGGsd9BMDWljxg==
+  dependencies:
+    "@rmwc/base" "^6.1.4"
+    "@rmwc/provider" "^6.1.4"
+    "@rmwc/types" "^6.0.5"
+
+"@rmwc/line-ripple@^6.1.4":
+  version "6.1.4"
+  resolved "https://registry.yarnpkg.com/@rmwc/line-ripple/-/line-ripple-6.1.4.tgz#fa8cf24207aa1e45360ce9a36c20f644d7b0479b"
+  integrity sha512-lynjPp436hDrhspPFGzzqzUidsMS+D+zwSnH6G527Le7wEYjx13r2x3zCJ2tHVJWx6oxmJti+Y0QyvtPu0ehbQ==
+  dependencies:
+    "@material/line-ripple" "^5.1.0"
+    "@rmwc/base" "^6.1.4"
+    "@rmwc/types" "^6.0.5"
+
 "@rmwc/list@^6.1.3":
   version "6.1.3"
   resolved "https://registry.yarnpkg.com/@rmwc/list/-/list-6.1.3.tgz#854abdc83cf4ccbd6b476b43711e0454e068eca8"
@@ -1297,6 +1395,15 @@
     "@rmwc/ripple" "^6.1.3"
     "@rmwc/types" "^6.0.5"
 
+"@rmwc/notched-outline@^6.1.4":
+  version "6.1.4"
+  resolved "https://registry.yarnpkg.com/@rmwc/notched-outline/-/notched-outline-6.1.4.tgz#479d77b698a2cd060b8802d9be0e50d864fe42b8"
+  integrity sha512-Q5INGaSwBu6ceARw/kLIBzsWKN99LICFPDVYL02eJaeOwgCRfuL1Y7ot3m7BA0Dnh7ggWFHkTXeIH8T5kqXEXw==
+  dependencies:
+    "@material/notched-outline" "^5.1.0"
+    "@rmwc/base" "^6.1.4"
+    "@rmwc/types" "^6.0.5"
+
 "@rmwc/provider@^6.1.3":
   version "6.1.3"
   resolved "https://registry.yarnpkg.com/@rmwc/provider/-/provider-6.1.3.tgz#5f31f8413ba688a91d140d7a6afbadc3d1c0ca84"
@@ -1305,6 +1412,14 @@
     "@rmwc/base" "^6.0.14"
     "@rmwc/types" "^6.0.5"
 
+"@rmwc/provider@^6.1.4":
+  version "6.1.4"
+  resolved "https://registry.yarnpkg.com/@rmwc/provider/-/provider-6.1.4.tgz#8af9d629df4fc045a68e94d019bbcb5cf7f9120e"
+  integrity sha512-883PclFrzv6KL/2R613/zdBDZe2d5nAWkT8PEU5z9ddWhOG95sJVj2/uuTc2M/l/vnstOI5YtmkbFvYYVd4XBQ==
+  dependencies:
+    "@rmwc/base" "^6.1.4"
+    "@rmwc/types" "^6.0.5"
+
 "@rmwc/ripple@^6.1.3":
   version "6.1.3"
   resolved "https://registry.yarnpkg.com/@rmwc/ripple/-/ripple-6.1.3.tgz#a91ef5422f34a563d6024cc21f98abaadf819261"
@@ -1315,6 +1430,30 @@
     "@rmwc/provider" "^6.1.3"
     "@rmwc/types" "^6.0.5"
 
+"@rmwc/ripple@^6.1.4":
+  version "6.1.4"
+  resolved "https://registry.yarnpkg.com/@rmwc/ripple/-/ripple-6.1.4.tgz#cf25b93ef141de26cf643bcaf589a345615c4021"
+  integrity sha512-bWir1kCOC8h0Dr7/wk89vkZ2icfMbObYk+/1cznukRy7m5QmUvFHFKrUFANT1Qk1w6yFxXG9qZrbnXI22c23MA==
+  dependencies:
+    "@material/ripple" "^5.1.0"
+    "@rmwc/base" "^6.1.4"
+    "@rmwc/provider" "^6.1.4"
+    "@rmwc/types" "^6.0.5"
+
+"@rmwc/textfield@^6.1.4":
+  version "6.1.4"
+  resolved "https://registry.yarnpkg.com/@rmwc/textfield/-/textfield-6.1.4.tgz#158ab1e599f83b64d1a821228749e360c14b21f4"
+  integrity sha512-K3b/exjDnHe5Lw8y8gzZ8u6O1EKOFv3Xiz4vy47TzchzOaQRHT6n0D87nACz30K1jROuaFirsUFI5z1i1Nk+Lw==
+  dependencies:
+    "@material/textfield" "^5.1.0"
+    "@rmwc/base" "^6.1.4"
+    "@rmwc/floating-label" "^6.1.4"
+    "@rmwc/icon" "^6.1.4"
+    "@rmwc/line-ripple" "^6.1.4"
+    "@rmwc/notched-outline" "^6.1.4"
+    "@rmwc/ripple" "^6.1.4"
+    "@rmwc/types" "^6.0.5"
+
 "@rmwc/toggleable@^6.0.14":
   version "6.0.14"
   resolved "https://registry.yarnpkg.com/@rmwc/toggleable/-/toggleable-6.0.14.tgz#1eca45f278aa2e808190be385ac29d494057a554"
@@ -1324,6 +1463,15 @@
     "@rmwc/formfield" "^6.0.14"
     "@rmwc/types" "^6.0.5"
 
+"@rmwc/tooltip@^6.1.4":
+  version "6.1.4"
+  resolved "https://registry.yarnpkg.com/@rmwc/tooltip/-/tooltip-6.1.4.tgz#f228c61145e4502c12aae64198ea70145ae3fb28"
+  integrity sha512-HPgEw2vqvJpHXefx+IuTHA6+MlrRV8M8NQAVWUJlc7PG3anF62Bg01Xy0FqWJ9D1FbDSYGE05DSmbTEbd3nboA==
+  dependencies:
+    "@rmwc/base" "^6.1.4"
+    "@rmwc/provider" "^6.1.4"
+    rc-tooltip "3.7.3"
+
 "@rmwc/top-app-bar@^6.1.3":
   version "6.1.3"
   resolved "https://registry.yarnpkg.com/@rmwc/top-app-bar/-/top-app-bar-6.1.3.tgz#235434cfaa2a9af72642e8d834712b2abfb87787"
@@ -1570,6 +1718,13 @@ acorn@^7.1.1:
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd"
   integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==
 
+add-dom-event-listener@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz#6a92db3a0dd0abc254e095c0f1dc14acbbaae310"
+  integrity sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==
+  dependencies:
+    object-assign "4.x"
+
 ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5:
   version "6.12.3"
   resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706"
@@ -1780,6 +1935,14 @@ babel-preset-jest@^26.1.0:
     babel-plugin-jest-hoist "^26.1.0"
     babel-preset-current-node-syntax "^0.1.2"
 
+babel-runtime@6.x, babel-runtime@^6.26.0:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
+  integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.11.0"
+
 balanced-match@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
@@ -2032,11 +2195,23 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
   dependencies:
     delayed-stream "~1.0.0"
 
+component-classes@^1.2.5:
+  version "1.2.6"
+  resolved "https://registry.yarnpkg.com/component-classes/-/component-classes-1.2.6.tgz#c642394c3618a4d8b0b8919efccbbd930e5cd691"
+  integrity sha1-xkI5TDYYpNiwuJGe/Mu9kw5c1pE=
+  dependencies:
+    component-indexof "0.0.3"
+
 component-emitter@^1.2.1:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
   integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
 
+component-indexof@0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/component-indexof/-/component-indexof-0.0.3.tgz#11d091312239eb8f32c8f25ae9cb002ffe8d3c24"
+  integrity sha1-EdCRMSI5648yyPJa6csAL/6NPCQ=
+
 concat-map@0.0.1:
   version "0.0.1"
   resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@@ -2054,6 +2229,11 @@ copy-descriptor@^0.1.0:
   resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
   integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
 
+core-js@^2.4.0:
+  version "2.6.11"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
+  integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==
+
 core-util-is@1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -2087,6 +2267,14 @@ cross-spawn@^7.0.0:
     shebang-command "^2.0.0"
     which "^2.0.1"
 
+css-animation@^1.3.2:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/css-animation/-/css-animation-1.6.1.tgz#162064a3b0d51f958b7ff37b3d6d4de18e17039e"
+  integrity sha512-/48+/BaEaHRY6kNQ2OIPzKf9A6g8WjZYjhiNDNuIVbsm5tXCGIAsHDjB4Xu1C4vXJtUWZo26O68OQkDpNBaPog==
+  dependencies:
+    babel-runtime "6.x"
+    component-classes "^1.2.5"
+
 cssom@^0.4.4:
   version "0.4.4"
   resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10"
@@ -2244,6 +2432,11 @@ doctrine@^3.0.0:
   dependencies:
     esutils "^2.0.2"
 
+dom-align@^1.7.0:
+  version "1.12.0"
+  resolved "https://registry.yarnpkg.com/dom-align/-/dom-align-1.12.0.tgz#56fb7156df0b91099830364d2d48f88963f5a29c"
+  integrity sha512-YkoezQuhp3SLFGdOlr5xkqZ640iXrnHAwVYcDg8ZKRUtO7mSzSC2BA5V0VuyAwPSJA4CLIc6EDDJh4bEsD2+zA==
+
 dom-helpers@^3.4.0:
   version "3.4.0"
   resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8"
@@ -4177,7 +4370,7 @@ oauth-sign@~0.9.0:
   resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
   integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
 
-object-assign@^4.1.1:
+object-assign@4.x, 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=
@@ -4472,7 +4665,7 @@ prompts@^2.0.1:
     kleur "^3.0.3"
     sisteransi "^1.0.4"
 
-prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
+prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
   version "15.7.2"
   resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
   integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -4509,6 +4702,69 @@ querystringify@^2.1.1:
   resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
   integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==
 
+raf@^3.4.0:
+  version "3.4.1"
+  resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
+  integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==
+  dependencies:
+    performance-now "^2.1.0"
+
+rc-align@^2.4.0:
+  version "2.4.5"
+  resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-2.4.5.tgz#c941a586f59d1017f23a428f0b468663fb7102ab"
+  integrity sha512-nv9wYUYdfyfK+qskThf4BQUSIadeI/dCsfaMZfNEoxm9HwOIioQ+LyqmMK6jWHAZQgOzMLaqawhuBXlF63vgjw==
+  dependencies:
+    babel-runtime "^6.26.0"
+    dom-align "^1.7.0"
+    prop-types "^15.5.8"
+    rc-util "^4.0.4"
+
+rc-animate@2.x:
+  version "2.11.1"
+  resolved "https://registry.yarnpkg.com/rc-animate/-/rc-animate-2.11.1.tgz#2666eeb6f1f2a495a13b2af09e236712278fdb2c"
+  integrity sha512-1NyuCGFJG/0Y+9RKh5y/i/AalUCA51opyyS/jO2seELpgymZm2u9QV3xwODwEuzkmeQ1BDPxMLmYLcTJedPlkQ==
+  dependencies:
+    babel-runtime "6.x"
+    classnames "^2.2.6"
+    css-animation "^1.3.2"
+    prop-types "15.x"
+    raf "^3.4.0"
+    rc-util "^4.15.3"
+    react-lifecycles-compat "^3.0.4"
+
+rc-tooltip@3.7.3:
+  version "3.7.3"
+  resolved "https://registry.yarnpkg.com/rc-tooltip/-/rc-tooltip-3.7.3.tgz#280aec6afcaa44e8dff0480fbaff9e87fc00aecc"
+  integrity sha512-dE2ibukxxkrde7wH9W8ozHKUO4aQnPZ6qBHtrTH9LoO836PjDdiaWO73fgPB05VfJs9FbZdmGPVEbXCeOP99Ww==
+  dependencies:
+    babel-runtime "6.x"
+    prop-types "^15.5.8"
+    rc-trigger "^2.2.2"
+
+rc-trigger@^2.2.2:
+  version "2.6.5"
+  resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-2.6.5.tgz#140a857cf28bd0fa01b9aecb1e26a50a700e9885"
+  integrity sha512-m6Cts9hLeZWsTvWnuMm7oElhf+03GOjOLfTuU0QmdB9ZrW7jR2IpI5rpNM7i9MvAAlMAmTx5Zr7g3uu/aMvZAw==
+  dependencies:
+    babel-runtime "6.x"
+    classnames "^2.2.6"
+    prop-types "15.x"
+    rc-align "^2.4.0"
+    rc-animate "2.x"
+    rc-util "^4.4.0"
+    react-lifecycles-compat "^3.0.4"
+
+rc-util@^4.0.4, rc-util@^4.15.3, rc-util@^4.4.0:
+  version "4.21.1"
+  resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-4.21.1.tgz#88602d0c3185020aa1053d9a1e70eac161becb05"
+  integrity sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==
+  dependencies:
+    add-dom-event-listener "^1.1.0"
+    prop-types "^15.5.10"
+    react-is "^16.12.0"
+    react-lifecycles-compat "^3.0.4"
+    shallowequal "^1.1.0"
+
 react-dom@^16.13.1:
   version "16.13.1"
   resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f"
@@ -4599,6 +4855,11 @@ readable-stream@^3.1.1:
     string_decoder "^1.1.1"
     util-deprecate "^1.0.1"
 
+regenerator-runtime@^0.11.0:
+  version "0.11.1"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
+  integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
+
 regenerator-runtime@^0.13.4:
   version "0.13.5"
   resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
@@ -4893,6 +5154,11 @@ set-value@^2.0.0, set-value@^2.0.1:
     is-plain-object "^2.0.3"
     split-string "^3.0.1"
 
+shallowequal@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
+  integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
+
 shebang-command@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"