未验证 提交 4913fdbb 编写于 作者: R RotPublic 提交者: GitHub

x2paddle转换前端代码 (#1153)

* finlys

* finlys2

* finlys3
Co-authored-by: Nchenjian <chenjian26@baidu.com>
上级 c6f47c6b
...@@ -44,8 +44,10 @@ ...@@ -44,8 +44,10 @@
"@tippyjs/react": "4.2.5", "@tippyjs/react": "4.2.5",
"@visualdl/icons": "2.2.1", "@visualdl/icons": "2.2.1",
"@visualdl/netron": "2.2.1", "@visualdl/netron": "2.2.1",
"@visualdl/netron2": "2.2.1",
"@visualdl/wasm": "2.2.1", "@visualdl/wasm": "2.2.1",
"antd": "^4.21.0", "antd": "^4.21.0",
"axios": "^1.1.3",
"bignumber.js": "9.0.1", "bignumber.js": "9.0.1",
"classnames": "2.3.1", "classnames": "2.3.1",
"d3": "7.0.1", "d3": "7.0.1",
...@@ -66,6 +68,7 @@ ...@@ -66,6 +68,7 @@
"polished": "4.1.3", "polished": "4.1.3",
"query-string": "7.0.1", "query-string": "7.0.1",
"react": "17.0.2", "react": "17.0.2",
"react-activation": "^0.12.1",
"react-content-loader": "6.0.3", "react-content-loader": "6.0.3",
"react-dnd": "14.0.3", "react-dnd": "14.0.3",
"react-dnd-html5-backend": "14.0.1", "react-dnd-html5-backend": "14.0.1",
...@@ -74,9 +77,10 @@ ...@@ -74,9 +77,10 @@
"react-i18next": "11.11.4", "react-i18next": "11.11.4",
"react-input-range": "1.3.0", "react-input-range": "1.3.0",
"react-rangeslider": "2.2.0", "react-rangeslider": "2.2.0",
"react-redux": "7.2.5", "react-redux": "7.2.9",
"react-router-dom": "5.3.0", "react-router-dom": "5.3.0",
"react-spinners": "0.11.0", "react-spinners": "0.11.0",
"react-stillness-component": "^0.9.0",
"react-table": "7.7.0", "react-table": "7.7.0",
"react-table-sticky": "1.1.3", "react-table-sticky": "1.1.3",
"react-toastify": "8.0.2", "react-toastify": "8.0.2",
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"error": "Error occurred", "error": "Error occurred",
"graph": "Graphs", "graph": "Graphs",
"graphDynamic": "dynamic", "graphDynamic": "dynamic",
"ToggleGraph": "X2Paddle",
"graphStatic": "static", "graphStatic": "static",
"high-dimensional": "High Dimensional", "high-dimensional": "High Dimensional",
"profiler":"performance analysis", "profiler":"performance analysis",
......
...@@ -53,8 +53,10 @@ ...@@ -53,8 +53,10 @@
"supported-model": "Supported models: ", "supported-model": "Supported models: ",
"Choose-model": "Choose a model", "Choose-model": "Choose a model",
"supported-model-list": "PaddlePaddle, ONNX, Keras, Core ML, Caffe, Caffe2, Darknet, MXNet, ncnn, TensorFlow Lite", "supported-model-list": "PaddlePaddle, ONNX, Keras, Core ML, Caffe, Caffe2, Darknet, MXNet, ncnn, TensorFlow Lite",
"supported-model-list-xpaddle": "ONNX、Caffe、Caffe2",
"upload-model": "Upload Model", "upload-model": "Upload Model",
"upload-tip": "Click or Drop file here to view neural network models", "upload-tip": "Click or Drop file here to view neural network models",
"upload-tip2": "Click or drag the file to the page to upload the model for model conversion",
"vertical": "Vertical", "vertical": "Vertical",
"zoom-in": "Zoom In", "zoom-in": "Zoom In",
"zoom-out": "Zoom Out" "zoom-out": "Zoom Out"
......
{
"transformation": "transformation",
"download": "download",
"convert_before": "Please convert before viewing",
"warin-info": "Please package the model description file. prototxt and parameter file. caffemodel into. tar to upload",
"warin-info2": "The model file does not support X2Paddle conversion temporarily",
"warin-info3": "Please convert before viewing",
"warin-info4": "The model has been converted, please do not click again",
"warin-info5": "Please upload the model file and convert it",
"warin-info6": "Model file has been converted, please do not click again",
"warin-info7": "Please upload the model file"
}
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"error": "发生错误", "error": "发生错误",
"graph": "网络结构", "graph": "网络结构",
"graphDynamic": "动态", "graphDynamic": "动态",
"ToggleGraph": "X2Paddle",
"graphStatic": "静态", "graphStatic": "静态",
"high-dimensional": "数据降维", "high-dimensional": "数据降维",
"profiler": "性能分析", "profiler": "性能分析",
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
}, },
"experimental-supported-model": "VisualDL实验性支持:", "experimental-supported-model": "VisualDL实验性支持:",
"experimental-supported-model-list": "TorchScript、PyTorch、Torch、 ArmNN、BigDL、Chainer、CNTK、Deeplearning4j、MediaPipe、ML.NET、MNN、OpenVINO、Scikit-learn、Tengine、TensorFlow.js、TensorFlow", "experimental-supported-model-list": "TorchScript、PyTorch、Torch、 ArmNN、BigDL、Chainer、CNTK、Deeplearning4j、MediaPipe、ML.NET、MNN、OpenVINO、Scikit-learn、Tengine、TensorFlow.js、TensorFlow",
"export-file": "导出文件", "export-file": "导出文件",
"export-png": "PNG", "export-png": "PNG",
"export-svg": "SVG", "export-svg": "SVG",
...@@ -52,8 +53,10 @@ ...@@ -52,8 +53,10 @@
"keep-expanded": "保持展开", "keep-expanded": "保持展开",
"supported-model": "VisualDL支持:", "supported-model": "VisualDL支持:",
"supported-model-list": "PaddlePaddle、ONNX、Keras、Core ML、Caffe、Caffe2、Darknet、MXNet、ncnn、TensorFlow Lite", "supported-model-list": "PaddlePaddle、ONNX、Keras、Core ML、Caffe、Caffe2、Darknet、MXNet、ncnn、TensorFlow Lite",
"supported-model-list-xpaddle": "ONNX、Caffe、Caffe2",
"upload-model": "上传模型", "upload-model": "上传模型",
"upload-tip": "点击或拖拽文件到页面上传模型,进行结构展示", "upload-tip": "点击或拖拽文件到页面上传模型,进行结构展示",
"upload-tip2": "点击或拖拽文件到页面上传模型,进行模型转换",
"vertical": "垂直", "vertical": "垂直",
"Choose-model": "选择模型", "Choose-model": "选择模型",
"zoom-in": "放大", "zoom-in": "放大",
......
{
"transformation": "转换",
"download": "下载",
"convert_before": "Please convert before viewing",
"warin-info": "请将模型描述文件.prototxt和参数文件.caffemodel打包成.tar上传",
"warin-info2": "该模型文件暂不支持X2Paddle转换",
"warin-info3": "请先进行转换,再查看",
"warin-info4": "模型已转换,请勿再次点击",
"warin-info5": "请上传模型文件并转换",
"warin-info6": "模型文件已转换,请勿再次点击",
"warin-info7": "请上传模型文件"
}
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
// cspell:words pnpify svgs entrypoints // cspell:words pnpify svgs entrypoints
import * as env from './builder/env.js'; import * as env from './builder/env.js';
import {fileURLToPath} from 'url'; import {fileURLToPath} from 'url';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
...@@ -37,7 +36,8 @@ function isWorkspace() { ...@@ -37,7 +36,8 @@ function isWorkspace() {
const iconsPath = path.dirname(resolve.sync(cwd, '@visualdl/icons')); const iconsPath = path.dirname(resolve.sync(cwd, '@visualdl/icons'));
const netronPath = path.dirname(resolve.sync(cwd, '@visualdl/netron')); const netronPath = path.dirname(resolve.sync(cwd, '@visualdl/netron'));
const TracePath = path.dirname(resolve.sync(cwd, './public/static')); const netronPath2 = path.dirname(resolve.sync(cwd, '@visualdl/netron2'));
const wasmPath = path.dirname(resolve.sync(cwd, '@visualdl/wasm')); const wasmPath = path.dirname(resolve.sync(cwd, '@visualdl/wasm'));
const dest = path.resolve(cwd, './dist/__snowpack__/link/packages'); const dest = path.resolve(cwd, './dist/__snowpack__/link/packages');
...@@ -66,8 +66,6 @@ export default { ...@@ -66,8 +66,6 @@ export default {
plugins: [ plugins: [
'@snowpack/plugin-react-refresh', '@snowpack/plugin-react-refresh',
'@snowpack/plugin-dotenv', '@snowpack/plugin-dotenv',
'snowpack-plugin-less',
'@snowpack/plugin-sass',
[ [
'@snowpack/plugin-typescript', '@snowpack/plugin-typescript',
{ {
...@@ -101,8 +99,8 @@ export default { ...@@ -101,8 +99,8 @@ export default {
destination: path.join(dest, 'netron/dist') destination: path.join(dest, 'netron/dist')
}, },
{ {
source: [path.join(TracePath, '**/*')], source: [path.join(netronPath2, '**/*')],
destination: path.join(dest, 'trace/dist') destination: path.join(dest, 'netron2/dist')
}, },
{ {
source: [path.join(wasmPath, '*.{js,wasm}')], source: [path.join(wasmPath, '*.{js,wasm}')],
...@@ -118,8 +116,9 @@ export default { ...@@ -118,8 +116,9 @@ export default {
}, },
packageOptions: { packageOptions: {
polyfillNode: true, polyfillNode: true,
// knownEntrypoints: ['chai', '@testing-library/react', 'fetch-mock/esm/client', 'react-is','rc-util/es/hooks/useId','rc-util/es/Portal','rc-util/es/Dom/contains','rc-util/es/Dom/css','rc-util/es/getScrollBarSize','rc-util/es/PortalWrapper','rc-select/es/hooks/useId','rc-util/es/Dom/isVisible','rc-util/es/Dom/focus','rc-util/es/Dom/focus'] namedExports: ['gl-vec2', 'dagre'],
knownEntrypoints: ['chai', '@testing-library/react', 'fetch-mock/esm/client', 'react-is', 'antd'] // knownEntrypoints: ['chai', '@testing-library/react', 'fetch-mock/esm/client']
knownEntrypoints: ['chai', '@testing-library/react']
}, },
buildOptions: { buildOptions: {
out: 'dist', out: 'dist',
......
...@@ -141,7 +141,12 @@ const App: FunctionComponent = () => { ...@@ -141,7 +141,12 @@ const App: FunctionComponent = () => {
</ErrorBoundary> </ErrorBoundary>
</Router> </Router>
</Main> </Main>
<ToastContainer /> <ToastContainer
autoClose={100000}
style={{wordBreak: 'break-all'}}
draggable={false}
closeOnClick={false}
/>
</SWRConfig> </SWRConfig>
</div> </div>
); );
......
...@@ -45,7 +45,7 @@ const Title = styled.div` ...@@ -45,7 +45,7 @@ const Title = styled.div`
const Content = styled.div` const Content = styled.div`
padding: ${rem(20)}; padding: ${rem(20)};
height: calc(100% - ${rem(60)}); height: ${rem(600)};
overflow: auto; overflow: auto;
`; `;
......
...@@ -208,7 +208,9 @@ const Graph = React.forwardRef<GraphRef, GraphProps>( ...@@ -208,7 +208,9 @@ const Graph = React.forwardRef<GraphRef, GraphProps>(
}; };
}, [handler, dispatch]); }, [handler, dispatch]);
useEffect(() => (ready && dispatch('change-files', files)) || undefined, [dispatch, files, ready]); useEffect(() => {
(ready && dispatch('change-files', files)) || undefined;
}, [dispatch, files, ready]);
useEffect( useEffect(
() => (ready && dispatch('toggle-attributes', showAttributes)) || undefined, () => (ready && dispatch('toggle-attributes', showAttributes)) || undefined,
[dispatch, showAttributes, ready] [dispatch, showAttributes, ready]
......
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type {Documentation, OpenedResult, Properties, SearchItem, SearchResult} from '~/resource/graph/types';
import React, {useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react';
import {contentHeight, position, primaryColor, rem, size, transitionProps} from '~/utils/style';
import ChartToolbox from '~/components/ChartToolbox';
import HashLoader from 'react-spinners/HashLoader';
import logo from '~/assets/images/netron.png';
import netron2 from '@visualdl/netron2';
import styled from 'styled-components';
import {toast} from 'react-toastify';
import useTheme from '~/hooks/useTheme';
import {useTranslation} from 'react-i18next';
const PUBLIC_PATH: string = import.meta.env.SNOWPACK_PUBLIC_PATH;
let IFRAME_HOST = `${window.location.protocol}//${window.location.host}`;
if (PUBLIC_PATH.startsWith('http')) {
const url = new URL(PUBLIC_PATH);
IFRAME_HOST = `${url.protocol}//${url.host}`;
}
const toolboxHeight = rem(40);
const Wrapper = styled.div`
position: relative;
height: ${contentHeight};
background-color: var(--background-color);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
${transitionProps('background-color')}
`;
const RenderContent = styled.div<{show: boolean}>`
position: absolute;
top: 0;
left: 0;
${size('100%', '100%')}
opacity: ${props => (props.show ? 1 : 0)};
z-index: ${props => (props.show ? 0 : -1)};
pointer-events: ${props => (props.show ? 'auto' : 'none')};
`;
const Toolbox = styled(ChartToolbox)`
height: ${toolboxHeight};
border-bottom: 1px solid var(--border-color);
padding: 0 ${rem(20)};
${transitionProps('border-color')}
`;
const Content = styled.div`
position: relative;
height: calc(100% - ${toolboxHeight});
> iframe {
${size('100%', '100%')}
border: none;
}
> .powered-by {
display: block;
${position('absolute', null, null, rem(20), rem(30))}
color: var(--graph-copyright-color);
font-size: ${rem(14)};
user-select: none;
img {
height: 1em;
filter: var(--graph-copyright-logo-filter);
vertical-align: middle;
}
}
`;
const Loading = styled.div`
${size('100%', '100%')}
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overscroll-behavior: none;
cursor: progress;
font-size: ${rem(16)};
line-height: ${rem(60)};
`;
export type GraphRef = {
export(type: 'svg' | 'png'): void;
changeGraph(name: string): void;
search(value: string): void;
select(item: SearchItem): void;
showModelProperties(): void;
showNodeDocumentation(data: Properties): void;
show2(): void;
};
type GraphProps = {
files: FileList | File[] | null;
uploader: JSX.Element;
showAttributes: boolean;
showInitializers: boolean;
showNames: boolean;
horizontal: boolean;
onRendered?: () => unknown;
onOpened?: (data: OpenedResult) => unknown;
onSearch?: (data: SearchResult) => unknown;
onShowModelProperties?: (data: Properties) => unknown;
onShowNodeProperties?: (data: Properties) => unknown;
onShowNodeDocumentation?: (data: Documentation) => unknown;
};
const Graph = React.forwardRef<GraphRef, GraphProps>(
(
{
files,
uploader,
showAttributes,
showInitializers,
showNames,
horizontal,
onRendered,
onOpened,
onSearch,
onShowModelProperties,
onShowNodeProperties,
onShowNodeDocumentation
},
ref
) => {
const {t} = useTranslation('graph');
const theme = useTheme();
const [ready, setReady] = useState(false);
const [loading, setLoading] = useState(false);
const [rendered, setRendered] = useState(false);
const iframe = useRef<HTMLIFrameElement>(null);
const handler = useCallback(
(event: MessageEvent) => {
if (event.data) {
const {type, data} = event.data;
switch (type) {
case 'status':
switch (data) {
case 'ready':
return setReady(true);
case 'loading':
return setLoading(true);
case 'rendered':
setLoading(false);
setRendered(true);
console.log('函数执行了');
onRendered?.();
return;
}
return;
case 'opened':
return onOpened?.(data);
case 'search':
return onSearch?.(data);
case 'cancel':
return setLoading(false);
case 'error':
toast.error(data);
setLoading(false);
return;
case 'show-model-properties':
return onShowModelProperties?.(data);
case 'show-node-properties':
return onShowNodeProperties?.(data);
case 'show-node-documentation':
return onShowNodeDocumentation?.(data);
}
}
},
[onRendered, onOpened, onSearch, onShowModelProperties, onShowNodeProperties, onShowNodeDocumentation]
);
const dispatch = useCallback((type: string, data?: unknown) => {
iframe.current?.contentWindow?.postMessage(
{
type,
data
},
IFRAME_HOST
);
}, []);
useEffect(() => {
window.addEventListener('message', handler);
dispatch('ready');
return () => {
window.removeEventListener('message', handler);
};
}, [handler, dispatch]);
useEffect(() => {
console.log('GraphStatic2', files, ready);
(files && ready && dispatch('change-files', files)) || undefined;
}, [dispatch, files, ready]);
useEffect(
() => (ready && dispatch('toggle-attributes', showAttributes)) || undefined,
[dispatch, showAttributes, ready]
);
useEffect(
() => (ready && dispatch('toggle-initializers', showInitializers)) || undefined,
[dispatch, showInitializers, ready]
);
useEffect(() => (ready && dispatch('toggle-names', showNames)) || undefined, [dispatch, showNames, ready]);
useEffect(
() => (ready && dispatch('toggle-direction', horizontal)) || undefined,
[dispatch, horizontal, ready]
);
useEffect(() => (ready && dispatch('toggle-theme', theme)) || undefined, [dispatch, theme, ready]);
useImperativeHandle(ref, () => ({
export(type) {
dispatch('export', type);
},
changeGraph(name) {
dispatch('change-graph', name);
},
search(value) {
dispatch('search', value);
},
select(item) {
dispatch('select', item);
},
showModelProperties() {
dispatch('show-model-properties');
},
showNodeDocumentation(data) {
dispatch('show-node-documentation', data);
},
show2() {
dispatch('show2');
}
}));
const content = useMemo(() => {
if (!ready || loading) {
return (
<Loading>
<HashLoader size="60px" color={primaryColor} />
</Loading>
);
}
if (ready && !rendered) {
return (
<Loading>
<HashLoader size="60px" color={primaryColor} />
</Loading>
);
}
return null;
}, [ready, loading, rendered, uploader]);
return (
<Wrapper>
{content}
<RenderContent show={!loading && rendered}>
<Toolbox
items={[
{
icon: 'zoom-in',
tooltip: t('graph:zoom-in'),
onClick: () => dispatch('zoom-in')
},
{
icon: 'zoom-out',
tooltip: t('graph:zoom-out'),
onClick: () => dispatch('zoom-out')
},
{
icon: 'restore-size',
tooltip: t('graph:restore-size'),
onClick: () => dispatch('zoom-reset')
}
]}
reversed
tooltipPlacement="bottom"
/>
<Content>
<iframe
ref={iframe}
src={PUBLIC_PATH + netron2}
frameBorder={0}
scrolling="no"
marginWidth={0}
marginHeight={0}
></iframe>
<a
className="powered-by"
href="https://github.com/lutzroeder/netron"
target="_blank"
rel="noreferrer"
>
Powered by <img src={PUBLIC_PATH + logo} alt="netron" />
</a>
</Content>
</RenderContent>
</Wrapper>
);
}
);
Graph.displayName = 'Graph';
export default Graph;
...@@ -77,9 +77,10 @@ const SupportTable = styled.table` ...@@ -77,9 +77,10 @@ const SupportTable = styled.table`
type UploaderProps = { type UploaderProps = {
onClickUpload?: () => unknown; onClickUpload?: () => unknown;
onDropFiles?: (files: FileList) => unknown; onDropFiles?: (files: FileList) => unknown;
Xpaddlae?: boolean;
}; };
const Uploader: FunctionComponent<UploaderProps> = ({onClickUpload, onDropFiles}) => { const Uploader: FunctionComponent<UploaderProps> = ({onClickUpload, onDropFiles, Xpaddlae}) => {
const {t} = useTranslation('graph'); const {t} = useTranslation('graph');
const [active, setActive] = useState(false); const [active, setActive] = useState(false);
...@@ -112,22 +113,31 @@ const Uploader: FunctionComponent<UploaderProps> = ({onClickUpload, onDropFiles} ...@@ -112,22 +113,31 @@ const Uploader: FunctionComponent<UploaderProps> = ({onClickUpload, onDropFiles}
onDragLeave={onDragLeave} onDragLeave={onDragLeave}
> >
<Icon type="upload" className="upload-icon" /> <Icon type="upload" className="upload-icon" />
<span>{t('graph:upload-tip')}</span> {Xpaddlae ? <span>{t('graph:upload-tip2')}</span> : <span>{t('graph:upload-tip')}</span>}
<Button type="primary" rounded className="upload-button" onClick={onClick}> <Button type="primary" rounded className="upload-button" onClick={onClick}>
{t('graph:upload-model')} {t('graph:upload-model')}
</Button> </Button>
</DropZone> </DropZone>
<SupportTable> <SupportTable>
<tbody> {Xpaddlae ? (
<tr> <tbody>
<td>{t('graph:supported-model')}</td> <tr>
<td>{t('graph:supported-model-list')}</td> <td>{t('graph:supported-model')}</td>
</tr> <td>{t('graph:supported-model-list-xpaddle')}</td>
<tr> </tr>
<td>{t('graph:experimental-supported-model')}</td> </tbody>
<td>{t('graph:experimental-supported-model-list')}</td> ) : (
</tr> <tbody>
</tbody> <tr>
<td>{t('graph:supported-model')}</td>
<td>{t('graph:supported-model-list')}</td>
</tr>
<tr>
<td>{t('graph:experimental-supported-model')}</td>
<td>{t('graph:experimental-supported-model-list')}</td>
</tr>
</tbody>
)}
</SupportTable> </SupportTable>
</> </>
); );
......
import React from 'react';
function index() {
return <div>index</div>;
}
export default index;
...@@ -17,7 +17,17 @@ ...@@ -17,7 +17,17 @@
import Aside, {AsideSection} from '~/components/Aside'; import Aside, {AsideSection} from '~/components/Aside';
import type {Documentation, OpenedResult, Properties, SearchItem, SearchResult} from '~/resource/graph/types'; import type {Documentation, OpenedResult, Properties, SearchItem, SearchResult} from '~/resource/graph/types';
import GraphComponent, {GraphRef} from '~/components/GraphPage/GraphStatic'; import GraphComponent, {GraphRef} from '~/components/GraphPage/GraphStatic';
import React, {FunctionComponent, useCallback, useEffect, useMemo, useRef, useState} from 'react'; import React, {
FunctionComponent,
ForwardRefRenderFunction,
useImperativeHandle,
forwardRef,
useCallback,
useEffect,
useMemo,
useRef,
useState
} from 'react';
import Select, {SelectProps} from '~/components/Select'; import Select, {SelectProps} from '~/components/Select';
import {actions, selectors} from '~/store'; import {actions, selectors} from '~/store';
import {primaryColor, rem, size} from '~/utils/style'; import {primaryColor, rem, size} from '~/utils/style';
...@@ -84,8 +94,17 @@ const Loading = styled.div` ...@@ -84,8 +94,17 @@ const Loading = styled.div`
font-size: ${rem(16)}; font-size: ${rem(16)};
line-height: ${rem(60)}; line-height: ${rem(60)};
`; `;
type GraphProps = {
const Graph: FunctionComponent = () => { changeName: (name: string) => void;
show?: boolean;
changeshowdata?: () => void;
Xpaddlae?: boolean;
};
type pageRef = {
files: FileList | File[] | null;
setNodeDocumentations: () => void;
};
const Graph = React.forwardRef<pageRef, GraphProps>(({changeName, changeshowdata, Xpaddlae, show = true}, ref) => {
const {t} = useTranslation(['graph', 'common']); const {t} = useTranslation(['graph', 'common']);
const storeDispatch = useDispatch(); const storeDispatch = useDispatch();
...@@ -97,7 +116,10 @@ const Graph: FunctionComponent = () => { ...@@ -97,7 +116,10 @@ const Graph: FunctionComponent = () => {
const setModelFile = useCallback( const setModelFile = useCallback(
(f: FileList | File[]) => { (f: FileList | File[]) => {
storeDispatch(actions.graph.setModel(f)); storeDispatch(actions.graph.setModel(f));
const name = f[0].name.substring(f[0].name.lastIndexOf('.') + 1);
changeName && changeName(name);
setFiles(f); setFiles(f);
changeshowdata && changeshowdata();
}, },
[storeDispatch] [storeDispatch]
); );
...@@ -116,14 +138,13 @@ const Graph: FunctionComponent = () => { ...@@ -116,14 +138,13 @@ const Graph: FunctionComponent = () => {
}, },
[setModelFile] [setModelFile]
); );
const {data, loading} = useRequest<BlobResponse>(files ? null : '/graph/graph');
const {data, loading} = useRequest<BlobResponse>(files ? null : '/graph/static_graph'); // useEffect(() => {
// if (data?.data?.size) {
useEffect(() => { // setFiles([new File([data.data], data.filename || 'unknown_model')]);
if (data?.data?.size) { // }
setFiles([new File([data.data], data.filename || 'unknown_model')]); // }, [data]);
}
}, [data]);
const [modelGraphs, setModelGraphs] = useState<OpenedResult['graphs']>([]); const [modelGraphs, setModelGraphs] = useState<OpenedResult['graphs']>([]);
const [selectedGraph, setSelectedGraph] = useState<NonNullable<OpenedResult['selected']>>(''); const [selectedGraph, setSelectedGraph] = useState<NonNullable<OpenedResult['selected']>>('');
...@@ -156,12 +177,20 @@ const Graph: FunctionComponent = () => { ...@@ -156,12 +177,20 @@ const Graph: FunctionComponent = () => {
const [modelData, setModelData] = useState<Properties | null>(null); const [modelData, setModelData] = useState<Properties | null>(null);
const [nodeData, setNodeData] = useState<Properties | null>(null); const [nodeData, setNodeData] = useState<Properties | null>(null);
const [nodeDocumentation, setNodeDocumentation] = useState<Documentation | null>(null); const [nodeDocumentation, setNodeDocumentation] = useState<Documentation | null>(null);
const [renderedflag3, setRenderedflag3] = useState(true);
useEffect(() => { useEffect(() => {
setSearch(''); setSearch('');
setSearchResult({text: '', result: []}); setSearchResult({text: '', result: []});
}, [files, showAttributes, showInitializers, showNames]); }, [files, showAttributes, showInitializers, showNames]);
useEffect(() => {
if (!show) {
setRenderedflag3(false);
} else {
setRenderedflag3(true);
setNodeData(null);
}
}, [show]);
const bottom = useMemo( const bottom = useMemo(
() => () =>
searching ? null : ( searching ? null : (
...@@ -173,7 +202,12 @@ const Graph: FunctionComponent = () => { ...@@ -173,7 +202,12 @@ const Graph: FunctionComponent = () => {
); );
const [rendered, setRendered] = useState(false); const [rendered, setRendered] = useState(false);
useImperativeHandle(ref, () => ({
files,
setNodeDocumentations: () => {
setRenderedflag3(false);
}
}));
const aside = useMemo(() => { const aside = useMemo(() => {
if (!rendered || loading) { if (!rendered || loading) {
return null; return null;
...@@ -185,7 +219,8 @@ const Graph: FunctionComponent = () => { ...@@ -185,7 +219,8 @@ const Graph: FunctionComponent = () => {
</Aside> </Aside>
); );
} }
if (nodeData) { console.log('nodeData && renderedflag3', nodeData, renderedflag3);
if (nodeData && renderedflag3) {
return ( return (
<Aside width={rem(360)}> <Aside width={rem(360)}>
<NodePropertiesSidebar <NodePropertiesSidebar
...@@ -283,14 +318,13 @@ const Graph: FunctionComponent = () => { ...@@ -283,14 +318,13 @@ const Graph: FunctionComponent = () => {
rendered, rendered,
loading, loading,
nodeData, nodeData,
nodeDocumentation nodeDocumentation,
renderedflag3
]); ]);
const uploader = useMemo( const uploader = useMemo(
() => <Uploader onClickUpload={onClickFile} onDropFiles={setModelFile} />, () => <Uploader onClickUpload={onClickFile} onDropFiles={setModelFile} Xpaddlae={Xpaddlae} />,
[onClickFile, setModelFile] [onClickFile, setModelFile]
); );
return ( return (
<> <>
<Title>{t('common:graph')}</Title> <Title>{t('common:graph')}</Title>
...@@ -334,6 +368,6 @@ const Graph: FunctionComponent = () => { ...@@ -334,6 +368,6 @@ const Graph: FunctionComponent = () => {
</Content> </Content>
</> </>
); );
}; });
export default Graph; export default Graph;
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Aside, {AsideSection} from '~/components/Aside';
import type {Documentation, OpenedResult, Properties, SearchItem, SearchResult} from '~/resource/graph/types';
import GraphComponent, {GraphRef} from '~/components/GraphPage/GraphStatic2';
import React, {FunctionComponent, useImperativeHandle, useCallback, useEffect, useMemo, useRef, useState} from 'react';
import Select, {SelectProps} from '~/components/Select';
import {actions, selectors} from '~/store';
import {primaryColor, rem, size} from '~/utils/style';
import {useDispatch, useSelector} from 'react-redux';
import type {BlobResponse} from '~/utils/fetch';
import Button from '~/components/Button';
import Checkbox from '~/components/Checkbox';
import Content from '~/components/Content';
import Field from '~/components/Field';
import HashLoader from 'react-spinners/HashLoader';
import ModelPropertiesDialog from '~/components/GraphPage/ModelPropertiesDialog';
import NodeDocumentationSidebar from '~/components/GraphPage/NodeDocumentationSidebar';
import NodePropertiesSidebar from '~/components/GraphPage/NodePropertiesSidebar';
import RadioButton from '~/components/RadioButton';
import RadioGroup from '~/components/RadioGroup';
import Search from '~/components/GraphPage/Search';
import Title from '~/components/Title';
import Uploader from '~/components/GraphPage/Uploader';
import styled from 'styled-components';
import useRequest from '~/hooks/useRequest';
import {useTranslation} from 'react-i18next';
const FullWidthButton = styled(Button)`
width: 100%;
`;
const FullWidthSelect = styled<React.FunctionComponent<SelectProps<NonNullable<OpenedResult['selected']>>>>(Select)`
width: 100%;
`;
const ExportButtonWrapper = styled.div`
display: flex;
justify-content: space-between;
> * {
flex: 1 1 auto;
&:not(:last-child) {
margin-right: ${rem(20)};
}
}
`;
// TODO: better way to auto fit height
const SearchSection = styled(AsideSection)`
max-height: calc(100% - ${rem(40)});
display: flex;
flex-direction: column;
&:not(:last-child) {
padding-bottom: 0;
}
`;
const Loading = styled.div`
${size('100%', '100%')}
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overscroll-behavior: none;
cursor: progress;
font-size: ${rem(16)};
line-height: ${rem(60)};
`;
type GraphProps = {
changeRendered?: () => void;
files?: FileList | File[] | null;
changeName?: () => void;
show?: boolean;
};
type pageRef = {
setModelFiles: (f: FileList | File[]) => void;
setNodeDocumentations: () => void;
rendered: boolean;
};
const Graph = React.forwardRef<pageRef, GraphProps>(({changeRendered, show = true}, ref) => {
const {t} = useTranslation(['graph', 'common']);
const storeDispatch = useDispatch();
const storeModel = useSelector(selectors.graph.model);
const graph = useRef<GraphRef>(null);
const file = useRef<HTMLInputElement>(null);
const [files, setFiles] = useState<FileList | File[] | null>(storeModel);
const [modelGraphs, setModelGraphs] = useState<OpenedResult['graphs']>([]);
const [selectedGraph, setSelectedGraph] = useState<NonNullable<OpenedResult['selected']>>('');
const {data, loading} = useRequest<BlobResponse>(files ? null : '/graph/graph');
const setModelFile = useCallback(
(f: FileList | File[]) => {
storeDispatch(actions.graph.setModel(f));
setFiles(f);
},
[storeDispatch]
);
const onClickFile = useCallback(() => {
if (file.current) {
file.current.value = '';
file.current.click();
}
}, []);
// const onChangeFile = (e: React.ChangeEvent<HTMLInputElement>) => {
// const target = e.target as EventTarget & HTMLInputElement;
// const file: FileList | null = target.files as FileList;
// if (file[0].name.split('.')[1] === 'pdmodel') {
// alert('该页面只能解析paddle的模型,如需解析请跳转网络结构静态图页面');
// return;
// }
// if (target && target.files && target.files.length) {
// fileUploader(target.files);
// }
// };
const onChangeFile = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const target = e.target;
if (target && target.files && target.files.length) {
setModelFile(target.files);
}
},
[setModelFile]
);
const setOpenedModel = useCallback((data: OpenedResult) => {
setModelGraphs(data.graphs);
setSelectedGraph(data.selected || '');
}, []);
const changeGraph = useCallback((name: string) => {
setSelectedGraph(name);
graph.current?.changeGraph(name);
}, []);
const [search, setSearch] = useState('');
const [searching, setSearching] = useState(false);
const [searchResult, setSearchResult] = useState<SearchResult>({text: '', result: []});
const onSearch = useCallback((value: string) => {
setSearch(value);
graph.current?.search(value);
}, []);
const onSelect = useCallback((item: SearchItem) => {
setSearch(item.name);
graph.current?.select(item);
}, []);
const [showAttributes, setShowAttributes] = useState(false);
const [showInitializers, setShowInitializers] = useState(true);
const [showNames, setShowNames] = useState(false);
const [horizontal, setHorizontal] = useState(false);
const [modelData, setModelData] = useState<Properties | null>(null);
const [nodeData, setNodeData] = useState<Properties | null>(null);
const [nodeDocumentation, setNodeDocumentation] = useState<Documentation | null>(null);
const [rendered, setRendered] = useState(false);
const [renderedflag, setRenderedflag] = useState(0);
const [renderedflag2, setRenderedflag2] = useState(0);
const [renderedflag3, setRenderedflag3] = useState(true);
useEffect(() => {
setSearch('');
setSearchResult({text: '', result: []});
}, [files, showAttributes, showInitializers, showNames]);
useEffect(() => {
if (renderedflag > 1 && renderedflag2 === 0) {
changeRendered && changeRendered();
setRenderedflag2(1);
setNodeDocumentation(null);
}
}, [renderedflag]);
useEffect(() => {
if (!show) {
setRenderedflag3(false);
} else {
setRenderedflag3(true);
setNodeData(null);
}
}, [show]);
const bottom = useMemo(
() =>
searching ? null : (
<FullWidthButton type="primary" rounded onClick={onClickFile}>
{t('graph:change-model')}
</FullWidthButton>
),
[t, onClickFile, searching]
);
useImperativeHandle(ref, () => ({
setModelFiles: file => {
setModelFile(file);
},
setNodeDocumentations: () => {
setRenderedflag3(false);
},
rendered: rendered
}));
const aside = useMemo(() => {
if (!rendered || loading) {
return null;
}
if (nodeDocumentation) {
return (
<Aside width={rem(360)}>
<NodeDocumentationSidebar data={nodeDocumentation} onClose={() => setNodeDocumentation(null)} />
</Aside>
);
}
console.log('nodeData && renderedflag3', nodeData, renderedflag3);
if (nodeData && renderedflag3) {
return (
<Aside width={rem(360)}>
<NodePropertiesSidebar
data={nodeData}
onClose={() => setNodeData(null)}
showNodeDocumentation={() => graph.current?.showNodeDocumentation(nodeData)}
/>
</Aside>
);
}
return (
<Aside>
<SearchSection>
<Search
text={search}
data={searchResult}
onChange={onSearch}
onSelect={onSelect}
onActive={() => setSearching(true)}
onDeactive={() => setSearching(false)}
/>
</SearchSection>
{!searching && (
<>
<AsideSection>
<FullWidthButton onClick={() => graph.current?.showModelProperties()}>
{t('graph:model-properties')}
</FullWidthButton>
</AsideSection>
{modelGraphs.length > 1 && (
<AsideSection>
<Field label={t('graph:subgraph')}>
<FullWidthSelect list={modelGraphs} value={selectedGraph} onChange={changeGraph} />
</Field>
</AsideSection>
)}
<AsideSection>
<Field label={t('graph:display-data')}>
<div>
<Checkbox checked={showAttributes} onChange={setShowAttributes}>
{t('graph:show-attributes')}
</Checkbox>
</div>
<div>
<Checkbox checked={showInitializers} onChange={setShowInitializers}>
{t('graph:show-initializers')}
</Checkbox>
</div>
<div>
<Checkbox checked={showNames} onChange={setShowNames}>
{t('graph:show-node-names')}
</Checkbox>
</div>
</Field>
</AsideSection>
<AsideSection>
<Field label={t('graph:direction')}>
<RadioGroup value={horizontal} onChange={setHorizontal}>
<RadioButton value={false}>{t('graph:vertical')}</RadioButton>
<RadioButton value={true}>{t('graph:horizontal')}</RadioButton>
</RadioGroup>
</Field>
</AsideSection>
<AsideSection>
<Field label={t('graph:export-file')}>
<ExportButtonWrapper>
<Button onClick={() => graph.current?.export('png')}>
{t('graph:export-png')}
</Button>
<Button onClick={() => graph.current?.export('svg')}>
{t('graph:export-svg')}
</Button>
</ExportButtonWrapper>
</Field>
</AsideSection>
</>
)}
</Aside>
);
}, [
t,
bottom,
search,
searching,
searchResult,
modelGraphs,
selectedGraph,
changeGraph,
onSearch,
onSelect,
showAttributes,
showInitializers,
showNames,
horizontal,
rendered,
loading,
nodeData,
nodeDocumentation,
renderedflag3
]);
const uploader = useMemo(
() => <Uploader onClickUpload={onClickFile} onDropFiles={setModelFile} />,
[onClickFile, setModelFile]
);
return (
<>
<Title>{t('common:graph')}</Title>
<ModelPropertiesDialog data={modelData} onClose={() => setModelData(null)} />
<Content aside={aside}>
{loading ? (
<Loading>
<HashLoader size="60px" color={primaryColor} />
</Loading>
) : (
<GraphComponent
ref={graph}
files={files}
uploader={uploader}
showAttributes={showAttributes}
showInitializers={showInitializers}
showNames={showNames}
horizontal={horizontal}
onRendered={() => {
setRendered(true);
setRenderedflag(flag => {
return flag + 1;
});
}}
onOpened={setOpenedModel}
onSearch={data => {
setSearchResult(data);
}}
onShowModelProperties={data => setModelData(data)}
onShowNodeProperties={data => {
setNodeData(data);
setNodeDocumentation(null);
}}
onShowNodeDocumentation={data => setNodeDocumentation(data)}
/>
)}
<input
ref={file}
type="file"
multiple={false}
onChange={onChangeFile}
style={{
display: 'none'
}}
/>
</Content>
</>
);
});
export default Graph;
import React, {useState, useEffect, useRef, useCallback, useMemo} from 'react';
import {rem, primaryColor, size} from '~/utils/style';
import Content from '~/components/Content';
import {toast} from 'react-toastify';
import {fetcher} from '~/utils/fetch';
import GraphStatic from '~/pages/graphStatic';
import GraphStatic2 from '~/pages/graphStatic2';
import HashLoader from 'react-spinners/HashLoader';
import styled from 'styled-components';
import {useTranslation} from 'react-i18next';
const ButtonContent = styled.section`
display: flex;
.active {
background-color: #2932e1;
color: white;
}
.un_active {
background-color: white;
color: #2932e1;
}
.disabled {
background: #ccc;
color: white;
cursor: not-allowed;
}
`;
type Fn = (data: FcResponse<any>) => unknown;
interface IAnyObj {
[index: string]: unknown;
}
interface FcResponse<T> {
errno: string;
errmsg: string;
data: T;
}
const Article = styled.article`
flex: auto;
display: flex;
min-width: 0;
margin: ${10};
min-height: ${10};
`;
const Buttons = styled.div`
width: 49%;
height: ${rem(40)};
line-height: ${rem(40)};
text-align: center;
font-size: 16px;
`;
const Contents = styled.div`
height: 100%;
`;
const Loading = styled.div`
${size('100%', '100%')}
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overscroll-behavior: none;
cursor: progress;
font-size: ${rem(16)};
line-height: ${rem(60)};
`;
const Aside = styled.aside`
width: ${rem(260)};
display: flex;
`;
function App() {
const {t} = useTranslation(['togglegraph']);
const [show, setShow] = useState({
show: true,
show2: false
});
const [showData, setshowData] = useState<any>(null);
const [baseId, setBaseId] = useState<any>(false);
const [loading, setLoading] = useState<any>(false);
const [file_names, setfile_names] = useState<any>(false);
const [names, setNames] = useState('');
const file = useRef<HTMLInputElement>(null);
const Graph = useRef(null);
const Graph2 = useRef(null);
// 创建 axios 实例
const blobToFile = function (theBlob: any, fileName: any, type: any) {
theBlob.lastModifiedDate = new Date();
theBlob.name = fileName;
return new window.File([theBlob], theBlob.name, {type: type});
};
const base64UrlToFile = (base64Url: any, filename: any) => {
// const arr = base64Url.split(',');
// const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(base64Url);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename);
};
const downloadEvt = (url: any, fileName = '未知文件') => {
const el = document.createElement('a');
el.style.display = 'none';
el.setAttribute('target', '_blank');
/**
* download的属性是HTML5新增的属性
* href属性的地址必须是非跨域的地址,如果引用的是第三方的网站或者说是前后端分离的项目(调用后台的接口),这时download就会不起作用。
* 此时,如果是下载浏览器无法解析的文件,例如.exe,.xlsx..那么浏览器会自动下载,但是如果使用浏览器可以解析的文件,比如.txt,.png,.pdf....浏览器就会采取预览模式
* 所以,对于.txt,.png,.pdf等的预览功能我们就可以直接不设置download属性(前提是后端响应头的Content-Type: application/octet-stream,如果为application/pdf浏览器则会判断文件为 pdf ,自动执行预览的策略)
*/
fileName && el.setAttribute('download', fileName);
const href = URL.createObjectURL(url);
el.href = href;
console.log(el, href);
document.body.appendChild(el);
el.click();
document.body.removeChild(el);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
const fileUploader = (files: FileList, formats = 'caffe') => {
if (!files) {
toast.warning('请上传模型文件模型文件');
return;
}
setLoading(true);
const formData = new FormData();
// // 将文件转二进制
formData.append('file', files[0]);
formData.append('filename', files[0].name);
formData.append('format', formats);
fetcher(`/inference/convert?format=${formats}`, {
method: 'POST',
body: formData
}).then(
(res: any) => {
// debugger
const name2: string = files[0].name.substring(files[0].name.lastIndexOf('.') + 1) + '.paddle';
console.log('res', res, name2);
const file = base64UrlToFile(res.pdmodel, name2);
console.log('file', file);
setshowData(file);
setBaseId(res.request_id);
const name3 = files[0].name.substring(0, files[0].name.lastIndexOf('.'));
setfile_names(name3 + '.tar');
setLoading(false);
},
res => {
// debugger
setLoading(false);
// const newFilesId = filesId + 1;
// setFilesId(newFilesId);
}
);
// fetcher('/graph/graph').then((res: any) => {
// console.log('res', res);
// setTimeout(() => {
// // const file = blobToFile(res.data, res.filename, res.type);
// const file = blobToFile(res.data, res.filename, res.type);
// console.log('bolbfile', file);
// downloadEvt(res.data, res.filename);
// setshowData(file);
// setLoading(false);
// }, 5000);
// // setShow2(true);
// });
};
const onClickFile = useCallback(() => {
// 这里为.prototxt, 用户点击转换按钮,弹出提示框,
// 『请将模型描述文件.prototxt和参数文件.caffemodel打包成.tar上传』。
// 弹出文件选择框,让用户重新进行选择.tar文件上传。
if (showData) {
// toast.warning('模型文件已转换,请勿再次点击');
toast.warning(t('warin-info6'));
return;
}
console.log('Graph.current.filess', Graph);
const Graphs: any = Graph;
const files: FileList | null = Graphs?.current?.files as FileList;
const name = files[0].name.split('.')[1];
if (name === 'prototxt') {
toast.warning(t('togglegraph:warin-info'));
if (file.current) {
file.current.value = '';
file.current.click();
}
return;
}
if (name === 'pb' || name === 'onnx') {
fileUploader(files, name);
return;
}
// toast.warning('该模型文件暂不支持X2Paddle转换');
toast.warning(t('togglegraph:warin-info2'));
// 用户上传的文件为.pb和.onnx格式,直接发动转换数据 //fileUploader
}, [fileUploader, showData, t]);
const onChangeFile = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const target = e.target;
if (target && target.files && target.files.length) {
fileUploader(target.files);
}
},
[fileUploader]
);
//将base64转换为blob
const dataURLtoBlob = (base64Url: any) => {
const bstr = atob(base64Url);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr]);
};
// * desc: 下载方法
// * @param url :返回数据的blob对象或链接
// * @param fileName :下载后文件名标记
// const downloadFile = (url: any, name = "What's the fuvk") => {
// const a = document.createElement('a');
// a.setAttribute('href', url);
// a.setAttribute('download', name);
// a.click();
// };
const downloadFileByBase64 = (baseId: any, fileName: string) => {
console.log('baseId', baseId, fileName);
if (baseId === undefined || !fileName) return;
setLoading(true);
fetcher(`/inference/download?request_id=${baseId}`, {
method: 'GET'
}).then(
(res: any) => {
console.log('blobres', res, res.data);
downloadEvt(res.data, fileName);
setLoading(false);
},
res => {
setLoading(false);
}
);
};
useEffect(() => {
// const Graphs: any = Graph;
const Graphs2: any = Graph2;
if (showData) {
console.log('Graph2', showData);
const files = [showData];
Graphs2?.current?.setModelFiles(files);
}
}, [showData]);
const Graphs2 = useMemo(() => {
return (
<div
style={{
height: show.show2 ? 'auto' : '0px',
overflowY: 'hidden'
}}
>
<GraphStatic2
ref={Graph2}
changeRendered={() => {
setShow({
show: false,
show2: true
});
}}
show={show.show2}
/>
</div>
);
}, [show.show2]);
return (
<Content>
{loading && (
<Loading>
<HashLoader size="60px" color={primaryColor} />
</Loading>
)}
<Contents
style={{
height: !loading ? 'auto' : '0px',
overflow: 'hidden'
}}
>
<div
style={{
height: show.show ? 'auto' : '0px',
// opacity: show2 ? 1 : 0
overflowY: 'hidden'
}}
>
<GraphStatic
ref={Graph}
changeName={setNames}
show={show.show}
changeshowdata={() => {
setshowData(null);
}}
Xpaddlae={true}
/>
</div>
{Graphs2}
</Contents>
{names && !loading && (
<ButtonContent style={{marginTop: '20px'}}>
<Article>
<Buttons
style={{marginRight: '3px'}}
className={show.show ? 'active' : 'un_active'}
onClick={() => {
setShow({
show: true,
show2: false
});
}}
>
{names ? names : 'Toggle'}
</Buttons>
<Buttons
className={!showData ? 'disabled' : show.show2 ? 'active' : 'un_active'}
onClick={() => {
if (!showData) {
// toast.warning('请先进行转换,再查看');
toast.warning(t('warin-info3'));
return;
}
setShow({
show: false,
show2: true
});
}}
>
paddle
</Buttons>
</Article>
<Aside>
<Buttons
style={{marginRight: '3px'}}
className={!showData && names ? 'active' : 'disabled'}
onClick={() => {
if (showData) {
toast.warning(t('warin-info4'));
// toast.warning('模型已转换,请勿再次点击');
return;
} else {
if (!names) {
toast.warning(t('warin-info7'));
} else {
onClickFile();
}
}
}}
>
{t('togglegraph:transformation')}
</Buttons>
<Buttons
className={showData ? 'active' : 'disabled'}
onClick={() => {
console.log('showData', showData);
if (!showData) {
// toast.warning('请上传模型文件并转换');
toast.warning(t('warin-info5'));
return;
}
downloadFileByBase64(baseId, file_names);
}}
>
{t('togglegraph:download')}
</Buttons>
</Aside>
</ButtonContent>
)}
<input
ref={file}
type="file"
multiple={false}
onChange={onChangeFile}
style={{
display: 'none'
}}
/>
</Content>
);
}
export default App;
...@@ -25,6 +25,7 @@ export enum Pages { ...@@ -25,6 +25,7 @@ export enum Pages {
Audio = 'audio', Audio = 'audio',
Text = 'text', Text = 'text',
Graph = 'graph', Graph = 'graph',
ToggleGraph = 'ToggleGraph',
HighDimensional = 'high-dimensional', HighDimensional = 'high-dimensional',
PRCurve = 'pr-curve', PRCurve = 'pr-curve',
ROCCurve = 'roc-curve', ROCCurve = 'roc-curve',
...@@ -37,7 +38,8 @@ export interface Route { ...@@ -37,7 +38,8 @@ export interface Route {
default?: boolean; default?: boolean;
visible?: boolean; visible?: boolean;
path?: string; path?: string;
component?: LazyExoticComponent<FunctionComponent>; // component?: LazyExoticComponent<FunctionComponent>;
component?: any;
children?: Pick<Route, 'id' | 'path' | 'component'>[]; children?: Pick<Route, 'id' | 'path' | 'component'>[];
} }
...@@ -89,6 +91,11 @@ const routes: Route[] = [ ...@@ -89,6 +91,11 @@ const routes: Route[] = [
} }
] ]
}, },
{
id: Pages.ToggleGraph,
path: '/x2paddle',
component: React.lazy(() => import('~/pages/x2paddle'))
},
{ {
id: Pages.Histogram, id: Pages.Histogram,
path: '/histogram', path: '/histogram',
......
...@@ -17,9 +17,10 @@ ...@@ -17,9 +17,10 @@
import type {TFunction} from 'i18next'; import type {TFunction} from 'i18next';
import i18next from 'i18next'; import i18next from 'i18next';
import queryString from 'query-string'; import queryString from 'query-string';
import {toast} from 'react-toastify';
const API_TOKEN_KEY: string = import.meta.env.SNOWPACK_PUBLIC_API_TOKEN_KEY; const API_TOKEN_KEY: string = import.meta.env.SNOWPACK_PUBLIC_API_TOKEN_KEY;
const API_URL: string = import.meta.env.SNOWPACK_PUBLIC_API_URL; const API_URL: string = import.meta.env.SNOWPACK_PUBLIC_API_URL;
console.log('API_URL', API_TOKEN_KEY);
const API_TOKEN_HEADER = 'X-VisualDL-Instance-ID'; const API_TOKEN_HEADER = 'X-VisualDL-Instance-ID';
...@@ -85,6 +86,8 @@ export function fetcher<T = unknown>(url: string, options?: RequestInit): Promis ...@@ -85,6 +86,8 @@ export function fetcher<T = unknown>(url: string, options?: RequestInit): Promis
export async function fetcher<T = unknown>(url: string, options?: RequestInit): Promise<BlobResponse | string | T> { export async function fetcher<T = unknown>(url: string, options?: RequestInit): Promise<BlobResponse | string | T> {
let res: Response; let res: Response;
try { try {
// res = await fetch('http://10.181.196.14:8040/app/api/deploy/convert?format=onnx', addApiToken(options));
res = await fetch(API_URL + url, addApiToken(options)); res = await fetch(API_URL + url, addApiToken(options));
} catch (e) { } catch (e) {
const t = await logErrorAndReturnT(e); const t = await logErrorAndReturnT(e);
...@@ -108,6 +111,7 @@ export async function fetcher<T = unknown>(url: string, options?: RequestInit): ...@@ -108,6 +111,7 @@ export async function fetcher<T = unknown>(url: string, options?: RequestInit):
if (response && 'status' in response) { if (response && 'status' in response) {
if (response.status !== 0) { if (response.status !== 0) {
const t = await logErrorAndReturnT(response); const t = await logErrorAndReturnT(response);
toast.error((response as ErrorData).msg);
throw new Error((response as ErrorData).msg || t('errors:error')); throw new Error((response as ErrorData).msg || t('errors:error'));
} else { } else {
return (response as SuccessData<T>).data; return (response as SuccessData<T>).data;
...@@ -126,6 +130,7 @@ export async function fetcher<T = unknown>(url: string, options?: RequestInit): ...@@ -126,6 +130,7 @@ export async function fetcher<T = unknown>(url: string, options?: RequestInit):
} else { } else {
let data: Blob; let data: Blob;
try { try {
console.log('datas', res);
data = await res.blob(); data = await res.blob();
} catch (e) { } catch (e) {
const t = await logErrorAndReturnT(e); const t = await logErrorAndReturnT(e);
...@@ -134,6 +139,7 @@ export async function fetcher<T = unknown>(url: string, options?: RequestInit): ...@@ -134,6 +139,7 @@ export async function fetcher<T = unknown>(url: string, options?: RequestInit):
const disposition = res.headers.get('Content-Disposition'); const disposition = res.headers.get('Content-Disposition');
// support safari // support safari
if (!data.arrayBuffer) { if (!data.arrayBuffer) {
console.log('arrayBuffer', data);
data.arrayBuffer = async () => data.arrayBuffer = async () =>
new Promise<ArrayBuffer>((resolve, reject) => { new Promise<ArrayBuffer>((resolve, reject) => {
const fileReader = new FileReader(); const fileReader = new FileReader();
...@@ -143,6 +149,7 @@ export async function fetcher<T = unknown>(url: string, options?: RequestInit): ...@@ -143,6 +149,7 @@ export async function fetcher<T = unknown>(url: string, options?: RequestInit):
fileReader.readAsArrayBuffer(data); fileReader.readAsArrayBuffer(data);
}); });
} }
console.log('datas', data);
let filename: string | null = null; let filename: string | null = null;
if (disposition && disposition.indexOf('attachment') !== -1) { if (disposition && disposition.indexOf('attachment') !== -1) {
const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(disposition); const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(disposition);
......
...@@ -18,3 +18,7 @@ declare module '@visualdl/netron' { ...@@ -18,3 +18,7 @@ declare module '@visualdl/netron' {
const ref: string; const ref: string;
export default ref; export default ref;
} }
declare module '@visualdl/netron2' {
const ref: string;
export default ref;
}
...@@ -20,7 +20,7 @@ import graph from '../../assets/graph/yolov3.cfg'; ...@@ -20,7 +20,7 @@ import graph from '../../assets/graph/yolov3.cfg';
export default async () => { export default async () => {
const result = await fetch(graph); const result = await fetch(graph);
console.log('result', result);
return new Response(await result.arrayBuffer(), { return new Response(await result.arrayBuffer(), {
status: 200, status: 200,
headers: { headers: {
......
...@@ -107,6 +107,7 @@ host.BrowserHost = class { ...@@ -107,6 +107,7 @@ host.BrowserHost = class {
return this._view.showNodeDocumentation(data); return this._view.showNodeDocumentation(data);
case 'ready': case 'ready':
if (this._ready) { if (this._ready) {
debugger;
return this.status('ready'); return this.status('ready');
} }
return; return;
...@@ -196,7 +197,9 @@ host.BrowserHost = class { ...@@ -196,7 +197,9 @@ host.BrowserHost = class {
} }
_changeFiles(files) { _changeFiles(files) {
if (files && files.length) { console.log('files', files);
if (files && files?.length) {
console.log('files.length', files.length);
files = Array.from(files); files = Array.from(files);
const file = files.find(file => this._view.accept(file.name)); const file = files.find(file => this._view.accept(file.name));
if (!file) { if (!file) {
...@@ -524,7 +527,7 @@ function getCaption(obj) { ...@@ -524,7 +527,7 @@ function getCaption(obj) {
return newObj; return newObj;
} }
const hash = getCaption(document.referrer); const hash = getCaption(document.referrer);
if (hash === 'graphStatic') { if (hash === 'graphStatic' || hash === 'x2paddle') {
window.__view__ = new view2.View(new host.BrowserHost()); window.__view__ = new view2.View(new host.BrowserHost());
} else { } else {
window.__view__ = new view.View(new host.BrowserHost()); window.__view__ = new view.View(new host.BrowserHost());
......
...@@ -261,12 +261,13 @@ view.View = class { ...@@ -261,12 +261,13 @@ view.View = class {
return this._timeout(2).then(() => { return this._timeout(2).then(() => {
return this._modelFactoryService.open(context).then(model => { return this._modelFactoryService.open(context).then(model => {
return this._timeout(20).then(() => { return this._timeout(20).then(() => {
console.log('model.graphs.length', model.graphs.length);
const graph = model.graphs.length > 0 ? model.graphs[0] : null; const graph = model.graphs.length > 0 ? model.graphs[0] : null;
this._host.message('opened', { this._host.message('opened', {
graphs: model.graphs.map(g => g.name || ''), graphs: model.graphs.map(g => g.name || ''),
selected: graph && (graph.name || '') selected: graph && (graph.name || '')
}); });
return this._updateGraph2(model, graph); return this._updateGraph2(graph);
}); });
}); });
}); });
...@@ -366,6 +367,9 @@ view.View = class { ...@@ -366,6 +367,9 @@ view.View = class {
if (graph && graph != this._activeGraph) { if (graph && graph != this._activeGraph) {
this._selectItem = null; this._selectItem = null;
const nodes = graph.nodes; const nodes = graph.nodes;
console.log('graphs', graph);
console.log('nodes.length', nodes);
if (nodes.length > 1400) { if (nodes.length > 1400) {
if ( if (
!this._host.confirm( !this._host.confirm(
...@@ -478,6 +482,7 @@ view.View = class { ...@@ -478,6 +482,7 @@ view.View = class {
for (const node of nodes) { for (const node of nodes) {
let path = node.name.split('/'); let path = node.name.split('/');
path.pop(); path.pop();
console.log('path.length', path.length);
while (path.length > 0) { while (path.length > 0) {
const name = path.join('/'); const name = path.join('/');
path.pop(); path.pop();
......
last 2 Chrome versions
last 2 Firefox versions
last 1 Safari version
last 1 iOS version
# VisualDL FrontEnd Server
A fork version of [Netron](https://github.com/lutzroeder/netron).
## Build
```bash
yarn build
```
{
"name": "@visualdl/netron2",
"version": "2.2.1",
"description": "A platform to visualize the deep learning process and result.",
"keywords": [
"visualdl",
"paddlepaddle",
"visualization",
"deep learning"
],
"homepage": "https://github.com/PaddlePaddle/VisualDL",
"bugs": {
"url": "https://github.com/PaddlePaddle/VisualDL/issues"
},
"license": "Apache-2.0",
"author": "PeterPanZH <littlepanzh@gmail.com> (https://github.com/PeterPanZH)",
"contributors": [
"Niandalu <littlepanzh@gmail.com> (https://github.com/Niandalu)"
],
"repository": {
"type": "git",
"url": "https://github.com/PaddlePaddle/VisualDL.git",
"directory": "frontend/packages/netron"
},
"scripts": {
"build": "rimraf dist && webpack",
"test": "echo \"Error: no test specified\" && exit 0"
},
"files": [
"dist"
],
"main": "dist/index.html",
"dependencies": {
"d3": "5.16.0",
"dagre": "0.8.5",
"flatbuffers": "1.12.0",
"long": "4.0.0",
"marked": "2.0.7",
"netron": "PeterPanZH/netron",
"pako": "1.0.11"
},
"devDependencies": {
"autoprefixer": "10.3.4",
"copy-webpack-plugin": "9.0.1",
"css-loader": "6.2.0",
"html-webpack-plugin": "5.3.2",
"mini-css-extract-plugin": "2.2.2",
"postcss": "8.3.6",
"postcss-loader": "6.1.1",
"rimraf": "3.0.2",
"sass": "1.39.0",
"sass-loader": "12.1.0",
"terser": "5.7.2",
"webpack": "5.52.0",
"webpack-cli": "4.8.0"
},
"engines": {
"node": ">=12",
"npm": ">=6"
},
"publishConfig": {
"access": "public"
}
}
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module.exports = {
plugins: [require('autoprefixer')]
};
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
/>
</head>
<body>
<div id="graph" class="graph">
<svg id="canvas" class="canvas" preserveaspectratio="xMidYMid meet" width="100%" height="100%"></svg>
</div>
</body>
</html>
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// cSpell:words actived nextcode
const view = require('./view');
const view2 = require('./view2');
const host = {};
host.BrowserHost = class {
constructor() {
window.eval = () => {
throw new Error('window.eval() not supported.');
};
this._document = window.document;
this._meta = {};
for (const element of Array.from(this._document.getElementsByTagName('meta'))) {
if (element.content) {
this._meta[element.name] = this._meta[element.name] || [];
this._meta[element.name].push(element.content);
}
}
this._type = this._meta.type ? this._meta.type[0] : 'Browser';
this._version = this._meta.version ? this._meta.version[0] : null;
this._ready = false;
}
get document() {
return this._document;
}
get version() {
return this._version;
}
get type() {
return this._type;
}
initialize(view) {
this._view = view;
return Promise.resolve();
}
start() {
window.addEventListener(
'message',
event => {
const originalData = event.data;
if (originalData) {
const type = originalData.type;
const data = originalData.data;
switch (type) {
// 在此书添加一个this._view的事件传递Graph页面过来的数据
case 'change-files':
return this._changeFiles(data);
case 'zoom-in':
return this._view.zoomIn();
case 'zoom-out':
return this._view.zoomOut();
case 'select-item':
return this._view.selectItem(data);
case 'toggle-Language':
return this._view.toggleLanguage(data);
case 'isAlt':
return this._view.changeAlt(data);
case 'zoom-reset':
return this._view.resetZoom();
case 'toggle-attributes':
return this._view.toggleAttributes(data);
case 'toggle-initializers':
return this._view.toggleInitializers(data);
case 'toggle-names':
return this._view.toggleNames(data);
case 'toggle-KeepData':
return this._view.toggleKeepData(data);
case 'toggle-direction':
return this._view.toggleDirection(data);
case 'toggle-theme':
return this._view.toggleTheme(data);
case 'export':
return this._view.export(`${document.title}.${data}`);
case 'change-graph':
return this._view.changeGraph(data);
case 'change-allGraph':
return this._view.changeAllGrap(data);
case 'change-select':
return this._view.changeSelect(data);
case 'search':
return this._view.find(data);
case 'select':
return this._view.select(data);
case 'show-model-properties':
return this._view.showModelProperties();
case 'show-node-documentation':
return this._view.showNodeDocumentation(data);
case 'show2':
return this._view._reload();
case 'ready':
if (this._ready) {
debugger;
return this.status('ready');
}
return;
}
}
},
false
);
this._ready = true;
this.status('ready');
}
message(type, data) {
if (window.parent) {
window.parent.postMessage({type: type, data: data}, '*');
}
}
status(status) {
// 反传回去
this.message('status', status);
}
selectNodeId(nodeInfo) {
// 反传回去
console.log('节点点击事件触发了', nodeInfo);
this.message('nodeId', nodeInfo);
}
selectItems(item) {
// 反传回去
console.log('节点点击事件触发了', item);
this.message('selectItem', item);
}
error(message, detail) {
this.message('error', (message === 'Error' ? '' : message + ' ') + detail);
}
reload() {
this.view._reload();
}
confirm(message, detail) {
const result = confirm(message + ' ' + detail);
if (!result) {
this.message('cancel');
}
return result;
}
require(id) {
const url = this._url(id + '.js');
window.__modules__ = window.__modules__ || {};
if (window.__modules__[url]) {
return Promise.resolve(window.__exports__[url]);
}
return new Promise((resolve, reject) => {
window.module = {exports: {}};
const script = document.createElement('script');
script.setAttribute('id', id);
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', url);
script.onload = () => {
const exports = window.module.exports;
delete window.module;
window.__modules__[id] = exports;
resolve(exports);
};
script.onerror = e => {
delete window.module;
reject(new Error("The script '" + e.target.src + "' failed to load."));
};
this.document.head.appendChild(script);
});
}
save(name, extension, defaultPath, callback) {
callback(defaultPath + '.' + extension);
}
export(file, blob) {
const element = this.document.createElement('a');
element.download = file;
element.href = URL.createObjectURL(blob);
this.document.body.appendChild(element);
element.click();
this.document.body.removeChild(element);
}
request(base, file, encoding) {
const url = base ? base + '/' + file : this._url(file);
return this._request(url, null, encoding);
}
_changeFiles(files) {
console.log('files2', files);
if (files && files?.length) {
console.log('files.length', files.length);
files = Array.from(files);
const file = files.find(file => this._view.accept(file.name));
if (!file) {
this.error('Error opening file.', 'Cannot open file ' + files[0].name);
return;
}
this._open(
files.find(file => this._view.accept(file.name)),
files
);
}
}
_request(url, headers, encoding, timeout) {
return new Promise((resolve, reject) => {
const request = new XMLHttpRequest();
if (!encoding) {
request.responseType = 'arraybuffer';
}
if (timeout) {
request.timeout = timeout;
}
const error = status => {
const err = new Error('The web request failed with status code ' + status + " at '" + url + "'.");
err.type = 'error';
err.url = url;
return err;
};
request.onload = () => {
if (request.status == 200) {
if (request.responseType == 'arraybuffer') {
resolve(new Uint8Array(request.response));
} else {
resolve(request.responseText);
}
} else {
reject(error(request.status));
}
};
request.onerror = e => {
const err = error(request.status);
err.type = e.type;
reject(err);
};
request.ontimeout = () => {
request.abort();
const err = new Error("The web request timed out in '" + url + "'.");
err.type = 'timeout';
err.url = url;
reject(err);
};
request.open('GET', url, true);
if (headers) {
for (const name of Object.keys(headers)) {
request.setRequestHeader(name, headers[name]);
}
}
request.send();
});
}
_url(file) {
let url = file;
if (window && window.location && window.location.href) {
let location = window.location.href.split('?').shift();
if (location.endsWith('.html')) {
location = location.split('/').slice(0, -1).join('/');
}
if (location.endsWith('/')) {
location = location.slice(0, -1);
}
url = location + '/' + file;
}
return url;
}
_open(file, files) {
this.status('loading');
const context = new BrowserFileContext(file, files);
context
.open()
.then(() => {
return this._view.open(context).then(model => {
if (this._view.actived) {
this.status('rendered');
}
this.document.title = files[0].name;
return model;
});
})
.catch(error => {
this.error(error.name, error.message);
});
}
};
if (typeof TextDecoder === 'undefined') {
TextDecoder = function TextDecoder(encoding) {
this._encoding = encoding;
};
TextDecoder.prototype.decode = function decode(buffer) {
let result = '';
const length = buffer.length;
let i = 0;
switch (this._encoding) {
case 'utf-8':
while (i < length) {
const c = buffer[i++];
switch (c >> 4) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7: {
result += String.fromCharCode(c);
break;
}
case 12:
case 13: {
const c2 = buffer[i++];
result += String.fromCharCode(((c & 0x1f) << 6) | (c2 & 0x3f));
break;
}
case 14: {
const c2 = buffer[i++];
const c3 = buffer[i++];
result += String.fromCharCode(((c & 0x0f) << 12) | ((c2 & 0x3f) << 6) | ((c3 & 0x3f) << 0));
break;
}
}
}
break;
case 'ascii':
while (i < length) {
result += String.fromCharCode(buffer[i++]);
}
break;
}
return result;
};
}
if (typeof TextEncoder === 'undefined') {
// eslint-disable-next-line @typescript-eslint/no-empty-function
TextEncoder = function TextEncoder() {};
TextEncoder.prototype.encode = function encode(str) {
'use strict';
const length = str.length;
let resPos = -1;
const resArr = typeof Uint8Array === 'undefined' ? new Array(length * 2) : new Uint8Array(length * 3);
for (let point = 0, nextcode = 0, i = 0; i !== length; ) {
point = str.charCodeAt(i);
i += 1;
if (point >= 0xd800 && point <= 0xdbff) {
if (i === length) {
resArr[(resPos += 1)] = 0xef;
resArr[(resPos += 1)] = 0xbf;
resArr[(resPos += 1)] = 0xbd;
break;
}
nextcode = str.charCodeAt(i);
if (nextcode >= 0xdc00 && nextcode <= 0xdfff) {
point = (point - 0xd800) * 0x400 + nextcode - 0xdc00 + 0x10000;
i += 1;
if (point > 0xffff) {
resArr[(resPos += 1)] = (0x1e << 3) | (point >>> 18);
resArr[(resPos += 1)] = (0x2 << 6) | ((point >>> 12) & 0x3f);
resArr[(resPos += 1)] = (0x2 << 6) | ((point >>> 6) & 0x3f);
resArr[(resPos += 1)] = (0x2 << 6) | (point & 0x3f);
continue;
}
} else {
resArr[(resPos += 1)] = 0xef;
resArr[(resPos += 1)] = 0xbf;
resArr[(resPos += 1)] = 0xbd;
continue;
}
}
if (point <= 0x007f) {
resArr[(resPos += 1)] = (0x0 << 7) | point;
} else if (point <= 0x07ff) {
resArr[(resPos += 1)] = (0x6 << 5) | (point >>> 6);
resArr[(resPos += 1)] = (0x2 << 6) | (point & 0x3f);
} else {
resArr[(resPos += 1)] = (0xe << 4) | (point >>> 12);
resArr[(resPos += 1)] = (0x2 << 6) | ((point >>> 6) & 0x3f);
resArr[(resPos += 1)] = (0x2 << 6) | (point & 0x3f);
}
}
if (typeof Uint8Array !== 'undefined') {
return new Uint8Array(resArr.buffer.slice(0, resPos + 1));
} else {
return resArr.length === resPos + 1 ? resArr : resArr.slice(0, resPos + 1);
}
};
TextEncoder.prototype.toString = function () {
return '[object TextEncoder]';
};
try {
Object.defineProperty(TextEncoder.prototype, 'encoding', {
get: function () {
if (Object.prototype.isPrototypeOf.call(TextEncoder.prototype, this)) {
return 'utf-8';
} else {
throw TypeError('Illegal invocation');
}
}
});
} catch (e) {
TextEncoder.prototype.encoding = 'utf-8';
}
if (typeof Symbol !== 'undefined') {
TextEncoder.prototype[Symbol.toStringTag] = 'TextEncoder';
}
}
if (typeof URLSearchParams === 'undefined') {
URLSearchParams = function URLSearchParams(search) {
const decode = str => {
return str.replace(/[ +]/g, '%20').replace(/(%[a-f0-9]{2})+/gi, match => {
return decodeURIComponent(match);
});
};
this._dict = {};
if (typeof search === 'string') {
search = search.indexOf('?') === 0 ? search.substring(1) : search;
const properties = search.split('&');
for (const property of properties) {
const index = property.indexOf('=');
const name = index > -1 ? decode(property.substring(0, index)) : decode(property);
const value = index > -1 ? decode(property.substring(index + 1)) : '';
if (!Object.prototype.hasOwnProperty.call(this._dict, name)) {
this._dict[name] = [];
}
this._dict[name].push(value);
}
}
};
URLSearchParams.prototype.get = function (name) {
return Object.prototype.hasOwnProperty.call(this._dict, name) ? this._dict[name][0] : null;
};
}
if (!HTMLCanvasElement.prototype.toBlob) {
HTMLCanvasElement.prototype.toBlob = function (callback, type, quality) {
setTimeout(() => {
const data = atob(this.toDataURL(type, quality).split(',')[1]);
const length = data.length;
const buffer = new Uint8Array(length);
for (let i = 0; i < length; i++) {
buffer[i] = data.charCodeAt(i);
}
callback(new Blob([buffer], {type: type || 'image/png'}));
}, 0);
};
}
class BrowserFileContext {
constructor(file, blobs) {
this._file = file;
this._blobs = {};
for (const blob of blobs) {
this._blobs[blob.name] = blob;
}
}
get identifier() {
return this._file.name;
}
get buffer() {
return this._buffer;
}
open() {
return this.request(this._file.name, null).then(data => {
this._buffer = data;
});
}
request(file, encoding) {
const blob = this._blobs[file];
if (!blob) {
return Promise.reject(new Error("File not found '" + file + "'."));
}
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = e => {
resolve(encoding ? e.target.result : new Uint8Array(e.target.result));
};
reader.onerror = e => {
e = e || window.event;
let message = '';
switch (e.target.error.code) {
case e.target.error.NOT_FOUND_ERR:
message = "File not found '" + file + "'.";
break;
case e.target.error.NOT_READABLE_ERR:
message = "File not readable '" + file + "'.";
break;
case e.target.error.SECURITY_ERR:
message = "File access denied '" + file + "'.";
break;
default:
message = "File read '" + e.target.error.code.toString() + "' error '" + file + "'.";
break;
}
reject(new Error(message));
};
if (encoding === 'utf-8') {
reader.readAsText(blob, encoding);
} else {
reader.readAsArrayBuffer(blob);
}
});
}
}
function getCaption(obj) {
let index = obj.lastIndexOf('/'); //获取-后边的字符串
let newObj = obj.substring(index + 1, obj.length);
return newObj;
}
const hash = getCaption(document.referrer);
console.log('hash', hash);
if (hash === 'graphStatic' || hash === 'x2paddle') {
window.__view__ = new view2.View(new host.BrowserHost());
} else {
window.__view__ = new view.View(new host.BrowserHost());
}
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export default {
leaf_nodes: [
{
name: 'layer',
schema: {
category: 'container'
}
},
{
name: 'layerlist',
schema: {
category: 'container'
}
},
{
name: 'parameterlist',
schema: {
category: 'container'
}
},
{
name: 'layerdict',
schema: {
category: 'container'
}
},
{
name: 'conv1d',
schema: {
category: 'conv'
}
},
{
name: 'conv1dtranspose',
schema: {
category: 'conv'
}
},
{
name: 'conv2d',
schema: {
category: 'conv'
}
},
{
name: 'conv2dtranspose',
schema: {
category: 'conv'
}
},
{
name: 'conv3d',
schema: {
category: 'conv'
}
},
{
name: 'conv3dtranspose',
schema: {
category: 'conv'
}
},
{
name: 'adaptiveavgpool1d',
schema: {
category: 'pool'
}
},
{
name: 'adaptiveavgpool2d',
schema: {
category: 'pool'
}
},
{
name: 'adaptiveavgpool3d',
schema: {
category: 'pool'
}
},
{
name: 'adaptivemaxpool1d',
schema: {
category: 'pool'
}
},
{
name: 'adaptivemaxpool2d',
schema: {
category: 'pool'
}
},
{
name: 'adaptivemaxpool3d',
schema: {
category: 'pool'
}
},
{
name: 'avgpool1d',
schema: {
category: 'pool'
}
},
{
name: 'avgpool2d',
schema: {
category: 'pool'
}
},
{
name: 'avgpool3d',
schema: {
category: 'pool'
}
},
{
name: 'maxpool1d',
schema: {
category: 'pool'
}
},
{
name: 'maxpool2d',
schema: {
category: 'pool'
}
},
{
name: 'maxpool3d',
schema: {
category: 'pool'
}
},
{
name: 'maxunpool1d',
schema: {
category: 'pool'
}
},
{
name: 'maxunpool2d',
schema: {
category: 'pool'
}
},
{
name: 'maxunpool3d',
schema: {
category: 'pool'
}
},
{
name: 'pad1d',
schema: {
category: 'pad'
}
},
{
name: 'pad2d',
schema: {
category: 'pad'
}
},
{
name: 'pad3d',
schema: {
category: 'pad'
}
},
{
name: 'zeropad2d',
schema: {
category: 'pad'
}
},
{
name: 'celu',
schema: {
category: 'activation'
}
},
{
name: 'elu',
schema: {
category: 'activation'
}
},
{
name: 'gelu',
schema: {
category: 'activation'
}
},
{
name: 'hardshrink',
schema: {
category: 'activation'
}
},
{
name: 'hardsigmoid',
schema: {
category: 'activation'
}
},
{
name: 'hardswish',
schema: {
category: 'activation'
}
},
{
name: 'hardtanh',
schema: {
category: 'activation'
}
},
{
name: 'leakyrelu',
schema: {
category: 'activation'
}
},
{
name: 'logsigmoid',
schema: {
category: 'activation'
}
},
{
name: 'logsoftmax',
schema: {
category: 'activation'
}
},
{
name: 'maxout',
schema: {
category: 'activation'
}
},
{
name: 'prelu',
schema: {
category: 'activation'
}
},
{
name: 'relu',
schema: {
category: 'activation'
}
},
{
name: 'relu6',
schema: {
category: 'activation'
}
},
{
name: 'selu',
schema: {
category: 'activation'
}
},
{
name: 'sigmoid',
schema: {
category: 'activation'
}
},
{
name: 'silu',
schema: {
category: 'activation'
}
},
{
name: 'softmax',
schema: {
category: 'activation'
}
},
{
name: 'softplus',
schema: {
category: 'activation'
}
},
{
name: 'softshrink',
schema: {
category: 'activation'
}
},
{
name: 'softsign',
schema: {
category: 'activation'
}
},
{
name: 'swish',
schema: {
category: 'activation'
}
},
{
name: 'mish',
schema: {
category: 'activation'
}
},
{
name: 'tanh',
schema: {
category: 'activation'
}
},
{
name: 'tanhshrink',
schema: {
category: 'activation'
}
},
{
name: 'thresholdedrelu',
schema: {
category: 'activation'
}
},
{
name: 'batchnorm',
schema: {
category: 'normalization'
}
},
{
name: 'batchnorm1d',
schema: {
category: 'normalization'
}
},
{
name: 'batchnorm2d',
schema: {
category: 'normalization'
}
},
{
name: 'batchnorm3d',
schema: {
category: 'normalization'
}
},
{
name: 'groupnorm',
schema: {
category: 'normalization'
}
},
{
name: 'instancenorm1d',
schema: {
category: 'normalization'
}
},
{
name: 'instancenorm2d',
schema: {
category: 'normalization'
}
},
{
name: 'instancenorm3d',
schema: {
category: 'normalization'
}
},
{
name: 'layernorm',
schema: {
category: 'normalization'
}
},
{
name: 'localresponsenorm',
schema: {
category: 'normalization'
}
},
{
name: 'spectralnorm',
schema: {
category: 'normalization'
}
},
{
name: 'syncbatchnorm',
schema: {
category: 'normalization'
}
},
{
name: 'alphadropout',
schema: {
category: 'normalization'
}
},
{
name: 'dropout',
schema: {
category: 'normalization'
}
},
{
name: 'dropout2d',
schema: {
category: 'normalization'
}
},
{
name: 'dropout3d',
schema: {
category: 'normalization'
}
},
{
name: 'birnn',
schema: {
category: 'sequence'
}
},
{
name: 'gru',
schema: {
category: 'sequence'
}
},
{
name: 'grucell',
schema: {
category: 'sequence'
}
},
{
name: 'lstm',
schema: {
category: 'sequence'
}
},
{
name: 'lstmcell',
schema: {
category: 'sequence'
}
},
{
name: 'rnn',
schema: {
category: 'sequence'
}
},
{
name: 'rnncellbase',
schema: {
category: 'sequence'
}
},
{
name: 'simplernn',
schema: {
category: 'sequence'
}
},
{
name: 'simplernncell',
schema: {
category: 'sequence'
}
},
{
name: 'multiheadattention',
schema: {
category: 'sequence'
}
},
{
name: 'transformer',
schema: {
category: 'sequence'
}
},
{
name: 'transformerdecoder',
schema: {
category: 'sequence'
}
},
{
name: 'transformerdecoderlayer',
schema: {
category: 'sequence'
}
},
{
name: 'transformerencoder',
schema: {
category: 'sequence'
}
},
{
name: 'transformerencoderlayer',
schema: {
category: 'sequence'
}
},
{
name: 'linear',
schema: {
category: 'sequence'
}
},
{
name: 'embedding',
schema: {
category: 'sequence'
}
},
{
name: 'bceloss',
schema: {
category: 'tensor'
}
},
{
name: 'bcewithlogitsloss',
schema: {
category: 'tensor'
}
},
{
name: 'crossentropyloss',
schema: {
category: 'tensor'
}
},
{
name: 'ctcloss',
schema: {
category: 'tensor'
}
},
{
name: 'hsigmoidloss',
schema: {
category: 'tensor'
}
},
{
name: 'kldivloss',
schema: {
category: 'tensor'
}
},
{
name: 'l1loss',
schema: {
category: 'tensor'
}
},
{
name: 'marginrankingloss',
schema: {
category: 'tensor'
}
},
{
name: 'mseloss',
schema: {
category: 'tensor'
}
},
{
name: 'nllloss',
schema: {
category: 'tensor'
}
},
{
name: 'smoothl1loss',
schema: {
category: 'tensor'
}
},
{
name: 'pixelshuffle',
schema: {
category: 'shape'
}
},
{
name: 'upsample',
schema: {
category: 'shape'
}
},
{
name: 'upsamplingbilinear2d',
schema: {
category: 'shape'
}
},
{
name: 'upsamplingnearest2d',
schema: {
category: 'shape'
}
},
{
name: 'clipgradbyglobalnorm',
schema: {
category: 'shape'
}
},
{
name: 'clipgradbynorm',
schema: {
category: 'shape'
}
},
{
name: 'clipgradbyvalue',
schema: {
category: 'shape'
}
},
{
name: 'beamsearchdecoder',
schema: {
category: 'shape'
}
},
{
name: 'cosinesimilarity',
schema: {
category: 'shape'
}
},
{
name: 'dynamic_decode',
schema: {
category: 'shape'
}
},
{
name: 'flatten',
schema: {
category: 'shape'
}
},
{
name: 'pairwisedistance',
schema: {
category: 'shape'
}
},
{
name: 'identity',
schema: {
category: 'shape'
}
},
{
name: 'unfold',
schema: {
category: 'shape'
}
},
{
name: 'fold',
schema: {
category: 'shape'
}
},
{
name: 'conv2d_grad',
schema: {
category: 'conv'
}
},
{
name: 'conv2d_transpose_grad',
schema: {
category: 'conv'
}
},
{
name: 'depthwise_conv2d_transpose',
schema: {
category: 'conv'
}
},
{
name: 'depthwise_conv2d_transpose_grad',
schema: {
category: 'conv'
}
},
{
name: 'deformable_conv_grad',
schema: {
category: 'conv'
}
},
{
name: 'depthwise_conv2d',
schema: {
category: 'conv'
}
},
{
name: 'deformable_conv',
schema: {
category: 'conv'
}
},
{
name: 'conv2d_transpose',
schema: {
category: 'conv'
}
},
{
name: 'depthwise_conv2d_grad',
schema: {
category: 'conv'
}
},
{
name: 'pool2d',
schema: {
category: 'pool'
}
},
{
name: 'pool2d_grad',
schema: {
category: 'pool'
}
},
{
name: 'max_pool2d_with_index',
schema: {
category: 'pool'
}
},
{
name: 'max_pool2d_with_index_grad',
schema: {
category: 'pool'
}
},
{
name: 'pad3d_grad',
schema: {
category: 'pad'
}
},
{
name: 'relu6_grad',
schema: {
category: 'activation'
}
},
{
name: 'leaky_relu',
schema: {
category: 'activation'
}
},
{
name: 'leaky_relu_grad',
schema: {
category: 'activation'
}
},
{
name: 'hard_sigmoid',
schema: {
category: 'activation'
}
},
{
name: 'hard_sigmoid_grad',
schema: {
category: 'activation'
}
},
{
name: 'sigmoid_grad',
schema: {
category: 'activation'
}
},
{
name: 'batch_norm',
schema: {
category: 'normalization'
}
},
{
name: 'batch_norm_grad',
schema: {
category: 'normalization'
}
},
{
name: 'sync_batch_norm',
schema: {
category: 'normalization'
}
},
{
name: 'sync_batch_norm_grad',
schema: {
category: 'normalization'
}
},
{
name: 'norm_grad',
schema: {
category: 'normalization'
}
},
{
name: 'p_norm',
schema: {
category: 'normalization'
}
},
{
name: 'p_norm_grad',
schema: {
category: 'normalization'
}
},
{
name: 'group_norm_grad',
schema: {
category: 'normalization'
}
},
{
name: 'squared_l2_norm',
schema: {
category: 'normalization'
}
},
{
name: 'squared_l2_norm_grad',
schema: {
category: 'normalization'
}
},
{
name: 'group_norm',
schema: {
category: 'normalization'
}
},
{
name: 'norm',
schema: {
category: 'normalization'
}
},
{
name: 'rnn_grad',
schema: {
category: 'sequence'
}
},
{
name: 'sequence_mask',
schema: {
category: 'sequence'
}
},
{
name: 'one_hot',
schema: {
category: 'sequence'
}
},
{
name: 'one_hot_v2',
schema: {
category: 'sequence'
}
},
{
name: 'bce_loss',
schema: {
category: 'tensor'
}
},
{
name: 'bce_loss_grad',
schema: {
category: 'tensor'
}
},
{
name: 'huber_loss',
schema: {
category: 'tensor'
}
},
{
name: 'huber_loss_grad',
schema: {
category: 'tensor'
}
},
{
name: 'log_loss',
schema: {
category: 'tensor'
}
},
{
name: 'log_loss_grad',
schema: {
category: 'tensor'
}
},
{
name: 'smooth_l1_loss',
schema: {
category: 'tensor'
}
},
{
name: 'smooth_l1_loss_grad',
schema: {
category: 'tensor'
}
},
{
name: 'elementwise_add',
schema: {
category: 'tensor'
}
},
{
name: 'elementwise_add_grad',
schema: {
category: 'tensor'
}
},
{
name: 'cumsum',
schema: {
category: 'tensor'
}
},
{
name: 'clip',
schema: {
category: 'tensor'
}
},
{
name: 'clip_grad',
schema: {
category: 'tensor'
}
},
{
name: 'greater_equal',
schema: {
category: 'tensor'
}
},
{
name: 'greater_than',
schema: {
category: 'tensor'
}
},
{
name: 'less_equal',
schema: {
category: 'tensor'
}
},
{
name: 'logical_and',
schema: {
category: 'tensor'
}
},
{
name: 'logical_or',
schema: {
category: 'tensor'
}
},
{
name: 'momentum',
schema: {
category: 'tensor'
}
},
{
name: 'reduce_max',
schema: {
category: 'tensor'
}
},
{
name: 'reduce_mean',
schema: {
category: 'tensor'
}
},
{
name: 'reduce_prod',
schema: {
category: 'tensor'
}
},
{
name: 'seed',
schema: {
category: 'tensor'
}
},
{
name: 'sigmoid_cross_entropy_with_logits',
schema: {
category: 'tensor'
}
},
{
name: 'label_smooth',
schema: {
category: 'tensor'
}
},
{
name: 'where_index',
schema: {
category: 'tensor'
}
},
{
name: 'is_empty',
schema: {
category: 'tensor'
}
},
{
name: 'sigmoid_cross_entropy_with_logits_grad',
schema: {
category: 'tensor'
}
},
{
name: 'target_assign',
schema: {
category: 'tensor'
}
},
{
name: 'gradient_accumulator',
schema: {
category: 'tensor'
}
},
{
name: 'size',
schema: {
category: 'tensor'
}
},
{
name: 'where',
schema: {
category: 'tensor'
}
},
{
name: 'elementwise_pow_grad',
schema: {
category: 'tensor'
}
},
{
name: 'argsort',
schema: {
category: 'tensor'
}
},
{
name: 'argsort_grad',
schema: {
category: 'tensor'
}
},
{
name: 'rmsprop',
schema: {
category: 'tensor'
}
},
{
name: 'atan',
schema: {
category: 'tensor'
}
},
{
name: 'atan_grad',
schema: {
category: 'tensor'
}
},
{
name: 'flatten_contiguous_range',
schema: {
category: 'tensor'
}
},
{
name: 'crop',
schema: {
category: 'tensor'
}
},
{
name: 'eye',
schema: {
category: 'tensor'
}
},
{
name: 'matmul',
schema: {
category: 'tensor'
}
},
{
name: 'set_value',
schema: {
category: 'tensor'
}
},
{
name: 'exp',
schema: {
category: 'tensor'
}
},
{
name: 'exp_grad',
schema: {
category: 'tensor'
}
},
{
name: 'square_grad',
schema: {
category: 'tensor'
}
},
{
name: 'log_softmax',
schema: {
category: 'tensor'
}
},
{
name: 'log_softmax_grad',
schema: {
category: 'tensor'
}
},
{
name: 'matmul_grad',
schema: {
category: 'tensor'
}
},
{
name: 'assign_value',
schema: {
category: 'tensor'
}
},
{
name: 'top_k_v2',
schema: {
category: 'tensor'
}
},
{
name: 'arg_max',
schema: {
category: 'tensor'
}
},
{
name: 'cos',
schema: {
category: 'tensor'
}
},
{
name: 'sin',
schema: {
category: 'tensor'
}
},
{
name: 'index_sample',
schema: {
category: 'shape'
}
},
{
name: 'squeeze_grad',
schema: {
category: 'shape'
}
},
{
name: 'squeeze2_grad',
schema: {
category: 'shape'
}
},
{
name: 'stack_grad',
schema: {
category: 'shape'
}
},
{
name: 'tril_triu',
schema: {
category: 'shape'
}
},
{
name: 'unstack',
schema: {
category: 'shape'
}
},
{
name: 'unstack_grad',
schema: {
category: 'shape'
}
},
{
name: 'bilinear_interp_v2',
schema: {
category: 'shape'
}
},
{
name: 'bilinear_interp_v2_grad',
schema: {
category: 'shape'
}
},
{
name: 'nearest_interp_v2',
schema: {
category: 'shape'
}
},
{
name: 'nearest_interp_v2_grad',
schema: {
category: 'shape'
}
},
{
name: 'randperm',
schema: {
category: 'shape'
}
},
{
name: 'sampling_id',
schema: {
category: 'shape'
}
},
{
name: 'bipartite_match',
schema: {
category: 'shape'
}
},
{
name: 'box_coder',
schema: {
category: 'shape'
}
},
{
name: 'density_prior_box',
schema: {
category: 'shape'
}
},
{
name: 'distribute_fpn_proposals',
schema: {
category: 'shape'
}
},
{
name: 'generate_proposals_v2',
schema: {
category: 'shape'
}
},
{
name: 'meshgrid',
schema: {
category: 'shape'
}
},
{
name: 'mine_hard_examples',
schema: {
category: 'shape'
}
},
{
name: 'yolo_box',
schema: {
category: 'shape'
}
},
{
name: 'warpctc',
schema: {
category: 'shape'
}
},
{
name: 'warpctc_grad',
schema: {
category: 'shape'
}
},
{
name: 'iou_similarity',
schema: {
category: 'shape'
}
},
{
name: 'split',
schema: {
category: 'shape'
}
},
{
name: 'flatten2',
schema: {
category: 'shape'
}
},
{
name: 'flatten2_grad',
schema: {
category: 'shape'
}
},
{
name: 'masked_select_grad',
schema: {
category: 'shape'
}
},
{
name: 'strided_slice',
schema: {
category: 'shape'
}
},
{
name: 'prior_box',
schema: {
category: 'shape'
}
},
{
name: 'elementwise_max_grad',
schema: {
category: 'shape'
}
},
{
name: 'not_equal',
schema: {
category: 'shape'
}
},
{
name: 'strided_slice_grad',
schema: {
category: 'shape'
}
},
{
name: 'fill_any_like',
schema: {
category: 'shape'
}
},
{
name: 'hard_swish',
schema: {
category: 'shape'
}
},
{
name: 'hard_swish_grad',
schema: {
category: 'shape'
}
},
{
name: 'expand_v2',
schema: {
category: 'shape'
}
},
{
name: 'expand_v2_grad',
schema: {
category: 'shape'
}
},
{
name: 'flatten_contiguous_range_grad',
schema: {
category: 'shape'
}
},
{
name: 'gather_nd',
schema: {
category: 'shape'
}
},
{
name: 'gather_nd_grad',
schema: {
category: 'shape'
}
},
{
name: 'reciprocal',
schema: {
category: 'shape'
}
},
{
name: 'reciprocal_grad',
schema: {
category: 'shape'
}
},
{
name: 'index_select',
schema: {
category: 'shape'
}
},
{
name: 'roi_align',
schema: {
category: 'shape'
}
},
{
name: 'roi_align_grad',
schema: {
category: 'shape'
}
},
{
name: 'reduce_mean_grad',
schema: {
category: 'shape'
}
},
{
name: 'masked_select',
schema: {
category: 'shape'
}
},
{
name: 'index_select_grad',
schema: {
category: 'shape'
}
},
{
name: 'elementwise_min_grad',
schema: {
category: 'shape'
}
},
{
name: 'fill_constant_batch_size_like',
schema: {
category: 'shape'
}
},
{
name: 'unsqueeze2_grad',
schema: {
category: 'shape'
}
},
{
name: 'unique',
schema: {
category: 'shape'
}
},
{
name: 'expand_as_v2',
schema: {
category: 'shape'
}
},
{
name: 'tile',
schema: {
category: 'shape'
}
},
{
name: 'nearest_interp_grad',
schema: {
category: 'shape'
}
}
],
non_leaf_nodes: [
{
name: 'Layer',
schema: {
category: 'container'
}
},
{
name: 'LayerList',
schema: {
category: 'container'
}
},
{
name: 'ParameterList',
schema: {
category: 'container'
}
},
{
name: 'LayerDict',
schema: {
category: 'container'
}
},
{
name: 'Conv1D',
schema: {
category: 'conv'
}
},
{
name: 'Conv1DTranspose',
schema: {
category: 'conv'
}
},
{
name: 'Conv2D',
schema: {
category: 'conv'
}
},
{
name: 'Conv2DTranspose',
schema: {
category: 'conv'
}
},
{
name: 'Conv3D',
schema: {
category: 'conv'
}
},
{
name: 'Conv3DTranspose',
schema: {
category: 'conv'
}
},
{
name: 'AdaptiveAvgPool1D',
schema: {
category: 'pool'
}
},
{
name: 'AdaptiveAvgPool2D',
schema: {
category: 'pool'
}
},
{
name: 'AdaptiveAvgPool3D',
schema: {
category: 'pool'
}
},
{
name: 'AdaptiveMaxPool1D',
schema: {
category: 'pool'
}
},
{
name: 'AdaptiveMaxPool2D',
schema: {
category: 'pool'
}
},
{
name: 'AdaptiveMaxPool3D',
schema: {
category: 'pool'
}
},
{
name: 'AvgPool1D',
schema: {
category: 'pool'
}
},
{
name: 'AvgPool2D',
schema: {
category: 'pool'
}
},
{
name: 'AvgPool3D',
schema: {
category: 'pool'
}
},
{
name: 'MaxPool1D',
schema: {
category: 'pool'
}
},
{
name: 'MaxPool2D',
schema: {
category: 'pool'
}
},
{
name: 'MaxPool3D',
schema: {
category: 'pool'
}
},
{
name: 'MaxUnPool1D',
schema: {
category: 'pool'
}
},
{
name: 'MaxUnPool2D',
schema: {
category: 'pool'
}
},
{
name: 'MaxUnPool3D',
schema: {
category: 'pool'
}
},
{
name: 'Pad1D',
schema: {
category: 'pad'
}
},
{
name: 'Pad2D',
schema: {
category: 'pad'
}
},
{
name: 'Pad3D',
schema: {
category: 'pad'
}
},
{
name: 'ZeroPad2D',
schema: {
category: 'pad'
}
},
{
name: 'CELU',
schema: {
category: 'activation'
}
},
{
name: 'ELU',
schema: {
category: 'activation'
}
},
{
name: 'GELU',
schema: {
category: 'activation'
}
},
{
name: 'Hardshrink',
schema: {
category: 'activation'
}
},
{
name: 'Hardsigmoid',
schema: {
category: 'activation'
}
},
{
name: 'Hardswish',
schema: {
category: 'activation'
}
},
{
name: 'Hardtanh',
schema: {
category: 'activation'
}
},
{
name: 'LeakyReLU',
schema: {
category: 'activation'
}
},
{
name: 'LogSigmoid',
schema: {
category: 'activation'
}
},
{
name: 'LogSoftmax',
schema: {
category: 'activation'
}
},
{
name: 'Maxout',
schema: {
category: 'activation'
}
},
{
name: 'PReLU',
schema: {
category: 'activation'
}
},
{
name: 'ReLU',
schema: {
category: 'activation'
}
},
{
name: 'ReLU6',
schema: {
category: 'activation'
}
},
{
name: 'SELU',
schema: {
category: 'activation'
}
},
{
name: 'Sigmoid',
schema: {
category: 'activation'
}
},
{
name: 'Silu',
schema: {
category: 'activation'
}
},
{
name: 'Softmax',
schema: {
category: 'activation'
}
},
{
name: 'Softplus',
schema: {
category: 'activation'
}
},
{
name: 'Softshrink',
schema: {
category: 'activation'
}
},
{
name: 'Softsign',
schema: {
category: 'activation'
}
},
{
name: 'Swish',
schema: {
category: 'activation'
}
},
{
name: 'Mish',
schema: {
category: 'activation'
}
},
{
name: 'Tanh',
schema: {
category: 'activation'
}
},
{
name: 'Tanhshrink',
schema: {
category: 'activation'
}
},
{
name: 'ThresholdedReLU',
schema: {
category: 'activation'
}
},
{
name: 'BatchNorm',
schema: {
category: 'normalization'
}
},
{
name: 'BatchNorm1D',
schema: {
category: 'normalization'
}
},
{
name: 'BatchNorm2D',
schema: {
category: 'normalization'
}
},
{
name: 'BatchNorm3D',
schema: {
category: 'normalization'
}
},
{
name: 'GroupNorm',
schema: {
category: 'normalization'
}
},
{
name: 'InstanceNorm1D',
schema: {
category: 'normalization'
}
},
{
name: 'InstanceNorm2D',
schema: {
category: 'normalization'
}
},
{
name: 'InstanceNorm3D',
schema: {
category: 'normalization'
}
},
{
name: 'LayerNorm',
schema: {
category: 'normalization'
}
},
{
name: 'LocalResponseNorm',
schema: {
category: 'normalization'
}
},
{
name: 'SpectralNorm',
schema: {
category: 'normalization'
}
},
{
name: 'SyncBatchNorm',
schema: {
category: 'normalization'
}
},
{
name: 'AlphaDropout',
schema: {
category: 'normalization'
}
},
{
name: 'Dropout',
schema: {
category: 'normalization'
}
},
{
name: 'Dropout2D',
schema: {
category: 'normalization'
}
},
{
name: 'Dropout3D',
schema: {
category: 'normalization'
}
},
{
name: 'BiRNN',
schema: {
category: 'sequence'
}
},
{
name: 'GRU',
schema: {
category: 'sequence'
}
},
{
name: 'GRUCell',
schema: {
category: 'sequence'
}
},
{
name: 'LSTM',
schema: {
category: 'sequence'
}
},
{
name: 'LSTMCell',
schema: {
category: 'sequence'
}
},
{
name: 'RNN',
schema: {
category: 'sequence'
}
},
{
name: 'RNNCellBase',
schema: {
category: 'sequence'
}
},
{
name: 'SimpleRNN',
schema: {
category: 'sequence'
}
},
{
name: 'SimpleRNNCell',
schema: {
category: 'sequence'
}
},
{
name: 'MultiHeadAttention',
schema: {
category: 'sequence'
}
},
{
name: 'Transformer',
schema: {
category: 'sequence'
}
},
{
name: 'TransformerDecoder',
schema: {
category: 'sequence'
}
},
{
name: 'TransformerDecoderLayer',
schema: {
category: 'sequence'
}
},
{
name: 'TransformerEncoder',
schema: {
category: 'sequence'
}
},
{
name: 'TransformerEncoderLayer',
schema: {
category: 'sequence'
}
},
{
name: 'Linear',
schema: {
category: 'sequence'
}
},
{
name: 'Embedding',
schema: {
category: 'sequence'
}
},
{
name: 'BCELoss',
schema: {
category: 'tensor'
}
},
{
name: 'BCEWithLogitsLoss',
schema: {
category: 'tensor'
}
},
{
name: 'CrossEntropyLoss',
schema: {
category: 'tensor'
}
},
{
name: 'CTCLoss',
schema: {
category: 'tensor'
}
},
{
name: 'HSigmoidLoss',
schema: {
category: 'tensor'
}
},
{
name: 'KLDivLoss',
schema: {
category: 'tensor'
}
},
{
name: 'L1Loss',
schema: {
category: 'tensor'
}
},
{
name: 'MarginRankingLoss',
schema: {
category: 'tensor'
}
},
{
name: 'MSELoss',
schema: {
category: 'tensor'
}
},
{
name: 'NLLLoss',
schema: {
category: 'tensor'
}
},
{
name: 'SmoothL1Loss',
schema: {
category: 'tensor'
}
},
{
name: 'PixelShuffle',
schema: {
category: 'shape'
}
},
{
name: 'Upsample',
schema: {
category: 'shape'
}
},
{
name: 'UpsamplingBilinear2D',
schema: {
category: 'shape'
}
},
{
name: 'UpsamplingNearest2D',
schema: {
category: 'shape'
}
},
{
name: 'ClipGradByGlobalNorm',
schema: {
category: 'shape'
}
},
{
name: 'ClipGradByNorm',
schema: {
category: 'shape'
}
},
{
name: 'ClipGradByValue',
schema: {
category: 'shape'
}
},
{
name: 'BeamSearchDecoder',
schema: {
category: 'shape'
}
},
{
name: 'CosineSimilarity',
schema: {
category: 'shape'
}
},
{
name: 'dynamic_decode',
schema: {
category: 'shape'
}
},
{
name: 'Flatten',
schema: {
category: 'shape'
}
},
{
name: 'PairwiseDistance',
schema: {
category: 'shape'
}
},
{
name: 'Identity',
schema: {
category: 'shape'
}
},
{
name: 'Unfold',
schema: {
category: 'shape'
}
},
{
name: 'Fold',
schema: {
category: 'shape'
}
}
]
};
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
window.base = require('netron/src/base');
window.flatbuffers = require('netron/src/flatbuffers');
window.long = {
Long: require('long')
};
window.protobuf = require('netron/src/protobuf');
window.zip = require('netron/src/zip');
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const sidebar = {};
const long = {Long: require('long')};
const marked = require('marked');
sidebar.NodeSidebar = class {
constructor(host, node) {
this._host = host;
this._node = node;
this._properties = [];
this._attributes = [];
this._inputs = [];
this._outputs = [];
if (node.type) {
this._addProperty(
'type',
new sidebar.ValueTextView(this._host, node.type, {documentation: !!node.metadata})
);
}
if (node.name) {
this._addProperty('name', new sidebar.ValueTextView(this._host, node.name));
}
if (node.location) {
this._addProperty('location', new sidebar.ValueTextView(this._host, node.location));
}
if (node.domain) {
this._addProperty('domain', new sidebar.ValueTextView(this._host, node.domain));
}
if (node.description) {
this._addProperty('description', new sidebar.ValueTextView(this._host, node.description));
}
if (node.device) {
this._addProperty('device', new sidebar.ValueTextView(this._host, node.device));
}
const attributes = node.attributes;
if (attributes && attributes.length > 0) {
const sortedAttributes = node.attributes.slice();
sortedAttributes.sort((a, b) => {
const au = a.name.toUpperCase();
const bu = b.name.toUpperCase();
return au < bu ? -1 : au > bu ? 1 : 0;
});
for (const attribute of sortedAttributes) {
this._addAttribute(attribute.name, attribute);
}
}
const inputs = node.inputs;
if (inputs && inputs.length > 0) {
for (const input of inputs) {
this._addInput(input.name, input);
}
}
const outputs = node.outputs;
if (outputs && outputs.length > 0) {
for (const output of outputs) {
this._addOutput(output.name, output);
}
}
}
render() {
return {
properties: this._properties,
groups: [
{
name: 'attributes',
properties: this._attributes
},
{
name: 'inputs',
properties: this._inputs
},
{
name: 'outputs',
properties: this._outputs
}
]
};
}
_addProperty(name, value) {
const item = new sidebar.NameValueView(this._host, name, value);
this._properties.push(item.render());
}
_addAttribute(name, attribute) {
const item = new sidebar.NameValueView(this._host, name, new NodeAttributeView(this._host, attribute));
this._attributes.push(item.render());
}
_addInput(name, input) {
if (input.arguments.length > 0) {
const view = new sidebar.ParameterView(this._host, input);
const item = new sidebar.NameValueView(this._host, name, view);
this._inputs.push(item.render());
}
}
_addOutput(name, output) {
if (output.arguments.length > 0) {
const view = new sidebar.ParameterView(this._host, output);
const item = new sidebar.NameValueView(this._host, name, view);
this._outputs.push(item.render());
}
}
static formatAttributeValue(value, type, quote) {
if (typeof value === 'function') {
return value();
}
if (value && long.Long.isLong(value)) {
return value.toString();
}
if (Number.isNaN(value)) {
return 'NaN';
}
switch (type) {
case 'shape':
return value.toString();
case 'shape[]':
return value ? value.map(item => item.toString()).join(', ') : '(null)';
case 'graph':
return value.toString();
case 'graph[]':
return value ? value.map(item => item.toString()).join(', ') : '(null)';
case 'tensor':
if (
value &&
value.type &&
value.type.shape &&
value.type.shape.dimensions &&
value.type.shape.dimensions.length == 0
) {
return value.toString();
}
return '[...]';
}
if (typeof value === 'string' && (!type || type != 'string')) {
return quote ? '"' + value + '"' : value;
}
if (Array.isArray(value)) {
if (value.length == 0) {
return quote ? '[]' : '';
}
let ellipsis = false;
if (value.length > 1000) {
value = value.slice(0, 1000);
ellipsis = true;
}
const array = value.map(item => {
if (item && long.Long.isLong(item)) {
return item.toString();
}
if (Number.isNaN(item)) {
return 'NaN';
}
return sidebar.NodeSidebar.formatAttributeValue(item, null, true);
});
if (ellipsis) {
array.push('\u2026');
}
return quote ? ['[', array.join(', '), ']'].join(' ') : array.join(', ');
}
if (value === null) {
return quote ? 'null' : '';
}
if (value === undefined) {
return 'undefined';
}
if (value !== Object(value)) {
return value.toString();
}
const list = [];
const keys = Object.keys(value).filter(key => !key.startsWith('__') && !key.endsWith('__'));
if (keys.length == 1) {
list.push(sidebar.NodeSidebar.formatAttributeValue(value[Object.keys(value)[0]], null, true));
} else {
for (const key of keys) {
list.push(key + ': ' + sidebar.NodeSidebar.formatAttributeValue(value[key], null, true));
}
}
let objectType = value.__type__;
if (!objectType && value.constructor.name && value.constructor.name !== 'Object') {
objectType = value.constructor.name;
}
if (objectType) {
return objectType + (list.length == 0 ? '()' : ['(', list.join(', '), ')'].join(''));
}
switch (list.length) {
case 0:
return quote ? '()' : '';
case 1:
return list[0];
default:
return quote ? ['(', list.join(', '), ')'].join(' ') : list.join(', ');
}
}
};
sidebar.NameValueView = class {
constructor(host, name, value) {
this._host = host;
this._name = name;
this._value = value;
this._element = {name, values: value.render()};
}
get name() {
return this._name;
}
render() {
return this._element;
}
};
// sidebar.SelectView = class {
// constructor(host, values, selected) {
// this._host = host;
// this._elements = [];
// const selectElement = this._host.document.createElement('select');
// selectElement.setAttribute('class', 'sidebar-view-item-select');
// selectElement.addEventListener('change', e => {
// this._raise('change', e.target.value);
// });
// this._elements.push(selectElement);
// for (const value of values) {
// const optionElement = this._host.document.createElement('option');
// optionElement.innerText = value;
// if (value == selected) {
// optionElement.setAttribute('selected', 'selected');
// }
// selectElement.appendChild(optionElement);
// }
// }
// render() {
// return this._elements;
// }
// on(event, callback) {
// this._events = this._events || {};
// this._events[event] = this._events[event] || [];
// this._events[event].push(callback);
// }
// _raise(event, data) {
// if (this._events && this._events[event]) {
// for (const callback of this._events[event]) {
// callback(this, data);
// }
// }
// }
// };
sidebar.ValueTextView = class {
constructor(host, value, action) {
this._host = host;
this._elements = [];
this._elements.push(Object.assign({value}, action));
}
render() {
return this._elements;
}
};
class NodeAttributeView {
constructor(host, attribute) {
this._host = host;
this._attribute = attribute;
this._element = {};
if (attribute.type) {
this._element.children = this.renderChildren();
}
let value = sidebar.NodeSidebar.formatAttributeValue(this._attribute.value, this._attribute.type);
if (value && value.length > 1000) {
value = value.substring(0, 1000) + '\u2026';
}
this._element.value = value ? value : ' ';
}
render() {
return [this._element];
}
renderChildren() {
const children = [];
const typeLine = this._host.document.createElement('div');
typeLine.className = 'sidebar-view-item-value-line-border';
const type = this._attribute.type;
const value = this._attribute.value;
if (type == 'tensor' && value && value.type) {
children.push({
name: 'type',
value: value.type.toString(),
type: 'code'
});
} else {
children.push({
name: 'type',
value: this._attribute.type,
type: 'code'
});
}
const description = this._attribute.description;
if (description) {
children.push({
value: description
});
}
if (this._attribute.type == 'tensor' && value) {
const state = value.state;
children.push({
value: state || value.toString(),
type: 'raw'
});
}
return children;
}
}
sidebar.ParameterView = class {
constructor(host, list) {
this._list = list;
this._elements = [];
this._items = [];
for (const argument of list.arguments) {
const item = new sidebar.ArgumentView(host, argument);
this._items.push(item);
this._elements.push(item.render());
}
}
render() {
return this._elements;
}
};
sidebar.ArgumentView = class {
constructor(host, argument) {
this._host = host;
this._argument = argument;
this._element = {};
const initializer = argument.initializer;
const quantization = argument.quantization;
const type = argument.type;
if (type || initializer || quantization) {
this._element.children = this.renderChildren();
}
let name = this._argument.name || '';
this._hasId = name ? true : false;
if (initializer && !this._hasId) {
this._element.name = 'kind';
this._element.value = initializer.kind;
} else {
if (typeof name !== 'string') {
throw new Error("Invalid argument identifier '" + JSON.stringify(name) + "'.");
}
name = name.split('\n').shift(); // custom argument id
this._element.name = 'name';
this._element.value = name || ' ';
}
}
render() {
return this._element;
}
renderChildren() {
const children = [];
let type = '?';
let denotation = null;
if (this._argument.type) {
type = this._argument.type.toString();
denotation = this._argument.type.denotation || null;
}
if (type) {
children.push({
name: 'type',
value: type,
type: 'code'
});
}
if (denotation) {
children.push({
name: 'denotation',
value: denotation,
type: 'code'
});
}
const description = this._argument.description;
if (description) {
children.push({
name: 'description',
value: description
});
}
const quantization = this._argument.quantization;
if (quantization) {
children.push({
name: 'quantization',
value: quantization
});
}
if (this._argument.location) {
children.push({
name: 'location',
value: this._argument.location
});
}
const initializer = this._argument.initializer;
if (initializer) {
const reference = initializer.reference;
if (reference) {
children.push({
name: 'reference',
value: this._argument.reference
});
}
const state = initializer.state;
// TODO: export tensor
// if (
// state === null &&
// this._host.save &&
// initializer.type.dataType &&
// initializer.type.dataType != '?' &&
// initializer.type.shape &&
// initializer.type.shape.dimensions &&
// initializer.type.shape.dimensions.length > 0
// ) {
// this._saveButton = this._host.document.createElement('div');
// this._saveButton.className = 'sidebar-view-item-value-expander';
// this._saveButton.innerHTML = '&#x1F4BE;';
// this._saveButton.addEventListener('click', () => {
// this._raise('export-tensor', initializer);
// });
// this._element.appendChild(this._saveButton);
// }
let content = '';
try {
content = state || initializer.toString();
} catch (err) {
content = err.toString();
this._host.exception(err, false);
}
children.push({
value: content,
type: 'raw'
});
}
return children;
}
};
sidebar.ModelSidebar = class {
constructor(host, model, graph) {
this._host = host;
this._model = model;
this._properties = [];
this._groups = [];
if (this._model.format) {
this._addProperty('format', new sidebar.ValueTextView(this._host, this._model.format));
}
if (this._model.producer) {
this._addProperty('producer', new sidebar.ValueTextView(this._host, this._model.producer));
}
if (this._model.source) {
this._addProperty('source', new sidebar.ValueTextView(this._host, this._model.source));
}
if (this._model.name) {
this._addProperty('name', new sidebar.ValueTextView(this._host, this._model.name));
}
if (this._model.version) {
this._addProperty('version', new sidebar.ValueTextView(this._host, this._model.version));
}
if (this._model.description) {
this._addProperty('description', new sidebar.ValueTextView(this._host, this._model.description));
}
if (this._model.author) {
this._addProperty('author', new sidebar.ValueTextView(this._host, this._model.author));
}
if (this._model.company) {
this._addProperty('company', new sidebar.ValueTextView(this._host, this._model.company));
}
if (this._model.license) {
this._addProperty('license', new sidebar.ValueTextView(this._host, this._model.license));
}
if (this._model.domain) {
this._addProperty('domain', new sidebar.ValueTextView(this._host, this._model.domain));
}
if (this._model.imports) {
this._addProperty('imports', new sidebar.ValueTextView(this._host, this._model.imports));
}
if (this._model.runtime) {
this._addProperty('runtime', new sidebar.ValueTextView(this._host, this._model.runtime));
}
const metadata = this._model.metadata;
if (metadata) {
for (const property of metadata) {
this._addProperty(property.name, new sidebar.ValueTextView(this._host, property.value));
}
}
if (this._model) {
// let graphSelector = new sidebar.SelectView(
// this._host,
// this._model.graphs.map(g => g.name),
// graph.name
// );
// graphSelector.on('change', (sender, data) => {
// this._raise('update-active-graph', data);
// });
this._addProperty('subgraph', new sidebar.ValueTextView(this._host, graph.name));
}
if (graph) {
if (graph.version) {
this._addProperty('version', new sidebar.ValueTextView(this._host, graph.version));
}
if (graph.type) {
this._addProperty('type', new sidebar.ValueTextView(this._host, graph.type));
}
if (graph.tags) {
this._addProperty('tags', new sidebar.ValueTextView(this._host, graph.tags));
}
if (graph.description) {
this._addProperty('description', new sidebar.ValueTextView(this._host, graph.description));
}
if (graph.inputs.length) {
for (const input of graph.inputs) {
this._addGroupProperty('inputs', input.name, input);
}
}
if (graph.outputs.length) {
for (const output of graph.outputs) {
this._addGroupProperty('outputs', output.name, output);
}
}
}
}
render() {
return {
properties: this._properties,
groups: this._groups
};
}
_addGroupProperty(group, name, argument) {
const exist = this._groups.find(g => g.name === group);
if (!exist) {
this._groups.push({
name: group,
properties: [this._addArgument(name, argument)]
});
} else {
exist.properties.push(this._addArgument(name, argument));
}
}
_addProperty(name, value) {
const item = new sidebar.NameValueView(this._host, name, value);
this._properties.push(item.render());
}
_addArgument(name, argument) {
const view = new sidebar.ParameterView(this._host, argument);
const item = new sidebar.NameValueView(this._host, name, view);
return item.render();
}
};
sidebar.DocumentationSidebar = class {
constructor(host, metadata) {
this._host = host;
this._metadata = metadata;
}
render() {
return sidebar.DocumentationSidebar.formatDocumentation(this._metadata);
}
static formatDocumentation(data) {
if (data) {
data = JSON.parse(JSON.stringify(data));
if (data.summary) {
data.summary = marked(data.summary);
}
if (data.description) {
data.description = marked(data.description);
}
if (data.attributes) {
for (const attribute of data.attributes) {
if (attribute.description) {
attribute.description = marked(attribute.description);
}
}
}
if (data.inputs) {
for (const input of data.inputs) {
if (input.description) {
input.description = marked(input.description);
}
}
}
if (data.outputs) {
for (const output of data.outputs) {
if (output.description) {
output.description = marked(output.description);
}
}
}
if (data.references) {
for (const reference of data.references) {
if (reference) {
reference.description = marked(reference.description);
}
}
}
return data;
}
return '';
}
};
sidebar.FindSidebar = class {
constructor(host, graphElement, graph) {
this._host = host;
this._graphElement = graphElement;
this._graph = graph;
}
static selection(item, graphElement) {
const selection = [];
const id = item.id;
const nodesElement = graphElement.getElementById('nodes');
if (nodesElement) {
let nodeElement = nodesElement.firstChild;
while (nodeElement) {
if (nodeElement.id == id) {
selection.push(nodeElement);
}
nodeElement = nodeElement.nextSibling;
}
}
const clustersElement = graphElement.getElementById('clusters');
if (clustersElement) {
let clusterElement = clustersElement.firstChild;
while (clusterElement) {
if (clusterElement.id == id) {
selection.push(clusterElement);
}
clusterElement = clusterElement.nextSibling;
}
}
const edgePathsElement = graphElement.getElementById('edge-paths');
if (edgePathsElement) {
let edgePathElement = edgePathsElement.firstChild;
while (edgePathElement) {
if (edgePathElement.id === id) {
// console.log('edgePathElement',edgePathElement.getAttribute("fromnode"),item);
// if (item.fromnode && edgePathElement.getAttribute("fromnode") === item.fromnode) {
// selection.push(edgePathElement);
// }
// if (item.tonode && edgePathElement.getAttribute("tonode") === item.tonode) {
// selection.push(edgePathElement);
// }
selection.push(edgePathElement);
}
edgePathElement = edgePathElement.nextSibling;
}
}
let initializerElement = graphElement.getElementById(id);
if (initializerElement) {
while (initializerElement.parentElement) {
initializerElement = initializerElement.parentElement;
if (initializerElement.id && initializerElement.id.startsWith('node-')) {
selection.push(initializerElement);
break;
}
}
}
if (selection.length > 0) {
return selection;
}
return null;
}
static selection2(item, graphElement) {
const selection = [];
const id = item.id;
const nodesElement = graphElement.getElementById('nodes');
if (nodesElement) {
let nodeElement = nodesElement.firstChild;
while (nodeElement) {
if (nodeElement.id == id) {
selection.push(nodeElement);
}
nodeElement = nodeElement.nextSibling;
}
}
const clustersElement = graphElement.getElementById('clusters');
if (clustersElement) {
let clusterElement = clustersElement.firstChild;
while (clusterElement) {
if (clusterElement.id == id) {
selection.push(clusterElement);
}
clusterElement = clusterElement.nextSibling;
}
}
const edgePathsElement = graphElement.getElementById('edge-paths');
if (edgePathsElement) {
let edgePathElement = edgePathsElement.firstChild;
while (edgePathElement) {
if (edgePathElement.id === id) {
if (item.fromnode && edgePathElement.getAttribute('fromnode') === item.fromnode) {
selection.push(edgePathElement);
}
if (item.tonode && edgePathElement.getAttribute('tonode') === item.tonode) {
selection.push(edgePathElement);
}
}
edgePathElement = edgePathElement.nextSibling;
}
}
let initializerElement = graphElement.getElementById(id);
if (initializerElement) {
while (initializerElement.parentElement) {
initializerElement = initializerElement.parentElement;
if (initializerElement.id && initializerElement.id.startsWith('node-')) {
selection.push(initializerElement);
break;
}
}
}
if (selection.length > 0) {
return selection;
}
return null;
}
update(searchText) {
const text = searchText.toLowerCase();
const nodeMatches = new Set();
const edgeMatches = new Set();
const result = [];
for (const node of this._graph.nodes) {
const initializers = [];
for (const input of node.inputs) {
for (const argument of input.arguments) {
if (
argument.name &&
argument.name.toLowerCase().indexOf(text) != -1 &&
!edgeMatches.has(argument.name)
) {
if (!argument.initializer) {
result.push({
type: 'input',
name: argument.name.split('\n').shift(), // custom argument id
id: 'edge-' + argument.name
});
edgeMatches.add(argument.name);
} else {
// initializers.push(argument.initializer);
}
}
}
}
const name = node.name;
console.log('name', node);
const operator = node.type;
if (
!nodeMatches.has(name) &&
name &&
(name.toLowerCase().indexOf(text) != -1 || (operator && operator.toLowerCase().indexOf(text) != -1))
) {
result.push({
type: 'node',
name: name,
id: 'node-' + name
});
nodeMatches.add(name);
}
// let path = node.name.split('/');
// path.pop();
// let groupName = path.join('/');
// console.log('groupName', groupName);
// const clusterNode = name => {
// if (
// !nodeMatches.has(name) &&
// name &&
// (name.toLowerCase().indexOf(text) != -1 || (operator && operator.toLowerCase().indexOf(text) != -1))
// ) {
// result.push({
// type: 'node',
// name: name,
// id: 'node-' + name
// });
// nodeMatches.add(name);
// let path = name.split('/');
// while (path.length > 0) {
// const name = path.join('/');
// path.pop();
// if (name) {
// clusterNode(name);
// }
// }
// }
// };
// if (groupName) {
// clusterNode(groupName);
// // g.setParent(nodeId, groupName);
// }
// clusterNode(node.show_name);
// if (
// !nodeMatches.has(name) &&
// name &&
// (name.toLowerCase().indexOf(text) != -1 || (operator && operator.toLowerCase().indexOf(text) != -1))
// ) {
// result.push({
// type: 'node',
// name: node.name,
// id: 'node-' + node.name
// });
// //
// nodeMatches.add(node.name);
// }
for (const initializer of initializers) {
result.push({
type: 'initializer',
name: initializer.name,
id: 'initializer-' + initializer.name
});
}
}
for (const node of this._graph.nodes) {
for (const output of node.outputs) {
for (const argument of output.arguments) {
if (
argument.name &&
argument.name.toLowerCase().indexOf(text) != -1 &&
!edgeMatches.has(argument.name)
) {
result.push({
type: 'output',
name: argument.name.split('\n').shift(), // custom argument id
id: 'edge-' + argument.name
});
edgeMatches.add(argument.name);
}
}
}
}
return {
text: searchText,
result: result
};
}
};
if (typeof module !== 'undefined' && typeof module.exports === 'object') {
module.exports.Sidebar = sidebar.Sidebar;
module.exports.ModelSidebar = sidebar.ModelSidebar;
module.exports.NodeSidebar = sidebar.NodeSidebar;
module.exports.DocumentationSidebar = sidebar.DocumentationSidebar;
module.exports.FindSidebar = sidebar.FindSidebar;
}
html {
text-size-adjust: 100%;
text-rendering: optimizeLegibility;
}
body {
overflow: hidden;
margin: 0;
width: 100vw;
height: 100vh;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', 'Ubuntu', 'Droid Sans', sans-serif,
'PingFang SC';
font-size: 12px;
text-rendering: geometricPrecision;
background-color: #fff;
&.dark {
background-color: #1d1d1f;
}
}
.graph {
overflow: auto;
width: 100%;
height: 100%;
}
.canvas {
display: block;
// position: absolute;
text-rendering: geometricPrecision;
user-select: none;
cursor: grab;
}
path {
stroke: #666;
stroke-width: 1px;
fill: none;
}
line {
stroke: #666;
stroke-width: 1px;
fill: #666;
}
text {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', 'Ubuntu', 'Droid Sans', sans-serif,
'PingFang SC';
font-size: 11px;
text-rendering: geometricPrecision;
fill: #000;
.dark & {
fill: #cfcfd1;
}
}
.node-item {
path {
fill: #fff;
fill-opacity: 1;
stroke: none;
transition: fill 0.075s ease-in, fill-opacity 0.075s ease-in;
}
text {
transition: fill 0.075s ease-in;
}
&:hover {
path {
fill: #2932e1;
fill-opacity: 1;
}
text {
fill: #fff;
}
}
}
.node-item-function path {
fill: #9bb9e8;
fill-opacity: 0.7;
}
.node-item-type {
cursor: pointer;
path {
fill: #8bb8ff;
fill-opacity: 0.9;
}
}
.node-item-type-constant path {
fill: #b4ccb7;
}
.node-item-type-control path {
fill: #a8e9b8;
}
.node-item-type-layer path {
fill: #db989a;
fill-opacity: 0.7;
}
.node-item-type-container path {
fill: #db989a;
fill-opacity: 0.7;
}
.node-item-type-wrapper path {
fill: #6dcde4;
fill-opacity: 0.7;
}
.node-item-type-conv path {
fill: #6dcde4;
fill-opacity: 0.7;
}
.node-item-type-activation path {
fill: #93c2ca;
fill-opacity: 0.7;
}
.node-item-type-pool path {
fill: #de7cce;
fill-opacity: 0.7;
}
.node-item-type-normalization path {
fill: #da96bc;
fill-opacity: 0.7;
}
.node-item-type-dropout path {
fill: #309e51;
fill-opacity: 0.7;
}
.node-item-type-pad path {
fill: #309e51;
fill-opacity: 0.7;
}
.node-item-type-shape path {
fill: #d6c482;
fill-opacity: 0.7;
}
.node-item-type-tensor path {
fill: #6d7ce4;
fill-opacity: 0.7;
}
.node-item-type-transform path {
fill: #cdcb74;
}
.node-item-type-sequence path {
fill: #cdcb74;
}
.node-item-type-data path {
fill: #2576ad;
fill-opacity: 0.7;
}
.node-item-type-custom path {
fill: #e46d6d;
fill-opacity: 0.7;
}
.node-item-input {
cursor: pointer;
path {
fill: #fff;
}
}
.node-item-constant {
cursor: pointer;
path {
fill: #eee;
}
}
.node-item-undefined {
cursor: pointer;
path {
fill: #ca5353;
fill-opacity: 0.7;
}
}
.node-attribute {
cursor: pointer;
text {
font-size: 9px;
font-weight: normal;
}
}
.node-attribute path {
fill: #fff;
stroke-width: 0;
.dark & {
fill: #262629;
}
}
.graph-item-input {
cursor: pointer;
path {
fill: #e49d6d;
fill-opacity: 0.7;
}
}
.graph-item-output {
cursor: pointer;
path {
fill: #e4e06d;
fill-opacity: 0.9;
}
}
.edge-label text {
font-size: 10px;
}
.edge-path {
stroke: #666;
stroke-width: 1px;
fill: none;
}
#arrowhead-vee path {
fill: #666;
}
.edge-path-control-dependency {
stroke-dasharray: 3, 2;
}
.cluster .clusterGroup {
fill: #dce9ff;
stroke: #666;
stroke-width: 1px;
}
.node-item-function path {
fill: #9bb9e8;
fill-opacity: 0.7;
}
.cluster .clusterGroup-constant {
fill: #e8efe9;
}
.cluster .clusterGroup-control {
fill: #e4f8e9;
}
.cluster .clusterGroup-layer {
fill: #f4e0e0;
}
.cluster .clusterGroup-conv {
fill: #d3f0f6;
}
.cluster .clusterGroup-container {
fill: #f4e0e0;
}
.cluster .clusterGroup-wrapper {
fill: #d3f0f6;
}
.cluster .clusterGroup-activation {
fill: #deecef;
}
.cluster .clusterGroup-pool {
fill: #f5d7f0;
}
.cluster .clusterGroup-normalization {
fill: #f3dfea;
}
.cluster .clusterGroup-dropout {
fill: #c0e1ca;
}
.cluster .clusterGroup-pad {
fill: #c0e1ca;
}
.cluster .clusterGroup-shape {
fill: #f2edd9;
}
.cluster .clusterGroup-tensor {
fill: #d3d7f6;
}
.cluster .clusterGroup-transform {
fill: #f0efd5;
}
.cluster .clusterGroup-sequence {
fill: #f0efd5;
}
.cluster .clusterGroup-data {
fill: #bdd5e6;
}
.cluster .clusterGroup-custom {
fill: #f6d3d3;
}
.cluster .clusterButton {
fill-opacity: 0.3;
fill: #db989a;
stroke: #999;
cursor: pointer;
}
.cluster .button-text {
fill: #999;
}
.cluster.border {
display: none;
}
.select {
&.edge-path {
stroke: #1527c2;
stroke-width: 2px;
stroke-dasharray: 6px 3px;
stroke-dashoffset: 0;
animation: pulse 4s infinite linear;
}
.node.border {
stroke: #1527c2;
stroke-width: 2px;
stroke-dasharray: 6px 3px;
stroke-dashoffset: 0;
animation: pulse 4s infinite linear;
}
.cluster.border {
display: block;
stroke: #1527c2;
stroke-width: 2px;
stroke-dasharray: 6px 3px;
stroke-dashoffset: 0;
animation: pulse 4s infinite linear;
}
}
@keyframes pulse {
from {
stroke-dashoffset: 100px;
}
to {
stroke-dashoffset: 0;
}
}
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var grapher = grapher || {};
var dagre = dagre || require('dagre');
grapher.Renderer = class {
constructor(host, svgElement, view) {
this._document = host.document;
this._svgElement = svgElement;
this._host = host;
this._view = view;
}
render(graph) {
let svgClusterGroup = null;
let svgEdgePathGroup = null;
let svgEdgeLabelGroup = null;
let svgNodeGroup = null;
svgClusterGroup = this.createElement('g');
svgClusterGroup.setAttribute('id', 'clusters');
svgClusterGroup.setAttribute('class', 'clusters');
this._svgElement.appendChild(svgClusterGroup);
svgEdgePathGroup = this.createElement('g');
svgEdgePathGroup.setAttribute('id', 'edge-paths');
svgEdgePathGroup.setAttribute('class', 'edge-paths');
this._svgElement.appendChild(svgEdgePathGroup);
svgEdgeLabelGroup = this.createElement('g');
svgEdgeLabelGroup.setAttribute('id', 'edge-labels');
svgEdgeLabelGroup.setAttribute('class', 'edge-labels');
this._svgElement.appendChild(svgEdgeLabelGroup);
svgNodeGroup = this.createElement('g');
svgNodeGroup.setAttribute('id', 'nodes');
svgNodeGroup.setAttribute('class', 'nodes');
this._svgElement.appendChild(svgNodeGroup);
// } else {
// svgClusterGroup = this._document.getElementById('clusters')
// svgEdgePathGroup = this._document.getElementById('edge-paths')
// svgEdgeLabelGroup = this._document.getElementById('edge-labels')
// svgNodeGroup = this._document.getElementById('nodes')
// }
for (const nodeId of graph.nodes()) {
if (graph.children(nodeId).length == 0) {
const node = graph.node(nodeId);
// 在这里进行缓存的判断
// console.log('this._document', this._document);
// const nodeDom = this._document.getElementById(node.id);
// console.log('nodeDom', nodeDom);
if (this._view._nodes.hasOwnProperty(node.id)) {
// 这个节点存在过
svgNodeGroup.appendChild(this._view._nodes[node.id]);
const nodeBox = this._view._nodes[node.id].getBBox();
node.width = nodeBox.width;
node.height = nodeBox.height;
node.element = this._view._nodes[node.id];
} else {
const element = this.createElement('g');
if (node.id) {
element.setAttribute('id', node.id);
}
element.setAttribute(
'class',
Object.prototype.hasOwnProperty.call(node, 'class') ? 'node ' + node.class : 'node'
);
element.style.opacity = 0;
const container = this.createElement('g');
container.appendChild(node.label);
// node.label 就是fromat 之后的节点
element.appendChild(container);
svgNodeGroup.appendChild(element);
const nodeBox = node.label.getBBox();
const nodeX = -nodeBox.width / 2;
const nodeY = -nodeBox.height / 2;
container.setAttribute('transform', 'translate(' + nodeX + ',' + nodeY + ')');
node.width = nodeBox.width;
node.height = nodeBox.height;
node.element = element;
}
}
}
for (const edgeId of graph.edges()) {
const edge = graph.edge(edgeId);
if (edge.label) {
const tspan = this.createElement('tspan');
tspan.setAttribute('xml:space', 'preserve');
tspan.setAttribute('dy', '1em');
tspan.setAttribute('x', '1');
tspan.appendChild(this._document.createTextNode(edge.label));
const text = this.createElement('text');
text.appendChild(tspan);
const textContainer = this.createElement('g');
textContainer.appendChild(text);
const labelElement = this.createElement('g');
labelElement.style.opacity = 0;
labelElement.setAttribute('class', 'edge-label');
labelElement.appendChild(textContainer);
svgEdgeLabelGroup.appendChild(labelElement);
const edgeBox = textContainer.getBBox();
const edgeX = -edgeBox.width / 2;
const edgeY = -edgeBox.height / 2;
textContainer.setAttribute('transform', 'translate(' + edgeX + ',' + edgeY + ')');
edge.width = edgeBox.width;
edge.height = edgeBox.height;
edge.labelElement = labelElement;
}
}
dagre.layout(graph);
// 实际要变的就是这一块
for (const nodeId of graph.nodes()) {
if (graph.children(nodeId).length == 0) {
const node = graph.node(nodeId);
node.element.setAttribute('transform', 'translate(' + node.x + ',' + node.y + ')');
node.element.style.opacity = 1;
delete node.element;
}
}
for (const edgeId of graph.edges()) {
const edge = graph.edge(edgeId);
if (edge.labelElement) {
edge.labelElement.setAttribute('transform', 'translate(' + edge.x + ',' + edge.y + ')');
edge.labelElement.style.opacity = 1;
delete edge.labelElement;
}
}
const edgePathGroupDefs = this.createElement('defs');
svgEdgePathGroup.appendChild(edgePathGroupDefs);
const marker = this.createElement('marker');
marker.setAttribute('id', 'arrowhead-vee');
marker.setAttribute('viewBox', '0 0 10 10');
marker.setAttribute('refX', 9);
marker.setAttribute('refY', 5);
marker.setAttribute('markerUnits', 'strokeWidth');
marker.setAttribute('markerWidth', 8);
marker.setAttribute('markerHeight', 6);
marker.setAttribute('orient', 'auto');
edgePathGroupDefs.appendChild(marker);
const markerPath = this.createElement('path');
markerPath.setAttribute('d', 'M 0 0 L 10 5 L 0 10 L 4 5 z');
markerPath.style.setProperty('stroke-width', 1);
markerPath.style.setProperty('stroke-dasharray', '1,0');
marker.appendChild(markerPath);
for (const edgeId of graph.edges()) {
const edge = graph.edge(edgeId);
const edgePath = grapher.Renderer._computeCurvePath(edge, graph.node(edgeId.v), graph.node(edgeId.w));
const edgeElement = this.createElement('path');
edgeElement.setAttribute(
'class',
Object.prototype.hasOwnProperty.call(edge, 'class') ? 'edge-path ' + edge.class : 'edge-path'
);
edgeElement.setAttribute('d', edgePath);
edgeElement.setAttribute('marker-end', 'url(#arrowhead-vee)');
if (edge.id) {
edgeElement.setAttribute('id', edge.id);
}
if (edge.fromnode) {
edgeElement.setAttribute('fromnode', edge.fromnode);
}
if (edge.tonode) {
edgeElement.setAttribute('tonode', edge.tonode);
}
svgEdgePathGroup.appendChild(edgeElement);
}
const groupArray = [];
for (const nodeId of graph.nodes()) {
if (!Number(nodeId) && Number(nodeId) !== 0) {
groupArray.push(nodeId);
}
}
const newGroupArray = groupArray.sort((a, b) => {
let level1 = a.split('/').length;
let level2 = b.split('/').length;
return level1 - level2;
});
for (const nodeId of newGroupArray) {
if (graph.children(nodeId).length > 0) {
const node = graph.node(nodeId);
// const nodeDom = this._document.getElementById(`node-${nodeId}`)
// if (this._view._nodes.hasOwnProperty(node.id)) {
// // 这个节点存在过
// svgNodeGroup.appendChild(this._view._nodes[node.id]);
// const nodeBox = this._view._nodes[node.id].getBBox();
// node.width = nodeBox.width;
// node.height = nodeBox.height;
// node.element = this._view._nodes[node.id]
if (this._view._clusters.hasOwnProperty(node.id)) {
const nodeDom = this._view._clusters.hasOwnProperty(node.id);
nodeDom.setAttribute('transform', 'translate(' + node.x + ',' + node.y + ')');
nodeDom.firstChild.setAttribute('x', -node.width / 2);
nodeDom.firstChild.setAttribute('y', -node.height / 2);
nodeDom.firstChild.setAttribute('width', node.width + 10);
nodeDom.firstChild.setAttribute('height', node.height + 10);
} else {
const nodeElement = this.createElement('g');
nodeElement.setAttribute('class', 'cluster');
nodeElement.setAttribute('id', `node-${nodeId}`);
nodeElement.setAttribute('transform', 'translate(' + node.x + ',' + node.y + ')');
const rect = this.createElement('rect');
const tspan = this.createElement('tspan');
const button = this.createElement('circle');
const buttonSign = this.createElement('tspan');
button.setAttribute('r', '6.5');
button.setAttribute('cx', node.width / 2 - 20 + 7.5 + 10);
button.setAttribute('cy', -(node.height / 2) + 5 + 7.5);
buttonSign.setAttribute('x', node.width / 2 - 15 + 9);
buttonSign.setAttribute('y', -(node.height / 2) + 1.3);
buttonSign.setAttribute('xml:space', 'preserve');
buttonSign.setAttribute('dy', '1em');
buttonSign.setAttribute('font-size', '16px');
buttonSign.setAttribute('class', 'button-text');
button.setAttribute('class', 'clusterButton');
tspan.setAttribute('xml:space', 'preserve');
tspan.setAttribute('dy', '1em');
tspan.setAttribute('x', 0);
tspan.setAttribute('y', -(node.height / 2) + 5);
tspan.setAttribute('text-anchor', 'middle');
let name = '';
for (const nodes of this._host._view._allGraph.nodes) {
if (nodes.name === node.nodeId) {
name = nodes.show_name.split('/')[nodes.show_name.split('/').length - 1];
}
}
tspan.appendChild(this._document.createTextNode(name));
buttonSign.appendChild(this._document.createTextNode('-'));
const text = this.createElement('text');
text.appendChild(tspan);
const text2 = this.createElement('text');
text2.appendChild(buttonSign);
rect.setAttribute('class', node.classList.join(' '));
rect.setAttribute('x', -node.width / 2);
rect.setAttribute('y', -node.height / 2);
rect.setAttribute('width', node.width + 10);
rect.setAttribute('height', node.height + 10);
const borderElement = this.createElement('path');
borderElement.setAttribute('class', ['cluster', 'border'].join(' '));
borderElement.setAttribute(
'd',
grapher.NodeElement.roundedRect(
-node.width / 2,
-node.height / 2,
node.width + 10,
node.height + 10,
true,
true,
true,
true
)
);
nodeElement.addEventListener('click', () => {
this._view.select({
id: `node-${nodeId}`,
name: nodeId,
type: 'node'
});
});
text2.addEventListener('click', () => {
this._host.selectNodeId({
nodeId: node.nodeId,
expand: node.expand,
isKeepData: node.isKeepData
});
this._host.selectItems({
id: `node-${node.nodeId}`,
name: node.nodeId,
type: 'node'
});
});
rect.addEventListener('click', () => {
if (this._view.isCtrl) {
for (const nodes of this._view._allGraph.nodes) {
if (nodes.name === node.nodeId) {
for (const type of this._view.non_graphMetadatas) {
if (type.name === nodes.type) {
if (this._view.Language === 'zh') {
window.open(
`https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/${type.name}_cn.html`
);
} else {
window.open(
`https://www.paddlepaddle.org.cn/documentation/docs/en/api/paddle/nn/${type.name}_en.html`
);
}
}
}
this._view.showNodeProperties(nodes);
return;
}
}
} else {
for (const nodes of this._view._allGraph.nodes) {
if (nodes.name === node.nodeId) {
this._view.showNodeProperties(nodes);
return;
}
}
}
});
if (node.rx) {
rect.setAttribute('rx', node.rx);
}
if (node.ry) {
rect.setAttribute('ry', node.ry);
}
nodeElement.appendChild(rect);
nodeElement.appendChild(text);
nodeElement.appendChild(button);
nodeElement.appendChild(text2);
nodeElement.appendChild(borderElement);
svgClusterGroup.appendChild(nodeElement);
}
}
}
}
createElement(name) {
return this._document.createElementNS('http://www.w3.org/2000/svg', name);
}
static _computeCurvePath(edge, tail, head) {
const points = edge.points.slice(1, edge.points.length - 1);
points.unshift(grapher.Renderer.intersectRect(tail, points[0]));
points.push(grapher.Renderer.intersectRect(head, points[points.length - 1]));
const path = new Path();
const curve = new Curve(path);
for (let i = 0; i < points.length; i++) {
const point = points[i];
if (i == 0) {
curve.lineStart();
}
curve.point(point.x, point.y);
if (i == points.length - 1) {
curve.lineEnd();
}
}
return path.data;
}
static intersectRect(node, point) {
const x = node.x;
const y = node.y;
const dx = point.x - x;
const dy = point.y - y;
let w = node.width / 2;
let h = node.height / 2;
let sx;
let sy;
if (Math.abs(dy) * w > Math.abs(dx) * h) {
if (dy < 0) {
h = -h;
}
sx = dy === 0 ? 0 : (h * dx) / dy;
sy = h;
} else {
if (dx < 0) {
w = -w;
}
sx = w;
sy = dx === 0 ? 0 : (w * dy) / dx;
}
return {x: x + sx, y: y + sy};
}
};
grapher.NodeElement = class {
constructor(document) {
this._document = document;
this._blocks = [];
}
block(type) {
this._block = null;
switch (type) {
case 'header':
this._block = new grapher.NodeElement.Header(this._document);
break;
case 'list':
this._block = new grapher.NodeElement.List(this._document);
break;
}
this._blocks.push(this._block);
return this._block;
}
format(contextElement) {
const rootElement = this.createElement('g');
contextElement.appendChild(rootElement);
let width = 0;
let height = 0;
const tops = [];
for (const block of this._blocks) {
tops.push(height);
block.layout(rootElement);
if (width < block.width) {
width = block.width;
}
height = height + block.height;
}
for (let i = 0; i < this._blocks.length; i++) {
// push 进来的header 或者 list
const top = tops.shift();
this._blocks[i].update(rootElement, top, width, i == 0, i == this._blocks.length - 1);
}
const borderElement = this.createElement('path');
borderElement.setAttribute('class', ['node', 'border'].join(' '));
borderElement.setAttribute('d', grapher.NodeElement.roundedRect(0, 0, width, height, true, true, true, true));
rootElement.appendChild(borderElement);
contextElement.innerHTML = '';
return rootElement;
}
static roundedRect(x, y, width, height, r1, r2, r3, r4) {
const radius = 5;
r1 = r1 ? radius : 0;
r2 = r2 ? radius : 0;
r3 = r3 ? radius : 0;
r4 = r4 ? radius : 0;
return (
'M' +
(x + r1) +
',' +
y +
'h' +
(width - r1 - r2) +
'a' +
r2 +
',' +
r2 +
' 0 0 1 ' +
r2 +
',' +
r2 +
'v' +
(height - r2 - r3) +
'a' +
r3 +
',' +
r3 +
' 0 0 1 ' +
-r3 +
',' +
r3 +
'h' +
(r3 + r4 - width) +
'a' +
r4 +
',' +
r4 +
' 0 0 1 ' +
-r4 +
',' +
-r4 +
'v' +
(-height + r4 + r1) +
'a' +
r1 +
',' +
r1 +
' 0 0 1 ' +
r1 +
',' +
-r1 +
'z'
);
}
createElement(name) {
return this._document.createElementNS('http://www.w3.org/2000/svg', name);
}
};
grapher.NodeElement.Header = class {
constructor(document) {
this._document = document;
this._items = [];
}
add(id, classList, content, tooltip, handler) {
this._items.push({
id: id,
classList: classList,
content: content,
tooltip: tooltip,
handler: handler
});
}
layout(parentElement) {
this._width = 0;
this._height = 0;
this._elements = [];
let x = 0;
const y = 0;
for (const item of this._items) {
const yPadding = 4;
const xPadding = 7;
const element = this.createElement('g');
let classList = ['node-item'];
parentElement.appendChild(element);
const pathElement = this.createElement('path');
const textElement = this.createElement('text');
element.appendChild(pathElement);
element.appendChild(textElement);
if (item.classList) {
classList = classList.concat(item.classList);
}
element.setAttribute('class', classList.join(' '));
if (item.id) {
element.setAttribute('id', item.id);
}
if (item.handler) {
element.addEventListener('click', item.handler);
}
if (item.tooltip) {
const titleElement = this.createElement('title');
titleElement.textContent = item.tooltip;
element.appendChild(titleElement);
}
if (item.content) {
textElement.textContent = item.content;
}
const boundingBox = textElement.getBBox();
const width = boundingBox.width + xPadding + xPadding;
const height = boundingBox.height + yPadding + yPadding;
this._elements.push({
group: element,
text: textElement,
path: pathElement,
x: x,
y: y,
width: width,
height: height,
tx: xPadding,
ty: yPadding - boundingBox.y
});
x += width;
if (this._height < height) {
this._height = height;
}
if (x > this._width) {
this._width = x;
}
}
}
get width() {
return this._width;
}
get height() {
return this._height;
}
update(parentElement, top, width, first, last) {
const dx = width - this._width;
let i;
let element;
for (i = 0; i < this._elements.length; i++) {
element = this._elements[i];
if (i == 0) {
element.width = element.width + dx;
} else {
element.x = element.x + dx;
element.tx = element.tx + dx;
}
element.y = element.y + top;
}
for (i = 0; i < this._elements.length; i++) {
element = this._elements[i];
element.group.setAttribute('transform', 'translate(' + element.x + ',' + element.y + ')');
const r1 = i == 0 && first;
const r2 = i == this._elements.length - 1 && first;
const r3 = i == this._elements.length - 1 && last;
const r4 = i == 0 && last;
element.path.setAttribute(
'd',
grapher.NodeElement.roundedRect(0, 0, element.width, element.height, r1, r2, r3, r4)
);
element.text.setAttribute('x', 6);
element.text.setAttribute('y', element.ty);
}
let lineElement;
for (i = 0; i < this._elements.length; i++) {
element = this._elements[i];
if (i != 0) {
lineElement = this.createElement('line');
lineElement.setAttribute('class', 'node');
lineElement.setAttribute('x1', element.x);
lineElement.setAttribute('x2', element.x);
lineElement.setAttribute('y1', top);
lineElement.setAttribute('y2', top + this._height);
parentElement.appendChild(lineElement);
}
}
if (!first) {
lineElement = this.createElement('line');
lineElement.setAttribute('class', 'node');
lineElement.setAttribute('x1', 0);
lineElement.setAttribute('x2', width);
lineElement.setAttribute('y1', top);
lineElement.setAttribute('y2', top);
parentElement.appendChild(lineElement);
}
}
createElement(name) {
return this._document.createElementNS('http://www.w3.org/2000/svg', name);
}
};
grapher.NodeElement.List = class {
constructor(document) {
this._document = document;
this._items = [];
}
add(id, name, value, tooltip, separator) {
this._items.push({id: id, name: name, value: value, tooltip: tooltip, separator: separator});
}
get handler() {
return this._handler;
}
set handler(handler) {
this._handler = handler;
}
layout(parentElement) {
this._width = 0;
this._height = 0;
const x = 0;
const y = 0;
this._element = this.createElement('g');
this._element.setAttribute('class', 'node-attribute');
parentElement.appendChild(this._element);
if (this._handler) {
this._element.addEventListener('click', this._handler);
}
this._backgroundElement = this.createElement('path');
this._element.appendChild(this._backgroundElement);
this._element.setAttribute('transform', 'translate(' + x + ',' + y + ')');
this._height += 3;
for (const item of this._items) {
const yPadding = 1;
const xPadding = 6;
const textElement = this.createElement('text');
if (item.id) {
textElement.setAttribute('id', item.id);
}
textElement.setAttribute('xml:space', 'preserve');
this._element.appendChild(textElement);
if (item.tooltip) {
const titleElement = this.createElement('title');
titleElement.textContent = item.tooltip;
textElement.appendChild(titleElement);
}
const textNameElement = this.createElement('tspan');
textNameElement.textContent = item.name;
if (item.separator.trim() != '=') {
textNameElement.style.fontWeight = 'bold';
}
textElement.appendChild(textNameElement);
const textValueElement = this.createElement('tspan');
textValueElement.textContent = item.separator + item.value;
textElement.appendChild(textValueElement);
const size = textElement.getBBox();
const width = xPadding + size.width + xPadding;
if (this._width < width) {
this._width = width;
}
textElement.setAttribute('x', x + xPadding);
textElement.setAttribute('y', this._height + yPadding - size.y);
this._height += yPadding + size.height + yPadding;
}
this._height += 3;
if (this._width < 100) {
this._width = 100;
}
}
get width() {
return this._width;
}
get height() {
return this._height;
}
update(parentElement, top, width, first, last) {
this._element.setAttribute('transform', 'translate(0,' + top + ')');
const r1 = first;
const r2 = first;
const r3 = last;
const r4 = last;
this._backgroundElement.setAttribute(
'd',
grapher.NodeElement.roundedRect(0, 0, width, this._height, r1, r2, r3, r4)
);
if (!first) {
const lineElement = this.createElement('line');
lineElement.setAttribute('class', 'node');
lineElement.setAttribute('x1', 0);
lineElement.setAttribute('x2', width);
lineElement.setAttribute('y1', 0);
lineElement.setAttribute('y2', 0);
this._element.appendChild(lineElement);
}
}
createElement(name) {
return this._document.createElementNS('http://www.w3.org/2000/svg', name);
}
};
class Path {
constructor() {
this._x0 = null;
this._y0 = null;
this._x1 = null;
this._y1 = null;
this._data = '';
}
moveTo(x, y) {
this._data += 'M' + (this._x0 = this._x1 = +x) + ',' + (this._y0 = this._y1 = +y);
}
lineTo(x, y) {
this._data += 'L' + (this._x1 = +x) + ',' + (this._y1 = +y);
}
bezierCurveTo(x1, y1, x2, y2, x, y) {
this._data += 'C' + +x1 + ',' + +y1 + ',' + +x2 + ',' + +y2 + ',' + (this._x1 = +x) + ',' + (this._y1 = +y);
}
closePath() {
if (this._x1 !== null) {
this._x1 = this._x0;
this._y1 = this._y0;
this._data += 'Z';
}
}
get data() {
return this._data;
}
}
class Curve {
constructor(context) {
this._context = context;
}
lineStart() {
this._x0 = NaN;
this._x1 = NaN;
this._y0 = NaN;
this._y1 = NaN;
this._point = 0;
}
lineEnd() {
switch (this._point) {
case 3:
this.curve(this._x1, this._y1);
this._context.lineTo(this._x1, this._y1);
break;
case 2:
this._context.lineTo(this._x1, this._y1);
break;
}
if (this._line || (this._line !== 0 && this._point === 1)) {
this._context.closePath();
}
this._line = 1 - this._line;
}
point(x, y) {
x = +x;
y = +y;
switch (this._point) {
case 0:
this._point = 1;
if (this._line) {
this._context.lineTo(x, y);
} else {
this._context.moveTo(x, y);
}
break;
case 1:
this._point = 2;
break;
case 2:
this._point = 3;
this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6);
this.curve(x, y);
break;
default:
this.curve(x, y);
break;
}
this._x0 = this._x1;
this._x1 = x;
this._y0 = this._y1;
this._y1 = y;
}
curve(x, y) {
this._context.bezierCurveTo(
(2 * this._x0 + this._x1) / 3,
(2 * this._y0 + this._y1) / 3,
(this._x0 + 2 * this._x1) / 3,
(this._y0 + 2 * this._y1) / 3,
(this._x0 + 4 * this._x1 + x) / 6,
(this._y0 + 4 * this._y1 + y) / 6
);
}
}
if (typeof module !== 'undefined' && typeof module.exports === 'object') {
module.exports.Renderer = grapher.Renderer;
module.exports.NodeElement = grapher.NodeElement;
}
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// cSpell:words grapher selectall nodesep ranksep rankdir pbtxt
const zip = require('netron/src/zip');
const gzip = require('netron/src/gzip');
const tar = require('netron/src/tar');
const protobuf = require('netron/src/protobuf');
const d3 = require('d3');
const dagre = require('dagre');
const grapher = require('./view-grapher');
const sidebar = require('./sidebar');
const view = {};
const graphMetadata = require('./paddle-metadata');
const {style} = require('d3');
view.View = class {
constructor(host) {
this._host = host;
this._host
.initialize(this)
.then(() => {
this.typeLayer = {};
this.Language = 'zh';
this.graphMetadatas = [];
this.non_graphMetadatas = [];
this.isCtrl = false;
this._clusters = {};
this._nodeName = {};
this._nodes = {};
this._model = null;
this._selection = [];
this._selectItem = null;
this._host.start();
this._showAttributes = false;
this._showInitializers = true;
this._showNames = false;
this._KeepData = false;
this._showHorizontal = false;
this._modelFactoryService = new view.ModelFactoryService(this._host);
this._graphNodes = {};
})
.catch(err => {
this.error(err.message, err);
});
}
cut() {
this._host.document.execCommand('cut');
}
copy() {
this._host.document.execCommand('copy');
}
paste() {
this._host.document.execCommand('paste');
}
selectAll() {
this._host.document.execCommand('selectall');
}
find(value) {
if (this._activeGraph) {
this.clearSelection();
const graphElement = document.getElementById('canvas');
if (this._allGraph) {
const view = new sidebar.FindSidebar(this._host, graphElement, this._allGraph);
this._host.message('search', view.update(value));
} else {
const view = new sidebar.FindSidebar(this._host, graphElement, this._activeGraph);
this._host.message('search', view.update(value));
}
}
}
toggleAttributes(toggle) {
if (toggle != null && !(toggle ^ this._showAttributes)) {
return;
}
this._showAttributes = toggle == null ? !this._showAttributes : toggle;
this._nodes = {};
this._clusters = {};
this._reload();
}
get showAttributes() {
return this._showAttributes;
}
toggleInitializers(toggle) {
if (toggle != null && !(toggle ^ this._showInitializers)) {
return;
}
this._showInitializers = toggle == null ? !this._showInitializers : toggle;
this._nodes = {};
this._clusters = {};
this._reload();
}
get showInitializers() {
return this._showInitializers;
}
toggleNames(toggle) {
if (toggle != null && !(toggle ^ this._showNames)) {
return;
}
this._showNames = toggle == null ? !this._showNames : toggle;
this._nodes = {};
this._clusters = {};
this._reload();
}
toggleKeepData(toggle) {
if (toggle != null && !(toggle ^ this._KeepData)) {
return;
}
this._KeepData = toggle == null ? !this._KeepData : toggle;
// this._reload();
}
toggleLanguage(data) {
this.Language = data;
}
get showNames() {
return this._showNames;
}
get KeepData() {
return this._KeepData;
}
toggleDirection(toggle) {
if (toggle != null && !(toggle ^ this._showHorizontal)) {
return;
}
this._showHorizontal = toggle == null ? !this._showHorizontal : toggle;
this._reload();
}
get showHorizontal() {
return this._showHorizontal;
}
toggleTheme(theme) {
this._host.document.body.className = theme;
}
_reload() {
this._host.status('loading');
if (this._model && this._activeGraph) {
this._updateGraph2(this._model, this._activeGraph).catch(error => {
if (error) {
this.error('Graph update failed.', error);
}
});
}
}
_timeout(time) {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, time);
});
}
zoomIn() {
if (this._zoom) {
this._zoom.scaleBy(d3.select(this._host.document.getElementById('canvas')), 1.2);
}
}
zoomOut() {
if (this._zoom) {
this._zoom.scaleBy(d3.select(this._host.document.getElementById('canvas')), 0.8);
}
}
selectItem(data) {
this._selectItem = data;
}
resetZoom() {
if (this._zoom) {
this._zoom.scaleTo(d3.select(this._host.document.getElementById('canvas')), 1);
}
}
select(item) {
this.clearSelection();
if (item.type === 'node') {
for (const nodes of this._allGraph.nodes) {
if (nodes.name === item.name) {
this.showNodeProperties(nodes);
break;
}
}
}
const graphElement = document.getElementById('canvas');
const selection = sidebar.FindSidebar.selection(item, graphElement);
if (selection && selection.length > 0) {
const graphElement = this._host.document.getElementById('canvas');
const graphRect = graphElement.getBoundingClientRect();
let x = 0;
let y = 0;
for (const element of selection) {
element.classList.add('select');
this._selection.push(element);
const transform = element.transform.baseVal.consolidate();
const box = element.getBBox();
const ex = transform ? transform.matrix.e : box.x + box.width / 2;
const ey = transform ? transform.matrix.f : box.y + box.height / 2;
x += ex;
y += ey;
}
x = x / selection.length;
y = y / selection.length;
this._zoom.transform(
d3.select(graphElement),
d3.zoomIdentity.translate(graphRect.width / 2 - x, graphRect.height / 2 - y)
);
}
}
select2(item) {
const graphElement = document.getElementById('canvas');
const selection = sidebar.FindSidebar.selection2(item, graphElement);
if (selection && selection.length > 0) {
for (const element of selection) {
this._selection.push(element);
element.classList.add('select');
}
}
}
clearSelection() {
while (this._selection.length > 0) {
const element = this._selection.pop();
element.classList.remove('select');
}
}
error(message, err) {
this._host.error(message, err.toString());
}
accept(file) {
return this._modelFactoryService.accept(file);
}
open(context) {
return this._timeout(2).then(() => {
return this._modelFactoryService.open(context).then(model => {
return this._timeout(20).then(() => {
console.log('model.graphs.length', model.graphs.length);
const graph = model.graphs.length > 0 ? model.graphs[0] : null;
this._host.message('opened', {
graphs: model.graphs.map(g => g.name || ''),
selected: graph && (graph.name || '')
});
return this._updateGraph2(graph);
});
});
});
}
changeAlt(data) {
this.isCtrl = data;
console.log('isCtrl', this.isCtrl);
}
keydown() {
// 用户按下ctrl后变量isCtrl为true
this._host.document.onkeydown = e => {
if (
e.code === 'MetaLeft' ||
e.code === 'MetaRight' ||
e.code === 'ControlLeft' ||
e.code === 'AltLeft' ||
e.code === 'AltRight'
) {
this.isCtrl = true;
}
};
// 用户松开ctrl后变量isCtrl为false
this._host.document.onkeyup = e => {
if (
e.code === 'MetaLeft' ||
e.code === 'MetaRight' ||
e.code === 'ControlLeft' ||
e.code === 'AltLeft' ||
e.code === 'AltRight'
) {
this.isCtrl = false;
}
};
}
changeGraph(name) {
this._updateActiveGraph(name);
}
changeAllGrap(graph) {
this._allGraph = graph;
for (const node of graph.nodes) {
this._nodeName[node.name] = node;
}
// console.log('this._nodeName',this._nodeName);
}
changeSelect(selectItem) {
this._selectItem = selectItem;
}
_updateActiveGraph(data) {
if (data) {
this._host.status('loading');
this._timeout(200).then(() => {
return this._updateGraph(data).catch(error => {
if (error) {
this.error('Graph update failed.', error);
}
});
});
}
}
_updateGraph(data) {
return this._timeout(100).then(() => {
// 直接在此处传入模型数据的数据
if (data && data != this._activeGraph) {
const nodes = data.nodes;
if (nodes.length > 1400) {
if (
!this._host.confirm(
'Large model detected.',
'This graph contains a large number of nodes and might take a long time to render. Do you want to continue?'
)
) {
return null;
}
}
}
return this.renderGraph(data, data)
.then(() => {
this._model = data;
this._activeGraph = data;
this._host.status('rendered');
return this._model;
})
.catch(error => {
return this.renderGraph(this._model, this._activeGraph)
.then(() => {
this._host.status('rendered');
})
.finally(() => {
throw error;
});
});
});
}
_updateGraph2(graph) {
return this._timeout(100).then(() => {
// 直接在此处传入模型数据的数据
if (graph && graph != this._activeGraph) {
this._selectItem = null;
const nodes = graph.nodes;
console.log('graphs', graph);
console.log('nodes.length', nodes);
if (nodes.length > 1400) {
if (
!this._host.confirm(
'Large model detected.',
'This graph contains a large number of nodes and might take a long time to render. Do you want to continue?'
)
) {
return null;
}
}
}
return this.renderGraph(graph, graph)
.then(() => {
this._model = graph;
this._activeGraph = graph;
this._host.status('rendered');
return this._model;
})
.catch(error => {
return this.renderGraph(this._model, this._activeGraph)
.then(() => {
this._host.status('rendered');
})
.finally(() => {
throw error;
});
});
});
}
jumpRoute(node) {
console.log('node', node);
if (node.is_leaf) {
console.log('isCtrl', this.isCtrl);
if (this.isCtrl) {
for (const nodes of this._allGraph.nodes) {
if (nodes.name === node.name) {
for (const type of this.non_graphMetadatas) {
console.log('type', type.name.toLowerCase(), node.type);
if (type.name.toLowerCase() === node.type) {
if (this.Language === 'zh') {
window.open(
`https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/${type.name}_cn.html`
);
} else {
window.open(
`https://www.paddlepaddle.org.cn/documentation/docs/en/api/paddle/nn/${type.name}_en.html`
);
}
}
}
}
}
}
} else {
if (this.isCtrl) {
for (const nodes of this._allGraph.nodes) {
if (nodes.name === node.name) {
for (const type of this.non_graphMetadatas) {
if (type.name === node.type) {
window.open(
`https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/${type.name}_cn.html`
);
}
}
}
}
}
}
}
renderGraph(model, graph) {
try {
this.keydown();
this.graphMetadatas = graphMetadata.default.leaf_nodes;
this.non_graphMetadatas = graphMetadata.default.non_leaf_nodes;
const typeLayer = {};
for (const type of graphMetadata.default.non_leaf_nodes) {
typeLayer[type.name] = true;
}
this.typeLayer = typeLayer;
const graphElement = this._host.document.getElementById('canvas');
while (graphElement.lastChild) {
// 做上一次渲染的的清理动作
graphElement.removeChild(graphElement.lastChild);
}
if (!graph) {
return Promise.resolve();
} else {
this._zoom = null;
graphElement.style.position = 'absolute';
graphElement.style.margin = '0';
const groups = true;
const graphOptions = {};
graphOptions.nodesep = 65;
graphOptions.ranksep = 60;
if (this._showHorizontal) {
graphOptions.rankdir = 'LR';
}
const g = new dagre.graphlib.Graph({compound: groups});
g.setGraph(graphOptions);
g.setDefaultEdgeLabel(() => {
return {};
});
let nodeId = 0;
const edgeMap = {};
const clusterMap = {};
const clusterParentMap = {};
let id = new Date().getTime();
let nodes = graph.nodes;
if (nodes.length > 1500) {
graphOptions.ranker = 'longest-path';
}
if (groups) {
for (const node of nodes) {
let path = node.name.split('/');
path.pop();
console.log('path.length', path.length);
while (path.length > 0) {
const name = path.join('/');
path.pop();
if (name) {
clusterParentMap[name] = path.join('/');
}
}
}
}
for (const node of nodes) {
let element = null;
if (!document.getElementById(`node-${node.name}`)) {
element = new grapher.NodeElement(this._host.document);
}
const addNode = (element, node, edges) => {
if (!document.getElementById(`node-${node.name}`)) {
const header = element.block('header');
const styles = ['node-item-type'];
const type = node.type;
if (node.is_leaf) {
for (const metadatas of this.graphMetadatas) {
if (node.type === metadatas.name) {
if (metadatas.schema.category) {
styles.push('node-item-type-' + metadatas.schema.category.toLowerCase());
}
}
}
} else {
for (const metadatas of this.non_graphMetadatas) {
if (node.type === metadatas.name) {
if (metadatas.schema.category) {
styles.push('node-item-type-' + metadatas.schema.category.toLowerCase());
}
}
}
}
if (typeof type !== 'string' || !type.split) {
// #416
throw new ModelError(
"Unknown node type '" + JSON.stringify(type) + "' in '" + model.format + "'."
);
}
const nodeName = node.name.split('/')[node.name.split('/').length - 1];
const content = this.showNames && node.name ? nodeName : type.split('.').pop();
const tooltip = this.showNames && node.name ? type : nodeName;
header.add(null, styles, content, tooltip, () => {
this.jumpRoute(node);
this.showNodeProperties(node);
this.select({
id: `node-${node.name}`,
name: node.name,
type: 'node'
});
const inputs = node.inputs;
for (const input of inputs) {
for (const argument of input.arguments) {
if (argument.name != '' && !argument.initializer) {
this.select2({
id: `edge-${argument.name}`,
name: argument.name,
type: 'input',
tonode: node.name
});
}
}
}
let outputs = node.outputs;
if (node.chain && node.chain.length > 0) {
const chainOutputs = node.chain[node.chain.length - 1].outputs;
if (chainOutputs.length > 0) {
outputs = chainOutputs;
}
}
for (const output of outputs) {
for (const argument of output.arguments) {
if (argument.name != '') {
this.select2({
id: `edge-${argument.name}`,
name: argument.name,
type: 'input',
fromnode: node.name
});
}
}
}
});
const buttons = ['node-item-buttons'];
if (!node.is_leaf) {
header.add(null, buttons, '+', null, () => {
// debugger;
this._host.selectNodeId({
nodeId: node.name,
expand: true
});
this._host.selectItems({
id: `node-${node.name}`,
name: node.name,
type: 'node'
});
});
}
const initializers = [];
let hiddenInitializers = false;
if (this._showInitializers) {
// 是否显示初始化参数
for (const input of node.inputs) {
if (
input.visible &&
input.arguments.length == 1 &&
input.arguments[0].initializer != null
) {
initializers.push(input);
}
if (
(!input.visible || input.arguments.length > 1) &&
input.arguments.some(argument => argument.initializer != null)
) {
hiddenInitializers = true;
}
}
}
let sortedAttributes = [];
const attributes = node.attributes;
if (this.showAttributes && attributes) {
// 是否显示属性参数
sortedAttributes = attributes.filter(attribute => attribute.visible).slice();
sortedAttributes.sort((a, b) => {
const au = a.name.toUpperCase();
const bu = b.name.toUpperCase();
return au < bu ? -1 : au > bu ? 1 : 0;
});
}
if (initializers.length > 0 || hiddenInitializers || sortedAttributes.length > 0) {
const block = element.block('list');
block.handler = () => {
// 侧边栏点击事件
this.jumpRoute(node);
this.showNodeProperties(node);
this.select({
id: `node-${node.name}`,
name: node.name,
type: 'node'
});
const inputs = node.inputs;
for (const input of inputs) {
for (const argument of input.arguments) {
if (argument.name != '' && !argument.initializer) {
this.select2({
id: `edge-${argument.name}`,
name: argument.name,
type: 'input',
tonode: node.name
});
}
}
}
let outputs = node.outputs;
if (node.chain && node.chain.length > 0) {
const chainOutputs = node.chain[node.chain.length - 1].outputs;
if (chainOutputs.length > 0) {
outputs = chainOutputs;
}
}
for (const output of outputs) {
for (const argument of output.arguments) {
if (argument.name != '') {
this.select2({
id: `edge-${argument.name}`,
name: argument.name,
type: 'input',
fromnode: node.name
});
}
}
}
};
for (const initializer of initializers) {
const argument = initializer.arguments[0];
const type = argument.type;
let shape = '';
let separator = '';
if (
type &&
type.shape &&
type.shape.dimensions &&
Object.prototype.hasOwnProperty.call(type.shape.dimensions, 'length')
) {
shape =
'\u3008' +
type.shape.dimensions.map(d => (d ? d : '?')).join('\u00D7') +
'\u3009';
if (
type.shape.dimensions.length == 0 &&
argument.initializer &&
!argument.initializer.state
) {
shape = argument.initializer.toString();
if (shape && shape.length > 10) {
shape = shape.substring(0, 10) + '\u2026';
}
separator = ' = ';
}
}
block.add(
'initializer-' + argument.name,
initializer.name,
shape,
type ? type.toString() : '',
separator
);
}
if (hiddenInitializers) {
block.add(null, '\u3008' + '\u2026' + '\u3009', '', null, '');
}
for (const attribute of sortedAttributes) {
if (attribute.visible) {
let attributeValue = sidebar.NodeSidebar.formatAttributeValue(
attribute.value,
attribute.type
);
if (attributeValue && attributeValue.length > 25) {
attributeValue = attributeValue.substring(0, 25) + '\u2026';
}
block.add(null, attribute.name, attributeValue, attribute.type, ' = ');
}
}
}
}
if (edges) {
const inputs = node.inputs;
for (const input of inputs) {
for (const argument of input.arguments) {
if (argument.name != '' && !argument.initializer) {
let tuple = edgeMap[argument.name];
if (!tuple) {
tuple = {from: null, to: []};
edgeMap[argument.name] = tuple;
}
tuple.to.push({
// 这个节点的id
node: nodeId,
name: input.name,
nodename: node.name
});
}
}
}
let outputs = node.outputs;
if (node.chain && node.chain.length > 0) {
const chainOutputs = node.chain[node.chain.length - 1].outputs;
if (chainOutputs.length > 0) {
outputs = chainOutputs;
}
}
for (const output of outputs) {
for (const argument of output.arguments) {
if (argument.name != '') {
let tuple = edgeMap[argument.name];
if (!tuple) {
tuple = {from: null, to: []};
edgeMap[argument.name] = tuple;
}
tuple.from = {
node: nodeId,
name: output.name,
type: argument.type,
nodename: node.name
};
}
}
}
}
if (node.chain && node.chain.length > 0) {
for (const innerNode of node.chain) {
addNode(element, innerNode, false);
}
}
if (node.inner) {
addNode(element, node.inner, false);
}
};
addNode(element, node, true);
if (node.controlDependencies && node.controlDependencies.length > 0) {
for (const controlDependency of node.controlDependencies) {
let tuple = edgeMap[controlDependency];
if (!tuple) {
tuple = {from: null, to: []};
edgeMap[controlDependency] = tuple;
}
tuple.to.push({
node: nodeId,
name: controlDependency,
controlDependency: true,
nodename: node.name
});
}
}
const nodeName = node.name;
if (!document.getElementById(`node-${node.name}`)) {
// 此时图上没有
if (nodeName) {
g.setNode(nodeId, {label: element.format(graphElement), id: 'node-' + nodeName});
} else {
g.setNode(nodeId, {label: element.format(graphElement), id: 'node-' + id.toString()});
id++;
}
} else {
g.setNode(nodeId, {label: 'node-' + nodeName, id: 'node-' + nodeName});
}
const isKeepData = this._KeepData;
const createCluster = (name, node) => {
const non_leaf_nodes = graphMetadata.default.non_leaf_nodes;
const styles = ['clusterGroup'];
const showName = node.show_name.split('/')[node.show_name.split('/').length - 1];
if (this._nodeName[name]) {
for (const non_leaf_node of non_leaf_nodes) {
if (this._nodeName[name].type === non_leaf_node.name) {
styles.push(`clusterGroup-${non_leaf_node.schema.category.toLowerCase()}`);
break;
}
}
}
let newStyle = ['clusterGroup'];
if (styles.length > 1) {
newStyle = ['clusterGroup', styles[1]];
}
if (!clusterMap[name]) {
g.setNode(name, {
rx: 10,
ry: 10,
nodeId: name,
showName: showName,
expand: false,
classList: newStyle,
isKeepData: isKeepData
});
clusterMap[name] = true;
const parent = clusterParentMap[name]; // 父节点的父节点
if (parent) {
createCluster(parent, node);
g.setParent(name, parent);
}
}
};
if (groups) {
let path = node.name.split('/');
path.pop();
let groupName = path.join('/');
if (groupName && groupName.length > 0) {
if (!Object.prototype.hasOwnProperty.call(clusterParentMap, groupName)) {
const lastIndex = groupName.lastIndexOf('/');
if (lastIndex != -1) {
groupName = groupName.substring(0, lastIndex);
if (!Object.prototype.hasOwnProperty.call(clusterParentMap, groupName)) {
groupName = null;
}
} else {
groupName = null;
}
}
if (groupName) {
createCluster(groupName, node);
g.setParent(nodeId, groupName);
}
}
}
this._graphNodes[node.name] = element;
nodeId++;
}
for (const input of graph.inputs) {
for (const argument of input.arguments) {
let tuple = edgeMap[argument.name];
if (!tuple) {
tuple = {from: null, to: []};
edgeMap[argument.name] = tuple;
}
tuple.from = {
node: nodeId,
type: argument.type
};
}
const types = input.arguments.map(argument => argument.type || '').join('\n');
let inputName = input.name || '';
if (inputName.length > 16) {
inputName = inputName.split('/').pop();
}
const inputElement = new grapher.NodeElement(this._host.document);
const inputHeader = inputElement.block('header');
inputHeader.add(null, ['graph-item-input'], inputName, types, () => {
this.showModelProperties();
});
g.setNode(nodeId++, {label: inputElement.format(graphElement), class: 'graph-input'});
}
for (const output of graph.outputs) {
for (const argument of output.arguments) {
let tuple = edgeMap[argument.name];
if (!tuple) {
tuple = {from: null, to: []};
edgeMap[argument.name] = tuple;
}
tuple.to.push({node: nodeId});
}
const outputTypes = output.arguments.map(argument => argument.type || '').join('\n');
let outputName = output.name || '';
if (outputName.length > 16) {
outputName = outputName.split('/').pop();
}
const outputElement = new grapher.NodeElement(this._host.document);
const outputHeader = outputElement.block('header');
outputHeader.add(null, ['graph-item-output'], outputName, outputTypes, () => {
this.showModelProperties();
});
g.setNode(nodeId++, {label: outputElement.format(graphElement)});
}
for (const edge of Object.keys(edgeMap)) {
const tuple = edgeMap[edge];
if (tuple.from != null) {
for (const to of tuple.to) {
let text = '';
const type = tuple.from.type;
if (type && type.shape && type.shape.dimensions && type.shape.dimensions.length > 0) {
text = type.shape.dimensions.join('\u00D7');
}
if (this._showNames) {
text = edge.split('\n').shift(); // custom argument id
}
if (to.controlDependency) {
g.setEdge(tuple.from.node, to.node, {
label: text,
id: 'edge-' + edge,
arrowhead: 'vee',
class: 'edge-path-control-dependency',
fromnode: tuple.from.nodename,
tonode: to.nodename
});
} else {
g.setEdge(tuple.from.node, to.node, {
label: text,
id: 'edge-' + edge,
arrowhead: 'vee',
fromnode: tuple.from.nodename,
tonode: to.nodename
});
}
}
}
}
// Workaround for Safari background drag/zoom issue:
// https://stackoverflow.com/questions/40887193/d3-js-zoom-is-not-working-with-mousewheel-in-safari
// if (!this.secondChange) {
const backgroundElement = this._host.document.createElementNS('http://www.w3.org/2000/svg', 'rect');
backgroundElement.setAttribute('id', 'background');
backgroundElement.setAttribute('width', '100%');
backgroundElement.setAttribute('height', '100%');
backgroundElement.setAttribute('fill', 'none');
backgroundElement.setAttribute('pointer-events', 'all');
graphElement.appendChild(backgroundElement);
const originElement = this._host.document.createElementNS('http://www.w3.org/2000/svg', 'g');
originElement.setAttribute('id', 'origin');
graphElement.appendChild(originElement);
let svg = null;
svg = d3.select(graphElement);
backgroundElement.addEventListener('click', () => {
this.clearSelection();
});
this._zoom = d3.zoom();
this._zoom(svg);
this._zoom.scaleExtent([0.01, 2]); // 缩放的范围
this._zoom.on('zoom', () => {
originElement.setAttribute('transform', d3.event.transform.toString());
});
this._zoom.transform(svg, d3.zoomIdentity);
return this._timeout(200).then(() => {
const graphRenderer = new grapher.Renderer(this._host, originElement, this);
graphRenderer.render(g);
for (const cluster of document.getElementById('clusters').children) {
this._clusters[cluster.getAttribute('id')] = cluster;
}
for (const node of document.getElementById('nodes').children) {
this._nodes[node.getAttribute('id')] = node;
}
const inputElements = graphElement.getElementsByClassName('graph-input');
const svgSize = graphElement.getBoundingClientRect();
if (inputElements && inputElements.length > 0) {
// Center view based on input elements
if (this._selectItem) {
this.select(this._selectItem);
} else {
const xs = [];
const ys = [];
for (let i = 0; i < inputElements.length; i++) {
const inputTransform = inputElements[i].transform.baseVal.consolidate().matrix;
xs.push(inputTransform.e);
ys.push(inputTransform.f);
}
let x = xs[0];
const y = ys[0];
if (ys.every(y => y == ys[0])) {
x = xs.reduce((a, b) => a + b) / xs.length;
}
const sx = svgSize.width / (this._showHorizontal ? 4 : 2) - x;
const sy = svgSize.height / (this._showHorizontal ? 2 : 4) - y;
this._zoom.transform(svg, d3.zoomIdentity.translate(sx, sy));
}
// 这里应该触发一次小地图重定位
} else {
if (this._selectItem) {
this.select(this._selectItem);
} else {
this._zoom.transform(
svg,
d3.zoomIdentity.translate(
(svgSize.width - g.graph().width) / 2,
(svgSize.height - g.graph().height) / 2
)
);
}
}
return;
});
}
} catch (error) {
return Promise.reject(error);
}
}
applyStyleSheet(element, name) {
let rules = [];
for (let i = 0; i < this._host.document.styleSheets.length; i++) {
const styleSheet = this._host.document.styleSheets[i];
if (styleSheet && styleSheet.href && styleSheet.href.endsWith('/' + name)) {
rules = styleSheet.cssRules;
break;
}
}
const nodes = element.getElementsByTagName('*');
for (let j = 0; j < nodes.length; j++) {
const node = nodes[j];
for (let k = 0; k < rules.length; k++) {
const rule = rules[k];
if (node.matches(rule.selectorText)) {
for (let l = 0; l < rule.style.length; l++) {
const item = rule.style.item(l);
node.style[item] = rule.style[item];
}
}
}
}
}
export(file) {
const lastIndex = file.lastIndexOf('.');
const extension = lastIndex != -1 ? file.substring(lastIndex + 1) : '';
if (this._activeGraph && (extension == 'png' || extension == 'svg')) {
const graphElement = this._host.document.getElementById('canvas');
const exportElement = graphElement.cloneNode(true);
this.applyStyleSheet(exportElement, 'style.css');
exportElement.setAttribute('id', 'export');
exportElement.removeAttribute('width');
exportElement.removeAttribute('height');
exportElement.style.removeProperty('opacity');
exportElement.style.removeProperty('display');
const backgroundElement = exportElement.querySelector('#background');
const originElement = exportElement.querySelector('#origin');
originElement.setAttribute('transform', 'translate(0,0) scale(1)');
backgroundElement.removeAttribute('width');
backgroundElement.removeAttribute('height');
const parentElement = graphElement.parentElement;
parentElement.insertBefore(exportElement, graphElement);
const size = exportElement.getBBox();
parentElement.removeChild(exportElement);
parentElement.removeChild(graphElement);
parentElement.appendChild(graphElement);
const delta = (Math.min(size.width, size.height) / 2.0) * 0.1;
const width = Math.ceil(delta + size.width + delta);
const height = Math.ceil(delta + size.height + delta);
originElement.setAttribute(
'transform',
'translate(' + delta.toString() + ', ' + delta.toString() + ') scale(1)'
);
exportElement.setAttribute('width', width);
exportElement.setAttribute('height', height);
backgroundElement.setAttribute('width', width);
backgroundElement.setAttribute('height', height);
backgroundElement.setAttribute('fill', '#fff');
const data = new XMLSerializer().serializeToString(exportElement);
if (extension === 'svg') {
const blob = new Blob([data], {type: 'image/svg'});
this._host.export(file, blob);
} else if (extension === 'png') {
const imageElement = new Image();
imageElement.onload = () => {
const max = Math.max(width, height);
const scale = max * 2.0 > 24000 ? 24000.0 / max : 2.0;
const canvas = this._host.document.createElement('canvas');
canvas.width = Math.ceil(width * scale);
canvas.height = Math.ceil(height * scale);
const context = canvas.getContext('2d');
context.scale(scale, scale);
context.drawImage(imageElement, 0, 0);
this._host.document.body.removeChild(imageElement);
canvas.toBlob(blob => {
if (blob) {
this._host.export(file, blob);
} else {
const err = new Error();
err.name = 'Error exporting image.';
err.message = 'Image may be too large to render as PNG.';
this._host.exception(err, false);
this._host.error(err.name, err.message);
}
}, 'image/png');
};
imageElement.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(data)));
this._host.document.body.insertBefore(imageElement, this._host.document.body.firstChild);
}
}
}
showModelProperties() {
if (this._model) {
const modelSidebar = new sidebar.ModelSidebar(this._host, this._model, this._activeGraph);
this._host.message('show-model-properties', modelSidebar.render());
// 通信函数
}
}
showNodeProperties(node) {
if (node) {
const nodeSidebar = new sidebar.NodeSidebar(this._host, node);
// TODO: export
// nodeSidebar.on('export-tensor', (sender, tensor) => {
// this._host
// .require('./numpy')
// .then(numpy => {
// const defaultPath = tensor.name
// ? tensor.name.split('/').join('_').split(':').join('_').split('.').join('_')
// : 'tensor';
// this._host.save('NumPy Array', 'npy', defaultPath, file => {
// try {
// const dataTypeMap = new Map([
// ['float16', 'f2'],
// ['float32', 'f4'],
// ['float64', 'f8'],
// ['int8', 'i1'],
// ['int16', 'i2'],
// ['int32', 'i4'],
// ['int64', 'i8'],
// ['uint8', 'u1'],
// ['uint16', 'u2'],
// ['uint32', 'u4'],
// ['uint64', 'u8'],
// ['qint8', 'i1'],
// ['qint16', 'i2'],
// ['quint8', 'u1'],
// ['quint16', 'u2']
// ]);
// const array = new numpy.Array();
// array.shape = tensor.type.shape.dimensions;
// array.data = tensor.value;
// array.dataType = dataTypeMap.has(tensor.type.dataType)
// ? dataTypeMap.get(tensor.type.dataType)
// : tensor.type.dataType;
// const blob = new Blob([array.toBuffer()], {type: 'application/octet-stream'});
// this._host.export(file, blob);
// } catch (error) {
// this.error('Error saving NumPy tensor.', error);
// }
// });
// })
// .catch(() => {});
// });
this._host.message('show-node-properties', {...nodeSidebar.render(), metadata: node.metadata});
}
}
showNodeDocumentation(node) {
const metadata = node.metadata;
if (metadata) {
const documentationSidebar = new sidebar.DocumentationSidebar(this._host, metadata);
this._host.message('show-node-documentation', documentationSidebar.render());
}
}
};
class ModelError extends Error {
constructor(message, telemetry) {
super(message);
this.name = 'Error loading model.';
this.telemetry = telemetry;
}
}
class ModelContext {
constructor(context) {
this._context = context;
this._tags = new Map();
this._entries = new Map();
}
request(file, encoding) {
return this._context.request(file, encoding);
}
get identifier() {
return this._context.identifier;
}
get buffer() {
return this._context.buffer;
}
get text() {
if (!this._text) {
this._text = new TextDecoder('utf-8').decode(this.buffer);
}
return this._text;
}
entries(extension) {
let entries = this._entries.get(extension);
if (!entries) {
entries = [];
try {
const buffer = this.buffer;
switch (extension) {
case 'zip': {
if (buffer && buffer.length > 2 && buffer[0] == 0x50 && buffer[1] == 0x4b) {
entries = new zip.Archive(buffer).entries;
}
break;
}
case 'tar': {
if (buffer.length >= 512) {
let sum = 0;
for (let i = 0; i < 512; i++) {
sum += i >= 148 && i < 156 ? 32 : buffer[i];
}
let checksum = '';
for (let i = 148; i < 156 && buffer[i] !== 0x00; i++) {
checksum += String.fromCharCode(buffer[i]);
}
checksum = parseInt(checksum, 8);
if (!isNaN(checksum) && sum == checksum) {
entries = new tar.Archive(buffer).entries;
}
}
break;
}
}
} catch (error) {
entries = [];
}
this._entries.set(extension, entries);
}
return entries;
}
tags(extension) {
let tags = this._tags.get(extension);
if (!tags) {
tags = new Map();
try {
switch (extension) {
case 'pbtxt': {
const b = this.buffer;
const length = b.length;
const signature =
(length >= 3 && b[0] === 0xef && b[1] === 0xbb && b[2] === 0xbf) ||
(length >= 4 && b[0] === 0x00 && b[1] === 0x00 && b[2] === 0xfe && b[3] === 0xff) ||
(length >= 4 && b[0] === 0xff && b[1] === 0xfe && b[2] === 0x00 && b[3] === 0x00) ||
(length >= 4 && b[0] === 0x84 && b[1] === 0x31 && b[2] === 0x95 && b[3] === 0x33) ||
(length >= 2 && b[0] === 0xfe && b[1] === 0xff) ||
(length >= 2 && b[0] === 0xff && b[1] === 0xfe);
if (
!signature &&
b.subarray(0, Math.min(1024, length)).some(c => c < 7 || (c > 14 && c < 32))
) {
break;
}
const reader = protobuf.TextReader.create(this.text);
reader.start(false);
while (!reader.end(false)) {
const tag = reader.tag();
tags.set(tag, true);
reader.skip();
}
break;
}
case 'pb': {
const tagTypes = new Set([0, 1, 2, 3, 5]);
const reader = protobuf.Reader.create(this.buffer);
const end = reader.next();
while (reader.pos < end) {
const tagType = reader.uint32();
tags.set(tagType >>> 3, tagType & 7);
if (!tagTypes.has(tagType & 7)) {
tags = new Map();
break;
}
try {
reader.skipType(tagType & 7);
} catch (err) {
tags = new Map();
break;
}
}
break;
}
}
} catch (error) {
tags = new Map();
}
this._tags.set(extension, tags);
}
return tags;
}
}
class ArchiveContext {
constructor(entries, rootFolder, identifier, buffer) {
this._entries = {};
if (entries) {
for (const entry of entries) {
if (entry.name.startsWith(rootFolder)) {
const name = entry.name.substring(rootFolder.length);
if (identifier.length > 0 && identifier.indexOf('/') < 0) {
this._entries[name] = entry;
}
}
}
}
this._identifier = identifier.substring(rootFolder.length);
this._buffer = buffer;
}
request(file, encoding) {
const entry = this._entries[file];
if (!entry) {
return Promise.reject(new Error('File not found.'));
}
const data = encoding ? new TextDecoder(encoding).decode(entry.data) : entry.data;
return Promise.resolve(data);
}
get identifier() {
return this._identifier;
}
get buffer() {
return this._buffer;
}
}
class ArchiveError extends Error {
constructor(message) {
super(message);
this.name = 'Error loading archive.';
}
}
view.ModelFactoryService = class {
constructor(host) {
this._host = host;
this._extensions = [];
this.register('./onnx', ['.onnx', '.pb', '.pbtxt', '.prototxt']);
this.register('./mxnet', ['.mar', '.model', '.json', '.params']);
this.register('./keras', ['.h5', '.hd5', '.hdf5', '.keras', '.json', '.model', '.pb', '.pth']);
this.register('./coreml', ['.mlmodel']);
this.register('./caffe', ['.caffemodel', '.pbtxt', '.prototxt', '.pt']);
this.register('./caffe2', ['.pb', '.pbtxt', '.prototxt']);
this.register('./pytorch', [
'.pt',
'.pth',
'.pt1',
'.pkl',
'.h5',
'.t7',
'.model',
'.dms',
'.tar',
'.ckpt',
'.bin',
'.pb',
'.zip'
]);
this.register('./torch', ['.t7']);
this.register('./tflite', ['.tflite', '.lite', '.tfl', '.bin', '.pb', '.tmfile', '.h5', '.model', '.json']);
this.register('./tf', ['.pb', '.meta', '.pbtxt', '.prototxt', '.json', '.index', '.ckpt']);
this.register('./mediapipe', ['.pbtxt']);
this.register('./uff', ['.uff', '.pb', '.trt', '.pbtxt', '.uff.txt']);
this.register('./sklearn', ['.pkl', '.pickle', '.joblib', '.model', '.meta', '.pb', '.pt', '.h5']);
this.register('./cntk', ['.model', '.cntk', '.cmf', '.dnn']);
this.register('./paddle', ['.paddle', '.pdmodel', '__model__']);
this.register('./armnn', ['.armnn']);
this.register('./bigdl', ['.model', '.bigdl']);
this.register('./darknet', ['.cfg', '.model']);
this.register('./mnn', ['.mnn']);
this.register('./ncnn', ['.param', '.bin', '.cfg.ncnn', '.weights.ncnn']);
this.register('./tnn', ['.tnnproto', '.tnnmodel']);
this.register('./tengine', ['.tmfile']);
this.register('./barracuda', ['.nn']);
this.register('./openvino', ['.xml', '.bin']);
this.register('./flux', ['.bson']);
this.register('./npz', ['.npz', '.h5', '.hd5', '.hdf5']);
this.register('./dl4j', ['.zip']);
this.register('./mlnet', ['.zip']);
}
register(id, extensions) {
for (const extension of extensions) {
this._extensions.push({extension: extension, id: id});
}
}
open(context) {
return this._openSignature(context).then(context => {
return this._openArchive(context).then(context => {
context = new ModelContext(context);
const identifier = context.identifier;
const extension = identifier.split('.').pop().toLowerCase();
const modules = this._filter(context);
if (modules.length == 0) {
throw new ModelError("Unsupported file extension '." + extension + "'.");
}
const errors = [];
let match = false;
const nextModule = () => {
if (modules.length > 0) {
const id = modules.shift();
return this._host.require(id).then(module => {
if (!module.ModelFactory) {
throw new ModelError("Failed to load module '" + id + "'.");
}
const modelFactory = new module.ModelFactory();
if (!modelFactory.match(context)) {
return nextModule();
}
match++;
return modelFactory
.open(context, this._host)
.then(model => {
return model;
})
.catch(error => {
errors.push(error);
return nextModule();
});
});
} else {
if (match) {
if (errors.length == 1) {
throw errors[0];
}
throw new ModelError(errors.map(err => err.message).join('\n'));
}
const knownUnsupportedIdentifiers = new Set([
'natives_blob.bin',
'v8_context_snapshot.bin',
'snapshot_blob.bin',
'image_net_labels.json',
'package.json',
'models.json',
'LICENSE.meta',
'input_0.pb',
'output_0.pb'
]);
const skip = knownUnsupportedIdentifiers.has(identifier);
const buffer = context.buffer;
const content = Array.from(buffer.subarray(0, Math.min(16, buffer.length)))
.map(c => (c < 16 ? '0' : '') + c.toString(16))
.join('');
throw new ModelError(
'Unsupported file content (' +
content +
") for extension '." +
extension +
"' in '" +
identifier +
"'.",
!skip
);
}
};
return nextModule();
});
});
}
_openArchive(context) {
let archive = null;
let extension;
let identifier = context.identifier;
let buffer = context.buffer;
try {
extension = identifier.split('.').pop().toLowerCase();
if (extension == 'gz' || extension == 'tgz') {
archive = new gzip.Archive(buffer);
if (archive.entries.length == 1) {
const entry = archive.entries[0];
if (entry.name) {
identifier = entry.name;
} else {
identifier = identifier.substring(0, identifier.lastIndexOf('.'));
if (extension == 'tgz') {
identifier += '.tar';
}
}
buffer = entry.data;
}
}
} catch (error) {
const message = error && error.message ? error.message : error.toString();
return Promise.reject(new ArchiveError(message.replace(/\.$/, '') + " in '" + identifier + "'."));
}
try {
extension = identifier.split('.').pop().toLowerCase();
switch (extension) {
case 'tar': {
// handle .pth.tar
const torch = [0x8a, 0x0a, 0x6c, 0xfc, 0x9c, 0x46, 0xf9, 0x20, 0x6a, 0xa8, 0x50, 0x19];
if (
!buffer ||
buffer.length < 14 ||
buffer[0] != 0x80 ||
!torch.every((v, i) => v == buffer[i + 2])
) {
archive = new tar.Archive(buffer);
}
break;
}
case 'zip': {
archive = new zip.Archive(buffer);
// PyTorch Zip archive
if (
archive.entries.some(e => e.name.split('/').pop().split('\\').pop() === 'version') &&
archive.entries.some(e => e.name.split('/').pop().split('\\').pop() === 'data.pkl')
) {
return Promise.resolve(context);
}
// dl4j
if (
archive.entries.some(e => e.name.split('/').pop().split('\\').pop() === 'coefficients.bin') &&
archive.entries.some(e => e.name.split('/').pop().split('\\').pop() === 'configuration.json')
) {
return Promise.resolve(context);
}
break;
}
}
} catch (error) {
const message = error && error.message ? error.message : error.toString();
return Promise.reject(new ArchiveError(message.replace(/\.$/, '') + " in '" + identifier + "'."));
}
if (!archive) {
return Promise.resolve(context);
}
try {
const folders = {};
for (const entry of archive.entries) {
if (entry.name.indexOf('/') != -1) {
folders[entry.name.split('/').shift() + '/'] = true;
} else {
folders['/'] = true;
}
}
if (extension == 'tar') {
delete folders['PaxHeader/'];
}
let rootFolder = Object.keys(folders).length == 1 ? Object.keys(folders)[0] : '';
rootFolder = rootFolder == '/' ? '' : rootFolder;
let matches = [];
const entries = archive.entries.slice();
const nextEntry = () => {
if (entries.length > 0) {
const entry = entries.shift();
if (entry.name.startsWith(rootFolder)) {
const identifier = entry.name.substring(rootFolder.length);
if (identifier.length > 0 && identifier.indexOf('/') < 0 && !identifier.startsWith('.')) {
const context = new ModelContext(
new ArchiveContext(null, rootFolder, entry.name, entry.data)
);
let modules = this._filter(context);
const nextModule = () => {
if (modules.length > 0) {
const id = modules.shift();
return this._host.require(id).then(module => {
if (!module.ModelFactory) {
throw new ArchiveError("Failed to load module '" + id + "'.", null);
}
const factory = new module.ModelFactory();
if (factory.match(context)) {
matches.push(entry);
modules = [];
}
return nextModule();
});
} else {
return nextEntry();
}
};
return nextModule();
}
}
return nextEntry();
} else {
if (matches.length == 0) {
return Promise.resolve(context);
}
// MXNet
if (
matches.length == 2 &&
matches.some(e => e.name.endsWith('.params')) &&
matches.some(e => e.name.endsWith('-symbol.json'))
) {
matches = matches.filter(e => e.name.endsWith('.params'));
}
if (matches.length > 1) {
return Promise.reject(new ArchiveError('Archive contains multiple model files.'));
}
const match = matches[0];
return Promise.resolve(
new ModelContext(new ArchiveContext(archive.entries, rootFolder, match.name, match.data))
);
}
};
return nextEntry();
} catch (error) {
return Promise.reject(new ArchiveError(error.message));
}
}
accept(identifier) {
identifier = identifier.toLowerCase();
for (const extension of this._extensions) {
if (identifier.endsWith(extension.extension)) {
return true;
}
}
if (
identifier.endsWith('.zip') ||
identifier.endsWith('.tar') ||
identifier.endsWith('.tar.gz') ||
identifier.endsWith('.tgz')
) {
return true;
}
return false;
}
_filter(context) {
const identifier = context.identifier.toLowerCase();
const list = this._extensions.filter(entry => identifier.endsWith(entry.extension)).map(entry => entry.id);
return Array.from(new Set(list));
}
_openSignature(context) {
const buffer = context.buffer;
if (context.buffer.length === 0) {
return Promise.reject(new ModelError('File has no content.', true));
}
const list = [
// cSpell:disable
{name: 'ELF executable', value: /^\x7FELF/},
{name: 'Git LFS header', value: /^version https:\/\/git-lfs.github.com\/spec\/v1\n/},
{name: 'Git LFS header', value: /^oid sha256:/},
{name: 'HTML markup', value: /^\s*<html>/},
{name: 'HTML markup', value: /^\s*<!DOCTYPE html>/},
{name: 'HTML markup', value: /^\s*<!DOCTYPE HTML>/},
{name: 'Unity metadata', value: /^fileFormatVersion:/},
{name: 'Vulkan SwiftShader ICD manifest', value: /^{\s*"file_format_version":\s*"1.0.0"\s*,\s*"ICD":/},
{name: 'StringIntLabelMapProto data', value: /^item\s*{\r?\n\s*id:/},
{name: 'StringIntLabelMapProto data', value: /^item\s*{\r?\n\s*name:/},
{name: 'Python source code', value: /^\s*import sys, types, os;/}
// cSpell:enable
];
const text = new TextDecoder().decode(buffer.subarray(0, Math.min(1024, buffer.length)));
for (const item of list) {
if (text.match(item.value)) {
return Promise.reject(new ModelError('Invalid file content. File contains ' + item.name + '.', true));
}
}
return Promise.resolve(context);
}
};
if (typeof module !== 'undefined' && typeof module.exports === 'object') {
module.exports.View = view.View;
module.exports.ModelFactoryService = view.ModelFactoryService;
}
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// cSpell:words grapher selectall nodesep ranksep rankdir pbtxt
const zip = require('netron/src/zip');
const gzip = require('netron/src/gzip');
const tar = require('netron/src/tar');
const protobuf = require('netron/src/protobuf');
const d3 = require('d3');
const dagre = require('dagre');
const grapher = require('netron/src/view-grapher');
const sidebar = require('./sidebar');
const view = {};
view.View = class {
constructor(host) {
this._host = host;
this._host
.initialize(this)
.then(() => {
this._model = null;
this._selection = [];
this._host.start();
this._showAttributes = false;
this._showInitializers = true;
this._showNames = false;
this._showHorizontal = false;
this._modelFactoryService = new view.ModelFactoryService(this._host);
})
.catch(err => {
this.error(err.message, err);
});
}
cut() {
this._host.document.execCommand('cut');
}
copy() {
this._host.document.execCommand('copy');
}
paste() {
this._host.document.execCommand('paste');
}
selectAll() {
this._host.document.execCommand('selectall');
}
find(value) {
if (this._activeGraph) {
this.clearSelection();
const graphElement = document.getElementById('canvas');
const view = new sidebar.FindSidebar(this._host, graphElement, this._activeGraph);
this._host.message('search', view.update(value));
}
}
toggleAttributes(toggle) {
if (toggle != null && !(toggle ^ this._showAttributes)) {
return;
}
this._showAttributes = toggle == null ? !this._showAttributes : toggle;
this._reload();
}
get showAttributes() {
return this._showAttributes;
}
toggleInitializers(toggle) {
if (toggle != null && !(toggle ^ this._showInitializers)) {
return;
}
this._showInitializers = toggle == null ? !this._showInitializers : toggle;
this._reload();
}
get showInitializers() {
return this._showInitializers;
}
toggleNames(toggle) {
if (toggle != null && !(toggle ^ this._showNames)) {
return;
}
this._showNames = toggle == null ? !this._showNames : toggle;
this._reload();
}
get showNames() {
return this._showNames;
}
toggleDirection(toggle) {
if (toggle != null && !(toggle ^ this._showHorizontal)) {
return;
}
this._showHorizontal = toggle == null ? !this._showHorizontal : toggle;
this._reload();
}
get showHorizontal() {
return this._showHorizontal;
}
toggleTheme(theme) {
this._host.document.body.className = theme;
}
_reload() {
this._host.status('loading');
if (this._model && this._activeGraph) {
this._updateGraph(this._model, this._activeGraph).catch(error => {
if (error) {
this.error('Graph update failed.', error);
}
});
}
}
_timeout(time) {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, time);
});
}
zoomIn() {
if (this._zoom) {
this._zoom.scaleBy(d3.select(this._host.document.getElementById('canvas')), 1.2);
}
}
zoomOut() {
if (this._zoom) {
this._zoom.scaleBy(d3.select(this._host.document.getElementById('canvas')), 0.8);
}
}
resetZoom() {
if (this._zoom) {
this._zoom.scaleTo(d3.select(this._host.document.getElementById('canvas')), 1);
}
}
select(item) {
this.clearSelection();
const graphElement = document.getElementById('canvas');
const selection = sidebar.FindSidebar.selection(item, graphElement);
if (selection && selection.length > 0) {
const graphElement = this._host.document.getElementById('canvas');
const graphRect = graphElement.getBoundingClientRect();
let x = 0;
let y = 0;
for (const element of selection) {
element.classList.add('select');
this._selection.push(element);
const transform = element.transform.baseVal.consolidate();
const box = element.getBBox();
const ex = transform ? transform.matrix.e : box.x + box.width / 2;
const ey = transform ? transform.matrix.f : box.y + box.height / 2;
x += ex;
y += ey;
}
x = x / selection.length;
y = y / selection.length;
this._zoom.transform(
d3.select(graphElement),
d3.zoomIdentity.translate(graphRect.width / 2 - x, graphRect.height / 2 - y)
);
}
}
clearSelection() {
while (this._selection.length > 0) {
const element = this._selection.pop();
element.classList.remove('select');
}
}
error(message, err) {
this._host.error(message, err.toString());
}
accept(file) {
return this._modelFactoryService.accept(file);
}
open(context) {
return this._timeout(2).then(() => {
return this._modelFactoryService.open(context).then(model => {
return this._timeout(20).then(() => {
const graph = model.graphs.length > 0 ? model.graphs[0] : null;
this._host.message('opened', {
graphs: model.graphs.map(g => g.name || ''),
selected: graph && (graph.name || '')
});
return this._updateGraph(model, graph);
});
});
});
}
changeGraph(name) {
this._updateActiveGraph(name);
}
_updateActiveGraph(name) {
if (this._model) {
const model = this._model;
const graph = model.graphs.filter(graph => name == graph.name).shift();
if (graph) {
this._host.status('loading');
this._timeout(200).then(() => {
return this._updateGraph(model, graph).catch(error => {
if (error) {
this.error('Graph update failed.', error);
}
});
});
}
}
}
_updateGraph(model, graph) {
return this._timeout(100).then(() => {
if (graph && graph != this._activeGraph) {
const nodes = graph.nodes;
if (nodes.length > 1400) {
if (
!this._host.confirm(
'Large model detected.',
'This graph contains a large number of nodes and might take a long time to render. Do you want to continue?'
)
) {
return null;
}
}
}
return this.renderGraph(model, graph)
.then(() => {
this._model = model;
this._activeGraph = graph;
this._host.status('rendered');
return this._model;
})
.catch(error => {
return this.renderGraph(this._model, this._activeGraph)
.then(() => {
this._host.status('rendered');
throw error;
})
.catch(() => {
throw error;
});
});
});
}
renderGraph(model, graph) {
try {
const graphElement = this._host.document.getElementById('canvas');
while (graphElement.lastChild) {
graphElement.removeChild(graphElement.lastChild);
}
if (!graph) {
return Promise.resolve();
} else {
this._zoom = null;
graphElement.style.position = 'absolute';
graphElement.style.margin = '0';
const groups = graph.groups;
const graphOptions = {};
graphOptions.nodesep = 25;
graphOptions.ranksep = 20;
if (this._showHorizontal) {
graphOptions.rankdir = 'LR';
}
const g = new dagre.graphlib.Graph({compound: groups});
g.setGraph(graphOptions);
g.setDefaultEdgeLabel(() => {
return {};
});
let nodeId = 0;
const edgeMap = {};
const clusterMap = {};
const clusterParentMap = {};
let id = new Date().getTime();
const nodes = graph.nodes;
if (nodes.length > 1500) {
graphOptions.ranker = 'longest-path';
}
if (groups) {
for (const node of nodes) {
if (node.group) {
const path = node.group.split('/');
while (path.length > 0) {
const name = path.join('/');
path.pop();
clusterParentMap[name] = path.join('/');
}
}
}
}
for (const node of nodes) {
const element = new grapher.NodeElement(this._host.document);
const addNode = (element, node, edges) => {
const header = element.block('header');
const styles = ['node-item-type'];
const metadata = node.metadata;
const category = metadata && metadata.category ? metadata.category : '';
if (category) {
styles.push('node-item-type-' + category.toLowerCase());
}
const type = node.type;
if (typeof type !== 'string' || !type.split) {
// #416
throw new ModelError(
"Unknown node type '" + JSON.stringify(type) + "' in '" + model.format + "'."
);
}
const content = this.showNames && node.name ? node.name : type.split('.').pop();
const tooltip = this.showNames && node.name ? type : node.name;
header.add(null, styles, content, tooltip, () => {
this.showNodeProperties(node);
});
if (node.function) {
header.add(null, ['node-item-function'], '+', null, () => {
// debugger;
});
}
const initializers = [];
let hiddenInitializers = false;
if (this._showInitializers) {
for (const input of node.inputs) {
if (
input.visible &&
input.arguments.length == 1 &&
input.arguments[0].initializer != null
) {
initializers.push(input);
}
if (
(!input.visible || input.arguments.length > 1) &&
input.arguments.some(argument => argument.initializer != null)
) {
hiddenInitializers = true;
}
}
}
let sortedAttributes = [];
const attributes = node.attributes;
if (this.showAttributes && attributes) {
sortedAttributes = attributes.filter(attribute => attribute.visible).slice();
sortedAttributes.sort((a, b) => {
const au = a.name.toUpperCase();
const bu = b.name.toUpperCase();
return au < bu ? -1 : au > bu ? 1 : 0;
});
}
if (initializers.length > 0 || hiddenInitializers || sortedAttributes.length > 0) {
const block = element.block('list');
block.handler = () => {
this.showNodeProperties(node);
};
for (const initializer of initializers) {
const argument = initializer.arguments[0];
const type = argument.type;
let shape = '';
let separator = '';
if (
type &&
type.shape &&
type.shape.dimensions &&
Object.prototype.hasOwnProperty.call(type.shape.dimensions, 'length')
) {
shape =
'\u3008' +
type.shape.dimensions.map(d => (d ? d : '?')).join('\u00D7') +
'\u3009';
if (
type.shape.dimensions.length == 0 &&
argument.initializer &&
!argument.initializer.state
) {
shape = argument.initializer.toString();
if (shape && shape.length > 10) {
shape = shape.substring(0, 10) + '\u2026';
}
separator = ' = ';
}
}
block.add(
'initializer-' + argument.name,
initializer.name,
shape,
type ? type.toString() : '',
separator
);
}
if (hiddenInitializers) {
block.add(null, '\u3008' + '\u2026' + '\u3009', '', null, '');
}
for (const attribute of sortedAttributes) {
if (attribute.visible) {
let attributeValue = sidebar.NodeSidebar.formatAttributeValue(
attribute.value,
attribute.type
);
if (attributeValue && attributeValue.length > 25) {
attributeValue = attributeValue.substring(0, 25) + '\u2026';
}
block.add(null, attribute.name, attributeValue, attribute.type, ' = ');
}
}
}
if (edges) {
const inputs = node.inputs;
for (const input of inputs) {
for (const argument of input.arguments) {
if (argument.name != '' && !argument.initializer) {
let tuple = edgeMap[argument.name];
if (!tuple) {
tuple = {from: null, to: []};
edgeMap[argument.name] = tuple;
}
tuple.to.push({
node: nodeId,
name: input.name
});
}
}
}
let outputs = node.outputs;
if (node.chain && node.chain.length > 0) {
const chainOutputs = node.chain[node.chain.length - 1].outputs;
if (chainOutputs.length > 0) {
outputs = chainOutputs;
}
}
for (const output of outputs) {
for (const argument of output.arguments) {
if (argument.name != '') {
let tuple = edgeMap[argument.name];
if (!tuple) {
tuple = {from: null, to: []};
edgeMap[argument.name] = tuple;
}
tuple.from = {
node: nodeId,
name: output.name,
type: argument.type
};
}
}
}
}
if (node.chain && node.chain.length > 0) {
for (const innerNode of node.chain) {
addNode(element, innerNode, false);
}
}
if (node.inner) {
addNode(element, node.inner, false);
}
};
addNode(element, node, true);
if (node.controlDependencies && node.controlDependencies.length > 0) {
for (const controlDependency of node.controlDependencies) {
let tuple = edgeMap[controlDependency];
if (!tuple) {
tuple = {from: null, to: []};
edgeMap[controlDependency] = tuple;
}
tuple.to.push({
node: nodeId,
name: controlDependency,
controlDependency: true
});
}
}
const nodeName = node.name;
if (nodeName) {
g.setNode(nodeId, {label: element.format(graphElement), id: 'node-' + nodeName});
} else {
g.setNode(nodeId, {label: element.format(graphElement), id: 'node-' + id.toString()});
id++;
}
const createCluster = function (name) {
if (!clusterMap[name]) {
g.setNode(name, {rx: 5, ry: 5});
clusterMap[name] = true;
const parent = clusterParentMap[name];
if (parent) {
createCluster(parent);
g.setParent(name, parent);
}
}
};
if (groups) {
let groupName = node.group;
if (groupName && groupName.length > 0) {
if (!Object.prototype.hasOwnProperty.call(clusterParentMap, groupName)) {
const lastIndex = groupName.lastIndexOf('/');
if (lastIndex != -1) {
groupName = groupName.substring(0, lastIndex);
if (!Object.prototype.hasOwnProperty.call(clusterParentMap, groupName)) {
groupName = null;
}
} else {
groupName = null;
}
}
if (groupName) {
createCluster(groupName);
g.setParent(nodeId, groupName);
}
}
}
nodeId++;
}
for (const input of graph.inputs) {
for (const argument of input.arguments) {
let tuple = edgeMap[argument.name];
if (!tuple) {
tuple = {from: null, to: []};
edgeMap[argument.name] = tuple;
}
tuple.from = {
node: nodeId,
type: argument.type
};
}
const types = input.arguments.map(argument => argument.type || '').join('\n');
let inputName = input.name || '';
if (inputName.length > 16) {
inputName = inputName.split('/').pop();
}
const inputElement = new grapher.NodeElement(this._host.document);
const inputHeader = inputElement.block('header');
inputHeader.add(null, ['graph-item-input'], inputName, types, () => {
this.showModelProperties();
});
g.setNode(nodeId++, {label: inputElement.format(graphElement), class: 'graph-input'});
}
for (const output of graph.outputs) {
for (const argument of output.arguments) {
let tuple = edgeMap[argument.name];
if (!tuple) {
tuple = {from: null, to: []};
edgeMap[argument.name] = tuple;
}
tuple.to.push({node: nodeId});
}
const outputTypes = output.arguments.map(argument => argument.type || '').join('\n');
let outputName = output.name || '';
if (outputName.length > 16) {
outputName = outputName.split('/').pop();
}
const outputElement = new grapher.NodeElement(this._host.document);
const outputHeader = outputElement.block('header');
outputHeader.add(null, ['graph-item-output'], outputName, outputTypes, () => {
this.showModelProperties();
});
g.setNode(nodeId++, {label: outputElement.format(graphElement)});
}
for (const edge of Object.keys(edgeMap)) {
const tuple = edgeMap[edge];
if (tuple.from != null) {
for (const to of tuple.to) {
let text = '';
const type = tuple.from.type;
if (type && type.shape && type.shape.dimensions && type.shape.dimensions.length > 0) {
text = type.shape.dimensions.join('\u00D7');
}
if (this._showNames) {
text = edge.split('\n').shift(); // custom argument id
}
if (to.controlDependency) {
g.setEdge(tuple.from.node, to.node, {
label: text,
id: 'edge-' + edge,
arrowhead: 'vee',
class: 'edge-path-control-dependency'
});
} else {
g.setEdge(tuple.from.node, to.node, {
label: text,
id: 'edge-' + edge,
arrowhead: 'vee'
});
}
}
}
}
// Workaround for Safari background drag/zoom issue:
// https://stackoverflow.com/questions/40887193/d3-js-zoom-is-not-working-with-mousewheel-in-safari
const backgroundElement = this._host.document.createElementNS('http://www.w3.org/2000/svg', 'rect');
backgroundElement.setAttribute('id', 'background');
backgroundElement.setAttribute('width', '100%');
backgroundElement.setAttribute('height', '100%');
backgroundElement.setAttribute('fill', 'none');
backgroundElement.setAttribute('pointer-events', 'all');
graphElement.appendChild(backgroundElement);
const originElement = this._host.document.createElementNS('http://www.w3.org/2000/svg', 'g');
originElement.setAttribute('id', 'origin');
graphElement.appendChild(originElement);
let svg = null;
svg = d3.select(graphElement);
this._zoom = d3.zoom();
this._zoom(svg);
this._zoom.scaleExtent([0.1, 2]);
this._zoom.on('zoom', () => {
originElement.setAttribute('transform', d3.event.transform.toString());
});
this._zoom.transform(svg, d3.zoomIdentity);
return this._timeout(20).then(() => {
const graphRenderer = new grapher.Renderer(this._host.document, originElement);
graphRenderer.render(g);
const inputElements = graphElement.getElementsByClassName('graph-input');
const svgSize = graphElement.getBoundingClientRect();
if (inputElements && inputElements.length > 0) {
// Center view based on input elements
const xs = [];
const ys = [];
for (let i = 0; i < inputElements.length; i++) {
const inputTransform = inputElements[i].transform.baseVal.consolidate().matrix;
xs.push(inputTransform.e);
ys.push(inputTransform.f);
}
let x = xs[0];
const y = ys[0];
if (ys.every(y => y == ys[0])) {
x = xs.reduce((a, b) => a + b) / xs.length;
}
const sx = svgSize.width / (this._showHorizontal ? 4 : 2) - x;
const sy = svgSize.height / (this._showHorizontal ? 2 : 4) - y;
this._zoom.transform(svg, d3.zoomIdentity.translate(sx, sy));
} else {
this._zoom.transform(
svg,
d3.zoomIdentity.translate(
(svgSize.width - g.graph().width) / 2,
(svgSize.height - g.graph().height) / 2
)
);
}
return;
});
}
} catch (error) {
return Promise.reject(error);
}
}
applyStyleSheet(element, name) {
let rules = [];
for (let i = 0; i < this._host.document.styleSheets.length; i++) {
const styleSheet = this._host.document.styleSheets[i];
if (styleSheet && styleSheet.href && styleSheet.href.endsWith('/' + name)) {
rules = styleSheet.cssRules;
break;
}
}
const nodes = element.getElementsByTagName('*');
for (let j = 0; j < nodes.length; j++) {
const node = nodes[j];
for (let k = 0; k < rules.length; k++) {
const rule = rules[k];
if (node.matches(rule.selectorText)) {
for (let l = 0; l < rule.style.length; l++) {
const item = rule.style.item(l);
node.style[item] = rule.style[item];
}
}
}
}
}
export(file) {
const lastIndex = file.lastIndexOf('.');
const extension = lastIndex != -1 ? file.substring(lastIndex + 1) : '';
if (this._activeGraph && (extension == 'png' || extension == 'svg')) {
const graphElement = this._host.document.getElementById('canvas');
const exportElement = graphElement.cloneNode(true);
this.applyStyleSheet(exportElement, 'style.css');
exportElement.setAttribute('id', 'export');
exportElement.removeAttribute('width');
exportElement.removeAttribute('height');
exportElement.style.removeProperty('opacity');
exportElement.style.removeProperty('display');
const backgroundElement = exportElement.querySelector('#background');
const originElement = exportElement.querySelector('#origin');
originElement.setAttribute('transform', 'translate(0,0) scale(1)');
backgroundElement.removeAttribute('width');
backgroundElement.removeAttribute('height');
const parentElement = graphElement.parentElement;
parentElement.insertBefore(exportElement, graphElement);
const size = exportElement.getBBox();
parentElement.removeChild(exportElement);
parentElement.removeChild(graphElement);
parentElement.appendChild(graphElement);
const delta = (Math.min(size.width, size.height) / 2.0) * 0.1;
const width = Math.ceil(delta + size.width + delta);
const height = Math.ceil(delta + size.height + delta);
originElement.setAttribute(
'transform',
'translate(' + delta.toString() + ', ' + delta.toString() + ') scale(1)'
);
exportElement.setAttribute('width', width);
exportElement.setAttribute('height', height);
backgroundElement.setAttribute('width', width);
backgroundElement.setAttribute('height', height);
backgroundElement.setAttribute('fill', '#fff');
const data = new XMLSerializer().serializeToString(exportElement);
if (extension === 'svg') {
const blob = new Blob([data], {type: 'image/svg'});
this._host.export(file, blob);
} else if (extension === 'png') {
const imageElement = new Image();
imageElement.onload = () => {
const max = Math.max(width, height);
const scale = max * 2.0 > 24000 ? 24000.0 / max : 2.0;
const canvas = this._host.document.createElement('canvas');
canvas.width = Math.ceil(width * scale);
canvas.height = Math.ceil(height * scale);
const context = canvas.getContext('2d');
context.scale(scale, scale);
context.drawImage(imageElement, 0, 0);
this._host.document.body.removeChild(imageElement);
canvas.toBlob(blob => {
if (blob) {
this._host.export(file, blob);
} else {
const err = new Error();
err.name = 'Error exporting image.';
err.message = 'Image may be too large to render as PNG.';
this._host.exception(err, false);
this._host.error(err.name, err.message);
}
}, 'image/png');
};
imageElement.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(data)));
this._host.document.body.insertBefore(imageElement, this._host.document.body.firstChild);
}
}
}
showModelProperties() {
if (this._model) {
const modelSidebar = new sidebar.ModelSidebar(this._host, this._model, this._activeGraph);
this._host.message('show-model-properties', modelSidebar.render());
}
}
showNodeProperties(node) {
if (node) {
const nodeSidebar = new sidebar.NodeSidebar(this._host, node);
// TODO: export
// nodeSidebar.on('export-tensor', (sender, tensor) => {
// this._host
// .require('./numpy')
// .then(numpy => {
// const defaultPath = tensor.name
// ? tensor.name.split('/').join('_').split(':').join('_').split('.').join('_')
// : 'tensor';
// this._host.save('NumPy Array', 'npy', defaultPath, file => {
// try {
// const dataTypeMap = new Map([
// ['float16', 'f2'],
// ['float32', 'f4'],
// ['float64', 'f8'],
// ['int8', 'i1'],
// ['int16', 'i2'],
// ['int32', 'i4'],
// ['int64', 'i8'],
// ['uint8', 'u1'],
// ['uint16', 'u2'],
// ['uint32', 'u4'],
// ['uint64', 'u8'],
// ['qint8', 'i1'],
// ['qint16', 'i2'],
// ['quint8', 'u1'],
// ['quint16', 'u2']
// ]);
// const array = new numpy.Array();
// array.shape = tensor.type.shape.dimensions;
// array.data = tensor.value;
// array.dataType = dataTypeMap.has(tensor.type.dataType)
// ? dataTypeMap.get(tensor.type.dataType)
// : tensor.type.dataType;
// const blob = new Blob([array.toBuffer()], {type: 'application/octet-stream'});
// this._host.export(file, blob);
// } catch (error) {
// this.error('Error saving NumPy tensor.', error);
// }
// });
// })
// .catch(() => {});
// });
this._host.message('show-node-properties', {...nodeSidebar.render(), metadata: node.metadata});
}
}
showNodeDocumentation(node) {
const metadata = node.metadata;
if (metadata) {
const documentationSidebar = new sidebar.DocumentationSidebar(this._host, metadata);
this._host.message('show-node-documentation', documentationSidebar.render());
}
}
};
class ModelError extends Error {
constructor(message, telemetry) {
super(message);
this.name = 'Error loading model.';
this.telemetry = telemetry;
}
}
class ModelContext {
constructor(context) {
this._context = context;
this._tags = new Map();
this._entries = new Map();
}
request(file, encoding) {
return this._context.request(file, encoding);
}
get identifier() {
return this._context.identifier;
}
get buffer() {
return this._context.buffer;
}
get text() {
if (!this._text) {
this._text = new TextDecoder('utf-8').decode(this.buffer);
}
return this._text;
}
entries(extension) {
let entries = this._entries.get(extension);
if (!entries) {
entries = [];
try {
const buffer = this.buffer;
switch (extension) {
case 'zip': {
if (buffer && buffer.length > 2 && buffer[0] == 0x50 && buffer[1] == 0x4b) {
entries = new zip.Archive(buffer).entries;
}
break;
}
case 'tar': {
if (buffer.length >= 512) {
let sum = 0;
for (let i = 0; i < 512; i++) {
sum += i >= 148 && i < 156 ? 32 : buffer[i];
}
let checksum = '';
for (let i = 148; i < 156 && buffer[i] !== 0x00; i++) {
checksum += String.fromCharCode(buffer[i]);
}
checksum = parseInt(checksum, 8);
if (!isNaN(checksum) && sum == checksum) {
entries = new tar.Archive(buffer).entries;
}
}
break;
}
}
} catch (error) {
entries = [];
}
this._entries.set(extension, entries);
}
return entries;
}
tags(extension) {
let tags = this._tags.get(extension);
if (!tags) {
tags = new Map();
try {
switch (extension) {
case 'pbtxt': {
const b = this.buffer;
const length = b.length;
const signature =
(length >= 3 && b[0] === 0xef && b[1] === 0xbb && b[2] === 0xbf) ||
(length >= 4 && b[0] === 0x00 && b[1] === 0x00 && b[2] === 0xfe && b[3] === 0xff) ||
(length >= 4 && b[0] === 0xff && b[1] === 0xfe && b[2] === 0x00 && b[3] === 0x00) ||
(length >= 4 && b[0] === 0x84 && b[1] === 0x31 && b[2] === 0x95 && b[3] === 0x33) ||
(length >= 2 && b[0] === 0xfe && b[1] === 0xff) ||
(length >= 2 && b[0] === 0xff && b[1] === 0xfe);
if (
!signature &&
b.subarray(0, Math.min(1024, length)).some(c => c < 7 || (c > 14 && c < 32))
) {
break;
}
const reader = protobuf.TextReader.create(this.text);
reader.start(false);
while (!reader.end(false)) {
const tag = reader.tag();
tags.set(tag, true);
reader.skip();
}
break;
}
case 'pb': {
const tagTypes = new Set([0, 1, 2, 3, 5]);
const reader = protobuf.Reader.create(this.buffer);
const end = reader.next();
while (reader.pos < end) {
const tagType = reader.uint32();
tags.set(tagType >>> 3, tagType & 7);
if (!tagTypes.has(tagType & 7)) {
tags = new Map();
break;
}
try {
reader.skipType(tagType & 7);
} catch (err) {
tags = new Map();
break;
}
}
break;
}
}
} catch (error) {
tags = new Map();
}
this._tags.set(extension, tags);
}
return tags;
}
}
class ArchiveContext {
constructor(entries, rootFolder, identifier, buffer) {
this._entries = {};
if (entries) {
for (const entry of entries) {
if (entry.name.startsWith(rootFolder)) {
const name = entry.name.substring(rootFolder.length);
if (identifier.length > 0 && identifier.indexOf('/') < 0) {
this._entries[name] = entry;
}
}
}
}
this._identifier = identifier.substring(rootFolder.length);
this._buffer = buffer;
}
request(file, encoding) {
const entry = this._entries[file];
if (!entry) {
return Promise.reject(new Error('File not found.'));
}
const data = encoding ? new TextDecoder(encoding).decode(entry.data) : entry.data;
return Promise.resolve(data);
}
get identifier() {
return this._identifier;
}
get buffer() {
return this._buffer;
}
}
class ArchiveError extends Error {
constructor(message) {
super(message);
this.name = 'Error loading archive.';
}
}
view.ModelFactoryService = class {
constructor(host) {
this._host = host;
this._extensions = [];
this.register('./onnx', ['.onnx', '.pb', '.pbtxt', '.prototxt']);
this.register('./mxnet', ['.mar', '.model', '.json', '.params']);
this.register('./keras', ['.h5', '.hd5', '.hdf5', '.keras', '.json', '.model', '.pb', '.pth']);
this.register('./coreml', ['.mlmodel']);
this.register('./caffe', ['.caffemodel', '.pbtxt', '.prototxt', '.pt']);
this.register('./caffe2', ['.pb', '.pbtxt', '.prototxt']);
this.register('./pytorch', [
'.pt',
'.pth',
'.pt1',
'.pkl',
'.h5',
'.t7',
'.model',
'.dms',
'.tar',
'.ckpt',
'.bin',
'.pb',
'.zip'
]);
this.register('./torch', ['.t7']);
this.register('./tflite', ['.tflite', '.lite', '.tfl', '.bin', '.pb', '.tmfile', '.h5', '.model', '.json']);
this.register('./tf', ['.pb', '.meta', '.pbtxt', '.prototxt', '.json', '.index', '.ckpt']);
this.register('./mediapipe', ['.pbtxt']);
this.register('./uff', ['.uff', '.pb', '.trt', '.pbtxt', '.uff.txt']);
this.register('./sklearn', ['.pkl', '.pickle', '.joblib', '.model', '.meta', '.pb', '.pt', '.h5']);
this.register('./cntk', ['.model', '.cntk', '.cmf', '.dnn']);
this.register('./paddle', ['.paddle', '.pdmodel', '__model__']);
this.register('./armnn', ['.armnn']);
this.register('./bigdl', ['.model', '.bigdl']);
this.register('./darknet', ['.cfg', '.model']);
this.register('./mnn', ['.mnn']);
this.register('./ncnn', ['.param', '.bin', '.cfg.ncnn', '.weights.ncnn']);
this.register('./tnn', ['.tnnproto', '.tnnmodel']);
this.register('./tengine', ['.tmfile']);
this.register('./barracuda', ['.nn']);
this.register('./openvino', ['.xml', '.bin']);
this.register('./flux', ['.bson']);
this.register('./npz', ['.npz', '.h5', '.hd5', '.hdf5']);
this.register('./dl4j', ['.zip']);
this.register('./mlnet', ['.zip']);
}
register(id, extensions) {
for (const extension of extensions) {
this._extensions.push({extension: extension, id: id});
}
}
open(context) {
return this._openSignature(context).then(context => {
return this._openArchive(context).then(context => {
context = new ModelContext(context);
const identifier = context.identifier;
const extension = identifier.split('.').pop().toLowerCase();
const modules = this._filter(context);
if (modules.length == 0) {
throw new ModelError("Unsupported file extension '." + extension + "'.");
}
const errors = [];
let match = false;
const nextModule = () => {
if (modules.length > 0) {
const id = modules.shift();
return this._host.require(id).then(module => {
if (!module.ModelFactory) {
throw new ModelError("Failed to load module '" + id + "'.");
}
const modelFactory = new module.ModelFactory();
if (!modelFactory.match(context)) {
return nextModule();
}
match++;
return modelFactory
.open(context, this._host)
.then(model => {
return model;
})
.catch(error => {
errors.push(error);
return nextModule();
});
});
} else {
if (match) {
if (errors.length == 1) {
throw errors[0];
}
throw new ModelError(errors.map(err => err.message).join('\n'));
}
const knownUnsupportedIdentifiers = new Set([
'natives_blob.bin',
'v8_context_snapshot.bin',
'snapshot_blob.bin',
'image_net_labels.json',
'package.json',
'models.json',
'LICENSE.meta',
'input_0.pb',
'output_0.pb'
]);
const skip = knownUnsupportedIdentifiers.has(identifier);
const buffer = context.buffer;
const content = Array.from(buffer.subarray(0, Math.min(16, buffer.length)))
.map(c => (c < 16 ? '0' : '') + c.toString(16))
.join('');
throw new ModelError(
'Unsupported file content (' +
content +
") for extension '." +
extension +
"' in '" +
identifier +
"'.",
!skip
);
}
};
return nextModule();
});
});
}
_openArchive(context) {
let archive = null;
let extension;
let identifier = context.identifier;
let buffer = context.buffer;
try {
extension = identifier.split('.').pop().toLowerCase();
if (extension == 'gz' || extension == 'tgz') {
archive = new gzip.Archive(buffer);
if (archive.entries.length == 1) {
const entry = archive.entries[0];
if (entry.name) {
identifier = entry.name;
} else {
identifier = identifier.substring(0, identifier.lastIndexOf('.'));
if (extension == 'tgz') {
identifier += '.tar';
}
}
buffer = entry.data;
}
}
} catch (error) {
const message = error && error.message ? error.message : error.toString();
return Promise.reject(new ArchiveError(message.replace(/\.$/, '') + " in '" + identifier + "'."));
}
try {
extension = identifier.split('.').pop().toLowerCase();
switch (extension) {
case 'tar': {
// handle .pth.tar
const torch = [0x8a, 0x0a, 0x6c, 0xfc, 0x9c, 0x46, 0xf9, 0x20, 0x6a, 0xa8, 0x50, 0x19];
if (
!buffer ||
buffer.length < 14 ||
buffer[0] != 0x80 ||
!torch.every((v, i) => v == buffer[i + 2])
) {
archive = new tar.Archive(buffer);
}
break;
}
case 'zip': {
archive = new zip.Archive(buffer);
// PyTorch Zip archive
if (
archive.entries.some(e => e.name.split('/').pop().split('\\').pop() === 'version') &&
archive.entries.some(e => e.name.split('/').pop().split('\\').pop() === 'data.pkl')
) {
return Promise.resolve(context);
}
// dl4j
if (
archive.entries.some(e => e.name.split('/').pop().split('\\').pop() === 'coefficients.bin') &&
archive.entries.some(e => e.name.split('/').pop().split('\\').pop() === 'configuration.json')
) {
return Promise.resolve(context);
}
break;
}
}
} catch (error) {
const message = error && error.message ? error.message : error.toString();
return Promise.reject(new ArchiveError(message.replace(/\.$/, '') + " in '" + identifier + "'."));
}
if (!archive) {
return Promise.resolve(context);
}
try {
const folders = {};
for (const entry of archive.entries) {
if (entry.name.indexOf('/') != -1) {
folders[entry.name.split('/').shift() + '/'] = true;
} else {
folders['/'] = true;
}
}
if (extension == 'tar') {
delete folders['PaxHeader/'];
}
let rootFolder = Object.keys(folders).length == 1 ? Object.keys(folders)[0] : '';
rootFolder = rootFolder == '/' ? '' : rootFolder;
let matches = [];
const entries = archive.entries.slice();
const nextEntry = () => {
if (entries.length > 0) {
const entry = entries.shift();
if (entry.name.startsWith(rootFolder)) {
const identifier = entry.name.substring(rootFolder.length);
if (identifier.length > 0 && identifier.indexOf('/') < 0 && !identifier.startsWith('.')) {
const context = new ModelContext(
new ArchiveContext(null, rootFolder, entry.name, entry.data)
);
let modules = this._filter(context);
const nextModule = () => {
if (modules.length > 0) {
const id = modules.shift();
return this._host.require(id).then(module => {
if (!module.ModelFactory) {
throw new ArchiveError("Failed to load module '" + id + "'.", null);
}
const factory = new module.ModelFactory();
if (factory.match(context)) {
matches.push(entry);
modules = [];
}
return nextModule();
});
} else {
return nextEntry();
}
};
return nextModule();
}
}
return nextEntry();
} else {
if (matches.length == 0) {
return Promise.resolve(context);
}
// MXNet
if (
matches.length == 2 &&
matches.some(e => e.name.endsWith('.params')) &&
matches.some(e => e.name.endsWith('-symbol.json'))
) {
matches = matches.filter(e => e.name.endsWith('.params'));
}
if (matches.length > 1) {
return Promise.reject(new ArchiveError('Archive contains multiple model files.'));
}
const match = matches[0];
return Promise.resolve(
new ModelContext(new ArchiveContext(archive.entries, rootFolder, match.name, match.data))
);
}
};
return nextEntry();
} catch (error) {
return Promise.reject(new ArchiveError(error.message));
}
}
accept(identifier) {
identifier = identifier.toLowerCase();
for (const extension of this._extensions) {
if (identifier.endsWith(extension.extension)) {
return true;
}
}
if (
identifier.endsWith('.zip') ||
identifier.endsWith('.tar') ||
identifier.endsWith('.tar.gz') ||
identifier.endsWith('.tgz')
) {
return true;
}
return false;
}
_filter(context) {
const identifier = context.identifier.toLowerCase();
const list = this._extensions.filter(entry => identifier.endsWith(entry.extension)).map(entry => entry.id);
return Array.from(new Set(list));
}
_openSignature(context) {
const buffer = context.buffer;
if (context.buffer.length === 0) {
return Promise.reject(new ModelError('File has no content.', true));
}
const list = [
// cSpell:disable
{name: 'ELF executable', value: /^\x7FELF/},
{name: 'Git LFS header', value: /^version https:\/\/git-lfs.github.com\/spec\/v1\n/},
{name: 'Git LFS header', value: /^oid sha256:/},
{name: 'HTML markup', value: /^\s*<html>/},
{name: 'HTML markup', value: /^\s*<!DOCTYPE html>/},
{name: 'HTML markup', value: /^\s*<!DOCTYPE HTML>/},
{name: 'Unity metadata', value: /^fileFormatVersion:/},
{name: 'Vulkan SwiftShader ICD manifest', value: /^{\s*"file_format_version":\s*"1.0.0"\s*,\s*"ICD":/},
{name: 'StringIntLabelMapProto data', value: /^item\s*{\r?\n\s*id:/},
{name: 'StringIntLabelMapProto data', value: /^item\s*{\r?\n\s*name:/},
{name: 'Python source code', value: /^\s*import sys, types, os;/}
// cSpell:enable
];
const text = new TextDecoder().decode(buffer.subarray(0, Math.min(1024, buffer.length)));
for (const item of list) {
if (text.match(item.value)) {
return Promise.reject(new ModelError('Invalid file content. File contains ' + item.name + '.', true));
}
}
return Promise.resolve(context);
}
};
if (typeof module !== 'undefined' && typeof module.exports === 'object') {
module.exports.View = view.View;
module.exports.ModelFactoryService = view.ModelFactoryService;
}
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable no-console */
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const Terser = require('terser');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const netron = path.dirname(require.resolve('netron/src'));
const output = path.resolve(__dirname, 'dist');
const excludes = ['index.js', 'view.js', 'view-sidebar.js', 'view-grapher.js', 'app.js', 'base.js', 'electron.js'];
const src = fs.readdirSync(netron, {encoding: 'utf-8'}).filter(file => fs.statSync(path.join(netron, file)).isFile());
const commons = src.filter(file => path.extname(file) === '.js' && !excludes.includes(file));
const metadata = src.filter(file => path.extname(file) === '.json');
module.exports = {
mode: 'production',
context: __dirname,
stats: {
assets: false,
builtAt: true,
cached: false,
cachedAssets: false,
children: false,
chunks: false,
chunkGroups: false,
chunkModules: false,
chunkOrigins: false,
colors: true,
entrypoints: false,
errors: true,
errorDetails: true,
hash: true,
modules: false,
moduleTrace: false,
performance: false,
providedExports: false,
publicPath: true,
reasons: false,
source: false,
timings: true,
usedExports: false,
version: true,
warnings: false
},
entry: {
index: './src/index.js',
shim: './src/shim.js',
style: './src/style.scss'
},
output: {
path: output,
filename: '[name].[contenthash].js',
publicPath: './'
},
optimization: {
splitChunks: {
cacheGroups: {
defaultVendors: {
name: 'vendors',
test: /[\\/]node_modules[\\/](?!netron)/,
chunks: 'all'
}
}
}
},
resolve: {
fallback: {
zlib: false
}
},
module: {
rules: [
{
test: /\.scss/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']
}
]
},
plugins: [
new webpack.ProvidePlugin({
pako: 'pako'
}),
new MiniCssExtractPlugin({
filename: '[name].css'
}),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './src/index.html',
inject: 'body',
scriptLoading: 'blocking'
}),
new CopyWebpackPlugin({
patterns: commons.map(file => ({
from: path.join(netron, file),
to: file,
transform: async content => {
try {
// It is important to keep class names and function names after compressing
// Netron relies on Class.constructor.name and Function.prototype.name to show attribute's value
const result = await Terser.minify(content.toString(), {
keep_classnames: true,
keep_fnames: true
});
return result.code;
} catch (e) {
console.error(e);
return content;
}
}
}))
}),
new CopyWebpackPlugin({
patterns: metadata.map(file => ({
from: path.join(netron, file),
to: file,
transform: content => {
try {
return JSON.stringify(JSON.parse(content.toString()));
} catch (e) {
console.error(e);
return content;
}
}
}))
})
]
};
...@@ -62,6 +62,7 @@ async function start() { ...@@ -62,6 +62,7 @@ async function start() {
const baseUri = snowpackEnv.SNOWPACK_PUBLIC_BASE_URI; const baseUri = snowpackEnv.SNOWPACK_PUBLIC_BASE_URI;
const apiUrl = snowpackEnv.SNOWPACK_PUBLIC_API_URL; const apiUrl = snowpackEnv.SNOWPACK_PUBLIC_API_URL;
console.log('apiUrl', apiUrl, backend);
if (backend) { if (backend) {
const {createProxyMiddleware} = await import('http-proxy-middleware'); const {createProxyMiddleware} = await import('http-proxy-middleware');
......
...@@ -496,6 +496,13 @@ ...@@ -496,6 +496,13 @@
dependencies: dependencies:
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
"@babel/runtime@^7.15.4":
version "7.20.1"
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.20.1.tgz#1148bb33ab252b165a06698fde7576092a78b4a9"
integrity sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==
dependencies:
regenerator-runtime "^0.13.10"
"@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.7": "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.7":
version "7.18.9" version "7.18.9"
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a" resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a"
...@@ -2774,10 +2781,10 @@ ...@@ -2774,10 +2781,10 @@
hoist-non-react-statics "^3.3.0" hoist-non-react-statics "^3.3.0"
redux "^4.0.0" redux "^4.0.0"
"@types/react-redux@^7.1.16": "@types/react-redux@^7.1.20":
version "7.1.16" version "7.1.24"
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.16.tgz#0fbd04c2500c12105494c83d4a3e45c084e3cb21" resolved "https://registry.npmmirror.com/@types/react-redux/-/react-redux-7.1.24.tgz#6caaff1603aba17b27d20f8ad073e4c077e975c0"
integrity sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw== integrity sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ==
dependencies: dependencies:
"@types/hoist-non-react-statics" "^3.3.0" "@types/hoist-non-react-statics" "^3.3.0"
"@types/react" "*" "@types/react" "*"
...@@ -3659,6 +3666,17 @@ array-ify@^1.0.0: ...@@ -3659,6 +3666,17 @@ array-ify@^1.0.0:
resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece"
integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=
array-includes@^3.1.1:
version "3.1.5"
resolved "https://registry.npmmirror.com/array-includes/-/array-includes-3.1.5.tgz#2c320010db8d31031fd2a5f6b3bbd4b1aad31bdb"
integrity sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.4"
es-abstract "^1.19.5"
get-intrinsic "^1.1.1"
is-string "^1.0.7"
array-includes@^3.1.2, array-includes@^3.1.3: array-includes@^3.1.2, array-includes@^3.1.3:
version "3.1.3" version "3.1.3"
resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.3.tgz#c7f619b382ad2afaf5326cddfdc0afc61af7690a" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.3.tgz#c7f619b382ad2afaf5326cddfdc0afc61af7690a"
...@@ -3845,6 +3863,15 @@ axios@^0.21.0: ...@@ -3845,6 +3863,15 @@ axios@^0.21.0:
dependencies: dependencies:
follow-redirects "^1.10.0" follow-redirects "^1.10.0"
axios@^1.1.3:
version "1.1.3"
resolved "https://registry.npmmirror.com/axios/-/axios-1.1.3.tgz#8274250dada2edf53814ed7db644b9c2866c1e35"
integrity sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==
dependencies:
follow-redirects "^1.15.0"
form-data "^4.0.0"
proxy-from-env "^1.1.0"
"babel-plugin-styled-components@>= 1.12.0": "babel-plugin-styled-components@>= 1.12.0":
version "1.12.0" version "1.12.0"
resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.12.0.tgz#1dec1676512177de6b827211e9eda5a30db4f9b9" resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.12.0.tgz#1dec1676512177de6b827211e9eda5a30db4f9b9"
...@@ -4628,7 +4655,7 @@ columnify@^1.5.4: ...@@ -4628,7 +4655,7 @@ columnify@^1.5.4:
strip-ansi "^3.0.0" strip-ansi "^3.0.0"
wcwidth "^1.0.0" wcwidth "^1.0.0"
combined-stream@^1.0.6, combined-stream@~1.0.6: combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
version "1.0.8" version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
...@@ -4971,6 +4998,14 @@ cpy@^8.0.0, cpy@^8.1.1: ...@@ -4971,6 +4998,14 @@ cpy@^8.0.0, cpy@^8.1.1:
p-filter "^2.1.0" p-filter "^2.1.0"
p-map "^3.0.0" p-map "^3.0.0"
create-react-context@^0.3.0:
version "0.3.0"
resolved "https://registry.npmmirror.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"
create-require@^1.1.0: create-require@^1.1.0:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
...@@ -5803,6 +5838,14 @@ define-properties@^1.1.3: ...@@ -5803,6 +5838,14 @@ define-properties@^1.1.3:
dependencies: dependencies:
object-keys "^1.0.12" object-keys "^1.0.12"
define-properties@^1.1.4:
version "1.1.4"
resolved "https://registry.npmmirror.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1"
integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==
dependencies:
has-property-descriptors "^1.0.0"
object-keys "^1.1.1"
define-property@^0.2.5: define-property@^0.2.5:
version "0.2.5" version "0.2.5"
resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
...@@ -6256,6 +6299,36 @@ es-abstract@^1.17.2, es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es- ...@@ -6256,6 +6299,36 @@ es-abstract@^1.17.2, es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-
string.prototype.trimstart "^1.0.4" string.prototype.trimstart "^1.0.4"
unbox-primitive "^1.0.1" unbox-primitive "^1.0.1"
es-abstract@^1.19.0, es-abstract@^1.19.5:
version "1.20.4"
resolved "https://registry.npmmirror.com/es-abstract/-/es-abstract-1.20.4.tgz#1d103f9f8d78d4cf0713edcd6d0ed1a46eed5861"
integrity sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==
dependencies:
call-bind "^1.0.2"
es-to-primitive "^1.2.1"
function-bind "^1.1.1"
function.prototype.name "^1.1.5"
get-intrinsic "^1.1.3"
get-symbol-description "^1.0.0"
has "^1.0.3"
has-property-descriptors "^1.0.0"
has-symbols "^1.0.3"
internal-slot "^1.0.3"
is-callable "^1.2.7"
is-negative-zero "^2.0.2"
is-regex "^1.1.4"
is-shared-array-buffer "^1.0.2"
is-string "^1.0.7"
is-weakref "^1.0.2"
object-inspect "^1.12.2"
object-keys "^1.1.1"
object.assign "^4.1.4"
regexp.prototype.flags "^1.4.3"
safe-regex-test "^1.0.0"
string.prototype.trimend "^1.0.5"
string.prototype.trimstart "^1.0.5"
unbox-primitive "^1.0.2"
es-module-lexer@^0.3.24, es-module-lexer@^0.3.25: es-module-lexer@^0.3.24, es-module-lexer@^0.3.25:
version "0.3.26" version "0.3.26"
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.3.26.tgz#7b507044e97d5b03b01d4392c74ffeb9c177a83b" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.3.26.tgz#7b507044e97d5b03b01d4392c74ffeb9c177a83b"
...@@ -6942,6 +7015,11 @@ follow-redirects@^1.0.0, follow-redirects@^1.10.0: ...@@ -6942,6 +7015,11 @@ follow-redirects@^1.0.0, follow-redirects@^1.10.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43"
integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg== integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==
follow-redirects@^1.15.0:
version "1.15.2"
resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
for-in@^1.0.2: for-in@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
...@@ -6952,6 +7030,15 @@ forever-agent@~0.6.1: ...@@ -6952,6 +7030,15 @@ forever-agent@~0.6.1:
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
form-data@^4.0.0:
version "4.0.0"
resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
form-data@~2.3.2: form-data@~2.3.2:
version "2.3.3" version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
...@@ -7058,11 +7145,26 @@ function-bind@^1.1.1: ...@@ -7058,11 +7145,26 @@ function-bind@^1.1.1:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
function.prototype.name@^1.1.5:
version "1.1.5"
resolved "https://registry.npmmirror.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621"
integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.3"
es-abstract "^1.19.0"
functions-have-names "^1.2.2"
functional-red-black-tree@^1.0.1: functional-red-black-tree@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
functions-have-names@^1.2.2:
version "1.2.3"
resolved "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
gauge@~2.7.3: gauge@~2.7.3:
version "2.7.4" version "2.7.4"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
...@@ -7108,6 +7210,15 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: ...@@ -7108,6 +7210,15 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
has "^1.0.3" has "^1.0.3"
has-symbols "^1.0.1" has-symbols "^1.0.1"
get-intrinsic@^1.1.3:
version "1.1.3"
resolved "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385"
integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==
dependencies:
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.3"
get-own-enumerable-property-symbols@^3.0.0: get-own-enumerable-property-symbols@^3.0.0:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
...@@ -7153,6 +7264,14 @@ get-stream@^6.0.0: ...@@ -7153,6 +7264,14 @@ get-stream@^6.0.0:
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
get-symbol-description@^1.0.0:
version "1.0.0"
resolved "https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6"
integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==
dependencies:
call-bind "^1.0.2"
get-intrinsic "^1.1.1"
get-uri@3: get-uri@3:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c" resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c"
...@@ -7371,6 +7490,11 @@ graphlib@^2.1.8: ...@@ -7371,6 +7490,11 @@ graphlib@^2.1.8:
dependencies: dependencies:
lodash "^4.17.15" lodash "^4.17.15"
gud@^1.0.0:
version "1.0.0"
resolved "https://registry.npmmirror.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==
handlebars@^4.7.6: handlebars@^4.7.6:
version "4.7.7" version "4.7.7"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1"
...@@ -7406,6 +7530,11 @@ has-bigints@^1.0.1: ...@@ -7406,6 +7530,11 @@ has-bigints@^1.0.1:
resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113"
integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==
has-bigints@^1.0.2:
version "1.0.2"
resolved "https://registry.npmmirror.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==
has-flag@^3.0.0: has-flag@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
...@@ -7423,11 +7552,30 @@ has-glob@^1.0.0: ...@@ -7423,11 +7552,30 @@ has-glob@^1.0.0:
dependencies: dependencies:
is-glob "^3.0.0" is-glob "^3.0.0"
has-property-descriptors@^1.0.0:
version "1.0.0"
resolved "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861"
integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==
dependencies:
get-intrinsic "^1.1.1"
has-symbols@^1.0.1, has-symbols@^1.0.2: has-symbols@^1.0.1, has-symbols@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423"
integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
has-symbols@^1.0.3:
version "1.0.3"
resolved "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
has-tostringtag@^1.0.0:
version "1.0.0"
resolved "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25"
integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==
dependencies:
has-symbols "^1.0.2"
has-unicode@^2.0.0, has-unicode@^2.0.1: has-unicode@^2.0.0, has-unicode@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
...@@ -7936,6 +8084,13 @@ interpret@^2.2.0: ...@@ -7936,6 +8084,13 @@ interpret@^2.2.0:
resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9"
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.npmmirror.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
dependencies:
loose-envify "^1.0.0"
ip@^1.1.5: ip@^1.1.5:
version "1.1.5" version "1.1.5"
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
...@@ -8004,6 +8159,11 @@ is-callable@^1.1.4, is-callable@^1.2.3: ...@@ -8004,6 +8159,11 @@ is-callable@^1.1.4, is-callable@^1.2.3:
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e"
integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==
is-callable@^1.2.7:
version "1.2.7"
resolved "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
is-ci@^2.0.0: is-ci@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
...@@ -8146,6 +8306,11 @@ is-negative-zero@^2.0.1: ...@@ -8146,6 +8306,11 @@ is-negative-zero@^2.0.1:
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24"
integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==
is-negative-zero@^2.0.2:
version "2.0.2"
resolved "https://registry.npmmirror.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150"
integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==
is-npm@^4.0.0: is-npm@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d"
...@@ -8225,11 +8390,26 @@ is-regex@^1.1.3: ...@@ -8225,11 +8390,26 @@ is-regex@^1.1.3:
call-bind "^1.0.2" call-bind "^1.0.2"
has-symbols "^1.0.2" has-symbols "^1.0.2"
is-regex@^1.1.4:
version "1.1.4"
resolved "https://registry.npmmirror.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
dependencies:
call-bind "^1.0.2"
has-tostringtag "^1.0.0"
is-regexp@^1.0.0: is-regexp@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk=
is-shared-array-buffer@^1.0.2:
version "1.0.2"
resolved "https://registry.npmmirror.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79"
integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==
dependencies:
call-bind "^1.0.2"
is-ssh@^1.3.0: is-ssh@^1.3.0:
version "1.3.3" version "1.3.3"
resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.3.3.tgz#7f133285ccd7f2c2c7fc897b771b53d95a2b2c7e" resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.3.3.tgz#7f133285ccd7f2c2c7fc897b771b53d95a2b2c7e"
...@@ -8247,6 +8427,13 @@ is-string@^1.0.5, is-string@^1.0.6: ...@@ -8247,6 +8427,13 @@ is-string@^1.0.5, is-string@^1.0.6:
resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f"
integrity sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w== integrity sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==
is-string@^1.0.7:
version "1.0.7"
resolved "https://registry.npmmirror.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==
dependencies:
has-tostringtag "^1.0.0"
is-subset@^0.1.1: is-subset@^0.1.1:
version "0.1.1" version "0.1.1"
resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6" resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6"
...@@ -8288,6 +8475,13 @@ is-valid-identifier@^2.0.2: ...@@ -8288,6 +8475,13 @@ is-valid-identifier@^2.0.2:
dependencies: dependencies:
assert "^1.4.1" assert "^1.4.1"
is-weakref@^1.0.2:
version "1.0.2"
resolved "https://registry.npmmirror.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==
dependencies:
call-bind "^1.0.2"
is-what@^3.14.1: is-what@^3.14.1:
version "3.14.1" version "3.14.1"
resolved "https://registry.npmmirror.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1" resolved "https://registry.npmmirror.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1"
...@@ -8596,6 +8790,14 @@ jss@10.9.2, jss@^10.5.1: ...@@ -8596,6 +8790,14 @@ jss@10.9.2, jss@^10.5.1:
is-in-browser "^1.1.3" is-in-browser "^1.1.3"
tiny-warning "^1.0.2" tiny-warning "^1.0.2"
jsx-ast-utils@^2.2.1:
version "2.4.1"
resolved "https://registry.npmmirror.com/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz#1114a4c1209481db06c690c2b4f488cc665f657e"
integrity sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w==
dependencies:
array-includes "^3.1.1"
object.assign "^4.1.0"
"jsx-ast-utils@^2.4.1 || ^3.0.0": "jsx-ast-utils@^2.4.1 || ^3.0.0":
version "3.2.0" version "3.2.0"
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz#41108d2cec408c3453c1bbe8a4aae9e1e2bd8f82" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz#41108d2cec408c3453c1bbe8a4aae9e1e2bd8f82"
...@@ -9059,7 +9261,7 @@ long@4.0.0: ...@@ -9059,7 +9261,7 @@ long@4.0.0:
resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
...@@ -10050,6 +10252,11 @@ object-inspect@^1.10.3, object-inspect@^1.9.0: ...@@ -10050,6 +10252,11 @@ object-inspect@^1.10.3, object-inspect@^1.9.0:
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369"
integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw== integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==
object-inspect@^1.12.2:
version "1.12.2"
resolved "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea"
integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==
object-keys@^1.0.12, object-keys@^1.1.1: object-keys@^1.0.12, object-keys@^1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
...@@ -10062,6 +10269,16 @@ object-visit@^1.0.0: ...@@ -10062,6 +10269,16 @@ object-visit@^1.0.0:
dependencies: dependencies:
isobject "^3.0.0" isobject "^3.0.0"
object.assign@^4.1.0, object.assign@^4.1.4:
version "4.1.4"
resolved "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f"
integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.4"
has-symbols "^1.0.3"
object-keys "^1.1.1"
object.assign@^4.1.2: object.assign@^4.1.2:
version "4.1.2" version "4.1.2"
resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
...@@ -11038,7 +11255,7 @@ proxy-agent@~4.0.1: ...@@ -11038,7 +11255,7 @@ proxy-agent@~4.0.1:
proxy-from-env "^1.0.0" proxy-from-env "^1.0.0"
socks-proxy-agent "^5.0.0" socks-proxy-agent "^5.0.0"
proxy-from-env@1.1.0, proxy-from-env@^1.0.0: proxy-from-env@1.1.0, proxy-from-env@^1.0.0, proxy-from-env@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
...@@ -11567,6 +11784,16 @@ rc@^1.2.8: ...@@ -11567,6 +11784,16 @@ rc@^1.2.8:
minimist "^1.2.0" minimist "^1.2.0"
strip-json-comments "~2.0.1" strip-json-comments "~2.0.1"
react-activation@^0.12.1:
version "0.12.1"
resolved "https://registry.npmmirror.com/react-activation/-/react-activation-0.12.1.tgz#8befff5c43e4c702a8511b632abe4d97c6d9ba8f"
integrity sha512-kUBzyTmI9PRZe7whlBaHdDy9CsUY2uIQ71LVNLDW9/Ofw46QjS2gNcjY7ZvJyyKSo8YjWdnfyGJKYiLaxL/utQ==
dependencies:
create-react-context "^0.3.0"
hoist-non-react-statics "^3.3.0"
react-node-key "^0.4.0"
szfe-tools "^0.0.0-beta.7"
react-content-loader@6.0.3: react-content-loader@6.0.3:
version "6.0.3" version "6.0.3"
resolved "https://registry.yarnpkg.com/react-content-loader/-/react-content-loader-6.0.3.tgz#32e28ca7120e0a2552fc26655d0d4448cc1fc0c5" resolved "https://registry.yarnpkg.com/react-content-loader/-/react-content-loader-6.0.3.tgz#32e28ca7120e0a2552fc26655d0d4448cc1fc0c5"
...@@ -11630,16 +11857,24 @@ react-input-range@1.3.0: ...@@ -11630,16 +11857,24 @@ react-input-range@1.3.0:
autobind-decorator "^1.3.4" autobind-decorator "^1.3.4"
prop-types "^15.5.8" prop-types "^15.5.8"
react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1" version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
"react-is@^16.8.0 || ^17.0.0", react-is@^17.0.1: "react-is@^16.8.0 || ^17.0.0", react-is@^17.0.1, react-is@^17.0.2:
version "17.0.2" version "17.0.2"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
react-node-key@^0.4.0:
version "0.4.0"
resolved "https://registry.npmmirror.com/react-node-key/-/react-node-key-0.4.0.tgz#acb90f06828f594051c6e37c005ea080be228ee2"
integrity sha512-puiuP2QYEuNBVVvcjpUE8d8/jdAhiXHBHMmjZzQT4+fe276RMYea/tY7JoZoYlrhAX8DORLPvjySjXYJZ1m6/A==
dependencies:
jsx-ast-utils "^2.2.1"
szfe-tools "^0.0.0-beta.7"
react-rangeslider@2.2.0: react-rangeslider@2.2.0:
version "2.2.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/react-rangeslider/-/react-rangeslider-2.2.0.tgz#4362b01f4f5a455f0815d371d496f69ca4c6b5aa" resolved "https://registry.yarnpkg.com/react-rangeslider/-/react-rangeslider-2.2.0.tgz#4362b01f4f5a455f0815d371d496f69ca4c6b5aa"
...@@ -11648,17 +11883,17 @@ react-rangeslider@2.2.0: ...@@ -11648,17 +11883,17 @@ react-rangeslider@2.2.0:
classnames "^2.2.3" classnames "^2.2.3"
resize-observer-polyfill "^1.4.2" resize-observer-polyfill "^1.4.2"
react-redux@7.2.5: react-redux@7.2.9:
version "7.2.5" version "7.2.9"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.5.tgz#213c1b05aa1187d9c940ddfc0b29450957f6a3b8" resolved "https://registry.npmmirror.com/react-redux/-/react-redux-7.2.9.tgz#09488fbb9416a4efe3735b7235055442b042481d"
integrity sha512-Dt29bNyBsbQaysp6s/dN0gUodcq+dVKKER8Qv82UrpeygwYeX1raTtil7O/fftw/rFqzaf6gJhDZRkkZnn6bjg== integrity sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==
dependencies: dependencies:
"@babel/runtime" "^7.12.1" "@babel/runtime" "^7.15.4"
"@types/react-redux" "^7.1.16" "@types/react-redux" "^7.1.20"
hoist-non-react-statics "^3.3.2" hoist-non-react-statics "^3.3.2"
loose-envify "^1.4.0" loose-envify "^1.4.0"
prop-types "^15.7.2" prop-types "^15.7.2"
react-is "^16.13.1" react-is "^17.0.2"
react-refresh@^0.9.0: react-refresh@^0.9.0:
version "0.9.0" version "0.9.0"
...@@ -11706,6 +11941,16 @@ react-spinners@0.11.0: ...@@ -11706,6 +11941,16 @@ react-spinners@0.11.0:
dependencies: dependencies:
"@emotion/react" "^11.1.4" "@emotion/react" "^11.1.4"
react-stillness-component@^0.9.0:
version "0.9.0"
resolved "https://registry.npmmirror.com/react-stillness-component/-/react-stillness-component-0.9.0.tgz#1ad072a45d7226192ff64638f05a53069fb13e5d"
integrity sha512-mYMxIAYkHMMGw7KRtYZGvbTXGWQI8zESY23i51kDs5W8CIIOIWxVTCQnOd3PiuD5RutKO1K7BsS1SYJgp2PgAg==
dependencies:
fast-deep-equal "^3.1.3"
hoist-non-react-statics "^3.3.2"
invariant "^2.2.4"
redux "^4.1.2"
react-table-sticky@1.1.3: react-table-sticky@1.1.3:
version "1.1.3" version "1.1.3"
resolved "https://registry.yarnpkg.com/react-table-sticky/-/react-table-sticky-1.1.3.tgz#af27c0afb2c4a32c292d486b21d9a896d354ba70" resolved "https://registry.yarnpkg.com/react-table-sticky/-/react-table-sticky-1.1.3.tgz#af27c0afb2c4a32c292d486b21d9a896d354ba70"
...@@ -11956,6 +12201,18 @@ redux@^4.0.0, redux@^4.0.5: ...@@ -11956,6 +12201,18 @@ redux@^4.0.0, redux@^4.0.5:
dependencies: dependencies:
"@babel/runtime" "^7.9.2" "@babel/runtime" "^7.9.2"
redux@^4.1.2:
version "4.2.0"
resolved "https://registry.npmmirror.com/redux/-/redux-4.2.0.tgz#46f10d6e29b6666df758780437651eeb2b969f13"
integrity sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==
dependencies:
"@babel/runtime" "^7.9.2"
regenerator-runtime@^0.13.10:
version "0.13.10"
resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz#ed07b19616bcbec5da6274ebc75ae95634bfc2ee"
integrity sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==
regenerator-runtime@^0.13.4: regenerator-runtime@^0.13.4:
version "0.13.7" version "0.13.7"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
...@@ -11977,6 +12234,15 @@ regexp.prototype.flags@^1.3.1: ...@@ -11977,6 +12234,15 @@ regexp.prototype.flags@^1.3.1:
call-bind "^1.0.2" call-bind "^1.0.2"
define-properties "^1.1.3" define-properties "^1.1.3"
regexp.prototype.flags@^1.4.3:
version "1.4.3"
resolved "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac"
integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.3"
functions-have-names "^1.2.2"
regexpp@^3.1.0: regexpp@^3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
...@@ -12268,6 +12534,15 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@^5.2.1, ...@@ -12268,6 +12534,15 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@^5.2.1,
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
safe-regex-test@^1.0.0:
version "1.0.0"
resolved "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295"
integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==
dependencies:
call-bind "^1.0.2"
get-intrinsic "^1.1.3"
is-regex "^1.1.4"
safe-regex@^1.1.0: safe-regex@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
...@@ -12923,6 +13198,15 @@ string.prototype.trimend@^1.0.4: ...@@ -12923,6 +13198,15 @@ string.prototype.trimend@^1.0.4:
call-bind "^1.0.2" call-bind "^1.0.2"
define-properties "^1.1.3" define-properties "^1.1.3"
string.prototype.trimend@^1.0.5:
version "1.0.5"
resolved "https://registry.npmmirror.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0"
integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.4"
es-abstract "^1.19.5"
string.prototype.trimstart@^1.0.4: string.prototype.trimstart@^1.0.4:
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed"
...@@ -12931,6 +13215,15 @@ string.prototype.trimstart@^1.0.4: ...@@ -12931,6 +13215,15 @@ string.prototype.trimstart@^1.0.4:
call-bind "^1.0.2" call-bind "^1.0.2"
define-properties "^1.1.3" define-properties "^1.1.3"
string.prototype.trimstart@^1.0.5:
version "1.0.5"
resolved "https://registry.npmmirror.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef"
integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.4"
es-abstract "^1.19.5"
string_decoder@^1.1.1: string_decoder@^1.1.1:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
...@@ -13138,6 +13431,13 @@ systeminformation@^5.7: ...@@ -13138,6 +13431,13 @@ systeminformation@^5.7:
resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.7.5.tgz#f841e034baccd3bca57b8a7c5ae5b3e2b36580b4" resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.7.5.tgz#f841e034baccd3bca57b8a7c5ae5b3e2b36580b4"
integrity sha512-z3h0aHzt4YKmMHEW3TlvQSV0/R7+ktrrEXU+JC88odNKslf2Ce3yD5rQlA+kRJT1ky0iN5v2sWTbp7wSyTsn7w== integrity sha512-z3h0aHzt4YKmMHEW3TlvQSV0/R7+ktrrEXU+JC88odNKslf2Ce3yD5rQlA+kRJT1ky0iN5v2sWTbp7wSyTsn7w==
szfe-tools@^0.0.0-beta.7:
version "0.0.0-beta.7"
resolved "https://registry.npmmirror.com/szfe-tools/-/szfe-tools-0.0.0-beta.7.tgz#580bacbc3d4e353c6ac00ab337b037aa53d14e96"
integrity sha512-/M7+Tel2G8zapfDYZlz17hf9ViqAi/loZMfM81b5iZMyaWL/t5dajBszEBI2kyIDFzlLT4btBcq+BimFgmAHug==
dependencies:
"@babel/runtime" "^7.10.2"
table-layout@^1.0.1: table-layout@^1.0.1:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04" resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04"
...@@ -13648,6 +13948,16 @@ unbox-primitive@^1.0.1: ...@@ -13648,6 +13948,16 @@ unbox-primitive@^1.0.1:
has-symbols "^1.0.2" has-symbols "^1.0.2"
which-boxed-primitive "^1.0.2" which-boxed-primitive "^1.0.2"
unbox-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.npmmirror.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==
dependencies:
call-bind "^1.0.2"
has-bigints "^1.0.2"
has-symbols "^1.0.3"
which-boxed-primitive "^1.0.2"
unbzip2-stream@1.3.3: unbzip2-stream@1.3.3:
version "1.3.3" version "1.3.3"
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz#d156d205e670d8d8c393e1c02ebd506422873f6a" resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz#d156d205e670d8d8c393e1c02ebd506422873f6a"
...@@ -13953,6 +14263,13 @@ walk-up-path@^1.0.0: ...@@ -13953,6 +14263,13 @@ walk-up-path@^1.0.0:
resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-1.0.0.tgz#d4745e893dd5fd0dbb58dd0a4c6a33d9c9fec53e" resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-1.0.0.tgz#d4745e893dd5fd0dbb58dd0a4c6a33d9c9fec53e"
integrity sha512-hwj/qMDUEjCU5h0xr90KGCf0tg0/LgJbmOWgrWKYlcJZM7XvquvUJZ0G/HMGr7F7OQMOUuPHWP9JpriinkAlkg== integrity sha512-hwj/qMDUEjCU5h0xr90KGCf0tg0/LgJbmOWgrWKYlcJZM7XvquvUJZ0G/HMGr7F7OQMOUuPHWP9JpriinkAlkg==
warning@^4.0.3:
version "4.0.3"
resolved "https://registry.npmmirror.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
dependencies:
loose-envify "^1.0.0"
wasm-pack@0.9.1: wasm-pack@0.9.1:
version "0.9.1" version "0.9.1"
resolved "https://registry.yarnpkg.com/wasm-pack/-/wasm-pack-0.9.1.tgz#f1e80814c7197a469e700ff15b6c16cad5dbb2ae" resolved "https://registry.yarnpkg.com/wasm-pack/-/wasm-pack-0.9.1.tgz#f1e80814c7197a469e700ff15b6c16cad5dbb2ae"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册