diff --git a/Ivette/.babelrc b/Ivette/.babelrc new file mode 100644 index 0000000000000000000000000000000000000000..3e895f0c581bd6d45a280384ee46860f7d37c213 --- /dev/null +++ b/Ivette/.babelrc @@ -0,0 +1,21 @@ +// -------------------------------------------------------------------------- +// --- Template .babelrc configuration file for Dome +// -------------------------------------------------------------------------- + +/* + Template from $(DOME)/template/babelrc.json + + This configuration is a necessary extension to electron-webpack + for enabling react-hot-reloading. +*/ + +{ + "presets": [ + [ "@babel/env", { "modules": false } ], + [ "@babel/react" ] + ], + "plugins": [ + "@babel/plugin-proposal-object-rest-spread", + "react-hot-loader/babel" + ] +} diff --git a/Ivette/.dome-pkg-app.lock b/Ivette/.dome-pkg-app.lock new file mode 100644 index 0000000000000000000000000000000000000000..7282f0cc447a1caf3cb155d03008966d7b2f41ab --- /dev/null +++ b/Ivette/.dome-pkg-app.lock @@ -0,0 +1 @@ +react@^16.8 react-dom source-map-support lodash react-virtualized react-draggable codemirror diff --git a/Ivette/.dome-pkg-dev.lock b/Ivette/.dome-pkg-dev.lock new file mode 100644 index 0000000000000000000000000000000000000000..e1751fd66367a580e267a065cb09c992b4c59e94 --- /dev/null +++ b/Ivette/.dome-pkg-dev.lock @@ -0,0 +1 @@ +@babel/core@^7 @babel/preset-env @babel/preset-react @babel/plugin-proposal-object-rest-spread electron@^7 electron-builder electron-webpack electron-devtools-installer webpack babel-loader css-loader react-hot-loader @hot-loader/react-dom @types/react diff --git a/Ivette/.gitignore b/Ivette/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..1efbc2521d6c0dff5b7105180523d02e9c033406 --- /dev/null +++ b/Ivette/.gitignore @@ -0,0 +1,15 @@ +# -------------------------------------------------------------------------- +# --- Template .gitignore file for Dome +# -------------------------------------------------------------------------- + +.dome-*.stamp +.dome-*.back +node_modules +yarn.lock +yarn-error.log +/bin +/dist +/html +/src/dome + +# -------------------------------------------------------------------------- diff --git a/Ivette/Makefile b/Ivette/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f4aa37843767cbbbce1a4783431c24d682f8dc64 --- /dev/null +++ b/Ivette/Makefile @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +APP=Ivette +DOME=src/dome +DOME_APP_CLI=bin/frama-c-gui +DOME_APP_SRC=src/frama-c +COPYRIGHT="CEA LIST / LSL" +# -------------------------------------------------------------------------- + +.PHONY: app dev doc dist + +app: dome-app +dev: dome-dev +doc: dome-api dome-doc +dist: dome-dist + +# -------------------------------------------------------------------------- +# --- Ivette Plugins +# -------------------------------------------------------------------------- + +DOME_PLUGINS= +DOME_EXPORTS= + +# -------------------------------------------------------------------------- +include $(DOME)/template/makefile +# -------------------------------------------------------------------------- diff --git a/Ivette/README.md b/Ivette/README.md new file mode 100644 index 0000000000000000000000000000000000000000..da470aaa23646815685ab9ab6d1b6b954acb31fc --- /dev/null +++ b/Ivette/README.md @@ -0,0 +1,25 @@ +## Setup + +From the `./gui` sub-directory of Frama-C main directory: + +``` +$ make app +``` + +## Mirroring to Dome/Electron + +The content of ./src/dome is git-subtree to be kept in sync +with Dome/Electron. The related commands must be issued from +the Frama-C root directory: + +1. Importing a branch from dome/electron: + +``` +$ git subtree pull -P gui/src/dome git@git.frama-c.com:dome/electron.git <branch> +``` + +2. Exporting to a branch into dome/electron: + +``` +$ git subtree push -P gui/src/dome git@git.frama-c.com:dome/electron.git <branch> +``` diff --git a/Ivette/backup/Configure.js b/Ivette/backup/Configure.js new file mode 100644 index 0000000000000000000000000000000000000000..b91206cb19da49d3518ca9ded6f4e51f34f2dc00 --- /dev/null +++ b/Ivette/backup/Configure.js @@ -0,0 +1,155 @@ +// -------------------------------------------------------------------------- +// --- Module Configuration View +// -------------------------------------------------------------------------- + +import _ from 'lodash' ; +import React from 'react' ; +import Dome from 'dome' ; +import Dialogs from 'dome/dialogs' ; +import { Catch } from 'dome/errors' ; +import { Label } from 'dome/controls/labels' ; +import Box from 'dome/layout/boxes' ; +import Toolbar from 'dome/layout/toolbars' ; +import Dispatch from 'dome/layout/dispatch' ; +import Form from 'dome/layout/forms' ; +import Ivette from '@ivette' ; +import Project from './Project' ; + +// -------------------------------------------------------------------------- +// --- Configuration View +// -------------------------------------------------------------------------- + +export default function Configure() +{ + + const [ state, setState ] = Project.useState(); + const configure = state.configure ; + if (!configure) return null; + + const { module, value, error, modified=false, copied } = configure ; + const valueId = value && value.id ; + const savedId = module && module.id ; + const isFresh = Ivette.isFresh(valueId); + const borrowed_label = copied && module.label ; + const borrowed_title = copied && module.title ; + + const validIdent = (id) => + id === savedId || + (!Ivette.isValid(id) ? 'Invalid identifier (not a filename)' : + !Ivette.isFresh(id) ? 'Already used identifier' : + true) ; + + const validLabel = borrowed_label && ((label) => label !== borrowed_label) ; + const validTitle = borrowed_title && ((title) => title !== borrowed_title) ; + + const onChange = (value,error) => { + Object.assign( configure, { modified: true, value, error } ); + setState({ configure }); + }; + + const onReload = () => { + setState({ configure: { + module, + copied: configure.copied, + value: Project.initConfigValue(configure.module) + }}); + }; + + const closeWith = (current) => { + setState({ + current, + configure: undefined, + frame: configure.onClose || 'home' + }); + }; + + const onClose = () => closeWith( state.current ); + + const onApply = () => { + if ( value && !error && !module.locked()) { + let commit = Ivette.commitModule( module, value ); + module.synchronize(commit) + .catch(onError) + .finally(() => closeWith( configure.copied ? module : undefined )); + } else { + closeWith( undefined ); + } + }; + + const onError = (err) => Dialogs.showMessageBox({ + kind: 'warning', + title: 'Module Management Error', + message: 'An error occurs during a module operation:\n' + err, + buttons: [{ label:'Ok' }] + }); + + const onRemove = () => Dialogs.showMessageBox({ + kind: 'warning', + title: 'Remove Module', + message: 'Definitively remove this Module from your Project ?', + defaultValue: false, + cancelValue: false, + buttons: [ + { value:false, label:'No' }, + { value:true, label:'Remove' } + ] + }).then( (ok) => { + if (ok) { + let removal = Ivette.removeModule( configure.module ); + module.synchronize(removal) + .catch(onError) + .finally(() => closeWith( undefined )); + } + }); + + return ( + <Box.Vfill> + <Dispatch.Item id='ivette.toolbar.configure'> + <Toolbar.Separator/> + <Toolbar.Button + kind='positive' icon='CHECK' + label='Apply' title='Apply modifications' + enabled={modified || isFresh} + disabled={error || module.locked()} + onClick={onApply} /> + <Toolbar.Inset/> + <Label>{ isFresh && 'New' } Module Configuration </Label> + <Toolbar.Filler/> + <Toolbar.Button + kind='negative' icon='TRASH' + label='Remove' title='Remove module' + disabled={isFresh} + enabled={valueId === savedId} + onClick={onRemove} /> + <Toolbar.Button + icon='RELOAD' title='Reset configuration' + enabled={modified} + onClick={onReload} /> + <Toolbar.Button + kind='cancel' + icon='CIRC.CLOSE' title='Cancel modifications' + onClick={onClose} /> + </Dispatch.Item> + <Form.Form + value={value} + error={error} + onChange={onChange} > + <Form.FieldCode + path='id' label='Module' + validate={validIdent} + placeholder={valueId} /> + <Form.FieldText + path='label' label='Display Name' + validate={validLabel} /> + <Form.FieldTextArea + path='title' label='Description' + validate={validTitle} rows={3} /> + <Form.Select path='config'> + <Catch label='Plugin Config'>{ module.renderConfig() }</Catch> + </Form.Select> + </Form.Form> + </Box.Vfill> + ); +} + +// -------------------------------------------------------------------------- diff --git a/Ivette/backup/Display.js b/Ivette/backup/Display.js new file mode 100644 index 0000000000000000000000000000000000000000..140f47ea5a92250db15d4bb69b8b6978e6292b83 --- /dev/null +++ b/Ivette/backup/Display.js @@ -0,0 +1,34 @@ +// -------------------------------------------------------------------------- +// --- Module Control View +// -------------------------------------------------------------------------- + +import _ from 'lodash' ; +import React from 'react' ; +import Dome from 'dome' ; +import { Catch } from 'dome/errors' ; +import { Label } from 'dome/controls/labels' ; +import Toolbar from 'dome/layout/toolbars' ; +import Dispatch from 'dome/layout/dispatch' ; +import Project from './Project' ; +import { ProvideModule } from '@ivette' ; + +// -------------------------------------------------------------------------- +// --- Current Module Display +// -------------------------------------------------------------------------- + +export default function Display() +{ + const [ { current } ] = Project.useState(); + if (!current) + return <Label>No module selected.</Label> ; + else + return ( + <ProvideModule module={current}> + <Catch label='Plugin Main View'> + <Dome.Render>{current.renderMain}</Dome.Render> + </Catch> + </ProvideModule> + ); +} + +// -------------------------------------------------------------------------- diff --git a/Ivette/backup/FileMenu.js b/Ivette/backup/FileMenu.js new file mode 100644 index 0000000000000000000000000000000000000000..c2bf7131c3ffe435c7c151d584c5f645d862c61f --- /dev/null +++ b/Ivette/backup/FileMenu.js @@ -0,0 +1,37 @@ +// -------------------------------------------------------------------------- +// --- File Menu +// -------------------------------------------------------------------------- + +import fs from 'fs' ; +import path from 'path' ; +import Dome from 'dome' ; +import Dialogs from 'dome/dialogs' ; +import Project from './Project' ; +import Ivette from '@ivette' ; + +// -------------------------------------------------------------------------- +// --- Actions +// -------------------------------------------------------------------------- + +function openProject() +{ + console.log('OPEN PROJECT…'); +} + +// -------------------------------------------------------------------------- +// --- Menu Items +// -------------------------------------------------------------------------- + +Dome.addMenuItem({ + menu: 'File', + id: 'ivette.menu.file.open', + label: 'Open Project…', + onClick: openProject +}); + +Dome.onUpdate(() => { + let enabled = Ivette.isProjectLocked(); + Dome.setMenuItem({ id: 'ivette.menu.file.open', enabled }); +}); + +// -------------------------------------------------------------------------- diff --git a/Ivette/backup/Home.js b/Ivette/backup/Home.js new file mode 100644 index 0000000000000000000000000000000000000000..93c98808a6c623b2aecd9316ede4fa4b5c300e12 --- /dev/null +++ b/Ivette/backup/Home.js @@ -0,0 +1,134 @@ +// -------------------------------------------------------------------------- +// --- Project Home View +// -------------------------------------------------------------------------- + +import React from 'react' ; +import Dome from 'dome' ; +import Toolbar from 'dome/layout/toolbars' ; +import { Scroll, Hpack, Vbox, Vfill, Hfill } from 'dome/layout/boxes' ; +import { Splitter } from 'dome/layout/splitters' ; +import { Title, Label, Code, Descr } from 'dome/controls/labels' ; +import { Button, IconButton } from 'dome/controls/buttons' ; +import Ivette from '@ivette' ; +import Project from './Project' ; + +// -------------------------------------------------------------------------- +// --- Generic Dongle +// -------------------------------------------------------------------------- + +function Dongle({ id, label, title, selected, onSelect, children }) +{ + const wident = id && <Code className='ivette-dongle-id' label={id}/> ; + const wlabel = label && <Label label={label} /> ; + const wdescr = title && <Descr label={title} /> ; + const classes = 'ivette-dongle' + + (onSelect ? ' ivette-dongle-selectable' : '') + + (selected ? ' ivette-dongle-selected' : '') ; + return ( + <Hfill className={classes} + onClick={onSelect} > + {wident} + <Vfill> + {wlabel} + {wdescr} + </Vfill> + { children } + </Hfill> + ); +} + +// -------------------------------------------------------------------------- +// --- Module Dongle +// -------------------------------------------------------------------------- + +function ModuleDongle({ module, current, configure }) +{ + let selected = module === current ; + let configuring = configure && configure.modified ; + let configured = configuring && configure.value && configure.value.id === module.id ; + let SELECT = () => Project.setState({ current: module }); + let DISPLAY = () => Project.setState({ current: module, frame:'display' }); + let CONFIGURE = () => { + if (configured) Project.setConfigure(); + else if (!configuring) Project.setConfiguring(module); + }; + return ( + <Dongle id={module.id} + label={module.label} + title={module.title} + selected={selected} + onSelect={SELECT} > + <Toolbar.ButtonGroup> + <Toolbar.Button + icon='DISPLAY' title={'Display ' + module.id} + onClick={DISPLAY} /> + <Toolbar.Button + icon='SETTINGS' title={'Configure ' + module.id} + disabled={configuring && !configured} + onClick={CONFIGURE} /> + </Toolbar.ButtonGroup> + </Dongle> + ); +} + +// -------------------------------------------------------------------------- +// --- Plugin Dongle +// -------------------------------------------------------------------------- + +function PluginDongle({ plugin, configure }) +{ + const CREATE = () => Project.setConfiguring( Ivette.newModule(plugin) ); + return ( + <Dongle label={plugin.label} title={plugin.title} > + <Button icon='CIRC.PLUS' label='New' + title='Create a new Module from this plugin' + kind='positive' + style={{ width:80, height: 32 }} + disabled={configure && configure.modified} + onClick={CREATE} /> + </Dongle> + ); +} + +// -------------------------------------------------------------------------- +// --- Main View +// -------------------------------------------------------------------------- + +export default function Home() +{ + const [ { current,configure } , setState ] = Project.useState(); + const PROJECT = Ivette.getProjectDirectory(); + + const MODULES= Ivette.getModules().map((module) => ( + <ModuleDongle + key={'M' + module.id} + module={module} + current={current} + configure={configure} + /> + )); + + const PLUGINS= Ivette.getPlugins().map((plugin) => ( + <PluginDongle + key={'P' + plugin.id} + plugin={plugin} + configure={configure} + /> + )); + + return ( + <Scroll> + <Vbox> + {PROJECT ? <Title label='Project'/> : null} + {PROJECT ? <div className='ivette-project'><Code>{PROJECT}</Code></div> : null} + {MODULES.length ? <Title label='Modules'/> : null} + {MODULES} + {MODULES.length ? <div style={{height: 32}}/> : null} + {PLUGINS.length ? <Title label='Plugins'/> : null} + {PLUGINS} + </Vbox> + </Scroll> + ); +} + +// -------------------------------------------------------------------------- diff --git a/Ivette/backup/Project.js b/Ivette/backup/Project.js new file mode 100644 index 0000000000000000000000000000000000000000..67e6fa6844307ef1b417f31c348b22977889524b --- /dev/null +++ b/Ivette/backup/Project.js @@ -0,0 +1,101 @@ +// -------------------------------------------------------------------------- +// --- Current State of Project +// -------------------------------------------------------------------------- + +import _ from 'lodash' ; +import React from 'react' ; +import Dome from 'dome' ; +import Dialogs from 'dome/dialogs' ; +import System from 'dome/system' ; +import Ivette from '@ivette' ; +import { Module } from '@ivette/plugins' ; + +// -------------------------------------------------------------------------- +// --- Global State +// -------------------------------------------------------------------------- + +/* + - 'frame': currently displayed frame in main window + - 'current': currently selected module object + - 'configure.module': original configured module + - 'configure.value': edited module properties + - 'configure.error': edited module errors + - 'configure.copied': true if the the target is a fresh copy from another module + - 'configure.modified': true if the value has been edited + */ + +const project = new Dome.State({ frame: 'home' }); + +export const setState = project.setState ; +export const useState = project.useState ; + +const mkSetFrame = (frame) => () => project.setState({frame}); +export const setHome = mkSetFrame('home'); +export const setDisplay = mkSetFrame('display'); +export const setConfigure = mkSetFrame('configure'); + +// -------------------------------------------------------------------------- +// --- Module Helpers +// -------------------------------------------------------------------------- + +export function initConfigValue( module ) +{ + let { id, label, descr } = module ; + let config = _.cloneDeep( module.config ); + return { id, label, descr, config }; +} + +export function setConfiguring( module, onClose ) +{ + if (module instanceof Module) { + let value = initConfigValue( module ); + setState({ + frame: 'configure', + configure: Object.assign( { onClose }, { value, module } ) + }); + } else + console.err( 'Not a plugin instance' , module ); +} + +// -------------------------------------------------------------------------- +// --- Module Helpers +// -------------------------------------------------------------------------- + +export function lookupProject() { + + let argv = System.argv(); + let commandProject = Ivette.lookupProject( argv[0] ); + if (commandProject) return commandProject ; + + let previousProject = Ivette.lookupProject( Dome.getGlobalSetting('ivette.working.project') ); + if (previousProject) return previousProject ; + + let workingProject = Ivette.lookupProject( System.getWorking() ); + if (workingProject) return workingProject ; + + return undefined ; +} + +export function loadProject( dir ) +{ + if (!dir) return ; + Dome.setGlobalSetting('ivette.working.project',dir); + let setup = Ivette.loadProject( dir ); + setup.then( (errors) => errors && errors.length && Dialogs.showMessageBox({ + kind: 'error', + message: 'Error(s) when loading project:\n' + errors.join('\n'), + buttons: [{ label: 'Ok' }] + })).finally(Dome.update); +} + +// -------------------------------------------------------------------------- +// --- Exports Default +// -------------------------------------------------------------------------- + +export default { + useState, setState, setHome, setConfigure, setDisplay, + setConfiguring, initConfigValue, + lookupProject, loadProject +}; + +// -------------------------------------------------------------------------- diff --git a/Ivette/backup/ivette/index.js b/Ivette/backup/ivette/index.js new file mode 100644 index 0000000000000000000000000000000000000000..c9520ab74cf096deef134b5131f51c13fe48fd33 --- /dev/null +++ b/Ivette/backup/ivette/index.js @@ -0,0 +1,455 @@ +/** @module @ivette */ + +import _ from 'lodash' ; +import React from 'react' ; +import Dome from 'dome' ; +import System from 'dome/system' ; +import { Module, Factory, CONFIG, UPDATE } from './plugins' ; +import { Registry } from './stores' ; + +// -------------------------------------------------------------------------- +// --- Plugin & Module Registries +// -------------------------------------------------------------------------- + +const pluginsRegistry = new Registry('plugin'); +const modulesRegistry = new Registry('module'); + +/** + @method + @summary Registered Plugins. + @return {Class[]} an array of `Plugin` classes + */ +export const getPlugins = () => pluginsRegistry.elements() ; + +/** + @method + @summary Registered Modules. + @return {Plugin[]} an array of `Plugin` instances + */ +export const getModules = () => modulesRegistry.elements() ; + +/** + @method + @summary Returns a module by id. + */ +export const getModule = (id) => modulesRegistry.get(id); + +// -------------------------------------------------------------------------- +// --- Register Plugin +// -------------------------------------------------------------------------- + +const checkModule = ( m ) => { + if (!(m instanceof Module)) + throw `Invalid Plugin '${m}'` ; +}; + +const checkPlugin = ( P ) => checkModule( P.prototype ); +const getPluginId = ( m ) => m.constructor.id ; + +/** + @summary Register a (new) plugin. + @param {PLUGIN|Class<Module>} Plugin - + [plugin specification](module-@ivette_plugins.html#~PLUGIN) or + [module class](module-@ivette_plugins.html#Module) + @description + + Register a new plugin in the Ivette system. + + It is recommand to use a [PLUGIN](module-@ivette_plugins.html#~PLUGIN) + object for plugin specification. + If a class is provided, it shall extends the [Module](module-@ivette_plugins.html#Module) + base class and shall have static properties `id`, `label` + and `title` defined. + + Unless your are in development mode (which implies hot module reloading), + it is not permitted to register two plugins with the same identifier, + and an error would be emitted on the console in turn. + */ +function registerPlugin( spec ) +{ + const ThePlugin = typeof(spec)==='object' ? Factory(spec) : spec ; + checkPlugin( ThePlugin ); + const id = ThePlugin.id ; + if (!id) + throw `Invalid plugin: missing identifier` ; + if (!System.DEVEL && pluginsRegistry.get(id)) + throw `Duplicate plugin '${id}'` ; + pluginsRegistry.add( ThePlugin ); + if (System.DEVEL) modulesRegistry.forEach( (module) => { + // Propagates changes from HMR + if (module.constructor.id === ThePlugin.id) Object.setPrototypeOf( module , ThePlugin.prototype ); + }); +} + +// -------------------------------------------------------------------------- +// --- Project Directory +// -------------------------------------------------------------------------- + +let projectDirectory ; + +const getProjectDir = () => { + if (!projectDirectory) return projectDirectory; + let cwd = System.getWorkingDir(); + return cwd ? System.join( cwd , '.ivette' ) : undefined ; +}; +const getProjectIndex = () => System.join( getProjectDir(), 'index.json' ); +const getModuleSession = (mid) => System.join( getProjectDir(), 'modules', mid ); +const getModuleConfig = (mid) => System.join( getProjectDir() , 'config.json' ); + +/** @method + @summary Check is fome module is locked. + @return {boolean} */ +export const isProjectLocked = () => ( + modulesRegistry.find((m) => m.locked()) !== undefined +); + +/** + @method + @summary Returns current project directory. + @return {string} absolute path or undefined */ +export const getProjectDirectory = () => projectDirectory; + +/** + @summary Find enclosing project. + @param {string} path - a file path to starts with + @return {string} project directory holding that path + @description + Looks for the closest directory with name `"*.ivette"` + containing the given path, or the closest directory with a `.ivette` + file at root. + Returns `undefined` if not found. +*/ +export function lookupProject( path ) { + try { + path = System.resolve(path); + let prev ; + while( prev !== path ) + { + if (System.extname(path) === '.ivette' && System.isDirectory(path)) + return path; + let here = System.join( path, '.ivette' ); + if (System.isDirectory(here)) + return here; + prev = path ; + path = System.dirname(path); + } + } catch(_err) { } + return undefined ; +} + +// -------------------------------------------------------------------------- +// --- Project Index +// -------------------------------------------------------------------------- + +const saveIndex = async () => { + let modules = modulesRegistry.elements().map((m) => m.id); + let indexFile = getProjectIndex(); + let indexJSON = JSON.stringify({ modules }); + await System.mkDir( projectDirectory , { recursive: true }); + await System.writeFile( indexFile , indexJSON ); +}; + +const loadIndex = () => { + let indexFile = getProjectIndex(); + if (System.isFile(indexFile)) { + return System.readFile( indexFile ).then((content) => { + try { + return JSON.parse(content); + } catch(err) { + console.warn('[Ivette] invalid index.json:',err); + return {}; + } + }); + } else { + return Promise.resolve({}); + } +}; + +// -------------------------------------------------------------------------- +// --- Module Helpers +// -------------------------------------------------------------------------- + +export const isFresh = (id) => modulesRegistry.isFresh(id); +export const isValid = (id) => modulesRegistry.isValid(id); + +/** + @summary Creates a fresh Plugin instance. + @param {Class} Plugin - a class extending Plugin + @return {Plugin} a fresh module instance + @description + The returned module has a fresh identifier but is not yet registered. + */ +export function newModule( Plugin ) +{ + checkPlugin( Plugin ); + let module = new Plugin(); + module.id = modulesRegistry.fresh( Plugin.id ); + return module; +} + +/** + @summary Creates a fresh duplicate of a Plugin instance. + @param {Module} module - the instance to duplicate + @return {Module} a fresh module instance + @description + The returned module has a fresh identifier but is not yet registered. + It inherits from the original `module` configuration, with tagged label and title. + */ +export function duplicateModule( module ) +{ + let { label, title, constructor: Plugin } = module ; + checkPlugin( Plugin ); + let duplicate = new Plugin(); + duplicate.id = modulesRegistry.fresh( module.id ); + duplicate.label = label && label + " (copy)" ; + duplicate.title = title && title + " (duplicated)" ; + duplicate.config = _.cloneDeep(module.config); + return duplicate ; +} + +/** + @summary Unregister a module (if registered). + @param {Module} module - the module to remove + @return {Promise} resolved when the module has been removed (from disk) + @description + + Remove a module from the current project. + If the module is locked, an exception if raised. + The function does nothing if the module is not registered. + The promise is resolved when the module session directory has been fully removed. + */ +function removeModule( module ) +{ + checkModule( module ); + if (module.locked()) throw `Try to remove locked module '${module}'` ; + modulesRegistry.remove( module.id ); + if (module.session) + return System.rmDir( module.session, { recursive: true } ).then(saveIndex); + else + return saveIndex(); +} + +// -------------------------------------------------------------------------- +// --- Commit Module +// -------------------------------------------------------------------------- + +/** + @summary Commit module updates. + @param {Module} module - the module to update + @param {object} update - the module fields to update with + @param {string} [update.id] - new identifier + @param {string} [update.label] - new display name + @param {string} [update.title] - new short description + @param {object} [update.config] - new configuration + @return {Promise} resolved when the module has been commited (on disk) + @description + + The module is registered in the current project, or updated if already present. + Its session directory is created or renamed if necessary. + Finally, the module is emitted a `Plugin.CONFIG` event. + + */ +export function commitModule( module, { id, label, title, config } ) +{ + checkModule( module ); + if (module.locked()) throw `Try to commit locked module '${id}'` ; + + const oldId = module.id ; + const newId = id || oldId ; + + // Update registry + let index ; // Promise + if ( newId !== oldId ) { + module.id = newId ; + modulesRegistry.remove( oldId ); + modulesRegistry.add( module ); + index = saveIndex(); + } else { + if (!modulesRegistry.get( newId )) { + modulesRegistry.add( module ); + index = saveIndex(); + } + } + + // Update module + if (label !== undefined) module.label = label; + if (title !== undefined) module.title = title; + if (config !== undefined) module.config = config ; + + // Setup session directory + let setup ; // Promise + let oldSession = module.session ; + let newSession = System.join( projectDirectory, 'modules', newId ); + if ( newSession !== oldSession ) { + module.session = newSession ; + if (System.exists( oldSession )) + setup = System.rename( oldSession, newSession ); + else + setup = System.mkDir( newSession, { recursive:true } ); + } else { + if (!System.exists( newSession )) + setup = System.mkDir( newSession , { recursive:true } ); + else + setup = Promise.resolve(); + } + + // Backup config + let configFile = System.join( module.session , 'config.json' ); + if (!id || !label || !title || !config || !System.exists(configFile)) + { + let plugin = getPluginId( module ); + let configJSON = JSON.stringify({ id, label, title, plugin, config }); + setup.then(() => System.writeFile( configFile , configJSON )); + } + + // Batch updates and finally emit config event + return Promise.all([index,setup]).finally(() => module.emit( CONFIG )); +} + +// -------------------------------------------------------------------------- +// --- Project Management +// -------------------------------------------------------------------------- + +function loadProjectModule(id) +{ + if (modulesRegistry.get(id)) + return Promise.reject('Duplicate module'); + let session = System.join( projectDirectory, 'modules', id ); + let configFile = System.join( session , 'config.json' ); + return System.readFile( configFile ) + .then( (configJSON) => { + let moduleConfig = JSON.parse(configJSON); + let { label, title, plugin, config } = moduleConfig ; + let P = pluginsRegistry.get( plugin ); + if (!P) throw `Invalid plugin identifier ('${plugin}')` ; + let module = new P(); + module.id = id ; + module.label = label ; + module.title = title ; + module.config = config ; + modulesRegistry.add( module ); + module.emit( CONFIG ); + }); +} + +function reportLoadModule(id) { + return loadProjectModule(id) + .then(() => undefined) + .catch((err) => `Error with module ${id}: ${err}`); +} + +/** Change project directory. + @param {string} path - the directory of the project + @return {Promise} returning an array of errors +*/ +export function loadProject( path ) { + if (isProjectLocked()) throw 'Try to close locked project' ; + if (!path) throw 'Try to open empty project' ; + projectDirectory = path ; + modulesRegistry.clear(); + return loadIndex() + .then(({ modules=[] }) => Promise.all(modules.map(reportLoadModule))) + .then((errors) => errors.filter((e) => e !== undefined)); +} + +// -------------------------------------------------------------------------- +// --- Plugin Hooks +// -------------------------------------------------------------------------- + +const ModuleContext = React.createContext(); + +/** + @class + @summary Set the current module for children components. + @property {Module} module - the current module (can be `'undefined'`) + @property {React.Children} children - content to be rendered with the current module + */ +export const ProvideModule = ({ module, children }) => ( + <ModuleContext.Provider value={module}> + {children} + </ModuleContext.Provider> +); + +/** + @method + @summary Use the current module (Custom React Hook). + @return {Module} the current module + @description + Convenient method to obtain the current module. Does _not_ update on events. +*/ +export const useModule = () => React.useContext(ModuleContext); + +/** + @method + @summary Listen to (current) module event (Custom React Hook). + @parameter {string} event - the plugin event to listen on + @parameter {function} callback - the callback on event + @return {Plugin} the plugin instance of the current module + @description + Same as `Dome.useEmitter(module,event,callback)` with the current module. + The hook itself does not force update, unless the callback does. +*/ +export const useEvent = (event,callback) => { + let module = React.useContext(ModuleContext); + Dome.useEmitter( module, event, callback ); +}; + +/** + @method + @summary Use the current module with optional update on events (Custom React Hook). + @parameter {string} [events...] - the event(s) to listen on, in addition to `UPDATE` + @return {Module} the current module + @description + Convenient method to obtain the current module and connect to updating events. +*/ +export const useUpdate = (...events) => { + let module = React.useContext(ModuleContext); + let callback = Dome.useForceUpdate(); + React.useEffect(() => { + if (module) { + events.push(UPDATE); + events.forEach((evt) => module.on(evt,callback)); + return () => events.forEach((evt) => module.off(evt,callback)); + } else + return undefined; + }); + return module ; +}; + +/** + @method + @summary Returns the current module configuration (Custom React Hook). + @return {Module} the plugin configuration (up-to-date) + @description + Equivalent to `useUpdate(CONFIG).config` unless there is no current module. +*/ +export const useConfig = () => { + let m = useUpdate(CONFIG); + return m && m.config; +}; + +// -------------------------------------------------------------------------- +// --- Export Default +// -------------------------------------------------------------------------- + +export default { + registerPlugin, + getPlugins, + getModules, + isProjectLocked, + getProjectDirectory, + loadProject, + lookupProject, + isFresh, isValid, + newModule, + duplicateModule, + commitModule, + removeModule, + ProvideModule, + useModule, + useEvent, + useUpdate, + useConfig +}; + +// -------------------------------------------------------------------------- diff --git a/Ivette/backup/ivette/plugins.js b/Ivette/backup/ivette/plugins.js new file mode 100644 index 0000000000000000000000000000000000000000..90cd687daf85b53a1434799d7504ddd0bef6017f --- /dev/null +++ b/Ivette/backup/ivette/plugins.js @@ -0,0 +1,247 @@ +// -------------------------------------------------------------------------- +// --- Plugin Base Class +// -------------------------------------------------------------------------- + +/** @module @ivette/plugins */ + +import _ from 'lodash' ; +import React from 'react' ; +import Dome from 'dome' ; +import EventEmitter from 'events' ; + +/** + @event + @description + Triggered when a module is asked for killing its pending jobs. +*/ +export const KILL = 'ivette.kill' ; + +/** + @event + @description + Triggered when a module enters in locked state +*/ +export const LOCK = 'ivette.lock' ; + +/** + @event + @description + Triggered when a module is back to unlocked state +*/ +export const UNLOCK = 'ivette.unlock' ; + +/** + @event + @description + Triggered when a plugin has been configured +*/ +export const CONFIG = 'ivette.config' ; + +/** + @event + @description + Triggered when a plugin has been updated +*/ +export const UPDATE = 'ivette.update' ; + +/** + @summary Base class for Module instances. + @property {string} id - Module identifier + @property {string} [label] - Module display name + @property {string} [title] - Module short description + @property {object} config - Module configuration object + @property {string} session - Module session directory + @description + Each Ivette module is associated to a global object maintaining its internal state. + A `Plugin` is a class responsible for creating and managing the internal state of a module. + It is also responsible for rendering the module main view, its toolbar and sidebar items, + and configuration fields. +*/ +export class Module extends EventEmitter { + + constructor() { + super(); + this.config = {} ; + let _lock = { sem: 0 } ; + let _LOCKED = () => _lock.sem > 0 ; + let _LOCK = () => { + if (_lock.sem == 0) this.emit(LOCK); + _lock.sem++; + } ; + let _UNLOCK = () => { + _lock.sem--; + if (_lock.sem == 0) this.emit(UNLOCK); + if (_lock.sem < 0) { + console.warn(`[Ivette:${this.id}] unbalanced lock/unlock`,this.id); + _lock.sem = 0 ; + } + } ; + let _SYNCHRO = (p,k) => { + _LOCK() ; + if (k) this.once(KILL,k); + p.finally(() => { + if (k) this.off(KILL,k); + _UNLOCK(); + }); + return p; + } ; + this.lock = _LOCK ; + this.unlock = _UNLOCK ; + this.locked = _LOCKED ; + this.synchronize = _SYNCHRO ; + this.renderMain = this.renderMain.bind(this); + this.renderConfig = this.renderConfig.bind(this); + } + + // -------------------------------------------------------------------------- + // --- Locking + // -------------------------------------------------------------------------- + + /** + @summary Lock the plugin. + @description + Prevents the module from being re-configured. + Nested calls to `lock/unlock` shall be well balanced. + It is preferrable to use `this.synchronize()` instead. + Emits the signal `'ivette.lock'` unless already locked. + */ + lock() {} // privately defined by constructor + + /** + @summary Unlock the plugin. + @description + Cancel the last `lock()` call effect. + Nested calls to `lock/unlock` shall be well balanced. + It is preferrable to use `this.synchronize()` instead. + Emits the signal `'ivette.unlock'` when actually unlocked. + */ + unlock() {} // privately defined by constructor + + /** Whether the module is currenly locked or not. + @return {boolean} the locked status of the module. */ + locked() {} // privately defined by constructor + + /** + @summary Lock the module until a promise is pending. + @param {Promise} job - the promise to lock on + @param {function} kill - a callback to kill the job + @return {Promise} the job, for chaining + @description + Locks the module and wait for the promise to terminate + (normally or with an error) before unlocking. The callback is triggered + if the module is asked to be killed while the job is still running. + */ + synchronize() {} // privately defined by constructor + + /** + @summary Promise awaiting until unlocked. + @return {Promise} awaiting promise + @description + The returned promise is resolved once the + plugin is unlocked. It is immediately resolved + if not locked. + */ + wait() { + if ( !this.locked() ) { + return Promise.resolved(); + } else { + return new Promise((resolve,reject) => this.once(UNLOCK,resolve)); + } + } + + /** + @summary Interrupts pending tasks. + @description + Emits the `'ivette.kill'` signal. + Any currently running job shall be interrupted, + and the module shall eventually be unlocked. + @return {Promise} a promise resolved once unlocked + */ + kill() { + this.emit(KILL); + return this.wait(); + } + + // -------------------------------------------------------------------------- + // --- Render + // -------------------------------------------------------------------------- + + /** + @summary Emits the `@ivette.plugins.UPDATE` event. + */ + update() { + this.emit(UPDATE); + } + + /** + @summary Main view for the plugin. + @return {React.Children} the main view for the module + @description + See also the '@ivette/views' for defining sidebars and toolbars. + */ + renderMain() { + return null; + } + + /** + @summary Configuration view for the plugin. + @return {React.Children} form fields for configuring the plugin + */ + renderConfig() { + return null; + } + +} + +// -------------------------------------------------------------------------- +// --- Plugin Factory +// -------------------------------------------------------------------------- + +/** + @typedef PLUGIN + @summary Plugin Specification + @property {string} id - plugin identifier + @property {string} [label] - display name + @property {string} [title] - short description + @property {function} [initializer] - module initializer + @property {React.Element} [mainView] - main view + @property {React.Element} [configView] - configuration view + @description + + Properties for [registerPlugin](module-@ivette.html#registerPlugin) + specification. + + The `initializer` function, when specified, + is invoked once on each plugin instance. + The initializer function can be written as follows: + - `initializer() { ... this.XXX ... }` + - `initializer: function() { ... this.XXX ... }` + - `initializer: (module) => { ... module.XXX ... }` + + Typical usage of `initializer` is to initialize specific module properties + and register static callbacks on module events like `CONFIG` and `KILL`. +*/ + +export function Factory(spec) { + const { id, label, title, mainView, configView, initializer } = spec; + + class Plugin extends Module { + constructor() { + super(); + initializer && initializer.apply(this, [this]); + } + renderMain() { return mainView; } + renderConfig() { return configView; } + }; + Plugin.id = id; + Plugin.label = label; + Plugin.title = title; + + return Plugin; +} + +// -------------------------------------------------------------------------- + +export default { Module, Factory, KILL, LOCK, UNLOCK, CONFIG, UPDATE } ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/backup/ivette/stores.js b/Ivette/backup/ivette/stores.js new file mode 100644 index 0000000000000000000000000000000000000000..201516c5d51c64ebd743c5ee7d80f012e909c85e --- /dev/null +++ b/Ivette/backup/ivette/stores.js @@ -0,0 +1,152 @@ +// -------------------------------------------------------------------------- +// --- Items Registry +// -------------------------------------------------------------------------- + +/** @module @ivette/stores */ + +import _ from 'lodash' ; + +const ALL = () => true ; +const IDENT = /^[a-zA-Z0-9_-]+$/ ; +const SUFFIX = /-[0-9]+$/ ; +const PADDING = (n) => n<10 ? "0"+n : n ; + +/** + @summary Base class for registries. + */ +export class Registry +{ + + /** @param {string} prefix - fresh identifier prefix */ + constructor( prefix ) { + this.items = {} ; + this.prefix = prefix ; + } + + /** + @summary Valid identifiers (letters, digits, dashes and underscores). + @return {boolean} `true` if the identifier is valid + */ + isValid(id) { + return typeof(id)=='string' && id.match( IDENT ); + } + + /** + @summary Test for freshness identifier. + @return {boolean} `true` if the identifier is not yet attributed + */ + isFresh(id) { + return !this.items[id] ; + } + + /** + @summary Creates an identifier. + @param {string} [id] - the base identifier to starts with + @return {string} a fresh identifier + @description + Returns a fresh identifier with format `<base>-<n>` where + the base is extracted from `id` (without its `-<n>` suffix, if any). + The default base is the registry prefix, if any. + */ + fresh(id) { + let base = this.prefix ; + if (id) { + let m = SUFFIX.exec(id); + base = m ? id.substring(0,m.index) : id ; + } + base += '-' ; + let kid = 1 ; + for( ;; ) { + var a = base + PADDING(kid++) ; + if (!this.items[a]) break ; + } + return a ; + } + + /** + @summary Iterates ovee the registry. + @param {function} job - called with `job(item,id)` in unspecified order + @description + If the iteratee returns `false`, the iteration is interrupted. + */ + forEach(job) { _.forEach( this.items , (item,id) => job(item,id) ); + } + + /** + @summary Iterates ovee the registry. + @param {function} test - called with `test(item,id)` in unspecified order + @description + Returns the first item such that `test(item,id)` returns a truthy value. + Returns `undefined` otherwise. + */ + find(test) { _.find( this.items , (item,id) => test(item,id) ); } + + /** + Select items from the registry + @param {object} [options] - filter and ordering options + @return {item[]} the selected array of items + @description +Available options are: +- `filter:(item) => boolean` to select some itmes (default: all) +- `sortBy:function | function[] | field | field[]` to sort items by (default: by identifier) + +Sorting is done by loadsh [sortBy](https://lodash.com/docs/4.17.11#sortBy) method. + */ + elements( options ) + { + const filter = (options && options.filter) || ALL ; + const sortBy = (options && options.sortBy) || 'id' ; + const pool = []; + _.forEach( this.items, (item) => { + if (filter(item)) pool.push(item); + }); + return _.sortBy(pool,sortBy); + } + + /** Register a new item + @param {object} - the item to register in + @param {once} - register only fresh items + @description +Each object shall define the following properties: +- `id:string` item identifier (default to `fresh()`) +- `label:string` _optional_ item display name +- `title:string` _optional_ item short description + */ + add( item, once=false ) { + if (!item.id) item.id = this.fresh(); + if (!this.isValid(item.id)) { + console.warn( `[Ivette:${this.prefix}] invalid identifier (${item.id})` ); + return ; + } + if (once && !this.isFresh(item.id)) { + console.warn( `[Ivette:${this.prefix}] duplicate identifier (${item.id})` ); + return ; + } + this.items[item.id] = item ; + } + + /** Retrieve an item by id + @param {string} id - item identifier + @return {object} the associated item + */ + get(id) { return id ? this.items[id] : undefined; } + + /** Remove an item by id + @param {string} id - item identifier + */ + remove( id ) { + if (id && this.items[id]) { + delete this.items[id]; + } + } + + /** Remove all items */ + clear() { + this.items = {}; + } + +} + +export default { Registry }; + +// -------------------------------------------------------------------------- diff --git a/Ivette/backup/ivette/views.js b/Ivette/backup/ivette/views.js new file mode 100644 index 0000000000000000000000000000000000000000..4b80dfc0ee5f75468071d485e17cc31d2e641b5e --- /dev/null +++ b/Ivette/backup/ivette/views.js @@ -0,0 +1,42 @@ +// -------------------------------------------------------------------------- +// --- Lab View Component +// -------------------------------------------------------------------------- + +/** @module @ivette/views */ + +import _ from 'lodash' ; +import React from 'react' ; +import { Catch } from 'dome/errors' ; +import { Item } from 'dome/layout/dispatch' ; + +import Ivette from '@ivette' ; + +/** + @class + @summary Defines the plugin toolbar + @description + Shall be defined once inside main plugin rendering. +*/ +export const PluginToolbar = ({children}) => ( + <Item id='ivette.toolbar.display'> + <Catch label='Plugin Toolbar'>{ children }</Catch> + </Item> +); + +/** + @class + @summary Defines the plugin toolbar + @description + Shall be defined once inside main plugin rendering. +*/ +export const PluginSidebar = ({children}) => ( + <Item id='ivette.sidebar.display'> + <Catch label='Plugin Sidevar'>{ children }</Catch> + </Item> +); + +// -------------------------------------------------------------------------- + +export default { PluginSidebar, PluginToolbar }; + +// -------------------------------------------------------------------------- diff --git a/Ivette/backup/sandbox/Events.js b/Ivette/backup/sandbox/Events.js new file mode 100644 index 0000000000000000000000000000000000000000..ab8069cbcd73b78d2313025fd3da71b3d5e087a2 --- /dev/null +++ b/Ivette/backup/sandbox/Events.js @@ -0,0 +1,7 @@ +// -------------------------------------------------------------------------- +// --- Frama-C Events +// -------------------------------------------------------------------------- + +export const reload = 'frama-c.reload' ; + +export default { reload } ; diff --git a/Ivette/backup/sandbox/Project.js b/Ivette/backup/sandbox/Project.js new file mode 100644 index 0000000000000000000000000000000000000000..37d33df468aedf4ad087430193c8e6ba1c18d445 --- /dev/null +++ b/Ivette/backup/sandbox/Project.js @@ -0,0 +1,206 @@ +import React, { useState, useEffect } from 'react'; +import { showOpenFiles } from 'dome/dialogs'; +import { Button } from 'dome/controls/buttons'; +import { Label } from 'dome/controls/labels'; +import { Badge } from 'dome/controls/icons'; +import { Hbox, Vbox } from 'dome/layout/boxes'; +import Server from './server'; +import { Set } from 'immutable'; + +class SelectList extends React.Component { + render() { + return ( + <select value={this.props.value} onChange={this.props.onChange}> + {this.props.values.map(v => <option key={v.id}>{v.name}</option>)} + </select> + ) + } +} + +function FileSelect(props) { + const [files, setFiles] = useState(Set([])); + const [addedFiles, setAddedFiles] = useState(Set([])); + const [removedFiles, setRemovedFiles] = useState(Set([])); + + function updateFiles() { + Server + .sendGET("kernel.ast.getFiles", [], false) + .then( + (data) => { + console.log("success: " + data + '\n'); + setFiles(Set(data)); + setAddedFiles(Set([])); + setRemovedFiles(Set([])); + }, + (_rid, data) => { + console.log("err:" + data + '\n') + }); + }; + + //Done only once + useEffect(updateFiles, []); + + function addFiles() { + showOpenFiles({ message: "Add files" }) + .then(files => { + setAddedFiles(() => { + const sfiles = Set(files); + const res = addedFiles.union(sfiles); + return res + }) + }); + }; + + function generateItem(v) { + const removed = removedFiles.has(v); + const added = addedFiles.has(v); + return ( + <Hbox key={v}> + <Label + style={(removed ? { color: 'red' } : (added ? { color: 'green' } : {}))}> + {v} + </Label> + <Badge + value={removed ? 'CIRC.PLUS' : 'CIRC.MINUS'} + onClick={() => + setRemovedFiles(() => + removed ? removedFiles.remove(v) : removedFiles.add(v)) + } /> + </Hbox> + ) + }; + + function sendFiles() { + const filesToSend = files.union(addedFiles).subtract(removedFiles); + Server + .sendSET("kernel.ast.setFiles", filesToSend.toArray(), false) + .then( + () => { + console.log("setFiles: success"); + Server + .sendEXEC("kernel.ast.execCompute", [], false) + .then( + () => { + console.log("execComput: success"); + updateFiles(); + }, + (_rid, data) => { + console.log("execCompute err:" + data + '\n') + } + ); + }, + (_rid, data) => { + console.log("setFiles err:" + data + '\n') + } + ); + }; + + return ( + <Vbox> + {files.map(generateItem)} + {addedFiles.map(generateItem)} + <Hbox> + <Button label='Add files' onClick={addFiles} /> + <Button label='Update' onClick={sendFiles} /> + </Hbox> + </Vbox> + ) +} + +function Projects(props) { + const [projects, setProjects] = useState([]); + const [current, setCurrent] = useState(undefined); + const [newName, setNewName] = useState("project_name"); + + + function updateProjects() { + Server + .sendGET("kernel.project.getList", [], false) + .then( + (data) => { + console.log("success: " + data.datadir + '\n'); + setProjects(data) + }, + (_rid, data) => { + console.log("err:" + data + '\n') + }); + }; + + //Done only once + useEffect(updateProjects, []); + + function new_project() { + Server + .sendSET("kernel.project.setCreate", newName, false) + .then( + (data) => { + console.log("success: " + data.datadir + '\n'); + updateProjects(); + }, + (_rid, data) => { + console.log("err:" + data + '\n') + }); + }; + + + console.log("projects:", projects); + return ( + <Hbox> + <form onSubmit={new_project}> + <label> + Name of new project : + <input + type="text" + value={newName} + onChange={event => setNewName(event.target.value)} + /> + </label> + <input type="submit" value="Create" /> + </form> + <label> + Current project: + <SelectList + values={projects} + value={current} + onChange={event => setCurrent(event.target.value)} + /> + </label> + </Hbox> + ) +} + +function Kernel(props) { + const [state, setState] = useState("undefined"); + + function getCfg() { + console.log("send request\n"); + Server + .sendGET("kernel.getConfig", [], false) + .then( + (data) => { + console.log("success: " + data.datadir + '\n'); + setState(data.datadir); + }, + (_rid, data) => { + console.log("err:" + data + '\n') + }); + }; + + return ( + <Hbox> + <Button label='GetConfig' onClick={getCfg} /> + <Label label={state} /> + </Hbox> + ) +} + +export default function Project(props) { + + return ( + <> + <Kernel /> + <Projects /> + <FileSelect /> + </> + ) +} \ No newline at end of file diff --git a/Ivette/backup/sandbox/Properties.js b/Ivette/backup/sandbox/Properties.js new file mode 100644 index 0000000000000000000000000000000000000000..ac8e770bef928215afea13c5dc33985af090daf4 --- /dev/null +++ b/Ivette/backup/sandbox/Properties.js @@ -0,0 +1,137 @@ +// -------------------------------------------------------------------------- +// --- Frama-C Properties Table +// -------------------------------------------------------------------------- + +import React from 'react' ; +import Dome from 'dome' ; +import { useState, useEffect } from 'react' ; + +import { Button } from 'dome/controls/buttons'; +import { Vfill, Vbox, Scroll } from 'dome/layout/boxes' ; +import { Splitter } from 'dome/layout/splitters' ; +import { Column, Table } from 'dome/table/views' ; +import { ArrayModel } from 'dome/table/arrays' ; +import { Form, Section, FieldList, FieldCheckbox, FieldRadio } from 'dome/layout/forms' ; + +import Server from './server.js' ; +import Events from './Events.js' ; + +export default function Properties (props) { + const model = props.properties; + + /* --- Columns of the table ----------------------------------------------- */ + + const columnFile = <Column id='file' + label='File' />; + const columnFct = <Column id='fct' + label='Function' />; + const columnProp = <Column id='property' + label='Property' + fill />; + const columnStatus = <Column id='status' + label='Status' />; + + /* The default columns displayed. The property column is always shown. */ + const defaultColumns = + { path:false, + fct:true, + status:true, + }; + /* The columns displayed. Set by the user through a form. */ + const [columnsValue, _] = useState(defaultColumns); + + /* Builds the array of columns according to [columnsValue]. */ + function makeColumns () { + const columns = new Array(); + if (columnsValue.path) + columns.push(columnFile); + if (columnsValue.fct) + columns.push(columnFct); + columns.push(columnProp); // Always shown. + if (columnsValue.status) + columns.push(columnStatus); + return columns; + } + + /* The columns array used by the table. */ + const [ columns, setColumns ] = useState(makeColumns()); + + function onChangeColumns () { + setColumns(makeColumns()); + } + + /* Form to choose the columns displayed. */ + const columns_list = + <Form value={columnsValue} onChange={onChangeColumns} > + <Section label="Columns" unfold='false' > + <FieldCheckbox label="File" path='path' /> + <FieldCheckbox label="Function" path='fct' /> + <FieldCheckbox label="Status" path='status' /> + </Section> + </Form>; + + /* --- Filters of logical properties ------------------------------------- */ + + /* All properties are shown by default. */ + const default_status = + { valid:true, + valid_hyp:true, + unknown:true, + invalid:true, + invalid_hyp:true, + considered_valid:true, + untried:true, + dead:true, + inconsistent:true + }; + const [status, setStatus] = useState(default_status); + + /* Function filtering the properties by status. */ + function filter (item) { + switch (item.status) { + case 'Valid': + case 'Valid_but_dead': return status.valid; + case 'Valid_under_hyp': return status.valid_hyp; + case 'Invalid': + case 'Invalid_but_dead': return status.invalid; + case 'Invalid_under_hyp': return status.invalid_hyp; + case 'Unknown': + case 'Unknown_but_dead': return status.unknown; + case 'Considered_valid': return status.considered_valid; + case 'Never_tried': return status.untried; + case 'Dead': return status.dead; + case 'Inconsistent': return status.inconsistent; + default: return true; + } + } + + function onChangeFilter (value, error) { + model.setFiltering(filter); + } + + /* Filters selection. */ + const filter_list = + <Form value={status} onChange={onChangeFilter} > + <Section label="Status" unfold='true' > + <FieldCheckbox label="Valid" path='valid' /> + <FieldCheckbox label="Valid under hyp." path='valid_hyp' /> + <FieldCheckbox label="Unknown" path='unknown' /> + <FieldCheckbox label="Invalid" path='invalid' /> + <FieldCheckbox label="Invalid under hyp." path='invalid_hyp' /> + <FieldCheckbox label="Considered valid" path='considered_valid' /> + <FieldCheckbox label="Untried" path='untried' /> + <FieldCheckbox label="Dead" path='dead' /> + <FieldCheckbox label="Inconsistent" path='inconsistent' /> + </Section> + </Form>; + + /* Table of logical properties. */ + const table = <Table model={model} children={columns} />; + + return ( + <Splitter dir='LEFT' > + <Vfill> <Scroll> {filter_list} {columns_list} </Scroll> </Vfill> + <Vfill> {table} </Vfill> + </Splitter> + ) +} diff --git a/Ivette/backup/sandbox/SourceCode.js b/Ivette/backup/sandbox/SourceCode.js new file mode 100644 index 0000000000000000000000000000000000000000..023eeafbfb30a162fb9aebacb2217358969aec90 --- /dev/null +++ b/Ivette/backup/sandbox/SourceCode.js @@ -0,0 +1,129 @@ +// -------------------------------------------------------------------------- +// --- Frama-C Source Panel +// ------------------------------------------------------------------------- + +import React from 'react' ; +import Dome from 'dome' ; + +import { Button } from 'dome/controls/buttons'; +import Toolbar from 'dome/layout/toolbars' ; +import { Hbox, Hfill, Vbox, Vfill, Space } from 'dome/layout/boxes' ; +import { Splitter } from 'dome/layout/splitters' ; +import { Column, Table } from 'dome/table/views' ; +import { Text } from 'dome/text/editors' ; +import Server from './server.js' ; +import Events from './Events.js' ; + +import { useState, useEffect } from 'react' ; + +import 'codemirror/mode/clike/clike.js'; +import 'codemirror/theme/ambiance.css' ; +import 'codemirror/theme/solarized.css'; + +/* Pretty prints the source code from [text] in [buffer]. */ +function printSource (buffer, text) { + if (text === null) return; + if (Array.isArray(text)) { + const tag = text.shift(); + if (tag !== '') { + buffer.openTextMarker( { id:tag } ); + text.forEach(txt => printSource(buffer, txt)); + buffer.closeTextMarker(); + } else + text.forEach(txt => printSource(buffer, txt)); + } else + buffer.append(text); +} + +/* Display the list of functions and the source code for the selected function + in the list. */ +export default function Source (props) { + /* Buffer for the source code. */ + const buffer = props.sourceCode; + /* Model for the function list. */ + const model = props.functions; + + /* Print the source code of the function [data.fct]. */ + function printFunction (data) { + console.log("Select function: " + data.fct); + Server.sendGET("kernel.ast.printFunction", data.fct, false).then + ( data => { + buffer.clear(); + printSource(buffer, data); + }); + } + + const [ theme, setTheme ] = useState('default'); + function selectTheme (name) { + return function () { setTheme(name); } + } + + function contextMenu (data) { + const item1 = { label:"Default", onClick:selectTheme("default") }; + const item2 = { label:"Ambiance", onClick:selectTheme("ambiance") }; + const item3 = { label:"Solarized light", onClick:selectTheme("solarized light") }; + const item4 = { label:"Solarized dark", onClick:selectTheme("solarized dark") }; + Dome.popupMenu([item1, item2, item3, item4]).catch(() => {}); + } + + /* Table for the function list. */ + const table = + <Table model={model} + onSelection={printFunction} > + <Column id='fct' + label='Functions' + title='List of functions in the current Frama-C project' /> + </Table>; + + const [ lineWrapping, setLineWrapping ] = useState(false); + function changeLineWrapping () { setLineWrapping(!lineWrapping); } + + const code = <Text buffer={buffer} + mode='text/x-csrc' + theme={theme} + lineWrapping={lineWrapping} + readOnly />; + + const [ fontSize, setFontSize ] = useState(12); + function increaseFontSize () { setFontSize(fontSize + 2); } + function decreaseFontSize () { setFontSize(fontSize - 2); } + + const toolbar = + <Toolbar.ToolBar> + <Toolbar.Space/> + <Toolbar.Select + value={theme} + onChange={(name) => {selectTheme(name)();}} > + <option value='default' label='Default'/> + <option value='ambiance' label='Ambiance'/> + <option value='solarized light' label='Solarized light'/> + <option value='solarized dark' label='Solarized dark'/> + </Toolbar.Select> + <Toolbar.ButtonGroup> + <Toolbar.Button + icon='MINUS' + title='Decrease the font size' + onClick={decreaseFontSize} + /> + <Toolbar.Button + icon='PLUS' + title='Increase the font size' + onClick={increaseFontSize} + /> + </Toolbar.ButtonGroup> + <Toolbar.Button icon={lineWrapping ? "CHECK" : "CROSS"} + label="Line wrapping" + title="Change line wrapping mode" + onClick={changeLineWrapping} /> + </Toolbar.ToolBar>; + + return ( + <Splitter dir='LEFT' > + <Vfill style={{ minWidth: 100 }}> {table} </Vfill> + <Vfill onContextMenu={contextMenu} style={{ fontSize: fontSize }} > + {toolbar} + {code} + </Vfill> + </Splitter> + ); +} diff --git a/Ivette/backup/sandbox/SourceFiles.js b/Ivette/backup/sandbox/SourceFiles.js new file mode 100644 index 0000000000000000000000000000000000000000..8a7386b57064bb60670ecca9b6145651e6b236c5 --- /dev/null +++ b/Ivette/backup/sandbox/SourceFiles.js @@ -0,0 +1,44 @@ +import React, { useState, useEffect } from 'react'; +import { Buffer } from 'dome/text/buffers' +import { Text } from 'dome/text/editors'; +import Server from './server'; +import System from 'dome/system'; +import 'codemirror/mode/clike/clike.js'; + +export default function SourceFiles() { + + const [filenames, setFilenames] = useState([]); + const buffer = new Buffer({ mode: 'text/x-csrc' }); + + function getSourceFilenames() { + console.log('SourceFiles::getFiles'); + + Server + .sendGET("kernel.ast.getFiles", [], false) + .then( + (fnames) => { + console.log('Got source filenames:' + fnames); + setFilenames(fnames); + }); + } + + useEffect(getSourceFilenames, []); + + useEffect(() => { + if (filenames.length > 0) { + console.log('Displaying ' + filenames[0] + '!'); + System + .readFile(filenames[0]) + .then( + (fcontent) => { + console.log('Got file content: ' + fcontent); + buffer.clear(); + buffer.append(fcontent); + }); + } + }, [filenames]) + + return ( + <Text buffer={buffer} readOnly='true' lineNumbers='true' /> + ) +} diff --git a/Ivette/backup/sandbox/index.js b/Ivette/backup/sandbox/index.js new file mode 100644 index 0000000000000000000000000000000000000000..a47d41f75e748ffa3b91cfac0e0ea8b617d936a2 --- /dev/null +++ b/Ivette/backup/sandbox/index.js @@ -0,0 +1,195 @@ +// -------------------------------------------------------------------------- +// --- Frama-C Ivette Plug-in +// -------------------------------------------------------------------------- + +import React from 'react' ; +import Dome from 'dome' ; +import Toolbar from 'dome/layout/toolbars' ; +import { GridItem, GridHbox, GridVbox } from 'dome/layout/grids' ; +import { Code } from 'dome/controls/labels' ; +import Ivette from '@ivette' ; +import { Module } from '@ivette/plugins' ; +import { PluginToolbar } from '@ivette/views' ; +import { LabView, View, Group, Component } from '@ivette/labviews' ; +import { Buffer } from 'dome/text/buffers' ; +import { ArrayModel } from 'dome/table/arrays' ; +import Dialogs from 'dome/dialogs'; +import Server from './server'; +import SourceFiles from './SourceFiles'; +import Events from './Events'; +import SourceCode from './SourceCode'; +import Properties from './Properties'; +import Project from "./Project"; + +// -------------------------------------------------------------------------- +// --- Frama-C Plugin +// -------------------------------------------------------------------------- + +/* Load a Frama-C session. */ +function LoadSession () { + Dialogs.showOpenFile({message: 'Select a Frama-C save file'}).then + ( path => { + if (path) { + console.log("Load session, path selected: " + path); + Server.sendSET("kernel.load",path,false).then + ( err => { + if (err) { + let message = + { kind: 'error', + title: 'Error while loading the Frama-C session', + message: err, + buttons: [{ label: 'Ok' }] + }; + Dialogs.showMessageBox(message); + } else { + Dome.emit(Events.reload); + console.log("Project successfully loaded."); + } + }); + } else + console.log("Load session: no path selected."); + }); +} + +function emitReload () { + Dome.emit(Events.reload); +} + +export class FramaC extends Module { + + constructor() + { + super(); + this.sourceCode = new Buffer ({ mode:'text/x-csrc' }); + this.functions = new ArrayModel (); + this.getFunctions = this.getFunctions.bind(this); + this.properties = new ArrayModel (); + this.getProperties = this.getProperties.bind(this); + Server.startServer(); + Dome.addMenuItem({ + menu: 'File', + id: 'ivette.menu.file.load', + label: 'Load session', + key: 'Cmd+L', + onClick: LoadSession + }); + } + + /* Get the list of functions from the server, and fill [this.functions]. */ + getFunctions () { + Server.sendGET("kernel.ast.getFunctions", [], false).then + ( data => { + console.log("Collecting " + data.length + " functions."); + this.functions.clear(); + const array = new Array(data.length); + data.forEach( (fct, index) => { array[index] = {fct: fct}; } ); + this.functions.setData(array); + }); + } + + /* Get the list of properties from the server, and fill [this.properties]. */ + getProperties () { + Server.sendGET("kernel.ast.getProperties", [], false).then + ( data => { + this.properties.clear(); + const array = new Array(data.length); + data.forEach( (item, index) => { + array[index] = { property: item.property, + fct: item.function, + status: item.status, + file: item.file }; + }); + this.properties.setData(array); + }); + } + + renderMain() { + let [ custom, setCustom ] = Dome.useState('sandbox.custom',false); + Dome.useEvent(Events.reload, this.getFunctions); + Dome.useEvent(Events.reload, this.getProperties); + return ( + <React.Fragment> + <PluginToolbar> + <Toolbar.Button + icon='FILE' + label='Load' + title='Load a Frama-C session' + onClick={LoadSession} + /> + <Toolbar.Filler/> + <Toolbar.Button + icon='RELOAD' + title='Reload the tables' + onClick={emitReload} + /> + <Toolbar.Button + icon='ITEMS.GRID' + title='Customize Main View' + selected={custom} + onClick={() => setCustom(!custom)}/> + </PluginToolbar> + <LabView + customize={custom} + settings='sandbox.labview' + > + <View id='lab.main' label='Lab View' defaultView > + <GridItem id='kernel.props' /> + </View> + <View id='lab.eva' label='EVA Lab'> + <GridHbox> + <GridItem id='kernel.globals' /> + <GridItem id='plugins.eva' /> + </GridHbox> + </View> + <View id='lab.wp' label='WP Lab'> + <GridHbox> + <GridItem id='kernel.globals' /> + <GridItem id='plugins.wp' /> + </GridHbox> + </View> + <Component id='dashboard' label='Dashboard'/> + <Group id='kernel' label='Kernel'> + <Component id='kernel.project' label='Projects' > + <Project /> + </Component> + <Component id='kernel.source' label='Source Code' > + <SourceCode functions={this.functions} + sourceCode={this.sourceCode} /> + </Component> + <Component id='kernel.files' label='Source Files'> + <SourceFiles /> + <Dome.Render> + {() => { + let m = Ivette.useModule(); + return (<Code> Module: {m.id} </Code>); + }} + </Dome.Render> + </Component> + <Component id='kernel.globals' label='Globals Index' /> + <Component id='kernel.ast' label='AST Inspector' /> + <Component id='kernel.props' label='Properties Status' > + <Properties properties={this.properties} /> + </Component> + </Group> + <Group id='plugins' label='Plugins'> + <Component id='plugins.eva' label='Frama-C / EVA' /> + <Component id='plugins.wp' label='Frama-C / WP' /> + </Group> + </LabView> + </React.Fragment> + ); + } + +} + +FramaC.id = 'frama-c-sandbox'; +FramaC.label = "Frama-C Sandbox" ; +FramaC.title = "A playground for Frama-C" ; + +// -------------------------------------------------------------------------- +// --- Registration +// -------------------------------------------------------------------------- + +Ivette.registerPlugin( FramaC ); + +// -------------------------------------------------------------------------- diff --git a/Ivette/backup/sandbox/server.js b/Ivette/backup/sandbox/server.js new file mode 100644 index 0000000000000000000000000000000000000000..cb14624f32a32cfdc2fe6b030e764aa5bccd99dd --- /dev/null +++ b/Ivette/backup/sandbox/server.js @@ -0,0 +1,226 @@ +// -------------------------------------------------------------------------- +// --- Global State +// -------------------------------------------------------------------------- + +import _ from 'lodash' ; +import Dome from 'dome' ; +import System from 'dome/system' ; +import { Request } from 'zeromq' ; + +// -------------------------------------------------------------------------- +// --- Frama-C Server +// -------------------------------------------------------------------------- + +const url = 'ipc:///tmp/fc.io' ; + +var stable = true ; +var server = null ; + +export function isStopped() { return stable && server === null; } +export function isRunning() { return stable && server !== null; } + +export function stopServer() { + if (server) { + stable = false; + server.kill(); + Dome.update(); + } +} + +export function startServer() { + if (stable && !server) { + stable = false ; + System.spawn + ( 'frama-c', + [ + '-server-zmq', url, + '-server-debug', 1 + ] + ).then((process) => { + stable = true ; + server = process ; + startSocket(); + process.stdout.on('data',(msg) => {console.log(msg); Dome.emit('console',msg)}); + process.stderr.on('data',(msg) => {console.log(msg); Dome.emit('console',msg)}); + process.on('close',(status) => { + console.log(`Frama-C exit with status ${status}\n`); + Dome.emit('console',`Frama-C exit with status ${status}\n`); + stable = true ; + server = null ; + stopSocket(); + Dome.update(); + }); + Dome.update(); + }).catch((err) => { + stable = true ; + server = null ; + console.log('Error: ' + err + '\n'); + Dome.emit('console','Error: ' + err + '\n'); + Dome.update(); + }); + Dome.update(); + } +} + +// // -------------------------------------------------------------------------- +// // --- Frama-C Socket +// // -------------------------------------------------------------------------- + +var socket = null; +var queue_cmd = []; +var queue_ids = []; +var waiting = false; +var promises = {}; +var pending = 0; +var kid = 0; + +export function getPending() { return pending; } + +export function killPending() { + _.forEach(promises,( _data , rid ) => { + queue_cmd.push( 'KILL' ); + queue_cmd.push( rid ); + }); + flushQueue(); +} + +function startSocket() { + if (socket) stopSocket(); + socket = new Request(); + socket.connect(url); + console.log("socket connected\n"); + // Dome.emit('server',true); +} + +function stopSocket() { + if (socket) { + _.forEach(promises,( { reject } ) => reject('socket closed') ); + socket.close(); + waiting = false; + socket = null; + // Dome.emit('server',false); + } +} + +function sendRequest( kind , request , params = null , more ) { + console.log("send request\n"); + return new Promise((resolve,reject) => { + if (!socket) reject('socket closed'); + try { + const rid = 'RQ' + kid++ ; + const data = JSON.stringify(params); + pending++; + promises[rid] = { resolve , reject } ; + queue_ids.push(rid); + queue_cmd.push(kind); + queue_cmd.push(rid); + queue_cmd.push(request); + queue_cmd.push(data); + if (!more) flushQueue(); + } catch(err) { + reject(err); + } + }); +} + +export function sendGET( request, params, more ) { return sendRequest('GET',request,params,more); } +export function sendSET( request, params, more ) { return sendRequest('SET',request,params,more); } +export function sendEXEC( request, params, more ) { return sendRequest('EXEC',request,params,more); } + +function flushQueue() { + if (!waiting && (queue_cmd.length > 0 || pending > 0)) { + console.log("flushQeue\n"); + const cmd = queue_cmd.length > 0 ? queue_cmd : 'POLL' ; + const ids = queue_ids ; + queue_ids = []; + queue_cmd = []; + waiting = true ; + socket.send( cmd ) + .then(() => {console.log("query sent\n"); socket.receive().then(receiveResponse)}) + .catch((err) => { + console.log("error: " + err + "\n") + waiting = false; + ids.forEach( (id) => rejectRequest(id,err) ); + }); + } +} + +function receiveResponse( commands ) { + console.log("response received\n"); + waiting = false; + while( commands.length ) { + var rid,data,err; + const cmd = commands.shift(); + switch( cmd.toString() ) { + case 'NONE': + break; + case 'DATA': + rid = commands.shift(); + data = commands.shift(); + resolveRequest(rid,data); + break; + case 'ERROR': + rid = commands.shift(); + err = commands.shift(); + rejectRequest(rid,err); + break; + case 'KILLED': + rid = commands.shift(); + rejectRequest(rid,'killed'); + break; + case 'REJECTED': + rid = commands.shift(); + rejectRequest(rid,'rejected'); + break; + case 'WRONG': + err = commands.shift(); + console.log('SERVER-ERROR:' + err); + // Dome.warn('SERVER-ERROR:',err); + break; + default: + // Dome.warn('SERVER-UNKNOWN-RESPONSE:',cmd,commands); + console.log(`SERVER-UNKNOWN-RESPONSE: (${cmd})\n`,commands); + commands.length = 0; + break; + } + } + flushQueue(); +} + +function rejectRequest(rid,err) { + const entry = promises[rid]; + if (entry) { + delete promises[rid]; + pending--; + entry.reject(err); + } +} + +function resolveRequest(rid,data) { + const entry = promises[rid]; + if (entry) { + delete promises[rid]; + pending--; + try { + entry.resolve(JSON.parse(data)); + } catch(err) { + entry.reject(err); + } + } +} + +// -------------------------------------------------------------------------- + +System.atExit(() => { + stopServer(); + stopSocket(); +}); + +export default { + isStopped, isRunning, + startServer, stopServer, + sendSET, sendGET, sendEXEC, + getPending, killPending +}; + +// -------------------------------------------------------------------------- diff --git a/Ivette/backup/style.css b/Ivette/backup/style.css new file mode 100644 index 0000000000000000000000000000000000000000..96b0490f3cda1cda3075da9919f93534f165a584 --- /dev/null +++ b/Ivette/backup/style.css @@ -0,0 +1,50 @@ +/* -------------------------------------------------------------------------- */ +/* --- Ivette Styling --- */ +/* -------------------------------------------------------------------------- */ + +.ivette-dongle { + flex-wrap: nowrap ; + margin: 8px ; + padding: 6px ; + max-width: 480px ; + background: #ddd ; + border: thin solid darkgrey ; + border-radius: 8px ; +} + +.ivette-dongle-id { + min-width: 80px ; +} + +.ivette-project { + margin: 6px 6px 18px 6px ; + padding: 3px ; +} + +.ivette-dongle-selectable:hover { + background: orange ; +} + +.dome-window-inactive .ivette-dongle { + background: #eee ; +} + +.dome-window-active .ivette-dongle-selected { + background: #ffcd00 ; +} + +.ivette-plugin-item { + margin: 2px ; + padding: 0px 6px ; + background: lightgrey ; + border: thin solid darkgrey ; + border-radius: 10px ; + align-items: baseline ; +} + +.ivette-dongle-cancel { + position: relative ; + visibility: hidden ; + top: 15px ; + height: 18px ; +} diff --git a/Ivette/electron-webpack.json b/Ivette/electron-webpack.json new file mode 100644 index 0000000000000000000000000000000000000000..048484644edbcf136112d58accdf3e584cda1979 --- /dev/null +++ b/Ivette/electron-webpack.json @@ -0,0 +1,22 @@ +// -------------------------------------------------------------------------- +// --- Electron-webpack configuration file for Dome +// -------------------------------------------------------------------------- + +/* + Template from $(DOME)/template/electron-webpack.json + + This configuration file makes electron-webpack loading + webpack extensions to resolve Dome packages differently + for electron main-process and renderer-process. + + You may configure further electron-webpack to your convenience. +*/ + +{ + "main": { + "webpackConfig": "webpack.main.js" + }, + "renderer": { + "webpackConfig": "webpack.renderer.js" + } +} diff --git a/Ivette/package.json b/Ivette/package.json new file mode 100644 index 0000000000000000000000000000000000000000..f64e23e2cd377d25fb48ad301f179aef78712d38 --- /dev/null +++ b/Ivette/package.json @@ -0,0 +1,36 @@ +{ + "name": "Ivette", + "version": "1.0.0", + "main": "index.js", + "repository": "git@git.frama-c.com:frama-c/Ivette.git", + "author": "Loïc Correnson <loic.correnson@cea.fr>", + "license": "MIT", + "devDependencies": { + "@babel/core": "^7", + "@babel/plugin-proposal-object-rest-spread": "^7.7.7", + "@babel/preset-env": "^7.7.7", + "@babel/preset-react": "^7.7.4", + "@hot-loader/react-dom": "^16.11.0", + "@types/react": "^16.9.17", + "babel-loader": "^8.0.6", + "css-loader": "^3.4.0", + "electron": "^7", + "electron-builder": "^21.2.0", + "electron-devtools-installer": "^2.2.4", + "electron-webpack": "^2.7.4", + "jsdoc": "^3.6.3", + "react-hot-loader": "^4.12.18", + "webpack": "^4.41.4" + }, + "dependencies": { + "codemirror": "^5.49.2", + "immutable": "^4.0.0-rc.12", + "lodash": "^4.17.15", + "react": "^16.8", + "react-dom": "^16.12.0", + "react-draggable": "^4.2.0", + "react-virtualized": "^9.21.2", + "source-map-support": "^0.5.16", + "zeromq": "^6.0.0-beta.5" + } +} diff --git a/Ivette/push-dome.sh b/Ivette/push-dome.sh new file mode 100755 index 0000000000000000000000000000000000000000..4e7e6914e3106f2cba50ed04afcbb943fe577ed8 --- /dev/null +++ b/Ivette/push-dome.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +DOME=$1 +BRANCH=$2 + +if [ "$DOME" == "" ] || [ "$BRANCH" == "" ] +then + echo "Usage: push-electron.sh <dome-clone-dir> <new-branch>" + exit 1 +fi + +git -C $DOME remote -v | grep -q dome/electron.git + +if [ "$?" != "0" ] +then + echo "Clone of dome/electron not found in '$DOME'" + exit 1 +fi + +echo "Push updates to $DOME#$BRANCH" + +git -C $DOME checkout -B $BRANCH + +FILES=$(cd src/dome ; git ls-files) + +for f in $FILES +do + cp -f src/dome/$f $DOME/$f +done + +git -C $DOME commit -a diff --git a/Ivette/src/dome/.gitignore b/Ivette/src/dome/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..48a7072b2d78c362021afca3d7840f424b1e2e05 --- /dev/null +++ b/Ivette/src/dome/.gitignore @@ -0,0 +1,47 @@ +######################################### +# Makefile +######################################### + +.dome-*.stamp +.dome-*.back +.dome-*.orig +.dome-*.lock + +######################################### +# JavaScript +######################################### + +node_modules +yarn.lock +/package.json + +######################################### +# Example Application +######################################### + +/.babelrc +/webpack.main.js +/webpack.renderer.js +/webpack.plugin.js +/electron-webpack.json +/dist +/bin +/src/main/index.js +/src/misc/exports.js +/src/renderer/index.js +/src/renderer/Application.js +/src/renderer/Preferences.js +/src/renderer/styles.css +/src/renderer/demo +/src/plugins + +######################################### +# Documentation +######################################### + +/html +/doc/template/gallery-icons.html +/doc/template/gallery-styles.js +/doc/template/gallery-styles.html + +######################################### diff --git a/Ivette/src/dome/CHANGELOG.md b/Ivette/src/dome/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..4e51470c1da281d1264d99637ca279df412f3ac7 --- /dev/null +++ b/Ivette/src/dome/CHANGELOG.md @@ -0,0 +1 @@ +# Version 0.0.1 diff --git a/Ivette/src/dome/CONTRIBUTING.md b/Ivette/src/dome/CONTRIBUTING.md new file mode 100644 index 0000000000000000000000000000000000000000..718b8d2fcd61ed47dedb4a630db6eea79a3402d2 --- /dev/null +++ b/Ivette/src/dome/CONTRIBUTING.md @@ -0,0 +1,56 @@ +## Authorship + +All contributions are proprietary of CEA Tech. +An exhaustive list of authors is maintained in [CONTRIBUTORS.md] file. + +## Git Conventions + +The branches are organized as follows: + +- `master` is the prototype for building the next release. +- `stable` is the current working candidate for the next release. +It shall be an ancestor of `master` and is considered ready to be distributed. +- `release/DOME-vN.N.N` are tags pointing to public releases of the framework. +- `feature/*` are branches where new development are experimented before being merged +into `master`. + +The release branches `master`, `stable` and `release/*` are protected and only +release managers are authorized to merge into. + +It is highly recommended to not rebase `feature` branches already pushed on the repository, +unless there is only one contributor to the feature, on order to avoid losing data. + +## Javascript Coding Rules + +Your favorite editor shall be configured such that: +- indentation in two-spaces per level, with no tabulation +- module names are lowercase identifiers +- react compomnents are capitalized + +## Framework Organization + +- [CHANGELOG.md] tracks modifications with releases +- [CONTRIBUTING.md] recommandations for Dome developpers +- [CONTRIBUTORS.md] maintains the list of authors +- [LICENSE.md] framework terms and conditions +- [README.md] public description +- `./Makefile` framework quick-testing +- `./doc` framework documentation resources +- `./dist` local build for tests (generated) +- `./html` local documentation (generated) +- `./src/dome` framework sources +- `./template` framework configuration templates + +For developping an application with **Dome**, follow the indications +provided by the [README.md] file. + +The root Makefile is _not_ designed for +developping an application with the **Dome** framework. +See `make` or `make help` for details. + +This Makefile has been designed for live-editing and quick-testing the +framework itself (see « Live Editing » chapter of Html documentation). +You can type `make dev` to generate an application in `.` and live-edit the +generated `./src/main/*.js` and `./src/renderer/*.js` files. +Then, `make app` and `make dist` can be used to test the framework in production mode. +Use `make doc` to build the documentation in `./html` directory. diff --git a/Ivette/src/dome/CONTRIBUTORS.md b/Ivette/src/dome/CONTRIBUTORS.md new file mode 100644 index 0000000000000000000000000000000000000000..f7753c13aed32ec8ff2062f3fd18b82762137233 --- /dev/null +++ b/Ivette/src/dome/CONTRIBUTORS.md @@ -0,0 +1,8 @@ +## Dome Contributors + +(by order of appearance) + +- [Loïc Correnson](loic.correnson@cea.fr), CEA-LIST, main architect +- [Franck Pujol](franck.pujol@atos.net), ATOS, early designer +- [Valentin Perrelle](valentin.perrelle@cea.fr), CEA-LIST, beta tester +- [Andre Maroneze](andre.oliveiramaroneze@cea.fr), CEA-LIST, beta tester diff --git a/Ivette/src/dome/LICENSE.md b/Ivette/src/dome/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..90f4610c92560f23a6273bfe73812313a21ae403 --- /dev/null +++ b/Ivette/src/dome/LICENSE.md @@ -0,0 +1,5 @@ +Copyright (C) 2016 +CEA (Commissariat à l'énergie atomique et aux énergies alternatives) + +All rights reserved. +Contact CEA LIST for licensing. diff --git a/Ivette/src/dome/Makefile b/Ivette/src/dome/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..91d1bf27385974c111d0cc69543f9870a1959f09 --- /dev/null +++ b/Ivette/src/dome/Makefile @@ -0,0 +1,45 @@ +# -------------------------------------------------------------------------- +help: + @echo "*****************************************" + @echo "*** Dome Framework Makefile ***" + @echo "*****************************************" + @echo + @echo " make doc: alias for dome-doc" + @echo " make dev: alias for dome-dev" + @echo " make app: alias for dome-app" + @echo " make dist: alias for dome-dist" + @echo " make dome-help: detailed help for dome" + @echo " make DEMO=<xxx> demo: switch to 'src/renderer/demo/xxx.js' " + @echo + @echo "*****************************************" + +# -------------------------------------------------------------------------- + +APP=Dome +DOME=. +DEMO=Hello + +include $(DOME)/template/makefile + +.PHONY: doc demo dev app dist + +doc: dome-doc +dev: dome-dev +app: dome-app +dist: dome-dist + +demo: src/renderer/demo/$(DEMO).js + @echo "Switch to src/renderer/demo/$(DEMO).js" + @rm -f src/renderer/Application.js + @echo "// Dome Demonstrator" >> src/renderer/Application.js + @echo "import React from 'react' ;" >> src/renderer/Application.js + @echo "import Main from './demo/$(DEMO).js' ;" >> src/renderer/Application.js + @echo "export default (() => <Main/>);" >> src/renderer/Application.js + +src/renderer/demo/%.js: + @echo "Generate $@" + @echo "// Dome Demonstrator" > $@ + @echo "import React from 'react';" >> $@ + @echo "export default (() => <h1>$* Demo</h1>);" >> $@ + +# -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/README.md b/Ivette/src/dome/README.md new file mode 100644 index 0000000000000000000000000000000000000000..049962c686f5719ef5cf8e277e3abeeb156b0e57 --- /dev/null +++ b/Ivette/src/dome/README.md @@ -0,0 +1,57 @@ +# Dome Framework + +This project allows you to build and distribute desktop applications. +The proposed framework is based on **React** [1] and **Electron** [2]. + +## Quick Start + +We strongly recommand to use **Yarn** [3] for installing the +necessary **Node** packages and their dependencies. Both shall be installed +with decently recent versions (`yarn -v 1.5.*` and `node -v 8.*`). + +Then, prepare a directory for developing your application, and download +the Dome Application Framework into sub-directory `dome`. +You shall setup a makefile for your application as follows: + +``` +include dome/template/makefile +all: dome-dev +``` + +Now, simply type `make` and all the necessary packages will be automatically +installed and configured. This can take a while for the very first installation. +Eventually, your application shall start with a « _Hello World_ » window. Now, +simply live edit the generated `src/renderer/Application.js` which is the main +entry point of your application. + +## Advanced Usage + +You may install the framework in any directory, +provided you set the `DOME` makefile or environment variable accordingly. +By default, this variable is set to `./dome` by the template makefile. + +Type `make help` to see all the predefined compilation targets. +In particular, `make dome-doc` will generate the Dome Documentation locally, in +`$(DOME)/html/index.hml`. + +The `$(DOME)/template/makefile` is provided with usefull targets, but you can also +use your own scripts. All generated configuration files are borrowed from +resources located in the `$(DOME)/template` directory. You can extend and modify +all the generated files, simply follow the comments provided. + +Typicall installation places for the Dome framework are: +- `DOME=./dome` for usual application developpers; +- `DOME=./src/dome` for application developpers that also have to hack and live-edit the Dome framework; +- `DOME=.` is also possible to quick test the framework or make a demo in `src/renderer/Application.js`. + +The last option is not possible when installing the framework since it would conflict with your +own project development. For instance, if your install Dome with `git`, you must keep the `$(DOME)/.git` +distinct and ignore the entire `$(DOME)` directory in your own versionned files. + +## References + +[1] https://reactjs.org + +[2] https://electronjs.org + +[3] https://yarnpkg.com/lang/en/docs/install/ diff --git a/Ivette/src/dome/doc/README.md b/Ivette/src/dome/doc/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1d046ec45e3e09e97ecd285bc7e1d55564d90b10 --- /dev/null +++ b/Ivette/src/dome/doc/README.md @@ -0,0 +1,26 @@ +# Introduction + +**Dome** allows you to build native, desktop applications using +[React](https://reactjs.org) javascript technology. It is build upon the +[Electron](http://electron.atom.io) framework, featuring a full-featured Chromium +engine which renders the graphical user interface to the user. + +The **Dome** framework provides you with the following facilities: +- all-in-one pre-configured rich development environment +- live-editing of your application code +- a collection of ready-to-use, well designed, scalable components +- easy integration with any other React components from your own +- binary distribution for all supported platform (Windows, Linux and MacOS) + +# Tutorials + +- [Quick Start](tutorial-quickstart.html) +- [Live Editing](tutorial-hotreload.html) +- [Application Design](tutorial-application.html) +- [Styling Components](tutorial-styling.html) +- [System Services](tutorial-services.html) + +# References + +- [Icon Gallery](gallery-icons.html) +- [Glossary](tutorial-glossary.html) diff --git a/Ivette/src/dome/doc/app.json b/Ivette/src/dome/doc/app.json new file mode 100644 index 0000000000000000000000000000000000000000..00507a9a78e4b6bcad2ce450619bafa1e6c9af25 --- /dev/null +++ b/Ivette/src/dome/doc/app.json @@ -0,0 +1,14 @@ +{ + "opts": { + "recurse": true, + "template": "doc/template" + }, + "plugins": [ "plugins/markdown" ], + "templates": { + "default": { + "useLongnameInNav": true, + "outputSourceFiles": false, + "includeDate": false + } + } +} diff --git a/Ivette/src/dome/doc/config.json b/Ivette/src/dome/doc/config.json new file mode 100644 index 0000000000000000000000000000000000000000..5afa1619947dcfad43202fc93c29fefa3268d6ed --- /dev/null +++ b/Ivette/src/dome/doc/config.json @@ -0,0 +1,18 @@ +{ + "source": { + "include": [ "doc/README.md", "src" ] + }, + "opts": { + "recurse": true, + "tutorials": "doc/tutorials", + "template": "doc/template" + }, + "plugins": [ "plugins/markdown" ], + "templates": { + "default": { + "useLongnameInNav": true, + "outputSourceFiles": false, + "includeDate": false + } + } +} diff --git a/Ivette/src/dome/doc/gallery.css b/Ivette/src/dome/doc/gallery.css new file mode 100644 index 0000000000000000000000000000000000000000..128e7f8bacf9facaecac2755b028ab705e2e91f8 --- /dev/null +++ b/Ivette/src/dome/doc/gallery.css @@ -0,0 +1,68 @@ +/* -------------------------------------------------------------------------- */ +/* --- Galleries & Palettes CSS --- */ +/* -------------------------------------------------------------------------- */ + +.database { + width: 100% ; + height: auto ; + display: flex ; + flex-direction: row ; + flex-wrap: wrap ; +} + +.refname { + -webkit-user-select: text; /* Safari 3.1+ */ + -moz-user-select: text; /* Firefox 2+ */ + -ms-user-select: text; /* IE 10+ */ + user-select: text; /* Standard syntax */ + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 14px ; + color: #4D8053; +} + +/* -------------------------------------------------------------------------- */ +/* --- Additional CSS for Icon Gallery --- */ +/* -------------------------------------------------------------------------- */ + +.icon-block { + margin: 3pt ; + padding: 2pt ; + display: flex ; + flex-direction: row ; + flex-wrap: nowrap ; + align-items: center ; +} + +.icon-block:hover { + background: lightblue ; +} + +.icon-name { + order: 2 ; + padding: 2pt ; + margin-left: 2pt ; + vertical-align: baseline ; + cursor: text ; + display: inline ; +} + +.icon-name:target { + background: orange ; +} + +.icon-name:hover, .icon-name:focus { + outline-style: none ; + text-decoration: none ; +} + +.icon-svg { + order: 1 ; + width: 20px ; + height: 20px ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Additional CSS for Style Palette --- */ +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ diff --git a/Ivette/src/dome/doc/icons.js b/Ivette/src/dome/doc/icons.js new file mode 100755 index 0000000000000000000000000000000000000000..0867937a8fc83ff2bfb4b2d08224758530490249 --- /dev/null +++ b/Ivette/src/dome/doc/icons.js @@ -0,0 +1,82 @@ +// -------------------------------------------------------------------------- +// --- Icons Gallery Generator +// -------------------------------------------------------------------------- + +const path = require('path'); +const icons = require(path.resolve( process.argv[2] )); +const index = []; +const sections = {}; + +// --- Indexing & Sectioning ----------------------------------------- + +for ( var name in icons ) { + const icon = icons[name]; + const section = icon.section || "Others" ; + if (section != "Others" && index.indexOf(section) < 0) index.push( section ); + var content = sections[section] ; + if (!content) sections[section] = content = [] ; + content.push(name) ; +} + +index.sort(); +if (sections["Others"]) index.push("Others"); + +console.log( `<div id="main">` ); + +// --- Gallery (per section) ----------------------------------------- + +console.log( `<div id="content">` ); +console.log( `<div id="page">` ); +console.log( ` <h1 class="page-title">Icons Gallery</h1>` ); + +for ( var s = 0 ; s < index.length ; s++ ) { + const section = index[s] ; + console.log( `<section>` ); + console.log( `<article><h4 id="SECTION.${section}">${section}</h4>` ); + console.log( ` <div class="database">` ); + + const content = sections[section] ; + content.sort(); + + for( var k = 0 ; k < content.length ; k++ ) { + const name = content[k]; + const icon = icons[name]; + const title = icon.title || name ; + console.log( ` <div class="icon-block" onclick="window.location.href='#ICON.${name}'" title="${title}">`); + console.log( ` <div class="icon-name refname" id="ICON.${name}">${name}</div>` ); + console.log( ` <svg class="icon-svg" viewBox="${icon.viewBox}">` ); + console.log( ` <path d="${icon.path}"/>`); + console.log( ` </svg>` ); + console.log( ` </div>` ); + } + console.log( ` </div>` ); + console.log( `</article>` ); + console.log( `</section>` ); +} + +console.log( `</div>` ); // #content +console.log( `</div>` ); // #page + +// --- Navigation Bar ------------------------------------------------ + +console.log( `<div id="index">` ); +console.log( `<nav>` ); +console.log( `<h2><a href="index.html">Dome</a></h2>` ); +console.log( `<h3>Classes</h3>` ); +console.log( `<ul><li><a href="module-dome_controls_icons.Icon.html">Icon (Component)</a></li>` ); +for ( var s=0; s < index.length ; s++ ) { + const section = index[s]; + console.log( ` <li><a href="#SECTION.${section}">${section}</a></li>` ); +} +console.log( `</ul>` ); +console.log( `<h3>Icons</h3><ul>` ); +for( var name in icons ) { + console.log( `<li><a href="#ICON.${name}">${name}</a></li>` ); +} +console.log( `</ul>`); +console.log( `</nav>` ); +console.log( `</div>` ); // #index + +console.log( `</div>` ); // #main + +// ------------------------------------------------------------------- diff --git a/Ivette/src/dome/doc/template/gallery-head.html b/Ivette/src/dome/doc/template/gallery-head.html new file mode 100644 index 0000000000000000000000000000000000000000..30ff5781d97df4e83a14566a7f447a946f11c601 --- /dev/null +++ b/Ivette/src/dome/doc/template/gallery-head.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>Dome</title> + <script src="scripts/prettify/prettify.js"> </script> + <script src="scripts/prettify/lang-css.js"> </script> + <!--[if lt IE 9]> + <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> + <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> + <link type="text/css" rel="stylesheet" href="styles/gallery.css"> +</head> +<body> diff --git a/Ivette/src/dome/doc/template/gallery-tail.html b/Ivette/src/dome/doc/template/gallery-tail.html new file mode 100644 index 0000000000000000000000000000000000000000..e29004ae18363bf68f2c9891cbd2307ac8ad583d --- /dev/null +++ b/Ivette/src/dome/doc/template/gallery-tail.html @@ -0,0 +1,11 @@ + +<br class="clear"/> + +<footer> +Copyright (©) CEA Tech 2017 +</footer> + +<script> prettyPrint(); </script> +<script src="scripts/linenumber.js"> </script> +</body> +</html> diff --git a/Ivette/src/dome/doc/template/publish.js b/Ivette/src/dome/doc/template/publish.js new file mode 100644 index 0000000000000000000000000000000000000000..4aa8e4fc54729092825b16a9880d9227895fda9d --- /dev/null +++ b/Ivette/src/dome/doc/template/publish.js @@ -0,0 +1,665 @@ +'use strict'; + +var doop = require('jsdoc/util/doop'); +var env = require('jsdoc/env'); +var fs = require('jsdoc/fs'); +var helper = require('jsdoc/util/templateHelper'); +var logger = require('jsdoc/util/logger'); +var path = require('jsdoc/path'); +var taffy = require('taffydb').taffy; +var template = require('jsdoc/template'); +var util = require('util'); + +var htmlsafe = helper.htmlsafe; +var linkto = helper.linkto; +var resolveAuthorLinks = helper.resolveAuthorLinks; +var scopeToPunc = helper.scopeToPunc; +var hasOwnProp = Object.prototype.hasOwnProperty; + +var data; +var view; + +var outdir = path.normalize(env.opts.destination); + +function find(spec) { + return helper.find(data, spec); +} + +function tutoriallink(tutorial) { + return helper.toTutorial(tutorial, null, { tag: 'em', classname: 'disabled', prefix: 'Tutorial: ' }); +} + +function getAncestorLinks(doclet) { + return helper.getAncestorLinks(data, doclet); +} + +function hashToLink(doclet, hash) { + if ( !/^(#.+)/.test(hash) ) { return hash; } + + var url = helper.createLink(doclet); + + url = url.replace(/(#.+|$)/, hash); + return '<a href="' + url + '">' + hash + '</a>'; +} + +function needsSignature(doclet) { + var needsSig = false; + + // function and class definitions always get a signature + if (doclet.kind === 'function' || doclet.kind === 'class') { + needsSig = true; + } + // typedefs that contain functions get a signature, too + else if (doclet.kind === 'typedef' && doclet.type && doclet.type.names && + doclet.type.names.length) { + for (var i = 0, l = doclet.type.names.length; i < l; i++) { + if (doclet.type.names[i].toLowerCase() === 'function') { + needsSig = true; + break; + } + } + } + + return needsSig; +} + +function getSignatureAttributes(item) { + var attributes = []; + + if (item.optional) { + attributes.push('opt'); + } + + if (item.nullable === true) { + attributes.push('nullable'); + } + else if (item.nullable === false) { + attributes.push('non-null'); + } + + return attributes; +} + +function updateItemName(item) { + var attributes = getSignatureAttributes(item); + var itemName = item.name || ''; + + if (item.variable) { + itemName = '…' + itemName; + } + + if (attributes && attributes.length) { + itemName = util.format( '%s<span class="signature-attributes">%s</span>', itemName, + attributes.join(', ') ); + } + + return itemName; +} + +function addParamAttributes(params) { + return params.filter(function(param) { + return param.name && param.name.indexOf('.') === -1; + }).map(updateItemName); +} + +function buildItemTypeStrings(item) { + var types = []; + + if (item && item.type && item.type.names) { + item.type.names.forEach(function(name) { + types.push( linkto(name, htmlsafe(name)) ); + }); + } + + return types; +} + +function buildAttribsString(attribs) { + var attribsString = ''; + + if (attribs && attribs.length) { + attribsString = htmlsafe( util.format('(%s) ', attribs.join(', ')) ); + } + + return attribsString; +} + +function addNonParamAttributes(items) { + var types = []; + + items.forEach(function(item) { + types = types.concat( buildItemTypeStrings(item) ); + }); + + return types; +} + +function addSignatureParams(f) { + var params = f.params ? addParamAttributes(f.params) : []; + + f.signature = util.format( '%s(%s)', (f.signature || ''), params.join(', ') ); +} + +function addSignatureReturns(f) { + var attribs = []; + var attribsString = ''; + var returnTypes = []; + var returnTypesString = ''; + + // jam all the return-type attributes into an array. this could create odd results (for example, + // if there are both nullable and non-nullable return types), but let's assume that most people + // who use multiple @return tags aren't using Closure Compiler type annotations, and vice-versa. + if (f.returns) { + f.returns.forEach(function(item) { + helper.getAttribs(item).forEach(function(attrib) { + if (attribs.indexOf(attrib) === -1) { + attribs.push(attrib); + } + }); + }); + + attribsString = buildAttribsString(attribs); + } + + if (f.returns) { + returnTypes = addNonParamAttributes(f.returns); + } + if (returnTypes.length) { + returnTypesString = util.format( ' → %s{%s}', attribsString, returnTypes.join('|') ); + } + + f.signature = '<span class="signature">' + (f.signature || '') + '</span>' + + '<span class="type-signature">' + returnTypesString + '</span>'; +} + +function addSignatureTypes(f) { + var types = f.type ? buildItemTypeStrings(f) : []; + + f.signature = (f.signature || '') + '<span class="type-signature">' + + (types.length ? ' :' + types.join('|') : '') + '</span>'; +} + +function addAttribs(f) { + var attribs = helper.getAttribs(f); + var attribsString = buildAttribsString(attribs); + + f.attribs = util.format('<span class="type-signature">%s</span>', attribsString); +} + +function shortenPaths(files, commonPrefix) { + Object.keys(files).forEach(function(file) { + files[file].shortened = files[file].resolved.replace(commonPrefix, '') + // always use forward slashes + .replace(/\\/g, '/'); + }); + + return files; +} + +function getPathFromDoclet(doclet) { + if (!doclet.meta) { + return null; + } + + return doclet.meta.path && doclet.meta.path !== 'null' ? + path.join(doclet.meta.path, doclet.meta.filename) : + doclet.meta.filename; +} + +function generate(title, docs, filename, resolveLinks) { + resolveLinks = resolveLinks === false ? false : true; + + var docData = { + env: env, + title: title, + docs: docs + }; + + var outpath = path.join(outdir, filename), + html = view.render('container.tmpl', docData); + + if (resolveLinks) { + html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a> + } + + fs.writeFileSync(outpath, html, 'utf8'); +} + +function generateSourceFiles(sourceFiles, encoding) { + encoding = encoding || 'utf8'; + Object.keys(sourceFiles).forEach(function(file) { + var source; + // links are keyed to the shortened path in each doclet's `meta.shortpath` property + var sourceOutfile = helper.getUniqueFilename(sourceFiles[file].shortened); + helper.registerLink(sourceFiles[file].shortened, sourceOutfile); + + try { + source = { + kind: 'source', + code: helper.htmlsafe( fs.readFileSync(sourceFiles[file].resolved, encoding) ) + }; + } + catch(e) { + logger.error('Error while generating source file %s: %s', file, e.message); + } + + generate('Source: ' + sourceFiles[file].shortened, [source], sourceOutfile, + false); + }); +} + +/** + * Look for classes or functions with the same name as modules (which indicates that the module + * exports only that class or function), then attach the classes or functions to the `module` + * property of the appropriate module doclets. The name of each class or function is also updated + * for display purposes. This function mutates the original arrays. + * + * @private + * @param {Array.<module:jsdoc/doclet.Doclet>} doclets - The array of classes and functions to + * check. + * @param {Array.<module:jsdoc/doclet.Doclet>} modules - The array of module doclets to search. + */ +function attachModuleSymbols(doclets, modules) { + var symbols = {}; + + // build a lookup table + doclets.forEach(function(symbol) { + symbols[symbol.longname] = symbols[symbol.longname] || []; + symbols[symbol.longname].push(symbol); + }); + + return modules.map(function(module) { + if (symbols[module.longname]) { + module.modules = symbols[module.longname] + // Only show symbols that have a description. Make an exception for classes, because + // we want to show the constructor-signature heading no matter what. + .filter(function(symbol) { + return symbol.description || symbol.kind === 'class'; + }) + .map(function(symbol) { + symbol = doop(symbol); + + if (symbol.kind === 'class' || symbol.kind === 'function') { + symbol.name = symbol.name.replace('module:', '(require("') + '"))'; + } + + return symbol; + }); + } + }); +} + +function buildMemberNav(items, itemHeading, itemsSeen, linktoFn) { + var nav = ''; + + if (items.length) { + var itemsNav = ''; + + items.forEach(function(item) { + if ( !hasOwnProp.call(item, 'longname') ) { + itemsNav += '<li>' + linktoFn('', item.name) + '</li>'; + } + else if ( !hasOwnProp.call(itemsSeen, item.longname) ) { + var displayName; + if (env.conf.templates.default.useLongnameInNav) { + displayName = item.longname; + } else { + displayName = item.name; + } + itemsNav += '<li>' + linktoFn(item.longname, displayName.replace(/\b(module|event):/g, '')) + '</li>'; + + itemsSeen[item.longname] = true; + } + }); + + if (itemsNav !== '') { + nav += '<h3>' + itemHeading + '</h3><ul>' + itemsNav + '</ul>'; + } + } + + return nav; +} + +function linktoTutorial(longName, name) { + return tutoriallink(name); +} + +function linktoExternal(longName, name) { + return linkto(longName, name.replace(/(^"|"$)/g, '')); +} + +/** + * Create the navigation sidebar. + * @param {object} members The members that will be used to create the sidebar. + * @param {array<object>} members.classes + * @param {array<object>} members.externals + * @param {array<object>} members.globals + * @param {array<object>} members.mixins + * @param {array<object>} members.modules + * @param {array<object>} members.namespaces + * @param {array<object>} members.tutorials + * @param {array<object>} members.events + * @param {array<object>} members.interfaces + * @return {string} The HTML for the navigation sidebar. + */ +function buildNav(members) { + const title = process.env.APP || 'Dome' ; + var nav = '<h2><a href="index.html">' + title + '</a></h2>'; + var seen = {}; + var seenTutorials = {}; + + const indexTutorials = require( path.resolve(process.env.DOME,'doc/tutorials/index.json' )); + const sortedTutorials = members.tutorials.sort((a,b) => { + const ta = indexTutorials[a.name] ; + const tb = indexTutorials[b.name] ; + const ra = (ta && ta.order) || 0 ; + const rb = (tb && tb.order) || 0 ; + return ra - rb ; + }); + + nav += buildMemberNav(sortedTutorials, 'Tutorials', seenTutorials, linktoTutorial); + nav += buildMemberNav(members.modules, 'Modules', {}, linkto); + nav += buildMemberNav(members.classes, 'Classes', seen, linkto); + nav += buildMemberNav(members.events, 'Events', seen, linkto); + nav += buildMemberNav(members.interfaces, 'Interfaces', seen, linkto); + nav += buildMemberNav(members.mixins, 'Mixins', seen, linkto); + nav += buildMemberNav(members.namespaces, 'Namespaces', seen, linkto); + nav += buildMemberNav(members.externals, 'Externals', seen, linktoExternal); + + if (members.globals.length) { + var globalNav = ''; + + members.globals.forEach(function(g) { + if ( g.kind !== 'typedef' && !hasOwnProp.call(seen, g.longname) ) { + globalNav += '<li>' + linkto(g.longname, g.name) + '</li>'; + } + seen[g.longname] = true; + }); + + if (!globalNav) { + // turn the heading into a link so you can actually get to the global page + nav += '<h3>' + linkto('global', 'Global') + '</h3>'; + } + else { + nav += '<h3>Global</h3><ul>' + globalNav + '</ul>'; + } + } + + return nav; +} + +/** + @param {TAFFY} taffyData See <http://taffydb.com/>. + @param {object} opts + @param {Tutorial} tutorials + */ +exports.publish = function(taffyData, opts, tutorials) { + data = taffyData; + + var conf = env.conf.templates || {}; + conf.default = conf.default || {}; + + var templatePath = path.normalize(opts.template); + view = new template.Template( path.join(templatePath, 'tmpl') ); + + // claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness + // doesn't try to hand them out later + var indexUrl = helper.getUniqueFilename('index'); + // don't call registerLink() on this one! 'index' is also a valid longname + + var globalUrl = helper.getUniqueFilename('global'); + helper.registerLink('global', globalUrl); + + // set up templating + view.layout = conf.default.layoutFile ? + path.getResourcePath(path.dirname(conf.default.layoutFile), + path.basename(conf.default.layoutFile) ) : + 'layout.tmpl'; + + // set up tutorials for helper + helper.setTutorials(tutorials); + + data = helper.prune(data); + data.sort('longname, version, since'); + helper.addEventListeners(data); + + var sourceFiles = {}; + var sourceFilePaths = []; + data().each(function(doclet) { + doclet.attribs = ''; + + if (doclet.examples) { + doclet.examples = doclet.examples.map(function(example) { + var caption, code; + + if (example.match(/^\s*<caption>([\s\S]+?)<\/caption>(\s*[\n\r])([\s\S]+)$/i)) { + caption = RegExp.$1; + code = RegExp.$3; + } + + return { + caption: caption || '', + code: code || example + }; + }); + } + if (doclet.see) { + doclet.see.forEach(function(seeItem, i) { + doclet.see[i] = hashToLink(doclet, seeItem); + }); + } + + // build a list of source files + var sourcePath; + if (doclet.meta) { + sourcePath = getPathFromDoclet(doclet); + sourceFiles[sourcePath] = { + resolved: sourcePath, + shortened: null + }; + if (sourceFilePaths.indexOf(sourcePath) === -1) { + sourceFilePaths.push(sourcePath); + } + } + }); + + // update outdir if necessary, then create outdir + var packageInfo = ( find({kind: 'package'}) || [] ) [0]; + if (packageInfo && packageInfo.name) { + outdir = path.join( outdir, packageInfo.name, (packageInfo.version || '') ); + } + fs.mkPath(outdir); + + // copy the template's static files to outdir + var fromDir = path.join(templatePath, 'static'); + var staticFiles = fs.ls(fromDir, 3); + + staticFiles.forEach(function(fileName) { + var toDir = fs.toDir( fileName.replace(fromDir, outdir) ); + fs.mkPath(toDir); + fs.copyFileSync(fileName, toDir); + }); + + // copy user-specified static files to outdir + var staticFilePaths; + var staticFileFilter; + var staticFileScanner; + if (conf.default.staticFiles) { + // The canonical property name is `include`. We accept `paths` for backwards compatibility + // with a bug in JSDoc 3.2.x. + staticFilePaths = conf.default.staticFiles.include || + conf.default.staticFiles.paths || + []; + staticFileFilter = new (require('jsdoc/src/filter')).Filter(conf.default.staticFiles); + staticFileScanner = new (require('jsdoc/src/scanner')).Scanner(); + + staticFilePaths.forEach(function(filePath) { + var extraStaticFiles; + + filePath = path.resolve(env.pwd, filePath); + extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter); + + extraStaticFiles.forEach(function(fileName) { + var sourcePath = fs.toDir(filePath); + var toDir = fs.toDir( fileName.replace(sourcePath, outdir) ); + fs.mkPath(toDir); + fs.copyFileSync(fileName, toDir); + }); + }); + } + + if (sourceFilePaths.length) { + sourceFiles = shortenPaths( sourceFiles, path.commonPrefix(sourceFilePaths) ); + } + data().each(function(doclet) { + var url = helper.createLink(doclet); + helper.registerLink(doclet.longname, url); + + // add a shortened version of the full path + var docletPath; + if (doclet.meta) { + docletPath = getPathFromDoclet(doclet); + docletPath = sourceFiles[docletPath].shortened; + if (docletPath) { + doclet.meta.shortpath = docletPath; + } + } + }); + + data().each(function(doclet) { + var url = helper.longnameToUrl[doclet.longname]; + + if (url.indexOf('#') > -1) { + doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop(); + } + else { + doclet.id = doclet.name; + } + + if ( needsSignature(doclet) ) { + addSignatureParams(doclet); + addSignatureReturns(doclet); + addAttribs(doclet); + } + }); + + // do this after the urls have all been generated + data().each(function(doclet) { + doclet.ancestors = getAncestorLinks(doclet); + + if (doclet.kind === 'member') { + addSignatureTypes(doclet); + addAttribs(doclet); + } + + if (doclet.kind === 'constant') { + addSignatureTypes(doclet); + addAttribs(doclet); + doclet.kind = 'member'; + } + }); + + var members = helper.getMembers(data); + members.tutorials = tutorials.children; + + // output pretty-printed source files by default + var outputSourceFiles = conf.default && conf.default.outputSourceFiles !== false ? true : + false; + + // add template helpers + view.find = find; + view.linkto = linkto; + view.resolveAuthorLinks = resolveAuthorLinks; + view.tutoriallink = tutoriallink; + view.htmlsafe = htmlsafe; + view.outputSourceFiles = outputSourceFiles; + + // once for all + view.nav = buildNav(members); + attachModuleSymbols( find({ longname: {left: 'module:'} }), members.modules ); + + // generate the pretty-printed source files first so other pages can link to them + if (outputSourceFiles) { + generateSourceFiles(sourceFiles, opts.encoding); + } + + if (members.globals.length) { generate('Global', [{kind: 'globalobj'}], globalUrl); } + + // index page displays information from package.json and lists files + var files = find({kind: 'file'}), + packages = find({kind: 'package'}); + + const title = process.env.APP || 'Dome' ; + generate(title + ' Documentation', + packages.concat( + [{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}] + ).concat(files), + indexUrl); + + // set up the lists that we'll use to generate pages + var classes = taffy(members.classes); + var modules = taffy(members.modules); + var namespaces = taffy(members.namespaces); + var mixins = taffy(members.mixins); + var externals = taffy(members.externals); + var interfaces = taffy(members.interfaces); + + Object.keys(helper.longnameToUrl).forEach(function(longname) { + var myModules = helper.find(modules, {longname: longname}); + if (myModules.length) { + generate('Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname]); + } + + var myClasses = helper.find(classes, {longname: longname}); + if (myClasses.length) { + generate('Class: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname]); + } + + var myNamespaces = helper.find(namespaces, {longname: longname}); + if (myNamespaces.length) { + generate('Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]); + } + + var myMixins = helper.find(mixins, {longname: longname}); + if (myMixins.length) { + generate('Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname]); + } + + var myExternals = helper.find(externals, {longname: longname}); + if (myExternals.length) { + generate('External: ' + myExternals[0].name, myExternals, helper.longnameToUrl[longname]); + } + + var myInterfaces = helper.find(interfaces, {longname: longname}); + if (myInterfaces.length) { + generate('Interface: ' + myInterfaces[0].name, myInterfaces, helper.longnameToUrl[longname]); + } + }); + + // TODO: move the tutorial functions to templateHelper.js + function generateTutorial(title, tutorial, filename) { + var tutorialData = { + title: title, + header: tutorial.title, + content: tutorial.parse(), + children: tutorial.children + }; + + var tutorialPath = path.join(outdir, filename), + html = view.render('tutorial.tmpl', tutorialData); + + // yes, you can use {@link} in tutorials too! + html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a> + + fs.writeFileSync(tutorialPath, html, 'utf8'); + } + + // tutorials can have only one parent so there is no risk for loops + function saveChildren(node) { + node.children.forEach(function(child) { + generateTutorial('Tutorial: ' + child.title, child, helper.tutorialToUrl(child.name)); + saveChildren(child); + }); + } + saveChildren(tutorials); +}; diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-Bold-webfont.eot b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Bold-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..5d20d916338a5890a033952e2e07ba7380f5a7d3 Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Bold-webfont.eot differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-Bold-webfont.svg b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Bold-webfont.svg new file mode 100644 index 0000000000000000000000000000000000000000..ff4d7ddb6aeedf32398e5f02be7aa31759373ccb Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Bold-webfont.svg differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-Bold-webfont.woff b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Bold-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..1205787b0ed50db71ebd4f8a7f85d106721ff258 Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Bold-webfont.woff differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-BoldItalic-webfont.eot b/Ivette/src/dome/doc/template/static/fonts/OpenSans-BoldItalic-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..1f639a15ff3cc66d3b22b55a7f28a8cf0d821b03 Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-BoldItalic-webfont.eot differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-BoldItalic-webfont.svg b/Ivette/src/dome/doc/template/static/fonts/OpenSans-BoldItalic-webfont.svg new file mode 100644 index 0000000000000000000000000000000000000000..5ef8ef90048c8f1600aa087b1b7b7617341986ea Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-BoldItalic-webfont.svg differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-BoldItalic-webfont.woff b/Ivette/src/dome/doc/template/static/fonts/OpenSans-BoldItalic-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..ed760c0628b6a0026041f5b8bba466a0471fd2e0 Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-BoldItalic-webfont.woff differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-Italic-webfont.eot b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Italic-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..0c8a0ae06ed09f6a7be1b84defae7ccda65cc2e0 Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Italic-webfont.eot differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-Italic-webfont.svg b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Italic-webfont.svg new file mode 100644 index 0000000000000000000000000000000000000000..d86c165fb1332ba91e2cac838a747822d451f26f Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Italic-webfont.svg differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-Italic-webfont.woff b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Italic-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..ff652e64356b538c001423b6aedefcf1ee66cd17 Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Italic-webfont.woff differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-Light-webfont.eot b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Light-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..14868406aa7d728a88d63963f119635813b5d30e Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Light-webfont.eot differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-Light-webfont.svg b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Light-webfont.svg new file mode 100644 index 0000000000000000000000000000000000000000..bac8c03979f56051d3e2b72cb2008865a07b09ca Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Light-webfont.svg differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-Light-webfont.woff b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Light-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..e786074813a27d0a7a249047832988d5bf0fe756 Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Light-webfont.woff differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-LightItalic-webfont.eot b/Ivette/src/dome/doc/template/static/fonts/OpenSans-LightItalic-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..8f445929ffb03b50e98c2a2f7d831a0cb1b276a2 Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-LightItalic-webfont.eot differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-LightItalic-webfont.svg b/Ivette/src/dome/doc/template/static/fonts/OpenSans-LightItalic-webfont.svg new file mode 100644 index 0000000000000000000000000000000000000000..047fc73b406572fa39ec17e00eb26d88fd9b7d1c Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-LightItalic-webfont.svg differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-LightItalic-webfont.woff b/Ivette/src/dome/doc/template/static/fonts/OpenSans-LightItalic-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..43e8b9e6cc061ff17fd2903075cbde12715512b3 Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-LightItalic-webfont.woff differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-Regular-webfont.eot b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Regular-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..6bbc3cf58cb011a6b4bf3cb1612ce212608f7274 Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Regular-webfont.eot differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-Regular-webfont.svg b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Regular-webfont.svg new file mode 100644 index 0000000000000000000000000000000000000000..b2ce45def77b17dfcecbbfeb545146f88d927792 Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Regular-webfont.svg differ diff --git a/Ivette/src/dome/doc/template/static/fonts/OpenSans-Regular-webfont.woff b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Regular-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..e231183dce4c7b452afc9e7799586fd285e146f4 Binary files /dev/null and b/Ivette/src/dome/doc/template/static/fonts/OpenSans-Regular-webfont.woff differ diff --git a/Ivette/src/dome/doc/template/static/scripts/linenumber.js b/Ivette/src/dome/doc/template/static/scripts/linenumber.js new file mode 100644 index 0000000000000000000000000000000000000000..8d52f7eafdb166eeba1de2f1a223fcde9ffbe4fe --- /dev/null +++ b/Ivette/src/dome/doc/template/static/scripts/linenumber.js @@ -0,0 +1,25 @@ +/*global document */ +(function() { + var source = document.getElementsByClassName('prettyprint source linenums'); + var i = 0; + var lineNumber = 0; + var lineId; + var lines; + var totalLines; + var anchorHash; + + if (source && source[0]) { + anchorHash = document.location.hash.substring(1); + lines = source[0].getElementsByTagName('li'); + totalLines = lines.length; + + for (; i < totalLines; i++) { + lineNumber++; + lineId = 'line' + lineNumber; + lines[i].id = lineId; + if (lineId === anchorHash) { + lines[i].className += ' selected'; + } + } + } +})(); diff --git a/Ivette/src/dome/doc/template/static/scripts/prettify/Apache-License-2.0.txt b/Ivette/src/dome/doc/template/static/scripts/prettify/Apache-License-2.0.txt new file mode 100644 index 0000000000000000000000000000000000000000..d645695673349e3947e8e5ae42332d0ac3164cd7 --- /dev/null +++ b/Ivette/src/dome/doc/template/static/scripts/prettify/Apache-License-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/Ivette/src/dome/doc/template/static/scripts/prettify/lang-css.js b/Ivette/src/dome/doc/template/static/scripts/prettify/lang-css.js new file mode 100644 index 0000000000000000000000000000000000000000..041e1f59067977554f29146ed51c13bcf509f0af --- /dev/null +++ b/Ivette/src/dome/doc/template/static/scripts/prettify/lang-css.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n"]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", +/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); diff --git a/Ivette/src/dome/doc/template/static/scripts/prettify/prettify.js b/Ivette/src/dome/doc/template/static/scripts/prettify/prettify.js new file mode 100644 index 0000000000000000000000000000000000000000..eef5ad7e6a07676b3919146d583d1c190bf1e163 --- /dev/null +++ b/Ivette/src/dome/doc/template/static/scripts/prettify/prettify.js @@ -0,0 +1,28 @@ +var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= +[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c< +f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&& +(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r= +{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length, +t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b=== +"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), +l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value", +m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m= +a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue= +j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b= +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m, +250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit", +PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})(); diff --git a/Ivette/src/dome/doc/template/static/styles/jsdoc-default.css b/Ivette/src/dome/doc/template/static/styles/jsdoc-default.css new file mode 100644 index 0000000000000000000000000000000000000000..f12f3f6d62c8d579d90e9bad4ad17f09d4c528fa --- /dev/null +++ b/Ivette/src/dome/doc/template/static/styles/jsdoc-default.css @@ -0,0 +1,496 @@ +/* -------------------------------------------------------------------------- */ +/* --- Main Document --- */ +/* -------------------------------------------------------------------------- */ + +@font-face { + font-family: 'Open Sans'; + font-weight: normal; + font-style: normal; + src: url('../fonts/OpenSans-Regular-webfont.eot'); + src: + local('Open Sans'), + local('OpenSans'), + url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/OpenSans-Regular-webfont.woff') format('woff'), + url('../fonts/OpenSans-Regular-webfont.svg#open_sansregular') format('svg'); +} + +@font-face { + font-family: 'Open Sans Light'; + font-weight: normal; + font-style: normal; + src: url('../fonts/OpenSans-Light-webfont.eot'); + src: + local('Open Sans Light'), + local('OpenSans Light'), + url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/OpenSans-Light-webfont.woff') format('woff'), + url('../fonts/OpenSans-Light-webfont.svg#open_sanslight') format('svg'); +} + +html +{ + background-color: #fff; + font-size: 14px; +} + +body +{ + display: block ; + position: fixed ; + top: 0px ; + bottom: 0px ; + left: 0px ; + right: 0px ; + overflow: hidden ; + margin: 0px ; + padding: 0px ; + font-family: 'Open Sans', sans-serif; + line-height: 1.5; + color: #4d4e53; + background-color: white; +} + +#main { + display: flex ; + flex-flow: row nowrap ; + width: 100% ; + height: 100% ; + overflow: hidden ; +} + +#index { + box-sizing: border-box ; + display: block ; + order: 2 ; + flex: 0 1 auto ; + width: auto ; + min-width: 300px ; + height: 100% ; + overflow: auto ; +} + +#content { + box-sizing: border-box ; + order: 1 ; + flex: 1 1 auto ; + width: 100% ; + height: 100% ; + display: flex ; + overflow: auto ; + justify-content: center ; + align-content: center ; +} + +#page { + margin: 10px ; + flex: 1 1 auto ; + min-width: 600px ; + max-width: 1000px ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Content Styling --- */ +/* -------------------------------------------------------------------------- */ + +h4:target { border-left: thick solid orange ; padding-top: 4px ; padding-left: 2px } + +a, a:visited, a:active, a code { + color: #b63910 ; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +header +{ + display: block; + padding: 0px 4px; +} + +tt, code, kbd, samp { + color: #8a8a61; + font-family: Consolas, Monaco, 'Andale Mono', monospace; +} + +.class-description { + font-size: 130%; + line-height: 140%; + margin-bottom: 1em; + margin-top: 1em; +} + +.class-description:empty { + margin: 0; +} + +article dl { + margin-bottom: 40px; +} + +div.summary { + margin-top: 10px ; + margin-bottom: 10px ; + padding-left: 20px ; + padding-bottom: 10px ; + border-bottom: thin solid #c0c0c0 ; +} + +table.summary { } +table.summary tr { } +table.summary td { padding-left: 20px } +table.summary p { margin: 0 } + +section +{ + display: block; + background-color: #fff; + padding: 12px 24px; + margin-right: 30px; +} + +.variation { + display: none; +} + +.signature-attributes { + font-size: 60%; + color: #aaa; + font-style: italic; + font-weight: lighter; +} + +nav +{ + display: block; + margin: 20px ; + width: content ; +} + +nav ul { + font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; + font-size: 100%; + padding: 0; + margin: 0; + list-style-type: none; +} + +nav li { + white-space: nowrap ; +} + +nav ul a, nav ul a:visited, nav ul a:active { + font-family: Consolas, Monaco, 'Andale Mono', monospace; + color: #4D8053; +} + +nav ul a:hover { + text-decoration: none ; + background-color: lightblue ; +} + +nav ul a { + padding-top: 4px ; + padding-bottom: 2px ; + padding-left: 2px ; + padding-right: 2px ; + margin-left: 4px ; +} + +nav h3 { + font-size: 18px; + margin-top: 12px; +} + +footer { + font-size: 8pt; + color: gray; + display: block; + padding: 6px; + margin-top: 12px; + margin-left: 20px; +} + +h1, h2, h3, h4 { + font-weight: 200; + margin: 0; +} + +h1 +{ + font-family: 'Verdana', sans-serif; + font-size: 32px; + letter-spacing: -2px; + margin: 20px 0px 12px ; +} + +h1.page-title { + background: #f50000; + color: white; + padding-left: 20px ; + margin: 0px ; +} + +h2, h3 +{ + font-size: 24px; + font-weight: 700; + letter-spacing: -1px; + margin-bottom: 12px; +} + +h4 +{ + font-size: 18px; + letter-spacing: -0.33px; + margin-bottom: 8px; + padding-bottom: 4px; + border-bottom: thin solid #c0c0c0; + color: #4d4e53; +} + +h5, .container-overview .subsection-title +{ + font-size: 120%; + font-weight: bold; + letter-spacing: -0.01em; + margin: 8px 0 3px 0; +} + +h6 +{ + font-size: 100%; + letter-spacing: -0.01em; + margin: 6px 0 3px 0; + font-style: italic; +} + +.ancestors { color: #999; } +.ancestors a +{ + color: #999 !important; + text-decoration: none; +} + +.clear +{ + clear: both; +} + +.important +{ + font-weight: bold; + color: #950B02; +} + +.yes-def { + text-indent: -1000px; +} + +.type-signature { + color: #aaa; +} + +.name, .signature { + font-family: Consolas, Monaco, 'Andale Mono', monospace; +} + +h4.name { position: relative; } +h4.name .anchor { position: absolute; right: 2px; } + +.details { margin-top: 14px; } +.details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } +.details dd { margin-left: 70px; } +.details ul { margin: 0; } +.details ul { list-style-type: none; } +.details li { margin-left: 30px; padding-top: 6px; } +.details pre.prettyprint { margin: 0 } +.details .object-value { padding-top: 0; } + +.description { + margin-bottom: 1em; + margin-top: 1em; +} + +.code-caption +{ + font-style: italic; + font-size: 107%; + margin: 0; +} + +.prettyprint +{ + border: 1px solid #ddd; + width: 80%; + overflow: auto; +} + +.prettyprint.source { + width: inherit; +} + +.prettyprint code +{ + font-size: 100%; + line-height: 18px; + display: block; + padding: 4px 12px; + margin: 0; + background-color: #fff; + color: #4D8053; +} + +.prettyprint code span.line +{ + display: inline-block; +} + +.prettyprint.linenums +{ + padding-left: 70px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.prettyprint.linenums ol +{ + padding-left: 0; +} + +.prettyprint.linenums li +{ + border-left: 3px #ddd solid; +} + +.prettyprint.linenums li.selected, +.prettyprint.linenums li.selected * +{ + background-color: lightyellow; +} + +.prettyprint.linenums li * +{ + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +table { + border-collapse: collapse; + margin-left: 1em; +} + +thead { + background-color: #ddd; + font-weight: bold; +} + +td, th +{ + border: 1px solid #ddd; + margin: 0px; + text-align: left; + vertical-align: baseline; + padding: 4px 6px; + display: table-cell; +} + +.params, .props, .description table, .description td, .description th, .summary td, .summary th +{ + border-spacing: 0; + border: 0; +} + +.params .name, .props .name, .name code, .params .type, .props .type { + color: #4D8053; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 9pt; + white-space: nowrap; +} + +.params td, .params th, .props td, .props th, .description td, .description th +{ + border: 1px solid #ddd; + margin: 0px; + text-align: left; + vertical-align: baseline; + padding: 4px 6px; + display: table-cell; +} + +.params thead tr, .props thead tr, .description thead tr +{ + background-color: #ddd; + font-weight: bold; +} + +.params .params thead tr, .props .props thead tr +{ + background-color: #fff; + font-weight: bold; +} + +.params th, .props th { border-right: 1px solid #aaa; } +.description th { border: 1px solid #aaa; } +.params thead .last, .props thead .last { border-right: 1px solid #ddd; } + +.params td.description > p:first-child, +.props td.description > p:first-child +{ + margin-top: 0; + padding-top: 0; +} + +.params td.description > p:last-child, +.props td.description > p:last-child +{ + margin-bottom: 0; + padding-bottom: 0; +} + +.list-index +{ + margin-top: 2em ; + border-top: 1px solid #ddd ; + border-bottom: 1px solid #ddd ; + margin-bottom: 2em ; +} + +.list-item:hover +{ + background: #ddd ; +} + +.list-title, +.list-descr +{ + border: none; + margin: 0; + padding: 1px 20px 1px 0px ; +} + +.list-separator +{ + border-top: 1px solid #ddd ; +} + +.list-descr p +{ + padding: 0; + margin: 0; +} + +.dimmed +{ + color: #bbb ; +} + +.disabled { + color: #454545; +} diff --git a/Ivette/src/dome/doc/template/static/styles/prettify-jsdoc.css b/Ivette/src/dome/doc/template/static/styles/prettify-jsdoc.css new file mode 100644 index 0000000000000000000000000000000000000000..5a2526e374846d0c80af0c06c25d25215463a0d9 --- /dev/null +++ b/Ivette/src/dome/doc/template/static/styles/prettify-jsdoc.css @@ -0,0 +1,111 @@ +/* JSDoc prettify.js theme */ + +/* plain text */ +.pln { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* string content */ +.str { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a keyword */ +.kwd { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a comment */ +.com { + font-weight: normal; + font-style: italic; +} + +/* a type name */ +.typ { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a literal value */ +.lit { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* punctuation */ +.pun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp open bracket */ +.opn { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp close bracket */ +.clo { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a markup tag name */ +.tag { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute name */ +.atn { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute value */ +.atv { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a declaration */ +.dec { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a variable name */ +.var { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a function name */ +.fun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} diff --git a/Ivette/src/dome/doc/template/static/styles/prettify-tomorrow.css b/Ivette/src/dome/doc/template/static/styles/prettify-tomorrow.css new file mode 100644 index 0000000000000000000000000000000000000000..b6f92a78db990ec1dc52e032452a979b8c216a85 --- /dev/null +++ b/Ivette/src/dome/doc/template/static/styles/prettify-tomorrow.css @@ -0,0 +1,132 @@ +/* Tomorrow Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* Pretty printing styles. Used with prettify.js. */ +/* SPAN elements with the classes below are added by prettyprint. */ +/* plain text */ +.pln { + color: #4d4d4c; } + +@media screen { + /* string content */ + .str { + color: #718c00; } + + /* a keyword */ + .kwd { + color: #8959a8; } + + /* a comment */ + .com { + color: #8e908c; } + + /* a type name */ + .typ { + color: #4271ae; } + + /* a literal value */ + .lit { + color: #f5871f; } + + /* punctuation */ + .pun { + color: #4d4d4c; } + + /* lisp open bracket */ + .opn { + color: #4d4d4c; } + + /* lisp close bracket */ + .clo { + color: #4d4d4c; } + + /* a markup tag name */ + .tag { + color: #c82829; } + + /* a markup attribute name */ + .atn { + color: #f5871f; } + + /* a markup attribute value */ + .atv { + color: #3e999f; } + + /* a declaration */ + .dec { + color: #f5871f; } + + /* a variable name */ + .var { + color: #c82829; } + + /* a function name */ + .fun { + color: #4271ae; } } +/* Use higher contrast and text-weight for printable form. */ +@media print, projection { + .str { + color: #060; } + + .kwd { + color: #006; + font-weight: bold; } + + .com { + color: #600; + font-style: italic; } + + .typ { + color: #404; + font-weight: bold; } + + .lit { + color: #044; } + + .pun, .opn, .clo { + color: #440; } + + .tag { + color: #006; + font-weight: bold; } + + .atn { + color: #404; } + + .atv { + color: #060; } } +/* Style */ +/* +pre.prettyprint { + background: white; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 12px; + line-height: 1.5; + border: 1px solid #ccc; + padding: 10px; } +*/ + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; } + +/* IE indents via margin-left */ +li.L0, +li.L1, +li.L2, +li.L3, +li.L4, +li.L5, +li.L6, +li.L7, +li.L8, +li.L9 { + /* */ } + +/* Alternate shading for lines */ +li.L1, +li.L3, +li.L5, +li.L7, +li.L9 { + /* */ } diff --git a/Ivette/src/dome/doc/template/tmpl/augments.tmpl b/Ivette/src/dome/doc/template/tmpl/augments.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..605c384364be4e131988ca4176f41a1a6fbd072b --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/augments.tmpl @@ -0,0 +1,25 @@ +<?js + var data = obj; + var self = this; + const href = /^\[(.+)\]\((.+)\) */; +?> + +<?js if (data.augments && data.augments.length) { ?> + <div class="summary"> + <table class="summary"> + <tbody> + <?js data.augments.forEach(function(a,descr) { + var m = href.exec(a) ; ?> + <tr> + <?js if (m) { ?> + <td><a href="<?js= m[2] ?>"><?js= m[1] ?></a></td> + <?js } else { ?> + <td><?js= a ?></td> + <?js } ?> + <td>Super Class Methods</td> + </tr> + <?js }) ?> + </tbody> + </table> + </div> +<?js } ?> diff --git a/Ivette/src/dome/doc/template/tmpl/container.tmpl b/Ivette/src/dome/doc/template/tmpl/container.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..6d77d043120425dd43dde4e92d06dfc957481ec6 --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/container.tmpl @@ -0,0 +1,261 @@ +<?js + var self = this; + var isGlobalPage; + + docs.forEach(function(doc, i) { +?> + +<?js + // we only need to check this once + if (typeof isGlobalPage === 'undefined') { + isGlobalPage = (doc.kind === 'globalobj'); + } +?> +<?js if (doc.kind === 'mainpage' || (doc.kind === 'package')) { ?> + <?js= self.partial('mainpage.tmpl', doc) ?> +<?js } else if (doc.kind === 'source') { ?> + <?js= self.partial('source.tmpl', doc) ?> +<?js } else { ?> + +<section> + +<header> + <?js if (!doc.longname || doc.kind !== 'module') { ?> + <h2><?js if (doc.ancestors && doc.ancestors.length) { ?> + <span class="ancestors"><?js= doc.ancestors.join('') ?></span><?js + } + ?><?js= (doc.name && doc.name.startsWith('module:')) ? doc.name.substring(7): doc.name ?><?js + if (doc.variation) { ?> + <sup class="variation"><?js= doc.variation ?></sup> + <?js } ?></h2> + <?js if (doc.classdesc) { ?> + <div class="class-description"><?js= doc.classdesc ?></div> + <?js } ?> + <?js } else if (doc.kind === 'module' && doc.modules) { ?> + <?js doc.modules.forEach(function(module) { ?> + <?js if (module.classdesc) { ?> + <div class="class-description"><?js= module.classdesc ?></div> + <?js } ?> + <?js }) ?> + <?js } ?> +</header> + +<article> + <div class="container-overview"> + <?js if (doc.kind === 'module' && doc.modules) { ?> + <?js if (doc.description) { ?> + <div class="description"><?js= doc.description ?></div> + <?js } ?> + + <?js doc.modules.forEach(function(module) { ?> + <?js= self.partial('method.tmpl', module) ?> + <?js }) ?> + <?js } else if (doc.kind === 'class') { ?> + <?js= self.partial('method.tmpl', doc) ?> + <?js } else { ?> + <?js if (doc.description) { ?> + <div class="description"><?js= doc.description ?></div> + <?js } ?> + + <?js= self.partial('details.tmpl', doc) ?> + + <?js if (doc.examples && doc.examples.length) { ?> + <h3>Example<?js= doc.examples.length > 1? 's':'' ?></h3> + <?js= self.partial('examples.tmpl', doc.examples) ?> + <?js } ?> + <?js } ?> + </div> + + <?js if (doc.augments && doc.augments.length) { ?> + <h3 class="subsection-title">Extends</h3> + + <?js= self.partial('augments.tmpl', doc) ?> + <?js } ?> + + <?js if (doc.requires && doc.requires.length) { ?> + <h3 class="subsection-title">Requires</h3> + + <ul><?js doc.requires.forEach(function(r) { ?> + <li><?js= self.linkto(r, r) ?></li> + <?js }); ?></ul> + <?js } ?> + + <?js + var classes = self.find({kind: 'class', memberof: doc.longname}); + if (!isGlobalPage && classes && classes.length) { + ?> + <h3 class="subsection-title">Classes</h3> + <div class="summary"> + <table class="summary"> + <?js classes.forEach(function(c) { ?> + <tr> + <td><?js= self.linkto(c.longname, c.name) ?></td> + <td><?js if (c.summary) { ?><?js= c.summary ?><?js } ?></td> + </tr> + <?js }); ?> + </table> + </div> + <?js } ?> + + <?js + var mixins = self.find({kind: 'mixin', memberof: doc.longname}); + if (!isGlobalPage && mixins && mixins.length) { + ?> + <h3 class="subsection-title">Mixins</h3> + + <dl><?js mixins.forEach(function(m) { ?> + <dt><?js= self.linkto(m.longname, m.name) ?></dt> + <dd><?js if (m.summary) { ?><?js= m.summary ?><?js } ?></dd> + <?js }); ?></dl> + <?js } ?> + + <?js + var namespaces = self.find({kind: 'namespace', memberof: doc.longname}); + if (!isGlobalPage && namespaces && namespaces.length) { + ?> + <h3 class="subsection-title">Namespaces</h3> + + <dl><?js namespaces.forEach(function(n) { ?> + <dt><?js= self.linkto(n.longname, n.name) ?></dt> + <dd><?js if (n.summary) { ?><?js= n.summary ?><?js } ?></dd> + <?js }); ?></dl> + <?js } ?> + + <?js + var members = self.find({kind: 'member', memberof: isGlobalPage ? {isUndefined: true} : doc.longname}); + var methods = self.find({kind: 'function', memberof: isGlobalPage ? {isUndefined: true} : doc.longname}); + + var hasMembers = members && members.length && members.forEach ; + var hasMethods = methods && methods.length && methods.forEach ; + + // symbols that are assigned to module.exports are not globals, even though they're not a memberof anything + if (isGlobalPage && hasMembers) { + members = members.filter(function(m) { + return m.longname && m.longname.indexOf('module:') !== 0; + }); + hasMembers = members && members.length && members.forEach ; + } + + var makeWarning = ( m , msg ) => { + let ident = m.longname + ':' ; + if (m.meta) { + let { path, filename, lineno } = m.meta ; + let root = process.env['DOME_PWD']; + let dir = root && path.startsWith(root) ? path.substring(root.length+1) : path ; + ident = dir + '/' + filename + ':' + lineno + ': (' + m.name + ')' ; + } + console.warn( ident, msg); + }; + + var makeSummary = (m) => { + if (m.summary) { + let s = m.summary.trim() ; + if ( s.startsWith('<p>') && s[3].toUpperCase() !== s[3] ) + makeWarning( m , "Not capitalized @summary" ); + if ( s.startsWith('<p>') && ! s.endsWith('.</p>') ) + makeWarning( m , "Missing @summary final '.'" ); + return s; + } + let descr = m.description ; + if (descr && typeof(descr)=='string' && descr.startsWith("<p>")) { + let pos = descr.indexOf("</p>"); + if (0 <= pos && pos < 60) return descr.substring(0,pos)+"</p>"; + } + makeWarning( m , "Missing @summary" ); + return '<span class="dimmed">(details below)</span>' ; + }; + + if ( hasMembers || hasMethods ) { + ?> + + <h3 class="subsection-title">Summary</h3> + <table class="list-index"> + <?js hasMembers && members.forEach(function(m) { ?> + <tr class="list-item"> + <td class="list-title"> + <a href="#<?js= m.id ?>"><code><?js= m.name ?></code></a> + </td> + <td class="list-descr"> + <?js= makeSummary(m) ?> + </tr> + <?js }); ?> + + <?js if (hasMethods && hasMembers) { ?> + <tr class="list-separator"> + <td class="list-title"/> + <td class="list-descr"/> + </tr> + <?js } ?> + + <?js hasMethods && methods.forEach(function(m) { ?> + <tr class="list-item"> + <td class="list-title"> + <a href="#<?js= m.id ?>"><code><?js= m.name ?>()</code></a> + </td> + <td class="list-descr"> + <?js= makeSummary(m) ?> + </td> + </tr> + <?js }); ?> + </table> + + <?js } ?> + + <?js + if (hasMembers) { + ?> + <h3 class="subsection-title">Members</h3> + + <?js members.forEach(function(p) { ?> + <?js= self.partial('members.tmpl', p) ?> + <?js }); ?> + <?js } ?> + + <?js + + if (hasMethods) { + ?> + + <h3 class="subsection-title">Methods</h3> + + <?js methods.forEach(function(m) { ?> + <?js= self.partial('method.tmpl', m) ?> + <?js }); ?> + <?js } ?> + + <?js + var typedefs = self.find({kind: 'typedef', memberof: isGlobalPage ? {isUndefined: true} : doc.longname}); + if (typedefs && typedefs.length && typedefs.forEach) { + ?> + <h3 class="subsection-title">Type Definitions</h3> + + <?js typedefs.forEach(function(e) { + if (e.signature) { + ?> + <?js= self.partial('method.tmpl', e) ?> + <?js + } + else { + ?> + <?js= self.partial('members.tmpl', e) ?> + <?js + } + }); ?> + <?js } ?> + + <?js + var events = self.find({kind: 'event', memberof: isGlobalPage ? {isUndefined: true} : doc.longname}); + if (events && events.length && events.forEach) { + ?> + <h3 class="subsection-title">Events</h3> + + <?js events.forEach(function(e) { ?> + <?js= self.partial('method.tmpl', e) ?> + <?js }); ?> + <?js } ?> +</article> + +</section> +<?js } ?> + +<?js }); ?> diff --git a/Ivette/src/dome/doc/template/tmpl/details.tmpl b/Ivette/src/dome/doc/template/tmpl/details.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..3b1ee84c1324ff1399e2a81946bf19eeb9d5ced5 --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/details.tmpl @@ -0,0 +1,143 @@ +<?js +var data = obj; +var self = this; +var defaultObjectClass = ''; + +// Check if the default value is an object or array; if so, apply code highlighting +if (data.defaultvalue && (data.defaultvaluetype === 'object' || data.defaultvaluetype === 'array')) { + data.defaultvalue = "<pre class=\"prettyprint\"><code>" + data.defaultvalue + "</code></pre>"; + defaultObjectClass = ' class="object-value"'; +} +?> +<?js + var properties = data.properties; + if (properties && properties.length && properties.forEach) { +?> + + <h5 class="subsection-title">Properties</h5> + + <?js= this.partial('properties.tmpl', data) ?> + +<?js } ?> + +<dl class="details"> + + <?js if (data.version) {?> + <dt class="tag-version">Version:</dt> + <dd class="tag-version"><ul class="dummy"><li><?js= version ?></li></ul></dd> + <?js } ?> + + <?js if (data.since) {?> + <dt class="tag-since">Since:</dt> + <dd class="tag-since"><ul class="dummy"><li><?js= since ?></li></ul></dd> + <?js } ?> + + <?js if (data.inherited && data.inherits && !data.overrides) { ?> + <dt class="inherited-from">Inherited From:</dt> + <dd class="inherited-from"><ul class="dummy"><li> + <?js= this.linkto(data.inherits, this.htmlsafe(data.inherits)) ?> + </li></ul></dd> + <?js } ?> + + <?js if (data.overrides) { ?> + <dt class="tag-overrides">Overrides:</dt> + <dd class="tag-overrides"><ul class="dummy"><li> + <?js= this.linkto(data.overrides, this.htmlsafe(data.overrides)) ?> + </li></ul></dd> + <?js } ?> + + <?js if (data.implementations && data.implementations.length) { ?> + <dt class="implementations">Implementations:</dt> + <dd class="implementations"><ul> + <?js data.implementations.forEach(function(impl) { ?> + <li><?js= self.linkto(impl, self.htmlsafe(impl)) ?></li> + <?js }); ?> + </ul></dd> + <?js } ?> + + <?js if (data.implements && data.implements.length) { ?> + <dt class="implements">Implements:</dt> + <dd class="implements"><ul> + <?js data.implements.forEach(function(impl) { ?> + <li><?js= self.linkto(impl, self.htmlsafe(impl)) ?></li> + <?js }); ?> + </ul></dd> + <?js } ?> + + <?js if (data.mixes && data.mixes.length) { ?> + <dt class="mixes">Mixes In:</dt> + + <dd class="mixes"><ul> + <?js data.mixes.forEach(function(a) { ?> + <li><?js= self.linkto(a, a) ?></li> + <?js }); ?> + </ul></dd> + <?js } ?> + + <?js if (data.deprecated) { ?> + <dt class="important tag-deprecated">Deprecated:</dt><?js + if (data.deprecated === true) { ?><dd class="yes-def tag-deprecated"><ul class="dummy"><li>Yes</li></ul></dd><?js } + else { ?><dd><ul class="dummy"><li><?js= data.deprecated ?></li></ul></dd><?js } + ?> + <?js } ?> + + <?js if (data.author && author.length) {?> + <dt class="tag-author">Author:</dt> + <dd class="tag-author"> + <ul><?js author.forEach(function(a) { ?> + <li><?js= self.resolveAuthorLinks(a) ?></li> + <?js }); ?></ul> + </dd> + <?js } ?> + + <?js if (data.copyright) {?> + <dt class="tag-copyright">Copyright:</dt> + <dd class="tag-copyright"><ul class="dummy"><li><?js= copyright ?></li></ul></dd> + <?js } ?> + + <?js if (data.license) {?> + <dt class="tag-license">License:</dt> + <dd class="tag-license"><ul class="dummy"><li><?js= license ?></li></ul></dd> + <?js } ?> + + <?js if (data.defaultvalue) {?> + <dt class="tag-default">Default Value:</dt> + <dd class="tag-default"><ul class="dummy"> + <li<?js= defaultObjectClass ?>><?js= data.defaultvalue ?></li> + </ul></dd> + <?js } ?> + + <?js if (data.meta && self.outputSourceFiles) {?> + <dt class="tag-source">Source:</dt> + <dd class="tag-source"><ul class="dummy"><li> + <?js= self.linkto(meta.shortpath) ?>, <?js= self.linkto(meta.shortpath, 'line ' + meta.lineno, null, 'line' + meta.lineno) ?> + </li></ul></dd> + <?js } ?> + + <?js if (data.tutorials && data.tutorials.length) {?> + <dt class="tag-tutorial">Tutorial<?js= data.tutorials.length > 1 ? 's' : '' ?>:</dt> + <dd class="tag-tutorial"> + <ul><?js tutorials.forEach(function(t) { ?> + <li><?js= self.tutoriallink(t) ?></li> + <?js }); ?></ul> + </dd> + <?js } ?> + + <?js if (data.see && data.see.length) {?> + <dt class="tag-see">See:</dt> + <dd class="tag-see"> + <ul><?js see.forEach(function(s) { ?> + <li><?js= self.linkto(s) ?></li> + <?js }); ?></ul> + </dd> + <?js } ?> + + <?js if (data.todo && data.todo.length) {?> + <dt class="tag-todo">To Do:</dt> + <dd class="tag-todo"> + <ul><?js todo.forEach(function(t) { ?> + <li><?js= t ?></li> + <?js }); ?></ul> + </dd> + <?js } ?> +</dl> diff --git a/Ivette/src/dome/doc/template/tmpl/example.tmpl b/Ivette/src/dome/doc/template/tmpl/example.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..e87caa5b72ca5b7830eb74495b831d237b3260c9 --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/example.tmpl @@ -0,0 +1,2 @@ +<?js var data = obj; ?> +<pre><code><?js= data ?></code></pre> diff --git a/Ivette/src/dome/doc/template/tmpl/examples.tmpl b/Ivette/src/dome/doc/template/tmpl/examples.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..04d975e96dc52016b0a0b7edb5139c14597b96ff --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/examples.tmpl @@ -0,0 +1,13 @@ +<?js + var data = obj; + var self = this; + + data.forEach(function(example) { + if (example.caption) { + ?> + <p class="code-caption"><?js= example.caption ?></p> + <?js } ?> + <pre class="prettyprint"><code><?js= self.htmlsafe(example.code) ?></code></pre> +<?js + }); +?> \ No newline at end of file diff --git a/Ivette/src/dome/doc/template/tmpl/exceptions.tmpl b/Ivette/src/dome/doc/template/tmpl/exceptions.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..9cef6c7d9516f0df44b7081cb89609b388623a39 --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/exceptions.tmpl @@ -0,0 +1,32 @@ +<?js + var data = obj; +?> +<?js if (data.description && data.type && data.type.names) { ?> +<dl> + <dt> + <div class="param-desc"> + <?js= data.description ?> + </div> + </dt> + <dd></dd> + <dt> + <dl> + <dt> + Type + </dt> + <dd> + <?js= this.partial('type.tmpl', data.type.names) ?> + </dd> + </dl> + </dt> + <dd></dd> +</dl> +<?js } else { ?> + <div class="param-desc"> + <?js if (data.description) { ?> + <?js= data.description ?> + <?js } else if (data.type && data.type.names) { ?> + <?js= this.partial('type.tmpl', data.type.names) ?> + <?js } ?> + </div> +<?js } ?> diff --git a/Ivette/src/dome/doc/template/tmpl/layout.tmpl b/Ivette/src/dome/doc/template/tmpl/layout.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..39dbc7889cba155499dcee4923c9df7cd4d1820e --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/layout.tmpl @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title><?js= title ?></title> + + <script src="scripts/prettify/prettify.js"> </script> + <script src="scripts/prettify/lang-css.js"> </script> + <!--[if lt IE 9]> + <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> + <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> +</head> + +<body> + <div id="main"> + <div id="content"> + <div id="page"> + <h1 class="page-title"> + <?js=( + title.startsWith('Class: module:') ? 'Class ' + title.substring(14) : + title.startsWith('Class: ') ? 'Class ' + title.substring(7) : + title.startsWith('Event: ') ? 'Event ' + title.substring(7) : + title.startsWith('Module: ') ? 'Module ' + title.substring(8) : + title.startsWith('Tutorial: ') ? title.substring(10) + ' (tutorial)' : + title + )?> + </h1> + <?js= content ?> + <br class="clear"> + <footer> + Copyright (©) <?js= process.env.COPYRIGHT ?> <?js= (new Date()).getFullYear() ?> + </footer> + </div> + </div> + + <div id="index"> + <nav> + <?js= this.nav ?> + </nav> + </div> + + </div> +<script> prettyPrint(); </script> +<script src="scripts/linenumber.js"> </script> +</body> +</html> diff --git a/Ivette/src/dome/doc/template/tmpl/mainpage.tmpl b/Ivette/src/dome/doc/template/tmpl/mainpage.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..64e9e5943a1ddeb4a81dfa9d8b3fc1d957eb7f26 --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/mainpage.tmpl @@ -0,0 +1,14 @@ +<?js +var data = obj; +var self = this; +?> + +<?js if (data.kind === 'package') { ?> + <h3><?js= data.name ?> <?js= data.version ?></h3> +<?js } ?> + +<?js if (data.readme) { ?> + <section> + <article><?js= data.readme ?></article> + </section> +<?js } ?> diff --git a/Ivette/src/dome/doc/template/tmpl/members.tmpl b/Ivette/src/dome/doc/template/tmpl/members.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..66a2799d1738a5d7e26244d5da64d8da45b2868d --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/members.tmpl @@ -0,0 +1,40 @@ +<?js +var data = obj; +var self = this; +?> +<h4 class="name" id="<?js= id ?>"><?js= data.attribs + name + (data.signature ? data.signature : '') ?> +<a class="anchor" href="#<?js= id ?>">♯</a> +</h4> + +<?js if (data.summary) { ?> +<p class="summary"><?js= data.summary ?></p> +<?js } ?> + +<?js if (data.description) { ?> +<div class="description"> + <?js= data.description ?> +</div> +<?js } ?> + +<?js if (data.type && data.type.names) {?> + <h5>Type</h5> + <ul> + <li> + <?js= self.partial('type.tmpl', data.type.names) ?> + </li> + </ul> +<?js } ?> + +<?js= this.partial('details.tmpl', data) ?> + +<?js if (data.fires && fires.length) { ?> + <h5>Fires</h5> + <ul><?js fires.forEach(function(f) { ?> + <li><?js= self.linkto(f) ?></li> + <?js }); ?></ul> +<?js } ?> + +<?js if (data.examples && examples.length) { ?> + <h5>Example<?js= examples.length > 1? 's':'' ?></h5> + <?js= this.partial('examples.tmpl', examples) ?> +<?js } ?> diff --git a/Ivette/src/dome/doc/template/tmpl/method.tmpl b/Ivette/src/dome/doc/template/tmpl/method.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..c29c67b7ccd7707fd03d098a9a82b5c5d91dc571 --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/method.tmpl @@ -0,0 +1,103 @@ +<?js +var data = obj; +var self = this; +?> + +<?js if (data.kind !== 'module') { ?> + <?js if (data.kind === 'class' && data.classdesc) { ?> + <h2>Constructor</h2> + <?js } ?> + + <?js if (data.kind !== 'class') { ?> + <h4 class="name" id="<?js= id ?>"><?js= data.attribs + name + (data.signature || '') ?> + <a class="anchor" href="#<?js= id ?>">♯</a> + </h4> + <?js } ?> + + <?js if (data.summary) { if (data.kind === 'class') { ?> + <div class="summary"><p><?js= data.summary ?></p></div> + <?js } else { ?> + <p class="summary"><?js= data.summary ?></p> + <?js }} ?> +<?js } ?> + +<?js if (data.kind !== 'module' && data.description) { ?> +<div class="description"> + <?js= data.description ?> +</div> +<?js } ?> + +<?js if (data.augments && data.alias && data.alias.indexOf('module:') === 0) { ?> + <h5>Extends</h5> + <?js= self.partial('augments.tmpl', data) ?> +<?js } ?> + +<?js if (kind === 'event' && data.type && data.type.names) {?> + <h5>Type</h5> + <ul> + <li> + <?js= self.partial('type.tmpl', data.type.names) ?> + </li> + </ul> +<?js } ?> + +<?js if (data['this']) { ?> + <h5>This</h5> + <ul><li><?js= this.linkto(data['this'], data['this']) ?></li></ul> +<?js } ?> + +<?js if (data.params && params.length) { ?> + <h5>Parameters</h5> + <?js= this.partial('params.tmpl', params) ?> +<?js } ?> + +<?js if (data.kind !== 'module' && data.requires && data.requires.length) { ?> +<h5>Requires</h5> +<ul><?js data.requires.forEach(function(r) { ?> + <li><?js= self.linkto(r) ?></li> +<?js }); ?></ul> +<?js } ?> + +<?js if (data.fires && fires.length) { ?> +<h5>Fires</h5> +<ul><?js fires.forEach(function(f) { ?> + <li><?js= self.linkto(f) ?></li> +<?js }); ?></ul> +<?js } ?> + +<?js if (data.listens && listens.length) { ?> +<h5>Events</h5> +<ul><?js listens.forEach(function(f) { ?> + <li><?js= self.linkto(f) ?></li> +<?js }); ?></ul> +<?js } ?> + +<?js if (data.listeners && listeners.length) { ?> +<h5>Listeners</h5> +<ul><?js listeners.forEach(function(f) { ?> + <li><?js= self.linkto(f) ?></li> +<?js }); ?></ul> +<?js } ?> + +<?js if (data.exceptions && exceptions.length) { ?> +<h5>Throws</h5> +<?js if (exceptions.length > 1) { ?><ul><?js + exceptions.forEach(function(r) { ?> + <li><?js= self.partial('exceptions.tmpl', r) ?></li> + <?js }); +?></ul><?js } else { + exceptions.forEach(function(r) { ?> + <?js= self.partial('exceptions.tmpl', r) ?> + <?js }); +} } ?> + +<?js if (data.returns && returns.length) { ?> + <h5>Returns</h5> + <?js= this.partial('returns.tmpl',returns) ?><?js } ?> + +<?js if (data.examples && examples.length) { ?> + <h5>Example<?js= examples.length > 1? 's':'' ?></h5> + <?js= this.partial('examples.tmpl', examples) ?> +<?js } ?> + +<?js= this.partial('details.tmpl', data) ?> diff --git a/Ivette/src/dome/doc/template/tmpl/params.tmpl b/Ivette/src/dome/doc/template/tmpl/params.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..000e36fb480364cb6c3cbb98cea8b4a6d5aecdc9 --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/params.tmpl @@ -0,0 +1,76 @@ +<?js + var params = obj; + + /* sort subparams under their parent params (like opts.classname) */ + var parentParam = null; + params.forEach(function(param, i) { + var paramRegExp; + + if (!param) { + return; + } + + if (parentParam && parentParam.name && param.name) { + paramRegExp = new RegExp('^(?:' + parentParam.name + '(?:\\[\\])*)\\.(.+)$'); + + if ( paramRegExp.test(param.name) ) { + param.name = RegExp.$1; + parentParam.subparams = parentParam.subparams || []; + parentParam.subparams.push(param); + params[i] = null; + } + else { + parentParam = param; + } + } + else { + parentParam = param; + } + }); + +?> + +<table class="params"> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th class="last">Description</th> + </tr> + </thead> + + <tbody> + <?js + var self = this; + const displayParam = (param,indent=0) => { + if (!param) { return; } + ?> + + <tr> + <td class="name"> + <code> + <?js for( var k = 0; k < indent; k++) { ?> + + <?js } ?> + <?js= (indent ? '.' : '') + param.name + (param.variable ? '...' : '') ?> + </code> + </td> + <td class="type"> + <?js if (param.type && param.type.names) {?> + <?js= self.partial('type.tmpl', param.type.names) ?> + <?js if (param.optional) { ?> + (opt.) + <?js } ?> + <?js } ?> + </td> + <td class="description last"> + <?js= param.description ?> + </td> + </tr> + <?js if (param.subparams) param.subparams.forEach((p) => displayParam(p,indent+1)); ?> + <?js + }; + params.forEach( (p) => displayParam(p) ); + ?> + </tbody> +</table> diff --git a/Ivette/src/dome/doc/template/tmpl/properties.tmpl b/Ivette/src/dome/doc/template/tmpl/properties.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..4c73e65805e7496e79e5d1e2eb8935bf12214995 --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/properties.tmpl @@ -0,0 +1,75 @@ +<?js + var data = obj; + var props = data.subprops || data.properties; + + /* sort subprops under their parent props (like opts.classname) */ + var parentProp = null; + props.forEach(function(prop, i) { + if (!prop) { return; } + if ( parentProp && prop.name && prop.name.indexOf(parentProp.name + '.') === 0 ) { + prop.name = prop.name.substr(parentProp.name.length+1); + parentProp.subprops = parentProp.subprops || []; + parentProp.subprops.push(prop); + props[i] = null; + } + else { + parentProp = prop; + } + }); +?> + +<table class="props"> + <thead> + <tr> + <th>Name</th> + <th>Type</th> + <th class="last">Description</th> + </tr> + </thead> + + <tbody> + <?js + var self = this; + const displayProp = (prop,indent=0) => { + if (!prop) { return; } + ?> + + <tr> + <td class="name"> + <code> + <?js for( var k = 0; k < indent; k++) { ?> + + <?js } ?> + <?js= (indent ? '.' : '') + prop.name ?> + </code> + </td> + <td class="type"> + <?js if (prop.type && prop.type.names) {?> + <?js= self.partial('type.tmpl', prop.type.names) ?> + <?js if (prop.optional) { ?> + (opt.) + <?js } ?> + <?js } ?> + </td> + <td class="description last"> + <?js= prop.description ?> + </td> + </tr> + <?js if (prop.subprops) prop.subprops.forEach((p) => displayProp(p,indent+1)); ?> + + <?js + }; + props.forEach( (p) => displayProp(p) ); + ?> + <?js if (data.augments && data.augments.length) data.augments.forEach((a) => { + const href = /^\[(.+)\]\((.+)\) */; + const m = href.exec(a); + if (m) { ?> + <tr> + <td><tt>...</tt></td> + <td><a href="<?js= m[2] ?>"><?js= m[1] ?></a></td> + <td>Super Class Properties</td> + </tr> + <?js }})?> + </tbody> +</table> diff --git a/Ivette/src/dome/doc/template/tmpl/returns.tmpl b/Ivette/src/dome/doc/template/tmpl/returns.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..0f24cbdb24a75db621659650dab9c23763b1037e --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/returns.tmpl @@ -0,0 +1,25 @@ +<?js var returns = obj; const self = this; ?> + +<table class="params"> + <thead> + <tr> + <th>Type</th> + <th class="last">Description</th> + </tr> + </thead> + <tbody> +<?js returns.forEach(function (r) { ?> + + <tr> + <td class="type"> + <?js if (r.type && r.type.names) { ?> + <?js= self.partial('type.tmpl', r.type.names) ?> + <?js } ?> + </td> + <td class="description last"> + <?js= r.description ?> + </td> + +<?js }); ?> + </tbody> +</table> diff --git a/Ivette/src/dome/doc/template/tmpl/source.tmpl b/Ivette/src/dome/doc/template/tmpl/source.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..e559b5d1038845d0cc0ee221fbd556fe85f0eb09 --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/source.tmpl @@ -0,0 +1,8 @@ +<?js + var data = obj; +?> + <section> + <article> + <pre class="prettyprint source linenums"><code><?js= data.code ?></code></pre> + </article> + </section> \ No newline at end of file diff --git a/Ivette/src/dome/doc/template/tmpl/tutorial.tmpl b/Ivette/src/dome/doc/template/tmpl/tutorial.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..88a0ad52aa2ce51ad0da458d8cd7dff610b67921 --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/tutorial.tmpl @@ -0,0 +1,19 @@ +<section> + +<header> + <?js if (children.length > 0) { ?> + <ul><?js + var self = this; + children.forEach(function(t) { ?> + <li><?js= self.tutoriallink(t.name) ?></li> + <?js }); ?></ul> + <?js } ?> + + <h2><?js= header ?></h2> +</header> + +<article> + <?js= content ?> +</article> + +</section> diff --git a/Ivette/src/dome/doc/template/tmpl/type.tmpl b/Ivette/src/dome/doc/template/tmpl/type.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..ec2c6c0df7211a1791ad1b52be218ce00500d967 --- /dev/null +++ b/Ivette/src/dome/doc/template/tmpl/type.tmpl @@ -0,0 +1,7 @@ +<?js + var data = obj; + var self = this; + data.forEach(function(name, i) { ?> +<span class="param-type"><?js= self.linkto(name, self.htmlsafe(name)) ?></span> +<?js if (i < data.length-1) { ?>|<?js } ?> +<?js }); ?> \ No newline at end of file diff --git a/Ivette/src/dome/doc/tutorials/application.md b/Ivette/src/dome/doc/tutorials/application.md new file mode 100644 index 0000000000000000000000000000000000000000..ec13570b91555ef2bc7ca83a7a859836bfb737fe --- /dev/null +++ b/Ivette/src/dome/doc/tutorials/application.md @@ -0,0 +1,119 @@ +<!-- Application Design --> + +This tutorial introduces how to design a **Dome** application within the +**Electron** & **React** frameworks. You shall be reasonably familiar with +**React** concepts, but no knowledge of **Electron** is required. + +A desktop **Dome** application looks like a native application, but is actually +a static web page rendered in a **Chrome** web browser. This is what provides +the **Electron** framework by default. **Dome** is simply a library of **React** +components and development templates tuned together to enable professional +application development. + +This tutorial provides an overview of this environment and how to design a typical +**Dome** application. + +## System Architecture + +Following the **Electron** framework design, your application will consists of +two different processes interacting with each others. +One is responsible for the management of the main GUI resources +(windows, menu-bar, desktop interaction, user settings, etc.) +and is named the `Main` process. +The second one will be responsible for running the +web page holding the main application window, and is named the `Renderer` process. +Both kind of process communicates through the message-passing API provided by +the **Electron** framework. + +When several instances of your application are running simultaneously, each invokation +have its own window, running its owan, separate `Renderer` process. However, the +**Dome** framework automatically makes them sharing the same `Main` process. + +Hence, each application instance has its own working directory and command-line arguments, +depending on how its has been launched by the user. The **Dome** framework build +both command-line and desktop entry points, depending on each target platform. + +## Event Driven Design + +On the renderer process side, the **React** framework induces a natural design where +_Application State_ is separated from _Application Rendering_. Moreover, +following a popular design introduced with **Redux**, application rendering tend +to be written like a pure function (or _view_) on the state, where user +actions are just state updater callbacks. Each time the state is modified, the +entire application rendering is recomputed, and **React** computes a minimal +diff to apply on the web page displayed in the main application window. + +Putting everything together, its is recommended to design **Dome** application +into two different parts, both running in the `Renderer` process of each +application instance: + +- **Application Internals (State)** +holding your application state and data and updating it in response to user or +system events; + +- **Application Components (View)** +responsible for rendering the application main window and +binding callbacks to application services. + +<img src="dataflow.png" style="float: right; width: 30em"/> + +Such an architecture is typical of a _Model-View-Controller_ design, but +revisited to scale. In particular, data flow between those three different +layers shall follow a unique-direction pattern in order to avoid the +combinatorial explosion of interactions between components that is generally +observed in most Model-View-Controller designs. + +Hence, data-flow shall follow one of the following routes between these +three layers, illustrated above: + +- from `State` to `View` : your rendering components shall only access the +current application state and data; +- from `View` to `State` or `System` : user action callbacks shall only trigger +state update or system operation, not any other view direct modification. +- from `System` to `State` : upon completion, system services shall trigger state +updates that would in turn trigger new requests and view re-rendering. + +## Data Management + +To implement the recommended data-flow described above, you may use a full +featured [Redux](https://redux.js.org) platform or any other framework of your +choice. However, **Dome** provides you with many facilities for implementing +your data flow. + +- **Global States** are necessary to implement the unidirectional data-flow. These + data are stored in the renderer process, but outside of the view hierarchy of + **React** components actually mounted in the DOM. Hence, it remains consistent whatever + the evolution of the view. See `Dome.State` class and the associated custom **React** hooks + to implement global states. You may also use global JavaScript variables and emit events + on your own. + +- **Local States** are necessary to maintain local states associated + to views. We strongly encourage the use of the `Dome.useState()` hook for this + purpose, since it generalizes `React.useState()` with persistent window settings + (see below). + +- **View Updates** to make your views listening for updates of the various data + sources, we encourage to use the **React** hooks we provide, since they + transparently make your components to re-render when required. However, + sometimes you will need to respond to special events by hand. For this purpose, + you can use **Dome** as a central event emitter, by using `Dome.emit()`, + `Dome.on()` and `Dome.off()` functions. Moreover, the `Dome.useUpdate()` and + `Dome.useEvent()` hooks can be used to make your components being notified by + events. + +- **Window Settings** are stored in the user's home directory but remain + generally unnoticed by most users, although they are responsible for a good user + experience. They typically include the window's position and dimension, + resizable items position, fold/unfold states, presentation options, etc. Most + **Dome** components with presentation options can be assigned a `settings` key + to make their state persistent. Contrary to Global Settings, however, they are + not shared across several windows. You may also access these data by using + `Dome.setWindowSetting()` and `Dome.getWindowSetting()`, or the **React** hook + `Dome.useWindowSetting()`. + +- **Global Settings** are stored in the user's home directory and automatically + saved and load with your application; they are typically modified _via_ the + Settings Window, which is accessible from the application menubar. In **Dome**, + you access these data by using `Dome.setGlobalSetting()` and + `Dome.getGlobalSetting()`, or the **React** hook `Dome.useGlobalSetting()`. + Settings must be JSON serializable JavaScript values. diff --git a/Ivette/src/dome/doc/tutorials/dataflow.png b/Ivette/src/dome/doc/tutorials/dataflow.png new file mode 100644 index 0000000000000000000000000000000000000000..648a290cadfa3d89ffe5861b76076ab18edfeac1 Binary files /dev/null and b/Ivette/src/dome/doc/tutorials/dataflow.png differ diff --git a/Ivette/src/dome/doc/tutorials/development.md b/Ivette/src/dome/doc/tutorials/development.md new file mode 100644 index 0000000000000000000000000000000000000000..7a10355c1379132572e05ce13391ff3e0ebf6ddb --- /dev/null +++ b/Ivette/src/dome/doc/tutorials/development.md @@ -0,0 +1,204 @@ +<!-- Application Development --> + +The [Quick Start](tutorial-quickstart.html) tutorial introduces how to setup a new application project, +and [Application Design](tutorial-application.html) draw a high-level view of how it works. +This tutorial goes into more details about the development environment provided by the **Dome** +framework. + + +## HTML & JavaScript Environment + +The Web environment for designing your application is based on the following +framework: + +- **Electron** [v5.0+](https://electronjs.org) runtime environment (packaging Chrome and Node) +- **Node** [v12.0+](https://nodejs.org/dist/latest-v12.x/docs/api) provided by Electron +- **Chromium** [v73.0+](https://www.chromium.org/Home) HTML rendering engine provided by Electron + +You will write your application in a an environment setup with the following +JavaScript features: + +- **Webpack** for packaging the application from sources +- **Babel** to parse language extensions +- **Babel Presets Env** to use ECMA modules and JavaScript strict mode +- **Babel Presets React** to use JSX react notation in all your `*.js` files +- **Babel Object Rest Spread** to use object spread syntax `{ ...props }` +- **React v16** with its latest features (including Hooks) +- **React Hot Loader** for [live-editing](tutorial-hotreload.html) your application +- **CSS Loader** to load and install `*.css` files + +## Available Packages + +The implementation and internals of the **Dome** framework rely on +high-quality and mature popular packages. They are automatically packed +into your dependencies by the provided template makefile. We list them here +since you may re-use them for your own purpose: + +- [**Lodash**](https://lodash.com) convenient JavaScript utilities +- [**React-Virtualized**](http://bvaughn.github.io/react-virtualized) +for layout of large data set in list, tables and grids +- [**React-Draggable**](https://github.com/mzabriskie/react-draggable) +for straightforward drag-and-drop features +- [**CodeMirror**](https://codemirror.net) for rich text capabilities and edition +that scales on large document +- [**ZeroMQ**](http://zeromq.org) for inter-process and distant communications +(see also [System Services](tutorial-services.html)). + + +## Project Files Organization + +The main directory holding your application project with **Dome** consists of +several files and directories. Each is created and/or managed by various +entities : yourself the **Developer**, the **Dome** template makefile, the +**Yarn** JavaScript package manager and the **Electron** suite of +utilities. Parts of those files are generated and updated on demand and shall or +shall _not_ be tracked in your source version control system, be it based on `git`, +`svn` or anything else. + +Most files are actually created and used by **Dome**, **Electron** and **Yarn**. +However, that are _in fine_ under the responsibility of the **Developer** +since you can edit and extend them to fit your needs. +Those generated files generally contains comments to indicate how you +can extend them. You shall put those files under version control only if you edit them. + +As depicted in the [Quick Start](tutorial-quickstart.html) tutorial, the only file you +need to create by yourself is the main `Makefile`, with a minimal content +limited to: + +```makefile +DOME="..." ;; path to your dome installation +include $(DOME)/template/makefile +``` + +The following table lists the main files and directories of your project, with +the associated entity responsible for it, and whether they should be tracked by +your source version control system (VCS). + +Optional files are tagged with « (Opt.) » in the corresponding `Entity` column, +and are _not_ generated by default. Similarly, files mainly used by the system +but that can still be configured by the developer are tagged with « (+Dev) ». +Files are tagged with « ✓(*) » in the `VCS` column shall be tracked only if you +actually modified them. + +| File or Directory | Description | Entity | VCS | +|:------------------|:------------|:-------:|:---:| +| `./Makefile` | Drives the build system | **Developer** | ✓ | +| `./src/main/` | Sources for the main process | **Developer** | ✓ | +| `./src/main/index.js` | Main process entry point | **Electron** (+Dev) | ✓ | +| `./src/renderer/` | Sources for the renderer process | **Developer** | ✓ | +| `./src/renderer/index.js` | Renderer process entry point | **Electron** (+Dev) | ✓ | +| `./src/renderer/Application.js` | Top React component of the main application window | **Developer** | ✓ | +| `./src/renderer/Preferences.js` | Top React component of the user preferences window | **Developer** | ✓ | +| `./src/common/` | Sources for _both_ processes | **Developer** (Opt.) | ✓ | +| `./static/` | Static resources | **Developer** (Opt.) | ✓ | +| `./package.json` | JavaScript packages configuration | **Yarn** (+Dev) | ✓ | +| `./node_modules` | Downloaded packages | **Yarn** | ð„‚ | +| `./yarn.lock` | Packages versions stamps | **Yarn** | ✓ | +| `./electron-webpack.json` | Electron configuration | **Electron** (+Dev) | ✓(*) | +| `./babelrc` | Babel configuration | **Electron** (+Dev) | ✓(*) | +| `./webpack.main.json` | Webpack main process config. | **Electron** (+Dev) | ✓(*) | +| `./webpack.renderer.json` | Webpack renderer process config. | **Electron** (+Dev) | ✓(*) | +| `./.dome-*` | Dome makefile stamps | **Dome** | ð„‚ | +| `$(DOME)/*` | Dome framework clone | **Dome** | (var.) | +| `./dist/` | Packaged application | **Dome** | ð„‚ | +| `./bin/` | Local command-lines | **Dome** | ð„‚ | + +The main entry points of the two **Electron** processes running your application, +`src/main/index.js` and `src/renderer/index.js` shall be modified with extreme care, +since they are in charge with the correct bootstrap of your application. +The generated files from **Dome** templates contains explicit comments and guidelines. + +You may want to modify the name of your application top-level **React** components, +namely `src/renderer/Application.js` and `src/render/Preferences.js` by default. +To do this, you shall hook into the +`src/renderer/index.js` file and follow the provided comments and guidelines, +and set the `DOME_CUSTOM_ENTRIES` variable into your own `./Makefile` to make +**Dome** aware about this. + +If you need static resource files to be packed with your application, put them in the `static` directory. +You can then access to their actual path from your code by using the `System.getStatic(<path>)` utility function. + +The location of the **Dome** resources actually depends on the developer +profile, as explained in more detailed in the [Live Editing](tutorial-hotreload.html) tutorial. +To summarize: +- for normal developers, it can be a local copy of the dome framework, for instance in your `/usr/local/lib/dome` directory; +- for developers working with a specific or modified version of the dome framework, it can be in the local +`./dome/` directory of your project, with or without versioning control; +- for **Dome** developers, it is also possible to clone the Git repository inside the `./src/dome/` sub-directory of your +project, hence also enabling live-editing of **Dome** itself; +- for **Dome** maintainers, it is even possible to use the root of the **Dome** development repository as an application project +in itself, for demos, examples or testing purposes. + +Most of the **Electron** configuration files depends on the definition of the +`DOME` environment variable to find the necessary resources for your application +during development. Commands initiated by **Dome** from `$(DOME)/template/makefile` +will explicitly copy the `$(DOME)` makefile variable into the `$DOME` shell environment +variable when calling the **Electron** builder utilities, and might use it to generate static +files from templates, if necessary. + +If you ever _move_ the place where **Dome** is installed, you +probably have to inspect the generated files that you have modified to check +if they still behave as expected. + +Notice, however, that distributed versions of +the application (those accessible from the `./dist/` directory) are +self-contained: they are _not_ tied to your local installation of **Dome**. + +The command-line version of the application is accessible to the developer from the `./bin` directory. + +# Common Development Tasks + +Most development tasks shall be accessible from your `./Makefile`, and simply delegate to the +predefined **Dome** targets in `$(DOME)/template/makefile` ; however, for very specific needs, +you can borrow the content of the template makefile into your own one and modify it at your +convenience. The **Dome** environment will not target this template makefile explicitly. + +The top target of the **Dome** template makefile is `make dome-help`, +which is thus activated by default unless you put your own targets _before_ +its inclusion. The `dome-help` target simply echoes a short list of all the +`dome-xxx` predefined targets in the template. It also reports on +actual values of makefile variables used by the template. + +``` +$ make dome-help + +[Dome] Builtin Targets: + make dome-help This help + make dome-dev Run application in development mode + make dome-app Compile application + make dome-dist Package application for production + make dome-doc Generate Dome documentation + make dome-api Generate Application documentation + make dome-pkg Install development packages + make dome-templ Update templates + make dome-reboot Rebuild templates from scratch + make dome-clean Remove dome temporary files + make dome-plugins Package plugins for distribution + +[Dome] Development Variables: + Dome framework DOME = '…' + Arguments (dev) DOME_ARGS = '' + Export modules DOME_EXPORTS = '…' + Plugin modules DOME_PLUGINS = '…' + Local (./bin/) DOME_APP_CLI = '…' + +[Dome] Documentation Variables: + Application APP = '…' + Copyright COPYRIGHT = '…' + Dome framework DOME_DOC = '…' + App. framework DOME_APP_DOC = '…' + App. Sources DOME_APP_SRC = '…' + +``` + +As depicted above, the **Dome** template also provides two extensible targets `help::` and `clean::`. +By default, the `make clean` would only remove the **Dome** stamp files, not the actually generated files, +since they can have been modified when developing the application. This can cause, however, an _update_ of +configuration files that can be managed incrementally, typically for the `package.json` and the installed +JavaScript packages. + +The **Dome** framework can generate its own documentation locally, hence you may consult it offline. It +is also capable of generating internal **JSDoc** documentation of the application itself. The application +documentation does _not_ contain the framework documentation, though. + +The environment variable can be redefined _via_ your own Makefile before the **Dome** template inclusion. diff --git a/Ivette/src/dome/doc/tutorials/glossary.md b/Ivette/src/dome/doc/tutorials/glossary.md new file mode 100644 index 0000000000000000000000000000000000000000..b8f8e0e09a6f007e4a991af9e64d43425a9ce344 --- /dev/null +++ b/Ivette/src/dome/doc/tutorials/glossary.md @@ -0,0 +1,30 @@ +<!-- Glossary --> + +## Basic Concepts + +- **Component** a React Component definition (class of function) +- **Element** a React Component instance of a Component, typically `<Component ...>` +- **Elements** a fragment of any number of elements, typically the `children` properties of elements +- **Render Prop** a function returning element(s), typically used instead of children elements + +## Component Properties + +- `id` an element identifier +- `icon` an icon identifier, as listed in the [gallery](gallery-icons.html) +- `label` a short text used as the displayed title of a component +- `text` textual content to be printed on screen +- `title` a description for a component, usually provided in a tooltip box +- `settings` a key for making local state(s) persistent in user's settings +- `value` the value associated to some basic control (see `onChange`) +- `state` an object holding some current state (see `onUpdate`) +- `default` identifies the element selected by default in a list +- `selected` whether an element is selected or not (never by default) +- `disabled` whether an element will not responds to user actions (never by default) +- `selection` the identifier or value of current selection, or `undefined` (see `onSelect`) +- `children` the children elements of a component instance +- `onClick` a callback function in response to a click event +- `onClose` a callback function in response to closing action +- `onChange` a callback function in response to value changes (see `value`) +- `onUpdate` a callback function in response to (partial) state updates (see `state`) +- `onSelection` a callback function in response to user selection (see `selection`) +- `style` an inlined CSS style object to inject in a DOM element diff --git a/Ivette/src/dome/doc/tutorials/hooks.md b/Ivette/src/dome/doc/tutorials/hooks.md new file mode 100644 index 0000000000000000000000000000000000000000..bf65a102d527bc514ba701c7c8fa6a032af6287d --- /dev/null +++ b/Ivette/src/dome/doc/tutorials/hooks.md @@ -0,0 +1,18 @@ +<!-- Dome React Hooks ---> + +The **Dome** framework provides several [React Hooks](https://reactjs.org/docs/hooks-intro.html) +to ease your developpement process. Here is a summary of them. + +- [`useUpdate(evt)`](dome_.html#.useUpdate) to trigger re-rendering on **Dome** events; +- [`useEvent(emitter,event,callback)`](dome_.html#.useEvent) to trigger callbacks on events; +- [`useForceUpdate()`](dome_.html#.useForceUpdate) to trigger re-rendering on demand; +- [`useState(settings,defaultValue)`](dome_.html#.useState) + similar to `React.useState()` with optional persistent _window_ settings; +- [`useSwitch(settings,defaultValue)`](dome_.html#.useSwitch) + similar to `React.useState()` for boolean values with _window_ settings; +- [`useGlobalSetting(settings,defaultValue)`](dome_.html#.useGlobalSetting) + similar to `React.useState()` with optional persistent _global_ settings; +- [`useClock(period,initStart)`](dome_.html#.useClock) +returns start/stop clocks synchronized on period. +- [`useCommand()`](dome_.html#.useCommand) for working with different application instances. +- See also the [`Dome.State`](dome(renderer).State.html) and the associated hooks. diff --git a/Ivette/src/dome/doc/tutorials/hotreload.md b/Ivette/src/dome/doc/tutorials/hotreload.md new file mode 100644 index 0000000000000000000000000000000000000000..283ae63281cb34888bae4c3af77e18988b142710 --- /dev/null +++ b/Ivette/src/dome/doc/tutorials/hotreload.md @@ -0,0 +1,45 @@ +<!-- Live Code Editing --> + +The **Dome** framework comes with live-editing facilities, provided by a +combination of +[Webpack Hot Module Reloading](https://webpack.js.org/concepts/hot-module-replacement) +and [React Hot Loader](http://gaearon.github.io/react-hot-loader). +This allows you to live edit your code and style sheets in real time while application +is running. This feature is only enabled in development mode, not in production mode +used when packaging the application for some platform. + +Hot reloading for **React** components is known to be a fragile feature and to +suffer from certain limitations. Typically, files that can trigger live updates +must be reachable from the `./src` directory, without traversing symbolic links. +Style sheets in `*.css` files can be live edited, and **React** components in +`*.js` files as well. Most **React** components can be live-edited, provided +they are defined in top-level variables or exported by modules. Generally, the +component states are preserved during live-editing. + +For live-editing to work properly, your source code must follow strict +configuration settings. These rules are enforced when using configuration files +and application entry points generated from **Dome** templates. Pay attention to +the provided comments in generated files when modifying them. + +By default, we suggest to install the **Dome** framework in the sub-directory `./dome` +of your project. Being outside `./src`, this normally prevents **Dome** files to +be live-edited. If you want to also live-edit the framework, you shall move the +`$(DOME)` directory inside your own `./src`. +In particular, you might install the framework with `DOME=src/dome` for instance. + +**State Management:** hot-reloading on **React** components preserves application +states _only_ when they are stored outside the reloaded module. This is the case +for local states maintained in **React** components, as they live in the virtual DOM. +However, for global application state stored in global variables of modules, +they simply vanish when a module is hot-reloaded. Worst, the virtual DOM will +be still bound to the _old_ versions of the modules. However, you usually don't +want to live-edit the global state of your application and mix new data with +old ones. A good practice is to separate files holding global state from files +implementing views. Hence, live-editing the views will not cause the global state +modules to reload, and views will stay in sync with your data. If you ever modify +the global state, you will have to reload the application window (`CmdOrCtrl-R`). + +**Versioning Note:** the framework currently sticks on `webpack` version 3 and +`react-hot-loader` version 3, because of limitations and issues when using +`electron-webpack` with most recent versions of those libraries. However, we +hope to be able to migrate to newer versions as soon as possible. diff --git a/Ivette/src/dome/doc/tutorials/index.json b/Ivette/src/dome/doc/tutorials/index.json new file mode 100644 index 0000000000000000000000000000000000000000..991424831e06777bfab43b1ee83c6447e5795466 --- /dev/null +++ b/Ivette/src/dome/doc/tutorials/index.json @@ -0,0 +1,9 @@ +{ + "quickstart": { "order": 1, "title": "Quick Start" }, + "application": { "order": 2, "title": "Application Design" }, + "development": { "order": 3, "title": "Application Development" }, + "hooks": { "order": 4, "title": "Custom React Hooks" }, + "hotreload": { "order": 5, "title": "Live Editing" }, + "styling": { "order": 7, "title": "Styling Components" }, + "glossary": { "order": 8, "title": "Glossary" } +} diff --git a/Ivette/src/dome/doc/tutorials/quickstart.md b/Ivette/src/dome/doc/tutorials/quickstart.md new file mode 100644 index 0000000000000000000000000000000000000000..44d9925fdd1da5072f1fd7491c69b6c58e7244eb --- /dev/null +++ b/Ivette/src/dome/doc/tutorials/quickstart.md @@ -0,0 +1,26 @@ +<!-- -------------------------------------------------------------------------- --> +<!-- --- Quick Start --- --> +<!-- -------------------------------------------------------------------------- --> + +We strongly recommand to use [**Yarn**](https://reactjs.org) +for installing the necessary Node packages and their dependencies. + +Then, prepare a directory for developing your application, and download +the Dome Application Framework into sub-directory `dome`. +You shall now setup a makefile for your application as follows: + +<pre> + # Makefile + include dome/template/makefile + all: dome-dev +</pre> + +Now, simply type `make` and all the necessary packages will be automatically +installed and configured. This can take a while for the very first installation. +You will be prompted for generating a default `package.json` file +if you do not have some already. + +Eventually, your application will start with +a « _Hello World_ » window. +Now, you can _live edit_ the generated `src/renderer/Application.js` which is the main entry point +of your application and see what happens into the main window. diff --git a/Ivette/src/dome/doc/tutorials/styling.md b/Ivette/src/dome/doc/tutorials/styling.md new file mode 100644 index 0000000000000000000000000000000000000000..9074a9373f0f2204fea054e8cdc182ce77564356 --- /dev/null +++ b/Ivette/src/dome/doc/tutorials/styling.md @@ -0,0 +1,63 @@ +<!-- Styling Components --> + +This tutorial explains how **Dome** style sheets are organized and how +to reuse them for styling your own components. Although modern styling +usually rely on _style preprocessors_ to leverage the complexity of +CSS style sheets development, the approach used here is based on separation +of concerns and multi-class styling. The advantage is that you can +develop your _own_ style sheets, while still being able +to re-use the existing classes provided by the framework. + +All CSS classes provided by **Dome** start with prefix `dome-` ; you shall not +use such a prefix when designing your own classes. Many class names are provided +with optional or mandatory variants. Typically: + +- `dome-<base>[-<a>,<b>,...]` describes class `dome-<base>` and its variants +`dome-<base>-<a>`, `dome-<base>-<b>` _etc_. + +- `dome-<name>-[<a>,<b>,...]` describes classes `dome-<name>-<a>`, `dome-<name>-<b>` _etc_. + +## Platform Context + +These classes can be used when writing selectors in order to style things +with respect to the target platform. The main window container is attributed +with one of the following class: + +- `dome-platform-[darwin,linux,windows]` derived from the `process.darwin` +global variable (**Node.js** environment). + +- `dome-window-[active|inactive]` depending on whether the main application window +has focus or not. + +## Color Palettes + +Attributing colors to graphical elements is often an issue, since a precise +hex variants shall be tuned depending on the surrounding context. However, +base colors are provided in public classes for several usages: + +- `dome-color-frame` background, foreground and borders for +window frames, which includes tool-bars, status-bars, tabs and such. +Those colors actually depend on the focus state of the main application window. + +- `dome-color-[dragzone|dragging]` for painting the background of a dragging +zone, typically a splitting rule. The `dragzone` variant is completely +transparent with a very transparent light gray when hovered. +The `dragging` variant is semi-transparent blended blue with light gray. +All these drag background effects are smoothly transitioned. + +## Text Properties + +- `dome-text-[label|title|descr]` for labels (_eg._ buttons, tabs, menu +entries), titles (larger labels) and descriptions (_eg._ tooltips). +Uses a sans-serif font, is non-selectable and truncated with an ellipsis. + +- `dome-text-[data|code]` for selectable text, typically input fields. +Uses a sans-serif font (for `data`) or monospace font (for `code`), +never wraps and is clipped when overflow. + +## Component Layout + +The entire application uses the `box-model` box-sizing property by default, +since it is usually much more consistent with nested `<div>` components. +Similarly, default margins and paddings are set to `0px` to avoid unwanted +messy background issues. diff --git a/Ivette/src/dome/src/main/dome.js b/Ivette/src/dome/src/main/dome.js new file mode 100644 index 0000000000000000000000000000000000000000..872f371a2c676fb553e721bb9fd7f461ae3afffd --- /dev/null +++ b/Ivette/src/dome/src/main/dome.js @@ -0,0 +1,506 @@ +/** + @module dome(main) + @description + + ## Dome Application (Main Process) + + This module manages the electron main-process of the application. + Your application will launch on `Dome.start()`: + + @example + // src/main/index.js: + import Dome from 'dome' ; + Dome.start(); +*/ + +import { + app, + ipcMain, + BrowserWindow +} from 'electron' ; + +import _ from 'lodash' ; +import fs from 'fs' ; +import path from 'path' ; +import Menubar from './menubar.js' ; +import System from 'dome/system' ; +import installExtension , { REACT_DEVELOPER_TOOLS } from 'dome/devtools' ; + +// -------------------------------------------------------------------------- +// --- System Helpers +// -------------------------------------------------------------------------- + +function fstat(path) { + try { + return fs.statSync(path); + } catch(_error) { + return undefined; + } +} + +// -------------------------------------------------------------------------- +// --- Helpers +// -------------------------------------------------------------------------- + +const LOCAL = process.env.DOME_LOCAL ; + +/** Development mode flag */ +export const DEVEL = System.DEVEL ; + +/** System platform */ +export const platform = System.platform ; + +// -------------------------------------------------------------------------- +// --- Settings +// -------------------------------------------------------------------------- + +const APP_DIR = app.getPath('userData'); +const APP_SETTINGS = path.join( APP_DIR , 'Settings.json' ); + +var s_frames = {} ; +var s_globals = {} ; +var s_application = {} ; +var s_preferences = {} ; + +function loadSettings() { + try { + if (!fstat( APP_SETTINGS )) return; + const content = fs.readFileSync( APP_SETTINGS, { encoding: 'utf8' } ); + const loaded = JSON.parse( content ); + const MERGE = (store,field) => _.merge( store , _.get( loaded , field )); + s_frames = MERGE( s_frames , 'frames' ); + s_globals = MERGE( s_globals, 'globals' ); + s_application = MERGE( s_application, 'application' ); + s_preferences = MERGE( s_application, 'preferences' ); + } catch(err) { + console.error("[Dome] Can not load application settings\n" + err); + } +} + +function saveSettings() { + try { + if (!fstat( APP_DIR )) fs.mkdirSync( APP_DIR ); + const saved = { + globals: s_globals, + application: s_application, + preferences: s_preferences, + frames: s_frames + }; + const content = JSON.stringify( saved, undefined, DEVEL ? 2 : 0 ); + fs.writeFileSync( APP_SETTINGS, content, { encoding: 'utf8' }, errorSettings ); + } catch(err) { + errorSettings(err); + } +} + +const fireSaveSettings = _.debounce( saveSettings , 50 ); + +function errorSettings(err) { + if (err) console.error("[Dome] Can not save application settings\n" + err); +} + +function remoteSyncSettings(event) +{ + const isSetting = windowSettings && windowSettings.id === event.frameId ; + event.returnValue = { + globals: s_globals, + settings: isSetting ? s_preferences : s_application + }; +} + +function remoteSaveWindowSettings(event,patches) +{ + const isSetting = windowSettings && windowSettings.id === event.frameId ; + _.merge( isSetting ? s_preferences : s_application , patches ); + saveSettings(); +} + +function remoteSaveGlobalSettings(event,patches) +{ + _.merge( s_globals , patches ); + saveSettings(); + BrowserWindow.getAllWindows().forEach((win) => { + if (win.id !== event.frameId) + win.send('dome.ipc.settings.update',patches); + }); +} + +ipcMain.on('dome.ipc.settings.sync', remoteSyncSettings ); +ipcMain.on('dome.ipc.settings.window', remoteSaveWindowSettings ); +ipcMain.on('dome.ipc.settings.global', remoteSaveGlobalSettings ); + +// -------------------------------------------------------------------------- +// --- Active Windows +// -------------------------------------------------------------------------- + +var appName = 'Dome' ; +const MODIFIED = '(*) ' ; + +/** + Sets application window name + @param {string} title - application name + */ +export function setName(title) { + appName = title; +} + +function setTitle(event,title) { + let w = BrowserWindow.fromId( event.frameId ); + w.setTitle( title || appName ); +} + +function setModified(event,modified) { + let w = BrowserWindow.frameId( event.frameId ); + if (platform == 'macos') + w.setDocumentEdited( modified ); + else { + let title = w.getTitle(); + if (title.startsWith(MODIFIED)) + title = title.substring(MODIFIED.length); + if (modified) + title = MODIFIED + title ; + w.setTitle(title); + } +} + +ipcMain.on('dome.ipc.window.title',setTitle); +ipcMain.on('dome.ipc.window.modified',setModified); + +// -------------------------------------------------------------------------- +// --- Main Window Web Navigation +// -------------------------------------------------------------------------- + +import { shell } from 'electron' ; +import { URL } from 'url' ; + +function getURL() +{ + if (DEVEL) + return `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}` ; + if (LOCAL) + return 'file://' + path.join(__dirname,'../renderer/index.html') ; + return 'file://' + __dirname + '/index.html' ; +} + +function navigateURL( event , url ) { + event.preventDefault(); + const href = new URL( url ); + const main = new URL( getURL() ); + if (href.origin == main.origin) + { + const query = href.pathname.substring(1) + href.query + href.hash ; + event.sender.send('dome.ipc.href', query); + } else { + shell.openExternal( url ); + } +} + +// -------------------------------------------------------------------------- +// --- Browser Window SetUp +// -------------------------------------------------------------------------- + +const windowsHandle = {} ; // Prevent live windows to be garbage collected + +function createBrowserWindow( config, isMain=true ) +{ + + const argv = isMain + ? System.WINDOW_APPLICATION_ARGV + : System.WINDOW_PREFERENCES_ARGV ; + + const options = _.merge( + { + show: false, + backgroundColor: '#f0f0f0', + webPreferences: { + nodeIntegration:true, + additionalArguments: [ argv ] + } + } + , config ); + + const frameId = isMain ? 'application' : 'preferences' ; + const frame = _.get( s_frames, frameId ); + const getInt = (v) => v && _.toSafeInteger(v); + if (frame) { + options.x = getInt(frame.x); + options.y = getInt(frame.y); + options.width = getInt(frame.width); + options.height = getInt(frame.height); + } + + const theWindow = new BrowserWindow( options ); + + // Load the index.html of the app. + if (DEVEL || LOCAL) + process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'; + + theWindow.loadURL(getURL()); + + // Load Finished + theWindow.once('ready-to-show' , () => { + if (DEVEL || LOCAL) + process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'false'; + if (DEVEL) + theWindow.openDevTools(); + theWindow.show(); + }); + + // Focus Management + theWindow.on('focus', () => theWindow.send('dome.ipc.focus',true)); + theWindow.on('blur', () => theWindow.send('dome.ipc.focus',false)); + + // URL Navigation + theWindow.webContents.on('will-navigate', navigateURL ); + theWindow.webContents.on('did-navigate-in-page', navigateURL ); + theWindow.webContents.on('did-finish-load', () => broadcast('dome.ipc.reload')); + + // Emitted when the window want's to close. + theWindow.on('close', (evt) => { + theWindow.send('dome.ipc.closing'); + const frame = theWindow.getBounds(); + _.set( s_frames, frameId , frame ); + }); + + // Keep track of frame positions (in DEVEL) + if (DEVEL) { + const reframe = _.debounce( (evt) => { + const frame = theWindow.getBounds(); + _.set( s_frames, frameId , frame ); + saveSettings(); + } , 300); + theWindow.on('resize',reframe); + theWindow.on('moved',reframe); + } + + // Keep the window reference to prevent destruction + const wid = theWindow.id ; + windowsHandle[ wid ] = theWindow ; + + // Emitted when the window is closed. + theWindow.on('closed', () => { + // Dereference the window object to actually destroy it + delete windowsHandle[ wid ] ; + }); + + return theWindow ; +} + +// -------------------------------------------------------------------------- +// --- Application Window(s) +// -------------------------------------------------------------------------- + +function filterArgv( argv ) { + return argv.slice( DEVEL ? 3 : (LOCAL ? 2 : 1) ).filter((p) => p); +} + +function sendCommand( win, argv, wdir ) { + win.webContents.on('did-finish-load', () => { + win.webContents.send('dome.ipc.command',argv,wdir); + }); +} + +function createPrimaryWindow() +{ + // Initialize Menubar + Menubar.install(); + + // Initialize Settings + loadSettings(); + + // React Developper Tools + if (DEVEL) + installExtension(REACT_DEVELOPER_TOOLS,true); + + const primary = createBrowserWindow({ title: appName } , true); + const wdir = process.cwd() === '/' ? app.getPath('home') : process.cwd() ; + sendCommand( primary , filterArgv(process.argv) , wdir ); +} + +var appCount = 1; + +function createSecondaryWindow(_event,argv,wdir) +{ + const secondary = createBrowserWindow({ title: `${appName} #${++appCount}` }, true); + sendCommand( secondary, filterArgv(argv), wdir ); +} + +function createDesktopWindow() +{ + const instance = appCount++ ; + const secondary = createBrowserWindow({ title: `${appName} #${++appCount}` }, true); + sendCommand( secondary , [] , app.getPath('home') ); +} + +// -------------------------------------------------------------------------- +// --- Activate Windows (macOS) +// -------------------------------------------------------------------------- + +function activateWindows() { + var isFocused = false ; + var toFocus = undefined ; + BrowserWindow.getAllWindows().forEach((w) => { + w.show(); + if (w.isFocused()) isFocused = true ; + else if (!toFocus) toFocus = w; + }); + if (!isFocused) { + if (toFocus) toFocus.focus(); + else { + // No focusable nor focused window + createDesktopWindow(); + } + } +} + +// -------------------------------------------------------------------------- +// --- Settings Window +// -------------------------------------------------------------------------- + +var windowSettings = undefined ; // Preference Window + +function showSettingsWindow() +{ + if (!windowSettings) + windowSettings = createBrowserWindow({ + title: appName + ' Settings', + width: 256, + height: 248, + fullscreen: false, + maximizable: false, + minimizable: false + }, false); + windowSettings.show(); + windowSettings.on('closed',() => windowSettings = undefined); +} + +function restoreDefaultSettings() +{ + s_globals = {} ; + s_preferences = {} ; + s_application = {} ; + s_frames = {} ; + fireSaveSettings(); + fireSaveSettings.flush(); + broadcast( 'dome.ipc.settings.defaults' ); +} + +// -------------------------------------------------------------------------- +// --- Main Application Starter +// -------------------------------------------------------------------------- + +/** Starts the main process. */ +export function start() { + + // Ensures second instance triggers the main one + if (!app.requestSingleInstanceLock()) app.quit(); + + // Change default locale + app.commandLine.appendSwitch('lang','en'); + + // Listen to window events + app.on( 'ready', createPrimaryWindow ); // Wait for Electron init + app.on( 'activate', activateWindows ); // Mac OSX response to dock + app.on( 'second-instance', createSecondaryWindow ); + app.on( 'dome.menu.settings', showSettingsWindow ); + app.on( 'dome.menu.defaults', restoreDefaultSettings ); + + // Performing on-exit callbacks + app.on( 'will-quit' , () => { + System.doExit() ; + fireSaveSettings(); + fireSaveSettings.flush(); + }); + + // On OS X menu bar stay active until the user quits explicitly from menu. + // On other systems, quit when all windows are closed. + // Warning: when no event handler is registered, the app automatically + // quit when all windows are closed. + app.on( 'window-all-closed', () => { + if (System.platform !== 'macos') app.quit(); + }); + +} + +// -------------------------------------------------------------------------- +// --- Renderer-Process Communication +// -------------------------------------------------------------------------- + +function broadcast( event, ...args ) +{ + BrowserWindow.getAllWindows().forEach((w) => { + w.send( event, ...args ); + }); +} + +// -------------------------------------------------------------------------- +// --- MenuBar Management +// -------------------------------------------------------------------------- + +const MENU_CLICK = (id,callback) => (_item,win,_event) => { + callback && callback(); + app.emit('dome.menu.clicked', id ); + win.send('dome.ipc.menu.clicked', id ); +}; + +/** + @summary Define a custom main window menu. + @description + Cf. [addMenu](dome_.html#.addMenu) in the renderer process. +*/ +export function addMenu( label ) { Menubar.addMenu( label ); } + +/** + @summary Define a custom menu item. + @description + Cf. [addMenuItem](dome_.html#.addMenuItem) in the renderer process. +*/ +export function addMenuItem( spec ) +{ + if ( spec.type === 'separator' ) { + Menubar.addMenuItem( spec ); + } else { + const id = spec.id ; + if (!id) { + console.error('[Dome] Missing menu-item identifier:',spec); + return; + } + const { callback , ...options } = spec ; + options.click = MENU_CLICK( id, callback ); + Menubar.addMenuItem( options ); + } +} + +/** + @summary Update a menu item. + @description + Cf. [setMenuItem](dome_.html#.setMenuItem) in the renderer process. +*/ +export function setMenuItem( options ) { + const { callback , ...updates } = options ; + if (callback !== undefined) { + const id = updates.id ; + updates.click = MENU_CLICK( id, callback ); + } + Menubar.setMenuItem( updates ); +} + +ipcMain.on( 'dome.ipc.menu.addmenu' , addMenu ); +ipcMain.on( 'dome.ipc.menu.addmenuitem' , addMenuItem ); +ipcMain.on( 'dome.ipc.menu.setmenuitem' , setMenuItem ); + +// -------------------------------------------------------------------------- +// --- Export Default +// -------------------------------------------------------------------------- + +export default { + platform, + DEVEL, + setName, + start, + addMenu, + addMenuItem, + setMenuItem +} ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/main/menubar.js b/Ivette/src/dome/src/main/menubar.js new file mode 100644 index 0000000000000000000000000000000000000000..9660a2b968e984346db1e5ee555af1d1a8e3a0ee --- /dev/null +++ b/Ivette/src/dome/src/main/menubar.js @@ -0,0 +1,415 @@ +// -------------------------------------------------------------------------- +// --- Menus & MenuBar Management +// -------------------------------------------------------------------------- + +import { app, BrowserWindow, Menu, MenuItem, shell } from 'electron' ; +import System from 'dome/system' ; + +// -------------------------------------------------------------------------- +// --- Special Callbacks +// -------------------------------------------------------------------------- + +function reloadWindow(item, focusedWindow) +{ + if (focusedWindow) { + // on reload, start fresh and close any old + // open secondary windows + if (focusedWindow.id === 1) + BrowserWindow.getAllWindows().forEach(function (win) { + if (win.id > 1) win.close(); + }); + reset(); // declared below + focusedWindow.reload(); + } +} + +function toggleFullScreen(item, focusedWindow) +{ + if (focusedWindow) + focusedWindow.setFullScreen(!focusedWindow.isFullScreen()); +} + +function toggleDevTools(item, focusedWindow) +{ + if (focusedWindow) + focusedWindow.toggleDevTools(); +} + +// -------------------------------------------------------------------------- +// --- Menu Utilities +// -------------------------------------------------------------------------- + +const separator = { type: 'separator' } ; + +function concatSep( ...menus ) { + var submenu = [] ; + var needsep = false ; + menus.forEach((items) => { + const n = items.length ; + if (n > 0) { + if (needsep) + submenu.push( separator ); + submenu = submenu.concat(items); + needsep = (items[n-1].type !== 'separator') ; + } + }); + return submenu ; +} + +// -------------------------------------------------------------------------- +// --- MacOS Menu Items +// -------------------------------------------------------------------------- + +const macosAppMenuItems = (name) => [ + { + label: `About ${name}`, + role: 'about' + }, + separator, + { + label: `Preferences…`, + accelerator: 'Command+,', + click: () => app.emit('dome.menu.settings') + }, + { + label: `Restore Defaults`, + click: () => app.emit('dome.menu.defaults') + }, + separator, + { + label: `Services`, + submenu: [], + role: 'services' + }, + separator, + { + label: `Hide ${name}`, + accelerator: 'Command+H', + role: 'hide' + }, { + label: 'Hide Others', + accelerator: 'Command+Alt+H', + role: 'hideothers' + }, { + label: 'Show All', + role: 'unhide' + }, + separator, + { + label: 'Quit', + accelerator: 'Command+Q', + role: 'quit' + } +]; + +// -------------------------------------------------------------------------- +// --- File Menu Items (platform dependant) +// -------------------------------------------------------------------------- + +var fileMenuItems_custom = []; + +const fileMenuItems_linux = [ + { + label: `Preferences…`, + click: () => app.emit('dome.menu.settings') + }, + { + label: `Restore Defaults`, + click: () => app.emit('dome.menu.defaults') + }, + separator, + { + label: 'Exit', + accelerator: 'Ctrl+Q', + role: 'quit' + } +]; + +// -------------------------------------------------------------------------- +// --- Edit Menu Items +// -------------------------------------------------------------------------- + +const editMenuItems = [ + { label: 'Undo', + accelerator: 'CmdOrCtrl+Z', + role: 'undo' + }, { + label: 'Redo', + accelerator: 'Shift+CmdOrCtrl+Z', + role: 'redo' + }, + separator, + { + label: 'Cut', + accelerator: 'CmdOrCtrl+X', + role: 'cut' + }, { + label: 'Copy', + accelerator: 'CmdOrCtrl+C', + role: 'copy' + }, { + label: 'Paste', + accelerator: 'CmdOrCtrl+V', + role: 'paste' + }, { + label: 'Select All', + accelerator: 'CmdOrCtrl+A', + role: 'selectall' + } +]; + +var editMenuItems_custom = [] ; + +// -------------------------------------------------------------------------- +// --- View Menu Items +// -------------------------------------------------------------------------- + +var viewMenuItems_custom = [] ; + +const viewMenuItems = (osx) => [ + { + label: 'Reload', + accelerator: 'CmdOrCtrl+R', + click: reloadWindow + }, { + label: 'Toggle Full Screen', + accelerator: (osx ? 'Ctrl+Command+F' : 'F11'), + click: toggleFullScreen + }, { + label: 'Toggle Developer Tools', + accelerator: (osx ? 'Alt+Command+I' : 'Ctrl+Shift+I'), + click: toggleDevTools + } +]; + +// -------------------------------------------------------------------------- +// --- Window Menu Items +// -------------------------------------------------------------------------- + +const windowMenuItems_linux = [ + { + label: 'Minimize', + accelerator: 'CmdOrCtrl+M', + role: 'minimize' + }, { + label: 'Close', + accelerator: 'CmdOrCtrl+W', + role: 'close' + }, + separator, + { + label: 'Reopen Window', + accelerator: 'CmdOrCtrl+Shift+T', + enabled: false, /*?*/ + key: 'reopenMenuItem', /*?*/ + click: () => { app.emit('activate'); } + } +]; + +const windowMenuItems_macos = windowMenuItems_linux.concat([ + { + label: 'Bring All to Front', + role: 'front' + } +]); + +// -------------------------------------------------------------------------- +// --- Help Menu Items +// -------------------------------------------------------------------------- + +const helpMenuItems = [ + { + label: 'Learn More', + click: function () { + shell.openExternal('http://electron.atom.io'); + } + } +]; + +// -------------------------------------------------------------------------- +// --- Update MenuBar (async) +// -------------------------------------------------------------------------- + +var updateRequired = false ; +var updateTriggered = false ; + +function requestUpdate() { + if (updateRequired && !updateTriggered) { + updateTriggered = true ; + setImmediate( install ); + } +} + +// -------------------------------------------------------------------------- +// --- CustomMenus +// -------------------------------------------------------------------------- + +var customMenus = [] ; +var customItems = {} ; + +function findMenu( label ) { + switch( label ) { + case 'File': return fileMenuItems_custom; + case 'Edit': return editMenuItems_custom; + case 'View': return viewMenuItems_custom; + default: + var theMenu = customMenus.find((m) => m.label === label); + return theMenu && theMenu.submenu ; + } +} + +export function addMenu( label ) +{ + if (findMenu(label)) { + console.warn(`Already defined menu '${menu}'`); + } else { + customMenus.push( { label , submenu:[] } ); + } + requestUpdate(); +} + +function updateItem( entry, options ) +{ +} + +export function addMenuItem( { menu , key, ...spec } ) +{ + var submenu = findMenu( menu ); + if (!submenu) { + console.error(`[Dome] Unknown menu '${menu}' (menu item #${spec.id || spec.label} undefined)`); + return; + } + if (!spec || spec.type === 'separator') { + submenu.push( separator ); + } else { + const id = spec.id ; + if (!id) { + console.error('[Dome] Invalid menu item:',spec); + return; + } + if (key) { + switch(System.platform) { + case 'macos': + if (key.startsWith('Cmd+')) spec.accelerator = "Cmd+" + key.substring(4) ; + if (key.startsWith('Alt+')) spec.accelerator = "Cmd+Alt+" + key.substring(4) ; + if (key.startsWith('Meta+')) spec.acceperator = "Cmd+Shift+" + key.substring(5) ; + break; + case 'windows': + case 'linux': + default: + if (key.startsWith('Cmd+')) spec.accelerator = "Ctrl+" + key.substring(4) ; + if (key.startsWith('Alt+')) spec.accelerator = "Alt+" + key.substring(4) ; + if (key.startsWith('Meta+')) spec.acceperator = "Ctrl+Alt+" + key.substring(5) ; + break; + } + } + const entry = customItems[id] ; + if (entry) { + if (!System.DEVEL) { + console.error('[Dome] Duplicate menu item:',spec); + return; + } else { + if (entry.spec) Object.assign( entry.spec , spec ); + if (entry.item) Object.assign( entry.item , spec ); + } + } else { + customItems[id] = { spec } ; + submenu.push( spec ); + } + } + requestUpdate(); +} + +export function setMenuItem({ id, ...options }) +{ + const entry = customItems[id] ; + if (entry) { + if (entry.spec) Object.assign( entry.spec , options ); + if (entry.item) Object.assign( entry.item , options ); + if ( options.label || options.type || options.click ) requestUpdate(); + } else + console.warn(`[Dome] unknown menu item #${id}`); +} + +// -------------------------------------------------------------------------- +// --- Menu Bar Template +// -------------------------------------------------------------------------- + +function template() { + switch(System.platform) { + case 'macos': + return [].concat( + [ + { label: app.name, submenu: macosAppMenuItems(app.name) }, + { label: 'File', submenu: fileMenuItems_custom }, + { label: 'Edit', submenu: concatSep(editMenuItems,editMenuItems_custom) }, + { label: 'View', submenu: concatSep(viewMenuItems_custom,viewMenuItems(true)) } + ], + customMenus, + [ + { label: 'Window', role: 'window', submenu: windowMenuItems_macos }, + { label: 'Help', role: 'help', submenu: helpMenuItems } + ] + ); + case 'windows': + case 'linux': + default: + return [].concat( + [ + { label: 'File', submenu: concatSep(fileMenuItems_custom,fileMenuItems_linux) }, + { label: 'Edit', submenu: concatSep(editMenuItems,editMenuItems_custom) }, + { label: 'View', submenu: concatSep(viewMenuItems_custom,viewMenuItems(false)) } + ], + customMenus, + [ + { label: 'Window', submenu: windowMenuItems_linux }, + { label: 'Help', submenu: helpMenuItems } + ] + ); + } +} + +// -------------------------------------------------------------------------- +// --- MenuBar SetUp +// -------------------------------------------------------------------------- + +var menubar ; + +function registerCustomItems( menu ) { + menu.items.forEach((item) => { + const entry = customItems[item.id]; + if (entry) entry.item = item ; + item.submenu && registerCustomItems( item.submenu ); + }); +} + +export function install() { + updateRequired = true; + updateTriggered = false; + menubar = Menu.buildFromTemplate(template()); + registerCustomItems( menubar ); + Menu.setApplicationMenu( menubar ); +} + +// Called by reload above +function reset() { + fileMenuItems_custom = [] ; + editMenuItems_custom = [] ; + viewMenuItems_custom = [] ; + customMenus = [] ; + customItems = {} ; + install(); +} + +// -------------------------------------------------------------------------- +// --- Export Default +// -------------------------------------------------------------------------- + +export default { + install, + addMenu, + addMenuItem, + setMenuItem +}; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/misc/devtools.js b/Ivette/src/dome/src/misc/devtools.js new file mode 100644 index 0000000000000000000000000000000000000000..222b66d9d3d159ba7703dbf7d822519abc0b5ab8 --- /dev/null +++ b/Ivette/src/dome/src/misc/devtools.js @@ -0,0 +1,12 @@ +// -------------------------------------------------------------------------- +// --- Dummy clone of electron-dev-installer +// -------------------------------------------------------------------------- + +// No need to export dummy identifiers (undefined is ok) + +export const REACT_DEVELOPER_TOOLS = undefined ; + +// Shall not be used in non-development mode +export default function installExtension(_id) { + return Promise.reject(); +} diff --git a/Ivette/src/dome/src/misc/events.js b/Ivette/src/dome/src/misc/events.js new file mode 100644 index 0000000000000000000000000000000000000000..16c0b380da32541801b4d3873c351045ef3128ad --- /dev/null +++ b/Ivette/src/dome/src/misc/events.js @@ -0,0 +1,81 @@ +// -------------------------------------------------------------------------- +// --- A Ghost Component aware of its enclosing positionned container +// -------------------------------------------------------------------------- + +import React from 'react' ; +import Props from 'prop-types' ; + +const SIZED = { + display: 'block', + position: 'absolute', + top: 0, + left: 0, + height: '100%', + width: '100%', + overflow: 'hidden', + pointerEvents: 'none', + zIndex: -1 +}; + +// -------------------------------------------------------------------------- +// --- Components +// -------------------------------------------------------------------------- + +/* + This component is a ghost element to be inserted inside a _positionned_ + container. It makes the container aware of its bounding client rectangle + _via_ the `onResize` property. + + The `onResize` callback is invoked whenever the parent container is + positionned or resized. The callback is passed the + `container.getBoundingClientRect()` rectangle. +*/ +export class Layout extends React.Component { + + // Init the element + componentDidMount() { + this.element.data = 'about:blank'; + this.handleResize = this.handleResize.bind(this); + } + + // Callback on Resize + handleResize() { + if (this.props.onResize) { + const r = this.element.getBoundingClientRect(); + this.props.onResize(r); + } + } + + componentWillUnmount() { + if (this.state.view) + this.state.view.removeEventListener('resize', this.handleResize); + } + + render() { + return React.createElement('object', { + type: 'text/html', style: SIZED, + ref: elt => { this.element = elt; }, + onLoad: evt => { + this.setState( + { view: evt.target.contentDocument.defaultView }, + () => { + this.state.view.addEventListener('resize', this.handleResize); + this.handleResize(); + } + ); + } + }); + } + +} + +// -------------------------------------------------------------------------- +// --- Props & Defaults +// -------------------------------------------------------------------------- + +Layout.propTypes = { onResize: Props.func }; +Layout.defaultProps = { }; + +export default { Layout }; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/misc/plugins.js b/Ivette/src/dome/src/misc/plugins.js new file mode 100644 index 0000000000000000000000000000000000000000..5d468d4017a308f65f0dfad93f3ef2dcc6c17aea --- /dev/null +++ b/Ivette/src/dome/src/misc/plugins.js @@ -0,0 +1,97 @@ +// -------------------------------------------------------------------------- +// --- Dome Plugins Management +// -------------------------------------------------------------------------- + +import fs from 'fs' ; +import path from 'path' ; + +const registry = {} ; + +// -------------------------------------------------------------------------- +// --- Installing Bundle +// -------------------------------------------------------------------------- + +export function register( id, exports ) +{ + registry[id] = Object.assign( {} , exports ); +} + +const WRAPPER_OPEN = '(function(module,require,__static){\n' ; +const WRAPPER_CLOSE = '\n})' ; +const PLUGINS = '@plugins/' ; + +export function install( name ) +{ + // Resolve plugin directory + let dir = path.resolve( __static , "plugins" , name ); + if (!fs.isDirectory()) + throw `Plugin '${name}' not installed` ; + + // Resolve plugin configuration + let pkg = path.resolve( dir , 'package.json' ); + if (!fs.isFile(pkg)) + throw `Plugin '${name}' has no 'package.json' file` ; + let config ; + try { config = JSON.pargse(fs.readFileSync( pkg , 'UTF-8' )); } + catch(err) { + console.error( `[Dome] reading '${pkg}':\n`, err ); + throw `Plugin '${name}' has invalid 'package.json' file` ; + } + + // Resolve plugin entry points + let bundlejs = path.resolve( dir, config.main || 'bundle.js' ); + if (!fs.isFile(bundlejs)) + throw `Plugin '${name}' entry point not found` ; + let static_d = path.resolve( dir, 'static' ); + if (!fs.isDirectory(static_d)) static_d = undefined; + + // Load bundle file + let bundle ; + try { bundle = fs.readFileSync( bundlejs , 'UTF-8' ); } + catch(err) { + console.error( `[Dome] loading '${bundlejs}':\n`, err ); + throw `Plugin '${name}' can not load its entry point` ; + } + + // Install bundle file + let id = PLUGINS + name ; + let exports = {} ; + register( id, exports ); // cut circularities + try { + let wrapped = WRAPPER_OPEN + bundle + WRAPPER_CLOSE ; + let compiled ; eval(wrapped); + let module = { id, exports }; + compiled( module, require, static_d ); + } catch(err) { + console.error( `[Dome] running '${bundlejs}':\n`, err ); + throw `Plugin '${name}' can not install bundle` ; + } + register( id, exports ); // final exports + + // Finally return exports + return exports ; +} + +// -------------------------------------------------------------------------- +// --- Resolving Modules +// -------------------------------------------------------------------------- + +export function require(id) +{ + let exports = registry[id]; + if (exports) return Object.assign( {} , exports ); + + // Resolving plugin + + if (id.startsWith(PLUGINS)) + { + let exports = install( id.substring(PLUGINS.length) ); + return Object.assign( {} , exports ); + } + + // Trap + + throw `Module '${id}' not found` ; +} + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/misc/register.js b/Ivette/src/dome/src/misc/register.js new file mode 100644 index 0000000000000000000000000000000000000000..17d3be008b3d659a052fb754d9578d4599cdc2ff --- /dev/null +++ b/Ivette/src/dome/src/misc/register.js @@ -0,0 +1,100 @@ +// -------------------------------------------------------------------------- +// --- Dome Classes +// -------------------------------------------------------------------------- + +import React from 'react' ; +import _ from 'lodash' ; + +// -------------------------------------------------------------------------- +// --- Register a Dome Class +// -------------------------------------------------------------------------- + +export function register(Component,NAME) { + Component._DOME = NAME ; + Component.istanceOf = (elt) => (elt.type ? elt.type._DOME === NAME : false) ; +} + +// -------------------------------------------------------------------------- +// --- Get the Dome Class of a Component +// -------------------------------------------------------------------------- + +export function classOf(elt) { + return elt && elt.type && elt.type._DOME ; +} + +// -------------------------------------------------------------------------- +// --- Dispatch Children components among different Dome Classes +// -------------------------------------------------------------------------- + +/* + Split a React Children structure according to filter. + For each field { key: spec } in the filter, returns + a field { key: selection } with all children satisfying + the given spec (undefined if none). + Filter specification can be: a Dome class name, + an array of Dome class names, or 'undefined' for all non-matched + children in the filter. + + Relies on React.Children.map instead ot React.Children.toArray + in order to avoid putting keys in original children when not necessary. +*/ +export function dispatch(children,filter) +{ + + var others = undefined; + + const acceptor = _.mapValues( filter , (spec,field) => { + switch(typeof(spec)) { + case 'string': + return (elt) => classOf(elt) === spec ; + case 'undefined': + others = field ; + return undefined ; + default: + console.error('[Dome.common.register] non-supported filter spec',spec); + return undefined ; + } + } ); + + var count = 0 , first = true , accepted = [] ; + const collected = _.mapValues( acceptor , (accept,_field) => { + if (accept) { + var empty = true ; + var filtered = + React.Children.map( children , (elt) => { + var ok = elt && accept(elt); + if (ok) empty = false ; + if (others) { + if (first) accepted.push(ok); + else { + if (ok) accepted[count] = ok ; + count++; + } + } + return ok && elt; + }); + first = false ; count = 0 ; + return empty ? undefined : filtered ; + } else + return undefined ; + }); + + if (others) { + var empty = true ; + var remaining = React.Children.map( children , (elt) => { + var ok = elt && !accepted[count] ; + if (ok) empty = false ; + count++; + return ok ? elt : null ; + }); + if (!empty) collected[others] = remaining ; + } + + return collected; +} + +// -------------------------------------------------------------------------- + +export default { register , classOf , dispatch }; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/misc/system.js b/Ivette/src/dome/src/misc/system.js new file mode 100644 index 0000000000000000000000000000000000000000..ae4bed45862083d22a5039110147587344864779 --- /dev/null +++ b/Ivette/src/dome/src/misc/system.js @@ -0,0 +1,653 @@ +/** @module dome/system */ + +// -------------------------------------------------------------------------- +// --- Evolved Spawn Process +// -------------------------------------------------------------------------- + +import _ from 'lodash' ; +import Emitter from 'events' ; +import Exec from 'child_process' ; +import fspath from 'path' ; +import fs from 'fs' ; +import { app, remote } from 'electron' ; + +// -------------------------------------------------------------------------- +// --- Platform Specificities +// -------------------------------------------------------------------------- + +var thePlatform = 'linux' ; +{ + switch( process.platform ) { + case 'darwin': + thePlatform = 'macos'; break; + case 'win32': + case 'win64': + thePlatform = 'windows'; break; + case 'aix': + case 'freebsd': + case 'linux': + case 'openbsd': + case 'sunos': + thePlatform = 'linux'; break; + default: + console.warn(`Unkwnon OS platform '${process.platform}' (fallback to 'linux')`); + thePlatform = 'linux'; break; + } +} + +/** + @summary System platform. + @description + Similar to `process.platform`, but fall into fewer categories: + - `'macos'` for Mac OSX, + - `'windows'` for Windows (32 or 64) + - `'linux'` for most unix-like platforms + +Non-recognized platforms will fallback to `'linux'` with the emission of a warning. +*/ +export const platform = thePlatform ; + +// -------------------------------------------------------------------------- +// --- Logging +// -------------------------------------------------------------------------- + +/** Development mode flag */ +export const DEVEL = process.env.NODE_ENV !== 'production' ; + +// -------------------------------------------------------------------------- +// --- At Exit +// -------------------------------------------------------------------------- + +const exitJobs = []; + +function exitJob(job,...args) { + try { job(...args); } + catch(err) { console.err('[Dome] atExit:',err); } +} + +/** + @summary Execute a routine at exit. + @param {function} callback - the function to be called when application is closing + @param {...any} [args] - the argument to be provided to the callback + @description + Exceptions thrown by the function are captured and reported on the console. + */ +export function atExit(callback,...args) { + exitJobs.push(() => exitJob(callback,...args)); +} + +/** + @summary Execute a callback at exit on each elements of a collection. + @param {array|object} elements - the collection to iterate over + @param {function} callback - the function to be called on each element + @description + The function will be invoked with `callback(value,key,elements)` via + the [Lodash `_.forOwn()`](https://lodash.com/docs/4.17.10#forOwn) iterator. + + Exceptions thrown by the function are individually captured and reported + on the console for each element in the object or array. + */ +export function atExitForEach(elements,callback) { + atExit(() => + _.forOwn(elements,(value,key,data) => exitJob(callback,value,key,data)) + ); +} + +/** Execute all pending exit jobs (and flush the list). */ +export function doExit() { + exitJobs.forEach((f) => f()); + exitJobs.length = 0; +} + +// -------------------------------------------------------------------------- +// --- Command Line Arguments +// -------------------------------------------------------------------------- + +var command_wdir = undefined ; +var command_argv = undefined ; + +function setCommand(argv,wdir) { + command_argv = argv ; + command_wdir = wdir ; +} + +// -------------------------------------------------------------------------- +// --- User's Directories +// -------------------------------------------------------------------------- + +const appProxy = app || remote.app ; + +/** Returns user's home directory. */ +export function getHome() { return appProxy.getPath('home'); } + +/** Returns user's desktop directory. */ +export function getDesktop() { return appProxy.getPath('desktop'); } + +/** Returns user's documents directory. */ +export function getDocuments() { return appProxy.getPath('documents'); } + +/** Returns user's downloads directory. */ +export function getDownloads() { return appProxy.getPath('downloads'); } + +/** + @summary Working directory (Application Window). + @return {string} absolute path + @description + This the current working directory from where the application window + was opened. + + The function returns `undefined` until the `dome.command` event has been emitted + from the `Main` process. + + See also [Dome.onCommand](dome_.html#.onCommand) event handler. +*/ +export function getWorkingDir() { return command_wdir; } + +/** + @summary Command-line arguments (Application Window). + @return {Array.<string>} command-line arguments + @description + This the command-line arguments used to open the application window. + + The function returns `undefined` until the `dome.command` event has been emitted + from the `Main` process. + + See also [Dome.onCommand](dome_.html#.onCommand) event handler. +*/ +export function getArguments() { return command_argv; } + +/** @summary Returns static assets. + @param {string} [...path] - a sequecne of path segments + @description + Returns the path to the associated `./static/<...path>` of your application. + The `./static/` directory is automatically packed into your application + by Dome thanks to `electron-webpack` default configuration. +*/ +export function getStatic(...path) { return fspath.join( __static, ...path ); } + +// -------------------------------------------------------------------------- +// --- File Join +// -------------------------------------------------------------------------- + +/** + @summary Join file paths. + @param {string} [...paths] - a sequence of path segments + @return {string} the joined filepath + @description + Same as [Node `path.join`](https://nodejs.org/dist/latest-v12.x/docs/api/path.html#path_path_join_paths) +*/ +export const join = fspath.join ; + +/** + @summary Absolute (joined) file paths. + @param {string} [...paths] - a sequence of path segments + @return {string} the corresponding absolute path + @description + Same as [Node `path.resolve`](https://nodejs.org/dist/latest-v12.x/docs/api/path.html#path_path_resolve_paths) +*/ +export const resolve = fspath.resolve ; + +/** + @summary Dirname of path. + @param {string} path - a file path + @return {string} the dirname of the path + @description + Same as [Node `path.dirname`](https://nodejs.org/dist/latest-v12.x/docs/api/path.html#path_path_dirname_path) +*/ +export const dirname = fspath.dirname ; + +/** + @summary Basename of path. + @param {string} path - a file path + @param {string} [ext] - file extension to remove + @return {string} the basename of the path + @description + Same as [Node `path.basename`](https://nodejs.org/dist/latest-v12.x/docs/api/path.html#path_path_basename_path_ext) +*/ +export const basename = fspath.basename ; + +/** + @summary File extension of path. + @param {string} path - a file path + @return {string} the file extension of the path + @description + Same as [Node `path.extname`](https://nodejs.org/dist/latest-v12.x/docs/api/path.html#path_path_extname_path) +*/ +export const extname = fspath.extname ; + +// -------------------------------------------------------------------------- +// --- File Stats +// -------------------------------------------------------------------------- + +/** + @summary Return an `fs.stat()` object for the path. + @param {string} path - the file path + @return {Promise<fs.Stats>} the file stats + @description +Promisified [Node `fs.stat`](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_fs_stat_path_callback). + +Returns a (promised) [Node `fs.Stats`](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_class_fs_stats) object, +including the following usefull fields and methods (and more): + - `stats.isFile()` returns `true` for a regular file + - `stats.isDirectory()` returns `true` for a directory + - `stats.mode` the bitfield (integer) of the file access mode + - `stats.size` the size of the file (in bytes) + - `stats.mtime` last modification time stamp (javascript `Date` object) + +The promise is rejected if the file does not exists. +*/ +export function fileStat( path ) { + return new Promise((resolve,reject) => { + fs.stat( path, (err,data) => err ? reject(err) : resolve(data) ); + }); +} + +/** + @summary Check is a path exists and is a regular file. + @param {string} path - the file path + @return {boolean} synchronous check +*/ +export function isFile( path ) +{ + try { + return path && fs.statSync( path ).isFile(); + } catch(_err) { + return false; + } +} + +/** + @summary Check is a path exists and is a directory. + @param {string} path - the dir path + @return {boolean} synchronous check +*/ +export function isDirectory( path ) +{ + try { + return path && fs.statSync( path ).isDirectory(); + } catch(_err) { + return false; + } +} + +/** + @summary Check is a path exists and is a file or directory. + @param {string} path - the dir path + @return {boolean} synchronous check +*/ +export function exists( path ) +{ + try { + if (!path) return false; + let stats = fs.statSync( path ); + return stats.isFile() || stats.isDirectory(); + } catch(_err) { + return false; + } +} + +// -------------------------------------------------------------------------- +// --- Read File +// -------------------------------------------------------------------------- + +/** + @summary Reads a textual file contents. + @param {string} path - the file path + @return {Promise<string>} the file's content + @description + Promisified + [Node `fs.readFile`](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_fs_readfile_path_options_callback) + using `UTF-8` encoding. + */ +export function readFile( path ) { + return new Promise((resolve,reject) => { + fs.readFile( path, 'UTF-8', (err,data) => err ? reject(err) : resolve(data) ); + }); +} + +// -------------------------------------------------------------------------- +// --- Write File +// -------------------------------------------------------------------------- + +/** + @summary Writes a textual content in a file. + @param {string} path - the file path + @param {string} content - the content to write in + @return {Promise} to handle the request. + @description + Promisified + [Node `fs.writeFile`](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_fs_writefile_file_data_options_callback) + using `UTF-8` encoding. + */ +export function writeFile( path , content ) { + return new Promise((resolve,reject) => { + fs.writeFile( path, content, 'UTF-8', (err) => err ? reject(err) : resolve() ); + }); +} + +// -------------------------------------------------------------------------- +// --- Copy File +// -------------------------------------------------------------------------- + +/** + @summary Copy file to a new path. + @param {string} srcPath - the source file path + @param {string} tgtPath - the target file path + @return {Promise} to handle the request. + @description + Promisified + [Node `fs.copyFile`](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_fs_copyfile_src_dest_flags_callback) + using `UTF-8` encoding. + */ +export function copyFile( srcPath , tgtPath ) { + return new Promise((resolve,reject) => { + fs.copyFile( srcPath, tgtPath, (err) => err ? reject(err) : resolve() ); + }); +} + +// -------------------------------------------------------------------------- +// --- Read Directory +// -------------------------------------------------------------------------- + +/** + @summary Reads a directory. + @param {string} path - the directory path + @return {Promise<string[]>} the directory content as an array of its file names (not full path) + @description + Promisified + [Node `fs.readdir`](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_fs_readdir_path_options_callback). + + Uses `UTF-8` encoding to obtain (relative) file names instead of byte buffers. On MacOS, `.DS_Store` entries + are filtered out. +*/ +export function readDir( path ) { + const filterDir = (f) => f !== '.DS_Store' ; + return new Promise((resolve,reject) => { + fs.readdir( path, 'UTF-8', (err,files) => err ? reject(err) : resolve(files.filter(filterDir)) ); + }); +} + +// -------------------------------------------------------------------------- +// --- Make Directory +// -------------------------------------------------------------------------- + +/** + @summary Creates a new directory. + @param {string} path - the directory path + @param {object} options - permissions and mode (defaults to recursive, `0o777`) + @return {Promise} to handle the request. + @description + Promisified + [Node `fs.mkdir`](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_fs_mkdir_path_options_callback). + Options: + - `mode:number` permission modes (default is `0o777`) + - `recursive:boolean` recursively create parent directories (default is `true`) +*/ +export function mkDir( path, { recursive=true, mode=0o777 }={} ) +{ + return new Promise((resolve,reject) => { + fs.mkdir( path, { recursive, mode }, (err) => err ? reject(err) : resolve() ); + }); +} + +// -------------------------------------------------------------------------- +// --- Remove File +// -------------------------------------------------------------------------- + +/** + @summary Remove a file. + @param {string} path - the file path to unlink + @return {Promise} to handle the request. + @description + Promisified + [Node `fs.unlink`](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_fs_unlink_path_callback) +*/ +export function remove( path ) +{ + return new Promise((resolve,reject) => { + fs.unlink( path, (err) => err ? reject(err) : resolve() ); + }); +} + +// -------------------------------------------------------------------------- +// --- Remove Directory +// -------------------------------------------------------------------------- + +// Not (yet) implemented in Node for Electron +function rmDirNonRec(path) { + return new Promise((resolve,reject) => { + fs.rmdir( path, (err) => err ? reject(err) : resolve() ); + }); +} + +// Not (yet) implemented in Node for Electron +function rmDirRec(path) { + try { + let stats = fs.statSync( path ); + if (stats.isFile()) { + return remove(path); + } + if (stats.isDirectory()) { + const rmDirSub = (name) => rmDirRec(fspath.join(path,name)); + return readDir(path) + .then((names) => Promise.all(names.map(rmDirSub))) + .then(() => rmDirNonRec(path)); + } + return Promise.resolve(); + } catch(_err) { + return Promise.resolve(); + } +} + +/** + @summary Remove a directory. + @param {string} path - the directory path + @param {object|boolean} [options] - deletion mode (defaults to non-recursive) + @return {Promise} to handle the request. + @description + Promisified + [Node `fs.rmdir`](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_fs_mkdir_path_options_callback). + Options: + - `recursive:boolean` recursively remove sub-directories (default is `true`) +*/ +export function rmDir( path, { recursive=true }={} ) +{ + return recursive ? rmDirRec( path ) : rmDirNonRec( path ); +} + +// -------------------------------------------------------------------------- +// --- Rename File +// -------------------------------------------------------------------------- + +/** + @summary Rename of file of direcory. + @param {string} oldPath - the old path + @param {string} newPath - the new path + @return {Promise} to handle the request. + @description + Promisified + [Node `fs.rename`](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_fs_rename_oldpath_newpath_callback) +*/ +export function rename( oldPath, newPath ) +{ + return new Promise((resolve,reject) => { + fs.rename( oldPath, newPath, (err) => err ? reject(err) : resolve() ); + }); +} + +// -------------------------------------------------------------------------- +// --- Child Process +// -------------------------------------------------------------------------- + +const childprocess = {} ; + +atExitForEach(childprocess,(process) => process.kill()); + +function stdSpec( spec , isOutput ) { + switch(spec) { + case undefined: + return { io: isOutput ? 'pipe' : 'ignore' }; + case null: + case 'null': + case 'ignore': + return { io: 'ignore' }; + case 'pipe': + return { io: 'pipe' }; + default: + const fd = fs.openSync( spec.path , spec.mode || (isOutput ? 'w' : 'r') ); + return (isOutput && spec.pipe) ? { io: 'pipe', fd } : { io: fd } ; + } +} + +function pipeTee( std , fd ) +{ + if (!fd) return; + const out = fs.createWriteStream(null,{ fd, encoding: 'UTF-8' }); + out.on('error',(err) => { + console.warn("[Dome] can not pipe:",err); + std.unpipe(out); + }); + std.pipe(out); +} + +/** + @summary Spawn a child process. + @param {string} command - the command to spawn + @param {string[]} [args] - the command arguments + @param {object} [options] - spawning options (see above) + @return {Promise<ChildProcess>} unless rejected, returns a process + object to interact with the spawned command + @description +Based on [Node `child_process.spawn`](https://nodejs.org/dist/latest-v12.x/docs/api/child_process.html#child_process_child_process_spawn_command_args_options). The promised process object is a regular [Node `ChildProcess`](https://nodejs.org/api/child_process.html#child_process_class_childprocess) object, for which we recall the main useful methods below: + + - `child.on('exit',(code) => {...})` emitted event when the process is terminated + - `child.on('close',(code) => {...})` emitted event when the process is fully terminated (all pipes closed) + - `child.on('message',(...data) => {...})` emitted from the _forked_ process (if applicable) + - `child.stdout.on('data',(text) => {...})` emitted when the process writes on piped stdout (receives `UTF-8` strings) + - `child.stderr.on('data',(text) => {...})` emitted when the process writes on piped stderr (receives `UTF-8` strings) + - `child.kill()` sends a `'SIGTERM'` unix message to the process + +Options is an object similar to the original Node options, with small adaptations. +The possible option fields are described as follows: + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `cwd` | `string` | `process.cmd` | Working directory for the command | +| `env` | `object` | `{}` | _additional_ environment variables | +| `stdin` | _stdio_ | `'ignored'` | Standard input stream | +| `stdout` | _stdio_ | `'pipe'` | Standard output stream | +| `stderr` | _stdio_ | `'pipe'` | Standard error stream | +| `fork` | `boolean` | `false` | Fork a Node-child process | + +Environment variables are _added_ to the default `process.env` environment. + +Input and output streams are defined according to the following table: + +| _stdio_ | Description | +|----------|-------------| +| `'pipe'` | Accessible _via_ the promised child-process object | +| `'ignored'` | Connected to `/dev/null` | +| `{ path[,mode][,pipe] }` | Connected to file `path` | + +All pipes have their encoding set to `UTF-8`, +hence all callbacks on process events will receive natural strings instead of raw byte buffers. + +When specifying a file for a process standard stream, an optional mode can be specified. +Default is `'r'` for input streams and `'w'` for output ones. +If option `pipe:true` is provided (output streams only), the output of the process is +also piped through the Process object. The file-path is relative to the current working directory +of the _application_, not be confused with the `cwd` option of the spawned command. + +When the `fork` flag is set, the child process is spawned using +[Node `child_process.fork`](https://nodejs.org/dist/latest-v12.x/docs/api/child_process.html#child_process_child_process_fork_modulepath_args_options). This enables Node inter-process communication _via_ the +`process.send()` and `process.on('message')` methods of the child process object. +*/ + +export function spawn(command,args,options) { + return new Promise((resolve,reject) => { + + const cwd = options ? options.cwd : undefined ; + const env = options && options.env ? Object.assign( {} , process.env , options.env ) : undefined ; + const stdin = stdSpec( options && options.stdin , false ); + const stdout = stdSpec( options && options.stdout , true ); + const stderr = stdSpec( options && options.stderr , true ); + const stdio = [ stdin.io , stdout.io , stderr.io ] ; + const opt = { cwd , env , stdio , windowsHide: true }; + const fork = options && options.fork ; + var process ; + + if (fork) { + opt.stdio.push( 'ipc' ); + process = Exec.fork(command,args,opt); + } else { + process = Exec.spawn(command,args,opt); + } + + if ( !process ) { + throw "[Dome] Can not create process ('"+command+"')"; + return; + } + + const pid = process.pid ; + + if ( !pid ) { + // Must defer rejection, otherwize an uncaught exception is raised. + process.on('error',(err) => reject(err)); + return; + } + + childprocess[pid] = process ; + process.on('exit',() => delete childprocess[pid]); + + const out = process.stdout ; + const err = process.stderr ; + + if (out) { + out.setEncoding('UTF-8'); + pipeTee( out , stdout.fd ); + } + if (err) { + err.setEncoding('UTF-8'); + pipeTee( err , stderr.fd ); + } + + resolve(process); + }); +} + +// -------------------------------------------------------------------------- +// --- Window Management +// -------------------------------------------------------------------------- + +const WINDOW_APPLICATION_ARGV = '--dome-application-window' ; +const WINDOW_PREFERENCES_ARGV = '--dome-preferences-window' ; + +// -------------------------------------------------------------------------- +// --- Export Default +// -------------------------------------------------------------------------- + +export default { + platform, + DEVEL, + atExit, + atExitForEach, + doExit, + getHome, + getDesktop, + getDocuments, + getDownloads, + getWorkingDir, + getArguments, + getStatic, + join, resolve, dirname, basename, extname, + fileStat, + isFile, readFile, writeFile, copyFile, + isDirectory, readDir, mkDir, rmDir, + rename, remove, exists, + spawn, + setCommand, + WINDOW_APPLICATION_ARGV, + WINDOW_PREFERENCES_ARGV +}; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/controls/buttons.css b/Ivette/src/dome/src/renderer/controls/buttons.css new file mode 100644 index 0000000000000000000000000000000000000000..8d83de5e744857e09faac010364356a902f1cdc5 --- /dev/null +++ b/Ivette/src/dome/src/renderer/controls/buttons.css @@ -0,0 +1,257 @@ +/* -------------------------------------------------------------------------- */ +/* --- Base Styling --- */ +/* -------------------------------------------------------------------------- */ + +.dome-control-enabled { + color: #333 ; + font-weight: normal ; +} + +.dome-control-disabled { + color: #b0b0b0 ; + fill: #b0b0b0 ; + font-weight: lighter ; +} + +.dome-control-hidden { + visibility: hidden ; +} + +.dome-control-erased { + display: none ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Styling Buttons --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xButton { + flex: 0 0 auto ; + align-self: baseline ; +} + +.dome-xBoxButton { + padding: 3px 8px ; + margin: 2px 4px ; + line-height: 1.4; + cursor: default; + border: 1px solid transparent; + border-radius: 6px; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.06); +} + +.dome-xCircButton { + padding: 2px ; + margin: 2px 4px ; + cursor: default; + border: 1px solid transparent; + border-radius: 20px; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.06); +} + +.dome-xButton:disabled, +.dome-xButton:active:disabled, +.dome-window-inactive .dome-xButton +{ + fill: #b0b0b0 ; + border-color: #ccc ; + background-color: #f4f4f4 ; + background-image: none; +} + +.dome-xButton:active { + background-color: #ddd; + background-image: none; +} + +.dome-xButton-lcd { + text-align: right ; + color: #61611a ; + background-color: #b2b798 ; + border-color: #c2c0c2 ; +} + +.dome-xButton-default { + border-color: #c2c0c2 ; + background-color: #f4f4f4 ; +} + +.dome-xButton-default:hover:not(:disabled) { + background-color: #fff ; +} + +.dome-xButton-selected { + border-color: #c2c0c2 ; + background-color: #ccc ; +} + +.dome-xButton-selected:hover:not(:disabled) { + background-color: #fff ; +} + +.dome-xButton-primary { + border-color: #888; + background-image: linear-gradient(to bottom, #449bef 0%, #4990e2 100%); +} + +.dome-xButton-primary:hover:not(:disabled) { + background-color: #00b6ff ; + background-image: none ; +} + +.dome-xButton-positive { + border-color: #888; + background-image: linear-gradient(to bottom, #60f577 0%, #3efb5b 100%); +} + +.dome-xButton-positive:hover:not(:disabled) { + background-color: #00ff00 ; + background-image: none ; +} + +.dome-xButton-negative { + border-color: #888; + fill: #333; + color: #333 ; + background-image: linear-gradient(to bottom, #ff827d 0%, #fb3832 100%); +} + +.dome-xButton-negative:hover:not(:disabled) { + background-color: #ff0000 ; + background-image: none ; +} + +.dome-xButton-warning { + border-color: #888; + background-image: linear-gradient(to bottom, #ffd483 0%, #ffb426 100%); +} + +.dome-xButton-warning:hover:not(:disabled) { + background-color: #ecdd09 ; + background-image: none ; +} + +.dome-xButton-label { + position: relative ; + padding: 2px ; + display: inline ; + font-size: 12px ; +} + +.dome-xButton-label.dome-control-enabled { + position: absolute ; left: 0 ; top: 0 ; width: 100% ; + /* font is smaller than disabled => absolute position */ +} + +.dome-xButton-label.dome-control-disabled { + position: relative ; width: 100% ; + /* font is larger than enabled => relative position */ +} + +/* -------------------------------------------------------------------------- */ +/* --- Styling Checkbox --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xCheckbox { + padding: 0 ; + margin: 1px 4px ; +} + +.dome-xCheckbox input { + margin-right: 8px ; + position: relative ; + left: 2px ; +} + +.dome-xRadio-group { + display: flex ; + overflow: hidden ; + flex-flow: column nowrap ; + align-items: flex-start ; + justify-contents: flex-start ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Styling IconButton --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xIconButton { + margin: 4px ; + background: transparent ; +} + +.dome-xIconButton:hover { + fill: #00b6ff ; +} + +.dome-xIconButton-default { + fill: #777 ; +} + +.dome-xIconButton-selected { fill: #449bef ; } + +.dome-xIconButton-positive { fill: #00d000 ; } + +.dome-xIconButton-negative { fill: #fb3832 ; } + +.dome-xIconButton-warning { + fill: #449bef ; +} + +.dome-xIconButton.dome-control-disabled, +.dome-xIconButton.dome-control-disabled:hover +{ + fill: #eee ; +} + +.dome-xIconButton.dome-control-hidden { + visibility: hidden ; +} + +.dome-xIconButton.dome-control-erased { + display: none ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Styling Switches --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xSwitch { + flex: 0 0 auto ; + padding: 0px ; + margin: 1px 4px ; +} + +.dome-xSwitch .dome-xIcon { + position: relative ; + height: 0px ; + top: 2px ; + margin-right: 3px ; +} + +.dome-xSwitch.dome-control-enabled:hover:not(:disabled) { + fill: blue ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Styling Select --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xSelect { + width: max-content ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Styling Field --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xField { + font-size: 10pt ; + width: 120px ; + padding-top: 1px ; + padding-bottom: 1px ; + padding-right: 4px ; + padding-left: 4px ; +} + +/* -------------------------------------------------------------------------- */ diff --git a/Ivette/src/dome/src/renderer/controls/buttons.js b/Ivette/src/dome/src/renderer/controls/buttons.js new file mode 100644 index 0000000000000000000000000000000000000000..4688fcc3edadcc302b41b6606421c4faea56bc5f --- /dev/null +++ b/Ivette/src/dome/src/renderer/controls/buttons.js @@ -0,0 +1,522 @@ +// -------------------------------------------------------------------------- +// --- Buttons, Check Boxes and Radio Groups +// -------------------------------------------------------------------------- + +/** + @module dome/controls/buttons + @description + + Those controls may work as _controlled_ or _uncontrolled_ components, + although you shall not use both modes at the same times. + +*/ + +import React from 'react' ; +import { Icon } from './icons' ; +import './buttons.css' ; + +const DISABLED = ({ disabled=false, enabled=true }) => !!disabled || !enabled ; +const TRIGGER = (onClick) => (evt) => { + evt.stopPropagation(); + if (onClick) onClick(); +}; + +// -------------------------------------------------------------------------- +// --- LCD +// -------------------------------------------------------------------------- + +const LCDCLASS = 'dome-xButton dome-text-code dome-xButton-lcd ' ; + +/** + @class + @summary Button-like label. + @property {string} [text] - Textual content (prepend to children components, if any) + @property {string} [icon] - Label icon (optional, on left side) + @property {string} [title] - Label tooltip (optional) + @property {string} [className] - Additional class + @property {object} [style] - Additional CSS style +*/ +export const LCD = (props) => ( + <label className={LCDCLASS + props.className} + title={props.title} + style={props.style} > + {props.icon && <Icon id={props.icon}/>} + {props.label} + {props.text} + {props.children} + </label> +); + +// -------------------------------------------------------------------------- +// --- Button +// -------------------------------------------------------------------------- + +const VISIBLE = { visibility:'visible' }; +const HIDDEN = { visibility:'hidden' }; + +const LABEL = ({disabled,label}) => ( + <div className="dome-xButton-label" > + <div className="dome-xButton-label dome-control-enabled" + style={disabled ? HIDDEN : VISIBLE} >{label}</div> + <div className="dome-xButton-label dome-control-disabled" + style={disabled ? VISIBLE : HIDDEN}>{label}</div> + </div> +); + +/** + @class + @summary Standard Button. + @property {string} [icon] - Label icon (optional, on left side) + @property {string} [label] - Button label + @property {string} [title] - Optional tooltip + @property {boolean} [selected] - Selected button + @property {boolean} [enabled] - Defaults to `true` + @property {boolean} [disabled] - Defaults to `false` + @property {boolean} [visible] - Defaults to `true` + @property {boolean} [display] - Defaults to `true` + @property {boolean} [focusable] - May gain focus + @property {string} [kind] - Styled button (see below) + @property {function} [onClick] - On-click callback + @property {string} [className] - Additional class + @property {object} [style] - Additional style + @description + The different available kinds for styling a button are: + - `'default'`: normal button; + - `'active'`: active normal button; + - `'primary'`: primary button, in blue; + - `'warning'`: warning button, in orange; + - `'positive'`: positive button, in green; + - `'negative'`: negative button, in red. + + Buttons without focus can not be triggered with the Enter key. +*/ +export const Button = (props) => { + const disabled = DISABLED(props); + const { focusable=false, kind='default', + visible=true, display=true, + selected, icon, label, className='' } = props; + const theClass = 'dome-xButton dome-xBoxButton dome-xButton-' + + (selected ? 'selected' : kind) + + (visible ? '' : ' dome-control-hidden') + + (display ? '' : ' dome-control-erased') + + (className ? ' ' + className : '') ; + const nofocus = focusable ? undefined : true ; + return ( + <button type='button' + className={theClass} + disabled={disabled} + onClick={TRIGGER(props.onClick)} + title={props.title} + style={props.style} + tabIndex={ nofocus && -1 } + onMouseDown={ nofocus && ((evt) => evt.preventDefault()) } + > + {icon && <Icon id={icon}/>} + {label && <LABEL disabled={disabled} label={label}/>} + </button> + ); +}; + +// -------------------------------------------------------------------------- +// --- Icon Button +// -------------------------------------------------------------------------- + +/** + @class + @summary Circled Icon Button. + @property {string} [icon] - Label icon (optional, on left side) + @property {string} [title] - Optional tooltip + @property {boolean} [selected] - Selected button + @property {boolean} [enabled] - Defaults to `true` + @property {boolean} [disabled] - Defaults to `false` + @property {boolean} [visible] - Defaults to `true` + @property {boolean} [display] - Defaults to `true` + @property {boolean} [focusable] - May gain focus + @property {string} [kind] - Styled button (see below) + @property {function} [onClick] - On-click callback + @property {string} [className] - Additional class + @property {object} [style] - Additional style + @description + The different available kinds for styling a button are: + - `'default'`: normal button; + - `'active'`: active normal button; + - `'primary'`: primary button, in blue; + - `'warning'`: warning button, in orange; + - `'positive'`: positive button, in green; + - `'negative'`: negative button, in red. + + Buttons without focus can not be triggered with the Enter key. +*/ + +export const CircButton = (props) => { + const disabled = DISABLED(props); + const { focusable=false, kind='default', + visible=true, display=true, + selected, icon, label, className='' } = props; + const theClass = 'dome-xButton dome-xCircButton dome-xButton-' + + (selected ? 'selected' : kind) + + (visible ? '' : ' dome-control-hidden') + + (display ? '' : ' dome-control-erased') + + (className ? ' ' + className : '') ; + const nofocus = focusable ? undefined : true ; + return ( + <button type='button' + className={theClass} + disabled={disabled} + onClick={TRIGGER(props.onClick)} + title={props.title} + style={props.style} + tabIndex={ nofocus && -1 } + onMouseDown={ nofocus && ((evt) => evt.preventDefault()) } + > + {icon && <Icon offset={-1} id={icon}/>} + </button> + ); +}; + +// -------------------------------------------------------------------------- +// --- Icon Button +// -------------------------------------------------------------------------- + +/** + @class + @summary Borderless Icon Button. + @property {string} icon - Icon identifier + @property {number} size - Icon size (default `12`) + @property {number} offset - Icon offset + @property {string} [title] - Optional tooltip + @property {boolean} [enabled] - Defaults to `true` + @property {boolean} [disabled] - Defaults to `false` + @property {boolean} [visible] - Defaults to `true` + @property {boolean} [display] - Defaults to `true` + @property {boolean} [selected] - Defaults to `false` + @property {function} [onClick] - Callback (receives the newly expected value) + @property {string} [kind] - Styled button (see below) + @property {string} [className] - Additional class + @property {object} [style] - Additional style + @description + The different available kinds for styling a button are: + - `'default'`: normal button; + - `'active'`: active normal button; + - `'warning'`: warning button, in orange; + - `'positive'`: positive button, in green; + - `'negative'`: negative button, in red. +*/ + +export const IconButton = (props) => { + const disabled = DISABLED(props); + const { icon, size, visible=true, display=true, selected, kind='default' } = props ; + const className = 'dome-xIconButton' + + ' dome-xIconButton-' + (selected ? 'selected' : kind) + + (disabled ? ' dome-control-disabled' : ' dome-control-enabled') + + (visible ? '' : ' dome-control-hidden') + + (display ? '' : ' dome-control-erased') + + (props.className ? ' ' + props.className : '') ; + return ( + <Icon + size={size} id={icon} + style={props.style} + offset={props.offset} + className={className} + onClick={TRIGGER(props.onClick)} + /> + ); +}; + +// -------------------------------------------------------------------------- +// --- CheckBox +// -------------------------------------------------------------------------- + +const CHECKBOX_ENABLED = 'dome-control-enabled dome-xCheckbox ' ; +const CHECKBOX_DISABLED = 'dome-control-disabled dome-xCheckbox ' ; + +/** + @class + @summary CheckBox with its label. + @property {string} [label] - Button label + @property {string} [title] - Optional tooltip + @property {boolean} [enabled] - Defaults to `true` + @property {boolean} [disabled] - Defaults to `false` + @property {boolean} [value] - Checked or not (defaults to internal state) + @property {function} [onChange] - Callback (receives the newly expected value) + @property {string} [className] - Additional class + @property {object} [style] - Additional style +*/ +export const Checkbox = (props) => { + const disabled = DISABLED(props); + const onChange = props.onChange && ((evt) => props.onChange(evt.target.checked)) ; + const baseClass = disabled ? CHECKBOX_DISABLED : CHECKBOX_ENABLED ; + const labelClass = props.className || '' ; + return ( + <label + title={props.title} + style={props.style} + className={baseClass + labelClass} > + <input type="checkbox" + disabled={disabled} + checked={props.value} + onChange={onChange} /> + {props.label} + </label> + ); +}; + +// -------------------------------------------------------------------------- +// --- Switch +// -------------------------------------------------------------------------- + +/** + @class + @summary Switch with its label. + @property {string} [label] - Button label + @property {string} [title] - Optional tooltip + @property {boolean} [enabled] - Defaults to `true` + @property {boolean} [disabled] - Defaults to `false` + @property {boolean} [visible] - Defaults to `true` + @property {boolean} [display] - Defaults to `true` + @property {boolean} [value] - Checked or not (defaults to internal state) + @property {function} [onChange] - Callback (receives the newly expected value) + @property {string} [className] - Additional class + @property {object} [style] - Additional style +*/ +export const Switch = (props) => { + const disabled = DISABLED(props); + const { visible=true, display=true } = props ; + const onChange = props.onChange && ((evt) => props.onChange(evt.target.checked)) ; + const iconId = props.value ? 'SWITCH.ON' : 'SWITCH.OFF' ; + const onClick = (disabled || !props.onChange) + ? undefined : () => props.onChange(!props.value) ; + const className = 'dome-xSwitch ' + + (disabled ? 'dome-control-disabled' : 'dome-control-enabled') + + (visible ? '' : ' dome-control-hidden') + + (display ? '' : ' dome-control-erased') + + (props.className ? ' ' + props.className : '') ; + return ( + <label + title={props.title} + style={props.style} + className={className} + onClick={TRIGGER(onClick)} + > + <Icon size={16} id={iconId} /> + {props.label} + </label> + ); +}; + +// -------------------------------------------------------------------------- +// --- Radio Button +// -------------------------------------------------------------------------- + +/** + @class + @summary Radio Button with its label. + @property {string} [label] - Button label + @property {string} [title] - Optional tooltip + @property {boolean} [enabled] - Defaults to `true` + @property {boolean} [disabled] - Defaults to `false` + @property {any} [value] - Associated value to the radio + @property {any} [selection] - Currently selected value + @property {function} [onSelection] - On-click callback + @property {string} [className] - Additional class + @property {object} [style] - Additional style + @description + See also [RadioGroup](module-dome_controls_buttons.RadioGroup.html). + + <strong>Note:</strong> property `value` and `selection` are consistent + with HTML standards and DOM element properties. +*/ +export const Radio = (props) => { + const disabled = DISABLED(props); + const checked = props.value === props.selection ; + const onChange = props.onSelection && (() => props.onSelection(props.value)) ; + const baseClass = disabled ? CHECKBOX_DISABLED : CHECKBOX_ENABLED ; + const labelClass = props.className || '' ; + return ( + <label + title={props.title} + style={props.style} + className={baseClass + labelClass} > + <input type="radio" disabled={disabled} checked={checked} onChange={onChange} /> + {props.label} + </label> + ); +}; + +// -------------------------------------------------------------------------- +// --- Radio Group +// -------------------------------------------------------------------------- + +/** + @class + @summary Selector of Radio Buttons. + @property {any} [value] - Currently selected value + @property {boolean} [enabled] - Defaults to `true` + @property {boolean} [disabled] - Defaults to `false` + @property {function} [onChange] - On-selection callback + @property {string} [className] - Additional class of the container `<div>` + @property {object} [style] - Additional style of the container `<div>` + @description + Childrens of the `RadioGroup` shall be [Radio](module-dome_controls_buttons.Radio.html) + buttons. + + The selected value of the group is broadcasted to the radio buttons. Their + callbacks are activated _before_ the radio group one, if any. + + If the radio group is disabled, all the radio buttons are disabled also and + their `disabled` properties are ignored. On the contrary, when the radio + group is enabled, the `disabled` property of each radio button is taken into + account. + + The radio buttons inside a group are laidout in a vertical box with the additional + styling properties. +*/ +export class RadioGroup extends React.Component { + + constructor(props) { + super(props); + this.state = { value: props.value }; + this.onChange = this.onChange.bind(this); + } + + componentDidUpdate() { + let v = this.props.value ; + if (v && this.state.value !== v) this.setState( { value: v } ); + } + + onChange(value) { + this.setState( { value } ); + this.props.onChange && this.props.onChange( value ); + } + + render() { + const groupdisabled = DISABLED(this.props); + const { className='', style } = this.props ; + const selection = this.state.value ; + const makeRadio = (radio) => { + const disabled = groupdisabled || DISABLED(radio.props) ; + const { onSelection: onRadioSelect } = radio.props ; + const onSelection = + onRadioSelect + ? (v) => { onRadioSelect(v) ; this.onChange(v); } + : this.handleSelect ; + return React.cloneElement( radio , { selection , disabled , onSelection } , null ); + } ; + return ( + <div className={ 'dome-xRadio-group ' + className } style={style}> + {React.Children.map( this.props.children , makeRadio )} + </div> + ); + } + +} + +// -------------------------------------------------------------------------- +// --- Selector +// -------------------------------------------------------------------------- + +/** + @class + @summary Menu Button. + @property {string} [placeholder] - Label of undefined selection + @property {string} [title] - Optional tooltip + @property {any} [value] - Currently selected value + @property {boolean} [enabled] - Defaults to `true` + @property {boolean} [disabled] - Defaults to `false` + @property {function} [onChange] - On-selection callback + @property {string} [className] - Additional class + @property {object} [style] - Additional style + @property {string} [id] - Select identifier + @description + Childrens of the `Select` shall be standard `<option>` or `<optgroup>` HTML + elements. When the `placeholder` property is set, an additional option is provided + and associated with any `undefined` value. + + The selected value of the group is broadcasted to the provided options, and their callbacks + linked to the button automatically. + + **Remark:** most non-positionning CSS properties might not work on the `<select>` element due + to the native rendering used by Chrome. + You might use `-webkit-appearance: none` to cancel this behavior, you will have to restyle the + component entirely, which is quite ugly by default. +*/ +export const Select = (props) => { + const disabled = DISABLED(props); + const onChange = props.onChange && ((e) => props.onChange(e.target.value)); + const className = props.className || '' ; + return ( + <select + id={props.id} + disabled={disabled} + className={'dome-xSelect ' + className} + style={props.style} + title={props.title} + value={props.value || ''} + onChange={onChange} + > + {props.placeholder && props.placeholder !=='' && ( + <option disabled value=''>— {props.placeholder} —</option> + )} + {props.children} + </select> + ); +}; + +// -------------------------------------------------------------------------- +// --- Text Input +// -------------------------------------------------------------------------- + +/** + @class + @summary Text Field + @property {string} [value] - Field initial content + @property {string} [edited] - Field current value + @property {boolean} [enabled] - Defaults to `true` + @property {boolean} [disabled] - Defaults to `false` + @property {boolean} [autoFocus] - Defaults to `false` + @property {function} [onChange] - Update callback (on every edit, debounced) + @property {function} [onEnter] - Enter callback (on Enter or Return key) + @property {string} [title] - Field tooltip text + @property {string} [placeholder] - Input field place holder + @property {string} [className] - Input field additional class + @property {object} [style] - Input field additional style + @property {string} [id] - Input field identifier + @description + Field with a Text Input element. The default latency is set to 600ms. +*/ +export const Field = (props) => { + const [ current, setCurrent ] = React.useState(props.value); + const disabled = DISABLED(props); + const className = props.className || '' ; + const { edited, onChange, onEnter } = props ; + const value = edited === undefined ? current : edited ; + const ONCHANGE = (evt) => { + let text = evt.target.value || '' ; + if (edited === undefined) setCurrent(text); + onChange && onChange(text); + }; + const ONKEYPRESS = (evt) => { + if (evt.key === 'Enter' && onEnter) onEnter(value); + }; + return ( + <input id={props.id} type='text' + autoFocus={!disabled && props.autoFocus} + value={value} + className={'dome-xField ' + className} + style={props.style} + disabled={disabled} + placeholder={props.placeholder} + onKeyPress={ONKEYPRESS} + onChange={ONCHANGE} /> + ); +}; + +// -------------------------------------------------------------------------- +// --- Exports +// -------------------------------------------------------------------------- + +export default { + Button, CircButton, IconButton, Switch, Checkbox, Radio, RadioGroup, Select +}; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/controls/icons.css b/Ivette/src/dome/src/renderer/controls/icons.css new file mode 100644 index 0000000000000000000000000000000000000000..066887a39172745fa58aa671f1c6ff496652a440 --- /dev/null +++ b/Ivette/src/dome/src/renderer/controls/icons.css @@ -0,0 +1,42 @@ +/* -------------------------------------------------------------------------- */ +/* --- Styling Icons --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xIcon { + flex: 0 0 auto ; + display: inline ; + margin: 1px ; + padding: 1px 0px 0px 0px ; +} + +.dome-xIcon svg { + position:relative ; +} + +.dome-xBadge { + flex: 0 0 auto ; + display: inline ; + margin: 1px ; + padding: 1px 6px 1px 6px ; + height: 16px ; + fill: #dedede ; + color: #dedede ; + font-family: sans-serif ; + font-size: smaller ; + font-weight: bold ; + border-radius: 8px ; + background: #777 ; +} + +.dome-window-inactive .dome-xBadge, +.dome-disabled .dome-xBadge +{ + background: #ccc ; + color: #eee ; + fill: #eee ; +} + +.dome-xBadge label { + position: relative ; + bottom: -1px ; +} diff --git a/Ivette/src/dome/src/renderer/controls/icons.js b/Ivette/src/dome/src/renderer/controls/icons.js new file mode 100644 index 0000000000000000000000000000000000000000..808cd0f2ce7db39939a9c8ab7860d121fb09090d --- /dev/null +++ b/Ivette/src/dome/src/renderer/controls/icons.js @@ -0,0 +1,156 @@ +// -------------------------------------------------------------------------- +// --- SVG Icons +// -------------------------------------------------------------------------- + +/** + @module dome/controls/icons + @description + Consult the [Icon Gallery](gallery-icons.html) for default icons. + You can [register](#.register) new icons or override existing ones + and [iterate](#.forEach) over the icon base. +*/ + +import React from 'react' ; +import Icons from './icons.json' ; +import './icons.css' ; +import _ from 'lodash' ; + +// -------------------------------------------------------------------------- +// --- Raw SVG element +// -------------------------------------------------------------------------- + +/** + @class + @property {string} id - icon's identifier (mandatory) + @property {string} [title] - icon's tool-tip (optional) + @property {number} [size] - icon's dimension in pixels (default: `12`) + @property {number} [offset] - vertical alignment offset (default: `- size * 0.125`) + @summary Raw SVG element. + @description + Consult the [Icon Gallery](gallery-icons.html) for default icons. +*/ +export function SVG( { id , title, size, offset } ) +{ + if (!id) return null; + const icon = Icons[id]; + if (!icon) return id; + if (size===undefined) size = 12 ; + if (offset===undefined) offset = _.floor( - size * 0.125 ); + return ( + <svg height={size} + width={size} + style={{bottom: offset }} + viewBox={icon.viewBox || "0 0 24 24"} > + { title && <title>{title}</title> } + <path d={icon.path}/> + </svg> + ); +} + +// -------------------------------------------------------------------------- +// --- Icon Component +// -------------------------------------------------------------------------- + +/** + @class + @summary Icon Component. + @property {string} id - icon's identifier (mandatory) + @property {string} [title] - icon's tool-tip (optional) + @property {function} [onClick] - callback when icon is clicked (optional) + @property {string} [fill] - icon's fill color (optional) + @property {number} [size] - icon's dimension in pixels (default `12`) + @property {number} [offset] - vertical alignment offset (default `-size * 0.125`) + @property {string} [className] - additional class name + @property {object} [style] - additional styles + @description + Consult the [Icon Gallery](gallery-icons.html) for default icons. +*/ +export function Icon( { id, title, onClick, fill, size, className='', offset, style } ) +{ + const divClass = 'dome-xIcon ' + className ; + const divStyle = fill ? Object.assign({fill},style) : style ; + return ( + <div className={divClass} + style={divStyle} + onClick={onClick}> + <SVG id={id} size={size} title={title} offset={offset} /> + </div> + ); +} + +// -------------------------------------------------------------------------- +// --- Badge Component +// -------------------------------------------------------------------------- + +/** + @class + @summary Rounded icon, number or letter. + @property {icon|number|string} [value] - badge content + @property {string} [title] - badge tool-tip (optional) + @property {function} [onClick] - badge on-click callback (optional) + @description + Depending on the type of value, display either a number, + a label, or the corresponding named icon. + Consult the [Icon Gallery](gallery-icons.html) for default icons. +*/ +export function Badge( { value, title, onClick } ) +{ + var content ; + if (Icons[value]) { + content = <Icon id={value} size={10} /> ; + } else { + const style = + ( typeof(value) === 'number' && value < 10 ) || + ( typeof(value) === 'string' && value.length == 1 ) ? + { paddingLeft: 2 , paddingRight: 2 } : {} ; + content = <label style={style} className='dome-text-label'>{value}</label>; + } + return ( + <div className="dome-xBadge" + title={title} onClick={onClick}> + {content} + </div> + ); +} + +// -------------------------------------------------------------------------- +// --- Icon Database +// -------------------------------------------------------------------------- + +/** + @summary Register a new icon. + @param {Object} icon - Icon's data to register (see below) + @description + The icon specification is an object with the following properties: + - `name`: icon's name + - `path`: svg path to draw the icon + - `title`: title for the icon (optional) + - `section`: section of the Icons (optional) + - `viewBox`: svg view-box property (optional, `"0 0 24 24"` by default) +*/ + +export function register(icon) { + const { name , ...deficon } = icon ; + if (!name) console.error(`[Dome] Icon has no name (skipped).`); + if (!deficon.path) console.error(`[Dome] Icon '${name}' has no path (skipped).`); + Icons[name] = deficon ; +} + +/** + @summary Iterate over registered icons. + @param {func} job - function applied to each icon + @description + See [register](#.register) for properties of the icon objects. +*/ + +export function forEach(job) { + for( var name in Icons ) { + job( Object.assign( { name } , Icons[name] )); + } +} + +// -------------------------------------------------------------------------- + +export default { Icon , Badge, SVG, register , forEach } ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/controls/icons.json b/Ivette/src/dome/src/renderer/controls/icons.json new file mode 100644 index 0000000000000000000000000000000000000000..1afd562e8e04d7a5fdfbb1255a5345dbd1e86987 --- /dev/null +++ b/Ivette/src/dome/src/renderer/controls/icons.json @@ -0,0 +1,319 @@ +{ + "SEARCH": { + "section": "Tools", + "title": "Search", + "viewBox": "0 0 22 24", + "path": "M15.429 11.143q0-2.478-1.761-4.239t-4.239-1.761-4.239 1.761-1.761 4.239 1.761 4.239 4.239 1.761 4.239-1.761 1.761-4.239zM22.286 22.286q0 0.696-0.509 1.205t-1.205 0.509q-0.723 0-1.205-0.509l-4.594-4.58q-2.397 1.661-5.344 1.661-1.915 0-3.663-0.743t-3.013-2.009-2.009-3.013-0.743-3.663 0.743-3.663 2.009-3.013 3.013-2.009 3.663-0.743 3.663 0.743 3.013 2.009 2.009 3.013 0.743 3.663q0 2.946-1.661 5.344l4.594 4.594q0.496 0.496 0.496 1.205z" + }, + "EXECUTE": { + "section": "Tools", + "viewBox": "0 0 16 16", + "path": "M5.683 11.282l0.645-0.903-0.707-0.707-0.903 0.645c-0.168-0.094-0.347-0.168-0.535-0.222l-0.183-1.095h-1l-0.183 1.095c-0.188 0.053-0.368 0.128-0.535 0.222l-0.903-0.645-0.707 0.707 0.645 0.903c-0.094 0.168-0.168 0.347-0.222 0.535l-1.095 0.183v1l1.095 0.183c0.053 0.188 0.128 0.368 0.222 0.535l-0.645 0.903 0.707 0.707 0.903-0.645c0.168 0.094 0.347 0.168 0.535 0.222l0.183 1.095h1l0.183-1.095c0.188-0.053 0.368-0.128 0.535-0.222l0.903 0.645 0.707-0.707-0.645-0.903c0.094-0.168 0.168-0.347 0.222-0.535l1.095-0.182v-1l-1.095-0.183c-0.053-0.188-0.128-0.368-0.222-0.535zM3.5 13.5c-0.552 0-1-0.448-1-1s0.448-1 1-1 1 0.448 1 1-0.448 1-1 1zM16 6v-1l-1.053-0.191c-0.019-0.126-0.044-0.25-0.074-0.372l0.899-0.58-0.383-0.924-1.046 0.226c-0.066-0.108-0.136-0.213-0.211-0.315l0.609-0.88-0.707-0.707-0.88 0.609c-0.102-0.074-0.207-0.145-0.315-0.211l0.226-1.046-0.924-0.383-0.58 0.899c-0.122-0.030-0.246-0.054-0.372-0.074l-0.191-1.053h-1l-0.191 1.053c-0.126 0.019-0.25 0.044-0.372 0.074l-0.58-0.899-0.924 0.383 0.226 1.046c-0.108 0.066-0.213 0.136-0.315 0.211l-0.88-0.609-0.707 0.707 0.609 0.88c-0.074 0.102-0.145 0.207-0.211 0.315l-1.046-0.226-0.383 0.924 0.899 0.58c-0.030 0.122-0.054 0.246-0.074 0.372l-1.053 0.191v1l1.053 0.191c0.019 0.126 0.044 0.25 0.074 0.372l-0.899 0.58 0.383 0.924 1.046-0.226c0.066 0.108 0.136 0.213 0.211 0.315l-0.609 0.88 0.707 0.707 0.88-0.609c0.102 0.074 0.207 0.145 0.315 0.211l-0.226 1.046 0.924 0.383 0.58-0.899c0.122 0.030 0.246 0.054 0.372 0.074l0.191 1.053h1l0.191-1.053c0.126-0.019 0.25-0.044 0.372-0.074l0.58 0.899 0.924-0.383-0.226-1.046c0.108-0.066 0.213-0.136 0.315-0.211l0.88 0.609 0.707-0.707-0.609-0.88c0.074-0.102 0.145-0.207 0.211-0.315l1.046 0.226 0.383-0.924-0.899-0.58c0.030-0.122 0.054-0.246 0.074-0.372l1.053-0.191zM10.5 7.675c-1.201 0-2.175-0.974-2.175-2.175s0.974-2.175 2.175-2.175 2.175 0.974 2.175 2.175c0 1.201-0.974 2.175-2.175 2.175z" + }, + "TUNINGS": { + "section": "Tools", + "title": "Tunings", + "viewBox": "0 0 24 24", + "path": "M4.714 18.857v1.714h-4.714v-1.714h4.714zM9.429 17.143q0.348 0 0.603 0.254t0.254 0.603v3.429q0 0.348-0.254 0.603t-0.603 0.254h-3.429q-0.348 0-0.603-0.254t-0.254-0.603v-3.429q0-0.348 0.254-0.603t0.603-0.254h3.429zM11.571 12v1.714h-11.571v-1.714h11.571zM3 5.143v1.714h-3v-1.714h3zM20.571 18.857v1.714h-9.857v-1.714h9.857zM7.714 3.429q0.348 0 0.603 0.254t0.254 0.603v3.429q0 0.348-0.254 0.603t-0.603 0.254h-3.429q-0.348 0-0.603-0.254t-0.254-0.603v-3.429q0-0.348 0.254-0.603t0.603-0.254h3.429zM16.286 10.286q0.348 0 0.603 0.254t0.254 0.603v3.429q0 0.348-0.254 0.603t-0.603 0.254h-3.429q-0.348 0-0.603-0.254t-0.254-0.603v-3.429q0-0.348 0.254-0.603t0.603-0.254h3.429zM20.571 12v1.714h-3v-1.714h3zM20.571 5.143v1.714h-11.571v-1.714h11.571z" + }, + "SETTINGS": { + "section": "Tools", + "title": "Configure", + "viewBox": "0 0 24 24", + "path": "M15.428 12q0-1.42-1.004-2.424t-2.424-1.004-2.424 1.004-1.004 2.424 1.004 2.424 2.424 1.004 2.424-1.004 1.004-2.424zM22.285 10.54v2.973q0 0.161-0.107 0.308t-0.268 0.174l-2.478 0.375q-0.254 0.723-0.522 1.219 0.469 0.67 1.433 1.848 0.134 0.161 0.134 0.335t-0.121 0.308q-0.362 0.496-1.326 1.446t-1.259 0.951q-0.161 0-0.348-0.121l-1.848-1.446q-0.589 0.308-1.219 0.509-0.214 1.821-0.388 2.491-0.094 0.375-0.482 0.375h-2.973q-0.188 0-0.328-0.114t-0.154-0.288l-0.375-2.464q-0.656-0.214-1.205-0.496l-1.888 1.433q-0.134 0.121-0.335 0.121-0.188 0-0.335-0.147-1.688-1.527-2.21-2.25-0.094-0.134-0.094-0.308 0-0.161 0.107-0.308 0.201-0.281 0.683-0.891t0.723-0.944q-0.362-0.67-0.549-1.326l-2.451-0.362q-0.174-0.027-0.281-0.167t-0.107-0.315v-2.973q0-0.161 0.107-0.308t0.254-0.174l2.491-0.375q0.188-0.616 0.522-1.232-0.536-0.763-1.433-1.848-0.134-0.161-0.134-0.321 0-0.134 0.121-0.308 0.348-0.482 1.319-1.44t1.266-0.958q0.174 0 0.348 0.134l1.848 1.433q0.589-0.308 1.219-0.509 0.214-1.821 0.388-2.491 0.094-0.375 0.482-0.375h2.973q0.188 0 0.328 0.114t0.154 0.288l0.375 2.464q0.656 0.214 1.205 0.496l1.902-1.433q0.121-0.121 0.321-0.121 0.174 0 0.335 0.134 1.728 1.594 2.21 2.277 0.094 0.107 0.094 0.295 0 0.161-0.107 0.308-0.201 0.281-0.683 0.891t-0.723 0.944q0.348 0.67 0.549 1.313l2.451 0.375q0.174 0.027 0.281 0.167t0.107 0.315z" + }, + "PRINT": { + "section": "Tools", + "title": "Print", + "viewBox": "0 0 22 24", + "path": "M5.143 20.571h12v-3.429h-12v3.429zM5.143 12h12v-5.143h-2.143q-0.536 0-0.911-0.375t-0.375-0.911v-2.143h-8.571v8.571zM20.571 12.857q0-0.348-0.254-0.603t-0.603-0.254-0.603 0.254-0.254 0.603 0.254 0.603 0.603 0.254 0.603-0.254 0.254-0.603zM22.286 12.857v5.571q0 0.174-0.127 0.301t-0.301 0.127h-3v2.143q0 0.536-0.375 0.911t-0.911 0.375h-12.857q-0.536 0-0.911-0.375t-0.375-0.911v-2.143h-3q-0.174 0-0.301-0.127t-0.127-0.301v-5.571q0-1.058 0.757-1.815t1.815-0.757h0.857v-7.286q0-0.536 0.375-0.911t0.911-0.375h9q0.536 0 1.179 0.268t1.018 0.643l2.036 2.036q0.375 0.375 0.643 1.018t0.268 1.179v3.429h0.857q1.058 0 1.815 0.757t0.757 1.815z" + }, + "RELOAD": { + "section": "Tools", + "title": "Reload", + "viewBox": "0 0 16 16", + "path": "M13.901 2.599c-1.463-1.597-3.565-2.599-5.901-2.599-4.418 0-8 3.582-8 8h1.5c0-3.59 2.91-6.5 6.5-6.5 1.922 0 3.649 0.835 4.839 2.161l-2.339 2.339h5.5v-5.5l-2.099 2.099z M14.5 8c0 3.59-2.91 6.5-6.5 6.5-1.922 0-3.649-0.835-4.839-2.161l2.339-2.339h-5.5v5.5l2.099-2.099c1.463 1.597 3.565 2.599 5.901 2.599 4.418 0 8-3.582 8-8h-1.5z" + }, + "SAVE": { + "section": "Tools", + "title": "Save", + "viewBox": "0 0 16 16", + "path": "M14 0h-14v16h16v-14l-2-2zM8 2h2v4h-2v-4zM14 14h-12v-12h1v5h9v-5h1.172l0.828 0.828v11.172z" + }, + "DUPLICATE": { + "section": "Tools", + "title": "Duplicate", + "viewBox": "0 0 16 16", + "path": "M10 4v-4h-7l-3 3v9h6v4h10v-12h-6zM3 1.414v1.586h-1.586l1.586-1.586zM1 11v-7h3v-3h5v3l-3 3v4h-5zM9 5.414v1.586h-1.586l1.586-1.586zM15 15h-8v-7h3v-3h5v10z" + }, + "LOCK": { + "section": "Tools", + "title":"Lock", + "viewBox":"0 0 16 16", + "path": "M12.249 6.5h-0.25v-3c0-1.654-1.346-3-3-3h-2c-1.654 0-3 1.346-3 3v3h-0.25c-0.413 0-0.75 0.338-0.75 0.75v7.5c0 0.412 0.337 0.75 0.75 0.75h8.5c0.412 0 0.75-0.338 0.75-0.75v-7.5c0-0.412-0.338-0.75-0.75-0.75zM5.999 3.5c0-0.551 0.449-1 1-1h2c0.551 0 1 0.449 1 1v3h-4v-3z" + }, + "EDIT": { + "section": "Tools", + "title":"Edit", + "viewBox":"0 0 16 16", + "path": "M13.5 0c1.381 0 2.5 1.119 2.5 2.5 0 0.563-0.186 1.082-0.5 1.5l-1 1-3.5-3.5 1-1c0.418-0.314 0.937-0.5 1.5-0.5zM1 11.5l-1 4.5 4.5-1 9.25-9.25-3.5-3.5-9.25 9.25zM11.181 5.681l-7 7-0.862-0.862 7-7 0.862 0.862z" + }, + "CHECK": { + "section": "Signs", + "title": "Check", + "viewBox": "0 0 24 24", + "path": "M22.379 7.58q0 0.536-0.375 0.911l-11.518 11.518q-0.375 0.375-0.911 0.375t-0.911-0.375l-6.67-6.67q-0.375-0.375-0.375-0.911t0.375-0.911l1.821-1.821q0.375-0.375 0.911-0.375t0.911 0.375l3.938 3.951 8.786-8.799q0.375-0.375 0.911-0.375t0.911 0.375l1.821 1.821q0.375 0.375 0.375 0.911z" + }, + "CROSS": { + "section": "Signs", + "title": "Cross", + "viewBox": "0 0 19 24", + "path": "M17.384 17.705q0 0.536-0.375 0.911l-1.821 1.821q-0.375 0.375-0.911 0.375t-0.911-0.375l-3.938-3.938-3.938 3.938q-0.375 0.375-0.911 0.375t-0.911-0.375l-1.821-1.821q-0.375-0.375-0.375-0.911t0.375-0.911l3.938-3.938-3.938-3.938q-0.375-0.375-0.375-0.911t0.375-0.911l1.821-1.821q0.375-0.375 0.911-0.375t0.911 0.375l3.938 3.938 3.938-3.938q0.375-0.375 0.911-0.375t0.911 0.375l1.821 1.821q0.375 0.375 0.375 0.911t-0.375 0.911l-3.938 3.938 3.938 3.938q0.375 0.375 0.375 0.911z" + }, + "WARNING": { + "section": "Signs", + "title": "Warning", + "viewBox": "0 0 24 24", + "path": "M13.714 18.415v-2.545q0-0.188-0.127-0.315t-0.301-0.127h-2.571q-0.174 0-0.301 0.127t-0.127 0.315v2.545q0 0.188 0.127 0.315t0.301 0.127h2.571q0.174 0 0.301-0.127t0.127-0.315zM13.688 13.406l0.241-6.147q0-0.161-0.134-0.254-0.174-0.147-0.321-0.147h-2.946q-0.147 0-0.321 0.147-0.134 0.094-0.134 0.281l0.228 6.121q0 0.134 0.134 0.221t0.321 0.087h2.478q0.188 0 0.315-0.087t0.141-0.221zM13.5 0.897l10.286 18.857q0.469 0.844-0.027 1.688-0.228 0.388-0.623 0.616t-0.85 0.228h-20.571q-0.455 0-0.85-0.228t-0.623-0.616q-0.496-0.844-0.027-1.688l10.286-18.857q0.228-0.415 0.629-0.656t0.871-0.241 0.871 0.241 0.629 0.656z" + }, + "INFO": { + "section": "Signs", + "title": "Information", + "viewBox": "0 0 6 16", + "path": "M5.717 12.571v1.143q0 0.232-0.17 0.402t-0.402 0.17h-4.571q-0.232 0-0.402-0.17t-0.17-0.402v-1.143q0-0.232 0.17-0.402t0.402-0.17h0.571v-3.429h-0.571q-0.232 0-0.402-0.17t-0.17-0.402v-1.143q0-0.232 0.17-0.402t0.402-0.17h3.429q0.232 0 0.402 0.17t0.17 0.402v5.143h0.571q0.232 0 0.402 0.17t0.17 0.402zM4.574 2.286v1.714q0 0.232-0.17 0.402t-0.402 0.17h-2.286q-0.232 0-0.402-0.17t-0.17-0.402v-1.714q0-0.232 0.17-0.402t0.402-0.17h2.286q0.232 0 0.402 0.17t0.17 0.402z" + }, + "HELP": { + "section": "Signs", + "title": "Help", + "viewBox": "0 0 9 16", + "path": "M5.874 11.214v2.143q0 0.143-0.107 0.25t-0.25 0.107h-2.143q-0.143 0-0.25-0.107t-0.107-0.25v-2.143q0-0.143 0.107-0.25t0.25-0.107h2.143q0.143 0 0.25 0.107t0.107 0.25zM8.696 5.857q0 0.482-0.138 0.902t-0.313 0.683-0.491 0.531-0.513 0.388-0.545 0.317q-0.366 0.205-0.612 0.58t-0.246 0.598q0 0.152-0.107 0.29t-0.25 0.138h-2.143q-0.134 0-0.228-0.165t-0.094-0.335v-0.402q0-0.741 0.58-1.397t1.277-0.969q0.527-0.241 0.75-0.5t0.223-0.679q0-0.375-0.415-0.661t-0.96-0.286q-0.58 0-0.964 0.259-0.313 0.223-0.955 1.027-0.116 0.143-0.277 0.143-0.107 0-0.223-0.071l-1.464-1.116q-0.116-0.089-0.138-0.223t0.049-0.25q1.429-2.375 4.143-2.375 0.714 0 1.438 0.277t1.304 0.741 0.946 1.138 0.366 1.415z" + }, + "ATTENTION": { + "section": "Signs", + "viewBox": "0 0 6 16", + "path": "M4.574 11.714v2q0 0.232-0.17 0.402t-0.402 0.17h-2.286q-0.232 0-0.402-0.17t-0.17-0.402v-2q0-0.232 0.17-0.402t0.402-0.17h2.286q0.232 0 0.402 0.17t0.17 0.402zM4.841 2.286l-0.25 6.857q-0.009 0.232-0.183 0.402t-0.406 0.17h-2.286q-0.232 0-0.406-0.17t-0.183-0.402l-0.25-6.857q-0.009-0.232 0.156-0.402t0.397-0.17h2.857q0.232 0 0.397 0.17t0.156 0.402z" + }, + "PLUS": { + "section": "Signs", + "viewBox": "0 0 13 16", + "path": "M12.575 7.143v1.714q0 0.357-0.25 0.607t-0.607 0.25h-3.714v3.714q0 0.357-0.25 0.607t-0.607 0.25h-1.714q-0.357 0-0.607-0.25t-0.25-0.607v-3.714h-3.714q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h3.714v-3.714q0-0.357 0.25-0.607t0.607-0.25h1.714q0.357 0 0.607 0.25t0.25 0.607v3.714h3.714q0.357 0 0.607 0.25t0.25 0.607z" + }, + "MINUS": { + "section": "Signs", + "viewBox": "0 0 13 16", + "path": "M12.575 7.143v1.714q0 0.357-0.25 0.607t-0.607 0.25h-10.857q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h10.857q0.357 0 0.607 0.25t0.25 0.607z" + }, + "TRASH": { + "section": "Desktop", + "title": "Trash", + "viewBox": "0 0 19 24", + "path": "M6.857 9.857v7.714q0 0.188-0.121 0.308t-0.308 0.121h-0.857q-0.188 0-0.308-0.121t-0.121-0.308v-7.714q0-0.188 0.121-0.308t0.308-0.121h0.857q0.188 0 0.308 0.121t0.121 0.308zM10.286 9.857v7.714q0 0.188-0.121 0.308t-0.308 0.121h-0.857q-0.188 0-0.308-0.121t-0.121-0.308v-7.714q0-0.188 0.121-0.308t0.308-0.121h0.857q0.188 0 0.308 0.121t0.121 0.308zM13.714 9.857v7.714q0 0.188-0.121 0.308t-0.308 0.121h-0.857q-0.188 0-0.308-0.121t-0.121-0.308v-7.714q0-0.188 0.121-0.308t0.308-0.121h0.857q0.188 0 0.308 0.121t0.121 0.308zM15.429 19.554v-12.696h-12v12.696q0 0.295 0.094 0.542t0.194 0.362 0.141 0.114h11.143q0.040 0 0.141-0.114t0.194-0.362 0.094-0.542zM6.429 5.143h6l-0.643-1.567q-0.094-0.121-0.228-0.147h-4.246q-0.134 0.027-0.228 0.147zM18.857 5.571v0.857q0 0.188-0.121 0.308t-0.308 0.121h-1.286v12.696q0 1.112-0.629 1.922t-1.513 0.81h-11.143q-0.884 0-1.513-0.783t-0.629-1.895v-12.75h-1.286q-0.188 0-0.308-0.121t-0.121-0.308v-0.857q0-0.188 0.121-0.308t0.308-0.121h4.138l0.938-2.237q0.201-0.496 0.723-0.844t1.058-0.348h4.286q0.536 0 1.058 0.348t0.723 0.844l0.938 2.237h4.138q0.188 0 0.308 0.121t0.121 0.308z" + }, + "FOLDER": { + "section": "Desktop", + "title": "Folder", + "viewBox": "0 0 22 24", + "path": "M20.573 18.428v-9.429q0-0.536-0.375-0.911t-0.911-0.375h-9.429q-0.536 0-0.911-0.375t-0.375-0.911v-0.857q0-0.536-0.375-0.911t-0.911-0.375h-4.286q-0.536 0-0.911 0.375t-0.375 0.911v12.857q0 0.536 0.375 0.911t0.911 0.375h16.286q0.536 0 0.911-0.375t0.375-0.911zM22.287 9v9.429q0 1.232-0.884 2.116t-2.116 0.884h-16.286q-1.232 0-2.116-0.884t-0.884-2.116v-12.857q0-1.232 0.884-2.116t2.116-0.884h4.286q1.232 0 2.116 0.884t0.884 2.116v0.429h9q1.232 0 2.116 0.884t0.884 2.116z" + }, + "FOLDER.OPEN": { + "section": "Desktop", + "title": "Folder (open)", + "viewBox": "0 0 26 24", + "path": "M23.853 12.469q0-0.469-0.71-0.469h-14.571q-0.536 0-1.145 0.288t-0.958 0.703l-3.938 4.862q-0.241 0.321-0.241 0.536 0 0.469 0.71 0.469h14.571q0.536 0 1.152-0.295t0.951-0.71l3.938-4.862q0.241-0.295 0.241-0.522zM8.571 10.286h10.286v-2.143q0-0.536-0.375-0.911t-0.911-0.375h-7.714q-0.536 0-0.911-0.375t-0.375-0.911v-0.857q0-0.536-0.375-0.911t-0.911-0.375h-4.286q-0.536 0-0.911 0.375t-0.375 0.911v11.424l3.429-4.219q0.589-0.71 1.554-1.172t1.875-0.462zM25.567 12.469q0 0.83-0.616 1.607l-3.951 4.862q-0.576 0.71-1.554 1.172t-1.875 0.462h-14.571q-1.232 0-2.116-0.884t-0.884-2.116v-12.857q0-1.232 0.884-2.116t2.116-0.884h4.286q1.232 0 2.116 0.884t0.884 2.116v0.429h7.286q1.232 0 2.116 0.884t0.884 2.116v2.143h2.571q0.723 0 1.326 0.328t0.897 0.944q0.201 0.429 0.201 0.911z" + }, + "DISPLAY": { + "section": "Desktop", + "viewBox": "0 0 24 24", + "title": "Display", + "path": "M21 15.984v-12h-18v12h18zM21 2.016q0.797 0 1.406 0.586t0.609 1.383v12q0 0.797-0.609 1.406t-1.406 0.609h-6.984v2.016h1.969v1.969h-7.969v-1.969h1.969v-2.016h-6.984q-0.797 0-1.406-0.609t-0.609-1.406v-12q0-0.797 0.609-1.383t1.406-0.586h18z" + }, + "ITEMS.GRID": { + "section": "Desktop", + "viewBox": "0 0 16 16", + "title": "Items (grid)", + "path": "M4.571 11.143v1.714q0 0.357-0.25 0.607t-0.607 0.25h-2.857q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h2.857q0.357 0 0.607 0.25t0.25 0.607zM4.571 6.571v1.714q0 0.357-0.25 0.607t-0.607 0.25h-2.857q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h2.857q0.357 0 0.607 0.25t0.25 0.607zM10.286 11.143v1.714q0 0.357-0.25 0.607t-0.607 0.25h-2.857q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h2.857q0.357 0 0.607 0.25t0.25 0.607zM4.571 2v1.714q0 0.357-0.25 0.607t-0.607 0.25h-2.857q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h2.857q0.357 0 0.607 0.25t0.25 0.607zM10.286 6.571v1.714q0 0.357-0.25 0.607t-0.607 0.25h-2.857q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h2.857q0.357 0 0.607 0.25t0.25 0.607zM16 11.143v1.714q0 0.357-0.25 0.607t-0.607 0.25h-2.857q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h2.857q0.357 0 0.607 0.25t0.25 0.607zM10.286 2v1.714q0 0.357-0.25 0.607t-0.607 0.25h-2.857q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h2.857q0.357 0 0.607 0.25t0.25 0.607zM16 6.571v1.714q0 0.357-0.25 0.607t-0.607 0.25h-2.857q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h2.857q0.357 0 0.607 0.25t0.25 0.607zM16 2v1.714q0 0.357-0.25 0.607t-0.607 0.25h-2.857q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h2.857q0.357 0 0.607 0.25t0.25 0.607z" + }, + "ITEMS.LIST": { + "section": "Desktop", + "viewBox": "0 0 16 16", + "title": "Items (list)", + "path": "M4.571 11.143v1.714q0 0.357-0.25 0.607t-0.607 0.25h-2.857q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h2.857q0.357 0 0.607 0.25t0.25 0.607zM4.571 6.571v1.714q0 0.357-0.25 0.607t-0.607 0.25h-2.857q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h2.857q0.357 0 0.607 0.25t0.25 0.607zM16 11.143v1.714q0 0.357-0.25 0.607t-0.607 0.25h-8.571q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h8.571q0.357 0 0.607 0.25t0.25 0.607zM4.571 2v1.714q0 0.357-0.25 0.607t-0.607 0.25h-2.857q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h2.857q0.357 0 0.607 0.25t0.25 0.607zM16 6.571v1.714q0 0.357-0.25 0.607t-0.607 0.25h-8.571q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h8.571q0.357 0 0.607 0.25t0.25 0.607zM16 2v1.714q0 0.357-0.25 0.607t-0.607 0.25h-8.571q-0.357 0-0.607-0.25t-0.25-0.607v-1.714q0-0.357 0.25-0.607t0.607-0.25h8.571q0.357 0 0.607 0.25t0.25 0.607z" + }, + "HOME": { + "section": "Desktop", + "title": "Home", + "viewBox": "0 0 22 24", + "path": "M18.857 13.286v6.429q0 0.348-0.254 0.603t-0.603 0.254h-5.143v-5.143h-3.429v5.143h-5.143q-0.348 0-0.603-0.254t-0.254-0.603v-6.429q0-0.013 0.007-0.040t0.007-0.040l7.701-6.348 7.701 6.348q0.013 0.027 0.013 0.080zM21.844 12.362l-0.83 0.991q-0.107 0.121-0.281 0.147h-0.040q-0.174 0-0.281-0.094l-9.268-7.728-9.268 7.728q-0.161 0.107-0.321 0.094-0.174-0.027-0.281-0.147l-0.83-0.991q-0.107-0.134-0.094-0.315t0.147-0.288l9.629-8.022q0.429-0.348 1.018-0.348t1.018 0.348l3.268 2.732v-2.612q0-0.188 0.121-0.308t0.308-0.121h2.571q0.188 0 0.308 0.121t0.121 0.308v5.464l2.933 2.438q0.134 0.107 0.147 0.288t-0.094 0.315z" + }, + "SIDEBAR": { + "section": "Desktop", + "title": "Sidebar", + "viewBox": "0 0 20 20", + "path": "M7 3h-5v14h5v-14zM9 3v14h9v-14h-9zM0 3c0-1.1 0.9-2 2-2h16c1.105 0 2 0.895 2 2v0 14c0 1.105-0.895 2-2 2v0h-16c-1.105 0-2-0.895-2-2v0-14zM3 4h3v2h-3v-2zM3 7h3v2h-3v-2zM3 10h3v2h-3v-2z" + }, + "FILE": { + "section": "Desktop", + "title": "File", + "viewBox": "0 0 24 24", + "path": "M19.661 5.089q0.375 0.375 0.643 1.018t0.268 1.179v15.429q0 0.536-0.375 0.911t-0.911 0.375h-18q-0.536 0-0.911-0.375t-0.375-0.911v-21.429q0-0.536 0.375-0.911t0.911-0.375h12q0.536 0 1.179 0.268t1.018 0.643zM13.714 1.821v5.036h5.036q-0.134-0.388-0.295-0.549l-4.192-4.192q-0.161-0.161-0.549-0.295zM18.857 22.286v-13.714h-5.571q-0.536 0-0.911-0.375t-0.375-0.911v-5.571h-10.286v20.571h17.143z" + }, + "CIRC.PLUS": { + "section": "Buttons", + "title": "Add", + "viewBox": "0 0 24 24", + "path": "M17.999 12.857v-1.714q0-0.348-0.254-0.603t-0.603-0.254h-3.429v-3.429q0-0.348-0.254-0.603t-0.603-0.254h-1.714q-0.348 0-0.603 0.254t-0.254 0.603v3.429h-3.429q-0.348 0-0.603 0.254t-0.254 0.603v1.714q0 0.348 0.254 0.603t0.603 0.254h3.429v3.429q0 0.348 0.254 0.603t0.603 0.254h1.714q0.348 0 0.603-0.254t0.254-0.603v-3.429h3.429q0.348 0 0.603-0.254t0.254-0.603zM22.285 12q0 2.799-1.379 5.163t-3.743 3.743-5.163 1.379-5.163-1.379-3.743-3.743-1.379-5.163 1.379-5.163 3.743-3.743 5.163-1.379 5.163 1.379 3.743 3.743 1.379 5.163z" + }, + "CIRC.MINUS": { + "section": "Buttons", + "title": "Remove", + "viewBox": "0 0 24 24", + "path": "M17.999 12.857v-1.714q0-0.348-0.254-0.603t-0.603-0.254h-10.286q-0.348 0-0.603 0.254t-0.254 0.603v1.714q0 0.348 0.254 0.603t0.603 0.254h10.286q0.348 0 0.603-0.254t0.254-0.603zM22.285 12q0 2.799-1.379 5.163t-3.743 3.743-5.163 1.379-5.163-1.379-3.743-3.743-1.379-5.163 1.379-5.163 3.743-3.743 5.163-1.379 5.163 1.379 3.743 3.743 1.379 5.163z" + }, + "CIRC.CLOSE": { + "section": "Buttons", + "title": "Close", + "viewBox": "0 0 24 24", + "path": "M8.973 17.102q0.348 0 0.603-0.254l2.424-2.424 2.424 2.424q0.254 0.254 0.603 0.254 0.362 0 0.616-0.254l1.205-1.205q0.254-0.254 0.254-0.616 0-0.348-0.254-0.603l-2.424-2.424 2.424-2.424q0.254-0.254 0.254-0.603 0-0.362-0.254-0.616l-1.205-1.205q-0.254-0.254-0.616-0.254-0.348 0-0.603 0.254l-2.424 2.424-2.424-2.424q-0.254-0.254-0.603-0.254-0.362 0-0.616 0.254l-1.205 1.205q-0.254 0.254-0.254 0.616 0 0.348 0.254 0.603l2.424 2.424-2.424 2.424q-0.254 0.254-0.254 0.603 0 0.362 0.254 0.616l1.205 1.205q0.254 0.254 0.616 0.254zM12 22.285q-2.799 0-5.163-1.379t-3.743-3.743-1.379-5.163 1.379-5.163 3.743-3.743 5.163-1.379 5.163 1.379 3.743 3.743 1.379 5.163-1.379 5.163-3.743 3.743-5.163 1.379z" + }, + "CIRC.CHECK": { + "section": "Buttons", + "title": "Check", + "viewBox": "0 0 24 24", + "path": "M18.91 9.83q0-0.375-0.241-0.616l-1.219-1.205q-0.254-0.254-0.603-0.254t-0.603 0.254l-5.464 5.451-3.027-3.027q-0.254-0.254-0.603-0.254t-0.603 0.254l-1.219 1.205q-0.241 0.241-0.241 0.616 0 0.362 0.241 0.603l4.848 4.848q0.254 0.254 0.603 0.254 0.362 0 0.616-0.254l7.272-7.272q0.241-0.241 0.241-0.603zM22.285 12q0 2.799-1.379 5.163t-3.743 3.743-5.163 1.379-5.163-1.379-3.743-3.743-1.379-5.163 1.379-5.163 3.743-3.743 5.163-1.379 5.163 1.379 3.743 3.743 1.379 5.163z" + }, + "CIRC.QUESTION": { + "section": "Buttons", + "title": "Check", + "viewBox": "0 0 24 24", + "path": "M13.714 18.429v-2.571q0-0.188-0.121-0.308t-0.308-0.121h-2.571q-0.188 0-0.308 0.121t-0.121 0.308v2.571q0 0.188 0.121 0.308t0.308 0.121h2.571q0.188 0 0.308-0.121t0.121-0.308zM17.142 9.429q0-1.179-0.743-2.183t-1.855-1.554-2.277-0.549q-3.254 0-4.969 2.853-0.201 0.321 0.107 0.563l1.768 1.339q0.094 0.080 0.254 0.080 0.214 0 0.335-0.161 0.71-0.911 1.152-1.232 0.455-0.321 1.152-0.321 0.643 0 1.145 0.348t0.502 0.79q0 0.509-0.268 0.817t-0.911 0.603q-0.844 0.375-1.547 1.158t-0.703 1.681v0.482q0 0.188 0.121 0.308t0.308 0.121h2.571q0.188 0 0.308-0.121t0.121-0.308q0-0.254 0.288-0.663t0.73-0.663q0.429-0.241 0.656-0.382t0.616-0.469 0.596-0.643 0.375-0.81 0.167-1.085zM22.285 12q0 2.799-1.379 5.163t-3.743 3.743-5.163 1.379-5.163-1.379-3.743-3.743-1.379-5.163 1.379-5.163 3.743-3.743 5.163-1.379 5.163 1.379 3.743 3.743 1.379 5.163z" + }, + "CIRC.INFO": { + "section": "Buttons", + "title": "Info", + "viewBox": "0 0 24 24", + "path": "M15.428 18.429v-2.143q0-0.188-0.121-0.308t-0.308-0.121h-1.286v-6.857q0-0.188-0.121-0.308t-0.308-0.121h-4.286q-0.188 0-0.308 0.121t-0.121 0.308v2.143q0 0.188 0.121 0.308t0.308 0.121h1.286v4.286h-1.286q-0.188 0-0.308 0.121t-0.121 0.308v2.143q0 0.188 0.121 0.308t0.308 0.121h6q0.188 0 0.308-0.121t0.121-0.308zM13.714 6.429v-2.143q0-0.188-0.121-0.308t-0.308-0.121h-2.571q-0.188 0-0.308 0.121t-0.121 0.308v2.143q0 0.188 0.121 0.308t0.308 0.121h2.571q0.188 0 0.308-0.121t0.121-0.308zM22.285 12q0 2.799-1.379 5.163t-3.743 3.743-5.163 1.379-5.163-1.379-3.743-3.743-1.379-5.163 1.379-5.163 3.743-3.743 5.163-1.379 5.163 1.379 3.743 3.743 1.379 5.163z" + }, + "SWITCH.OFF": { + "section": "Buttons", + "title": "Off", + "viewBox": "0 0 32 28", + "path": "M18 14c0-4.406-3.594-8-8-8s-8 3.594-8 8 3.594 8 8 8 8-3.594 8-8zM30 14c0-4.406-3.594-8-8-8h-6.031c2.438 1.828 4.031 4.734 4.031 8s-1.594 6.172-4.031 8h6.031c4.406 0 8-3.594 8-8zM32 14c0 5.516-4.484 10-10 10h-12c-5.516 0-10-4.484-10-10s4.484-10 10-10h12c5.516 0 10 4.484 10 10z" + }, + "SWITCH.ON": { + "section": "Buttons", + "title": "On", + "viewBox": "0 0 32 28", + "path": "M0 14c0-5.516 4.484-10 10-10h12c5.516 0 10 4.484 10 10s-4.484 10-10 10h-12c-5.516 0-10-4.484-10-10zM22 22c4.406 0 8-3.594 8-8s-3.594-8-8-8-8 3.594-8 8 3.594 8 8 8z" + }, + "TRIANGLE.LEFT": { + "section": "Arrows", + "title": "Left", + "viewBox": "0 0 16 16", + "path": "M13 2l-10 6 10 6z" + }, + "TRIANGLE.UP": { + "section": "Arrows", + "title": "Up", + "viewBox": "0 0 16 16", + "path": "M2 13l6-10 6 10z" + }, + "TRIANGLE.RIGHT": { + "section": "Arrows", + "title": "Right", + "viewBox": "0 0 16 16", + "path": "M3 2l10 6-10 6z" + }, + "TRIANGLE.DOWN": { + "section": "Arrows", + "title": "Down", + "viewBox": "0 0 16 16", + "path": "M14 3l-6 10-6-10z" + }, + "ANGLE.LEFT": { + "section": "Arrows", + "title": "Left", + "viewBox": "0 0 11 16", + "path": "M10.166 3.259l-4.741 4.741 4.741 4.741q0.17 0.17 0.17 0.402t-0.17 0.402l-1.482 1.482q-0.17 0.17-0.402 0.17t-0.402-0.17l-6.625-6.625q-0.17-0.17-0.17-0.402t0.17-0.402l6.625-6.625q0.17-0.17 0.402-0.17t0.402 0.17l1.482 1.482q0.17 0.17 0.17 0.402t-0.17 0.402z" + }, + "ANGLE.RIGHT": { + "section": "Arrows", + "title": "Right", + "viewBox": "0 0 11 16", + "path": "M10.166 8.402l-6.625 6.625q-0.17 0.17-0.402 0.17t-0.402-0.17l-1.482-1.482q-0.17-0.17-0.17-0.402t0.17-0.402l4.741-4.741-4.741-4.741q-0.17-0.17-0.17-0.402t0.17-0.402l1.482-1.482q0.17-0.17 0.402-0.17t0.402 0.17l6.625 6.625q0.17 0.17 0.17 0.402t-0.17 0.402z" + }, + "ANGLE.UP": { + "section": "Arrows", + "title": "Up", + "viewBox": "0 0 16 16", + "path": "M15.027 10.978l-1.482 1.473q-0.17 0.17-0.402 0.17t-0.402-0.17l-4.741-4.741-4.741 4.741q-0.17 0.17-0.402 0.17t-0.402-0.17l-1.482-1.473q-0.17-0.17-0.17-0.406t0.17-0.406l6.625-6.616q0.17-0.17 0.402-0.17t0.402 0.17l6.625 6.616q0.17 0.17 0.17 0.406t-0.17 0.406z" + }, + "ANGLE.DOWN": { + "section": "Arrows", + "title": "Down", + "viewBox": "0 0 16 16", + "path": "M15.027 5.835l-6.625 6.616q-0.17 0.17-0.402 0.17t-0.402-0.17l-6.625-6.616q-0.17-0.17-0.17-0.406t0.17-0.406l1.482-1.473q0.17-0.17 0.402-0.17t0.402 0.17l4.741 4.741 4.741-4.741q0.17-0.17 0.402-0.17t0.402 0.17l1.482 1.473q0.17 0.17 0.17 0.406t-0.17 0.406z" + }, + "DIR.VERTICAL": { + "section": "Arrows", + "title": "Vertical", + "viewBox": "0 0 7 16", + "path": "M6.287 2.857q0 0.232-0.17 0.402t-0.402 0.17h-1.143v9.143h1.143q0.232 0 0.402 0.17t0.17 0.402-0.17 0.402l-2.286 2.286q-0.17 0.17-0.402 0.17t-0.402-0.17l-2.286-2.286q-0.17-0.17-0.17-0.402t0.17-0.402 0.402-0.17h1.143v-9.143h-1.143q-0.232 0-0.402-0.17t-0.17-0.402 0.17-0.402l2.286-2.286q0.17-0.17 0.402-0.17t0.402 0.17l2.286 2.286q0.17 0.17 0.17 0.402z" + }, + "DIR.HORIZONTAL": { + "section": "Arrows", + "title": "Horizontal", + "viewBox": "0 0 16 16", + "path": "M16 8q0 0.232-0.17 0.402l-2.286 2.286q-0.17 0.17-0.402 0.17t-0.402-0.17-0.17-0.402v-1.143h-9.143v1.143q0 0.232-0.17 0.402t-0.402 0.17-0.402-0.17l-2.286-2.286q-0.17-0.17-0.17-0.402t0.17-0.402l2.286-2.286q0.17-0.17 0.402-0.17t0.402 0.17 0.17 0.402v1.143h9.143v-1.143q0-0.232 0.17-0.402t0.402-0.17 0.402 0.17l2.286 2.286q0.17 0.17 0.17 0.402z" + }, + "DIR.EXPAND": { + "section": "Arrows", + "title": "Expand", + "viewBox": "0 0 16 16", + "path": "M16 0h-6.5l2.5 2.5-3 3 1.5 1.5 3-3 2.5 2.5z M16 16v-6.5l-2.5 2.5-3-3-1.5 1.5 3 3-2.5 2.5z M0 16h6.5l-2.5-2.5 3-3-1.5-1.5-3 3-2.5-2.5z M0 0v6.5l2.5-2.5 3 3 1.5-1.5-3-3 2.5-2.5z" + }, + "MEDIA.PREV": { + "section": "Media", + "title": "Previous", + "viewBox": "0 0 14 24", + "path": "M13.112 1.888q0.254-0.254 0.429-0.174t0.174 0.429v19.714q0 0.348-0.174 0.429t-0.429-0.174l-9.509-9.509q-0.121-0.121-0.174-0.254v9.080q0 0.348-0.254 0.603t-0.603 0.254h-1.714q-0.348 0-0.603-0.254t-0.254-0.603v-18.857q0-0.348 0.254-0.603t0.603-0.254h1.714q0.348 0 0.603 0.254t0.254 0.603v9.080q0.054-0.147 0.174-0.254z" + }, + "MEDIA.NEXT": { + "section": "Media", + "title": "Next", + "viewBox": "0 0 14 24", + "path": "M0.603 22.112q-0.254 0.254-0.429 0.174t-0.174-0.429v-19.714q0-0.348 0.174-0.429t0.429 0.174l9.509 9.509q0.107 0.107 0.174 0.254v-9.080q0-0.348 0.254-0.603t0.603-0.254h1.714q0.348 0 0.603 0.254t0.254 0.603v18.857q0 0.348-0.254 0.603t-0.603 0.254h-1.714q-0.348 0-0.603-0.254t-0.254-0.603v-9.080q-0.067 0.134-0.174 0.254z" + }, + "MEDIA.PLAY": { + "section": "Media", + "viewBox": "0 0 19 24", + "path": "M18.547 12.415l-17.786 9.884q-0.308 0.174-0.529 0.040t-0.221-0.482v-19.714q0-0.348 0.221-0.482t0.529 0.040l17.786 9.884q0.308 0.174 0.308 0.415t-0.308 0.415z" + }, + "MEDIA.PAUSE": { + "section": "Media", + "viewBox": "0 0 24 24", + "path": "M20.571 2.571v18.857q0 0.348-0.254 0.603t-0.603 0.254h-6.857q-0.348 0-0.603-0.254t-0.254-0.603v-18.857q0-0.348 0.254-0.603t0.603-0.254h6.857q0.348 0 0.603 0.254t0.254 0.603zM8.571 2.571v18.857q0 0.348-0.254 0.603t-0.603 0.254h-6.857q-0.348 0-0.603-0.254t-0.254-0.603v-18.857q0-0.348 0.254-0.603t0.603-0.254h6.857q0.348 0 0.603 0.254t0.254 0.603z" + }, + "MEDIA.STOP": { + "section": "Media", + "viewBox": "0 0 24 24", + "path": "M20.571 2.571v18.857q0 0.348-0.254 0.603t-0.603 0.254h-18.857q-0.348 0-0.603-0.254t-0.254-0.603v-18.857q0-0.348 0.254-0.603t0.603-0.254h18.857q0.348 0 0.603 0.254t0.254 0.603z" + }, + "MEDIA.EJECT": { + "section": "Media", + "viewBox": "0 0 21 24", + "path": "M0.188 13.112l9.509-9.509q0.254-0.254 0.603-0.254t0.603 0.254l9.509 9.509q0.254 0.254 0.174 0.429t-0.429 0.174h-19.714q-0.348 0-0.429-0.174t0.174-0.429zM19.728 20.571h-18.857q-0.348 0-0.603-0.254t-0.254-0.603v-3.429q0-0.348 0.254-0.603t0.603-0.254h18.857q0.348 0 0.603 0.254t0.254 0.603v3.429q0 0.348-0.254 0.603t-0.603 0.254z" + }, + "COMPONENT": { + "section": "Software", + "title": "Component", + "viewBox": "0 0 16 16", + "path": "M8 14.545l5.714-3.116v-5.679l-5.714 2.080v6.714zM7.429 6.821l6.232-2.268-6.232-2.268-6.232 2.268zM14.857 4.571v6.857q0 0.313-0.161 0.58t-0.438 0.42l-6.286 3.429q-0.25 0.143-0.545 0.143t-0.545-0.143l-6.286-3.429q-0.277-0.152-0.438-0.42t-0.161-0.58v-6.857q0-0.357 0.205-0.652t0.545-0.42l6.286-2.286q0.196-0.071 0.393-0.071t0.393 0.071l6.286 2.286q0.339 0.125 0.545 0.42t0.205 0.652z" + }, + "PACKAGE": { + "section": "Software", + "title": "Package", + "viewBox": "0 0 21 16", + "path": "M5.714 14.571l3.429-1.714v-2.804l-3.429 1.464v3.054zM5.143 10.518l3.607-1.545-3.607-1.545-3.607 1.545zM14.857 14.571l3.429-1.714v-2.804l-3.429 1.464v3.054zM14.286 10.518l3.607-1.545-3.607-1.545-3.607 1.545zM10.286 7.902l3.429-1.473v-2.375l-3.429 1.464v2.384zM9.714 4.518l3.938-1.688-3.938-1.688-3.938 1.688zM19.429 9.143v3.714q0 0.321-0.17 0.598t-0.464 0.42l-4 2q-0.223 0.125-0.509 0.125t-0.509-0.125l-4-2q-0.045-0.018-0.063-0.036-0.018 0.018-0.063 0.036l-4 2q-0.223 0.125-0.509 0.125t-0.509-0.125l-4-2q-0.295-0.143-0.464-0.42t-0.17-0.598v-3.714q0-0.339 0.192-0.625t0.504-0.429l3.875-1.661v-3.571q0-0.339 0.192-0.625t0.504-0.429l4-1.714q0.205-0.089 0.446-0.089t0.446 0.089l4 1.714q0.313 0.143 0.504 0.429t0.192 0.625v3.571l3.875 1.661q0.321 0.143 0.509 0.429t0.188 0.625z" + } + +} diff --git a/Ivette/src/dome/src/renderer/controls/labels.css b/Ivette/src/dome/src/renderer/controls/labels.css new file mode 100644 index 0000000000000000000000000000000000000000..e7417b8bd757c78768630264189d11b2c217c203 --- /dev/null +++ b/Ivette/src/dome/src/renderer/controls/labels.css @@ -0,0 +1,18 @@ +/* -------------------------------------------------------------------------- */ +/* --- Styling Labels --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xLabel { + padding: 2px ; + margin: 2px 4px ; +} + +.dome-xLabel .dome-xIcon { + margin-right: 4px ; +} + +.dome-xLabel.dome-text-descr { + overflow: auto ; +} + +/* -------------------------------------------------------------------------- */ diff --git a/Ivette/src/dome/src/renderer/controls/labels.js b/Ivette/src/dome/src/renderer/controls/labels.js new file mode 100644 index 0000000000000000000000000000000000000000..e407ce76c54e36e82f78e36529de2ae3fa601fc7 --- /dev/null +++ b/Ivette/src/dome/src/renderer/controls/labels.js @@ -0,0 +1,97 @@ +// -------------------------------------------------------------------------- +// --- Labels +// -------------------------------------------------------------------------- + +/** @module dome/controls/labels */ + +import React from 'react' ; +import labels from './labels.css' ; +import { Icon } from './icons' ; + +// -------------------------------------------------------------------------- +// --- Generic Label +// -------------------------------------------------------------------------- + +const addClass = (a,b) => b ? a + ' ' + b : a ; + +const makeLabel = (classes,props) => ( + <label className={addClass(classes,props.className)} + title={props.title} + style={props.style} > + {props.icon && <Icon title={props.title} id={props.icon}/>} + {props.label} + {props.text} + {props.children} + </label> +); + +// -------------------------------------------------------------------------- +// --- CSS Classes +// -------------------------------------------------------------------------- + +const LABEL = "dome-xLabel dome-text-label" ; +const TITLE = "dome-xLabel dome-text-title" ; +const DESCR = "dome-xLabel dome-text-descr" ; +const TDATA = "dome-xLabel dome-text-data" ; +const TCODE = "dome-xLabel dome-text-code" ; + +// -------------------------------------------------------------------------- +// --- Components +// -------------------------------------------------------------------------- + +/** + @class + @summary Component labels. + @property {string} [label] - Textual content (prepend to children components, if any) + @property {string} [icon] - Label icon (optional, on left side) + @property {string} [title] - Label tooltip (optional) + @property {string} [className] - Additional class + @property {object} [style] - Additional CSS style +*/ +export const Label = (props) => makeLabel(LABEL,props); + +/** + @class + @summary Title and headings. + @property {string} [label] - Textual content (prepend to children components, if any) + @property {string} [icon] - Label icon (optional, on left side) + @property {string} [title] - Label tooltip (optional) + @property {string} [className] - Additional class + @property {object} [style] - Additional CSS style +*/ +export const Title = (props) => makeLabel(TITLE,props); + +/** + @class + @summary Description, textbook content. + @property {string} [label] - Textual content (prepend to children components, if any) + @property {string} [icon] - Label icon (optional, on left side) + @property {string} [title] - Label tooltip (optional) + @property {string} [className] - Additional class + @property {object} [style] - Additional CSS style +*/ +export const Descr = (props) => makeLabel(DESCR,props); + +/** + @class + @summary Selectable textual information. + @property {string} [label] - Textual content (prepend to children components, if any) + @property {string} [icon] - Label icon (optional, on left side) + @property {string} [title] - Label tooltip (optional) + @property {string} [className] - Additional class + @property {object} [style] - Additional CSS style +*/ +export const Data = (props) => makeLabel(TDATA,props); + +/** + @class + @summary Selectable source-code content. + @property {string} [text] - Textual content (prepend to children components, if any) + @property {string} [icon] - Label icon (optional, on left side) + @property {string} [title] - Label tooltip (optional) + @property {string} [className] - Additional class + @property {object} [style] - Additional CSS style +*/ +export const Code = (props) => makeLabel(TCODE,props); + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/dialogs.js b/Ivette/src/dome/src/renderer/dialogs.js new file mode 100644 index 0000000000000000000000000000000000000000..92f5416323cb2bc9d8c3ebd7219db61ca5519da4 --- /dev/null +++ b/Ivette/src/dome/src/renderer/dialogs.js @@ -0,0 +1,318 @@ +/** + @module dome/dialogs + @description + Various kind of (modal) dialogs attached to the main application window. + */ + +import { remote } from 'electron' ; +import System from 'dome/system' ; + +// -------------------------------------------------------------------------- +// --- Message Box +// -------------------------------------------------------------------------- + +const defaultItems = [ + { value:undefined }, + { value:true, label:'Ok' } +]; + +const valueLabel = (v) => { + switch(v) { + case undefined: return 'Cancel' ; + case true: return 'Ok' ; + case false: return 'No' ; + default: return ''+v ; + } +}; + +const itemLabel = ({value,label}) => label || valueLabel(value) ; +const isDefault = ({value,label}) => value===true || label==='Ok' || label==='Yes' ; +const isCancel = ({value,label}) => !value || label==='Cancel' || label==='No' ; + +/** + @summary Show a configurable message box. + @parameter {object} options - configuration (see above) + @return {Promise} the selected option (see above) + @description +The available fields and options for configuring the dialog are: + +| Options | Type | Description | +|:--------|:----:|:------------| +| `kind` | `'none','info','error','warning'` | Icon of the message box | +| `title` | `string` (_opt._) | Heading of message box | +| `message` | `string` | Message text | +| `buttons` | `button[]` (_opt._) | Dialog buttons | +| `defaultValue` | (any) (_opt._) | Value of the default button | +| `cancelValue` | (any) (_opt._) | Value of the cancel key | + +The dialog buttons are specified by objects with the following fields: + +| Button Field | Type | Description | +|:-------------|:----:|:------------| +| `label` | `string` | Button label | +| `value` | (any) | Button identifier (items only) | + +The returned promise object is never rejected, and is asynchronously +resolved into: +- the cancel value if the cancel key is pressed, +- the default value if the enter key is pressed, +- or the value of the clicked button otherwised. + +The default buttons are `"Ok"` and `"Cancel"` associated to values `true` and +`undefined`, which are also associated to the enter and cancel keys. +Unless specified, the default value is associated with the first button +with 'true' value or 'Ok' or 'Yes' label, +and the cancel value is the first button with a falsy value or 'Cancel' +or 'No' label. +*/ +export function showMessageBox( options ) +{ + const { + kind, + title, + message, + defaultValue, + cancelValue, + buttons = defaultItems + } = options ; + + const labels = buttons.map(itemLabel); + let defaultId = + defaultValue === undefined + ? buttons.findIndex(isDefault) + : buttons.findIndex((a) => a.value === defaultValue); + let cancelId = + cancelValue === undefined + ? buttons.findIndex(isCancel) + : buttons.findIndex((a) => a.value === cancelValue); + + if (cancelId === defaultId) cancelId = -1; + + return remote.dialog.showMessageBox( + remote.getCurrentWindow(), + { + type:kind, + message: message && title, + detail: message || title, + defaultId, cancelId, buttons: labels + } + ).then((result) => { + let itemIndex = result ? result.response : -1 ; + return itemIndex ? buttons[itemIndex].value : cancelValue ; + }); +} + +// -------------------------------------------------------------------------- +// --- openFile dialog +// -------------------------------------------------------------------------- + +import filepath from 'path' ; +const defaultPath = (path) => filepath.extname(path) ? filepath.dirname(path) : path ; + +/** + @summary Show a dialog for opening file. + @parameter {object} options - configuration (see above) + @return {Promise} the selected file (see above) + @description +The available fields and options for configuring the dialog are: + +| Options | Type | Description | +|:--------|:----:|:------------| +| `message` | `string` (_opt._) | Prompt message | +| `label` | `string` (_opt._) | Open button label | +| `path` | `filepath` (_opt._) | Initially selected path | +| `hidden` | `boolean` (_opt._) | Show hidden files (not by default) | +| `filters` | `filter[]` (_opt._) | File filters (all files by default) | + +The file filters are object with the following fields: + +| Filter Field | Type | Description | +|:-------------|:----:|:------------| +| `name` | `string` | Filter name | +| `extensions` | `string[]` | Allowed file extensions, _without_ dots («.») | + +A file filter with `extensions:["*"]` would accept any file extension. + +The returned promise object will be asynchronously: +- either _resolved_ with `undefined` if no file has been selected, +- or _resolved_ with the selected path + +The promise is never rejected. + +*/ +export function showOpenFile( options ) +{ + const { message, label, path, hidden, filters } = options ; + const properties = [ 'openFile' ]; + if (hidden) properties.push('showHiddenFiles'); + + return remote.dialog.showOpenDialog( + remote.getCurrentWindow(), + { + message, buttonLabel: label, + defaultPath: path && defaultPath(path), + properties, filters + } + ).then(result => { + if (!result.canceled && result.filePaths && result.filePaths.length > 0) + return result.filePaths[0] ; + else + return undefined ; + }); +} + +/** + @summary Show a dialog for opening file. + @parameter {object} options - configuration (see above) + @return {Promise} the selected file(s) (see above) + @description +The available fields and options for configuring the dialog are: + +| Options | Type | Description | +|:--------|:----:|:------------| +| `message` | `string` (_opt._) | Prompt message | +| `label` | `string` (_opt._) | Open button label | +| `path` | `filepath` (_opt._) | Initially selected path | +| `hidden` | `boolean` (_opt._) | Show hidden files (not by default) | +| `filters` | `filter[]` (_opt._) | File filters (all files by default) | + +The file filters are object with the following fields: + +| Filter Field | Type | Description | +|:-------------|:----:|:------------| +| `name` | `string` | Filter name | +| `extensions` | `string[]` | Allowed file extensions, _without_ dots («.») | + +A file filter with `extensions:["*"]` would accept any file extension. + +The returned promise object will be asynchronously: +- either _resolved_ with `undefined` if no file has been selected, +- or _resolved_ with the selected paths + +The promise is never rejected. + +*/ +export function showOpenFiles( options ) +{ + const { message, label, path, hidden, filters } = options ; + const properties = [ 'openFile', 'multiSelections' ]; + if (hidden) properties.push('showHiddenFiles'); + + return remote.dialog.showOpenDialog( + remote.getCurrentWindow(), + { + message, buttonLabel: label, + defaultPath: path && defaultPath(path), + properties, filters + } + ).then(result => { + if (!result.canceled && result.filePaths && result.filePaths.length > 0) + return result.filePaths ; + else + return undefined ; + }); +} + + +// -------------------------------------------------------------------------- +// --- saveFile dialog +// -------------------------------------------------------------------------- + +/** + @summary Show a dialog for saving file. + @parameter {object} options - configuration (see above) + @return {Promise} the selected path (see above) + @description +The available fields and options for configuring the dialog are: + +| Options | Type | Description | +|:--------|:----:|:------------| +| `message` | `string` (_opt._) | Prompt message | +| `label` | `string` (_opt._) | Save button label | +| `path` | `filepath` (_opt._) | Initially selected path | +| `filters` | `filter[]` (_opt._) | Cf. `openFileDialog` | + +The returned promise object will be asynchronously: +- either _resolved_ with `undefined` if no file has been selected, +- or _resolved_ with the selected (single) path. + +The promise is never rejected. + +*/ +export function showSaveFile( options ) +{ + const { message, label, path, filters } = options ; + + return remote.dialog.showSaveDialog( + remote.getCurrentWindow(), + { + message, buttonLabel: label, + defaultPath: path, + filters + } + ); +} + +// -------------------------------------------------------------------------- +// --- openDir dialog +// -------------------------------------------------------------------------- + +/** + @summary Show a dialog for selecting directories. + @parameter {object} options - configuration (see above) + @return {Promise} the selected directories (see above) + @description +The available fields and options for configuring the dialog are: + +| Options | Type | Description | +|:--------|:----:|:------------| +| `message` | `string` (_opt._) | Prompt message | +| `label` | `string` (_opt._) | Open button label | +| `path` | `filepath` (_opt._) | Initially selected path | +| `hidden` | `boolean` (_opt._) | Show hidden files (not by default) | + +The returned promise object will be asynchronously: +- either _resolved_ with `undefined` if no file has been selected, +- or _resolved_ with the selected path + +*/ +export function showOpenDir( options ) +{ + const { message, label, path, hidden } = options ; + const properties = [ 'openDirectory' ]; + if (hidden) properties.push('showHiddenFiles'); + + switch(System.platform) { + case 'macos': properties.push( 'createDirectory' ); break; + case 'windows': properties.push( 'promptToCreate' ); break; + } + + return remote.dialog.showOpenDialog( + remote.getCurrentWindow(), + { + message, + buttonLabel: label, + defaultPath: path, + properties + } + ).then(result => { + if (!result.canceled && result.filePaths && result.filePaths.length > 0) + return result.filePaths[0] ; + else + return undefined ; + }); +} + +// -------------------------------------------------------------------------- +// --- Export +// -------------------------------------------------------------------------- + +export default { + showMessageBox, + showOpenFile, + showOpenFiles, + showSaveFile, + showOpenDir +} ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/dnd.js b/Ivette/src/dome/src/renderer/dnd.js new file mode 100644 index 0000000000000000000000000000000000000000..89829fbb5a3c86d6d251713c6ead917d2b96d503 --- /dev/null +++ b/Ivette/src/dome/src/renderer/dnd.js @@ -0,0 +1,860 @@ +/** + @module dome/dnd + @summary Drag & Drop Features. + @description + +## D&D Sequences + +A Drag & Drop sequence is monitored by a D&D controller. +Drag Sources initiates the a D&D sequence, and the D&D controller will then +notify the Drop Target when they are dragged over. + +More precisely, the D&D controller is notified with all events of any D&D sequence. +Drag sources are notified will all events of the D&D sequences they have initiated. +Drop targets are only notified when they are actually participating into some D&D sequence. +For instance, when the dragged item directly moves from one target into another one, both +targets will be notified, but not the others. + + +## Dragging Events + +Many dragging events are triggered during a D&D sequence. +All event listeners will be notified with a single argument, +which is a `Dragging` object with the following properties: + - `move`: the kind of move (see below); + - `meta`: a boolean indicating whether Ctrl, Alt or Meta key is pressed during the move; + - `held`: a boolean indicating whether the mouse is holding over position; + - `sourceClientRect`: the position of the drag source element; + - `targetClientRect`: the position of the drop target element; + - `deltaX`, `deltaY`: the current offset position of the dragged element, +relative to its _initial_ position; + - `clientX`, `clientY`: the current client position of the _cursor_, as obtained from the dragging event; + - `position`: the current position from React-Draggable API (see DragSource documentation). + +All coordinates are provided in the window coordinate system, +as returned by the `getBoundingClientRect` DOM method. + + +## Dragging State + +During the entire sequence, the D&D controller is responsible for managing a shared +state among source and targets. +The drag source and each drop targets may update the shared state when receiving +events, and will be re-rendered in turn when necessary. + +This design eases the separation of concern: each participant in the D&D +sequence is only responsible with its own rendering, while synchronizing between the +participants is ensured through the global state. + + +## Kind of Moves + +During a D&D sequence, different kind of events can be triggered. +They can be distinguished with the `move` property of the dragging events, +as follows: + - `'START'`: D&D sequence initiated; + - `'STOP'`: D&D sequence finished without drop target; + - `'DROP'`: D&D sequence finished over some drop target; + - `'DRAG'`: the source is dragged over some drop target; + - `'HOLD'`: the source is holding the position for a while; + - `'MOVE'`: the source is moving again after holding for a while ; + - `'ENTER'`: the source is entering a target from _no_ other target; + - `'LEAVE'`: the source is leaving a target into _no_ other target; + - `'SWITCH'`: the source is leaving a target into another target. + +Notice that in kind of a `'SWITCH'` event, the leaved target will receive a `'LEAVE'` event +and the entered target will receive an `'ENTER'` event. + + +## Event Callbacks + +D&D controllers, drag sources and drop targets can listen to +dragging events _via_ various callbacks. + +Each callback has signature `(Dragging) => void` and is sensible to +specific kinds of events, as described below: + - `onDnd()`: all kind of events; + - `onStart()`: `START` events; + - `onEnter()`: `ENTER` and `SWITCH` events; + - `onLeave()`: `LEAVE` and `SWITCH` events; + - `onDrag()`: `DRAG` and `MOVE` events; + - `onHold()`: `HOLD` events; + - `onMove()`: `MOVE` events; + - `onDrop()`: `DROP` events; + - `onStop()`: `STOP` events; + - `onUpdate()`: only for D&D controllers, see below. + +In case of a `SWITCH` event, the `onLeave` listener is called first, +then the `onEnter` listener. This is only relevant for the D&D controller +and the drag source, since drop targets will receive either `ENTER` or `LEAVE` events. + +The same `Dragging` object is shared across all the event listeners, but +not among different drag source and drop targets. For each source or target +participating into the event, the `onDnd` listener is called first, +then the more specific ones, when defined. Hence, you can modify the `Dragging` +object during the process of `onDnd` and safely propagate those modifications accross +all listeners. + +Inside a D&D sequence, the leaved targets are notified first, +then the source and the target, and finally the D&D controller. +This allow you to maintain the D&D state in sync with the different participants. + +Additionally, the D&D controller might be equiped with +an `onUpdate()` handler, which is responsible for listening only to state update events. +This event handler will receive the current D&D state in argument, with the cumulated +updates from all participants merged in. + +*/ + +import React from 'react' ; +import Draggable, { DraggableCore } from 'react-draggable'; +import _ from 'lodash' ; + +const HOLD_TIME = 100 ; /* time in ms */ +const HOLD_FIRE = 6 ; /* number of HOLD_TIME before « hold » */ +const HOLD_MOVE = 3 ; /* maximum moved pixels for « holding » */ + +// -------------------------------------------------------------------------- +// --- Events Dispatcher +// -------------------------------------------------------------------------- + +const notify = ( cb, evt ) => cb && cb(evt); + +/** + @method + @summary Dispatch a dragging event over listeners. + @param {Dragging} dragging - the Dragging event to dispatch over + @param {object} [handlers] - an object with (optional) listeners + @description + +Dispatch a `Dragging` event among listeners defined in the `handlers` object, +when defined. For instance, `disptachEvents( evt , { onStop: myCallback } )` +will trigger `myCallback(evt)` if and only if `evt` is a `STOP` event. + +See event listeners documentation above for more details on listeners. + +You normally don't have to call this function, unless when you need to add +D&D features into your own component. Here is a typical pattern: + + const MyComponent = (props) => ( + <DragSource + dnd={props.dnd} + onDnd={(evt) => DnD.dispatchEvent(Object.assign(evt,…),props)} > + … + </DragSource> + ); + + */ +export const dispatchEvent = ( dragging , handlers ) => { + if (!handlers) return; + const dragged = Object.assign( {} , dragging ); + notify( handlers.onDnd , dragged ); + switch( dragged.move ) { + case 'START': + notify( handlers.onStart, dragged ); + return; + case 'STOP': + notify( handlers.onStop, dragged ); + return; + case 'ENTER': + notify( handlers.onEnter, dragged ); + return; + case 'SWITCH': + notify( handlers.onLeave, dragged ); + notify( handlers.onEnter, dragged ); + return; + case 'LEAVE': + notify( handlers.onLeave, dragged ); + return; + case 'DRAG': + notify( handlers.onDrag, dragged ); + return; + case 'MOVE': + notify( handlers.onMove, dragged ); + notify( handlers.onDrag, dragged ); + return; + case 'HOLD': + notify( handlers.onHold, dragged ); + return; + case 'DROP': + notify( handlers.onDrop, dragged ); + return; + default: + return; + } +}; + +// -------------------------------------------------------------------------- +// --- Dnd Controllers +// -------------------------------------------------------------------------- + +/** + @class + @summary D&D Controller. + @param {object} [handlers] - D&D events callbacks + @property {object} state - Current D&D state + @property {Dragging} dragging - Last D&D event + @description + D&D controlers are responsible for managing various drop targets + and dispatching the drag source events among them. + + The handler object shall define listeners to the D&D dragging events. + Each callback is sensible to specific kind of events, as specified + in the [event listeners](module-dome_dnd.html) + documentation. + + You need a D&D controller whenever an element can be dragged + between different containers. D&D controllers also offers an + abstraction over dragging events, dispatching among several + drop targets and the management of « holding » the mouse over + one drop target. + + Normally, you simply have to create D&D controllers in your global + (or local) state and pass them around into the hierarchy of your + components. For lower-level control, see the documentation of + the exposed methods. + + Having several D&D controllers allows you to assign specific + sources to specific targets. You shall have one D&D controller + for each « kind » of data that you can drag over. + + The `state` and `dragging` properties are shared across all partipants + of a D&D sequence, which are also re-rendered when the state is updated. + Outside of a D&D sequence, the `state` and `dragging` properties are undefined. + +*/ + +export class DnD { + + constructor(handlers) { + this.kid = 0 ; + this.targets = {} ; + this.tickHold = this.tickHold.bind(this); + this.triggerUpdate = this.triggerUpdate.bind(this); + this.triggerDnd = this.triggerDnd.bind(this); + this.handlers = handlers || {} ; + } + + /** @summary Update the D&D event handlers. + @param {object} [handlers] - D&D events callbacks + @description + Replace the event handlers by those specified in the `handlers` object. + Not mentionned callbacks are left unchanged. + If the `null` object is given, all current handlers are removed. + */ + setHandlers( handlers ) { + this.handlers = + handlers === null ? {} : Object.assign( this.handlers, handlers ); + } + + //--- Registering + + /** @summary Registers a target into the D&D controller. + @param {React.ref} ref - a referrence on the drop target DOM element + @param {function} callback - generic D&D events callback + @return {ident} the target identifier + @description + You normally don't call this method by yoursef, it is automatically + called when `<DropTarget/>` are mounted in the DOM. + */ + register( ref, callback ) + { + if (!ref) return undefined; + const id = 'DOME$' + (++this.kid) ; + this.targets[id] = { id, ref , callback } ; + return id; + } + + //--- Updating + + /** @summary Update the event handlers associated to a drop target. + @param {ident} id - the drop target identifier + @param {React.ref} ref - a referrence on the drop target DOM element + @param {function} callback - generic D&D events callback + @description + You normally don't call this method by yoursef, it is automatically + called when `<DropTarget/>` are updated. If the target data is falsy, the target identifier + is used instead. + */ + update( id, ref, callback ) { + if (this.targets[id]) { + this.targets[id] = { id, ref, callback }; + } + } + + //--- Un-Registering + + /** @summary Un-register a target from the D&D controller. + @param {ident} id - the drop target identifier to remove + @description + You normally don't call this method by yoursef, it is automatically + called when `<DropTarget/>` are unmounted from the DOM. + */ + remove( id ) { + delete this.targets[id] ; + } + + //--- Generic Mouse Event + + handleMouseEvent( evt, x, y ) { + const d = this.dragging ; + d.meta = evt.ctrKey || evt.altKey || evt.metaKey ; + d.deltaX = x - this.rootX ; + d.deltaY = y - this.rootY ; + d.position = {x,y} ; + const ex = d.clientX = evt.clientX ; + const ey = d.clientY = evt.clientY ; + d.targetClientRect = undefined ; + this.leaved = this.target ; + this.leavedHandler = this.targetHandler ; + this.target = undefined ; + this.targetHandler = undefined ; + const elts = document.elementsFromPoint(ex,ey); + elts.find((elt) => { + const target = _.find( this.targets, (tgt) => tgt.ref.current === elt ); + if (target) { + const { id, callback } = target ; + this.target = id ; + this.targetHandler = target.callback ; + if (id === this.leaved) this.leavedHandler = undefined ; + d.targetClientRect = elt.getBoundingClientRect(); + return true; + } + return false; + }); + } + + //--- Starting D&D sequence + + /** @summary Initiates a new drag. + @param {Event} evt - the mouse event originating the drag + @param {number} x - initial horizontal coordinate + @param {number} y - initial vertical coordinate + @param {Element} node - the source DOM element + @param {function} callback - generic D&D events callback + @description +You normally don't call this method by sourself, it is automatically +called by `DragSource` objects. + +Initial `(x,y)` coordinates can be in any coordinate system, they +are only used to compute relative offsets of further D&D events. +They can be typically taken from React-Draggable events data. + +The generic callback shall handle two kind of events: + - `callback()` when the global D&D state has been updated; + - `callback(Dragging)` when some D&D event is triggered. + +Generally, you shall `forceUpdate()` your component in the first case, +and `dispatchEvent()` the event to D&D listeners in the second case. + + */ + handleStart( evt, x, y, node, callback ) { + if (this.dragging) { + this.triggerDnd('STOP'); + if (this.timer) clearInterval(this.timer); + } + this.state = {}; + this.dragging = { + sourceClientRect: node.getBoundingClientRect() + }; + this.sourceHandler = callback ; + this.targetHandler = undefined ; + this.leavedHandler = undefined ; + this.rootX = x; + this.rootY = y; + this.lastX = x; + this.lastY = y; + this.ticks = 0; + this.handleMouseEvent( evt, x, y ); + this.triggerDnd( 'START' ); + this.timer = setInterval( this.tickHold , HOLD_TIME ); + } + + //--- Dragging D&D sequence + + /** @summary Dispatch a drag-event amoung registered drop targets. + @param {Event} evt - the dragging mouse event + @param {number} x - the horizontal coordinate + @param {number} y - the vertical coordinate + @description +You normally don't call this method by sourself, it is automatically +called by `DragSource` objects. + +The `(x,y)` coordinates shall be in the same coordinate system than +when starting the D&D sequence. It is only used to compute relative +the offsets of the associated D&D event. + */ + handleDrag( evt, x, y ) { + let kind = 'DRAG' ; + let delta = Math.abs( x - this.lastX ) + Math.abs( y - this.lastY ); + this.lastX = x ; + this.lastY = y ; + if (delta > HOLD_MOVE) { + this.ticks = 0 ; + const d = this.dragging ; + if (d.held) { + d.held = false ; + kind = 'MOVE' ; + } + } + this.handleMouseEvent( evt, x, y ); + const target = this.target ; + const leaved = this.leaved ; + if (target !== leaved) { + if (target && !leaved) kind = 'ENTER' ; else + if (!target && leaved) kind = 'LEAVE' ; else + if (target && leaved) kind = 'SWITCH' ; + } + this.triggerDnd(kind); + } + + //--- Stopping D&D sequence + + /** @summary Dispatch a drop-event over registered drop targets. + @param {Event} evt - the dropping mouse event + @param {number} x - the horizontal coordinate + @param {number} y - the vertical coordinate + @description +You normally don't call this method by sourself, it is automatically +called by `DragSource` objects. + +The `(x,y)` coordinates shall be in the same coordinate system than +when starting the D&D sequence. It is only used to compute relative +the offsets of the associated D&D event. + */ + handleStop( evt, x, y ) { + clearInterval( this.timer ); + this.handleMouseEvent( evt, x, y ); + this.triggerDnd(this.target ? 'DROP' : 'STOP'); + this.dragging = undefined ; + this.state = undefined ; + this.timer = undefined; + this.ticks = undefined; + this.triggerUpdate(); + } + + //--- Hold Detection + + tickHold() { + if (this.dragging && (this.ticks++) > HOLD_FIRE) + { + this.dragging.held = true ; + this.triggerDnd('HOLD'); + this.ticks = 0 ; + } + } + + //--- Update State + + /** + @summary Update the controller state. + @parameter {object} update - the data to update the state with + @description + Update the state with the given updates, like React component states. + This will force the drag source target and drop target components to re-render. + */ + setState(update) { + const state = this.state ; + if (state && update) { + this.state = Object.assign( state, update ); + if (!this.dirty) { + this.dirty = true ; + setImmediate( this.triggerUpdate ); + } + } + } + + triggerUpdate() { + this.dirty = false ; + notify( this.leavedHandler ); // always different from target + notify( this.sourceHandler ); + notify( this.targetHandler ); + notify( this.handlers.onUpdate , this.state ); + } + + //--- Trigger Dragging Events + + triggerDnd(move) { + const d = this.dragging ; + d.move = move ; + switch( move ) { + case 'ENTER': + notify( this.sourceHandler, d ); + notify( this.targetHandler, d ); + break; + case 'LEAVE': + notify( this.leavedHandler, d ); + notify( this.sourceHandler, d ); + break; + case 'SWITCH': + d.move = 'LEAVE' ; notify( this.leavedHandler, d ); + d.move = 'SWITCH' ; notify( this.sourceHandler, d ); + d.move = 'ENTER' ; notify( this.targetHandler, d ); + d.move = 'SWITCH' ; + break; + default: + notify( this.leavedHandler, d ); // allways different from target + notify( this.sourceHandler, d ); + notify( this.targetHandler, d ); + break; + } + dispatchEvent( d, this.handlers ); + } + +} + +// -------------------------------------------------------------------------- +// --- Drag Overlay +// -------------------------------------------------------------------------- + +/** + @class + @summary Display a Drag Source with an Overlay. + @property {Dragging} [dragging] - current dragging event + @property {string} [className] - source content class + @property {object} [style] - source content style + @property {object} [draggedStyle] - additional style for the source placeholder + @property {object} [draggingStyle] - additional style for the source being dragged + @property {number} [offsetX] - horizontal offset during drag (default 4) + @property {number} [offsetY] - vertical offset during drag (default 4) + @property {number} [zIndex] - fixed positioning during drag (default 1) + @property {any} [...divProps] - other properties to inject in the root element + @property {React.children|function} [children] - drag source content + @description + When dragged, a source drag is generally blit by its embedding container. + Using z-index CSS property might be a solution, but this is generally not + enough to escape from a positionned parent `<div>` element. + + The alternative is to separate the internal content of + a drag source from its outer `<div>`, and to use fixed positionning + during a D&D sequence. + + The `<Overlay>` component implements this behaviour. The root element is + normally laid out with the `className`, `style` and `divProps` properties and + its internal content is wrapped inside an internal `<div>` container. + + During dragging, this normal layout is slightly altered, without causing + extra React mounting or unmounting. The outer `<div>` is styled with its + original class plus the `'dome-dragged'` class which provides by default a + light-blue background and invisible border style. The inner class is styled + with its original class plus the `dome-dragging` class, canceled margins and + fixed positionning with respect to the dragging event. You may use those + additinal classes to add conditional styling when dragging. + + Additionnaly, when dragged around, the source content is offsets + with `offsetX` and `offsetY`, which defaults to 4 pixels each. + + Finally, you may supply a custom rendering function for rendering the drag + source content, which is fed with the current dragging event. + */ + +export const Overlay = ({ + dragging, className='', style, styleDragged, styleDragging, + offsetX=4, offsetY=4, insetX=0, insetY=0, + zIndex=1, + children, + ...divProps +}) => { + let outerClass,outerStyle,innerStyle,innerClass ; + if (dragging) { + const { left, top, width, height } = dragging.sourceClientRect ; + const position = { + position: 'fixed', + left: left + offsetX + dragging.deltaX, + top: top + offsetY + dragging.deltaY, + width, height, zIndex, margin: 0 + }; + const holder = { + width, height + }; + outerClass = 'dome-dragged ' + className ; + innerClass = 'dome-dragging ' + className ; + outerStyle = Object.assign( {}, style, styleDragged, holder ); + innerStyle = Object.assign( {}, style, styleDragging, position ); + } else { + outerClass = className ; + outerStyle = style ; + innerClass = undefined ; + innerStyle = undefined ; + } + return ( + <div className={outerClass} style={outerStyle} {...divProps}> + <div className={innerClass} style={innerStyle}> + {typeof(children)==='function' ? children(dragging) : children} + </div> + </div> + ); +}; + +// -------------------------------------------------------------------------- +// --- Drag Sources +// -------------------------------------------------------------------------- + +/** + @class + @summary Drag Source Component. + @property {DnD} [dnd] - the associated D&D controller + @property {string} [handle] - DOM selector initiating the drag (eg. `'.handle'`) + @property {boolean} [disabled] - cancel D&D events if non falsy value + @property {object} [draggable] - additional properties for the internal react-draggable wrapper + @property {function} [onDnd] - callback to D&D generic events + @property {function} [onXxx] - callback to other D&D specific events + @property {string} [className] - the class of the internal 'div' component (unless custom rendering) + @property {object} [style] - the style of the internal 'div' component (unless custom rendering) + @property {object} [position] - relative position of the internal 'div' component (unless custom rendering) + @property {boolean|object} [overlay] - use an `Overlay` to display the content + @property {React.children|function} children - element content or custom rendering function + @description + +Creates a drag source element and manage its dragging state. The component +is rendered by an internal `<div>` element with the given class and style with specific +handlers attached in. You can use the `'position'` property to modify its relative position +_after_ a D&D sequence, the position being `{x:0,y:0}`. This position is set relative to the normal +positioning of the internal `<div>` element, as specified by the provided class and style properties. +Notice that during dragging, your component is attached an additional `'dome-dragging'` class name that +you can use to alter its rendering. + +Alternatively, you may provide a custom rendering function as the unique children of the Drag Source element. +The function will be given the current D&D dragging events, or `undefined` when outside a D&D sequence. +The custom rendering _shall_ return a single root element supporting property injection in order for the Drag +Source element to attach its event handlers into it. You are then fully responsible for rendering and positioning +the element both _during_ and _outside_ of a D&D sequence. No internal `<div>` element is inserted for you, +and the `className`, `style` and `position` properties are ignored. + +Finally, you may also use an [Overlay](module-dome_dnd.Overlay.html) component to render +your content, by setting `overlay=true` or passing `overlay` the desired properties. + +When dragged, the [DnD](module-dome_dnd.DnD.html) controller is informed and dispatches +the dragging events to the registered drop targets. The `handle` selector can be used +to identify which parts of the content may initiate the drag. By default, any drag event +may initiate the drag. + +The `onDnd` event listener receives all D&D events associated to this drop target. +See [event callbacks](module-dome_dnd.html) +documentation for more details on other specific event listeners. + +The `draggable` object, when provided, is used to inject additional properties +into the internal `Draggable` or `DraggableCore` wrapper used to manage D&D events. +By default, a full featured `Draggable` component is used. +When a custom rendering function is specified, a `DraggableCore` is used instead. +See [react-draggable](https://github.com/mzabriskie/react-draggable) +documentation for more details. + +*/ + +export class DragSource extends React.Component +{ + constructor(props) + { + super(props); + this.onStart = this.onStart.bind(this); + this.onDrag = this.onDrag.bind(this); + this.onStop = this.onStop.bind(this); + this.handleDnd = this.handleDnd.bind(this); + this.state = { }; + } + + componentDidMount() { + this.mounted = true; + } + + componentWillUnmount() { + this.mounted = false; + } + + onStart(evt,drag) { + const { dnd, disabled } = this.props; + if (dnd) dnd.handleStart(evt,drag.x,drag.y,drag.node,this.handleDnd); + } + + onDrag(evt,drag) { + const { dnd, disabled } = this.props ; + if (dnd) dnd.handleDrag(evt,drag.x,drag.y); + } + + onStop(evt,drag) { + const { dnd, disabled } = this.props ; + if (dnd) dnd.handleStop(evt,drag.x,drag.y); + } + + handleDnd(dragging) { + if (!this.mounted) return; + if (!dragging) + this.forceUpdate(); + else { + dispatchEvent( dragging, this.props ); + switch(dragging.move) { + case 'STOP': + case 'DROP': + this.setState({dragging:undefined}); + break; + default: + this.setState({dragging}); + break; + } + } + } + + render() { + const { dnd, disabled, className, style, + handle, draggable, overlay, + children } = this.props ; + if (overlay || typeof(children)==='function') { + const dragging = this.state.dragging ; + return ( + <DraggableCore + handle={handle} + disabled={!dnd || disabled} + onStart={this.onStart} + onDrag={this.onDrag} + onStop={this.onStop} + {...draggable} + > + { overlay ? + ( + <Overlay + dragging={dragging} + className={className} style={style} + {...overlay} > + {children} + </Overlay> + ) + : children(dragging) + } + </DraggableCore> + ); + } else { + const { className, style, position={x:0,y:0} } = this.props ; + return ( + <Draggable + handle={handle} + disabled={!dnd || disabled} + position={position} + defaultClassName='' + defaultClassNameDragged='' + defaultClassNameDragging='dome-dragging' + onStart={this.onStart} + onDrag={this.onDrag} + onStop={this.onStop} + {...draggable} + > + <div className={className} style={style}>{children}</div> + </Draggable> + ); + } + } + +} + +// -------------------------------------------------------------------------- +// --- Drop Target +// -------------------------------------------------------------------------- + +/** + @class + @summary Drop Target Container. + @property {DnD} [dnd] - the associated D&D Controller + @property {function} [onDnd] - callback to D&D generic events + @property {function} [onXxx] - callback to other D&D specific events + @property {string} [className] - class name(s) of the internal `<div>` element (unless custom rendering) + @property {object} [style] - style property for the internal `<div>` element (unless custom rendering) + @property {React.ref} [targetRef] - the React ref to use for identifying the target DOM element + @property {React.children|function} children - element content or custom rendering function + @description + +Crates a drop target container and register its callbacks into the specified +[DnD](module-dome_dnd.DnD.html) controller. In case the DnD controller is undefined, +the drag events are just disabled. + +The drop target container must inform the D&D controller of its DOM element that is responsible +for reacting to dragging events. By default, the drop target element renders its children elements +inside an internal `<div>` element with the specified class ans style properties. Notice that, during +a D&D sequence, the `dome-dragging` class name is added to this `<div>` element and you can use this selector +for your styling. + +Alternatively, you may provide a custom rendering function as the unique children of the Drag Source element. +Your rendering function will receive the current D&D dragging of the D&D sequence, if any. +The [targetRef] property shall be used to identify the target DOM element, otherwize, the drop target +will not respond to dragging events. +In case of custom rendering, the `className` and `style` properties are ignored. + +During a D&D sequence, the `onDnd` event listener receives all D&D events associated +to this drop target. See [event callbacks](module-dome_dnd.html) +documentation for more details on other specific event listeners. + +*/ +export class DropTarget extends React.Component +{ + + constructor(props) { + super(props); + this.targetRef = this.props.targetRef || React.createRef() ; + this.handleDnd = this.handleDnd.bind(this); + this.state = {}; + } + + componentDidMount() { + const { dnd } = this.props ; + this.id = dnd && dnd.register( this.targetRef, this.handleDnd ); + this.mounted = true ; + } + + componentDidUpdate() { + const { dnd } = this.props ; + dnd && dnd.update(this.id, this.targetRef, this.handleDnd ); + } + + componentWillUnmount() { + const { dnd } = this.props ; + dnd && dnd.remove( this.id ); + this.mounted = false ; + } + + handleDnd(dragging) { + if (!this.mounted) return; + if (!dragging) + this.forceUpdate(); + else { + dispatchEvent( dragging, this.props ); + switch(dragging.move) { + case 'STOP': + case 'DROP': + case 'LEAVE': + this.setState({dragging:undefined}); + break; + default: + this.setState({dragging}); + break; + } + } + } + + render() { + const targetRef = this.targetRef ; + const { children } = this.props ; + const { dragging } = this.state ; + if (typeof(children)==='function') + return children(dragging); + else { + let { className='', style } = this.props ; + return ( + <div ref={targetRef} + className={ dragging ? className + ' dome-dragging' : className } + style={style} > + {children} + </div> + ); + } + } + +} + +// -------------------------------------------------------------------------- +// --- Export +// -------------------------------------------------------------------------- + +export default { + DnD, DragSource, DropTarget, dispatchEvent +} ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/dome.css b/Ivette/src/dome/src/renderer/dome.css new file mode 100644 index 0000000000000000000000000000000000000000..3320c9f51007536736c5319369d058c10fb26da9 --- /dev/null +++ b/Ivette/src/dome/src/renderer/dome.css @@ -0,0 +1,131 @@ +/* -------------------------------------------------------------------------- */ +/* --- Main Dome Styles --- */ +/* -------------------------------------------------------------------------- */ + +* { + user-select: none; + box-sizing: border-box; + margin: 0 ; + padding: 0 ; + } + +body { + overflow: hidden ; + position: fixed ; + font-family: sans-serif ; + font-size: 13px ; + color: #333333 ; + background: #f0f0f0 ; + top: 0 ; + bottom: 0 ; + left: 0 ; + right: 0 ; +} + +#app { + width: 100% ; + height: 100% ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Frame Colors --- */ +/* -------------------------------------------------------------------------- */ + +.dome-window-active .dome-color-frame { + fill: #606060 ; + color: #606060 ; + border-color: #afafaf ; + background: #d8d8d8 ; +} + +.dome-window-inactive .dome-color-frame { + fill: #b0b0b0 ; + color: #b0b0b0 ; + border-color: #d6d6d6 ; + background: #f6f6f6 ; +} + +.dome-window-active .dome-color-selected { + border-color: #e8e8e8 ; + background: #ff9504 ; + color: #ffffff ; +} + +.dome-window-inactive .dome-color-selected { + border-color: #e8e8e8 ; + background: #d8d8d8 ; +} + +.dome-color-dragzone { + opacity: 0.0 ; + background: transparent ; + transition: opacity .1s linear 0.1s , background .1s linear 0.1s ; +} + +.dome-color-dragzone:hover { + background: #808080 ; + opacity: 0.2 ; + transition: opacity .1s linear 0.1s , background .1s linear 0.1s ; +} + +.dome-color-dragging { + background: #64b4f0 ; + opacity: 0.5 ; + transition: opacity .1s linear 0.1s , background .1s linear 0.1s ; +} + +div.dome-dragged { + background: lightblue ; + border: none ; +} + +.dome-dragging * { + cursor: move ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Text Properties --- */ +/* -------------------------------------------------------------------------- */ + +.dome-text-label { + font-family: sans-serif ; + user-select: none ; + white-space: nowrap ; + text-overflow: ellipsis ; +} + +.dome-text-title { + font-family: sans-serif ; + font-size: larger ; + font-weight: bolder ; + user-select: none ; + white-space: nowrap ; + text-overflow: ellipsis ; +} + +.dome-text-descr { + font-family: sans-serif ; + font-size: smaller ; + user-select: none ; + white-space: wrap ; + text-overflow: ellipsis ; +} + +.dome-text-data { + cursor: text ; + user-select: text ; + font-family: sans-serif ; + white-space: nowrap ; + text-overflow: clip ; +} + +.dome-text-code { + cursor: text ; + user-select: text ; + font-family: 'Andale mono', monospace ; + font-size: 9pt ; + white-space: pre ; + text-overflow: clip ; +} + +/* -------------------------------------------------------------------------- */ diff --git a/Ivette/src/dome/src/renderer/dome.js b/Ivette/src/dome/src/renderer/dome.js new file mode 100644 index 0000000000000000000000000000000000000000..8a4b389dc5d9cd0a82fff7a19ded1fddf316cd2e --- /dev/null +++ b/Ivette/src/dome/src/renderer/dome.js @@ -0,0 +1,987 @@ +/** + @module dome(renderer) + @description + + ## Dome Application (Renderer Process) + + This modules manages your main application window + and its interaction with the main process. + + @example // File 'src/renderer/index.js': + import Dome from 'dome'; + import Application from './Application.js' ; + Dome.setContent( Application ); + */ + +import _ from 'lodash' ; +import React from 'react'; +import ReactDOM from 'react-dom'; +import { AppContainer } from 'react-hot-loader' ; +import { remote , ipcRenderer } from 'electron'; +import System from 'dome/system' ; +import './dome.css' ; + +// -------------------------------------------------------------------------- +// --- Context +// -------------------------------------------------------------------------- + +// main window focus +var focus = true ; + +function setContextAppNode() +{ + const node = document.getElementById('app'); + if (node) { + node.className = + 'dome-container dome-platform-' + System.platform + + ( focus ? ' dome-window-active' : ' dome-window-inactive' ) ; + } + return node; +} + +// -------------------------------------------------------------------------- +// --- Helpers +// -------------------------------------------------------------------------- + +/** @summary Development mode flag. + @description + Configured to be `'true'` when in development mode +*/ +export const DEVEL = System.DEVEL ; + +/** @summary System platform. + @description + Same as [`platform`](module-dome_system.html#.platform) from `dome/system` */ +export const platform = System.platform ; + +// -------------------------------------------------------------------------- +// --- Application Emitter +// -------------------------------------------------------------------------- + +import { EventEmitter } from 'events' ; + +/** @summary Application Emitter. + @description + Can be used as a basic _Flux_ dispatcher. */ +export const emitter = new EventEmitter(); + +/** Same as `emitter.on` */ +export function on(evt,job) { emitter.on(evt,job); } + +/** Same as `emitter.off` */ +export function off(evt,job) { emitter.off(evt,job); } + +/** Same as `emitter.emit` */ +export function emit(evt,...args) { emitter.emit(evt,...args); } + +// -------------------------------------------------------------------------- +// --- Application Events +// -------------------------------------------------------------------------- + +/** @event 'dome.update' + @description + Convenient pre-defined events for triggering a global re-render. + See also [Dome.onUpdate](#.onUpdate), [Dome.update](#.update) methods and + the [Dome.useUpdate](#.useUpdate) hook. +*/ + +/** @event 'dome.reload' + @description + Triggered when the application has been loaded or re-loaded + See also [Dome.onReload](#.onReload). +*/ + +/** @event 'dome.command' + @param {Array.<string>} argv - command line arguments + @param {string} wdir - working directory + @description + Triggered when the command line argument has been received, and when + the application is re-loaded (in development mode). + + See also [Dome.onCommand](#.onCommand). +*/ + +/** + @summary Emits the `dome.update` event. +*/ +export function update() { emitter.emit('dome.update'); } + +/** + @summary Update event handler. + @param {function} cb - invoked on update events. + @description + Register a callback on [dome.update](#~event:'dome.update') event. +*/ +export function onUpdate(job) { emitter.on('dome.update',job); } + +/** + @summary Update event handler. + @param {function} cb - invoked on reload events. + @description + Register a callback on [dome.reload](#~event:'dome.reload') event. +*/ +export function onReload(job) { emitter.on('dome.reload',job); } + +/** @summary Command-line event handler. + @param {function} cb - invoked with `cb(argv,wdir)` + @description +Register a callback on [dome.command](#~event:'dome.reload') event, +emitted by the `Main` process when the application instance is launched. + +See also: + - [Dome.useCommand](#.useCommand) + - [System.getArguments](module-dome_system.html#.getArguments) + - [System.getWorkingDir](module-dome_system.html#.getWorkingDir) +*/ +export function onCommand(job) { emitter.on('dome.command',job); } + +ipcRenderer.on('dome.ipc.reload',() => emitter.emit('dome.reload')); +ipcRenderer.on('dome.ipc.command', (_event,argv,wdir) => { + System.setCommand(argv,wdir); + emitter.emit('dome.command',argv,wdir); +}); + +// -------------------------------------------------------------------------- +// --- Main-Process Communication +// -------------------------------------------------------------------------- + +// -------------------------------------------------------------------------- +// --- Window Management +// -------------------------------------------------------------------------- + +export function isApplicationWindow() +{ + return process.argv.includes( System.WINDOW_APPLICATION_ARGV ); +} + +export function isPreferencesWindow() +{ + return process.argv.includes( System.WINDOW_PREFERENCES_ARGV ); +} + +// -------------------------------------------------------------------------- +// --- Window Title +// -------------------------------------------------------------------------- + +export function setModified( modified ) +{ + ipcRenderer.send('dome.ipc.window.modified',modified); +} + +export function setTitle( title ) +{ + ipcRenderer.send('dome.ipc.window.title',title); +} + +// -------------------------------------------------------------------------- +// --- Main Content +// -------------------------------------------------------------------------- + +/** + @summary Defines the user's main window content. + @param {React.Component} Component - to be rendered in the main window + @description + Binds the component to the main window. + + <strong>Notes:</strong> a `<Component/>` instance is generated and rendered in the `#app` + window element. Its class name is set to `dome-platform-<platform>` with + the `<platform>` set to the `Dome.platform` value. This class name can be used + as a CSS selector for platform-dependent styling. +*/ +export function setApplicationWindow( Component ) +{ + if (isApplicationWindow()) { + syncSettings(); + const appNode = setContextAppNode(); + ReactDOM.render( <AppContainer><Component/></AppContainer> , appNode ); + } +} + +// -------------------------------------------------------------------------- +// --- Settings Window +// -------------------------------------------------------------------------- + +/** + @summary Defines the user's preferences window content. + @param {React.Component} Component - to be rendered in the settings window + @description + Binds the component to the settings window. + + <strong>Notes:</strong> a `<Component/>` instance is generated and rendered in the `#app` + window element. Its class name is set to `dome-platform-<platform>` with + the `<platform>` set to the `Dome.platform` value. This class name can be used + as a CSS selector for platform-dependent styling. +*/ +export function setPreferencesWindow( Component ) +{ + if (isPreferencesWindow()) { + syncSettings(); + const appNode = setContextAppNode(); + ReactDOM.render( <AppContainer><Component/></AppContainer> , appNode ); + } +} + +// -------------------------------------------------------------------------- +// --- MenuBar Management +// -------------------------------------------------------------------------- + +const customItemCallbacks = {} ; + +/** + @summary Create a new custom menu in the menu bar. + @param {string} label - the menu title (shall be unique) + @description + This function can be triggered at any time, and will eventually trigger + an update of the whole application menubar. + + It is also possible to call this function from the main process. +*/ +export function addMenu( label ) { ipcRenderer.send( 'dome.ipc.menu.addmenu' , label ); } + +/** + @summary Insert a new custom item in a menu. + @param {object} spec - the menu-item specification + @description +The menu-item shall be specified by using the following fields: + - `menu` (`string`, _required_) : the label of the menu to insert the item in; + can be a custom menu, or one of the predefined `'File'`, `'Edit'` or `'View'` menus. + - `id` (`string|number`, _required_) : the item identifier; + shall be unique among the entire menu-bar. + - `type` (`string`, _optional_) : one of `'normal'`, `'separator'`, `'checkbox'` or `'radio'`. + - `label` (`string`, _optional_) : the item label. + - `visible` (`boolean`, _optional_, default is `true`). + - `enabled` (`boolean`, _optional_, default is `true`). + - `checked` (`boolean`, _optional_, for `type:'checkbox'` and `type:'radio'` only, default is `false`). + - `key` (`string`, _optional_) : a keyboard shortcut for menu-item. + - `onClick` (`function`, _optional_) : an optional callback. + +These options (except `menu` and `id`) can be modified later on by using the [setMenuItem](#.setMenuItem) function. + +When clicked, the menu-item will also trigger a `'dome.menu.clicked'` event on the entire application (both process) +with the corresponding `id`. + +Key short cuts shall be specified with the following codes: + - `"Cmd+<Key>"` for command (MacOS) or control (Linux) key + - `"Alt+<Key>"` for command+option (MacOS) or alt (Linux) key + - `"Meta+<Key>"` for command+shift (MacOS) or control+alt (Linux) key + +Alternatively, more precise keybord shortcuts can be specified with the `'accelerator'` option, +which follows the same encoding that menu-item specifications from Electron. + +The `addMenu` function can be triggered at any time, and will eventually trigger +an update of the whole application menubar. +It is also possible to call this function from the main process. + +*/ +export function addMenuItem( spec ) +{ + if (!spec.id && spec.type !== 'separator') { + console.error('[Dome] Missing menu-item identifier',spec); + return; + } + const { onClick , ...options } = spec ; + if ( onClick ) customItemCallbacks[ spec.id ] = onClick ; + ipcRenderer.send( 'dome.ipc.menu.addmenuitem' , options ); +} + +/** + @summary Update properties of an existing menu-item. + @param {object} options - the menu-item specification to update + @description + Options must follow the specification of the [addMenuItem](#.addMenuItem) function. + Option `id` must specify the identifier of the menu item to update. + The menu and item positions can _not_ be modified. + If an `onClick` callback is specified, it will _replace_ the previous one. + You shall specify `null` to remove the previously registered callback + (`undefined` callback is ignored). + + This function can be triggered at any time, and will possibly trigger + an update of the whole application menubar if the properties + can not be changed dynamically in Electron. + + It is also possible to call this function from the main process. + When specified, the item callback is only invoked in the process which + specify it. To register callbacks in other process, + you shall listen to the `'dome.menu.clicked'` event. + */ +export function setMenuItem( options ) { + if (!options.id) { + console.error('[Dome] Missing menu-item identifier',options); + return; + } + const { onClick , ...updates } = options ; + if (onClick !== undefined) { + if (onClick) customItemCallbacks[options.id] = onClick ; + else delete customItemCallbacks[options.id] ; + } + ipcRenderer.send( 'dome.ipc.menu.setmenuitem', updates ); +} + +/** @event 'dome.menu.clicked' + @description Emitted with the clicked menu-item identifier */ + +ipcRenderer.on('dome.ipc.menu.clicked',(id) => { + const callback = customItemCallbacks[id] ; + callback && callback(); +}); + +// -------------------------------------------------------------------------- +// --- Context Menus +// -------------------------------------------------------------------------- + +/** + @summary Popup a contextual menu. + @param {item[]} items - the array of menu items + @param {function} [callback] - an optional callback + @description +Each menu item is specified by an object with the following fields: + - `id` (`string|number`, _optional_) : the item identifier. + - `label` (`string`, _optional_) : the item label. + - `enabled` (`boolean`, _optional_, default is `true`). + - `display` (`boolean`, _optional_, default is `true`). + - `onClick` (`function`, _optional_) : callback on item selection. + +Items can be separated by inserting a `'separator'` constant string +in the array. Item identifier and label default to each others. Alternatively, +an item can be specified by a single string that will be used for both +its label and identifier. + +The menu is displayed at the current mouse location. +The callback is called with the selected item identifier or label. +If the menu popup is canceled by the user, the callback is called with `undefined`. + +@example +let myPopup = (_evt) => Dome.popupMenu([ …items… ],(id) => … ); +<div onRightClick={myPopup}>...</div> + +*/ +export function popupMenu( items, callback ) +{ + const { Menu , MenuItem } = remote ; + const menu = new Menu(); + var selected = undefined ; + items.forEach((item,kid) => { + if (item === 'separator') + menu.append(new MenuItem({ type:'separator' })); + else + { + const { display=true } = item ; + if (display) { + const label = item.label || '#'+(kid+1) ; + const id = item.id || label ; + const enabled = item.enabled ; + const click = () => { + selected = id ; + item.onClick && item.onClick(); + }; + menu.append(new MenuItem({ label, enabled, click })); + } + } + }); + const job = callback ? () => callback( selected ) : undefined ; + menu.popup({window: remote.getCurrentWindow(), callback:job }); +} + +// -------------------------------------------------------------------------- +// --- Settings +// -------------------------------------------------------------------------- + +var globals = {} ; +var globalPatches = {} ; + +var settings = {} ; +var settingsPatches = {} ; + +// initial values => synchronized event +function syncSettings() { + const fullSettings = ipcRenderer.sendSync('dome.ipc.settings.sync'); + globals = fullSettings.globals ; + settings = fullSettings.settings ; +} + +const readSetting = ( local, key, defaultValue ) => { + const value = _.get( local ? settings : globals , key ); + return value === undefined ? defaultValue : value ; +}; + +const writeSetting = ( local, key, value ) => { + if (key) { + const theValue = value===undefined ? null : value ; + const store = local ? settings : globals ; + const patches = local ? settingsPatches : globalPatches ; + _.set( store, key, theValue ); + _.set( patches, key, theValue ); + emitter.emit('dome.settings'); + if (local) { + if (DEVEL) fireSaveSettings(); + } else { + fireSaveGlobals(); + } + } +}; + +const fireSaveSettings = _.debounce( + () => { + if (!_.isEmpty(settingsPatches)) { + ipcRenderer.send( 'dome.ipc.settings.window', settingsPatches ) ; + settingsPatches = {} ; + } + }, 200 +); + +const fireSaveGlobals = _.debounce( + () => { + if (!_.isEmpty(globalPatches)) { + ipcRenderer.send( 'dome.ipc.settings.global', globalPatches ) ; + globalPatches = {} ; + } + }, 200 +); + +ipcRenderer.on('dome.ipc.closing', (_evt) => { + fireSaveSettings(); + fireSaveSettings.flush(); + fireSaveGlobals(); + fireSaveGlobals.flush(); + System.doExit(); +}); + +/** @event 'dome.settings' + @description Emitted when the settings have been updated. */ + +/** @event 'dome.defaults' + @description Emitted when the settings have been reset to default. */ + +ipcRenderer.on('dome.ipc.settings.defaults',(sender) => { + fireSaveSettings.cancel(); + fireSaveGlobals.cancel(); + settingsPatches = {}; + globalPatches = {}; + settings = {}; + globals = {}; + emitter.emit('dome.defaults'); + emitter.emit('dome.settings'); +}); + +ipcRenderer.on('dome.ipc.settings.update',(sender,patches) => { + // Don't cancel local updates + _.merge( globals , patches , globalPatches ); + emitter.emit('dome.settings'); +}); + +/** + @summary Get value from local window (persistent) settings. + @param {string} key User's Setting Key (`'dome.*'` are reserved keys) + @param {any} [defaultValue] - default value if the key is not present + @return {any} associated value of object or `undefined`. + @tutorial application + @description + This settings are local to the current window, but persistently + saved in the user's home directory.<br/> + For global application settings, use `getGlobal()` instead. +*/ +export function getWindowSetting( key, defaultValue ) { + return key ? readSetting( true, key , defaultValue ) : defaultValue ; +} + +/** @summary Set value into local window (persistent) settings. + @param {string} key to store the data + @param {any} value associated value or object + @tutorial application + @description + This settings are local to the current window, but persistently + saved in the user's home directory.<br/> + For global application settings, use `setGlobal()` instead. +*/ +export function setWindowSetting( key , value ) { + writeSetting( true, key, value ); +} + +/** + @summary Get value from application (persistent) settings. + @param {string} key User's Setting Key (`'dome.*'` are reserved keys) + @param {any} [defaultValue] - default value if the key is not present + @return {any} associated value of object or `undefined`. + @tutorial application + @description + These settings are global to the application and persistently + saved in the user's home directory.<br/> + For local window settings, use `get()` instead. +*/ +export function getGlobalSetting( key, defaultValue ) { + return key ? readSetting( false, key , defaultValue ) : defaultValue ; +} + +/** @summary Set value into application (persistent) settings. + @param {string} key to store the data + @param {any} value associated value or object + @tutorial application + @description + These settings are global to the current window, but persistently + saved in the user's home directory. Updated values are broadcasted + in batch to all other windows, which in turn receive a `'dome.settings'` + event for synchronizing.<br/> + For local window settings, use `set()` instead. +*/ +export function setGlobalSetting( key , value ) { + writeSetting( false, key, value ); +} + +// -------------------------------------------------------------------------- +// --- Focus Management +// -------------------------------------------------------------------------- + +/** Current focus state of the main window. */ +export function isFocused() { return focus; } + +/** + @event 'dome.focus' + @param {boolean} state - updated focus state + @description Emitted when the application gain or loses focus. +*/ +ipcRenderer.on('dome.ipc.focus',(sender,value) => { + focus = value; + setContextAppNode(); + emitter.emit('dome.focus',value); +}); + +// -------------------------------------------------------------------------- +// --- Web Navigation +// -------------------------------------------------------------------------- + +/** + @event 'dome.href' + @param {string} href - internal `<a href=...>` target + @description + Emitted when the user clicks on a local `<a href=...>`. + URL with an `http://` protocole are opened externally + by the user's default browser. +*/ +ipcRenderer.on('dome.ipc.href',(href) => emitter.emit('dome.href',href)); + +// -------------------------------------------------------------------------- +// --- Function Component +// -------------------------------------------------------------------------- + +/** + @class + @summary Inlined Function React Component + @property {function} children - render function as children + @description + Allows to define an inlined functional component inside JSX. + The children function _can_ use hooks. + +@example +<Render> + {() => { + let [ state, setState ] = React.useState(); + … + return (<div>…</div>); + }} +</Render> +*/ +export const Render = ({children}) => { + return children(); +}; + +// -------------------------------------------------------------------------- +// --- React Hooks +// -------------------------------------------------------------------------- + +/** + @summary Hook to re-render on demand (Custom React Hook). + @return {function} to trigger re-rendering + @description + Returns a callback to trigger a render on demand. +*/ +export function useForceUpdate() +{ + const [tac,onTic] = React.useState(); + return () => onTic(!tac); +} + +/** + @summary Hook to re-render on Dome events (Custom React Hook). + @param {string} [event] - event name (default: `'dome.update'`) + @tutorial hooks + @description + Returns nothing. +*/ +export function useUpdate(evt = 'dome.update') +{ + const update = useForceUpdate(); + React.useEffect(() => { + emitter.on(evt,update); + return () => emitter.off(evt,update); + }); +} + +/** + @summary Hook to register callbacks to Dome events (Custom React Hook). + @param {string} event - Event to register on + @param {function} callback - The callback to register + @tutorial hooks + @description + Register the callback on event until the component is unmount. + Do not force the component to re-render (unless the callback does).<br/> + Returns nothing. +*/ +export function useEvent(evt,callback) +{ + React.useEffect(() => { + emitter.on(evt,callback); + return () => emitter.off(evt,callback); + }); +} + +/** + @summary Hook to register callbacks to events (Custom React Hook). + @param {EventEmitter} emitter - event emitter + @param {string} event - Event to register on + @param {function} callback - The callback to register + @tutorial hooks + @description + Register the callback on event until the component is unmount. + Do not force the component to re-render (unless the callback does).<br/> + Returns nothing. +*/ +export function useEmitter(emitter,evt,callback) +{ + React.useEffect(() => { + emitter.on(evt,callback); + return () => emitter.off(evt,callback); + }); +} + +const NULL = {}; // Dummy initial value + +// -------------------------------------------------------------------------- +// --- Commands Hooks +// -------------------------------------------------------------------------- + +/** + @summary Hook for command-line interface (Custom React Hook). + @return {array} `[argv,wdir]` command-line arguments and working directory + @tutorial hooks + @description + Returns the command-line arguments and working directory for the application + instance running in the window. Automatically updated on `dome.command` events. + + See also [Dome.onCommand](#.onCommand) event handler. +*/ +export function useCommand() { + useUpdate('dome.command'); + let wdir = System.getWorkingDir(); + let argv = System.getArguments(); + return [ argv , wdir ]; +} + +// -------------------------------------------------------------------------- +// --- Settings Hooks +// -------------------------------------------------------------------------- + +function useSettings( local, settings, defaultValue ) +{ + let [ value, setValue ] = React.useState(() => readSetting( local, settings, defaultValue )); + React.useEffect(() => { + if (settings) { + let callback = () => { + let v = readSetting( local, settings , defaultValue ); + setValue(v); + }; + emitter.on('dome.settings',callback); + return () => emitter.off( 'dome.settings', callback ); + } else { + let callback = () => setValue(defaultValue); + emitter.on('dome.defaults',callback); + return () => emitter.off( 'dome.defaults', callback ); + } + }); + let doUpdate = (upd) => { + const theValue = typeof(upd)==='function' ? upd(value) : upd ; + if (settings) writeSetting( local, settings, theValue ); + else setValue(theValue); + }; + return [ value, doUpdate ]; +} + +/** + @summary Local state with optional window settings (Custom React Hook). + @param {string} [settings] - optional window settings to backup the value + @param {any} [defaultValue] - the initial (and default) value + @return {array} `[value,setValue]` of the local state + @tutorial hooks + @description + Similar to `React.useState()` with persistent _window_ settings. + When the settings key is undefined, it simply uses a local React state. + Also responds to `'dome.settings'` to update the state and `'dome.defaults'` + to restore the default value. + + The `setValue` callback accepts either a value, or a function to be applied + on current value. +*/ +export function useState( settings, defaultValue ) { + return useSettings( true, settings, defaultValue ); +} + +/** + @summary Local boolean state with optional window settings (Custom React Hook). + @param {string} [settings] - optional window settings to backup the value + @param {boolean} [defaultValue] - the initial value (default is `false`) + @return {array} `[value,flipValue]` for the local state + @tutorial hooks + @description + Same as [useState](#.useState) with a boolean value that can be set or flipped: + - `flipValue()` change the value to its opposite; + - `flipValue(v)` change the value to `v`. +*/ +export function useSwitch( settings, defaultValue ) { + let [ value, update ] = useSettings( true, settings, defaultValue ); + return [ value, v => update(v===undefined ? !value : v) ]; +} + +/** + @summary Local state with global settings (Custom React Hook). + @param {string} settings - global settings for storing the value + @param {any} [defaultValue] - the initial and default value + @return {array} `[value,setValue]` of the local state + @tutorial hooks + @description + Similar to `React.useState()` with persistent _global_ settings. + When the settings key is undefined, it simply uses a local React state. + Also responds to `'dome.settings'` to update the state and `'dome.defaults'` + to restore the default value. + + The `setValue` callback accepts either a value, or a function to be applied + on current value. +*/ +export function useGlobalSetting( settings, defaultValue ) +{ + return useSettings( false, settings, defaultValue ); +} + +// -------------------------------------------------------------------------- +// --- Global States +// -------------------------------------------------------------------------- + +/** @event 'dome.state.update' + @description + Notify updates within a State object. +*/ + +const STATE_UPDATE = 'dome.state.update' ; + +/** + @summary Global state object. + @property {object} state - the current state properties + @property {object} defaults - the default state properties + @description + +You may use this class as convenient way to implement global +state for your Dome application. Simply create a state `s` with `new State(defaults)` +and use `s.setState()`, `s.getState()` or `s.state` property, and `s.useState()` +custom hooks. + +A state is also an event emitter that you can use to fire events, and you can use +the React custom hooks `s.useUpdate()` and `s.useEvent()`. + +All above methods are bound to `this` by the constructor. + +*/ +export class State extends EventEmitter +{ + + constructor(props) { + super(); + // Makes this field private + this.defaults = props ; + this.state = Object.assign( {}, props ); + this.update = this.update.bind(this); + this.getState = this.getState.bind(this); + this.setState = this.setState.bind(this); + this.clearState = this.clearState.bind(this); + this.replaceState = this.replaceState.bind(this); + this.useState = this.useState.bind(this); + this.useEvent = this.useEvent.bind(this); + this.useUpdate = this.useUpdate.bind(this); + } + + /** Emits the `dome.state.update` event */ + update() { this.emit('dome.state.update'); } + + /** Returns the state property. */ + getState() { return this.state; } + + /** @summary Update the state with (some) properties. + @param {object} props - the properties to be updated + @description + Update the state with `Object.assign`, like `setState()` on React components. + Also fire the `'dome.update'` property on the object. */ + setState(props) { + Object.assign( this.state, props ); + this.update(); + } + + /** @summary Replace (all) state properties. + @description + Replace the entire store with the new properties. + Also fire the `'dome.update'` property on the object. */ + replaceState(props) { + this.state = Object.assign( {}, props ); + this.update(); + } + + /** @summary Reset (all) state properties. + @description + Restore the entire store with the default properties. + Also fire the `'dome.state.update'` property on the object. */ + clearState() { + this.state = Object.assign( {}, this.defaults ); + this.update(); + } + + /** @summary Hook to use the state (custom React Hook). + @return {array} `[state,setState]` with current object properties and + function to update them. */ + useState() { + let forceUpdate = useForceUpdate(); + useEmitter( this, 'dome.state.update', forceUpdate ); + return [ this.state , this.setState ]; + } + + /** @summary Hook to re-render your component on State events. + @param {string} [event] - the event to listen to (defaults to `'dome.update'`) + */ + useUpdate(evt = 'dome.state.update') { + let forceUpdate = useForceUpdate(); + useEmitter( this, evt, forceUpdate ); + } + + /** @summary Hook to trigger callbacks on State events. + @param {string} event - the event to listen to + @param {function} callback - the callback triggered on event + */ + useEvent(evt,callback) { + useEmitter( this, evt, callback ); + } + +} + +// -------------------------------------------------------------------------- +// --- Timer Hooks +// -------------------------------------------------------------------------- + +// Collection of { pending, timer, period, time, event } indexed by period +const clocks = {}; + +const CLOCKEVENT = (period) => 'dome.clock.' + period ; + +const TIC_CLOCK = (clk) => () => { + if (0 < clk.pending) { + clk.time += clk.period ; + emitter.emit(clk.event,clk.time); + } else { + clearInterval(clk.timer); + delete clocks[clk.period]; + } +}; + +const INC_CLOCK = (period) => { + let clk = clocks[period] ; + if (!clk) { + let event = CLOCKEVENT(period); + let time = (new Date()).getTime(); + clk = { pending: 0, time, period, event }; + clocks[period] = clk ; + let tic = TIC_CLOCK(clk); + clk.timer = setInterval(tic,period); + } + clk.pending++; +}; + +const DEC_CLOCK = (period) => { + let clk = clocks[period] ; + if (clk) { + clk.pending--; + } +}; + +/** + @summary Synchronized start & stop timer (Custom React Hook). + @param {number} period - timer interval, in milliseconds (ms) + @param {boolean} [initStart] - whether to initially start the timer (default is `false`) + @tutorial hooks + @return {timer} Timer object + @description + Create a local timer, synchronized on a global clock, that can be started + and stopped on demand during the life cycle of the component. + + Each timer has its individual start & stop state. However, + all timers with the same period _are_ synchronized with each others. + + The timer object has the following properties and methods: + - `timer.start()` starts the timer, + - `timer.stop()` starts the timer, + - `timer.time` is the time stamp of the last clock (see below) + + It is safe to call `start()` and `stop()` whether the timer is running or not. + When `timer.time` is `-1`, it means the timer is stopped. + When `timer.time` is `0` it means the timer has just been started and no tic has + been received yet. The time stamp is in milliseconds; it is shared among all + timers synchronized on the same period and roughly equal to the `Date.getTime()` + of the associated clock. + + */ + +export function useClock(period,initStart) +{ + const [time,setTime] = React.useState(initStart ? 0 : -1); + const running = 0 <= time ; + React.useEffect(() => { + if (running) { + INC_CLOCK(period); + const event = CLOCKEVENT(period); + emitter.on(event,setTime); + return () => { + DEC_CLOCK(period); + emitter.off(event,setTime); + }; + } else + return undefined ; + }); + return { + time, + start: () => { if (!running) setTime(0); }, + stop: () => { if (running) setTime(-1); } + }; +} + +// -------------------------------------------------------------------------- +// --- Export +// -------------------------------------------------------------------------- + +export default { + platform, + DEVEL, + setTitle, + setModified, + isApplicationWindow, setApplicationWindow, + isPreferencesWindow, setPreferencesWindow, + isFocused, + emitter, emit, on, off, + addMenu, + addMenuItem, + setMenuItem, + popupMenu, + setWindowSetting, getWindowSetting, + setGlobalSetting, getGlobalSetting, + update, onUpdate, onReload, onCommand, + State, Render, + useForceUpdate, + useUpdate, useEvent, useEmitter, + useCommand, useClock, + useState, useSwitch, + useGlobalSetting +} ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/errors.js b/Ivette/src/dome/src/renderer/errors.js new file mode 100644 index 0000000000000000000000000000000000000000..bb3ea064aae87841fe90421142efec17808be573 --- /dev/null +++ b/Ivette/src/dome/src/renderer/errors.js @@ -0,0 +1,75 @@ +// -------------------------------------------------------------------------- +// --- Managing Errors +// -------------------------------------------------------------------------- + +import React from 'react' ; +import { Label } from 'dome/controls/labels' ; +import { Button } from 'dome/controls/buttons' ; + +/** @module dome/errors */ + +// -------------------------------------------------------------------------- +// --- Error Boundaries +// -------------------------------------------------------------------------- + +/** + @summary React Error Boundaries. + @property {string} [label] - Default error box label + @property {function} [onError] - Alternative renderer + @description + Install an error boundary. In case of error, the default + rendering is a warning button that output on console the + catched error. + + An alternative rendering can be supplied + with `onError:(error,info) => React.Element`. + + */ +export class Catch extends React.Component +{ + + constructor(props) { + super(props); + this.state = { }; + this.logerr = this.logerr.bind(this); + this.reload = this.reload.bind(this); + } + + dumpError(error,info) { + } + + componentDidCatch(error, info) { + this.setState({ error, info }); + } + + logerr() { + const { error, info } = this.state ; + console.error('[dome] Catched error:',error,info); + } + + reload() { + this.setState({ error: undefined, info: undefined }); + } + + render() { + const { error, info } = this.state ; + if (error) { + const { onError, label='Error' } = this.props ; + if (typeof(onError)==='function') + return onError(error,info,this.reload); + else + return ( + <div> + <Button icon='WARNING' kind='warning' + title={error} + onClick={this.logerr} /> + <Button icon='RELOAD' onClick={this.reload} /> + <Label>{label}</Label> + </div> + ); + } + return this.props.children || null ; + } +} + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/layout/boxes.css b/Ivette/src/dome/src/renderer/layout/boxes.css new file mode 100644 index 0000000000000000000000000000000000000000..a53382360de5caed92ac8239926234f8e0fd5bf9 --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/boxes.css @@ -0,0 +1,86 @@ +/* -------------------------------------------------------------------------- */ +/* --- Box Containers --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xBoxes-hbox +{ + display: flex ; + overflow: hidden ; + flex-flow: row nowrap ; + align-items: stretch ; +} + +.dome-xBoxes-vbox +{ + display: flex ; + overflow: hidden ; + flex-flow: column nowrap ; + align-items: stretch ; +} + +.dome-xBoxes-grid +{ + flex: 1 1 auto ; + overflow: auto ; + display: grid ; + display: grid; + grid-auto-rows: auto; + grid-auto-flow: row; + align-items: stretch; + align-content: start; + justify-content: start; +} + +/* -------------------------------------------------------------------------- */ +/* --- Extensibility --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xBoxes-pack +{ + flex: 0 0 auto ; + align-self: flex-start ; +} + +.dome-xBoxes-box +{ + flex: 0 0 auto ; +} + +.dome-xBoxes-fill +{ + flex: 1 1 auto ; +} + +.dome-xBoxes-scroll +{ + flex: 1 1 auto ; + overflow: auto ; +} + +.dome-container > .dome-xBoxes-fill +{ + width: 100% ; + height: 100% ; +} + +.dome-container > .dome-xBoxes-scroll +{ + width: 100% ; + height: 100% ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Spaces --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xBoxes-space +{ + flex: 0 1 24px ; +} + +.dome-xBoxes-filler +{ + flex: 1 1 24px ; +} + +/* -------------------------------------------------------------------------- */ diff --git a/Ivette/src/dome/src/renderer/layout/boxes.js b/Ivette/src/dome/src/renderer/layout/boxes.js new file mode 100644 index 0000000000000000000000000000000000000000..b648f612cfb75d2af04252b78b3bad8ad4299f9a --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/boxes.js @@ -0,0 +1,201 @@ +// -------------------------------------------------------------------------- +// --- Box Layout +// -------------------------------------------------------------------------- + +/** @module dome/layout/boxes + @description + +This modules offers several `<div>` containers with various +predefined layout. + +Boxes are the very elementary way to layout components horizontally +or vertically. The different kinds of proposed boxes differ in how they +extends in both directions: normal boxes extends +along their layout direction, _pack_ boxes don't extends and _fill_ boxes +extends along both directions. + +Grids layout their component from left-to-right inside predefined _columns_, +then vertically by wrapping cells in rows. + +The various containers are summarized on the table below: + +| **Box** | Layout | Extends | +|:-------------:|:-----------:|:----------:|:----------:| +| [Hbox](module-dome_layout_boxes.Hpack.html) | horiz. | horiz. | +| [Vbox](module-dome_layout_boxes.Vpack.html) | vert. | vert. | +| [Hpack](module-dome_layout_boxes.Hpack.html) | horiz. | none | +| [Vpack](module-dome_layout_boxes.Vpack.html) | vert. | none | +| [Hfill](module-dome_layout_boxes.Hpack.html) | horiz. | both | +| [Vfill](module-dome_layout_boxes.Vpack.html) | vert. | both | +| [Grid](module-dome_layout_boxes.Hpack.html) | columns | both | +| [Scroll](module-dome_layout_boxes.Scroll.html) | n/a | both | + +Inside a box, you may add `<Space/>` and `<Filler/>` to separate items. +Inside a grid, you may also use `<Space/>` or an empty `<div/>` for empty cells. + +<strong>Warning:</strong> large elements will be clipped if they overflow. +If you want to add scrolling capabilities to some item that does not manage overflow +natively, place it inside a `<Scroll/>` sub-container. + +*/ + +import React from 'react'; +import Dome from 'dome'; +import { Title } from 'dome/controls/labels' ; +import './boxes.css' ; + +// -------------------------------------------------------------------------- +// --- Generic Box +// -------------------------------------------------------------------------- + +const makeBox = ( boxClasses, props, morestyle ) => { + const { children, className, style, ...others } = props ; + const allClasses = className ? boxClasses + ' ' + className : boxClasses ; + const allStyles = morestyle ? (style ? Object.assign( {}, style, morestyle ) : morestyle) : style ; + return ( + <div className={allClasses} style={allStyles} {...others} > + {children} + </div> + ); +}; + +// -------------------------------------------------------------------------- +// --- Predefined Defaults +// -------------------------------------------------------------------------- + +/** + @class + @summary Horizontal box (extends horizontally, no overflow) + @property {object} [...props] - Extra properties passed to the `<div>` container + @description + <strong>Warning:</strong> large elements will be clipped if they overflow. +*/ +export const Hbox = (props) => makeBox( 'dome-xBoxes-hbox dome-xBoxes-box' , props ); + +/** + @class + @summary Vertical box (extends vertically, no overflow) + @property {object} [...props] - Extra properties passed to the `<div>` container + @description + <strong>Warning:</strong> large elements will be clipped if they overflow. +*/ +export const Vbox = (props) => makeBox( 'dome-xBoxes-vbox dome-xBoxes-box' , props ); + +/** + @class + @summary Compact Horizontal box (fixed dimensions, no overflow) + @property {object} [...props] - Extra properties passed to the `<div>` container + @description + <strong>Warning:</strong> large elements would be clipped if they overflow. +*/ +export const Hpack = (props) => makeBox( 'dome-xBoxes-hbox dome-xBoxes-pack' , props ); + +/** + @class + @summary Compact Vertical box (fixed dimensions, no overflow) + @property {object} [...props] - Extra properties passed to the `<div>` container + @description + <strong>Warning:</strong> large elements will be clipped if they overflow. +*/ +export const Vpack = (props) => makeBox( 'dome-xBoxes-vbox dome-xBoxes-pack' , props ); + +/** + @class + @summary Horizontally filled box (fixed height, maximal width, no overflow) + @property {object} [...props] - Extra properties passed to the `<div>` container + @description + <strong>Warning:</strong> large elements will be clipped if they overflow. +*/ +export const Hfill = (props) => makeBox( 'dome-xBoxes-hbox dome-xBoxes-fill' , props ); + +/** + @class + @summary Vertically filled box (fixed width, maximal height, no overflow) + @property {object} [...props] - Extra properties passed to the `<div>` container + @description + <strong>Warning:</strong> large elements will be clipped if they overflow. +*/ +export const Vfill = (props) => makeBox( 'dome-xBoxes-vbox dome-xBoxes-fill' , props ); + +// -------------------------------------------------------------------------- +// --- Scrolling & Spacing +// -------------------------------------------------------------------------- + +/** + @class + @summary Scrolling container + @property {object} [...props] - Extra properties passed to the `<div>` container +*/ +export const Scroll = (props) => makeBox( 'dome-xBoxes-scroll dome-container' , props ); + +/** + @class + @summary rigid space between items in a box + @property {object} [...props] - Extra properties passed to the `<div>` separator +*/ +export const Space = (props) => makeBox( 'dome-xBoxes-space' , props ); + +/** + @class + @summary extensible space between items in a box + @property {object} [...props] - Extra properties passed to the `<div>` separator +*/ +export const Filler = (props) => makeBox( 'dome-xBoxes-filler' , props ); + +// -------------------------------------------------------------------------- +// --- Grids +// -------------------------------------------------------------------------- + +/** + @class + @summary Grid box container + @property {string} [columns] - Grid column specifications + @property {object} [...props] - Extra properties passed to the `<div>` container + @description + Layout its children in a multi-column grid. Each column is specified by its + width, following the CSS Grid Layout `grid-template-columns` property. + + The rows are populated with children from left-to-right, using one column at a time. + Items layout can be modified by adding CSS Grid Layout item properties. + + Example: `<Grid columns="25% auto auto"> ... </Grid>` +*/ +export const Grid = ({columns='auto',...props}) => + makeBox( 'dome-xBoxes-grid', props , { gridTemplateColumns: columns }); + +// -------------------------------------------------------------------------- +// --- Folders +// -------------------------------------------------------------------------- + +/** + @class + @summary Foldable Vpack box + @property {string} label - box label + @property {string} [title] - box label tooltip + @property {string} [settings] - window setting to store the fold/unfold state + @property {boolean} [defaultUnfold] - initial state (default is `false`) + @property {React.Children} [children] - content of the vertical box + @description + A vertical `Vpack` box with a clickable head label to fold/unfold its content. +*/ +export function Folder( { settings, defaultUnfold=false, indent=18, label, title, children } ) +{ + const [ unfold , setUnfold ] = Dome.useState( settings, defaultUnfold ); + const icon = unfold ? 'TRIANGLE.DOWN' : 'TRIANGLE.RIGHT' ; + const onClick = () => setUnfold( !unfold ); + return ( + <Vpack> + <Hpack onClick={onClick}><Title icon={icon} label={label} title={title} /></Hpack> + <Vpack style={{ marginLeft:indent }}> + { unfold && children } + </Vpack> + </Vpack> + ); +} + +// -------------------------------------------------------------------------- + +export default { Hpack, Vpack, Hbox, Vbox, Hfill, Vfill, + Space, Filler, Scroll, Grid, Folder }; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/layout/dispatch.js b/Ivette/src/dome/src/renderer/layout/dispatch.js new file mode 100644 index 0000000000000000000000000000000000000000..fd40b802d3f3c5ad04dd574fe521b2533dbd6dbc --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/dispatch.js @@ -0,0 +1,118 @@ +// -------------------------------------------------------------------------- +// --- Dispatch Layout +// -------------------------------------------------------------------------- + +/** @module dome/layout/dispatch + @description + +This module allow to declare components anywhere in a component hierarchy +and to render them a totally different place. + +You shall wrap dispatched components inside a `<Dispatch.Item>` container, +and render them wherever you want with `<Dispatch.Render>`. Each target +place can display only one uniquely identified item. + +This can be also used to display some item among many in one unique place. +*/ + +import _ from 'lodash' ; +import React from 'react'; +import Dome from 'dome' ; + +// -------------------------------------------------------------------------- +// --- Global Dispatcher +// -------------------------------------------------------------------------- + +const EVENT = (id) => 'dome.dispatch.' + id ; +const ITEMS = {}; + +const getItem = (id) => { + let item = ITEMS[id]; + if (!item) item = ITEMS[id] = { + id, evt: EVENT(id) + }; + return item; +}; + +const trigger = (item) => { + if (item.rendered) { + item.rendered = false ; + setImmediate(() => Dome.emit(item.evt)); + } +}; + +const setItem = (id,children) => { + let item = getItem(id); + item.content = children ; + trigger(item); +}; + +const removeItem = (id) => { + let item = getItem(id); + item.content = null ; + trigger(item); +}; + +// -------------------------------------------------------------------------- +// --- Dispatched Items +// -------------------------------------------------------------------------- + +/** + @class + @summary Define dispatched item + @property {string} id - the item _global_ unique identifier + @property {React.Children} {children} - item contents + @description + Declare the content of some dispatched item. + Each item identifier shall be assigned once from the mounted + hierarchy of components. Otherwize, the content that would be + displayed is totally unpredictable. +*/ +export function Item({ id, children }) +{ + React.useEffect(() => { + setItem(id,children); + return () => removeItem(id); + }); + return null; +} + +// -------------------------------------------------------------------------- +// --- Render Targets +// -------------------------------------------------------------------------- + +/** + @class + @summary Render dispatched item + @property {string} id - the item _global_ unique identifier to render + @property {function|React.Children} {children} - conditional or alternative content (default: `null`) + @description + Render the content of some dispatched item. + In case multiple of rendering, the children elements would be shared + among several places, with unpredicatable behavior. + + If the render element has a function as children, it is passed the content of the + item, or undefined. This allows for conditional rendering, depending on whether the item + has been specified somewhere in the hierarchy or not. + + Otherwized, when the item is not specified, the render element display + its own content, if any. +*/ +export function Render({ id, children=null }) +{ + Dome.useUpdate(EVENT(id)); + let item = getItem(id); + item.rendered = true ; + if (typeof(children)==='function') + return children(item.content); + else { + let content = item.content || children ; + return content && <React.Fragment>{content}</React.Fragment>; + } +} + +// -------------------------------------------------------------------------- + +export default { Item, Render }; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/layout/forms.css b/Ivette/src/dome/src/renderer/layout/forms.css new file mode 100644 index 0000000000000000000000000000000000000000..23a1712dc346d0bf66214dcf09bae04ded0a4c44 --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/forms.css @@ -0,0 +1,254 @@ +/* -------------------------------------------------------------------------- */ +/* --- Form Containers --- */ +/* -------------------------------------------------------------------------- */ + +/* Main Form */ +.dome-xForm-grid +{ + flex: 1 1 auto; + overflow: auto; + display: grid; + padding: 12px 32px; + grid-template-columns: [left] auto [field] auto [right] ; + grid-gap: 4px 12px; + grid-auto-rows: auto; + grid-auto-flow: row; + align-items: start; + align-content: start; + justify-content: start; +} + +/* Field List */ +.dome-xForm-list +{ + display: grid; + grid-template-columns: [field] auto [right] ; + grid-gap: 4px ; + grid-auto-rows: auto; + grid-auto-flow: row; + align-items: start; +} + +/* Block Container */ +.dome-xForm-block +{ + margin-bottom: 6px ; + margin-top: 6px ; + position: relative ; + grid-column-start: left ; + grid-column-end: right ; + justify-self: start ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Fields --- */ +/* -------------------------------------------------------------------------- */ + +/* Label */ +.dome-xForm-label +{ + position: relative ; + grid-column-start: left ; + grid-column-end: field ; + justify-self: end ; +} + +.dome-xForm-section +{ + margin-bottom: 6px ; + position: relative ; + left: -6px ; + grid-column-start: left ; + grid-column-end: right ; + justify-self: start ; +} + +.dome-xForm-section .dome-disabled { + color: #aaa ; +} + +.dome-xForm-hsep +{ + grid-column-start: left ; + grid-column-end: right ; + height: 6px ; +} + +.dome-xForm-fold +{ + position: absolute ; + top: 2px ; + fill: #888 ; + left: -14px ; +} + +.dome-xForm-block .dome-xForm-label +{ + display: none ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Field --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xForm-field +{ + position: relative ; + grid-column-start: field ; + grid-column-end: right ; + justify-self: start ; +} + +.dome-xForm-label.dome-disabled, .dome-xForm-field.dome-disabled +{ + color: #aaa ; + opacity: 0.9 ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Errors --- */ +/* -------------------------------------------------------------------------- */ + +/* Error Icon */ +.dome-xForm-error +{ + position: absolute ; + top: -1px ; + fill: darkorange ; + margin-left: 6px ; +} + +/* Error Warning */ +.dome-xForm-warning +{ + visibility: hidden ; + position: absolute ; + top: 3px ; + color: darkorange ; + margin-left: 4px ; + font-size: smaller ; +} + +/* Hovered Warning */ +.dome-xForm-error:hover .dome-xForm-warning +{ + visibility: visible ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Text Fields --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xForm-text-field +{ + font-size: 10pt ; + width: 180px ; + padding-top: 1px ; + padding-bottom: 1px ; + padding-right: 4px ; + padding-left: 4px ; +} + +.dome-xForm-textarea-field +{ + border-color: #d6d6d6 ; + font-size: 10pt ; + padding-top: 2px ; + padding-bottom: 2px ; + padding-right: 4px ; + padding-left: 4px ; +} + +.dome-xForm-field.dome-disabled .dome-xForm-textarea-field +{ + opacity: 0.6 ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Number Fields --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xForm-number-field +{ + text-align: right ; + padding-right: 12px ; + padding-left: 12px ; + width: 80px ; +} + +.dome-xForm-spinner-field +{ + text-align: right ; + padding-left: 12px ; + width: 80px ; +} + +.dome-xForm-units +{ + color: #888 ; + font-size: smaller ; + margin-left: 4px ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Sliders --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xForm-slider-field +{ + padding-right: 12px ; + padding-left: 12px ; + width: 120px ; +} + +.dome-xForm-slider-value +{ + position: relative ; + top: -4px ; +} + +.dome-xForm-slider-hide +{ + opacity: 0.0 ; + transition: opacity 0.5s ease-in 0.1s ; +} + +.dome-xForm-slider-show +{ + transition: none ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Date & Time --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xForm-date-field +{ + text-align: right ; + width: 137px ; +} + +.dome-xForm-time-field +{ + text-align: right ; + width: 109px ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Color --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xForm-color-field +{ + position: relative ; + top: -1px ; + height: 21px ; + width: 32px ; +} + +.dome-disabled .dome-xForm-color-field +{ + opacity: 0.2 ; +} + +/* -------------------------------------------------------------------------- */ diff --git a/Ivette/src/dome/src/renderer/layout/forms.js b/Ivette/src/dome/src/renderer/layout/forms.js new file mode 100644 index 0000000000000000000000000000000000000000..2753c40bff6ebda733cfc0454f37162d3568a7da --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/forms.js @@ -0,0 +1,1147 @@ +// -------------------------------------------------------------------------- +// --- Form Layout +// -------------------------------------------------------------------------- + +/** @module dome/layout/forms */ + +import React from 'react' ; +import Dome from 'dome' ; +import { SVG } from 'dome/controls/icons' ; +import { Checkbox, Radio, Select as Selector } from 'dome/controls/buttons' ; +import _ from 'lodash' ; +import './forms.css' ; + +// -------------------------------------------------------------------------- +// --- Utilities +// -------------------------------------------------------------------------- + +const Context = React.createContext(); + +const SELECT = (props,context) => props === undefined ? context : props ; +const ACCESS = (props,context,path) => props === undefined ? _.get(context,path) : props ; +const CONDITION = (context,cond,undef) => { + switch(typeof(cond)) { + case 'undefined': + return undef; + case 'string': + case 'array': + return _.get(context,cond); + default: + return cond; + } +}; + +const COMBINE = (a,b) => { + if (a === undefined) return b; + if (b === undefined) return a; + return (...args) => { a(...args); b(...args); }; +}; + +const UPDATE = (value,error,path,callback) => callback && + ((v,e) => { + let update = value || {} ; + _.set( update, path, v ); + let errors ; + if (error || e) { + errors = error || {} ; + _.set( errors, path, e ); + if (!_.find(errors)) + errors = undefined; + } + callback(update,errors); + }); + +const CHECK = (validate,v) => { + if (typeof(validate) === 'function') + return validate(v); + if (_.isRegExp(validate)) + return validate.test(v); + return validate; +}; + +const ERROR = (validate,warning,v) => { + let ok = CHECK(validate,v); + switch(ok) { + case undefined: + case true: + return undefined ; + default: + return ok || warning ; + } +}; + +const VALIDATE = (validate,warning,callback) => { + if (!validate) return callback; + return ((v,e) => { + if (!callback) return; + else if (v===undefined || e) callback(v,e); + else { + let e = ERROR(validate,warning,v); + callback(v,e); + } + }); +}; + +const RENDER = (children,context) => ( + children ? + ( typeof(children)==='function' + ? children(context) + : children ) + : null +); + +const ONCHANGE = (onChange) => + typeof(onChange)==='function' + ? (evt) => onChange(evt.target.value) + : undefined ; + +const CLASSES = (...args) => _.filter(args).join(' '); + +// -------------------------------------------------------------------------- +// --- Filtering DataFlow +// -------------------------------------------------------------------------- + +const FILTER_ERROR = (err) => + err ? _.toString(err) : 'Invalid input, enter a new value to fix' +; + +class FILTER extends React.Component +{ + + constructor(props) { + super(props); + this.state = this.forward(); + this.onChange = this.onChange.bind(this); + if (props.period) + this.backward = _.debounce(this.backward,props.period); + } + + componentDidUpdate(prevProps) { + const props = this.props ; + if (props.value !== prevProps.value || + props.error !== prevProps.error) + this.setState(this.forward()); + } + + onChange(value,error) { + this.setState({value,error}); + this.backward(value,error); + } + + forward() { + try { + const { input , value , error } = this.props ; + return { value: input ? input(value) : value, error }; + } catch(err) { + return { value: undefined, error: FILTER_ERROR(err) }; + } + }; + + backward(v,e) + { + const { output, onChange } = this.props ; + try { + if (output) v = output(v); + } catch(err) { + this.setState({error: FILTER_ERROR(err)}); + return; + } + if (onChange) onChange(v,e); + } + + render() { + const { disabled, children } = this.props ; + const { value, error } = this.state ; + const context = { onChange: this.onChange, disabled, value, error }; + return ( + <Context.Provider value={context}> + {RENDER(children,context)} + </Context.Provider> + ); + } + +} + +// -------------------------------------------------------------------------- +// --- Generic Field +// -------------------------------------------------------------------------- + +const PERIOD = (latency) => { + switch(typeof(latency)) { + case 'undefined': return 0; + case 'number': return latency; + default: + return latency ? 600 : 0 ; + } +}; + +/** + @class + @summary Generic context wrapper for field values + @property {string} [path] - select a property in the context value (and error) + @property {any} [value] - set the inherited or edited value + @property {any} [error] - set the inherited or edited error + @property {function} [input] - pre-processing of input values (after `path` selection) + @property {function} [output] - post-processing of output values (before `path` update) + @property {function} [onChange] - callback for edited values and errors + @property {boolean|string|function} [disabled] - disabled field (default is `false`) + @property {boolean|string|function} [enabled] - conditional enabling (default is `true`) + @property {boolean|string|function} [visible] - conditional rendering (default is `true`) + @property {boolean|string|function} [hidden] - conditional hidding (default is `false`) + @property {boolean|regexp|function} [validate] - validation of the updated value + @property {string} [warning] - error message in case `validate` returns `false` + @property {boolean|number} [latency] - delay validation and propagation callbacks + @property {boolean} [state] - maintain a locally edited state (default is `false`) + @property {React.children|function} [children] - elements to render in the new context + @description + +Forms are based on a local context that can be modified by using this multi-purposed +component. The local context consists of: +- `value`: the currently edited value; +- `error`: the last emitted error for this value; +- `onChange(value[,error])`: the callback to be used on updates; +- `disabled`: whether this value can be edited or not. + +Undefined properties are inherited from the context. If the `path` property is defined, +the `<Select>` component extract the associated value and error from the inherited context. +When both `path` and `value` properties are defined, the specified value takes the precedence. +Access and updates of `path` are performed with the lodash `_.get()` and `_.set()` functions. +Although, the `<Select>` might perform in-place modifications of previous object or array value. +Use `_.cloneDeep()` to build a (recursive) copy of some value. + +Before being processed downward, the inherited or selected value can be transformed. +The `input` function is applied on incomming value, and `output` function is applied +on updated values. + +The specified callback `onChange` is invoked with the updated value and error. The callback +inherited from the context is _also_ notified. When the `path` property is set, +the contextual callback will be notified with the full context values and errors, +updated with local changes to the selected path. + +The validation callback is invoked on updates. It shall return `undefined` +or a string explaining why the value is invalid. Boolean are also accepted, +leading to an error string defined by the `warning` property, which defaults to `"Invalid field"`. +Alternatively, `validate` can be a regexp that is tested against the value. +For instance, to accept only numbers, you can use `validate={/^[0-9]+$/}` +and `warning='Must be a number'`. + +To avoid too many callback and validation checks, typically for text-based fields, it is possible to +set a latency period before validating the input and emitting the callback. In such a case, a transient +local state for value and error is maintained until the edited value is stabilized, before performing +validation and upward propagation. The default lantency period is 600ms. + +It is possible to conditionally enabling, disabling or hiding the content by using +the `disabled`, `enabled`, `visible` and `hidden` properties. They all can be boolean values, +or path in or function of the inherited value. For instance, `<Select path='f.g' enabled='f.ok'/>` +would allow to edit the value `value.f.g`, but disable edition when `value.f.ok` is falsy. +Remark that if the inherited context is disabled, the selected content is disabled too. + +When latency, or input/output transformation are required, a local state is maintained. +Otherwized, context and callbacks are propagated upward and backward. However, you can +force this local state to be maintained by specifying the property `state` to `true`. +This shall be used only at top-level for implementing a non-controlled component. + +*/ +export function Select({ + path, latency, + defaultValue:def, + children, state, + ...props +}) { + let context = React.useContext( Context ); + if (!CONDITION(context.value,props.visible,true) || + CONDITION(context.value,props.hidden,false)) + return null; + let disabled = context.disabled + || CONDITION(context.value,props.disabled,false) + || !CONDITION(context.value,props.enabled,true); + let value,error,callback ; + if (path) { + value = ACCESS( props.value , context.value , path ); + error = ACCESS( props.error , context.error , path ); + if (!disabled) + callback = UPDATE(context.value,context.error,path,context.onChange); + } else { + value = SELECT( props.value , context.value ); + error = SELECT( props.error , context.error ); + if (!disabled) + callback = context.onChange; + }; + + let onChange ; + if (!disabled) { + onChange = VALIDATE( props.validate, props.warning, + COMBINE(props.onChange,callback) ); + } + + if (props.validate && value && !error) { + error = ERROR( props.validate, props.warning, value ); + } + + let newContext = { value,error, disabled, onChange }; + if (state || latency || props.input || props.output) { + return ( + <FILTER period={PERIOD(latency)} + input={props.input} + output={props.output} + {...newContext}> + {children} + </FILTER> + ); + } else + return ( + <Context.Provider value={newContext}> + {RENDER(children,newContext)} + </Context.Provider> + ); +} + +// -------------------------------------------------------------------------- +// --- Form Container +// -------------------------------------------------------------------------- + +/** + @class + @summary Form Container + @property {string} [className] - Container additional class + @property {object} [style] - Container additional style + @property {object} [value] - Set the form context value + @property {object} [error] - Set the form context error + @property {boolean} [disabled] - Disables the form (default is `false`) + @property {onChange} [function] - Callback to updated `(value,error)` + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @property {React.children|function} [children] - Fields to populate the form + @description + + Setup a form context with the provided values. + A local state is maintained unless you fully control the `value` and `error` + properties. You may also specify any other properties of the + [Select](module-dome_layout_forms.Select.html) filter component. + +*/ + +export const Form = ({className,style,...props}) => + ( + <div className={CLASSES('dome-xForm-grid',className)}> + <Context.Provider value={{}}> + <Select state {...props}/> + </Context.Provider> + </div> + ); + +// -------------------------------------------------------------------------- +// --- Generic Error Badge +// -------------------------------------------------------------------------- + +const ERROR_MSG = (error) => { + switch(typeof(error)) { + case 'undefined': + return undefined ; + case 'string': + return error; + case 'object': + case 'array': + var n = 0; + _.forEach(error,(err) => { if (err) n++; }); + if (n==1) return 'Invalid field' ; + if (n>1) return n + ' Invalid fields' ; + return undefined ; + default: + return _.toString(error); + } +}; + +/** + @class + @summary Warning badge with description + @property {string} [warn] - the short message (hovered) + @property {number} [offset] - the label offset (Cf. field) + @property {any} [error] - the error description (in tooltip) + @property {full} [boolean] - full error message on error (no tooltip, default `false`) + @description + Display a warning badge with a tooltip when the `error` is not + undefined. Otherwize, renders nothing. +*/ +export const Warning = ({full,warn,offset,error,width}) => { + let msg = ERROR_MSG(error); + return msg ? ( + <div className='dome-xIcon dome-xForm-error' + style={{top: (offset-2)}} > + <SVG id='WARNING' size={11} title={full ? undefined : msg}/> + {(full + ? <span className='dome-xForm-warning' style={{width: 'max-content'}}>{msg}</span> + : <span className='dome-xForm-warning'>{warn}</span> + )} + </div> + ) : null ; +}; + +// -------------------------------------------------------------------------- +// --- Section Container +// -------------------------------------------------------------------------- + +const TITLE_ENABLED = 'dome-text-title' ; +const TITLE_DISABLED = 'dome-text-title dome-disabled' ; + +/** + @class + @summary Expandable Section sub-form + @property {string} label - Section title + @property {string} [title] - Tooltip text + @property {string} [path] - Fields selection + @property {string} [settings] - User's settings for making fold/unfold state persistent + @property {boolean} [unfold] - Default fold/unfold state (default is `false`) + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @property {React.children|function} [children] - Section field content + @description + Wraps some fields inside a foldable section. + When unfolded, the section fields are not visible but still rendered. +*/ + +export function Section(props) +{ + + let [ unfold, setUnfold ] = Dome.useState(props.settings,props.unfold); + + const onSwitch = () => setUnfold(!unfold); + + const { label, title, path, children, ...otherProps } = props ; + + return ( + <Select path={path} {...otherProps}> + {(context) => ( + <React.Fragment> + <div className='dome-xForm-section'> + <div className='dome-xForm-fold' onClick={onSwitch}> + <SVG id={unfold?'TRIANGLE.DOWN':'TRIANGLE.RIGHT'} size={11}/> + </div> + <label className={ (path && context.disabled) ? TITLE_DISABLED : TITLE_ENABLED } + title={title}> + {label} + </label> + { unfold && path && <Warning full error={context.error}/> } + </div> + { unfold && RENDER(children,context) } + { unfold && <div className='dome-xForm-hsep'/> } + </React.Fragment> + )} + </Select> + ); +} + +// -------------------------------------------------------------------------- +// --- Block Container +// -------------------------------------------------------------------------- + +/** + @class + @summary Full width form block + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @property {React.children|function} [children] - Block content + @description + Wraps its children inside the entire width of the form. +*/ + +export const Block = ({ children, ...props }) => ( + <Select {...props}> + {(context) => ( + <div className='dome-xForm-block'> + {RENDER(children,context)} + </div>)} + </Select> +); + +// -------------------------------------------------------------------------- +// --- Generic Fields +// -------------------------------------------------------------------------- + +let fid = 0 ; + +const LABEL_ENABLED = 'dome-xForm-label dome-text-label'; +const LABEL_DISABLED = 'dome-xForm-label dome-text-label dome-disabled'; +const FIELD_ENABLED = 'dome-xForm-field dome-text-label'; +const FIELD_DISABLED = 'dome-xForm-field dome-text-label dome-disabled'; + +/** + @class + @summary Generic Custom Field + @property {string} [label] - Field label + @property {string} [title] - Field tooltip text + @property {number} [offset] - Vertical label offset (for baseline alignment) + @property {boolean|string} [warn] - Display errors (default: `true`) + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @property {React.children|function} [children] - Custom field content + @description + +Field layout inside a Form container. +The custom field component is positionned on the left of the label, right-aligned. +The label itself is left-aligned with the other fields. + +The Field component setup a [Select](module-dome_layout_forms.Select.html) +filter for your custom component. Additionnaly, if you use a custom function rendering, +the context is enriched with the `id` of the `<label/>` DOM element of the label, that +you can use with `<input htmlFor={id}/>` as custom field component. + +A warning badge is displayed on the right of your custom component, unless `warn:false` +is specified. When hovered, the badge displays `Error` or the specified `string`. When +hovered for a while, a full description of the error is displayed in a tooltip. +*/ + +export class Field extends React.Component +{ + + constructor(props) { + super(props); + this.id = props.id || 'DOME$' + (fid++) ; + } + + render() { + const id = this.id ; + const { label, title, offset=1, children, warn='Error', ...props } = this.props ; + return ( + <Select {...props}> + {(context) => ( + <React.Fragment> + <label className={context.disabled ? LABEL_DISABLED : LABEL_ENABLED} + style={{top: offset}} + htmlFor={id} + title={title}> + {label} + </label> + <div className={context.disabled ? FIELD_DISABLED : FIELD_ENABLED}> + {RENDER(children,Object.assign(context,{id}))} + {warn && <Warning offset={offset} warn={warn} error={context.error}/>} + </div> + </React.Fragment> + )} + </Select> + ); + } + +} + +// -------------------------------------------------------------------------- +// --- Field List Container +// -------------------------------------------------------------------------- + +/** + @class + @summary Field List Container + @property {string} [label] - Field label + @property {string} [title] - Field tooltip text + @property {boolean} [warn] - Display errors (default: `false`) + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @property {React.children|function} [children] - List field content + @description + +Render its field children in a right-aligned list on the left of the label. +Typically designed for a list of checkboxes and radio buttons. + +Inside the field list, the field-label column no more exists. Hence, text field labels are +typically never displayed when placed in a field list. + +*/ +export const FieldList = ({ label, title, warn=false, children, ...props }) => ( + <Field label={label} title={title} warn={warn} {...props}> + <div className='dome-xForm-list'> + {children} + </div> + </Field> +); + +// -------------------------------------------------------------------------- +// --- Text Field +// -------------------------------------------------------------------------- + +/** + @class + @summary Text Field + @property {string} [label] - Field label + @property {string} [title] - Field tooltip text + @property {string} [placeholder] - Input field place holder + @property {string} [className] - Input field additional class + @property {object} [style] - Input field additional style + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @description + Field with a Text Input element. The default latency is set to 600ms. +*/ +export const FieldText = ({ className, style, latency=true, placeholder, ...props }) => ( + <Field offset={4} latency={latency} {...props}> + {({id,value,disabled,onChange}) => ( + <input id={id} + type='text' + value={value || ''} + className={CLASSES('dome-xForm-text-field',className)} + style={style} + disabled={disabled} + placeholder={placeholder} + onChange={ONCHANGE(onChange)} + /> + )} + </Field> +); + +// -------------------------------------------------------------------------- +// --- Code Field +// -------------------------------------------------------------------------- + +/** + @class + @summary Monospaced Text Field + @property {string} [label] - Field label + @property {string} [title] - Field tooltip text + @property {string} [placeholder] - Input field place holder + @property {string} [className] - Input field additional class + @property {object} [style] - Input field additional style + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @description + Field with a Text Input element. The default latency is set to 600ms. +*/ +export const FieldCode = ({ className, style, latency=true, placeholder, ...props }) => ( + <Field offset={4} latency={latency} {...props}> + {({id,value,disabled,onChange}) => ( + <input id={id} + type='text' + value={value || ''} + className={CLASSES('dome-xForm-text-field dome-text-code',className)} + style={style} + disabled={disabled} + placeholder={placeholder} + onChange={ONCHANGE(onChange)} + /> + )} + </Field> +); + +// -------------------------------------------------------------------------- +// --- TextArea Field +// -------------------------------------------------------------------------- + +/** + @class + @summary Text Area Field + @property {string} [label] - Field label + @property {string} [title] - Field tooltip text + @property {string} [className] - Input field additional class + @property {string} [placeholder] - Input field place holder + @property {number} [cols] - Number of columns (default 35, min 5) + @property {number} [rows] - Number of lines (default 5, min 2) + @property {object} [style] - Input field additional style + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @description + Field with a Text Input element. The default latency is set to 900ms. +*/ +export const FieldTextArea = ({ className, style, cols=35, rows=5, + placeholder, latency=900, ...props }) => ( + <Field offset={4} latency={latency} {...props}> + {({id, value, disabled, onChange }) => ( + <textarea id={id} + type='text' + className={CLASSES('dome-xForm-textarea-field',className)} style={style} + disabled={disabled} + wrap='off' spellchecker='true' + value={value || ''} + cols={Math.max(5,cols)} + rows={Math.max(1,rows-1)} + placeholder={placeholder} + onChange={ONCHANGE(onChange)} + /> + )} + </Field> +); + +// -------------------------------------------------------------------------- +// --- CodeArea Field +// -------------------------------------------------------------------------- + +/** + @class + @summary Text Area Field + @property {string} [label] - Field label + @property {string} [title] - Field tooltip text + @property {string} [className] - Input field additional class + @property {string} [placeholder] - Input field place holder + @property {number} [cols] - Number of columns (default 35, min 5) + @property {number} [rows] - Number of lines (default 5, min 2) + @property {object} [style] - Input field additional style + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @description + Field with a Text Input element. The default latency is set to 900ms. +*/ +export const FieldCodeArea = ({ className, style, cols=35, rows=5, + placeholder, latency=900, ...props }) => ( + <Field offset={4} latency={latency} {...props}> + {({id, value, disabled, onChange }) => ( + <textarea id={id} + ref={this.area} + type='text' + className={CLASSES('dome-xForm-textarea-field dome-text-code',className)} style={style} + disabled={disabled} + wrap='off' spellchecker='false' + value={value || ''} + cols={Math.max(5,cols)} + rows={Math.max(1,rows-1)} + placeholder={placeholder} + onChange={ONCHANGE(onChange)} + /> + )} + </Field> +); + +// -------------------------------------------------------------------------- +// --- Number Field +// -------------------------------------------------------------------------- + +const PARSE_NUMBER = (v,debug) => { + let n = parseFloat(v); + if (Number.isNaN(n)) { + let msg = "Invalid number format"; + if (debug) { + let txt = _.toString(v); + if (txt.length > 20) txt = txt.substring(0,19)+'…' ; + msg += ": «" + txt + "»" ; + } + throw msg ; + } + return n; +}; +const TEXT_OF_NUMBER = (v) => v===undefined ? '' : PARSE_NUMBER(v,true).toLocaleString('en'); +const NUMBER_OF_TEXT = (s) => s==='' ? undefined : PARSE_NUMBER(s.replace(/[ ,]/g,'')); + +/** + @class + @summary Number Field + @property {string} [label] - Field label + @property {string} [title] - Field tooltip text + @property {string} [placeholder] - Input field place holder + @property {string} [units] - Number units or currency + @property {string} [className] - Input field additional class + @property {object} [style] - Input field additional style + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @description + Field to edit number values with a Text Input element. + The default latency is set to 600ms. Numbers are rendered in the english locale, grouping thousands + with «,». The currency or units is displayed on the right of the field. The edited text + is converted back and forth to number values with `parseFloat`. +*/ +export const FieldNumber = + ({ className, style, latency=true, units, placeholder, ...props }) => ( + <Field latency={latency} + input={TEXT_OF_NUMBER} + output={NUMBER_OF_TEXT} + {...props}> + {({id,value,disabled,onChange}) => ( + <React.Fragment> + <input id={id} + type='text' + value={value || ''} + className={CLASSES('dome-xForm-number-field',className)} + style={style} + disabled={disabled} + placeholder={placeholder} + onChange={ONCHANGE(onChange)} + /> + {units && <label className='dome-text-label dome-xForm-units'>{units}</label>} + </React.Fragment> + )} + </Field> + ); + +// -------------------------------------------------------------------------- +// --- Spinner field +// -------------------------------------------------------------------------- + +const PARSE_INT = (v,debug) => { + let n = parseInt(v); + if (Number.isNaN(n)) { + let msg = "Invalid number format"; + if (debug) { + let txt = _.toString(v); + if (txt.length > 20) txt = txt.substring(0,19)+'…' ; + msg += ": «" + txt + "»" ; + } + throw msg ; + } + return n; +}; +const TEXT_OF_INT = (v) => v===undefined ? '' : PARSE_INT(v,true); +const INT_OF_TEXT = (s) => s==='' ? undefined : PARSE_INT(s); + +const INT_RANGE = (min,max,warning) => (v) => + (min <= v && v <= max) ? undefined : + warning || 'Range ' + min + '…' + max ; + +/** + @class + @summary Spinner Field + @property {string} [label] - Field label + @property {string} [title] - Field tooltip text + @property {string} [placeholder] - Input field place holder + @property {string} [units] - Number units or currency + @property {number} [min] - Minimum value (default: 0) + @property {number} [max] - Maximum value (default: 1000) + @property {number} [step] - Stepper increment + @property {string} [warning] - Out of bound message (default is explaining the range) + @property {string} [className] - Input field additional class + @property {object} [style] - Input field additional style + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @description + Field to edit integer numbers with a spinner element. + The default latency is set to 600ms. +*/ +export const FieldSpinner = + ({ className, style, latency=true, units, placeholder, min=0, max=1000, step, ...props }) => ( + <Field latency={latency} + input={TEXT_OF_INT} + output={INT_OF_TEXT} + validate={INT_RANGE(min,max)} + {...props}> + {({id,value,disabled,onChange}) => ( + <React.Fragment> + <input id={id} + type='number' + value={ value === undefined ? '' : value } + className={CLASSES('dome-xForm-spinner-field',className)} + style={style} + min={min} + max={max} + step={step} + disabled={disabled} + placeholder={placeholder} + onChange={ONCHANGE(onChange)} + /> + {units && <label className='dome-text-label dome-xForm-units'>{units}</label>} + </React.Fragment> + )} + </Field> + ); + +// -------------------------------------------------------------------------- +// --- Slider field +// -------------------------------------------------------------------------- + +const RESET_RANGE = (onChange,min,max) => + onChange && (() => onChange(Math.round( min + (max - min) / 2 ))); + +const SHOW_VALUE = (show,v) => { + if (typeof(show)==='function') + return show(v); + if (v>0) return '+' + v ; + if (v<0) return v ; + return undefined ; +}; + +const SLIDER_VALUE = 'dome-text-label dome-xForm-units dome-xForm-slider-value ' ; +const SHOW_SLIDER = SLIDER_VALUE + 'dome-xForm-slider-show' ; +const HIDE_SLIDER = SLIDER_VALUE + 'dome-xForm-slider-hide' ; + +class REVEAL extends React.Component { + + constructor(props) { + super(props); + this.state = { shown: false }; + this.fadeOut = _.debounce(this.fadeOut,PERIOD(props.latency)); + } + + componentDidUpdate(prevProps) { + if (prevProps.value !== this.props.value) { + this.fadeIn(); + this.fadeOut(); + } + } + + fadeIn() { + if (!this.state.shown) this.setState({ shown: true }); + } + + fadeOut() { + if (this.state.shown) this.setState({ shown: false }); + } + + render() { + const { show, value } = this.props ; + const { shown } = this.state ; + return ( + <label className={shown ? SHOW_SLIDER : HIDE_SLIDER}>{SHOW_VALUE(show,value)}</label> + ); + } + +} + + +/** + @class + @summary Slider Field + @property {string} [label] - Field label + @property {string} [title] - Field tooltip text + @property {number} [min] - Minimum value (default: -24) + @property {number} [max] - Maximum value (default: 24) + @property {number} [step] - Stepper increment (default: 1) + @property {boolean} [reset] - Reset on double click (default is `true`) + @property {boolean|function} [show] - Display the selected value on the right (default is `true`) + @property {string} [className] - Input field additional class + @property {object} [style] - Input field additional style + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @description + Field to edit integer numbers with a spinner element. + The default latency is set to 600ms. Double click on the slider reset it + to its median value, unless `toreset` is specified. The `show` flag can be set to display + the actual value when the slider is dragged. Alternatively, a function can be provided + for computing the text to display for the dragged value. +*/ +export const FieldSlider = + ({ className, style, latency=true, min=-24, max=24, step=1, reset=true, show=true, ...props }) => ( + <Field latency={latency} + input={TEXT_OF_INT} + output={INT_OF_TEXT} + {...props}> + {({id,value,disabled,onChange}) => ( + <React.Fragment> + <input id={id} + type='range' + value={ value === undefined ? '' : value } + className={CLASSES('dome-xForm-slider-field',className)} + style={style} + min={min} + max={max} + step={step} + disabled={disabled} + onDoubleClick={reset ? RESET_RANGE(onChange,min,max) : undefined} + onChange={ONCHANGE(onChange)} + /> + {show && <REVEAL latency={latency} show={show} value={value}/>} + </React.Fragment> + )} + </Field> + ); + +// -------------------------------------------------------------------------- +// --- Date Field +// -------------------------------------------------------------------------- + +/** + @class + @summary Date Field + @property {string} [label] - Field label + @property {string} [title] - Field tooltip text + @property {string} [min] - Minimum date (default to `undefined`) + @property {string} [max] - Maximum date (default to `undefined`) + @property {string} [className] - Input field additional class + @property {object} [style] - Input field additional style + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @description + Field with a Date Input element. The default latency is set to 600ms. + The date is presented in english locale, with format `mm/dd/yyyy`, but the internal value + is a string compatible with javascript `Date('yyyy-dd-mm')` format. +*/ +export const FieldDate = ({ className, style, latency=true, min, max, ...props }) => ( + <Field latency={latency} {...props}> + {({id,value,disabled,onChange}) => ( + <input id={id} + type='date' + value={value || ''} min={min} max={max} + className={CLASSES('dome-xForm-date-field',className)} + style={style} + disabled={disabled} + onChange={ONCHANGE(onChange)} + /> + )} + </Field> +); + +// -------------------------------------------------------------------------- +// --- Time Field +// -------------------------------------------------------------------------- + +/** + @class + @summary Time Field + @property {string} [label] - Field label + @property {string} [title] - Field tooltip text + @property {string} [min] - Minimum time (default to `undefined`) + @property {string} [max] - Maximum time (default to `undefined`) + @property {string} [className] - Input field additional class + @property {object} [style] - Input field additional style + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @description + Field with a Time Input element. The default latency is set to 600ms. + The time is presented in english locale, but its internal value is a string 'hh:mm' + on 24h per day basis. This internal format can be used to form a valid javascript + `Date('yyyy-mm-ddThh:mm')` object. +*/ +export const FieldTime = ({ className, style, latency=true, min, max, ...props }) => ( + <Field latency={latency} {...props}> + {({id,value,disabled,onChange}) => ( + <input id={id} + type='time' + value={value || ''} min={min} max={max} + className={CLASSES('dome-xForm-time-field',className)} + style={style} + disabled={disabled} + onChange={ONCHANGE(onChange)} + /> + )} + </Field> +); + +// -------------------------------------------------------------------------- +// --- Date Field +// -------------------------------------------------------------------------- + +/** + @class + @summary Color Field + @property {string} [label] - Field label + @property {string} [title] - Field tooltip text + @property {string} [className] - Input field additional class + @property {object} [style] - Input field additional style + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @description + Field with a Text Input element. The default latency is set to 600ms. +*/ +export const FieldColor = ({ className, style, latency=true, ...props }) => ( + <Field latency={latency} {...props}> + {({id,value,disabled,onChange}) => ( + <input id={id} + type='color' + value={value || '#ffffff'} + className={CLASSES('dome-xForm-color-field',className)} + style={style} + disabled={disabled} + onChange={ONCHANGE(onChange)} + /> + )} + </Field> +); + +// -------------------------------------------------------------------------- +// --- Select Field +// -------------------------------------------------------------------------- + +/** + @class + @summary Select Field + @property {string} [label] - Field label + @property {string} [title] - Field tooltip text + @property {string} [placeholder] - Selector placeholder + @property {string} [className] - Input field additional class + @property {object} [style] - Input field additional style + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @property {option|optgroup} [children] - HTML options of the `<select>` element + @description + Field with a Select element. Children must be standard `<option>` and `<optgroup>` elements. + Typically: + + ``` + <FieldSelect placeholder='Choose a value'> + <option value='A'>Item A</option> + <option value='B'>Item B</option> + <option value='C'>Item C</option> + </FieldSelect> + ``` + +*/ +export const FieldSelect = ({ className, style, children, placeholder, ...props }) => ( + <Field {...props}> + {({id,value,disabled,onChange}) => ( + <Selector id={id} + className={className} + style={style} + placeholder={placeholder} + value={value} + onChange={onChange} > + {children} + </Selector> + )} + </Field> +); + +// -------------------------------------------------------------------------- +// --- CheckBox Field +// -------------------------------------------------------------------------- + +/** + @class + @summary Checkbox Field + @property {string} [label] - Field label + @property {string} [title] - Field tooltip text + @property {boolean} [inverted] - Inverted value (incompatible with `input` and `output` properties) + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @description + A check box field. +*/ + +export const FieldCheckbox = ({ label, title, inverted, ...props }) => { + let transform = inverted ? (v) => !v : (v) => !!v ; + return ( + <Select input={transform} output={transform} {...props}> + {({value,disabled,onChange}) => ( + <Checkbox className={disabled ? FIELD_DISABLED : FIELD_ENABLED} + label={label} title={title} + disabled={disabled} + value={value} onChange={onChange}/> + )} + </Select> + ); +}; + +// -------------------------------------------------------------------------- +// --- Radio Field +// -------------------------------------------------------------------------- + +/** + @class + @summary Radio Button Field + @property {string} [label] - Field label + @property {string} [title] - Field tooltip text + @property {any} [value] - Value associated with the radio button + @property {any} [...props] - [Select](module-dome_layout_forms.Select.html) properties + @description + A radio button field. + + <strong>Note:</strong> there is no need for using a radio group here, + since the selected value is taken from the context. +*/ + +export const FieldRadio = ({ label, title, value, ...props }) => { + return ( + <Select {...props}> + {({value:selection,disabled,onChange}) => ( + <Radio className={disabled ? FIELD_DISABLED : FIELD_ENABLED} + label={label} title={title} + disabled={disabled} + value={value} + selection={selection} + onSelection={onChange}/> + )} + </Select> + ); +}; + +// -------------------------------------------------------------------------- +// --- Exports +// -------------------------------------------------------------------------- + +export default { + Select, + Form, + Block, + Field, + Section, + FieldText, + FieldCode, + FieldTextArea, + FieldCodeArea, + FieldNumber, + FieldSpinner, + FieldSlider, + FieldDate, + FieldTime, + FieldColor, + FieldSelect, + FieldList, + FieldCheckbox, + FieldRadio +}; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/layout/frames.js b/Ivette/src/dome/src/renderer/layout/frames.js new file mode 100644 index 0000000000000000000000000000000000000000..d16aa614cf787a5b170f2a9e9ee4b4bf258ae7bb --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/frames.js @@ -0,0 +1,211 @@ +// -------------------------------------------------------------------------- +// --- Frames +// -------------------------------------------------------------------------- + +/** @module dome/layout/frames */ + +import React from 'react' ; +import Dome from 'dome' ; +import { dispatch } from 'dome/misc/register' ; +import { Vfill } from 'dome/layout/boxes' ; +import { SideBar } from 'dome/layout/sidebars' ; +import { ToolBar } from 'dome/layout/toolbars' ; +import { TabsBar , TabContent } from 'dome/layout/tabs' ; +import { Splitter } from 'dome/layout/splitters' ; + +const callbacks = (f,g) => (f ? (g ? (id) => { f(id); g(id); } : f ) : g ); + +// -------------------------------------------------------------------------- +// --- Frame Component +// -------------------------------------------------------------------------- + +/** + @class + @summary Main view with optional tabs, toolbar and sidebar. + @property {string} [settings] - User-setting base name for + persistent selection and customization + @property {string} [selectedTab] - Currently selected tab + @property {string} [selectedItem] - Currently selected sidebar item + @property {string} [defaultTab] - Default selected tab (see also default tab's property) + @property {string} [defaultItem] - Default selected item + @property {function} [onTabClose] - tab closing callback + @property {function} [onTabSelection] - tab selection callback + @property {function} [onItemSelection] - sidebar item selection callback + @property {boolean} [hideToolbar] - hide tool bar (default is `false`) + @property {boolean} [hideTabsbar] - hide tabs bar (default is `false`) + @description + + ##### Content + The Frame layout and its decorations are specified according to + the type of its children elements: + - [Tab](module-dome_layout_tabs.Tab.html), if any, will be rendered into an optional + [TabsBar](module-dome_layout_tabs.TabsBar.html) and the selected tab content + will be rendered into the main content of the frame. + - [Sidebar items](module-dome_layout_sidebars.html), if any, will be rendered + inside a sidebar on the left of the frame. + - [Toolbar items](module-dome_layout_toolbars.html), if any, + will be rendered inside a toolbar on top of the frame. + - The remaining elements will be rendered (inside a vertical box) into the + main content the frame, provided there is no defined tab. + + + ##### Callbacks + Both general callbacks and tab ones are invoked + when the user select or close a tab. The tab callbacks are invoked _before_ the + frame ones. + + + ##### Settings + When provided, user selection will be saved in user's settings + under the following keys (when relevant): + - `'<settings>.dome.tab'` tab selection + - `'<settings>.dome.item'` item selection + - `'<settings>.dome.sidebar'` position of side-bar splitter + - `'<settings>.dome.section'` visibility of side-bar sections +*/ + +export class Frame extends React.Component +{ + + constructor(props) + { + super(props); + const settings = props.settings ; + const derived = ( selected , user , def ) => + (selected || ( settings && Dome.getWindowSetting( settings + user ) ) || def) ; + var selectedTab = derived( props.selectedTab , '.dome.tab' , props.defaultTab ); + var selectedItem = derived( props.selectedItem , '.dome.item' , props.defaultItem ); + this.state = { selectedTab , selectedItem }; + this.handleSelectTab = this.handleSelectTab.bind(this); + this.handleSelectItem = this.handleSelectItem.bind(this); + } + + // -------------------------------------------------------------------------- + // --- Life Cycle + // -------------------------------------------------------------------------- + + componentWillMount() { + const onTabSelection = this.props.onTabSelection ; + if (onTabSelection) { + const stateId = this.state.selectedTab ; + const propsId = this.props.selectedTab ; + if (stateId !== propsId) setImmediate(() => onTabSelection( stateId )); + } + const onItemSelection = this.props.onItemSelection ; + if (onItemSelection) { + const stateId = this.state.selectedItem ; + const propsId = this.props.selectedItem ; + if (stateId !== propsId) setImmediate(() => onItemSelection( stateId )); + } + } + + componentDidUpdate() { + const tabid = this.props.selectedTab ; + if (tabid && this.state.selectedTab !== tabid) + this.setState( { selectedTab: tabid } ); + const itemid = this.props.selectedItem ; + if (itemid && this.state.selectedItem !== itemid) + this.setState( { selectedItem: itemid } ); + } + + // -------------------------------------------------------------------------- + // --- Update + // -------------------------------------------------------------------------- + + handleSelectTab(id) { + this.setState( { selectedTab: id } ); + const settings = this.props.settings ; + const onSelect = this.props.onTabSelection ; + settings && Dome.setWindowSetting( settings + '.dome.tab' , id ); + onSelect && onSelect( id ); + } + + handleSelectItem(id) { + this.setState( { selectedItem: id } ); + const settings = this.props.settings ; + const onSelect = this.props.onItemSelection ; + settings && Dome.setWindowSetting( settings + '.dome.item' , id ); + onSelect && onSelect( id ); + } + + // -------------------------------------------------------------------------- + // --- Rendering + // -------------------------------------------------------------------------- + + render() { + + const content = dispatch( this.props.children , { + tabsItems: 'DOME_TABSBAR_ITEM', + sideItems: 'DOME_SIDEBAR_ITEM', + toolItems: 'DOME_TOOLBAR_ITEM', + others: undefined + }); + + var selection = this.state.selectedTab ; + if (selection === undefined) + React.Children.forEach( content.tabsItems , (tab) => { + if (!selection && tab && tab.props.default) + selection = tab.props.ident ; + }); + + const makeTab = (tab) => { + const onSelection = callbacks( tab.props.onSelection , this.handleSelectTab ); + const onClose = callbacks( tab.props.onClose , this.props.onTabClose ); + const props = { selection , onSelection , onClose , content: false } ; + return React.cloneElement( tab , props , null ); + }; + + const makeContent = (tab) => { + const props = { + selection , + onSelection : undefined, + onClose : undefined, + content: true + }; + return React.cloneElement( tab , props ); + }; + + var tabs , main ; + const settings = this.props.settings ; + const tools = content.toolItems ; + + if (content.tabsItems) { + tabs = React.Children.map( content.tabsItems , (tab) => tab && makeTab(tab) ); + main = React.Children.map( content.tabsItems , (tab) => tab && makeContent(tab) ); + if (content.others) console.warn('Unexpected main content for Frame with Tabs'); + } else { + tabs = undefined ; + main = content.others ; + } + + if (content.sideItems) { + const sidebarOffset = settings && (settings + '.dome.sidebar'); + const sidebarSections = settings && (settings + '.dome.section'); + main = ( + <Splitter dir='LEFT' settings={sidebarOffset} > + { <SideBar + settings={sidebarSections} + selection={this.state.selectedItem} + onSelection={this.handleSelectItem} + >{content.sideItems}</SideBar> } + { main } + </Splitter> + ); + } + + return ( + <Vfill> + { !this.props.hideToolbar && tools && <ToolBar>{tools}</ToolBar> } + { !this.props.hideTabsbar && tabs && <TabsBar>{tabs}</TabsBar> } + { main } + </Vfill> + ); + } + +} + +// -------------------------------------------------------------------------- + +export default { Frame }; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/layout/grids.css b/Ivette/src/dome/src/renderer/layout/grids.css new file mode 100644 index 0000000000000000000000000000000000000000..25af9503850fa09f6ba1ec8a50853d1766f96d67 --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/grids.css @@ -0,0 +1,51 @@ +/* -------------------------------------------------------------------------- */ +/* --- GridLayout Styles --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xGridLayout { + flex: 1 1 auto ; + width: 100% ; + height: 100% ; + position: relative ; + overflow: auto ; +} + +.dome-xGridLayout-splitter { + z-index: 1 ; + position: absolute ; +} + +.dome-xGridLayout-hsplit { cursor: col-resize } +.dome-xGridLayout-hdrag { cursor: ew-resize } +.dome-xGridLayout-vsplit { cursor: row-resize } +.dome-xGridLayout-vdrag { cursor: ns-resize } + +.dome-xGridLayout-target { + z-index: 2 ; + position: absolute ; + border-radius: 12px ; + background: #64b4f0 ; + opacity: 0.5 ; +} + +.dome-xGridLayout-holder { + z-index: -1 ; + position: absolute ; + overflow: hidden ; + background: lightblue ; + opacity: 0.5 ; +} + +.dome-xGridLayout-item { + z-index: 0 ; + position: absolute ; + overflow: hidden ; + transition: all 0.1s ease-out ; +} + +.dome-xGridLayout-item.dome-dragging +{ + z-index: +1 ; +} + +/* -------------------------------------------------------------------------- */ diff --git a/Ivette/src/dome/src/renderer/layout/grids.js b/Ivette/src/dome/src/renderer/layout/grids.js new file mode 100644 index 0000000000000000000000000000000000000000..91f3882f40f757aa8f00fce014e16195dad9892b --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/grids.js @@ -0,0 +1,1347 @@ +// -------------------------------------------------------------------------- +// --- Grid Layout +// -------------------------------------------------------------------------- + +/** @module dome/layout/grids */ + +import React from 'react' ; +import Dome from 'dome' ; +import { dispatchEvent, DnD, DragSource, DropTarget } from 'dome/dnd' ; +import { AutoSizer } from 'react-virtualized' ; +import { DraggableCore } from 'react-draggable' ; +import _ from 'lodash' ; +import './grids.css' ; + +// -------------------------------------------------------------------------- +// --- Grid Utilities +// -------------------------------------------------------------------------- + +function flatten( dir, gs ) +{ + const content = [] ; + gs && gs.forEach((g) => { + let kd = g && g.kind ; + if (kd) + if ( kd === dir ) { + if (g.content.length > 0) content.push( ...g.content ); + } else + content.push( g ); + }); + return content ; +} + +function iter( grid , fn ) +{ + function visit(g) { + if (!g) return; + if (g.kind === 'ITEM') fn(g); + else g.content.forEach(visit); + } + visit(grid); +} + +function get( g, id ) +{ + if (g) { + if (g.id === id) return g; + switch( g.kind ) { + case 'HBOX': + case 'VBOX': + const gs = g.content ; + var k = 0; + while (k < gs.length) { + let r = get(gs[k],id); + if (r) return r; + k++; + } + } + } + return undefined; +} + +/** + @summary Pretty-print shape. + */ + +export function stringOfShape( s ) +{ + if (!s) return "<>" ; + switch(s.kind) { + case 'ITEM': + if (s.switch || s.height) + return s.id + "(" + s.width + "x" + s.height + ")" ; + else + return s.id ; + case 'HBOX': return "H<" + s.content.map(stringOfShape).join(',') + ">" ; + case 'VBOX': return "V<" + s.content.map(stringOfShape).join(',') + ">" ; + default: return "<?" + s + "?>"; + } +} + +// -------------------------------------------------------------------------- +// --- Shape Utilities +// -------------------------------------------------------------------------- + +/** + @summary Iterates over items in a shape. + @parameter {Shape} shape - the shape to iter over + @parameter {function} job - the function to apply on each + @description + The iteree receives `job(id,width,height)` for each `ITEM` in the shape. + */ +export function iterShape( shape, job ) +{ + iter( shape , (item) => job(item.id,item.width,item.height) ); +} + +/** + @summary Returns the shape element of the given item identifier. + @parameter {Shape} shape - the shape to look into + @parameter {string} id - the item identifier + @return {object} the associated item object, or `undefined` + */ +export function getShapeItem( shape, id ) +{ + return get(shape,id); +} + +/** + @summary Remove an item or sub-grid from the shape. + @parameter {Shape} shape - the shape to filter + @parameter {string} id - the item or grid identifier to remove + @return {Shape} the filtered shape + */ +export function removeShapeItem( shape, id ) +{ + const visit = (s) => { + if (s && s.id !== id) { + switch(s.kind) { + case 'ITEM': + return s; + case 'HBOX': + case 'VBOX': + return makeShapeBox( s.kind , s.id, s.content.map(visit) ); + //otherwize continue + } + } + return null; + }; + return visit(shape); +} + + +// -------------------------------------------------------------------------- +// --- Dimensions +// -------------------------------------------------------------------------- + +function shareDim( d , ds ) +{ + d.min = 0; + d.size = 0; + d.next = 0; + d.ext = 0; + d.fill = false; + d.resize = false; + ds.forEach( (di) => { + d.min += di.min ; + d.size += di.size ; + if (di.resize) d.resize = true ; + if (di.fill) { + d.fill = true ; + d.ext += di.min ; + d.next ++ ; + } else + d.ext += di.size ; + }); +} + +function stackDim( d , ds ) +{ + d.min = 0; + d.size = 0; + d.fill = 0; + d.resize = 0; + ds.forEach( (di) => { + d.min = Math.max( d.min, di.min ); + d.size = Math.max( d.size, di.size ); + if (di.fill) d.fill = true ; + if (di.resize) d.resize = true ; + }); +} + + +// -------------------------------------------------------------------------- +// --- Sequence Layout +// -------------------------------------------------------------------------- + +/* Distributes extra available space w.r.t respective ratio. */ +function layoutShare( d0 , ds ) +{ + const d = d0.dim ; + const s = d0.size ; + const e = d0.ext ; + const m = d0.min ; + + let flayout ; + + if ( s <= d ) { + const K = d0.next ; + flayout = (di) => + di.fill ? di.size + ( d - s ) / K : di.size ; + } else if ( e <= d ) { + // Have e <= d < s, Hence e < s + const alpha = (d - e) / (s - e) ; + flayout = (di) => + di.fill ? di.min + alpha * (di.size - di.min) : di.size ; + } else if ( m <= d ) { + // Have m <= d < {e,s}, Hence m < e + const alpha = (d - m) / (e - m) ; + flayout = (di) => + !di.fill ? di.min + alpha * (di.size - di.min) : di.min ; + } else if ( m > 0 ) { + const alpha = d / m ; + flayout = (di) => alpha * di.min ; + } else { + flayout = (di) => 0 ; + } + + var p0 = d0.pos ; + var p1 = p0 ; + var ps = 0 ; + ds.forEach((di) => { + ps += di.drag ? di.drag : flayout(di) ; // Avoids cumulative rounding + let p2 = p0 + Math.round(ps) ; + di.pos = p1 ; + di.dim = p2-p1 ; + p1 = p2 ; + }); +} + +// -------------------------------------------------------------------------- +// --- Parallel Layout +// -------------------------------------------------------------------------- + +/* Apply available space to all elements */ + +function layoutStack( d0 , ds ) +{ + const p = d0.pos ; + const d = d0.dim ; + ds.forEach((di) => { + di.pos = p ; + di.dim = di.drag ? di.drag : (di.fill ? d : Math.min( d , di.size )) ; + di.room = d - di.dim ; + }); +} + +// -------------------------------------------------------------------------- +// --- Layout Grid +// -------------------------------------------------------------------------- + +function layoutGrid(grid,width,height) +{ + function visit(g) { + if (!g) return ; + switch( g.kind ) { + case 'ITEM': + break; + case 'HBOX': + layoutShare( g.dx , g.dxs ); + layoutStack( g.dy , g.dys ); + g.content.forEach(visit); + break; + case 'VBOX': + layoutStack( g.dx , g.dxs ); + layoutShare( g.dy , g.dys ); + g.content.forEach(visit); + break; + } + } + grid.dx.pos = 0; grid.dy.pos = 0; + grid.dx.dim = width; grid.dy.dim = height; + visit(grid); +} + +// -------------------------------------------------------------------------- +// --- Freezing +// -------------------------------------------------------------------------- + +function freezeGrid( g ) +{ + if (!g) return; + switch(g.kind) { + case 'ITEM': + g.dx.size = g.dx.dim ; + g.dy.size = g.dy.dim ; + break; + case 'HBOX': + g.content.forEach( freezeGrid ); + shareDim(g.dx,g.dxs); + stackDim(g.dy,g.dys); + break; + case 'VBOX': + g.content.forEach( freezeGrid ); + stackDim(g.dx,g.dxs); + shareDim(g.dy,g.dys); + break; + } +} + +function resizeGrid(g,dgx,dgy) +{ + if (!g) return; + switch(g.kind) { + case 'ITEM': + if (dgx && !g.dx.room) g.dx.drag = dgx ; + if (dgy && !g.dy.room) g.dy.drag = dgy ; + break; + case 'HBOX': + g.content.forEach( (g) => resizeGrid(g,g.dx.drag,dgy) ); + break; + case 'VBOX': + g.content.forEach( (g) => resizeGrid(g,dgx,g.dy.drag) ); + break; + } +} + +// -------------------------------------------------------------------------- +// --- Grid Constructors +// -------------------------------------------------------------------------- + +const BOXID = 'DOME$' ; +const MINDIM = 12 ; +const INSETS = 6 ; // For insertion borders + +function makeGridItem( content, width, height ) +{ + if (content.display !== undefined && !content.display) return undefined ; + const dimension = (d) => Math.max( d || 0 , MINDIM ); + const w = dimension(content.width) ; + const h = dimension(content.height); + const mw = dimension(content.minWidth); + const mh = dimension(content.minHeight); + const dx = { size: Math.max( mw , w ), min: Math.min( mw , w ), resize:false, fill:false }; + const dy = { size: Math.max( mh , h ), min: Math.min( mh , h ), resize:false, fill:false }; + switch( content && content.fill ) { + case 'both': dx.fill = true ; dy.fill = true ; break; + case 'horizontal': dx.fill = true ; break; + case 'vertical': dy.fill = true ; break; + } + switch( content && content.resize ) { + case undefined: dx.resize = dx.fill ; dy.resize = dy.fill; break; + case 'both': dx.resize = true ; dy.resize = true ; break; + case 'horizontal': dx.resize = true ; break; + case 'vertical': dy.resize = true ; break; + } + if (width && dx.resize && dx.min <= width) + dx.size = width ; + if (height && dy.resize && dy.min <= height) + dy.size = height ; + const id = content.id ; + return { kind: 'ITEM', dx, dy, id, content }; +} + +function makeGridHbox( id, gs ) +{ + const content = flatten( 'HBOX' , gs ); + switch(content.length) { + case 0: return null ; + case 1: return content[0]; + default: + const dxs = content.map((g) => g.dx); + const dys = content.map((g) => g.dy); + const dx = {} ; + const dy = {} ; + shareDim(dx,dxs); + stackDim(dy,dys); + return { kind: 'HBOX', id , dx, dxs, dy, dys, content }; + } +} + +function makeGridVbox( id, gs ) +{ + const content = flatten( 'VBOX' , gs ); + switch(content.length) { + case 0: return null ; + case 1: return content[0]; + default: + const dxs = content.map((g) => g.dx); + const dys = content.map((g) => g.dy); + const dx = {} ; + const dy = {} ; + stackDim(dx,dxs); + shareDim(dy,dys); + return { kind: 'VBOX', id, dx, dxs, dy, dys, content }; + } +} + +function makeGridDir( dir, id, gs ) +{ + switch( dir || 'vertical') { + case 'horizontal': + return makeGridHbox(id,gs); + case 'vertical': + return makeGridVbox(id,gs); + default: + return null; + } +} + +function makeShapeDir( dir, id, content ) +{ + switch( dir || 'vertical') { + case 'horizontal': + return makeShapeBox('HBOX',id,content); + case 'vertical': + return makeShapeBox('VBOX',id,content); + default: + return null; + } +} + +// -------------------------------------------------------------------------- +// --- Shapes +// -------------------------------------------------------------------------- + +function makeShapeBox( kind, id, gs ) +{ + const content = flatten( kind, gs ); + switch(content.length) { + case 0: return null ; + case 1: return content[0]; + default: return { kind, id, content }; + } +} + +function makeShapeOfGrid( g ) +{ + let kind = g && g.kind ; + switch( kind ) { + case 'HBOX': + case 'VBOX': + return { kind, id: g.id, content: g.content.map(makeShapeOfGrid) }; + case 'ITEM': + return { kind:'ITEM', id: g.id, width: g.dx.dim, height: g.dy.dim }; + default: + return null; + } +} + +const BOXINSERT = 'DOME$INSERT' ; +let insertId = 0 ; + +function makeShapeInsert( shape,at,dir,item ) +{ + const visit = (s) => { + if (!s || s.id === item.id) return null; + switch( s.kind ) { + case 'HBOX': + case 'VBOX': + s = makeShapeBox( s.kind , s.id, s.content.map(visit) ); + // then falls through + } + if (s.id === at) { + const id = BOXINSERT + (insertId++) ; + switch( dir ) { + case 'NORTH': return makeShapeBox('VBOX', id, [ item , s ]); + case 'SOUTH': return makeShapeBox('VBOX', id, [ s , item ]); + case 'EAST': return makeShapeBox('HBOX', id, [ s , item ]); + case 'WEST': return makeShapeBox('HBOX', id, [ item , s ]); + // otherwize falls through + } + } + return s ; + }; + return at === '*' ? item : at === item.id ? shape : visit(shape); +} + +// -------------------------------------------------------------------------- +// --- Insertions +// -------------------------------------------------------------------------- + +const quadrant = ( dx , dy , x , y ) => { + let dir, best = 10000 ; + const qdir = ( d , w ) => { if (0 <= w && w < best) { best = w ; dir = d; } }; + qdir( 'NORTH', y - dy.pos ); + qdir( 'SOUTH', dy.pos + dy.dim - y ); + qdir( 'EAST', dx.pos + dx.dim - x ); + qdir( 'WEST', x - dx.pos ); + return dir; +}; + +const isHead = (d,p) => ( d.pos <= p && p <= d.pos + INSETS ); +const isTrail = (d,p) => ( d.pos + d.dim - INSETS <= p && p <= d.pos + d.dim ) ; +const inside = (x,y) => (g) => { + const dx = g.dx ; + const dy = g.dy ; + return ( dx.pos < x && x < dx.pos + dx.dim && + dy.pos < y && y < dy.pos + dy.dim ); +} ; + +const targetAt = ( grid , x , y ) => { + if (!grid) return undefined; + const dx = grid.dx ; + const dy = grid.dy ; + let dir ; + switch( grid.kind ) { + case 'ITEM': + dir = quadrant(dx,dy,x,y); + break; + case 'HBOX': + if (isHead(dy,y)) { dir = 'NORTH'; break; } + if (isTrail(dy,y)) { dir = 'SOUTH'; break; } + return targetAt( grid.content.find(inside(x,y)), x , y ); + case 'VBOX': + if (isHead(dx,x)) { dir = 'WEST'; break; } + if (isTrail(dx,x)) { dir = 'EAST'; break; } + return targetAt( grid.content.find(inside(x,y)), x , y ); + } + return dir && Object.assign( { at:grid.id, dir } , makePosition(grid) ) ; +}; + +const TARGET_PLAIN = { at:'*', dir:'*', left:0, top:0 }; + +// -------------------------------------------------------------------------- +// --- Resizing Events +// -------------------------------------------------------------------------- + +const onResizeStart = ({ id,resizer,dp,dq }) => { + dp.root = dp.dim ; + dq.root = dq.dim ; + freezeGrid( resizer.grid ); + resizer.id = id ; + resizer.splitters = [resizer.splitters[id]] ; + resizer.element.setState({ resizer }); +}; + +const onResizeDrag = ({ id,resizer,dp,dq },offset) => { + offset = Math.max( dp.min - dp.root , offset ); + offset = Math.min( dq.root - dq.min , offset ); + resizer.offset = offset ; + dp.drag = dp.root + offset ; + dq.drag = dq.root - offset ; + resizeGrid( resizer.grid ); + resizer.element.forceUpdate(); +}; + +const onResizeStop = ({ resizer }) => { + let shape = makeShapeOfGrid( resizer.grid ); + resizer.element.setShape( shape ); +}; + +const onResizeReset = ({ resizer }) => { + resizer.element.setShape( undefined ); +}; + +// -------------------------------------------------------------------------- +// --- Splitters & Targets +// -------------------------------------------------------------------------- + +const ITEMCLASS = 'dome-xGridLayout-item dome-container' ; +const HDRAGZONE = 'dome-xGridLayout-splitter dome-xGridLayout-hsplit dome-color-dragzone' ; +const HDRAGGING = 'dome-xGridLayout-splitter dome-xGridLayout-hdrag dome-color-dragging' ; +const VDRAGZONE = 'dome-xGridLayout-splitter dome-xGridLayout-vsplit dome-color-dragzone' ; +const VDRAGGING = 'dome-xGridLayout-splitter dome-xGridLayout-vdrag dome-color-dragging' ; + +class HSPLIT extends React.Component { + render() { + let {x,y,width,height,...handler} = this.props ; + let id = handler.id ; + let { id:sid , offset=0 } = handler.resizer ; + return ( + <DraggableCore + onStart={() => { + onResizeStart(handler); + this.forceUpdate(); + }} + onDrag={(_evt,data) => { + onResizeDrag(handler,data.x - x + 2); + this.forceUpdate(); + }} + onStop={() => onResizeStop(handler)} + > + <div className={ id === sid ? HDRAGGING : HDRAGZONE } + onClick={(evt) => evt.altKey && onResizeReset(handler)} + style={{ top:y, height, left:x+offset-2, width:4 }} /> + </DraggableCore> + ); + } +} + +class VSPLIT extends React.Component { + render() { + let {x,y,width,height,...handler} = this.props ; + let id = handler.id ; + let { id:sid , offset=0 } = handler.resizer ; + return ( + <DraggableCore + onStart={() => { + onResizeStart(handler); + this.forceUpdate(); + }} + onDrag={(_evt,data) => { + onResizeDrag(handler,data.y - y + 2); + this.forceUpdate(); + }} + onStop={() => onResizeStop(handler)} + > + <div className={ id === sid ? VDRAGGING : VDRAGZONE } + onDoubleClick={(evt) => evt.altKey && onResizeReset(handler)} + style={{ top:y+offset-2, height:4, left:x, width }} /> + </DraggableCore> + ); + } +} + +const TARGET = ({target:{ dir,left,top,width,height }}) => { + switch(dir) { + case 'NORTH': + top = top - 3 ; height = 6 ; + break; + case 'SOUTH': + top = top + height - 3 ; height = 6 ; + break; + case 'WEST': + left = left -3 ; width = 6 ; + break; + case 'EAST': + left = left + width -3 ; width = 6 ; + break; + } + let style = { left, top, width, height }; + return <div className='dome-xGridLayout-target' style={style} />; +}; + +const HOLDER = ({position}) => ( + <div className='dome-xGridLayout-holder' style={position} /> +); + +const ELEMENT = ({id,className,style,children}) => ( + <div key={id} className={className} style={style}> + { children } + </div> +); + +// -------------------------------------------------------------------------- +// --- Grid Splitters +// -------------------------------------------------------------------------- + +function splitSequence( d,ds,fn ) +{ + const n = ds.length || 0 ; + if (n<=0) return; + const dt = ds[n-1] ; + const dn = { resize:false, dim:0, min:0 }; + const trail = d.room ; + if (trail > 0) { + dn.resize = true; dn.dim = trail; + let i,p,di ; + for (i = 0, p = -1; i < n; i++) { + di = ds[i]; + p = di.resize ? i : p ; + if (p>=0) { + fn(di.pos+di.dim,ds[p],dn); + } + } + } else { + const dr = ds.slice(1).concat(dn); + const ps = Array(n); + const qs = Array(n); + let i,k ; + for (i = 0, k = -1; i < n; i++) + k = ps[i] = ds[i].resize ? i : k ; + for (i = n-1, k = -1; 0 <= i; i--) + k = qs[i] = dr[i].resize ? i : k ; + ds.forEach((di,i) => { + var p = ps[i]; + var q = qs[i]; + if (p>=0 && q>=0) + fn(di.pos+di.dim,ds[p],dr[q]); + }); + } +} + +function extendItem( d , fn ) { + if (d.resize && d.room > 0) { + const df = { resize:true, dim:d.room, min:0 }; + fn(d.pos + d.dim,d,df); + } +}; + +function splitGrid( resizer,grid ) +{ + var SID = 0 ; + const splitters = resizer.splitters ; + const makeHsplit = (dy) => (x,dp,dq) => { + var id = SID++; + var s = ( + <HSPLIT id={id} key={id} resizer={resizer} + x={x} y={dy.pos} height={dy.dim} + dp={dp} dq={dq} + />) ; + splitters.push(s); + }; + const makeVsplit = (dx) => (y,dp,dq) => { + var id = SID++; + var s = ( + <VSPLIT id={id} key={id} resizer={resizer} + x={dx.pos} y={y} width={dx.dim} + dp={dp} dq={dq} + />) ; + splitters.push(s); + }; + function visit(g) { + if (!g) return; + switch(g.kind) { + case 'ITEM': + extendItem( g.dx , makeHsplit(g.dy) ); + extendItem( g.dy , makeVsplit(g.dx) ); + return; + case 'HBOX': + splitSequence( g.dx , g.dxs , makeHsplit(g.dy) ); + g.content.forEach(visit); + return; + case 'VBOX': + splitSequence( g.dy , g.dys , makeVsplit(g.dx) ); + g.content.forEach(visit); + return; + } + } + visit(grid); +} + +// -------------------------------------------------------------------------- +// --- Grid Elements +// -------------------------------------------------------------------------- + +const makePosition = ( {dx,dy}, padding=0 ) => ({ + left: dx.pos + padding, + top: dy.pos + padding, + width: dx.dim - padding, + height: dy.dim - padding +}); + +function makeElement( render = ELEMENT, item, padding ) +{ + if (!item) return null; + const { id, content:{className:itemClass,style:itemStyle,children,...itemProps} } = item; + const position = makePosition( item, padding ); + const className = itemClass ? ITEMCLASS + " " + itemClass : ITEMCLASS ; + const style = Object.assign( {}, itemStyle , position ); + return render({id,className,style,children,...itemProps}); +} + +function orderElements( e1 , e2 ) +{ + let a = e1.key ; + let b = e2.key ; + if (!a || a < b) return -1; + if (!b || a > b) return 1; + return 0; +} + +// -------------------------------------------------------------------------- +// --- GridItem +// -------------------------------------------------------------------------- + +/** + @class + @summary Elementary GridLayout Component + @property {string} id - Component identifier + @property {boolean} display - Whether to mount the component + @property {number} width - Desired component width + @property {number} height - Desired component height + @property {number} minWidth - Minimum component width + @property {number} minHeight - Minium component height + @property {directions} [fill] - Direction(s) the component fills in + @property {directions} [resize] - Direction(s) the component can be resized in + @property {directions} [shrink] - Direction(s) the component can be shrinked in + @property {string} [className] - Additional class of the component + @property {string} [handle] - class name of the handler for dragging the component + @property {object} [style] - Additional style of the component + @property {React.children} children - grid item content + @description + + The `id` property is mandatory for the GridLayout container + to property manage its different components. All items in the same GridLayout shall + have distinct identifiers. + + Direction properties (with type `directions`) can take the following values: + `'none'`, `'horizontal'`, `'vertical'` or `'both'`. + */ +export const GridItem = () => null; + +// -------------------------------------------------------------------------- +// --- Grid H/V Boxes +// -------------------------------------------------------------------------- + +/** + @class + @property {ident} [id] - the box identifier + @property {direction} dir - either `'horizontal'` or `'vertical'` + @property {GridContent} [children] - internal grid contents + @summary Layout its content in an horizontal or vertical box. + @description + +This container is a _fake_ component thats simply groups several +`GridItem`s or `GridBox`es horizontally or vertically. + +It can be used only as direct children of `GridLayout` +and other `GridBox` containers. + +See also: + - [GridLayout](module-dome_layout_grids.GridLayout.html) top-level container + - [GridItem](module-dome_layout_grids.GridItem.html) elementary component + - [GridHbox](module-dome_layout_grids.GridHbox.html) horizontal box + - [GridVbox](module-dome_layout_grids.GridVbox.html) vertical box +*/ +export const GridBox = () => null ; + +/** + @class + @summary Layout its content in an horizontal box. + @property {ident} [id] - the box identifier + @description + See [GridBox](module-dome_layout_grids.GridBox.html) +*/ +export const GridHbox = () => null ; + +/** + @class + @summary Layout its content in a vertical box. + @property {ident} [id] - the box identifier + @description + See [GridBox](module-dome_layout_grids.GridBox.html) +*/ +export const GridVbox = () => null ; + +// -------------------------------------------------------------------------- +// --- User Grid & Components Extraction +// -------------------------------------------------------------------------- + +import { register, classOf } from 'dome/misc/register' ; + +register(GridBox, 'DOME_GRIDLAYOUT_BOX'); +register(GridHbox, 'DOME_GRIDLAYOUT_HBOX'); +register(GridVbox, 'DOME_GRIDLAYOUT_VBOX'); +register(GridItem, 'DOME_GRIDLAYOUT_ITEM'); + +/** + @summary Extract shape from GridChildren. + @parameter {GridChildren} children - Grid items elements arranged in grids + @parameter {direction} [dir] - default direction + @return {Shape} the associated shape + @description + Converts a React JSX-based grid of items into a Shape object. + */ +export function makeChildrenShape( children, dir ) +{ + const makeEltShape = (elt) => { + let { id, width, height } = elt.props ; + return { kind: 'ITEM', id, width, height }; + }; + + const makeBoxShape = (dir,elt) => { + let { id, children } = elt.props ; + let gs = makeShapes(children); + return makeShapeDir(dir,id,gs); + }; + + const makeShapes = (children) => { + return React.Children.map(children,(elt) => { + if (!elt) return null; + switch( classOf(elt) ) { + case 'DOME_GRIDLAYOUT_ITEM': + return makeEltShape(elt); + case 'DOME_GRIDLAYOUT_HBOX': + return makeBoxShape('horizontal',elt); + case 'DOME_GRIDLAYOUT_VBOX': + return makeBoxShape('vertical',elt); + case 'DOME_GRIDLAYOUT_BOX': + return makeBoxShape(elt.props.dir,elt); + default: + console.warn('[Dome.GridLayout] Unknown grid box', elt); + return null; + } + }); + }; + + return makeShapeDir( dir, undefined, makeShapes(children) ); +} + +function makeChildrenGrid( dir, items, children, shape ) +{ + let kid = 0 ; + let index = {} ; + + const indexElt = (elt) => { + let { id } = elt.props ; + let props = index[id]; + if (!props) props = index[id] = {}; + Object.assign( props , elt.props ); + return props; + }; + + const makeGridElt = (elt) => makeGridItem(indexElt(elt)); + + const makeGridBox = (dir,elt) => { + let { id, children } = elt.props ; + if (!id) id = BOXID + (++kid) ; + return makeGridDir(dir,id,makeGrids(children)); + }; + + const makeGrids = (children) => { + return React.Children.map(children,(elt) => { + if (!elt) return null; + switch( classOf(elt) ) { + case 'DOME_GRIDLAYOUT_ITEM': + return makeGridElt(elt); + case 'DOME_GRIDLAYOUT_HBOX': + return makeGridBox('horizontal',elt); + case 'DOME_GRIDLAYOUT_VBOX': + return makeGridBox('vertical',elt); + case 'DOME_GRIDLAYOUT_BOX': + return makeGridBox(elt.props.dir,elt); + default: + console.warn('[Dome.GridLayout] Unknown grid box', elt); + return null; + } + }); + }; + + const makeShape = (s) => { + switch( s && s.kind ) { + case 'ITEM': + let props = index[ s.id ] ; + if (!props) return null; + index[ s.id ] = undefined ; + return makeGridItem( props, s.width, s.height ); + case 'HBOX': + return makeGridHbox( s.id, s.content.map(makeShape) ); + case 'VBOX': + return makeGridVbox( s.id, s.content.map(makeShape) ); + default: + return null; + } + }; + + items && items.forEach && items.forEach( indexElt ); + + if (shape) + return makeShape(shape); + else + return makeGridDir(dir,BOXID,makeGrids(children)); +} + +// -------------------------------------------------------------------------- +// --- GridLayout Core +// -------------------------------------------------------------------------- + +/** + @class + @summary Grid-based Flexible Container + @property {direction} [dir] - Default children layout (`'horizontal'` or `'vertical'`) + @property {number} [padding] - Padding between items + @property {Shape} [shape] - The desired shape (defaults to children grid) + @property {GridItem[]} [items] - A collection of items (defaults to children items) + @property {GridContent} [children] - Grid items arranged in box (used for default items and shape) + @property {ident} [dragged] - Dragged item to materialize + @property {object} [dragging] - Dragging event to localize with `onTarget()` + @property {object} [target] - Insertion target to materialze + @property {function} [onReshape] - Callback with the updated shape + @property {function} [onTarget] - Callback when dragging is a valid target + @property {function} [render] - Rendering function for items + @property {React.ref} [targetRef] - Reference for D&D drop target + @description + +Low-level GridLayout container, with only resizing capabilities. +Additional rendering options are available: + +- `dragged` : item being dragged, materialized with a dragging background; +- `dragging` : current [D&D](dome-module_dnd.html) event to notify `onTarget()` with; +- `target` : `{at,dir,left,top,width,height}` insertion position to materialize; +- `shape:Shape` : desired reshaping of the children grid; +- `onReshape(Shape)` : notified when grid content has been resized; +- `onTarget(Target)` : notified when `dragging` corresponds to a new target; +- `render({id,className,style,handle,children,...})` : rendering function for the provided item. + +The rendering function shall return a keyed React element or fragment. +It receives all properties of the associated item to render, with +class and style merged with the `dome-xGridLayout-item` base class +and the absolute coordinates of the item inside the container. + +*/ + +export class GridLayoutCore extends React.Component +{ + + constructor(props) { + super(props); + this.state = {}; + } + + setShape( newshape ) + { + const { onReshape, shape } = this.props ; + onReshape && onReshape(newshape); + this.setState({ resizer:undefined }); + } + + render() { + const { targetRef, padding=0 } = this.props ; + return ( + <div className='dome-xGridLayout' ref={targetRef}> + <AutoSizer key='grid'>{({width,height}) => this.renderSized(width-padding,height-padding)}</AutoSizer> + </div> + ); + } + + renderSized(width, height) + { + const { dragged } = this.props ; + const { resizer:resizing } = this.state ; + let grid,markers=[] ; + if (resizing) { + // When Resizing + grid = resizing.grid ; + markers = resizing.splitters ; + layoutGrid(grid,width,height); + } else { + const { + shape, dir, + dragging, onTarget, + items, children + } = this.props ; + // Compute Layout + grid = makeChildrenGrid( dir, items, children, shape ); + if (grid) layoutGrid(grid,width,height); + // Compute Dragging & notify Target + let targetted ; + if (dragging) { + if (grid) { + const r = dragging.targetClientRect ; + if (r) { + const x = dragging.clientX - r.left ; + const y = dragging.clientY - r.top ; + targetted = targetAt( grid, x, y ); + } + } else { + targetted = Object.assign( { width, height } , TARGET_PLAIN ) ; + } + } + if (onTarget) { + const { at,dir } = targetted || {} ; + const held = dragging ? dragging.held : false ; + if ( this.targetAt !== at || + this.targetDir !== dir || + this.targetHeld !== held ) + { + this.targetAt = at ; + this.targetDir = dir ; + this.targetHeld = held ; + if (targetted) targetted.shape = makeShapeOfGrid(grid); + setImmediate(() => onTarget(targetted)); + } + } + const { target } = this.props ; + if (target && target.at !== dragged) { + markers.push( <TARGET key='target' target={target}/> ); + } + if (grid && !dragging && !target) { + // Splitters + splitGrid( { grid,element:this,splitters:markers } ,grid ); + } + } + const elements = []; + const { render, padding } = this.props ; + iter(grid,(item) => { + let e = makeElement(render,item,padding); + if (e) elements.push(e); + if (dragged && dragged === item.id) + markers.push(<HOLDER key='holder' position={makePosition(item)}/>); + }); + return [ + (<React.Fragment key='items'>{elements.sort(orderElements)}</React.Fragment>), + (<React.Fragment key='markers'>{markers}</React.Fragment>) + ]; + }; +} + +// -------------------------------------------------------------------------- +// --- GridLayout Full +// -------------------------------------------------------------------------- + +const positionOfStyle = ({left,top,width,height}) => ({left,top,width,height}); + +const DRAGGABLEITEM = + (dnd,anchor,onSelfDrag,insert) => + ({id,className,style,handle,children}) => + ( id === insert + ? ( <HOLDER key='DOME$holder' position={positionOfStyle(style)}/> ) + : ( + <DragSource + key={id} + dnd={dnd} + handle={handle} + onStart={() => onSelfDrag(id,{x:style.left,y:style.top})} + > + {(dragging) => { + let theStyle = style ; + if (dragging && anchor) { + theStyle = Object.assign( {} , style ); + theStyle.left = anchor.x + dragging.deltaX ; + theStyle.top = anchor.y + dragging.deltaY ; + className += ' dome-dragging' ; + } + return (<div className={className} style={theStyle}>{children}</div>); + }} + </DragSource> + ) + ); + +/** + @class + @summary Grid Container + @property {direction} [dir] - Default children layout (`'horizontal'` or `'vertical'`) + @property {number} [padding] - Padding between items + @property {Shape} [shape] - The desired shape (defaults to children grid) + @property {GridItem[]} [items] - A collection of items (defaults to children items) + @property {Grid} [children] - Grid items arranged in box (used for default items and shape) + @property {string} [settings] - User-settings key for making the shape persistent + @property {DnD} [dnd] - Optional D&D controller to be used + @property {GridItem} [holding] - Dragged external element + @property {function} [onTarget] - Callback for dragged target proposal + @property {function} [onReshape] - Callback on reshaping self content + @property {function} [onInsert] - Callback on dropping the holding element + @property {function} [onDnd] - Callback on D&D events + @property {function} [onXxx] - Other D&D [callback events](module-dome_dnd.html) + @description + +Layout several components with nested vertical and horizontal boxes. + +Direct children of the container must be either: +- [GridBox](module-dome_layout_grids.GridBox.html) and its derivated +- [GridItem](module-dome_layout_grids.GridItem.html) for elementary component + +Top-level children are laidout vertically (default) or horizontally according +to the `dir` property. Nested boxes of same directions are flattened, +and singleton boxes simply lift-up their content into their parent box. + +You may dynamically change the box hierarchy, without causing unmounting +and re-monting the different items. Actually, the container renders all +the collected `GridItem` elements as a flat array ordered by keys. + +All item specifications are taken from the provided items. However, the grid +layout of the items is taken from the provided shape, the settings of the +children grix boxes, in this order of priority. Extra items or missing items are +simply ignored from the shape taken into account. + +GridLayout containers can be used as drop targets, both for re-arranging +internal grid items, or to insert external drag sources inside. +If you supply an external [DnD](module-dome_dnd.DnD.html) controller, +the GridLayout will register itself as a drop target. Otherwize, it will +use its own controller. + +The callbacks `onReshape` and `onTarget` are invoked on drag and drop operations: +- `onReshape(Shape)` is invoked when the grid elements are resized or rearranged; +- `onTarget(Target)` in invoked when a drag source targets an element of the grid; +- `onInsert(Shape,Target)` when a drag source is dropped inside the grid, at some +target position, possibly resulting in the given new shape. + +When dragging a source over the grid, the grid element specified by the `holding` +property of the grid is used to materialize the insertion of the dragged source +inside the grid. To decline a dragging operation, the `onTarget()` must return a +falsy value other than `undefined` (eg: `false`). + +A `Target` is a plain serialisable object with the following properties: +- `at:ident` the box or item identifier where to insert the target, +or `'*'` when targetting an empty shape; +- `dir:'NORTH'|'EAST'|'SOUTH'|'WEST'` the direction to insert the target item along, +or `'*'` when targetting an empty shape; +- `id:ident` the inserted item identifier. + +A `Shape` is a plain serializable object with the following properties: +- `{ kind:'HBOX', id, content: [Shape,…] }` for horizontal boxes, +- `{ kind:'VBOX', id, content: [Shape,…] }` for vertical boxes, +- `{ kind:'ITEM', id, height, width }` for leaf items. + +*/ +export class GridLayout extends React.Component +{ + + constructor(props) { + super(props); + this.state = {}; + this.dnd = this.props.dnd || new DnD(); + this.onReloadSettings = this.onReloadSettings.bind(this); + this.onReshape = this.onReshape.bind(this); + this.onTarget = this.onTarget.bind(this); + this.onSelfDrag = this.onSelfDrag.bind(this); + this.onDnd = this.onDnd.bind(this); + this.container = React.createRef(); + } + + componentDidMount() { + Dome.on('dome.defaults',this.onReloadSettings); + } + + componentWillUnmont() { + Dome.off('dome.defaults',this.onReloadSettings); + } + + computeTargetProposal(target) { + if (!target) return undefined; + const { at,dir } = target ; + const { dragged } = this.state ; + if (dragged) + return at === dragged ? undefined : { id:dragged,at,dir }; + else { + const { holding } = this.props ; + const id = holding && holding.props && holding.props.id ; + return at === id ? undefined : { id,at,dir }; + } + } + + computeNewShapeForTarget(target) { + if (!target) return []; + const { shape,at,dir } = target ; + const { holding } = this.props ; + const { dragged,inserted:oldInsert } = this.state ; + let item,inserted,newShape ; + if (dragged) { + item = get(shape,dragged); + newShape = makeShapeInsert( shape, at, dir, item ); + } + else if (holding && holding.props) { + const { id,width,height } = holding.props ; + if (at === id) { + inserted = oldInsert ; + newShape = shape ; + } else { + inserted = { at,dir,id } ; + item = { kind:'ITEM',id,width,height }; + newShape = makeShapeInsert( shape,at,dir,item ); + } + } + return [inserted,newShape]; + } + + onReloadSettings() { + const { settings, onReshape } = this.props ; + if (!settings) return; + const newShape = Dome.getWindowSetting( settings ); + this.setState({ shape: newShape }); + if (onReshape) onReshape( newShape ); + } + + onReshape(newShape) { + const { settings, shape:setShape, onReshape } = this.props ; + if (!setShape) this.setState({ shape: newShape }); + if (settings) Dome.setWindowSetting( settings, newShape ); + if (onReshape) onReshape( newShape ); + } + + onTarget(newTarget) { + const proposal = this.computeTargetProposal(newTarget); + if (!proposal) this.setState({target:undefined}); + else { + const { onTarget } = this.props ; + const { held } = this.state ; + const approval = onTarget && onTarget(proposal) ; + const valid = approval === undefined || approval ; + if (valid) { + if ( held ) { + const [inserted,holdedShape] = this.computeNewShapeForTarget(newTarget); + this.setState({held:false,target:undefined,inserted,holdedShape}); + } else + this.setState({target: newTarget}); + } else + this.setState({target: undefined}); + }; + } + + // Self dragged callback, see DRAGGABLEITEM + onSelfDrag(dragged,anchor) { + this.setState({ dragged, anchor }); + } + + // Generic D&D event + onDnd(dragging) { + dispatchEvent(dragging,this.props); + switch( dragging && dragging.move ) { + case 'HOLD': this.setState({held: true}); break; + case 'MOVE': this.setState({held: false}); break; + case 'DROP': + let { target, inserted, holdedShape:shape } = this.state ; + if (target) + [inserted,shape] = this.computeNewShapeForTarget(target); + if (inserted) { + const { onInsert } = this.props ; + const callback = onInsert || this.onReshape ; + callback && callback(shape,inserted); + } else { + shape && this.onReshape(shape); + } + // Continue on 'STOP' + case 'STOP': + this.setState({ + dragged: undefined, + anchor: undefined, + target: undefined, + held: undefined, + inserted: undefined, + holdedShape: undefined + }); + break; + } + } + + render() { + const { shape:setShape, dir, items, children, holding, padding, settings } = this.props ; + const { shape:newShape, target, dragged, anchor, holdedShape, inserted } = this.state ; + const insert = inserted ? inserted.id : undefined ; + const render = DRAGGABLEITEM(this.dnd,anchor,this.onSelfDrag,insert); + const shape = holdedShape || setShape || newShape || Dome.getWindowSetting(settings) ; + return ( + <DropTarget + dnd={this.dnd} + targetRef={this.container} + onDnd={this.onDnd} + > + {(dragging) => ( + <GridLayoutCore + targetRef={this.container} + dir={dir} + padding={padding} + shape={shape} + items={items} + dragging={dragging} + onReshape={this.onReshape} + onTarget={this.onTarget} + dragged={dragged} + target={target} + render={render} + > + {children} + {inserted ? holding : null} + </GridLayoutCore> + )} + </DropTarget> + ); + } +} + +// -------------------------------------------------------------------------- +// --- Defaults +// -------------------------------------------------------------------------- + +export default { + GridLayout, + GridLayoutCore, + GridItem, GridBox, GridHbox, GridVbox, + iterShape, getShapeItem, removeShapeItem, + stringOfShape, + makeChildrenShape +} ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/layout/pages.css b/Ivette/src/dome/src/renderer/layout/pages.css new file mode 100644 index 0000000000000000000000000000000000000000..6d593e550c77eadf0113b3e25e5d41c7282a0059 --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/pages.css @@ -0,0 +1,81 @@ +/* -------------------------------------------------------------------------- */ +/* --- Styling Page --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xPages-note { + background: white ; + padding: 2px ; +} + +.dome-xPages-page { + flex: 1 1 auto ; + overflow: hidden ; +} + +.dome-xPages-sheet { + position: relative ; + width: calc(100% - 16px) ; + height: calc(100% - 16px) ; + margin: 8px ; + padding: 8px ; + background: white ; + border-radius: 2px ; + box-shadow: 2px 2px 6px 3px lightgray ; + overflow: auto ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Styling Content --- */ +/* -------------------------------------------------------------------------- */ + +.dome-pages * { + user-select: text ; +} + +.dome-pages h1:first-child { + margin-top: 0px ; +} + +.dome-pages h1 { + margin-top: 24px ; + margin-bottom: 5px ; +} + +.dome-pages h2 { + margin-top: 16px ; + margin-bottom: 5px ; +} + +.dome-pages h3 { + margin-top: 10px ; + margin-bottom: 5px ; +} + +.dome-pages h4 { + margin-top: 6px ; + margin-bottom: 3px ; +} + +.dome-pages h5 { + margin-top: 3px ; + margin-bottom: 3px ; +} + +.dome-pages p +{ + margin-top: 3px ; + margin-bottom: 3px ; +} + +.dome-pages ul +{ + padding-left: 6px ; + margin-left: 16px ; +} + +.dome-pages li +{ + +} + +/* -------------------------------------------------------------------------- */ diff --git a/Ivette/src/dome/src/renderer/layout/pages.js b/Ivette/src/dome/src/renderer/layout/pages.js new file mode 100644 index 0000000000000000000000000000000000000000..bd7b1b6113c20eb69771fded05177d369a3e7bc4 --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/pages.js @@ -0,0 +1,81 @@ +// -------------------------------------------------------------------------- +// --- Text Pages +// -------------------------------------------------------------------------- + +/** + @module dome/layout/pages + @description + A collection of text area and elements do render textual content. + + Inside such areas, all elements are styled like a classical web page. + All elements are encapsulated inside a `<div>` with `'dome-pages'` + class name, which can be used in your CSS selectors. + + All the textual parts are selectable inside the page, contrarily to + most other widget components. + + The behaviour of `<a href=...>` elements differs for local links and external URLs. + Local links trigger a ['dome.href'](dome_.html#~event:'dome.href') event, that + you can listen to from the originating renderer process, _eg. by using `Dome.useUpdate()` + custom hook. + + External links launch the user's default browser. + +*/ + +import React from 'react' ; +import { AutoSizer } from 'react-virtualized' ; +import './pages.css' ; + +// -------------------------------------------------------------------------- +// --- Page +// -------------------------------------------------------------------------- + +/** + @class + @property {object} [style] - additional style elements + @property {Elements} [children] - page content + @summary a blank HTML page + @description + + The page has insets and shadows and fills the entire available area. + Large content is crolled inside in both directions. +*/ + +export const Page = ({style,children}) => { + return ( + <div className='dome-xPages-page'> + <div className='dome-xPages-sheet dome-pages'> + {children} + </div> + </div> + ); +}; + +// -------------------------------------------------------------------------- +// --- Page +// -------------------------------------------------------------------------- + +/** + @class + @property {object} [style] - additional style elements + @property {Elements} [children] - page content + @summary a blank HTML textarea + @description + + The area has small padding and no margin, and does not scroll its content. +*/ + +export const Note = ({style,children}) => ( + <div className=' dome-xPages-note dome-pages' style={style}> + {children} + </div> +); + +// -------------------------------------------------------------------------- +// Export Default +// -------------------------------------------------------------------------- + +export default { Page, Note }; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/layout/sidebars.css b/Ivette/src/dome/src/renderer/layout/sidebars.css new file mode 100644 index 0000000000000000000000000000000000000000..ca4193112159084ad4cad634f8df75fdd4b13889 --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/sidebars.css @@ -0,0 +1,107 @@ +/* -------------------------------------------------------------------------- */ +/* --- Styling SideBars --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xSideBar { + width: 100% ; + height: 100% ; + overflow-x: hidden ; + overflow-y: auto ; + padding-top: 6px ; + padding-bottom: 6px ; +} + +.dome-window-active .dome-xSideBar.dome-color-frame { + background: #e3e8ec ; +} + +/* -------------------------------------------------------------------------- */ +/* --- SideBar Section --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xSideBarSection { + display: block ; + margin-top: 10px ; + margin-bottom: 10px ; +} + +.dome-xSideBarSection-title { + padding-left: 3px ; + padding-right: 2px ; + display: flex ; + flew-flow: row nowrap ; + align-items: center ; +} + +.dome-xSideBarSection-title > .dome-xLabel { + flex: 1 1 ; + overflow: hidden ; + text-overflow: ellipsis ; + font-weight: bold ; +} + +.dome-xSideBarSection-title > .dome-xBadge { + flex: 0 0 ; +} + +.dome-xSideBarSection-hideshow { + flex: 0 0 ; + margin: 1px ; + color: #aaa ; + width: 32px ; + font-weight: normal ; + display: inline ; + visibility: hidden ; +} + +.dome-xSideBarSection-title:hover .dome-xSideBarSection-hideshow { + visibility: visible ; +} + +.dome-xSideBarSection-content { + overflow: hidden ; + transition: max-height 250ms ease-in-out ; +} + + +/* -------------------------------------------------------------------------- */ +/* --- SideBar Items --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xSideBarItem { + padding-left: 2px ; + padding-right: 2px ; + display: flex ; + flex-flow: row nowrap ; + align-items: center ; +} + +.dome-window-active .dome-xSideBarItem.dome-active { + background: #ccc ; +} + +.dome-window-inactive .dome-xSideBarItem.dome-active { + background: #ddd ; +} + +.dome-xSideBarItem > .dome-xLabel { + flex: 1 1 ; + overflow: hidden ; + text-overflow: ellipsis ; + padding-left: 12px ; +} + +.dome-xSideBarItem.dome-disabled > .dome-xLabel { + color: #b0b0b0 ; + fill: #b0b0b0 ; +} + +.dome-xSideBarItem > .dome-xLabel:last-child { + margin-right: 20px ; +} + +.dome-xSideBarItem > .dome-xBadge { + flex: 0 0 ; +} + +/* -------------------------------------------------------------------------- */ diff --git a/Ivette/src/dome/src/renderer/layout/sidebars.js b/Ivette/src/dome/src/renderer/layout/sidebars.js new file mode 100644 index 0000000000000000000000000000000000000000..39f691c478a7ee6391ba59ea407a552b3d4f2b13 --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/sidebars.js @@ -0,0 +1,216 @@ +// -------------------------------------------------------------------------- +// --- SideBars +// -------------------------------------------------------------------------- + +/** @module dome/layout/sidebars */ + +import React from 'react' ; +import Dome from 'dome' ; +import { Badge } from 'dome/controls/icons' ; +import { Label } from 'dome/controls/labels' ; +import './sidebars.css' ; + +const SideBarContext = React.createContext(); + +// -------------------------------------------------------------------------- +// --- SideBar Container +// -------------------------------------------------------------------------- + +/** + @class + @summary Container for sidebar items + @property {Elements} [children] - Side bar items + @property {string} [settings] - Side bar items settings + @property {string} [selection] - Current item selection + @property {function} [onSelection] - Selection callback + @property {function} [onContextMenu] - Context Menu callback + @description + See also [Frame](module-dome_layout_frames.Frame.html) containers. + + When a base settings is set on the sidebar, all contained + sections and items are attributed derived settings based on their identifiers. + + The global selection state and callback are also propagated to the side bar items. + */ +export const SideBar = ({ children , ...props }) => ( + <div className="dome-xSideBar dome-color-frame"> + <SideBarContext.Provider value={props}> + {children} + </SideBarContext.Provider> + </div> +); + +const makeSettings = ( globalSettings, { settings, label, id } ) => { + if (settings) return settings ; + if (globalSettings) { + let localId = id || label ; + if (localId) + return globalSettings + '.' + localId ; + } + return undefined ; +}; + +// -------------------------------------------------------------------------- +// --- Badges Specifications +// -------------------------------------------------------------------------- + +const makeBadge = ((element) => { + switch(typeof(element)) { + case 'number': + case 'string': + return <Badge value={element}/>; + default: + return element ; + } +}); + +// -------------------------------------------------------------------------- +// --- SideBar Section Hide/Show Button +// -------------------------------------------------------------------------- + +const HideShow = (props) => ( + <label className='dome-xSideBarSection-hideshow dome-text-label' + onClick={props.onClick} > + {props.visible ? 'Hide' : 'Show'} + </label> +); + +// -------------------------------------------------------------------------- +// --- SideBar Section +// -------------------------------------------------------------------------- + +const disableAll = (children) => + React.Children.map( children , (elt) => React.cloneElement( elt , { disabled: true } ) ); + +/** + @class + @summary Sidebar Section. + @property {string} [id] - Section identifier (used for derived settings) + @property {string} label - **Section label** + @property {string} [title] - Section short description (label tooltip) + @property {boolean} [enabled] - Enabled section (by default) + @property {boolean} [disabled] - Disabled section (not by default) + @property {boolean} [unfold] - Fold/unfold local state (default to local state) + @property {string} [settings] - Fold/unfold window settings (local state) + @property {boolean} [defaultUnfold] - Fold/unfold default state (default is `true`) + @property {Badge} [summary] - Badge summary (when content is hidden) + @property {Item[]} children - Content items + @description + + Unless specified, sections can be hidden on click. When items in the section have badge(s) + it is highly recommended to provide a badge summary to be displayed + when the content is hidden. + + Sections with no items are not displayed. +*/ +export function Section(props) { + + const context = React.useContext( SideBarContext ); + const [ state=true, setState ] = Dome.useState( + makeSettings(context,props), + props.defaultUnfold + ); + const { enabled=true, disabled=false, unfold, children } = props ; + + if (React.Children.count(children) == 0) return null; + + const dimmed = context.disabled || disabled || !enabled ; + const foldable = unfold === undefined ; + const visible = foldable ? state : unfold ; + const onClick = foldable ? (() => setState(!state)) : undefined ; + const maxHeight = visible ? 2000 : 0 ; + const subContext = Object.assign( {}, context, { disabled: dimmed } ); + + return ( + <div className='dome-xSideBarSection'> + <div className='dome-xSideBarSection-title' title={props.label}> + <Label className={ dimmed ? 'dome-disabled' : '' } label={props.label} /> + {!visible && React.Children.map(props.summary,makeBadge)} + {foldable && <HideShow visible={visible} onClick={onClick}/>} + </div> + <div className='dome-xSideBarSection-content' style={{ maxHeight }}> + <SideBarContext.Provider value={subContext}> + {children} + </SideBarContext.Provider> + </div> + </div> + ); +} + +// -------------------------------------------------------------------------- +// --- SideBar Items +// -------------------------------------------------------------------------- + +/** + @class + @property {string} [id] - Item identifier + @property {string} [label] - **Item label** + @property {string} [icon] - Item icon + @property {string} [title] - Item tooltip + @property {boolean} [enabled] - Enabled item (default is `true`) + @property {boolean} [disabled] - Disabled item (default is `false`) + @property {boolean} [selected] - Item selection state (default is `SideBar` selection) + @property {function} [onSelection] - Selection callback + @property {function} [onContextMenu] - Context Menu callback + @property {Badge} [badge] - Badge element(s) + @property {React.Children} [children] - Item additional content + @summary Sidebar Section Items + @description + + The item will be highlighted if selected _via_ the `selection` property of the + englobing sidebar. The `onSelection` and `onContextMenu` callbacks are invoked with the item identifier. + Context menu callback also triggers the selection callback (first). + In case callbacks are defined from the englobing sidebar, both are invoked. + + Badges can be single or multiple [Badge](module-dome_controls_icons.Badge.html) values. + They are displayed stacked on the right edge of the item. + +**/ +export function Item(props) +{ + const { selection, + disabled: disabledSection, + onSelection: ctxtOnSelect, + onContextMenu: ctxtOnPopup + } = React.useContext(SideBarContext); + const { id, selected, + disabled=false, enabled=true, + onSelection:itemOnSelect, + onContextMenu:itemOnPopup + } = props ; + const isDisabled = disabled || !enabled || disabled ; + const isSelected = selected !== undefined ? selected : (selection && id && (selection === id)) ; + const onClick = isDisabled ? undefined : () => { + itemOnSelect && itemOnSelect(id); + ctxtOnSelect && ctxtOnSelect(id); + }; + const onContextMenu = isDisabled ? undefined : () => { + onClick(); + itemOnPopup && itemOnPopup(id); + ctxtOnPopup && ctxtOnPopup(id); + }; + const classes = 'dome-xSideBarItem' + + ( isSelected ? ' dome-active' : ' dome-inactive' ) + + ( isDisabled ? ' dome-disabled' : '' ); + return ( + <div className={classes} title={props.title} + onContextMenu={onContextMenu} + onClick={onClick}> + <Label icon={props.icon} label={props.label} /> + {props.children} + {React.Children.map(props.badge,makeBadge)} + </div> + ); +} + +// -------------------------------------------------------------------------- + +import { register } from 'dome/misc/register' ; + +register( SideBar, 'DOME_SIDEBAR' ); +register( Section, 'DOME_SIDEBAR_ITEM' ); +register( Item, 'DOME_SIDEBAR_ITEM' ); + +export default { SideBar, Section, Item } ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/layout/splitters.css b/Ivette/src/dome/src/renderer/layout/splitters.css new file mode 100644 index 0000000000000000000000000000000000000000..0b1e80e44131a434d16e6e165003dc7ee317d95c --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/splitters.css @@ -0,0 +1,51 @@ +/* -------------------------------------------------------------------------- */ +/* --- XSplitter Style Sheet --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xSplitter-container { + position: relative ; + width: 100% ; + height: 100% ; +} + +.dome-xSplitPane { + position: relative ; +} + +.dome-xSplitter-grab { + z-index: 1 ; + position: relative ; + border: 0 ; +} + +.dome-xSplitter-h { + left: -1px ; + width: 3px ; + height: 100% ; + cursor: col-resize ; +} + +.dome-xSplitter-v { + top: -1px ; + height: 3px ; + width: 100% ; + cursor: row-resize ; +} + +.dome-xSplitter-no-cursor { } +.dome-xSplitter-h-cursor { cursor: col-resize ; } +.dome-xSplitter-v-cursor { cursor: row-resize ; } + +.dome-window-active .dome-xSplitLine { + background: #afafaf ; +} + +.dome-window-inactive .dome-xSplitLine { + background: #d6d6d6 ; +} + +.dome-xSplitPane, .dome-xSplitLine { + transition: all 0.1s ease-out ; +} + +/* -------------------------------------------------------------------------- */ diff --git a/Ivette/src/dome/src/renderer/layout/splitters.js b/Ivette/src/dome/src/renderer/layout/splitters.js new file mode 100644 index 0000000000000000000000000000000000000000..18007cfbbfcd7959ce319e884fb520b1af6977ac --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/splitters.js @@ -0,0 +1,389 @@ +// -------------------------------------------------------------------------- +// --- Splitters +// -------------------------------------------------------------------------- + +/** @module dome/layout/splitters */ + +import React from 'react' ; +import Props from 'prop-types' ; +import Dome from 'dome' ; +import { Layout } from 'dome/misc/events' ; +import './splitters.css' ; +import _ from 'lodash' ; + +// -------------------------------------------------------------------------- +// --- Splitter Layout +// -------------------------------------------------------------------------- + +const SUBVIEW = { overflow: 'hidden' }; + +const LAYOUT = { + // Container Class + hcursor: 'dome-xSplitter-h-cursor', + vcursor: 'dome-xSplitter-v-cursor', + nocursor: 'dome-xSplitter-no-cursor', + // Grab Class + hgrab: 'dome-xSplitter-grab dome-xSplitter-h dome-color-dragzone', + vgrab: 'dome-xSplitter-grab dome-xSplitter-v dome-color-dragzone', + hdrag: 'dome-xSplitter-grab dome-xSplitter-h dome-color-dragging', + vdrag: 'dome-xSplitter-grab dome-xSplitter-v dome-color-dragging', + // Non-Positionned Splitter Styles + hsplitter: { width:1, height: '100%' }, + vsplitter: { height:1, width: '100%' }, + // Hidden style + hide: { display: 'none' }, + // Non-Positionned Pane Styles + fixH: { flex: 'none', height: 'auto', width: '100%' }, + extH: { flex: 'auto', minHeight: 30, width: '100%' }, + fixW: { flex: 'none', width: 'auto', height: '100%' }, + extW: { flex: 'auto', minWidth: 10, height: '100%' }, + // Non-Positionned Contailer Styles + horizontal: { + display:'flex', flexFlow: 'row nowrap' + }, + vertical: { + display:'flex', flexFlow: 'column nowrap' + }, + // Positionned Container Style + container: { + display:'block' + } +}; + +const subview = ( primary,secondary ) => + Object.assign( {} , SUBVIEW , { primary,secondary } ); + +// Tabulated flex-box styles +const FLEX = { + 'HORIZONTAL': subview( LAYOUT.extW, LAYOUT.extW ), + 'LEFT': subview( LAYOUT.fixW, LAYOUT.extW ), + 'RIGHT': subview( LAYOUT.extW, LAYOUT.fixW ), + 'VERTICAL': subview( LAYOUT.extH, LAYOUT.extH ), + 'TOP': subview( LAYOUT.fixH, LAYOUT.extH ), + 'BOTTOM': subview( LAYOUT.extH, LAYOUT.fixH ) +}; + +// Tabulated hidden styles +const HIDDEN = { + 'HORIZONTAL': subview( LAYOUT.hide, LAYOUT.extW ), + 'LEFT': subview( LAYOUT.hide, LAYOUT.extW ), + 'RIGHT': subview( LAYOUT.extW, LAYOUT.hide ), + 'VERTICAL': subview( LAYOUT.hide, LAYOUT.extH ), + 'TOP': subview( LAYOUT.hide, LAYOUT.extH ), + 'BOTTOM': subview( LAYOUT.extH, LAYOUT.hide ) +}; + +// Horizontal / Vertical mode +const LR = { + 'HORIZONTAL': true, + 'LEFT': true, + 'RIGHT': true, + 'VERTICAL': false, + 'TOP': false, + 'BOTTOM': false +}; + +// -------------------------------------------------------------------------- +// --- Splitter Component +// -------------------------------------------------------------------------- + +/** + @class + @summary Draggable split pane + @property {Direction} [dir] - Layout and dimensionning strategy + @property {string} [settings] - User-settings key for persistent splitter position + @property {number} [margin] - Minimal margin from container edges + @property {boolean} [unfold] - whether to display or not the slider component (by default) + @description + Layout two panels horizontally or vertically with a draggable splitter. + Clicking the splitter bar with any modifier key restore its natural position. + + The visibility of the slider component (the fixed size one, or the primary one) can + be defined by the `unfold` property. + + ##### Direction + + | Tag | Description + |:-------------------:|------------------------------------------------- + | `'HORIZONTAL'` | Horizontal layout (default) + | `'LEFT'`, `'RIGHT'` | Horizontal layout with _fixed_ left or right component + | `'VERTICAL'` | Vertical layout + | `'TOP'`, `'BOTTOM'` | Vertical layout with _fixed_ top or bottom component + + When resizing the entire component, free available space is distributed among both children + except when one is _fixed_ by the `dir` property. + Typically, if your component has a left side-bar, you would provide a `LEFT` direction + to the splitter. + + + ##### Children + + The component is designed for two children. If no-children is given, the + component returns `undefined`. If only one children is provided, it is + rendered as is-it, without any additional decoration. Extra chidren after the + 2nd are simply not rendered. + + + ##### Borders & Margin + + Primary and secondary components are laidout within positionned div elements with hidden overflows. + If your components have borders, you should adjust their CSS box-sizing property to `'border-box'`. + Margin with `'100%'` height or width should be avoided and replaced by padding, otherwize + the left and bottom sides of the views are likely to be cropped. + +*/ + +export class Splitter extends React.Component { + + // -------------------------------------------------------------------------- + // --- Life Cycle + // -------------------------------------------------------------------------- + + constructor(props) { + super(props); + this.handleReset = this.handleReset.bind(this); + this.handleClick = this.handleClick.bind(this); + this.handleResize = this.handleResize.bind(this); + this.handleDragInit = this.handleDragInit.bind(this); + this.handleDragMove = this.handleDragMove.bind(this); + this.handleDragStop = this.handleDragStop.bind(this); + this.doDragMove = _.throttle( this.doDragMove , 100 ); + this.lr = LR[ this.props.dir ]; + this.margin = Math.max( 32 , this.props.margin || 0 ); + this.state = { + dragging: false, // Splitter is currently dragging + absolute: false, // Splitter is positionned with offset + anchor: 0, // Invariant: anchor == mouse position - offset + offset: 0 // Position of splitter edge from container edge + }; + } + + // -------------------------------------------------------------------------- + // --- Mounting + // -------------------------------------------------------------------------- + + componentDidMount() { + if (this.refs.container && this.refs.splitter) { + const container = this.refs.container.getBoundingClientRect() ; + const dimension = this.lr ? container.width : container.height ; + this.range = dimension - this.margin ; + const settings = this.props.settings ; + if (settings) { + const offset = Dome.getWindowSetting(settings,-1); + if (this.margin <= offset && offset <= this.range) + this.setState({ absolute: true, offset }); + } + } + Dome.on( 'dome.defaults', this.handleReset ); + } + + componentWillUnmount() { + Dome.off( 'dome.defaults', this.handleReset ); + } + + componentDidUpdate() { + this.lr = LR[ this.props.dir ]; + this.margin = Math.max( 32 , this.props.margin || 0 ); + } + + // -------------------------------------------------------------------------- + // --- Reset Offset + // -------------------------------------------------------------------------- + + handleReset() { + this.setState({ absolute: false, dragging: false, anchor: 0, offset: 0 }); + Dome.setWindowSetting(this.props.settings, -1); + } + + handleClick(event) { + if (event.altKey || event.ctrlKey || event.cmdKey || event.shiftKey) + this.handleReset(); + } + + // -------------------------------------------------------------------------- + // --- Resizing Handler + // -------------------------------------------------------------------------- + + handleResize() { + // Defensive + if (this.refs.container && this.refs.splitter && this.state.absolute) { + let container = this.refs.container.getBoundingClientRect() ; + let dimension = this.lr ? container.width : container.height ; + if (dimension == 0) return; + let newrange = dimension - this.margin ; + let newoffset ; + switch(this.props.dir) { + case 'LEFT': + case 'TOP': + newoffset = this.state.offset ; + break; + case 'RIGHT': + case 'BOTTOM': + newoffset = this.state.offset + newrange - this.range ; + break; + default: + newoffset = this.state.offset + (newrange - this.range) / 2 ; + break; + } + this.range = newrange ; + if ( this.margin <= this.range) { + if (newoffset > this.range) newoffset = this.range ; + if (newoffset < this.margin) newoffset = this.margin ; + } else { + newoffset = dimension / 2 ; + } + this.setState( { offset: newoffset } ); + } + } + + // -------------------------------------------------------------------------- + // --- Init Drag + // -------------------------------------------------------------------------- + + handleDragInit(evt) { + evt.preventDefault(); + // Invariant: offset == position - anchor + let position = this.lr ? evt.clientX : evt.clientY ; + // Defensive + if (this.refs.splitter && this.refs.container) { + let splitter = this.refs.splitter.getBoundingClientRect() ; + let container = this.refs.container.getBoundingClientRect() ; + let dimension = this.lr ? container.width : container.height ; + let offset = this.lr + ? splitter.left - container.left + : splitter.top - container.top ; + this.range = dimension - this.margin ; + if (this.margin <= offset && offset <= this.range) { + let anchor = position - offset ; + this.setState( { dragging: true, absolute: true, + anchor: anchor, offset: offset } ); + } + } + } + + // -------------------------------------------------------------------------- + // --- Move Drag + // -------------------------------------------------------------------------- + + // Throttled 100ms + doDragMove(client) { + // Invariant: offset == position - anchor + let offset = client - this.state.anchor ; + if (this.margin <= offset && offset <= this.range) + this.setState( { offset: offset, absolute: true } ); + } + + // Not throttled (non-persistent event) + handleDragMove(evt) { + this.doDragMove(this.lr ? evt.clientX : evt.clientY); + } + + // -------------------------------------------------------------------------- + // --- Stop Drag + // -------------------------------------------------------------------------- + + handleDragStop(evt) { + Dome.setWindowSetting( this.props.settings, this.state.offset ); + this.setState({ dragging: false }); + } + + // -------------------------------------------------------------------------- + // --- Rendering + // -------------------------------------------------------------------------- + + render() { + const children = this.props.children ; + switch(children.length) { + case 0: + return undefined; + case 1: + return children[0]; + default: + let dir = this.props.dir; + let dragging = this.state.dragging; + let offset = this.state.offset; + let cursor = dragging + ? (this.lr ? LAYOUT.hcursor : LAYOUT.vcursor) + : LAYOUT.nocursor ; + let grab = this.state.dragging + ? (this.lr ? LAYOUT.hdrag : LAYOUT.vdrag ) + : (this.lr ? LAYOUT.hgrab : LAYOUT.vgrab ) ; + let container, splitter, primary, secondary ; + let { unfold=true } = this.props ; + let absolute = this.state.absolute ; + if (!unfold) + { + container = LAYOUT.container ; + splitter = LAYOUT.hide ; + let hidden = HIDDEN[dir] ; + primary = hidden.primary ; + secondary = hidden.secondary ; + } + else if (!absolute) + { + container = this.lr ? LAYOUT.horizontal : LAYOUT.vertical ; + splitter = this.lr ? LAYOUT.hsplitter : LAYOUT.vsplitter ; + let flex = FLEX[dir]; + primary = flex.primary ; + secondary = flex.secondary ; + } + else + { + container = LAYOUT.container ; + if (this.lr) { + primary = { position: 'absolute', left: 0, width: offset, height: '100%' }; + splitter = { position: 'absolute', left: offset, width: 1, height: '100%' }; + secondary = { position: 'absolute', left: offset+1, right: 0, height: '100%' }; + } else { + primary = { position: 'absolute', top: 0, height: offset, width: '100%' }; + splitter = { position: 'absolute', top: offset, height: 1, width: '100%' }; + secondary = { position: 'absolute', top: offset+1, bottom: 0, width: '100%' }; + } + Object.assign( primary , SUBVIEW ); + Object.assign( secondary , SUBVIEW ); + } + return ( + <div ref="container" + onMouseUp={dragging ? this.handleDragStop : undefined} + onMouseMove={dragging ? this.handleDragMove : undefined} + className={'dome-xSplitter-container ' + cursor} + style={container}> + <div ref="primary" style={primary} className='dome-xSplitPane dome-container'> + {children[0]} + </div> + <div ref="splitter" style={splitter} className='dome-xSplitLine'> + <div className={grab} + onMouseDown={this.handleDragInit} + onClick={absolute ? this.handleClick : undefined} /> + </div> + <div ref="secondary" style={secondary} className='dome-xSplitPane dome-container'> + {children[1]} + </div> + <Layout onResize={this.handleResize} /> + </div> + ); + } + } + +} + +// -------------------------------------------------------------------------- +// --- Props & Defaults +// -------------------------------------------------------------------------- + +Splitter.propTypes = { + dir: Props.oneOf(['HORIZONTAL','VERTICAL','LEFT','RIGHT','TOP','BOTTOM']), + settings: Props.string, + margin: Props.number +}; + +Splitter.defaultProps = { + dir: 'HORIZONTAL', + margin: 32 +}; + +// -------------------------------------------------------------------------- + +export default { Splitter }; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/layout/tabs.css b/Ivette/src/dome/src/renderer/layout/tabs.css new file mode 100644 index 0000000000000000000000000000000000000000..f604114d0a72f62f98505e1456e6111fc7375c4e --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/tabs.css @@ -0,0 +1,98 @@ +/* -------------------------------------------------------------------------- */ +/* --- Tabs & Tab Style Sheet --- */ +/* -------------------------------------------------------------------------- */ + +/* Tabs Bar */ + +.dome-xTabsBar { + flex: 0 1 auto ; + position: relative ; + height: 20px ; + width: calc( 100% + 1px ); /* hides last border */ + display: flex ; + flex: row wrap ; + border-width: 1px ; + border-bottom-style: solid ; +} + +/* Tab Content */ + +.dome-xTab-content { + width: 100% ; + height: 100% ; +} + +/* Tab Item */ + +.dome-xTab { + flex: 1 1 150px ; + position: relative ; + font-size: 10px ; + text-align: center ; + padding: 4px 20px 4px 20px ; + border-color: inherit ; + border-width: 1px ; + border-top-style: none ; + border-bottom-style: none ; + border-left-style: none ; + border-right-style: solid ; +} + +.dome-window-inactive .dome-xTab.dome-inactive { + color: #606060 ; + border-color: inherit ; +} + +.dome-xTab.dome-inactive:hover { + background: #bababa ; +} + +.dome-xTab.dome-inactive { + color: #606060 ; + border-color: #9c9c9c ; + background: #b4b4b4 ; +} + +.dome-window-inactive .dome-xTab.dome-inactive { + color: #b0b0b0 ; + background: #e6e6e6 ; +} + +/* Closing Tab button */ + +.dome-xTab-closing { + display: inline ; + border-radius: 4px ; + position: absolute ; + width: 12px ; + height: 12px ; + padding: 2px ; + top: 2px ; + opacity: 0 ; + transition: opacity .1s linear 0.1s , background .1s linear 0.1s ; +} + +.dome-platform-darwin .dome-xTab-closing { + right: initial ; + left: 5px ; +} + +.dome-xTab-closing { + right: 5px ; + left: initial ; +} + +.dome-active .dome-xTab-closing:hover { + background: #c0c0c0 ; +} + +.dome-inactive .dome-xTab-closing:hover { + background: #a0a0a0 ; +} + +.dome-xTab:hover .dome-xTab-closing , .dome-xTab:hover .dome-xTab-closing +{ + opacity: 1 ; +} + +/* -------------------------------------------------------------------------- */ diff --git a/Ivette/src/dome/src/renderer/layout/tabs.js b/Ivette/src/dome/src/renderer/layout/tabs.js new file mode 100644 index 0000000000000000000000000000000000000000..19987a0948c9d522ae7220b72689802227213077 --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/tabs.js @@ -0,0 +1,123 @@ +import React from 'react' ; +import { Icon } from 'dome/controls/icons' ; +import './tabs.css' ; + +/** @module dome/layout/tabs */ + +// -------------------------------------------------------------------------- +// --- Tabs Bar +// -------------------------------------------------------------------------- + +/** + @class + @summary Pure Container for tab buttons. + @description + Shall contains [Tab](module-dome_layout_tabs.Tab.html) instances. +*/ + +export function TabsBar(props) { + return ( + <div className='dome-xTabsBar dome-color-frame'> + {props.children} + </div> + ); +} + +// -------------------------------------------------------------------------- +// --- Single Tab +// -------------------------------------------------------------------------- + +const VISIBLE = { display: 'block' }; +const HIDDEN = { display: 'none' }; + +/** + @class + @summary Pure Component for rendering a tab button. + @property {string} [id] - tab's identifier + @property {component} [label] - tab's label + @property {string} [title] - tab's tooltip + @property {string} [closing] - closing button's tooltip (defaults to `"Close Tab"`) + @property {string} [selection] - Currently selected tab identifier + @property {function} [onSelection] - selection callcack, feed with value + @property {function} [onClose] - selection callcack, feed with value + @property {boolean} [default] - if `true`, selected tab by default + @property {boolean} [content] - render content instead of tab + @description + A single tab selector. Shall only be used as a children + of [TabsBar](module-dome_layout_tabs.TabsBar.html) + or [Frame](module-dome_layout_frames.Frame.html). + + When `content` is positionned, the component renders + its content children instead of the tab button. In such a case, content + is displayed only when selected. + + __Remark__: on Mac OSX, the close button appears on the left-side of the tab. +*/ + +export function Tab(props) { + const selected = props.id === props.selection ; + if (props.content) { + //--- Content Rendering + const style = selected ? VISIBLE : HIDDEN ; + return ( + <div className='dome-xTab-content dome-container' style={style}> + {props.children} + </div> + ); + } else { + //--- Tab Rendering + const onClick = props.onSelection && (() => props.onSelection(props.id)); + const onClose = props.onClose && (() => props.onClose(props.id)); + var closing = onClose ? ( + <Icon className="dome-xTab-closing" + title={props.closing || "Close Tab"} + name="CROSS" onClick={onClose} /> + ) : undefined ; + const classes = 'dome-xTab' + ( selected ? ' dome-active' : ' dome-inactive' ) ; + return ( + <label + className={classes} title={props.title} onClick={onClick}> + {props.label} + {closing} + </label> + ); + } +} + +// -------------------------------------------------------------------------- +// --- TabsPane +// -------------------------------------------------------------------------- + +/** + @class + @summary Pure Container for tab contents. + @property {string} selection - tab identifier to render + @property {Tab[]} children - tabs (content) to render + @description + Shall contains [Tab](module-dome_layout_tabs.Tab.html) instances. + Only the selected tab identifier will be displayed, although all tab + contents remains properly mounted. If no tab is selected, + no content is displayed. +*/ + +export function TabsPane({ selection, children }) { + const showTab = (elt) => React.cloneElement(elt, { content: true, selection }); + return ( + <React.Fragment> + {React.Children.map(children , showTab)} + </React.Fragment> + ); +} + +// -------------------------------------------------------------------------- +// --- Dome Class (private) +// -------------------------------------------------------------------------- + +import { register } from 'dome/misc/register' ; + +register(TabsBar, 'DOME_TABSBAR'); +register(Tab, 'DOME_TABSBAR_ITEM'); + +export default { Tab , TabsBar , TabsPane } ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/layout/toolbars.css b/Ivette/src/dome/src/renderer/layout/toolbars.css new file mode 100644 index 0000000000000000000000000000000000000000..453fe172fbe3e651aed0fb11c584be8727bd74c0 --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/toolbars.css @@ -0,0 +1,228 @@ +/* -------------------------------------------------------------------------- */ +/* --- Styling ToolBars --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xToolBar { + flex: 0 0 auto ; + width: 100% ; + display: flex ; + flex-direction: row ; + flex-wrap: wrap ; + align-items: baseline ; + border-width: 1px ; + border-bottom-style: solid ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Styling ToolBar Spaces --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xToolBar-inset { + flex: 0 1 5px ; +} + +.dome-xToolBar-space { + flex: 0 1 20px ; +} + +.dome-xToolBar-filler { + flex: 1 1 20px ; +} + +.dome-xToolBar-separator + .dome-xToolBar-separator { + display: none ; +} + +.dome-xToolBar-separator { + flex: 0 0 10px ; + align-self: center ; +} + +.dome-xToolBar-vrule { + width: 2px ; + position: relative ; + left: 4px ; + height: 18px ; +} + +.dome-window-active .dome-xToolBar-vrule { + background: #aaa ; +} + +.dome-window-inactive .dome-xToolBar-vrule { + background: #ddd ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Styling ToolBar Buttons --- */ +/* -------------------------------------------------------------------------- */ + +/* Layout */ + +.dome-xToolBar-Control { + flex: 0 0 auto ; + height: 26px ; + margin: 6px 5px 6px 5px ; + padding: 2px 8px 2px 8px ; + box-shadow: 0 1px 1px rgba(0, 0, 0, .06); + border: 1px solid transparent; + border-radius: 4px; + outline: none ; +} + +.dome-xToolBar-Control svg { + position: relative ; +} + +.dome-xToolBar-Control svg + label { + margin-left: 4px ; +} + +/* Background */ + +.dome-window-active .dome-xToolBar-Control { + background-image: linear-gradient(to bottom, #e8e8e8 0, #f1f1f1 100%); +} + +.dome-window-active .dome-xToolBar-Control:hover:not(:disabled) { + background-color: #ffffff ; + background-image: none ; +} + +.dome-window-active .dome-xToolBar-Control.dome-xToolBar-positive:not(:disabled) { + background-image: linear-gradient(to bottom, #34ff52 0%, #48fd64 100%); +} + +.dome-window-active .dome-xToolBar-Control.dome-xToolBar-positive:hover:not(:disabled) { + background-color: #00ff00 ; + background-image: none ; +} + +.dome-window-active .dome-xToolBar-Control.dome-xToolBar-negative:not(:disabled) { + color: #ccc ; + fill: #ccc ; + background-image: linear-gradient(to bottom, #ec453e 0%, #ff4c47 100%); +} + +.dome-window-active .dome-xToolBar-Control.dome-xToolBar-negative:hover:not(:disabled) { + background-color: red ; + background-image: none ; +} + +.dome-window-active .dome-xToolBar-Control.dome-xToolBar-warning:not(:disabled) { + background-image: linear-gradient(to bottom, #fece72 0%, #fcaa0e 100%); +} + +.dome-window-active .dome-xToolBar-Control.dome-xToolBar-warning:hover:not(:disabled) { + background-color: orange ; + background-image: none ; +} + +.dome-window-active .dome-xToolBar-Control.dome-xToolBar-cancel:not(:disabled) { + background-color: #c2c0c2 ; + background-image: none ; +} + +.dome-window-active .dome-xToolBar-Control.dome-xToolBar-cancel:hover:not(:disabled) { + background-image: linear-gradient(to bottom, #e8e8e8 0, #f1f1f1 100%); +} + +.dome-window-inactive .dome-xToolBar-Control { + box-shadow: none ; + background-image: none ; +} + +/* Activated */ + +.dome-window-active .dome-xToolBar-Control:active:not(:disabled) { + fill: #ddd ; + color: #ddd ; + background-color: gray ; + background-image: none ; +} + +/* Disabled */ + +.dome-window-active .dome-xToolBar-Control:disabled { + fill: #ccc ; + color: #ccc ; + box-shadow: none ; + border-color: #bbb ; +} + +.dome-window-inactive .dome-xToolBar-Control:disabled { + fill: #ccc ; + color: #ccc ; +} + +/* Selected */ + +.dome-window-active .dome-xToolBar-Control.dome-selected { + fill: #fff; + color: #fff; + border: 1px solid transparent ; + background-color: #7f7f7f ; + background-image: none ; +} + +.dome-window-active .dome-xToolBar-Control.dome-selected:hover { + background-color: #888 ; + background-image: none ; +} + +.dome-window-inactive .dome-xToolBar-Control.dome-selected { + fill: #eee; + color: #eee; + background-color: #ccc ; +} + +/* Selected & Disabled */ + +.dome-window-active .dome-xToolBar-Control.dome-selected:disabled { + fill: #ccc ; + color: #ccc ; + border: 1px solid #bbb ; + background-color: #eee ; +} + +.dome-window-inactive .dome-xToolBar-Control.dome-selected:disabled { + fill: #ccc ; + color: #ccc ; + border-color: #ddd ; + background-color: #eee ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Styling ToolBar Button Group --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xToolBar-Group { + display: flex ; + flex-direction: row ; + flex-wrap: nowrap ; + margin: 6px 5px 6px 5px ; +} + +.dome-xToolBar-Group .dome-xToolBar-Control { + margin: 0 ; +} + +.dome-xToolBar-Group .dome-xToolBar-Control:not(:first-child) { + border-left: 0 ; +} + +.dome-xToolBar-Group > .dome-xToolBar-Control:first-child { + border-top-right-radius: 0 ; + border-bottom-right-radius: 0 ; +} + +.dome-xToolBar-Group > .dome-xToolBar-Control:last-child { + border-top-left-radius: 0 ; + border-bottom-left-radius: 0 ; +} + +.dome-xToolBar-Group > .dome-xToolBar-Control:not(:first-child):not(:last-child) { + border-radius: 0 ; +} + +/* -------------------------------------------------------------------------- */ diff --git a/Ivette/src/dome/src/renderer/layout/toolbars.js b/Ivette/src/dome/src/renderer/layout/toolbars.js new file mode 100644 index 0000000000000000000000000000000000000000..0aa477f44ff2a38aafb7b1a5f65c3a4c4a98f6c4 --- /dev/null +++ b/Ivette/src/dome/src/renderer/layout/toolbars.js @@ -0,0 +1,198 @@ +// -------------------------------------------------------------------------- +// --- ToolBars +// -------------------------------------------------------------------------- + +/** @module dome/layout/toolbars */ + +import React from 'react' ; +import './toolbars.css' ; + +// -------------------------------------------------------------------------- +// --- ToolBar Container +// -------------------------------------------------------------------------- + +/** + @class + @summary Container for toolbar items + @description + See also [Frame](module-dome_layout_frames.Frame.html) containers. + */ +export class ToolBar extends React.Component { + + constructor(props) { + super(props); + } + + render() { + const children = this.props.children ; + return React.Children.count(children) > 0 && ( + <div className='dome-xToolBar dome-color-frame'> + <div className='dome-xToolBar-inset'/> + {children} + <div className='dome-xToolBar-inset'/> + </div> + ); + } + +} + +// -------------------------------------------------------------------------- +// --- ToolBar Spaces +// -------------------------------------------------------------------------- + +/** + @class + @summary Fixed (tiny) space +*/ +export const Inset = (() => <div className='dome-xToolBar-inset'/>); + +/** + @class + @summary Fixed space +*/ +export const Space = (() => <div className='dome-xToolBar-space'/>); + +/** + @class + @summary Extensible space (can be used to right-align controls) +*/ +export const Filler = (() => <div className='dome-xToolBar-filler'/>); + +/** + @class + @summary Vertical rule +*/ +export const Separator = () => ( + <div className='dome-xToolBar-separator'> + <div className='dome-xToolBar-vrule'/> + </div> +); + +// -------------------------------------------------------------------------- +// --- ToolBar Button +// -------------------------------------------------------------------------- + +import { SVG } from 'dome/controls/icons' ; + +const SELECT = 'dome-xToolBar-Control dome-selected' ; +const BUTTON = 'dome-xToolBar-Control dome-color-frame' ; +const KIND = (kind) => kind ? ' dome-xToolBar-' + kind : ''; + +const isSelected = ( { selected , selection , value } ) => ( + selected !== undefined ? selected : ( value !== undefined && value === selection ) +); + +const isDisabled = ( { enabled=true, disabled=false } ) => (disabled || !enabled) ; +const onClick = ( { onClick , value } ) => onClick ? (() => onClick(value)) : undefined ; + +/** + @class + @property {string} [icon] - Button icon name (See [gallery](gallery-icons.html)) + @property {string} [label] - Button label + @property {string} [title] - Button tooltip + @property {string} [kind] - Styled button (see below) + @property {boolean} [selected] - Selected button (default: `false`) + @property {boolean} [disabled] - Disabled button (default: `false`) + @property {boolean} [enabled] - Enabled button (default: `true`) + @property {any} [value] - button's value + @property {any} [selection] - Currently selected value + @property {function} [onClick] - Button callback (receives the current value) + @summary toolbar button + @description + + By default, the propery `selected` is computed from properties `value` + and `selection`, when provided. + + The callback is given the `value` property, if any. + + The different available kinds for styling a (non-selected) button are: + - `'default'`: normal button; + - `'cancel'`: normal button, in dark grey; + - `'warning'`: warning button, in orange; + - `'positive'`: positive button, in green; + - `'negative'`: negative button, in red. + +*/ +export const Button = ( props ) => ( + <button + disabled={isDisabled(props)} + className={isSelected(props) ? SELECT : (BUTTON + KIND(props.kind))} + onClick={onClick(props)} + title={props.title} + > + {props.icon && <SVG id={props.icon} />} + {props.label && <label>{props.label}</label>} + </button> +); + +// -------------------------------------------------------------------------- +// --- ToolBar Button Group +// -------------------------------------------------------------------------- + +/** + @class + @property {Button[]} children - Buttons in the group + @property {any} [value] - Passed to children as `selection` property + @property {any} [onChange] - Passed to children as `onClick` property + @property {any} [...props] - Properties passed to all children + @summary toolbar button group +*/ +export const ButtonGroup = + ({ children, value, onChange, ...props }) => + { + if (value !== undefined ) props.selection = value ; + if (onChange !== undefined ) props.onClick = onChange ; + return ( + <div className='dome-xToolBar-Group'> + {React.Children.map(children,(elt) => React.cloneElement(elt,props))} + </div> + ); + }; + +// -------------------------------------------------------------------------- +// --- ToolBar Menu +// -------------------------------------------------------------------------- + +/** + @class + @property {any} [value] - selected option's value + @property {function} [onChange] - selection callback (receives option value) + @property {boolean} [disabled] - disable the selector (default: `false`) + @property {boolean} [enabled] - enable the selector (default: `true`) + @property {option[]} children - Array of menu options + @summary Toolbar selector menu + @description + + Behaves likes a standard `<select>` element, except that callback directly + receives the select value, not the entire event. + + The list of options shall be given with standard `<option value={...} label={...}>` + elements. + +*/ +export const Select = (props) => ( + <select className='dome-xToolBar-Control dome-color-frame' + value={props.value} + disabled={isDisabled(props)} + onChange={(props.onChange && ((evt) => props.onChange(evt.target.value)))} + > + {props.children} + </select> +); + +// -------------------------------------------------------------------------- +// --- Export & Registration +// -------------------------------------------------------------------------- + +import { register } from 'dome/misc/register' ; + +register( ToolBar, 'DOME_TOOLBAR' ); +register( Inset , 'DOME_TOOLBAR_ITEM' ); +register( Space , 'DOME_TOOLBAR_ITEM' ); +register( Separator , 'DOME_TOOLBAR_ITEM' ); +register( Filler , 'DOME_TOOLBAR_ITEM' ); +register( Button , 'DOME_TOOLBAR_ITEM' ); + +export default { ToolBar , Space , Inset, Separator, Filler, Button, ButtonGroup, Select }; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/table/arrays.js b/Ivette/src/dome/src/renderer/table/arrays.js new file mode 100644 index 0000000000000000000000000000000000000000..9663577ff459ef5b95d9743552fa333cdc90538a --- /dev/null +++ b/Ivette/src/dome/src/renderer/table/arrays.js @@ -0,0 +1,489 @@ +// -------------------------------------------------------------------------- +// --- Table Models +// -------------------------------------------------------------------------- + +/** @module dome/table/arrays */ + +import { Model, ASC, DESC } from 'dome/table/models' ; + +// -------------------------------------------------------------------------- +// --- Ordering +// -------------------------------------------------------------------------- + +// Compute the value of an item +const getValueWith = + ( item , value ) => + ( item === undefined ? undefined : + typeof(value) === 'function' ? value(item) : + item[value] ); + +// Compute the primary ordering function +const comparisonWith = (sorting) => { + switch(typeof(sorting)) { + + case 'function': + return sorting ; + + case 'string': + return (a,b) => { + if ( a === b ) return 0 ; + if ( a === undefined ) return 1 ; + if ( b === undefined ) return -1 ; + const va = a[sorting]; + const vb = b[sorting]; + if ( va === vb ) return 0; + if ( va === undefined ) return 1 ; + if ( vb === undefined ) return -1 ; + if ( va < vb ) return -1; + if ( va > vb ) return 1; + return 0; + }; + + case 'object': + const { sortBy, sortDirection=ASC } = sorting ; + return (a,b) => { + if ( a === b ) return 0 ; + if ( a === undefined ) return 1 ; + if ( b === undefined ) return -1 ; + const isFun = typeof(sortBy)==='function' ; + const va = isFun ? sortBy(a) : a[sortBy] ; + const vb = isFun ? sortBy(b) : b[sortBy] ; + if ( va === vb ) return 0; + if ( va === undefined ) return 1 ; + if ( vb === undefined ) return -1 ; + switch(sortDirection) { + case ASC: + if (va < vb) return -1; + if (va > vb) return 1; + break; + case DESC: + if (va < vb) return 1; + if (va > vb) return -1; + break; + } + return 0; + }; + + default: + return () => 0; + + } +}; + +// Make a chainable order +const chainableOrder = ( order ) => { + + const compare = (a,b) => { + for (var k = 0; k < order.length ; k++) { + const cmp = (order[k])(a,b); + if (cmp) return cmp; + } + return 0; + }; + + compare.thenWith = (sorting) => + sorting ? + chainableOrder( order.slice().push(comparisonWith(sorting)) ) + : compare ; + + return compare ; +}; + +/** + @summary Comparison helper. + @method + @param {any} sorting - the sorting properties + @return {function} the corresponding comparison function + @description + +This function is a helper for comparing items, by comparing +values extracted from them with chaining. It returns +a comparison function that you can use, for instance, +in `Array.sort` fort sorting arrays. + +##### Comparison + +The comparison order is defined according the `sorting` parameter +provided to the helper: + +If `sorting` is a function, it is used as the primary comparison function. +When items compare equal, chained comparisons are used to refine the +ordering (see Chaining below). + +If `sorting` is a property name (a string), items `a` and `b` are ordered +by comparing their respective values `a[sorting]` and `b[sorting]` for +this property. + +If `sorting` as an object, it shall provides `{ sortBy, sortDirection }` +properties and the comparison function is defined as follows: +- `sortBy` can be a function or a property name. +If a function is given, items `a` and `b` are ordered by comparing +values `sortBy(a)` and `sortBy(b)`. Otherwize, they are ordered by +comparing `a[sortBy]` and `b[sortBy]`. +- `sortDirection` can be either `ASC` for normal comparison or `DESC` +for reversing the comparison. +If no direction is given (or any other value) `ASC` is assumed. + +When computing comparison, `undefined` values are _always_ rejected to the +end of the ordering, whatever the specified direction. + +##### Chaining + +The returned comparison function can be chained with a secondary +comparison function, which will be used when two items compare equal. + +You can chain as many comparison functions you want by using +`.thenWith(sorting)` like in the example below. Each call to `.thenWith` returns +a different comparison function that can be safely forked with subsequent calls +to `.thenWith` as illustrated in the second example. + +Remark than `compareWith` and `.thenWith` also accept undefined or null values, which +are considered neutral. + +@example +// Chaining Comparison +items.sort( + compareWith({sortBy:'name',sortDirection: ASC}) + .thenWith( (a,b) => a.priority - b.priority ) + .thenWith({sortBy:'age',sortDirection: DESC}) +); + +@example +// Forking Comparison +const primary = compareWith( (a,b) => a.priority - b.prioroty ); +const byName = primary.thenWith('name'); +const byAge = primary.thenWith('age'); + +*/ +export const compareWith = + ( sorting ) => + ( sorting ? chainableOrder([ comparisonWith(sorting) ]) : () => 0 ); + +// -------------------------------------------------------------------------- +// --- Comparison Ring +// -------------------------------------------------------------------------- + +/** + @class + @summary Helper for column comparison. + @description +A comparison ring can be used to implement column ordering, where each +column selection _refines_ the previous ordering. + +Hence, the ring holds the current comparison order and it is well suited +for being used in conjunction with [Table](module-dome_table_views.Table.html) +components. + +A comparison specification can be a property name or a function. +See [compareWith](module-dome_table_arrays.html#compareWith) for more details. +By default, the ring uses the column identifier as a property name for comparing. + +Initially, the ordering is _natural_. +*/ +export class ComparisonRing { + + /** + @param {id|function} [natural] - default (natural) order + */ + + constructor(natural) { + this.columns = {} ; + this.natural = natural && comparisonWith(natural) ; + this.compare = this.compare.bind(this); + this.ring = [] ; + this.sort = undefined ; + } + + /** + @summary Current order comparison. + @description + Returns the comparison function corresponding to the current order. + The comparison function is _chainable_, see + [compareWith](module-dome_table_arrays.html#compareWith) for more details. + */ + compareWith() + { + if (!this.sort) { + const ordering = this.ring.map( + ({sortBy,sortDirection}) => + comparisonWith({ + sortBy: this.columns[sortBy] || sortBy , + sortDirection + }) + ); + if (this.natural) ordering.push(this.natural); + this.sort = chainableOrder(ordering); + } + return this.sort; + } + + /** + @summary Refine current order comparison. + @description + Short cut for `this.compareWith().thenWith(sorting)` + */ + thenWith(sorting) { + return this.compareWith().thenWith(sorting); + } + + /** + @summary Get value for ordering a column. + @param {any} item - the item to compare with + @param {string} column - the column identifier + @return {any} item's value for the column + Returns the value used to order an item within a given column. + */ + getValue(item,column) { + return getValueWith(item,this.columns[column] || column); + } + + /** + @summary Set value to order a column. + @param {string} column - column identifier + @param {string|function} [value] - value accessor (defaults to `column`) + @description + Set the sorting specification (property name or function) for the given column. + */ + setValue( column , value ) { + this.columns[column] = value ; + } + + /** Sets natural ordering (property name or value accessor) */ + setNatural( natural ) { + this.natural = natural ; + } + + /** @summary Compare two items with respect to the current ordering. + @description + You can use `this.compare` as a closure to the current comparison function + (no need for `this.compare.bind(this)`). + */ + compare(a,b) { + return this.order()(a,b); + } + + /** @summary Return current ordering. + @return {object} ordering specification + @description + Return the last `{ sortBy, sortDirection }` ordering. + Shall be used for the Table view. */ + getOrdering() { + return this.ring[0] ; + } + + /** + @summary Specify current ordering. + @param {object} sorting - the new ordering + @description + Use the specified `{ sortBy, sortDirection }` ordering, and refine it with + the previous one. + + If `sorting` is undefined, reset the ring to the natural ordering. + */ + setOrdering( sorting ) { + if (sorting) { + const key = sorting.sortBy ; + this.ring = this.ring.filter( (s) => s.sortBy !== key ); + this.ring.unshift( sorting ); + } else { + this.ring = [] ; + } + this.sort = undefined ; + } + +} + +// -------------------------------------------------------------------------- +// --- Unsorted Model +// -------------------------------------------------------------------------- + +/** + @summary A table Model for unsorted datasets. + @description + + This class implements a simple [Model](module-dome_table_models.Model.html) + where item's are identified by their index. Such a model is not adapted to + re-ordering and filtering, because table views will have no way to synchronize + the selected index before and after re-ordering, hence the name. + +*/ + +export class UnsortedModel extends Model { + + /** + @param {number} [count] - the initial size (default `0`) + */ + constructor(count=0) { + super(); + this.count = count < 0 ? 0 : count ; + } + + /** + @summary Set the number of items. + @param {number} n - the number of items + @param {boolean} [reload] - force reloading (false by default) + @description + Triggers a reload if the item count has changed, + unless you force it. + */ + setItemCount(n,reload=false) { + if (n<0) n=0; + if ( reload || n != this.count ) { + this.count = n ; + this.reload(); + } + } + + getItemCount() { return this.count; } + + /** Identity, or `undefined` when out of range. */ + getItemAt(k) { + return 0 <= k && k < this.count ? k : undefined ; + } + + /** Identity, or `-1` when out of range. */ + getIndexOf(k) { + return 0 <= k && k < this.count ? k : -1 ; + } + +} + +// -------------------------------------------------------------------------- +// --- Array Model +// -------------------------------------------------------------------------- + +/** + @summary A table Model based on array. + @description + + This class implements a simple [Model](module-dome_table_models.Model.html) + implementation where item's are stored in an array. The model supports built-in + ordering thanks with a + [ComparisonRing](module-dome_table_arrays.ComparisonRing.html) + with additional filtering capabilities. + + The model keep items in sync with their ordered & filtered index by + injecting an `index` property in them each time the collection is re-ordered. + You shall not use `index` property for your own needs. + + Item objects can be modified in place, but you shall call `model.updateItem(item)` + or `model.reload()` to re-renderer the associated (visible) cells. + */ +export class ArrayModel extends Model { + + /** Initially empty model */ + constructor() { + super(); + this.ring = new ComparisonRing('index'); // Used for stable sorting + this.data = []; // Array of item elements + } + + /** Remove all items (and reload) */ + clear() { + this.data = [] ; + this.reload(); + } + + /** Add one or more items (and reload) */ + add( ...items ) { + this.data.push(...items); + this.reload(); + } + + /** + @summary Model items array. + @description +Returns the internal item array holding _all_ the items in the model. + +This array is _not_ sortered and filtered. You can obtain the current index of an item in +table views by accessing its `item.index` property, which is `undefined` if the item has been +filtered out. + +If you modify the internal item array, don't forget to call `reload()` after modifications +in order to keep views in sync. + */ + getData() { return this.data; } + + /** Replace the entire collection of items */ + setData(data) { + this.data = data || [] ; + this.reload(); + } + + _order() { + if (!this.order) { + const filter = this.filtering ; + const compare = this.ring.compareWith(); + const ordered = this.data.filter((item,index) => { + const ok = filter ? filter(item) : true ; + // Index inside initial collection is used for stable sort + item.index = ok ? index : undefined ; + return ok ; + }).sort(compare); + // Now set index in filtered & sorted collection + ordered.forEach((item,index) => item.index = index); + this.order = ordered ; + } + return this.order ; + } + + /** Return a _copy_ of the visible items */ + getItems() { return this._order().slice(); } + + /** Returns the number of visible items */ + getItemCount() { return (this._order()).length; } + + /** Returns the visible item at the given index */ + getItemAt(index) { return (this._order())[index] ; } + + /** Returns the index of an item */ + getIndexOf(item) { return item && item.index ; } + + /** @summary Current filtering function. + @return {function} `undefined` means no filtering + */ + getFiltering() { return this.filtering ; } + + /** Current ordering (see `ComparisonRing`) */ + getOrdering() { return this.ring.getOrdering(); } + + /** Set the filtering function */ + setFiltering(filter) { + this.filtering = filter ; + this.reload(); + } + + /** Set ordering (see `ComparisonRing`) */ + setOrdering(order) { + if (order === undefined || order.sortBy !== 'index') + { + this.ring.setOrdering(order); + this.reload(); + } + } + + /** Get the value of an item for the given column */ + getValue( item , column ) { + return this.ring.getValue( item , column ); + } + + /** Set the value-getter for the given column */ + setValue( column , value ) { + this.ring.setValue(column,value); + this.reload(); + } + + /** Re-order the items collection and re-render the table */ + reload() { + this.order = undefined ; + super.reload(); + } +} + +// -------------------------------------------------------------------------- +// --- Exports +// -------------------------------------------------------------------------- + +export default { compareWith , ComparisonRing , UnsortedModel } ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/table/models.js b/Ivette/src/dome/src/renderer/table/models.js new file mode 100644 index 0000000000000000000000000000000000000000..f0f53312345a8f0c4b1f5dd7360dc6c7ede8ea25 --- /dev/null +++ b/Ivette/src/dome/src/renderer/table/models.js @@ -0,0 +1,255 @@ +// -------------------------------------------------------------------------- +// --- Models +// -------------------------------------------------------------------------- + +/** @module dome/table/models */ + +import _ from 'lodash' ; +import { SortDirection } from 'react-virtualized' ; + +// -------------------------------------------------------------------------- +// --- Sorting +// -------------------------------------------------------------------------- + +/** Ascending Order (SortDirection) */ +export const ASC = SortDirection.ASC ; + +/** Descending Order (SortDirection) */ +export const DESC = SortDirection.DESC ; + +// -------------------------------------------------------------------------- +// --- Collection Model +// -------------------------------------------------------------------------- + +/** + @class + @summary Data Listener. + @description + + A Model is responsible for keeping the tables and lists views in sync + with their associated data sets. The model listens for updates, retrieves + items from their index, and re-render the views when necessary. + + + Model could be part of the global _Application State_, or part of a + statefull React Component, depending on your need as described in + the [Application Design](tutorial-application.html) tutorial. + + + Several tables may connect to the same table model, but they will share the + same number and ordering of items. However, each connected table will only + render its own range of items and will re-renderer only when impacted by + individual updates. + + + A Model instance may not hold the data directly. A table or list component + uses the model only as a _proxy_ reponsible for fetching the items with respect to + some current filtering and ordering selection. The model also serves as + a proxy for triggering table re-rendering when table data is updated. + + + To design your data model, you shall extends the base `Model` class and + override the public methods to fit your needs. + + - `getItemCount() -> number` (the number of items) + - `getItemAt(number) -> item` (the item at the given index) + - `getIndexOf(item) -> number` (the index of an item in the current orderer) + - `getValue(item,column) -> any` (the value associated to some item in a column) + + + To implement sorting, you shall also override the following methods: + + - `getOrdering() -> { sortBy, sortDirection }` + - `setOrdering({ sortBy, sortDirection }) -> ()` + + + Whenever data is added, removed, updated or re-ordered, the `Model` shall be + informed by calling one of the following methods: + + - `updateItem(item);` when an individual item shall be re-rendered (if ever visible) + - `updateIndex(index[,index]);` when an item or a range of items shall be re-rendered + - `reload();` for all other modifications of the collection, including filtering and re-ordering + + + Items count and items indices shall be consistent with the current filter(s) + and order(s) selected by the user. Tables are equipped with + callbacks on table headers that can be used to trigger re-ordering of your data, but + you can implement your own controls or use menus to do that. + + Items can be represented by any javascript values (string, integers, objects...). + Default table cell renderers expect items to be object with one property per column, but you + can override those default. The default `getValue` implementation simply returns the + item property corresponding to the column identifier. + + When some data is updated, selection and scrolling of the views will be + preserved based on item's value. Table and List views will + keep each rendered item in sync with their index thanks to methods `getItemAt` + and `getIndexOf` that you provide with the Model. + + Hence, items implementation shall contains enough information to uniquely identify them, + whatever their current index. + + ##### Model Helpers + + The module [dome/table/arrays](module-dome_table_arrays.html) provides you with + usefull helpers to implement Models with filtering and ordering features. + +*/ +export class Model { + + constructor() { + this._dome_clients = {} ; + this._dome_clientId = 0 ; + } + + /** + @summary Items count. + @abstract + @return {number} number of items + @description + Shall return the number of items to be displayed by the table. + Negative values are considered as zero. + Default implementation returns zero. + */ + getItemCount() { return 0; } + + /** + @summary Item at given index. + @abstract + @param {number} index - item's ordering index + @return {any} the item's value + @description + Shall return the item at a given index in the table with respect to + current filtering and ordering (if appropriate). + <p> + Default implementation returns `undefined`. + */ + getItemAt() { return undefined; } + + /** + @summary Index of an item. + @abstract + @param {any} item - the item + @return {number} index of the item in the filtered and ordered collection + @description + Shall return the index of a given item inside the table with respect to + current filtering and ordering, or `undefined` if no such item exists. + <p> + Default implementation returns `undefined`. + */ + getIndexOf() { return undefined; } + + /** + @summary Item value in a column. + @param {any} item - an item + @param {string} column - a column identifier + @return {any} the value associated to the item for the given column. + @description + Defaults to accessing the column property of the item (ie. `item[column]`). + This method can be overriden by custom models and also table columns. + */ + getValue(item,column) { return item[column]; } + + /** + @summary Re-render an item. + @param {any} item - the updated item + @description + Signal that a given item has been updated and need to be re-rendered if visible. + */ + updateItem(item) { + const k = this.getIndexOf(item); + if ( 0 <= k ) this.updateIndex(k); + } + + /** + @summary Re-render a range of items. + @param {number} first - the first updated item index + @param {number} [last] - the last updated item index (defaults to `first`) + @description + Signal that a range of items have been updated and need to be re-rendered if visible. + */ + updateIndex(a,b=a) { + _.forOwn(this._dome_clients,({ lower,upper,trigger }) => { + if ( a <= upper && lower <= b ) trigger(); + }); + } + + /** Re-render all items */ + reload() { _.forOwn(this._dome_clients,({trigger})=> trigger()); } + + /** + @summary Current ordering. + @return {object} current sorting order + @description + Shall return the current ordering `{ sortBy, sortDirection }` + for user feedback in table headers, and `undefined` for natural ordering + or no ordering at all. + <p> + Default implementation returns `undefined`. + */ + getOrdering() { return undefined; } + + /** + @summary Change ordering of the model. + @param {object} [sort] - sorting order + @description + Callback to user clicks on table headers. This method receives + the new `{ sortBy, sortDirection }` ordering requested by the user action, + of `undefined` to reset initial, natural ordering of items. + You can also invoke this method on your own, away from any table view. + <p> + The method shall eventually reorder the items internally, and finally + signal completion with a call to `Model.reload()` in order to sync the views. + If re-ordering can take a while, this shall be performed asynchronously. + <p> + Default implementation does nothing. + */ + setOrdering() { } + + /** + @summary Connect a trigger to the model. + @protected + @param {Function} trigger - callback to force table update + @return {ClientID} client identifier + @description + Returns a _client_ identifier for removing and watching. + The trigger function is called for each update watched by the _client_. + Initially, the watching range is empty. + */ + _bind(trigger) { + const client = "#" + this._dome_clientId++ ; + this._dome_clients[client] = { lower:0, upper:0, trigger }; + return client; + } + + /** + @summary Disconnect the _client_ from the model. + @protected + @param {ClientID} client - the identifier of the client to disconnect + */ + _remove(client) { + delete this._dome_clients[client]; + } + + /** + @summary Set the current range of items watched by the _client_. + @protected + @param {ClientID} client - the identifier of the client to disconnect + @param {number} first - first index of the range + @param {number} last - last index of the range + @description + Data updates tha fall outside this range will _not_ trigger + re-rendering of the client. + */ + _watch(client,a,b) { + const listener = this._dome_clients[client]; + if (listener) { listener.lower = a ; listener.upper = b; } + } + +} + +// -------------------------------------------------------------------------- + +export default { Model , ASC , DESC } ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/table/tables.css b/Ivette/src/dome/src/renderer/table/tables.css new file mode 100644 index 0000000000000000000000000000000000000000..bf732426f386057343a6d9a1cf89ca777e3b2f10 --- /dev/null +++ b/Ivette/src/dome/src/renderer/table/tables.css @@ -0,0 +1,121 @@ +/* -------------------------------------------------------------------------- */ +/* --- Styling Dome Tables --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xTable { + flex: 1 1 auto ; + width: 100% ; + height: 100% ; +} + +.dome-xTable * { + outline: none ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Styling Table Headers --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xTable .ReactVirtualized__Table__headerRow { + display: flex ; + align-items: stretch ; + background: #eee ; + color: #555 ; + fill: #777 ; +} + +.dome-xTable .ReactVirtualized__Table__headerColumn { + overflow: hidden ; + padding-left: 4px ; + padding-right: 4px ; + margin: 0px ; /* Necessary for column alignement */ + border-color: #cfcfcf ; + border-bottom-width: 1px ; + border-bottom-style: solid ; +} + +.dome-xTable .ReactVirtualized__Table__headerColumn:not(:last-child) { + border-right-width: 1px ; + border-right-style: solid ; +} + +.dome-xTable-header { + /* flex: is inlined by react-virtualized */ + /* height: must be kept in sync with table.js */ + display: flex ; + height: 22px ; + flex-flow: row no-wrap ; + align-items: center ; +} + +.dome-xTable-header-icon { + flex: 0 0 auto ; + margin-left: 3px ; + margin-right: 3px ; +} + +.dome-xTable-header-label { + flex: 1 1 auto ; + overflow: hidden ; + margin-left: 3px ; + margin-right: 3px ; +} + +.dome-xTable-header-sorter { + flex: 0 0 auto ; + margin-right: 2px ; +} + +.dome-xTable-resizer { + position: absolute ; + cursor: col-resize ; + width: 3px ; + top: 0px ; + bottom: 0px ; + z-index: 1 ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Styling Table Rows --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xTable .ReactVirtualized__Table__row { + display: flex ; + align-items: stretch ; +} + +.dome-xTable .ReactVirtualized__Table__rowColumn { + /* flex: is inlined by react-virtualized */ + /* height: must be kept in sync with table.js */ + display: block ; + position: relative ; + margin: 0 ; /* Necessary for column alignement */ + padding-top: 3px ; + padding-left: 4px ; + padding-right: 4px ; + vertical-align: baseline ; +} + +.dome-xTable-odd { + background: #fdfdfd ; +} + +.dome-xTable-even { + background: #efefef ; +} + +.ReactVirtualized__Table__row.dome-color-selected { + border-bottom-style: solid ; + border-bottom-width: 1px ; +} + +/* -------------------------------------------------------------------------- */ +/* --- Styling Table Cells --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xTable-cell { + display: block ; + position: relative ; +} + +/* -------------------------------------------------------------------------- */ diff --git a/Ivette/src/dome/src/renderer/table/views.js b/Ivette/src/dome/src/renderer/table/views.js new file mode 100644 index 0000000000000000000000000000000000000000..637add9f45e1222cf6fd2a64c5fe312fe0a783bc --- /dev/null +++ b/Ivette/src/dome/src/renderer/table/views.js @@ -0,0 +1,552 @@ +// -------------------------------------------------------------------------- +// --- Tables +// -------------------------------------------------------------------------- + +/** @module dome/table/views */ + +import React from 'react' ; +import { DraggableCore } from 'react-draggable'; +import { SVG } from 'dome/controls/icons' ; +import { + AutoSizer, + SortDirection, + Table as VTable, + Column as VColumn +} from 'react-virtualized' ; +import _ from 'lodash' ; +import './tables.css' ; + +// -------------------------------------------------------------------------- +// --- Header Renderer +// -------------------------------------------------------------------------- + +const headerRowRenderer = + (onDoubleClick) => + // Borrowed from react-virtualized Table.defaultHeaderRowRenderer + ({ + className, + columns, + style + }) => ( + <div role="row" + className={className} + style={style} + onDoubleClick={onDoubleClick} > + {columns} + </div> + ); + +const headerIcon = (icon) => ( + icon && <div className='dome-xTable-header-icon'><SVG id={icon}/></div> +); + +const headerLabel = (label) => ( + label && <label className='dome-xTable-header-label dome-text-label'> + {label} + </label> +); + +const makeSorter = (id) => ( + <div className='dome-xTable-header-sorter'> + <SVG id={id} size={8}/> + </div> +); + +const headerSorter = {} ; +headerSorter[ SortDirection.ASC ] = makeSorter('ANGLE.UP'); +headerSorter[ SortDirection.DESC ] = makeSorter('ANGLE.DOWN'); + +const headerRenderer = + ({ + columnData: { label, icon, title, headerRef }, + dataKey, + sortBy, + sortDirection + }) => { + const sorting = dataKey === sortBy ; + const tooltip = title || label ; + const onRef = (elt) => headerRef(dataKey,elt) ; + return ( + <div className='dome-xTable-header' title={tooltip} ref={onRef} + > + { headerIcon(icon) } + { headerLabel(label) } + { sorting && headerSorter[sortDirection] } + </div> + ); + }; + +// -------------------------------------------------------------------------- +// --- Cell Renderer +// -------------------------------------------------------------------------- + +const cellDataGetter = + (getValue) => + ({ rowData:{ model , item }, dataKey:id }) => + ( item == undefined ? undefined : + getValue ? getValue(item) : + model.getValue(item,id) + ); + +const cellRenderer = + (renderValue) => + ({ cellData: data }) => + ( + data === undefined ? undefined : + renderValue ? renderValue(data) : + (<div className='dome-xTable-cell dome-text-data'>{data}</div>) + ); + +// -------------------------------------------------------------------------- +// --- Column Resizer +// -------------------------------------------------------------------------- + +const DRAGGING = 'dome-xTable-resizer dome-color-dragging' ; +const DRAGZONE = 'dome-xTable-resizer dome-color-dragzone' ; + +const Resizer = (props) => ( + <DraggableCore + onStart={props.onStart} + onStop={props.onStop} + onDrag={(_elt,data)=> props.onDrag(props.left,props.right,data.x - props.offset)} + > + <div + className={ props.id === props.dragging ? DRAGGING : DRAGZONE } + style={{ left: props.offset-2 }} + /> + </DraggableCore> +); + +const computeWidth = (elt) => { + const parent = elt && elt.parentElement ; + return parent && parent.getBoundingClientRect().width ; +}; + +// -------------------------------------------------------------------------- +// --- Table Columns +// -------------------------------------------------------------------------- + +/** + @class + @summary Table Column. + @property {string} id - Column unique identifier (required) + @property {string} [icon] - Header icon + @property {string} [label] - Header label + @property {string} [title] - Header tooltip + @property {string} [align] - Column alignment (`'left'`, `'center'`, `'right'`) + @property {number} [width] - Column base width (in pixels, default `60`) + @property {boolean} [fill] - Extensible column (not by default) + @property {boolean} [fixed] - Non-resizable column (not by default) + @property {boolean} [disableSort] - Do not trigger sorting callback for this column + @property {function} [getValue] - Obtain an item's value for this column + @property {function} [renderValue] - Render item's value in each table cell + @description + + Each column displays a specific value derived from the item displayed in a + row. Column properties enforce a separation between how to extract the value + from an item and how to render it in the cell. + + - `getValue(item) : any` shall returns the value to render for the _item_ + - `renderValue(any) : Element` shall returns the (React) element to display the item + + + By default, values are obtained from the underlying model by invoking + [Model.getValue](module-dome_table_models.Model.html#getValue) with the column + identifier. + + The default `renderValue` renders the item's value + packed in a `<label>` with class `dome-text-data` as described in the + [Styling Component](tutorial-styling.html) tutorial. + + This separation of concerns allows for defining + Column types, where for instance the renderer is already defined and you only need to + know how to extract the expected value of items. + See [DefineColumn](module-dome_table_views.DefineColumn.html) + for more informations and examples. + + A table should have at least one extensible column to occupy the available width. + If no column in the table is explicitely declared to be extensible, the last + one would be implicitely set to fill. + +*/ +export const Column = () => null; +// Fake component only used to store props. +// Virtualized column is rendered with function below: +const vColumn = (columnResize,headerRef,hasFill,lastElt) => (elt) => { + const defaults = elt.type._DOME_COLUMN_DEFAULTS || {} ; + const forcers = !hasFill && elt == lastElt ? { fill:true } : {} ; + const { id,label,title,icon,align,width,fill,disableSort,getValue,renderValue } + = Object.assign( defaults , elt.props , forcers ) ; + return ( + <VColumn + displayName='React-Virtualized-Column' + width={columnResize[id] || width || 60} + flexGrow={ fill ? 1 : 0 } + dataKey={id} + columnData={{label,title,icon,headerRef}} + headerRenderer={headerRenderer} + cellRenderer={cellRenderer(renderValue)} + cellDataGetter={cellDataGetter(getValue)} + headerStyle={{ textAlign: align }} + disableSort={disableSort} + style={{ textAlign: align }} + /> + ); +}; + +// -------------------------------------------------------------------------- +// --- Specific Columns +// -------------------------------------------------------------------------- + +/** + @class + @summary Define specific Column instances. + @param {Object} properties - default Column properties + @return {Column} a new Column class of Component + @description + + Allow to define specialized instances of + [Column](module-dome_table_views.Column.html) + + @example // Example of column type + import { DefineColumn } from 'dome/table/views' ; + export const ColumnCheck = DefineColumn({ + align: 'center', + renderValue: (ok) => <Icon id={ok ? 'CHECK' : 'CROSS'}/> + }); + + @example // Usage in a Table + <Table ...> + <Column id='name' label='Name' fill /> + <ColumnCheck id='check' label='Checked' /> + </Table> + + */ +export const DefineColumn = (DEFAULTS) => { + const Component = () => null; + Component._DOME_COLUMN_DEFAULTS = DEFAULTS ; + return Component ; +}; + +// -------------------------------------------------------------------------- +// --- Table Rows +// -------------------------------------------------------------------------- + +const rowClassName = + (multipleSelection,selected) => + ({index}) => + (multipleSelection + ? 0 <= _.sortedIndexOf( selected , index ) + : (index === selected)) + ? 'dome-color-selected' : + index & 1 ? 'dome-xTable-even' : 'dome-xTable-odd' ; + +// -------------------------------------------------------------------------- +// --- Table View +// -------------------------------------------------------------------------- + +// Must be kept in sync with table.css +const CSS_HEADER_HEIGHT = 22 ; +const CSS_ROW_HEIGHT = 20 ; + +/** + @class + @summary Table View. + @property {Model} model - table data proxy (required) + @property {Column[]} children - one or more table columns (required) + @property {any} [selection] - current selection (depends on `multipleSelection`) + @property {function} [onSelection] - callback to selection changes (depends on `multipleSelection`) + @property {boolean} [multipleSelection] - select single or multiple selection + @property {any} [scrollToItem] - ensures the item is visible + @property {function} [renderEmpty] - callback to render an empty table + @description + + This component is base on [React-Virtualized + Tables](https://bvaughn.github.io/react-virtualized/#/components/Table), + offering a lazy, super-optimized rendering process that scales on huge + datasets. + + A table shall be connected to an instance of + [Model](module-dome_table_models.Model.html) class to retrieve the data and + get informed of data updates. + + The table columns shall be instances of + [Column](module-dome_table_views.Column.html) class. + + Clicking on table headers trigger re-ordering callback on the model with the + expected column and direction, unless disabled _via_ the column + specification. However, actual sorting (and corresponding feedback on table + headers) would only take place if the model supports re-ordering and + eventually triggers a reload. Double clicking the table headers resets + re-ordering to natural order, with the same considerations. + + Tables do not control item selection state. Instead, you shall supply the selection + state and callback _via_ properties, like any other controlled React components. + + Item selection can be based either on single-row or multiple-row. In case of + single-row selection (`multipleSelection:false`, the default), selection state + must be a single item or `undefined`, and the `onSelection` callback is called + with the same type of values. + + In case of multiple-row selection (`multipleSelection:true`), the selection state + shall be an _array_ of items, and `onSelection` callback also. Single items are _not_ + accepted, but `undefined` selection can be used in place of an empty array. + + Clicking on a row triggers the `onSelection` callback with the updated selection. + In single-selection mode, the clicked item is sent to the callback. In + multiple-selection mode, key modifiers are taken into account for determining the new + slection. By default, the new selection only contains the clicked item. If the `Shift` + modifier has been pressed, the current selection is extended with a range of items + from the last selected one, to the newly selected one. If the `CtrlOrCmd` modifier + has been pressed, the selection is extended with the newly clicked item. + Clicking an already selected item with the `CtrlOrCmd` modifier removes it from + the current selection. + + */ +export class Table extends React.Component { + + constructor(props) + { + super(props); + + // Table Reload + this.tableRef = undefined ; + this.setTableRef = (ref) => this.tableRef = ref ; + this.reloadTable = () => { + this.reloaded = true ; + this.forceUpdate(); + const ref = this.tableRef ; + ref && ref.forceUpdateGrid(); + }; + + // Model Watching + this.watchModel = ({startIndex,stopIndex}) => { + this.props.model._watch( this.client , startIndex , stopIndex ); + }; + + // Header Double Click + this.resetOrdering = () => this.props.model.setOrdering() ; + + // Header Column References + this.columnSize = {} ; + this.headerRef = (id,elt) => { + const old = this.columnSize[id]; + const fixed = this.columnResize[id]; + const width = computeWidth(elt); + if (elt && old !== width) { + this.columnSize[id] = width ; + this.forceUpdate(); + } + }; + + // Column Resizing + this.columnResize = {} ; + this.resizeColumns = (lcol,rcol,delta) => { + const wl = this.columnSize[lcol] + delta ; + const wr = this.columnSize[rcol] - delta ; + if (wl > 40 && wr > 40) { + this.columnResize[lcol] = wl ; + this.columnResize[rcol] = wr ; + this.forceUpdate(); + } + }; + + // Selection + this.selectRow = this.selectRow.bind(this); + + } + + // --- Life Cycle (binding to model) + + componentDidMount() + { + this.client = this.props.model._bind(this.reloadTable); + } + + componentWillUnmont() + { + this.props.model._remove(this.client); + } + + // --- Column Resizers + + computeResizers() { + // Insert a resizer on each side of non-fixed columns, + // provided there also exists some non-fixed column on both side. + const columns = React.Children.toArray(this.props.children); + if (columns.length < 2) return null; + const resizing = columns.map( ({props:{id,fixed}}) => ({id,fixed}) ); + var k, cid ; + for (cid = undefined, k = 0; k < columns.length; k++) { + const r = resizing[k]; + r.left = cid ; + if (!r.fixed) cid = r.id ; + } + for (cid = undefined, k = columns.length-1; 0 <= k ; k--) { + const r = resizing[k]; + r.right = cid ; + if (!r.fixed) cid = r.id ; + } + var offset = 0 , resizers = [] ; + for (k = 0; k < columns.length - 1 ; k++) { + const width = this.columnSize[resizing[k].id] ; + if (!width) return null; + offset += width ; + const a = resizing[k]; + const b = resizing[k+1]; + if ((!a.fixed || !b.fixed) && a.right && b.left) { + const id = k ; + const onStart = () => { this.dragging = id ; this.forceUpdate(); }; + const onStop = () => { this.dragging = undefined ; this.forceUpdate(); }; + const resizer = ( + <Resizer key={id} + id={id} + dragging={this.dragging} + onStart={onStart} + onStop={onStop} + onDrag={this.resizeColumns} + offset={offset} + left={b.left} + right={a.right} /> + ); + resizers.push(resizer); + } + } + return resizers ; + } + + // --- Row Selection + + selectRow({event, index, rowData:{item}}) { + this.focus = item ; + window.getSelection().empty(); + if (item) { + const { model, multipleSelection , selection, onSelection } = this.props ; + if (multipleSelection) { + const selectedItems = + selection === undefined ? [] : + Array.isArray(selection) ? selection : + [selection] ; + if (event.metaKey || event.ctrlKey) { + var s, a ; + const isClicked = (e) => model.getIndexOf(e) === index ; + if (_.find( selectedItems , isClicked )) { + s = _.filter( selectedItems, (e) => model.getIndexOf(e) !== index ); + } else { + s = selectedItems.slice(); + s.push(item); + a = index ; + } + this.anchor = a ; + this.anchored = undefined ; + onSelection(s); + } + else if (event.shiftKey && this.anchor) { + var old = this.anchored || (this.anchored = selection) ; + var updated = old.slice(); + var anchor = this.anchor ; + var k ; + if (anchor < index) + for (k = anchor ; k <= index ; k++) { + updated.push(model.getItemAt(k)); + } + else + for (k = anchor ; index <= k ; k--) { + updated.push(model.getItemAt(k)); + } + // No anchor modification + onSelection(_.uniqBy(updated, model.getIndexOf.bind(model))); + } + else { + this.anchor = index ; + this.anchored = undefined ; + onSelection([item]); + } + } else { + onSelection(item); + } + } + } + + // --- Rendering + + render() { + + const { + model, children, renderEmpty, + multipleSelection, selection, onSelection, + scrollToItem + } = this.props ; + + const itemCount = model.getItemCount(); + const ordering = model.getOrdering(); + var selected = undefined ; + if (selection) + if (multipleSelection && Array.isArray(selection)) { + selected = selection.map((elt) => { + var k = model.getIndexOf(elt); + return Number.isInteger(k) ? k : -1 ; + }).sort((a,b) => a-b); + } else + selected = model.getIndexOf(selection); + + const rowGetter = ({index}) => ({ + model , item: (index < itemCount ? model.getItemAt(index) : undefined) + }) ; + + var hasFill = false ; + var lastElt = undefined ; + React.Children.forEach(this.props.children,(elt) => { + if (elt.props.fill) hasFill = true ; else lastElt = elt ; + }); + const SizedTable = ({ height, width }) => { + const tableHeight = CSS_HEADER_HEIGHT + CSS_ROW_HEIGHT * itemCount ; + const smallHeight = itemCount > 0 && tableHeight < height ; + const rowCount = ( smallHeight ? itemCount + 1 : itemCount) ; + const reloaded = this.reloaded ; + if (reloaded) this.reloaded = false ; + const scrollToIndex = + scrollToItem ? model.getIndexOf(scrollToItem) : + reloaded && this.focus ? model.getIndexOf(this.focus) : undefined ; + const resizers = this.computeResizers(); + return ( + <React.Fragment> + <VTable + key='table' + displayName='React-Virtualized-Table' + width={width} + height={height} + rowCount={rowCount} + noRowsRenderer={renderEmpty} + rowGetter={rowGetter} + rowClassName={rowClassName(multipleSelection,selected)} + rowHeight={CSS_ROW_HEIGHT} + headerHeight={CSS_HEADER_HEIGHT} + headerRowRenderer={headerRowRenderer(this.resetOrdering)} + onRowsRendered={this.watchModel} + onRowClick={onSelection && this.selectRow} + sortBy={ordering && ordering.sortBy} + sortDirection={ordering && ordering.sortDirection} + sort={model.setOrdering.bind(model)} + scrollToIndex={ scrollToIndex } + scrollToAlignment='center' + > + {React.Children.map(children,vColumn(this.columnResize,this.headerRef,hasFill,lastElt))} + </VTable> + {resizers} + </React.Fragment> + ); + }; + return ( + <div className='dome-xTable'> + <AutoSizer key='table'>{SizedTable}</AutoSizer> + </div> + ); + } +} + +// -------------------------------------------------------------------------- + +export default { Table, Column, DefineColumn }; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/text/buffers.js b/Ivette/src/dome/src/renderer/text/buffers.js new file mode 100644 index 0000000000000000000000000000000000000000..be2324b324883e8a772421511f2d67eee2d8c893 --- /dev/null +++ b/Ivette/src/dome/src/renderer/text/buffers.js @@ -0,0 +1,446 @@ +// -------------------------------------------------------------------------- +// --- Text Documents +// -------------------------------------------------------------------------- + +/** @module dome/text/buffers */ + +import Emitter from 'events' ; +import CodeMirror from 'codemirror/lib/codemirror.js' ; + +const combineClass = (a,b) => a ? (b ? (a + " " + b) : a) : b ; + +// -------------------------------------------------------------------------- +// --- Marker Proxy +// -------------------------------------------------------------------------- + +class Proxy { + + clear() { this.marker && this.marker.clear(); } + changed() { this.marker && this.marker.changed(); } + find() { return this.marker && this.marker.find(); } + _link(marker) { this.marker = marker ; } + +} + +// -------------------------------------------------------------------------- +// --- Buffer +// -------------------------------------------------------------------------- + +/** + @summary Rich Text Content and State. + @description + + A buffer encapsulate a CodeMirror document instance inside an standard + Node event emitter. CodeMirror signals are automatically linked back to + the event emitter (on a lazy basis). + + The `maxlines` will control the maximum number of lines kept in the buffer. + By default, it is set to `10000`, but you can use `null`, `0` or any negative + value to disable this behavior. See also `this.setMaxlines()` method. + + Additionnaly, a Buffer maintains an _edited_ state internally that can + be manually updated, and that is automatically set to `true` when the + underlying CodeMirror document is changed. It is associated to an `'edited'` + event of the buffer, and can be used to manage the « Saved » / « Not-Saved » + state of an editor, for instance. + + Typically, a sequence of changed events would fire a unique `'edited'` buffer + event, untill `setEdited(false)` is invoked. The `clear()` method also resets + the _edited_ state to `false`, but sill emit an `'edited'` event if the + buffer was not empty. + + Buffers can also be updated programmatically by various methods. In addition to + specified CodeMirror modes, you can also attach text markers programmatically with + a push/pop API. + + Text markers can be associated with an identifier, that can be used for + dynamic highlighting, called Decorations. Decorations are class names that + add styling attributes upon the current mode. Typically, consider only using + background colors, underlines and/or strike-through for decorations, since + font styles and colors are likely to be managed by CodeMirror modes, unless + you know exactly what your are doing. + + The `setDecorator` method can be used to set or update + the highlighting function that computes the decoration of a text marker + from its identifier. When the decorations may have change, you shall either + set again the highlighting function with a call to `setDecorator()` or call + the `updateDecorations()` method. This also triggers the `'decorated'` event. + + */ + +export class Buffer extends Emitter { + + /** + @param {object} [props] - Constructor properties (see below) + @param {string | object} [props.mode] - CodeMirror [mode](https://codemirror.net/mode/index.html) specification + @param {number} [props.maxlines] - Maximum number of lines in the buffer + */ + constructor(props = {}) { + super(); + const { mode , maxlines } = props ; + this._doc = new CodeMirror.Doc('',mode); + this._stacked = [] ; + this._edited = false ; + this._focused = false ; + this._markid = 0 ; + this._markers = {} ; + this._decorator = undefined ; + this.setMaxlines(maxlines); + this.setEdited = this.setEdited.bind(this); + this.setFocused = this.setFocused.bind(this); + this.clear = this.clear.bind(this); + this.append = this.append.bind(this); + this.log = this.log.bind(this); + this._doc.on('change', ( _target , { origin } ) => { + if (origin !== 'buffer') this.setEdited(true); + }); + } + + /** + @summary CodeMirror document instance. + @return {CodeMirror.Doc} internal [document](https://codemirror.net/doc/manual.html#api_doc) + @description + Returns the `CodeMirror.Doc` instance holding the buffer contents. + This can be used for further customization. + <p> + This document will never be bound to a `CodeMirror` instance. Instead, `Text` views + will use _linked_ documents to the buffer one. This allows for several views to + share the same document (and history). + */ + getDoc() { return this._doc; } + + // -------------------------------------------------------------------------- + // --- Buffer Manipulation + // -------------------------------------------------------------------------- + + /** Clear buffer contents and resets _edited_ state. */ + clear() { + this._doc.setValue(''); + this._edited = false; + this._stacked = [] ; + this._focused = false ; + this._markid = 0 ; + this._markers = {} ; + } + + /** + @summary Writes in the buffer. + @param {any} [value] - content to append in the buffer + @description + Appends textual contents to the end of the buffer. + All parameters are converted to string and joined with spaces. + The generated change event has origin `'buffer'` and it does not + modifies the _edited_ internal state. + */ + append(...value) { + if (value.length > 0) { + const doc = this._doc ; + const from = doc.posFromIndex(Infinity); + const text = value.join(' '); + doc.replaceRange(text,from,undefined,'buffer'); + this.shrink(); + } + } + + /** + @summary Appends with newline and auto-scrolling. + @param {any} [value] - content to append in the buffer + @description + This is a short-cut to `append(...value)`, followed by + `append('\n')` and `scroll()`. + */ + log(...value) { + this.append(...value); + this.append('\n'); + this.scroll(); + } + + /** + @summary Opens a text marker. + @param {object} options - CodeMirror + [text marker](https://codemirror.net/doc/manual.html#api_marker) options + @return {CodeMirror.TextMarker} the associated + [text marker](https://codemirror.net/doc/manual.html#api_marker) (proxy) + @description +Opens a text marker at the current (end) position in the buffer. + +The text marker is stacked and would be actually created on the +matching `closeTextMarker()` call. It will be applied to the full range of text +inserted between its associated `openTextMarker()` and `closeTextMarker()` calls. + +The returned text marker is actually a _proxy_ to the text marker that +will be eventually created by `closeTextMarker()`. Its methods (`find`, `clear` and `changed`) +are automatically forwarded to the actual `CodeMirror.TextMarker` instance, once created. +Hence, you can safely invoke these methods on either the _proxy_ or the _final_ +text marker at your convenience. + +Additionnaly to standard `CodeMirror.TextMarker` options, you may also the +following Dome specific ones: +- `id: string` assigns an identifier to the marker (expected to be unique) ; +- `hover: boolean` makes the text-marker highlighted on mouse-hover ; this is compatible with + _nested_ markers, which is not possible with CSS `:hover` pseudo selectors ; defaults to `true` for + identified text markers and `false` otherwize. +*/ + + openTextMarker( { id , hover, className, ...options } ) { + const from = this._doc.posFromIndex(Infinity); + const proxy = new Proxy(); + this._stacked.push( { from , id , hover, className, options , proxy } ); + return proxy ; + } + + /** + @summary Close last opened marker. + @return {CodeMirror.TextMarker} the (actual) + [text marker](https://codemirror.net/doc/manual.html#api_marker) + @description + Closes the lastly opened text marker with `openTextMarker()`. + The method returns the _actual_ + text marker ; the _proxy_ text marker provided by the corresponding + call to `openTextMarker()` is automatically bound to the actual one. + */ + closeTextMarker() { + const tag = this._stacked.pop(); + if (tag) { + const { id, hover, from } = tag ; + const to = this._doc.posFromIndex(Infinity); + var classNameWithId ; + var tagid ; + if ( id || hover ) { + const mhover = hover !== undefined ? hover : (id !== undefined) ; + const cid = id ? 'dome-xMark-' + id : ('dome-xHover-' + (++this._markid)) ; + const p = this._doc.indexFromPos(from); + const q = this._doc.indexFromPos(to); + const m = this._markers[cid]; + if (m) console.warn('[Dome.text.buffers] duplicate marker',id); + tagid = this._markers[cid] = { id, hover:mhover, classNameId:cid, length: q-p } ; + classNameWithId = id ? "dome-xMarked " + cid : cid ; + } + const className = combineClass( tag.className, classNameWithId ); + const options = Object.assign( { shared:true, className } , tag.options ); + const marker = this._doc.markText( from , to , options ); + tag.proxy._link(marker); + if (tagid) tagid.marker = marker ; + this.shrink(); + return marker ; + } else + return undefined ; + } + + /** + @description Lookup a text marker + @param {string} id - requested identifier + @return {CodeMirror.TextMarker} the identified text marker, or `undefined` if not found. + */ + findTextMarker(id) { + if (id) { + const m = this._markers['dome-xMark-' + id] ; + if (m) return m.marker ; + } + return undefined; + } + + /** + @summary Lookup a hover class. + @param {string} className - a class name, possibly identifying a hover element + @return {hover} the associated hovered element `{id, classNameId, length}`, or + `undefined` if the provided `className` does not identify any such element. + */ + findHover(name) { return this._markers[name]; } + + // -------------------------------------------------------------------------- + // --- Highlighter + // -------------------------------------------------------------------------- + + /** + @summary Define highlighter. + @param {function} highlighter - the function that computes + the decoration class of a marker id. + */ + setDecorator(f) { this._decorator = f ; this.emit('decorated'); } + + /** + @summary Current highlighter. + @return {function} the current highlighting function + */ + getDecorator() { return this._decorator ; } + + /** + @summary Rehighlight document. + @description + Emits the `'decorated'` event to make editors + updating the decorations of identified text markers. + */ + updateDecorations() { this.emit('decorated'); } + + // -------------------------------------------------------------------------- + // --- Edited State + // -------------------------------------------------------------------------- + + /** + @summary Set edited state. + @param {boolean} [state] - the new edited state (defaults to `true`). + @description + +Set the _edited_ internal state. The method is automatically invoked by editor +views when the user actually edit the document. The state is _not_ modified +when modifying the document from buffer's own methods, _eg._ `append()` and +`clear()`. + +The method fires the `'edited'` event on modifications. This method is bound to +`this`, hence `this.setEdited` can be used as a valid callback function. + */ + setEdited(state = true) { + if ( state !== this._edited ) { + this._edited = state ; + this.emit('edited',state); + } + } + + /** + @summary Set focused state. + @param {boolean} [focus] - the new focused state (defaults to `true`). + @description + +Set the _focused_ internal state. The method is automatically invoked by editor +views when they gain or lose focus or when the user actually interact with the +view, eg. mouse-scrolling, edition, cursor move, etc. The escape key `ESC` +explicitly relax the _focused_ state, although the editor view might actually +keep the _focus_. + +When a buffer is _focused_, shrinking and scrolling are temporarily deactivated +to avoid confusing user's experience. + +The method fires `'focused'` events on modifications. This method is bound to +`this`, hence `this.setEdited` can be used as a valid callback function. + */ + setFocused(state = true) { + if ( state !== this._focused ) { + this._focused = state ; + this.emit('focused',state); + this.shrink(); + } + } + + /** Returns the current _edited_ state. */ + isEdited() { return this._edited; } + + /** Returns the current _focused_ state. */ + isFocused() { return this._focused; } + + // -------------------------------------------------------------------------- + // --- Document Scrolling + // -------------------------------------------------------------------------- + + /** + @summary Set (or unset) the maximum number of lines. + @param {number} [maxlines] - maximum number of lines + @description + +By default, the maximum number of lines is set to `10,000` to avoid +unwanted memory leaks. Setting `null`, `0` of any negative value cancel +the management of maximum number of lines. + +Although CodeMirror is powerfull enough to manage huge buffers, +you should turn this limit _off_ with care. + */ + setMaxlines(maxlines=10000) { + this._maxlines = maxlines > 0 ? 1 + maxlines : 0 ; + this.shrink(); + } + + /** + @summary Remove head lines to fits into maximum lines. + @description + +Shrinking is activated when `maxlines` property is set to a strictly +positive number. When the number of lines in the buffer is larger than +the max, buffer is trimmed by removing extra _heading_ lines. + +When the buffer if _focused_ or when there are still opened text marks pending, +shrinking is automatically postponed until focus is lost and all pending marks +have been closed. + */ + shrink() + { + if (!this._focused && this._maxlines > 0 && this._stacked.length == 0) { + const lines = this._doc.lineCount(); + if (lines > this._maxlines) { + const p = this._doc.firstLine(); + const q = p + lines - this._maxlines ; + this._doc.replaceRange('',{line:p,ch:0},{line:q,ch:0},'buffer'); + } + } + } + + /** + @summary Requires all connected views to scroll to the specified position in the buffer. + @param {...any} [args] - the position or range to be made visible + @description +Typical usage: + - `scroll()` to the end of buffer + - `scroll(id)` to identified marked `id`; + - `scroll(p)` a position: line number or `{line,ch?}` CodeMirror position; + - `scroll(p,q)` a range of two positions (like above); + - `scroll({from,to})` an object range of two positions (like above). + +When the buffer is _focused_, programmatic scrolling is blocked. + */ + scroll(a,b) { + if (this._focused) return; + switch(typeof(a)) { + case 'undefined': + this.emit('scroll',{line:this._doc.lastLine(),ch:0}); + break; + case 'string': + const tm = this.findTextMarker(a); + const rg = tm.find(); + if (rg) this.emit('scroll',rg); + break; + default: + const isLineCh = (a) => ( + a && Number.isInteger(a.line) + && (a.ch === undefined || Number.isInteger(a.ch)) + ); + const getPos = (a) => ( + Number.isInteger(a) ? { line: a, ch:0 } : + isLineCh(a) ? a : console.warn('[Dome.text.buffers] can not scroll to',a) + ); + var from,to ; + if (a && a.from && a.to) { + from = getPos(a.from); + to = getPos(a.to); + } else { + from = getPos(a); + to = b && getPos(b); + } + if (from && to) this.emit('scroll',{from,to}); + else if (from) this.emit('scroll',from); + } + } + + // -------------------------------------------------------------------------- + // --- Document Linking + // -------------------------------------------------------------------------- + + /** + @summary Linked CodeMirror document. + @description + Returns a CodeMirror document linked to this buffer (with shared history). + */ + linkedDoc() { return this._doc.linkedDoc( { sharedHist: true } ); } + + /** + @summary Release a linked CodeMirror document. + @description + Unlinks a CodeMirror document obtained by `linkedDoc()`. + */ + unlinkDoc(doc) { this._doc.unlinkDoc( doc ); } + +} + +// -------------------------------------------------------------------------- + +export default { Buffer }; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/src/renderer/text/editors.css b/Ivette/src/dome/src/renderer/text/editors.css new file mode 100644 index 0000000000000000000000000000000000000000..3a15484d39d77ca589ed8b4d28b7f60943571e5e --- /dev/null +++ b/Ivette/src/dome/src/renderer/text/editors.css @@ -0,0 +1,28 @@ +/* -------------------------------------------------------------------------- */ +/* --- Styling Code Editors --- */ +/* -------------------------------------------------------------------------- */ + +.dome-xText { + flex: 1 1 auto ; + overflow: hidden ; + position: relative ; +} + +.dome-xText .CodeMirror { + width: 100% ; + height: 100% ; +} + +.dome-xText-hover { + background: lightgreen ; +} + +.dome-xText-select { + background: #ffda95 !important ; +} + +.dome-xText-select.dome-xText-hover { + background: orange !important ; +} + +/* -------------------------------------------------------------------------- */ diff --git a/Ivette/src/dome/src/renderer/text/editors.js b/Ivette/src/dome/src/renderer/text/editors.js new file mode 100644 index 0000000000000000000000000000000000000000..415c3a442bb9c65d149b031a0bb891f9d0db5f07 --- /dev/null +++ b/Ivette/src/dome/src/renderer/text/editors.js @@ -0,0 +1,375 @@ +// -------------------------------------------------------------------------- +// --- Text Documents +// -------------------------------------------------------------------------- + +/** @module dome/text/editors */ + +import React from 'react' ; +import Dome from 'dome' ; +import CodeMirror from 'codemirror/lib/codemirror.js' ; +import 'codemirror/lib/codemirror.css' ; +import './editors.css' ; +import _ from 'lodash' ; + +const CSS_HOVERED = 'dome-xText-hover' ; +const CSS_SELECTED = 'dome-xText-select' ; + +// -------------------------------------------------------------------------- +// --- Text View +// -------------------------------------------------------------------------- + +/** + @class + @summary Rich Text Editor. + @property {Buffer} buffer - + associated [Buffer](module-dome_text_buffers.Buffer.html) holding the text content + @property {string} selection - currently selected markder identifier + @property {function} onSelection - callback used when an identified marker is clicked + @property {object} [...options] - additional CodeMirror + [configuration](https://codemirror.net/doc/manual.html#config) properties + @description + + A component rendering the content of a text buffer, that shall be instances + of the [Buffer](module-dome_text_buffers.Buffer.html) base class. + + The view is based on a [CodeMirror](https://codemirror.net) component linked with + the internal Code Mirror Document from the associated buffer. + + Multiple views might share the same buffer as source content. The buffer will be + kept in sync with all its linked views. + + The Text component never update its mounted NODE element, however, all property + modifications (including buffer) are propagated to the internal CodeMirror instance. + Undefined properties are set (or reset) to the CodeMirror defaults. + + ##### Themes + + The CodeMirror `theme` option allow you to style your document, + especially when using modes. + Themes are only accessible if you load the associated CSS style sheet. + For instance, to use the `'ambiance'` theme provided with CodeMirror, you shall + import `'codemirror/theme/ambiance.css'` somewhere in your application. + + ##### Modes & Adds-On + + You can install modes and adds-on provided by the CodeMirror distribution by + simply importing (once, before being used) the associated modules in your + application. For instance, to use the `'javascript'` mode option, you shall + import `'codemirror/mode/javascript/javascript.js'` file in your application. + + ##### Further Customization + + You can register your own extensions directly into the global `CodeMirror` + class instance. However, the correct instance must be retrieved by using + `import CodeMirror from 'codemirror/lib/codemirror.js'` ; using `from + 'codemirror'` returns a different instance of `CodeMirror` class and will + not work. + + */ + +export class Text extends React.Component { + + constructor(props) { + super(props); + this.mountPoint = this.mountPoint.bind(this); + this.refresh = this.refresh.bind(this); + this.autoRefresh = this.autoRefresh.bind(this); + this.onBlur = this.onBlur.bind(this); + this.onFocus = this.onFocus.bind(this); + this.onScroll = this.onScroll.bind(this); + this.onClick = this.onClick.bind(this); + this.onMouseMove = this.onMouseMove.bind(this); + this.handleKey = this.handleKey.bind(this); + this.handleUpdate = this.handleUpdate.bind(this); + this.handleHover = _.throttle(this.handleHover,50); + this.handleScrollTo = this.handleScrollTo.bind(this); + this.rootElement = undefined ; + this.decorations = {} ; + this.hover = undefined ; + } + + // -------------------------------------------------------------------------- + // --- Mounting + // -------------------------------------------------------------------------- + + mountPoint(elt) { + this.rootElement = elt ; + if (elt) { + // Mounting... + const { buffer , ...config } = this.props ; + const value = buffer ? buffer.linkedDoc() : "" ; + const cm = this.codeMirror = new CodeMirror(elt, { value }); + // Passing all options to constructor does not work (Cf. CodeMirror's BTS) + for (var opt in config) cm.setOption( opt , config[opt] ); + cm.on('update',this.handleUpdate); + cm.on('keyHandled',this.handleKey); + buffer.on('decorated',this.handleUpdate); + buffer.on('scroll',this.handleScrollTo); + Dome.on('dome.update',this.refresh); + this.refreshPolling = setInterval( this.autoRefresh, 250 ); + this.handleUpdate(); + } else { + // Unmounting... + const polling = this.refreshPolling ; + if (polling) { + clearInterval( polling ); + this.refreshPolling = undefined ; + } + const cm = this.codeMirror ; + Dome.off('dome.update',this.refresh); + const { buffer } = this.props ; + if (cm && buffer) { + buffer.unlinkDoc(cm.getDoc()); + buffer.off('decorated',this.handleUpdate); + buffer.off('scroll',this.handleScrollTo); + } + this.codeMirror = undefined ; + } + } + + // -------------------------------------------------------------------------- + // --- Auto Refresh + // -------------------------------------------------------------------------- + + refresh() { + const elt = this.rootElement ; + const cm = this.codeMirror ; + if (cm && elt) { + this.currentWidth = elt.offsetWidth ; + this.currentHeight = elt.offsetHeight ; + this.currentParent = elt.offsetParent ; + cm.refresh(); + } + } + + // Polled every 250ms + autoRefresh() { + const elt = this.rootElement ; + const cm = this.codeMirror ; + if (cm && elt) { + const eltW = elt.offsetWidth ; + const eltH = elt.offsetHeight ; + const eltP = elt.offsetParent ; + if (eltW !== this.currentWidth || + eltH !== this.currentHeight || + eltP !== this.currentParent) + { + this.currentWidth = eltW ; + this.currentHeight = eltH ; + this.currentParent = eltP ; + cm.refresh(); + } + } + } + + // -------------------------------------------------------------------------- + // --- Hover + // -------------------------------------------------------------------------- + + _findHover(elt) { + const buffer = this.props.buffer ; + var best = undefined ; + elt.classList.forEach((name) => { + const hover = buffer.findHover(name); + if (hover && (!best || hover.length < best.length )) best = hover ; + }); + return best; + } + + _findDecoration(classes,buffer,decorator) + { + var best_hover = undefined ; + var best_decor = undefined ; + var best_decoration = undefined ; + classes.forEach((name) => { + + const hover = buffer.findHover(name); + var decoration = hover && hover.id && decorator(hover.id); + + if (hover && (!best_hover || hover.length < best_hover.length)) + best_hover = hover ; + + if (decoration && (!best_decor || hover.length < best_decor.length)) { + best_decor = hover ; + best_decoration = decoration ; + } + + }); + return best_hover && { classNameId: best_hover.classNameId , decoration: best_decoration } ; + } + + _markElementsWith(classNameId,className) { + const root = this.rootElement ; + const tohover = root && root.getElementsByClassName(classNameId); + const n = tohover ? tohover.length : 0 ; + for (var k = 0; k < n; k++) tohover[k].classList.add(className); + } + + _unmarkElementsWith(className) { + const root = this.rootElement ; + const hovered = root && root.getElementsByClassName(className); + const n = hovered ? hovered.length : 0 ; + if (n==0) return ; + const elts = new Array(n); ; + for (var k = 0; k < n; k++) elts[k] = hovered[k]; + elts.forEach((elt) => elt.classList.remove(className)); + } + + handleHover(target) { + // Throttled (see constructor) + const older = this.hover ; + const hover = this._findHover(target); + if (older !== hover) { + if (older) this._unmarkElementsWith( CSS_HOVERED ); + if (hover && hover.hover) this._markElementsWith( hover.classNameId, CSS_HOVERED ); + this.hover = hover ; + } + } + + handleUpdate() { + const root = this.rootElement ; + const marked = root && root.getElementsByClassName('dome-xMarked'); + const n = marked ? marked.length : 0 ; + if (n==0) return; + const hover = this.hover ; + const hovered = hover && hover.hover && hover.classNameId ; + const selection = this.props.selection ; + const selected = selection && ('dome-xMark-' + selection) ; + const buffer = this.props.buffer; + const decorator = buffer.getDecorator(); + if ( !hovered && !selection && !decorator ) return; + const actual = {} ; + for (var k = 0; k < n; k++) { + const elt = marked[k]; + const classes = elt.classList ; + if (hovered && classes.contains(hovered)) classes.add( CSS_HOVERED ); + if (selected && classes.contains(selected)) classes.add( CSS_SELECTED ); + if (decorator) { + const hover = this._findDecoration(classes,buffer,decorator,hovered,selected); + if (hover) { + const prev = this.decorations[ hover.classNameId ]; + const curr = hover.decoration ; + if (prev !== curr && prev) classes.remove(prev); + if (curr) { classes.add(curr); actual[ hover.classNameId ] = curr ; } + } + } + } + this.decorations = actual ; + } + + onMouseMove(evt) { + // Not throttled (can not leak Synthetic Events) + this.handleHover( evt.target ); + } + + onClick(evt) { + // No need for throttling + const target = evt.target ; + const onSelection = this.props.onSelection ; + if ( target && onSelection ) { + const hover = this._findHover(target); + if ( hover && hover.id ) onSelection( hover.id ); + } + this.props.buffer.setFocused(true); + } + + // -------------------------------------------------------------------------- + // --- Scrolling + // -------------------------------------------------------------------------- + + handleScrollTo(position) { + try { + const cm = this.codeMirror; + cm && cm.scrollIntoView(position); + } catch(_error) { } // Out of range + } + + // -------------------------------------------------------------------------- + // --- Focus + // -------------------------------------------------------------------------- + + handleKey(cm,key,_evt) { + switch(key) { + case 'Esc': + this.props.buffer.setFocused(false); + break; + default: + this.props.buffer.setFocused(true); + break; + } + } + + onFocus() { this.props.buffer.setFocused(true); } + onBlur() { this.props.buffer.setFocused(false); } + onScroll() { + const cm = this.codeMirror; + if (cm) { + const rect = cm.getScrollInfo(); + const delta = rect.height-rect.top-rect.clientHeight; + const buffer = this.props.buffer; + buffer.setFocused(delta > 0); + } + } + + // -------------------------------------------------------------------------- + // --- Rendering + // -------------------------------------------------------------------------- + + shouldComponentUpdate(newProps) { + const cm = this.codeMirror ; + if (cm) { + // Swap documents if necessary + const { buffer:oldBuffer, + selection:oldSelect, + ...oldConfig } = this.props ; + const { buffer:newBuffer, + selection:newSelect, + ...newConfig } = newProps ; + if (oldBuffer !== newBuffer) { + const newDoc = newBuffer.linkedDoc(); + const oldDoc = cm.swapDoc( newDoc ); + oldBuffer.unlinkDoc( oldDoc ); + } + // Incremental update options + var opt ; + for ( opt in oldConfig ) if (!(opt in newConfig)) { + const defValue = CodeMirror.defaults[opt]; + if (defValue) + cm.setOption( opt , defValue ); + } + for ( opt in newConfig ) { + const oldValue = oldConfig[opt]; + const newValue = newConfig[opt]; + if (newValue !== oldValue) { + cm.setOption( opt , newValue ); + } + } + // Update selection + if ( oldSelect !== newSelect ) { + if (oldSelect) this._unmarkElementsWith( CSS_SELECTED ); + if (newSelect) this._markElementsWith( 'dome-xMark-' + newSelect, CSS_SELECTED ); + } + } + // Keep mounted node unchanged + return false; + } + + render() { + return ( + <div className='dome-xText' + ref={this.mountPoint} + onClick={this.onClick} + onBlur={this.onBlur} + onFocus={this.onFocus} + onScroll={this.onScroll} + onMouseMove={this.onMouseMove} + />); + } + +} + +// -------------------------------------------------------------------------- + +export default { Text }; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/template/Application.js b/Ivette/src/dome/template/Application.js new file mode 100644 index 0000000000000000000000000000000000000000..f7720a2a81fa1ff5a15b2e0f58f28cf95140f1c0 --- /dev/null +++ b/Ivette/src/dome/template/Application.js @@ -0,0 +1,22 @@ +// -------------------------------------------------------------------------- +// --- Main React Component rendered by './index.js' +// -------------------------------------------------------------------------- + +/* + Template from $(DOME)/template/Application.js + + This module shall export a React Component that + will be rendered (with empty props and children) + in the main window of your application. + +*/ + +import React from 'react' ; +import Dome from 'dome' ; +import 'dome/misc/exports' ; + +export default (() => ( + <h1 className='dome-text-title' style={{margin: 24}}> + Hello World! + </h1> +)); diff --git a/Ivette/src/dome/template/Preferences.js b/Ivette/src/dome/template/Preferences.js new file mode 100644 index 0000000000000000000000000000000000000000..542d1d7c97a42463aa3f0f6f528e1262b58a4e07 --- /dev/null +++ b/Ivette/src/dome/template/Preferences.js @@ -0,0 +1,20 @@ +// -------------------------------------------------------------------------- +// --- Main React Component rendered by './index.js' +// -------------------------------------------------------------------------- + +/* + Template from $(DOME)/template/Settings.js + + This module shall export a React Component that + will be rendered (with empty props and children) + in the settings window of your application. + +*/ + +import React from 'react' ; + +export default (() => ( + <h1 className='dome-text-title' style={{margin: 24}}> + Settings (none) + </h1> +)); diff --git a/Ivette/src/dome/template/babelrc.json b/Ivette/src/dome/template/babelrc.json new file mode 100644 index 0000000000000000000000000000000000000000..3e895f0c581bd6d45a280384ee46860f7d37c213 --- /dev/null +++ b/Ivette/src/dome/template/babelrc.json @@ -0,0 +1,21 @@ +// -------------------------------------------------------------------------- +// --- Template .babelrc configuration file for Dome +// -------------------------------------------------------------------------- + +/* + Template from $(DOME)/template/babelrc.json + + This configuration is a necessary extension to electron-webpack + for enabling react-hot-reloading. +*/ + +{ + "presets": [ + [ "@babel/env", { "modules": false } ], + [ "@babel/react" ] + ], + "plugins": [ + "@babel/plugin-proposal-object-rest-spread", + "react-hot-loader/babel" + ] +} diff --git a/Ivette/src/dome/template/electron-webpack.json b/Ivette/src/dome/template/electron-webpack.json new file mode 100644 index 0000000000000000000000000000000000000000..048484644edbcf136112d58accdf3e584cda1979 --- /dev/null +++ b/Ivette/src/dome/template/electron-webpack.json @@ -0,0 +1,22 @@ +// -------------------------------------------------------------------------- +// --- Electron-webpack configuration file for Dome +// -------------------------------------------------------------------------- + +/* + Template from $(DOME)/template/electron-webpack.json + + This configuration file makes electron-webpack loading + webpack extensions to resolve Dome packages differently + for electron main-process and renderer-process. + + You may configure further electron-webpack to your convenience. +*/ + +{ + "main": { + "webpackConfig": "webpack.main.js" + }, + "renderer": { + "webpackConfig": "webpack.renderer.js" + } +} diff --git a/Ivette/src/dome/template/export.sh b/Ivette/src/dome/template/export.sh new file mode 100755 index 0000000000000000000000000000000000000000..ea5dc39d5fee0fabce5501431253fce3e19bf788 --- /dev/null +++ b/Ivette/src/dome/template/export.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- +# --- Export Dome API +# -------------------------------------------------------------------------- + +DOME=$1 +COND='' +COND+=' -not -path "*/demo/*"' +COND+=' -not -name "Application.js"' +COND+=' -not -name "Preferences.js"' +COND+=' -not -name "dome.js"' +COND+=' -not -name "index.js"' + +FILES=`cd $DOME/src ; find renderer -name "*.js" $COND` + +echo "{ let m = require('react'); register('react',m); }" +echo "{ let m = require('dome'); register('dome',m); }" +echo "{ let m = require('dome/system'); register('dome/system',m); }" +for f in $FILES +do + j=${f/renderer/dome} + m=${j/.js/} + echo "{ let m = require('$m'); register('$m',m); }" +done + +# -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/template/git-ignore b/Ivette/src/dome/template/git-ignore new file mode 100644 index 0000000000000000000000000000000000000000..ba1bdcdb1d98c0fbb219d8bef30c60d864e51a94 --- /dev/null +++ b/Ivette/src/dome/template/git-ignore @@ -0,0 +1,14 @@ +# -------------------------------------------------------------------------- +# --- Template .gitignore file for Dome +# -------------------------------------------------------------------------- + +.dome-*.stamp +.dome-*.back +node_modules +yarn.lock +yarn-error.log +/bin +/dist +/html + +# -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/template/main.js b/Ivette/src/dome/template/main.js new file mode 100644 index 0000000000000000000000000000000000000000..d102caa8c34b4a2c33a0166f86e23fbea55f6bf2 --- /dev/null +++ b/Ivette/src/dome/template/main.js @@ -0,0 +1,17 @@ +// -------------------------------------------------------------------------- +// --- Electron main-process entry-point for Dome. +// -------------------------------------------------------------------------- + +/* + Template of ./src/main/index.js + Imported from $(DOME)/template/main.js + + The call to Dome.start() will initialize the Dome application + and create the main window that will run the renderer process + from `src/renderer/index.js`. + + You may add your own code to be run in the Electron main-process + before or after the call to `Dome.start()`. +*/ + +import Dome from 'dome' ; diff --git a/Ivette/src/dome/template/makefile b/Ivette/src/dome/template/makefile new file mode 100644 index 0000000000000000000000000000000000000000..461cb2a1f8418e43c4f12753dbff3a642d9891d0 --- /dev/null +++ b/Ivette/src/dome/template/makefile @@ -0,0 +1,369 @@ +# -------------------------------------------------------------------------- +# --- Main Makefile for building Dome applications +# -------------------------------------------------------------------------- + +# DOMEMK_ reserved for makefile derived variables + +APP?=$(shell basename $(PWD)) +COPYRIGHT?="CEA Tech" + +DOME?=dome +DOME_ARGS?= +DOME_EXPORTS?= +DOME_PLUGINS?= +DOME_DOC?=html/dome +DOME_APP_CLI?=bin/$(shell echo $(APP) | tr [:upper:] [:lower:]) +DOME_APP_DOC?=html/$(shell echo $(APP) | tr [:upper:] [:lower:]) +DOME_APP_SRC?=src/renderer + +# -------------------------------------------------------------------------- +# --- Makefile Help +# -------------------------------------------------------------------------- + +.PHONY: dome-help + +dome-help: + @echo + @echo "[Dome] Builtin Targets:" + @echo " make dome-help This help" + @echo " make dome-dev Run application in development mode" + @echo " make dome-app Compile application" + @echo " make dome-dist Package application for production" + @echo " make dome-doc Generate Dome documentation" + @echo " make dome-api Generate Application documentation" + @echo " make dome-pkg Install development packages" + @echo " make dome-templ Update templates" + @echo " make dome-reboot Rebuild templates from scratch" + @echo " make dome-clean Remove dome temporary files" + @echo " make dome-plugins Package plugins for distribution" + @echo + @echo "[Dome] Development Variables:" + @echo " Dome framework DOME = '$(DOME)'" + @echo " Arguments (dev) DOME_ARGS = '$(DOME_ARGS)'" + @echo " Export modules DOME_EXPORTS = '$(DOME_EXPORTS)'" + @echo " Plugin modules DOME_PLUGINS = '$(DOME_PLUGINS)'" + @echo " Local command DOME_APP_CLI = '$(DOME_APP_CLI)'" + @echo + @echo "[Dome] Documentation Variables:" + @echo " Application APP = '$(APP)'" + @echo " Copyright COPYRIGHT = '$(COPYRIGHT)'" + @echo " Dome framework DOME_DOC = '$(DOME_DOC)'" + @echo " App. framework DOME_APP_DOC = '$(DOME_APP_DOC)'" + @echo " App. Sources DOME_APP_SRC = '$(DOME_APP_SRC)'" + @echo + +# -------------------------------------------------------------------------- +# --- Application Cleaning +# -------------------------------------------------------------------------- + +.PHONY: dome-clean + +dome-clean: + @echo "[Dome] remove temporary files" + @rm -fr dist .dome-*.stamp + +# -------------------------------------------------------------------------- +# --- Development Packages Init & Installation +# -------------------------------------------------------------------------- + +.PHONY: dome-pkg + +include $(DOME)/template/makefile.packages + +DOME_MK_BIN=$(PWD)/node_modules/.bin +DOME_MK_PKG= \ + package.json node_modules \ + $(DOME)/template/makefile.packages \ + $(DOME)/template/package.sh + +node_modules: + mkdir $@ + +dome-pkg: .dome-pkg.stamp +.dome-pkg.stamp: $(DOME_MK_PKG) + @echo "[Dome] ----------------------------------------------------------------" + @echo "[Dome] installing development packages" + @echo "[Dome] ----------------------------------------------------------------" + @$(DOME)/template/package.sh --dev $(DOME_DEV_PACKAGES) + @echo "[Dome] ----------------------------------------------------------------" + @echo "[Dome] installing application packages" + @echo "[Dome] ----------------------------------------------------------------" + @$(DOME)/template/package.sh --app $(DOME_APP_PACKAGES) + @echo "[Dome] ----------------------------------------------------------------" + @echo "[Dome] building application dependencies" + @echo "[Dome] ----------------------------------------------------------------" + yarn install + yarn run electron-builder install-app-deps + @touch $@ + +package.json: + yarn init + +# -------------------------------------------------------------------------- +# --- Application Templating +# -------------------------------------------------------------------------- + +.PHONY: dome-templ dome-reboot + +DOME_MK_TEMPLATES= \ + .gitignore \ + .babelrc \ + webpack.main.js \ + webpack.plugin.js \ + webpack.renderer.js \ + electron-webpack.json \ + src/main/index.js \ + src/renderer/index.js + +dome-templ: $(DOME_MK_TEMPLATES) +dome-reboot: + echo "[Dome] Backup templates" + @for f in $(DOME_MK_TEMPLATES) ; do mv -fv $$f $$f.backup ; done + $(MAKE) dome-templ dome-pkg + +# Templated files + +ifeq ("$(DOME)",".") +.gitignore: + @cp -f $(DOME)/template/git-ignore $@ +else +.gitignore: $(DOME)/template/update.sh $(DOME)/template/git-ignore + @((tail -r $(DOME)/template/git-ignore | tail -n +3 | tail -r) || head -n -3 $(DOME)/template/git-ignore) > $(DOME)/template/git-ignore.local + @echo "/$(DOME)" >> $(DOME)/template/git-ignore.local + @tail -2 $(DOME)/template/git-ignore >> $(DOME)/template/git-ignore.local + @$^.local $@ + @rm -f $(DOME)/template/git-ignore.local +endif + +.babelrc: $(DOME)/template/update.sh $(DOME)/template/babelrc.json + @$^ $@ + +webpack.main.js: $(DOME)/template/update.sh $(DOME)/template/webpack.main.js + @$^ $@ + +webpack.renderer.js: $(DOME)/template/update.sh $(DOME)/template/webpack.renderer.js + @$^ $@ + +webpack.plugin.js: $(DOME)/template/update.sh $(DOME)/template/webpack.plugin.js + @$^ $@ + +electron-webpack.json: $(DOME)/template/update.sh $(DOME)/template/electron-webpack.json + @$^ $@ + +src/renderer/index.js: $(DOME)/template/update.sh $(DOME)/template/renderer.js + @$^ $@ + +src/main/index.js: $(DOME)/template/update.sh $(DOME)/template/main.js + @cp $(DOME)/template/main.js $(DOME)/template/main.js.local + @echo "Dome.setName('$(APP)');" >> $(DOME)/template/main.js.local + @echo "Dome.start();" >> $(DOME)/template/main.js.local + @$^.local $@ + @rm -f $(DOME)/template/main.js.local + +# -------------------------------------------------------------------------- +# --- Custom Entry Points +# -------------------------------------------------------------------------- + +ifndef DOME_CUSTOM_ENTRIES + +dome-templ: src/renderer/Application.js +src/renderer/Application.js: + @echo "[Dome] creating $@ from template" + @mkdir -p src/renderer + @cp -f $(DOME)/template/Application.js $@ + +dome-templ: src/renderer/Preferences.js +src/renderer/Preferences.js: + @echo "[Dome] creating $@ from template" + @mkdir -p src/renderer + @cp -f $(DOME)/template/Preferences.js $@ + +endif + +# -------------------------------------------------------------------------- +# --- Exported API for Plugins +# -------------------------------------------------------------------------- + +.PHONY: dome-export-dev dome-export-app + +DOME_MK_EXPORTS_JS=$(DOME)/src/misc/exports.js + +# -------------------------------------------------------------------------- + +dome-export-dev: + @rm -f $(DOME_MK_EXPORTS_JS) + @echo "// Static Plugins Loader" > $(DOME_MK_EXPORTS_JS) + @for m in $(DOME_EXPORTS) ;\ + do \ + echo "[Dome] installing '$$m'" ;\ + echo "import '$$m';" \ + >> $(DOME_MK_EXPORTS_JS) ;\ + done + @for m in $(DOME_PLUGINS) ;\ + do \ + echo "[Dome] loading plugin $$m" ;\ + echo "import '@plugins/$$m';" >> $(DOME_MK_EXPORTS_JS) ;\ + done + @chmod a-w $(DOME_MK_EXPORTS_JS) + +# -------------------------------------------------------------------------- + +dome-export-app: + @rm -f $(DOME_MK_EXPORTS_JS) + @echo "// Static Loader (Generated by Dome)" > $(DOME_MK_EXPORTS_JS) + @echo "import { register } from 'dome/misc/plugins' ;" >> $(DOME_MK_EXPORTS_JS) ; + @echo "[Dome] export 'dome'" ; + @$(DOME)/template/export.sh $(DOME) >> $(DOME_MK_EXPORTS_JS) + @for m in $(DOME_EXPORTS) ;\ + do \ + echo "[Dome] export '$$m'" ;\ + echo "{ let m = require('$$m'); register('$$m',m); }" \ + >> $(DOME_MK_EXPORTS_JS) ;\ + done + @for m in $(DOME_PLUGINS) ;\ + do \ + echo "[Dome] install '@plugins/$$m'" ;\ + echo "{ let m = require('@plugins/$$m'); register('@plugins/$$m',m); }" \ + >> $(DOME_MK_EXPORTS_JS) ;\ + done + @chmod a-w $(DOME_MK_EXPORTS_JS) + +# -------------------------------------------------------------------------- +# --- Packaging Plugins +# -------------------------------------------------------------------------- + +.PHONY: dome-plugins dome-plugin-% + +DOME_MK_PLUGINS_TARGET=$(addprefix dome-plugin-, $(DOME_PLUGINS)) +DOME_MK_PLUGINS_SOURCE=$(addprefix src/plugins/, $(DOME_PLUGINS)) +DOME_MK_PLUGINS_CONFIG=$(addsuffix /package.json, $(DOME_MK_PLUGINS_SOURCE)) + +dome-plugins: $(DOME_MK_PLUGINS_CONFIG) $(DOME_MK_PLUGINS_TARGET) + +dome-plugin-%: src/plugins/%/package.json webpack.plugin.js + @echo "[Dome] building plugin '$*'" + @rm -fr dist/plugins/$* + @mkdir -p dist/plugins/$* + @node $(DOME)/template/packplugin.js '$*' + DOME=$(DOME) DOME_PLUGIN='$*' yarn run webpack -p --config webpack.plugin.js + @echo "[Dome] plugin packaged in ./dist/plugins/$*" + +src/plugins/%/package.json: + @echo "[Dome] creating package.json for plugin '$*'" + @echo '{' > $@ + @echo ' "name": "$*",' >> $@ + @echo ' "version": "0.1",' >> $@ + @echo ' "license": "UNLICENSED"' >> $@ + @echo '}' >> $@ + +# -------------------------------------------------------------------------- +# --- Application Development +# -------------------------------------------------------------------------- + +DOME_MK_CLIDIR=$(dir $(DOME_APP_CLI)) + +.PHONY: dome-dev + +dome-dev: dome-pkg dome-templ dome-export-dev + @echo "[Dome] linking $(DOME_APP_CLI)" + @mkdir -p $(DOME_MK_CLIDIR) + @rm -f $(DOME_APP_CLI) + @echo "#!/bin/sh" >> $(DOME_APP_CLI) + @echo "export DOME='$(DOME)'" >> $(DOME_APP_CLI) + @echo "export DOME_ENV='dev'" >> $(DOME_APP_CLI) + @echo 'exec $(DOME_MK_BIN)/electron-webpack dev "$$@"' >> $(DOME_APP_CLI) + @chmod 555 $(DOME_APP_CLI) + @echo "[Dome] running application (development)" + @$(DOME_APP_CLI) $(DOME_ARGS) + +# -------------------------------------------------------------------------- +# --- Application Building +# -------------------------------------------------------------------------- + +.PHONY: dome-app + +dome-app: dome-pkg dome-templ dome-export-app + @echo "[Dome] compiling application (production)" + DOME=$(DOME) DOME_ENV='app' yarn run electron-webpack app + @echo "[Dome] linking $(DOME_APP_CLI)" + @mkdir -p $(DOME_MK_CLIDIR) + @rm -f $(DOME_APP_CLI) + @echo "#!/bin/sh" >> $(DOME_APP_CLI) + @echo "export DOME_LOCAL=true" >> $(DOME_APP_CLI) + @echo 'exec $(DOME_MK_BIN)/electron $(PWD)/dist/main/main.js "$$@"' >> $(DOME_APP_CLI) + @chmod 555 $(DOME_APP_CLI) + +# -------------------------------------------------------------------------- +# --- Application Packaging +# -------------------------------------------------------------------------- + +.PHONY: dome-dist + +dome-dist: dome-app + @echo "[Dome] packaging application (production)" + DOME=$(DOME) yarn run electron-builder --dir -c.compression=store -c.mac.identity=null + @echo "[Dome] application packaged in ./dist" + +# -------------------------------------------------------------------------- +# --- Application JSdoc +# -------------------------------------------------------------------------- + +DOME_MK_API_DOC=$(PWD)/$(DOME_APP_DOC) +DOME_MK_API_SRC=$(PWD)/$(DOME_APP_SRC) $(addprefix $(PWD)/src/plugins/, $(DOME_PLUGINS)) + +dome-api: $(DOME_MK_BIN)/jsdoc + @echo "[Dome] generating $(APP) documentation" + @mkdir -p $(DOME_APP_DOC) + @rm -f $(DOME_APP_DOC)/*.html + @rm -f $(DOME_APP_DOC)/*.png + @rm -f $(DOME_APP_DOC)/*.css + @rm -fr $(DOME_APP_DOC)/fonts + @rm -fr $(DOME_APP_DOC)/styles + @(cd $(DOME) && DOME='.' DOME_PWD=$(PWD) APP=$(APP) COPYRIGHT=$(COPYRIGHT) \ + $(DOME_MK_BIN)/jsdoc -c ./doc/app.json $(DOME_MK_API_SRC) -d $(DOME_MK_API_DOC)) + @echo "[Dome] $(DOME_APP_DOC)/index.html" + +# -------------------------------------------------------------------------- +# --- Icon gallery +# -------------------------------------------------------------------------- + +DOME_MK_ICON_MAKE=$(DOME)/doc/icons.js +DOME_MK_ICON_DATA=$(DOME)/src/renderer/controls/icons.json +DOME_MK_ICON_HTML=$(DOME)/doc/template/gallery-icons.html + +$(DOME_MK_ICON_HTML): $(DOME_MK_ICON_MAKE) $(DOME_MK_ICON_DATA) + @echo "[Dome] generating icons gallery" + @node $(DOME_MK_ICON_MAKE) $(DOME_MK_ICON_DATA) > $(DOME_MK_ICON_HTML) + +# -------------------------------------------------------------------------- +# --- Dome Documentation +# -------------------------------------------------------------------------- + +DOME_MK_DOC_OUT=$(addprefix $(PWD)/, $(DOME_DOC)) + +dome-doc: $(DOME_MK_BIN)/jsdoc $(DOME_MK_ICON_HTML) + @echo "[Dome] generating Dome documentation" + @mkdir -p $(DOME_DOC) + @rm -f $(DOME_DOC)/*.html + @rm -f $(DOME_DOC)/*.png + @rm -f $(DOME_DOC)/*.css + @rm -fr $(DOME_DOC)/fonts + @rm -fr $(DOME_DOC)/styles + @(cd $(DOME) && DOME="." DOME_PWD=$(PWD) COPYRIGHT='CEA Tech' \ + $(DOME_MK_BIN)/jsdoc -c ./doc/config.json -d $(DOME_MK_DOC_OUT)) + @cp -f $(DOME)/doc/gallery.css $(DOME_DOC)/styles/ + @cp -f $(DOME)/doc/tutorials/*.png $(DOME_DOC)/ + @cat \ + $(DOME)/doc/template/gallery-head.html \ + $(DOME)/doc/template/gallery-icons.html \ + $(DOME)/doc/template/gallery-tail.html \ + > $(DOME_DOC)/gallery-icons.html + @echo "[Dome] $(DOME_DOC)/index.html" + +# --- Doc binaries --------------------------------------------------------- + +$(DOME_MK_BIN)/jsdoc: + @echo "[Dome] installing jsdoc" + @yarn add -D jsdoc + +# -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/template/makefile.app.packages b/Ivette/src/dome/template/makefile.app.packages new file mode 100644 index 0000000000000000000000000000000000000000..58aa6a3ad516168d48315864bfcf57376187f2b0 --- /dev/null +++ b/Ivette/src/dome/template/makefile.app.packages @@ -0,0 +1,15 @@ +# -------------------------------------------------------------------------- +# --- Package Template Definitions +# -------------------------------------------------------------------------- + +# Additional development yarn package specifications: + +DOME_PKG_DEV= + +# -------------------------------------------------------------------------- + +# Additional production yarn package specifications: + +DOME_PKG_APP= + +# -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/template/makefile.packages b/Ivette/src/dome/template/makefile.packages new file mode 100644 index 0000000000000000000000000000000000000000..05b8cb03aece9be54813a53d3952d9e804943839 --- /dev/null +++ b/Ivette/src/dome/template/makefile.packages @@ -0,0 +1,30 @@ +# -------------------------------------------------------------------------- +# --- Packages Definitions for Dome environment --- +# -------------------------------------------------------------------------- + +DOME_DEV_PACKAGES= \ + @babel/core@^7 \ + @babel/preset-env \ + @babel/preset-react \ + @babel/plugin-proposal-object-rest-spread \ + electron@^7 \ + electron-builder \ + electron-webpack \ + electron-devtools-installer \ + webpack \ + babel-loader \ + css-loader \ + react-hot-loader \ + @hot-loader/react-dom \ + @types/react + +DOME_APP_PACKAGES= \ + react@^16.8 \ + react-dom \ + source-map-support \ + lodash \ + react-virtualized \ + react-draggable \ + codemirror + +# -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/template/package.sh b/Ivette/src/dome/template/package.sh new file mode 100755 index 0000000000000000000000000000000000000000..58e4428ffb8b421a8c3c99266057dbb0962bc1fe --- /dev/null +++ b/Ivette/src/dome/template/package.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +# -------------------------------------------------------------------------- +# --- Compute mode +# -------------------------------------------------------------------------- + +OPT="" +LOG="" + +case $1 in + "--dev"|"-D") + OPT="--dev" + LOG=".dome-pkg-dev" + shift + ;; + "--app"|"-A") + OPT="" + LOG=".dome-pkg-app" + shift + ;; + *) + echo "Require --dev or --app option" + exit 1 + ;; +esac + +# -------------------------------------------------------------------------- +# --- Check for Updates +# -------------------------------------------------------------------------- + +rm -f $LOG.tmp +echo $* > $LOG.tmp + +if [ -f $LOG.lock ] +then + diff $LOG.tmp $LOG.lock + if [ $? -eq 0 ] + then + rm -f $LOG.tmp + echo "Packages are up-to-date." + exit 0 + fi +fi + +# -------------------------------------------------------------------------- +# --- Updates Packages +# -------------------------------------------------------------------------- + +echo "yarn add $OPT $*" +yarn add $OPT $* + +if [ $? -eq 0 ] +then + mv -f $LOG.tmp $LOG.lock +else + echo "Package installation failed." + exit 1 +fi + +# -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/template/packplugin.js b/Ivette/src/dome/template/packplugin.js new file mode 100644 index 0000000000000000000000000000000000000000..d0a9f265c2826d99fc11b7fed2a32ba4a574fb00 --- /dev/null +++ b/Ivette/src/dome/template/packplugin.js @@ -0,0 +1,31 @@ +#!/bin/node + +const fs = require('fs'); +const name = process.argv[2]; +const INFOS = [ + 'name', + 'version', + 'description', + 'homepage', + 'bugs', + 'keywords', + 'author', + 'contributors', + 'repository', + 'license' +]; + +const dst = { + name, + version: '0.1', + license: 'UNLICENSED', + main: 'bundle.js' +}; + +let src = './src/plugins/' + name + '/package.json' ; +let tgt = './dist/plugins/' + name + '/package.json' ; +let pkg = JSON.parse( fs.readFileSync( src , 'UTF-8' ) ); +INFOS.forEach((fd) => { let d = pkg[fd] ; if (!d) dst[fd] = d }); +fs.writeFileSync( tgt , JSON.stringify(dst) , 'UTF-8' ); + +// End. diff --git a/Ivette/src/dome/template/renderer.js b/Ivette/src/dome/template/renderer.js new file mode 100644 index 0000000000000000000000000000000000000000..1544ac9e11373febc48161e9672b71456c6819f6 --- /dev/null +++ b/Ivette/src/dome/template/renderer.js @@ -0,0 +1,41 @@ +// -------------------------------------------------------------------------- +// --- Electron renderer-process entry-point for Dome. +// -------------------------------------------------------------------------- + +/* + Template of ./src/renderer/index.js + Imported from $(DOME)/template/renderer.js + + You can modify this template and add your own code before or + after rendering the main components. + + However, please note that React hot-reloading is fragile. + Component that are not imported by <Application/> or <Preferences/> + may suffer from well known limitations of hot-reloading and + may lead to state losses or complete application reloads. +*/ + +// Enable live-editing in React: +import 'react-hot-loader/patch' ; +import React from 'react' ; +import Dome from 'dome' ; + +// You can change the name of the main components, +// provided you define the makefile variable +// `DOME_CUSTOM_ENTRIES` to prevent files 'Application.js' and 'Preferences.js' +// from being generated by the template makefile. + +import Application from './Application' ; +import Preferences from './Preferences' ; + +// Define the application main components for each window: +Dome.setApplicationWindow(Application); +Dome.setPreferencesWindow(Preferences); + +// Mark the main application reloadable and enable live updates: +module.hot && Dome.isApplicationWindow() && + module.hot.accept('./Application',() => Dome.setApplicationWindow(Application)); +module.hot && Dome.isPreferencesWindow() && + module.hot.accept('./Preferences',() => Dome.setPreferencesWindow(Preferences)); + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/template/update.sh b/Ivette/src/dome/template/update.sh new file mode 100755 index 0000000000000000000000000000000000000000..56d22295ef24fa4f37c19a100797c6005561921d --- /dev/null +++ b/Ivette/src/dome/template/update.sh @@ -0,0 +1,75 @@ +#!/bin/sh + +# -------------------------------------------------------------------------- +# --- Update Templated File (merge with user modifications) +# -------------------------------------------------------------------------- + +USER=$2 +TEMPLATE=$1 +BACK=$(dirname $USER)/.dome-$(basename $USER).back +ORIGIN=$(dirname $TEMPLATE)/.dome-$(basename $TEMPLATE).orig +DIFF=$(dirname $USER)/.dome-diff + +if [ ! -f $TEMPLATE ] +then + echo "[Dome] missing template ('$TEMPLATE')" + exit 2 +fi + +if [ -f $USER ] +then + if [ ! -f $ORIGIN ] + then + echo "[Dome] lost original template for '$USER' (search for diffs)" + cp -f $TEMPLATE $ORIGIN + fi + cp -f $USER $BACK + rm -f $USER + diff3 -m -L YOURS $BACK -L ORIGIN $ORIGIN -L TEMPLATE $TEMPLATE > $USER + MERGED=$? + cp -f $TEMPLATE $ORIGIN + if [ $MERGED -eq 0 ] + then + diff $USER $BACK > $DIFF + if [ $? -eq 0 ] + then + echo "[Dome] updated '$USER' with new template (no modifications)" + else + echo "[Dome] merged '$USER' with new template (backup saved)." + fi + rm -f $DIFF + exit 0 + else + while true + do + echo "[Dome] conflicting '$USER' with new template." + echo " (d) show diffs (e) edit conflict" + echo " (k) keep current (t) use template" + read -p "Your choice ? [t] " ACTION + case $ACTION in + d) + echo "Differences ( > yours, < template ):" + diff $TEMPLATE $BACK + ;; + e) + echo "Previous content saved in '$BACK'." + echo "Run 'make dome-templ' after '$USER' has been fixed." + exit 1 + ;; + k) + exit 0 + ;; + t|"") + cp -f $TEMPLATE $USER + exit 0 + ;; + esac + done + fi +else + echo "[Dome] creating '$USER' from template" + cp -f $TEMPLATE $USER + cp -f $TEMPLATE $ORIGIN +fi + +# -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/template/webpack.main.js b/Ivette/src/dome/template/webpack.main.js new file mode 100644 index 0000000000000000000000000000000000000000..608d29372314dcb2e5cd7406dac737c35371daf6 --- /dev/null +++ b/Ivette/src/dome/template/webpack.main.js @@ -0,0 +1,38 @@ +// -------------------------------------------------------------------------- +// --- Webpack extension for electron main-process +// -------------------------------------------------------------------------- + +/* + Template of ./webpack.main.js from $(DOME)/template/webpack.main.js + + This webpack definitions will be merged into electron-webpack + ones thanks to electron-webpack.json configuration file. + + You may extend it with your own additions. +*/ + +const path = require('path'); +const DOME = process.env.DOME || path.resolve(__dirname , 'dome'); +const ENV = process.env.DOME_ENV ; + +// Do not use electron-devtools-installer in production mode +function domeDevtools() { + switch(ENV) { + case 'dev': + return 'electron-devtools-installer'; + default: + return path.resolve( DOME , 'src/misc/devtools.js' ); + } +} + +module.exports = { + resolve: { + alias: { + 'dome$': path.resolve( DOME , 'src/main/dome.js' ), + 'dome/system$': path.resolve( DOME , 'src/misc/system.js' ), + 'dome/devtools': domeDevtools() + } + } +} ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/template/webpack.plugin.js b/Ivette/src/dome/template/webpack.plugin.js new file mode 100644 index 0000000000000000000000000000000000000000..f60bdbf7ab8cda15ad9dcba2c747a5a3d82e57ed --- /dev/null +++ b/Ivette/src/dome/template/webpack.plugin.js @@ -0,0 +1,41 @@ +// -------------------------------------------------------------------------- +// --- Webpack configuration for packing plugins +// -------------------------------------------------------------------------- + +/* + Template of ./webpack.plugin.js from $(DOME)/template/webpack.plugin.js + + This webpack definitions will be used to make plugin bundles. + + You may extend it with your own additions. +*/ + +const path = require('path'); +const DOME = process.env.DOME || path.resolve( __dirname , 'dome' ); +const PLUGIN = process.env.DOME_PLUGIN ; +const ENTRY = path.resolve( __dirname , 'src/plugins' , PLUGIN ); +const DIST = path.resolve( __dirname , 'dist/plugins' , PLUGIN ); + +module.exports = { + entry: ENTRY, + output: { + path: DIST, + filename: 'bundle.js', + libraryTarget: 'commonjs2' + }, + module: { + rules: [ + { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, + { test: /\.js$/, use: [ 'babel-loader' ], exclude: /(node_modules)/ } + ] + }, + externals: [ + 'lodash', + 'react', + /^dome\/.+$/, + /^@plugins\/.+$/, + /^@\/.+$/ + ] +}; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/dome/template/webpack.renderer.js b/Ivette/src/dome/template/webpack.renderer.js new file mode 100644 index 0000000000000000000000000000000000000000..5cba35d887a82293a2c5ee5c482eda406729fdd4 --- /dev/null +++ b/Ivette/src/dome/template/webpack.renderer.js @@ -0,0 +1,35 @@ +// -------------------------------------------------------------------------- +// --- Webpack extension for electron main-process +// -------------------------------------------------------------------------- + +/* + Template from $(DOME)/template/webpack.main.js + + This webpack definitions will be merged into electron-webpack + ones thanks to electron-webpack.json configuration file. + + You may extend it with your own additions. +*/ + +const path = require('path'); +const DOME = process.env.DOME || path.resolve( __dirname , 'dome' ); + +module.exports = { + module: { + rules: [ + { test: /\.css$/, use: [ 'css-loader' ] } + ] + }, + resolve: { + alias: { + '@plugins': path.resolve( __dirname , 'src/plugins' ), + 'dome/misc': path.resolve( DOME , 'src/misc' ), + 'dome/system': path.resolve( DOME , 'src/misc/system.js' ), + 'dome$': path.resolve( DOME , 'src/renderer/dome.js' ), + 'dome': path.resolve( DOME , 'src/renderer' ), + 'react-dom': '@hot-loader/react-dom' + } + } +} ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/frama-c/labviews.css b/Ivette/src/frama-c/labviews.css new file mode 100644 index 0000000000000000000000000000000000000000..1b6893fd996b7985af7b39b50199026d0f1ef621 --- /dev/null +++ b/Ivette/src/frama-c/labviews.css @@ -0,0 +1,53 @@ +/* -------------------------------------------------------------------------- */ +/* --- Styling LabViews --- */ +/* -------------------------------------------------------------------------- */ + +.dome-window-active .labview-icon { + fill: #7d7d7d ; +} + +.labview-field { + position: relative ; + left: -8px ; +} + +.labview-stock:hover { + background: #ccc ; +} + +.labview-stock:hover * { + cursor: move ; +} + +.labview-stock.dome-dragging +{ + border-radius: 4px ; + background: #ccc ; + border: thin solid black ; +} + +.labview-content +{ + background: #e6e6e6 ; +} + +.labview-titlebar +{ + background: #ccc ; +} + +.labview-titlebar .dome-xLabel +{ + padding-top: 3px ; +} + +.labview-handle +{ + flex: 1 1 auto ; + cursor: move ; +} + +.labview-close:hover +{ + fill: red ; +} diff --git a/Ivette/src/frama-c/labviews.js b/Ivette/src/frama-c/labviews.js new file mode 100644 index 0000000000000000000000000000000000000000..97fdcc2413e9693bdeb6fed36d8555b3440a35e4 --- /dev/null +++ b/Ivette/src/frama-c/labviews.js @@ -0,0 +1,597 @@ +// -------------------------------------------------------------------------- +// --- Lab View Component +// -------------------------------------------------------------------------- + +/** @module frama-c/labviews */ + +import _ from 'lodash' ; +import React from 'react' ; +import Dome from 'dome' ; +import { Catch } from 'dome/errors' ; +import { DnD, DragSource } from 'dome/dnd' ; +import { SideBar, Section, Item } from 'dome/layout/sidebars' ; +import { Splitter } from 'dome/layout/splitters' ; +import Grids, { GridLayout, GridItem } from 'dome/layout/grids' ; +import { Hbox, Hfill, Vfill, Filler } from 'dome/layout/boxes' ; +import { IconButton, Field } from 'dome/controls/buttons' ; +import { Label } from 'dome/controls/labels' ; +import { Icon } from 'dome/controls/icons' ; +import { Item as RenderItem, Render } from 'dome/layout/dispatch' ; +import './labviews.css' ; + +// -------------------------------------------------------------------------- +// --- Library +// -------------------------------------------------------------------------- + +class Library { + + constructor() { + this.modified = false ; + this.virtual = {} ; + this.collection = {} ; + this.items = [] ; + } + + commit() { + if (!_.isEqual(this.collection,this.virtual)) { + this.collection = Object.assign({},this.virtual) ; + this.items = _.sortBy(this.collection , [ 'order', 'id' ]); + this.modified = false ; + Dome.emit('labview.library'); + } + } + + useItem(id,group,path,props) { + if (!this.modified) { + this.modified = true ; + setImmediate(() => this.commit()); + } + if (!id) return undefined; + let order = props.rank === undefined + ? path + : path.slice(0,-1).concat([props.rank]); + let collection = this.virtual ; + collection[id] = Object.assign( { id, order, group }, props ); + return () => delete collection[id]; + } + +} + +// -------------------------------------------------------------------------- +// --- Library Components +// -------------------------------------------------------------------------- + +const isItemId = (fd,id) => id.startsWith(fd) && id[fd.length] === '.' ; +const getItemId = (fd,id) => isItemId(fd,id) ? id.substring(fd.length+1) : undefined ; +const getItems = (items,fd) => items.filter((item) => isItemId(fd,item.id)); + +const LibraryManager = React.createContext(); + +const useLibraryItem = (fd,{id, ...props}) => { + let context = React.useContext(LibraryManager); + React.useEffect(() => { + if (context) { + let { group, order, library } = context ; + let itemId = fd + '.' + id ; + return library.useItem(itemId,group,order,props); + } else + return undefined ; + }); + return context ; +}; + + +const Rankify = ({ library, group, order, children }) => { + let rank = 0; + let rankify = (elt) => { + let context = { group, order:order.concat([rank++]), library }; + return ( + <LibraryManager.Provider value={context}> + {elt} + </LibraryManager.Provider> + ); + }; + return ( + <React.Fragment> + {React.Children.map( children, rankify )} + </React.Fragment> + ); +}; + +const HIDDEN = { display: 'none' }; + +const UseLibrary = ( { library, children } ) => ( + <div style={HIDDEN}> + <Rankify library={library} order={[]}> + {children} + </Rankify> + </div> +); + +/** + @class + @summary Ordered collection of LabView Components. + @description + Renderers its children in the specified order. + Otherwized, elements are ordered by `rank` and `id`. + */ +export const Fragment = ({ group, children }) => { + let context = React.useContext(LibraryManager); + if (!context) + return null; + else { + return ( + <Rankify + group={group || context.group} + order={context.order} + library={context.library} > + {children} + </Rankify> + ); + } +}; + +/** + @class + @summary Group of LabView Components. + @property {string} id - group identifier + @property {string} label - displayed name + @property {string} [title] - description tooltip + @property {React.Children} [children] - group content + @description + Defines a group of components. The components rendered + _inside_ its content are implicitely affected to this group, + unless specified. The group content are also rendered + in their specified order. For nested collections of components, + use `<Fragment/>` instead of `<React.Fragment/>` to specify order. + */ +export const Group = ({ children,...props}) => { + let context = useLibraryItem('groups',props); + return ( + <Rankify + group={props.id} + order={context.order} + library={context.library} > + {children} + </Rankify> + ); +}; + +// -------------------------------------------------------------------------- +// --- Views +// -------------------------------------------------------------------------- + +/** + @class + @summary Layout of LabView Components. + @property {string} id - view identifier + @property {string} label - displayed name + @property {string} [title] - description tooltip + @property {boolean} [defaultView] - use this view by default + @property {GridContent} children - grid content of the view + @description + Defines a predefined layout of components. The view is organized + into a GridContent, which must _only_ consists of: + - `<GridHbox>…</GridHbox>` an horizontal grid of `GridContent` elements; + - `<GridVbox>…</GridVbox>` a vertical grid of `GridContent` elements; + - `<GridItem id=…>` a single component. + + These grid content components must be imported from the `dome/layout/grids` module: + ``` + import { GridItem, GridHbox, GridVbox } from 'dome/layout/grids'; + ``` + */ +export const View = (props) => { + useLibraryItem('views',props); + return null; +}; + +// -------------------------------------------------------------------------- +// --- Components +// -------------------------------------------------------------------------- + +/** + @class + @summary LabView Component. + @property {string} id - component identifier + @property {string} label - displayed name + @property {number} [rank] - ordering index + @property {string} [group] - attachment group + @property {string} [title] - description tooltip + @property {React.Children} children - component rendering elements + @description + Defines a component and its content when incorporated inside a view. + Unless specified, the component will be implicitely attached + to the current enclosing group. The `rank` property can be used + for adjusting component ordering (see also `<Fragment/>` and `<Group/>`). + */ +export const Component = (props) => { + useLibraryItem('components',props); + return null; +}; + +const TitleContext = React.createContext(); + +/** + @class + @summary LabView Component's title bar. + @property {string} [icon] - displayed icon + @property {string} [label] - displayed name + @property {string} [title] - description tooltip + @property {React.Children} children - additional components to render + @description + Defines an alternative component title bar. + If specified, the icon, label and title properties are rendered in an `<Label/>` component. + By default, the component title bar is labelled according to the component properties. + */ +export const Title = ({icon,label,title,children}) => { + let context = React.useContext(TitleContext); + return ( + <RenderItem id={'labview.title.'+context.id}> + <Label className='labview-handle' icon={icon} + label={label || context.label} + title={title || context.title}/> + {children} + </RenderItem> + ); +}; + +// -------------------------------------------------------------------------- +// --- Grid Item +// -------------------------------------------------------------------------- + +const GRIDITEM = { + className: 'dome-container dome-xBoxes-vbox dome-xBoxes-box', + handle: '.labview-handle', + resize: 'both', + fill: 'none', + shrink: 'none', + minWidth: 40, + minHeight: 40, + width: 120, + height: 120 +}; + +const GRIDITEM_PLAIN = { fill: 'both' }; +const GRIDITEM_HPANE = { fill: 'horizontal' }; +const GRIDITEM_VPANE = { fill: 'vertical' }; + +const makeGridItem = (customize,onClose) => comp => { + let { id:libId, label, title, layout='PLAIN', children } = comp ; + let id = getItemId('components',libId); + let properties = Object.assign( {}, GRIDITEM ); + switch( layout ) { + case 'PLAIN': + Object.assign( properties, GRIDITEM_PLAIN ); + break; + case 'HPANE': + Object.assign( properties, GRIDITEM_HPANE ); + break; + case 'VPANE': + Object.assign( properties, GRIDITEM_VPANE ); + break; + default: + console.warn(`[labviews] unexpected layout for ${id} component`,layout); + break; + } + for (let fd in properties) { + let prop = comp[fd] ; + if (prop) properties[fd] = prop ; + } + let CLOSING ; + if (customize) CLOSING = ( + <IconButton + className='labview-close' + offset={-1} icon='CROSS' + onClick={() => onClose(id)}/> + ); + return ( + <GridItem id={id} {...properties}> + <Vfill className='labview-content'> + <Hbox className='labview-titlebar'> + <Hfill className='labview-handle'> + <Catch title={id}> + <Render id={ 'labview.title.' + id }> + <Label className='labview-handle' + label={label} title={title} /> + </Render> + </Catch> + </Hfill> + { CLOSING } + </Hbox> + <TitleContext.Provider value={{id,label,title}}> + <Catch title={id}>{children}</Catch> + </TitleContext.Provider> + </Vfill> + </GridItem> + ); +}; + +// -------------------------------------------------------------------------- +// --- Customization Views +// -------------------------------------------------------------------------- + +function CustomViews( { settings, shape, setShape, views:libViews } ) +{ + const [ local, setLocal ] = Dome.useState( settings, {} ); + const [ customs, setCustoms ] = Dome.useGlobalSetting( settings, {} ); + const [ edited, setEdited ] = React.useState(); + const { current , shapes={} } = local ; + + let theViews = {}; + + _.forEach( libViews, (view) => { + const { id: origin, order, label='(Stock View)', title } = view ; + const id = 'builtin.' + origin ; + theViews[ id ] = { id, order, label, title, builtin: true, origin }; + }); + + _.forEach( customs, (view) => { + const { id, order, label='(Custom View)', title, origin } = view ; + if (id && !theViews[id]) + theViews[id] = { id, order, label, title, builtin: false, origin }; + }); + + const getStock = (origin) => ( + (origin + && _.find( libViews, (v) => v.id === origin )) + || _.find( libViews, (v) => v.defaultView ) + || libViews[0] + ); + + const getDefaultShape = ( view ) => { + let stock = getStock( view && view.origin ); + return stock && Grids.makeChildrenShape(stock.children); + }; + + const SELECT = (id) => { + if (id && current !== id) { + if (current) shapes[current] = shape ; + setLocal({ current: id, shapes }); + setShape( shapes[id] || getDefaultShape(theViews[id]) ); + } + }; + + const POPUP = (id) => { + let view = theViews[id]; + if (!view) return; + let isCurrent = current === id ; + let isCustom = !view.builtin ; + + const DEFAULT = () => { + shapes[id] = undefined; + setLocal({ current:id, shapes }); + setShape( getDefaultShape(view) ); + }; + + const RENAME = () => setEdited(id); + + const DUPLICATE = () => { + let base = 'custom.' + view.origin ; + let stock = getStock(view.origin); + let k = 1, newId = base ; + while (theViews[newId]) newId = base + '~' + (++k) ; + let newOrder = view.order ; + if (newOrder && newOrder.concat) newOrder = newOrder.concat([k]); + let newLabel = 'Custom ' + stock.label ; + if (k>1) newLabel += '~' + k ; + customs[newId] = { + id: newId, + label: newLabel, + order: newOrder, + title:'Derived from ' + stock.label, + origin: view.origin, + builtin: false + }; + setCustoms(customs); + if (current) shapes[current] = shape; + setLocal({ current:newId, shapes }); + setEdited(newId); + }; + + const REMOVE = () => { + delete customs[id]; + delete shapes[id]; + setCustoms(customs); + let newCurrent = current === id ? undefined : current ; + setLocal({ current: newCurrent, shapes }); + }; + + Dome.popupMenu([ + { label: "Rename View", display:(!edited && isCustom), onClick: RENAME }, + { label: "Restore Default", display:isCurrent, onClick: DEFAULT }, + { label: "Duplicate View",onClick: DUPLICATE }, + 'separator', + { label: "Remove View", display:isCustom, onClick: REMOVE } + ]); + }; + + const makeViewItem = ({ id, label, title, builtin, origin }) => { + if (edited === id) { + const RENAMED = (newLabel) => { + if (newLabel) { + let custom = customs[id] ; + if (custom) custom.label = newLabel ; + setCustoms( customs ); + } + setEdited( undefined ); + }; + const FIELD=( + <Field className='labview-field' + placeholder='View Name' + autoFocus value={label} + onEnter={RENAMED} /> + ); + return ( + <Item key={id} id={id} icon='DISPLAY' title={title} label={FIELD}/> + ); + } else { + const FLAGS=[] ; + if (builtin) FLAGS.push('LOCK'); + return ( + <Item + key={id} id={id} + icon='DISPLAY' + label={label} + title={title} + selected={id && current === id} + onSelection={SELECT} + onContextMenu={POPUP} + > + {FLAGS.map((icn) => ( + <Icon key={icn} className='labview-icon' size={9} offset={1} id={icn} /> + ))} + </Item> + ); + } + }; + + return ( + <Section label='Views'> + {_.sortBy(theViews,['order','id']).map(makeViewItem)} + </Section> + ); +} + +// -------------------------------------------------------------------------- +// --- Customization Components +// -------------------------------------------------------------------------- + +const DRAGOVERLAY = { className: 'labview-stock' }; + +function CustomGroup( { dnd, shape, setDragging, id, title, label, components } ) +{ + + const makeComponent = ({ id, label, title }) => { + let itemId = getItemId('components',id); + let disabled = Grids.getShapeItem(shape,itemId) !== undefined ; + return ( + <DragSource key={id} dnd={dnd} + disabled={ disabled } + overlay={ disabled ? undefined : DRAGOVERLAY } + onStart={() => setDragging(itemId)} > + <Item icon='COMPONENT' disabled={ disabled } label={label} title={title} /> + </DragSource> + ); + }; + + return ( + <Section id={id} label={label} title={title}> + { components.map(makeComponent) } + </Section> + ); +} + +// -------------------------------------------------------------------------- +// --- Customization Panel +// -------------------------------------------------------------------------- + +function CustomizePanel({ dnd, settings, library, shape, setShape, setDragging }) +{ + + const items = library.items ; + const views = getItems(items,'views'); + const groups = getItems(items,'groups'); + const components = getItems(items,'components'); + const setting_folds = settings && settings + '.folds' ; + const setting_views = settings && settings + '.views' ; + const contents = {} ; + + groups.unshift({ id:'nogroup', label:'Components' }); + groups.forEach((g) => contents[g.id] = []); + + components.forEach((c) => { + let gid = c.group ? 'groups.' + c.group : 'nogroup' ; + let content = contents[gid] ; + if (content === undefined) content = contents.nogroup ; + content.push(c); + }); + + return ( + <SideBar settings={setting_folds}> + <CustomViews + key='views' + settings={setting_views} + shape={shape} + setShape={setShape} + views={views} /> + {groups.map((g) => ( + <CustomGroup + key={g.id} id={g.id} + label={g.label} title={g.title} + dnd={dnd} setDragging={setDragging} shape={shape} + components={contents[g.id]} /> + ))} + </SideBar> + ); +} + +// -------------------------------------------------------------------------- +// --- LabView Container +// -------------------------------------------------------------------------- + +/** + @class + @summary Reconfigurable Container (React Component) + @property {boolean} [customize] - show components panel (false by default) + @property {string} [settings] - window settings to make views persistent + @property {React.Children} children - the labview content + @description + This container displays its content into a reconfigurable view. + + The entire content is rendered, but elements must be packed into `<Component/>` + containers, otherwise, they would remain invisible. + Content may also contains `<View/>` and `<Group/>` definitions, and the content + can be defined through any kind of React components. +*/ +export function LabView(props) +{ + // Parameters + const { settings, customize=false, children } = props ; + const setting_split = settings && settings + '.split' ; + const setting_shape = settings && settings + '.shape' ; + const setting_panel = settings && settings + '.panel' ; + // Hooks & State + Dome.useUpdate('labview.library','dome.defaults'); + const dnd = React.useMemo(() => new DnD(),[]); + const lib = React.useMemo(() => new Library(),[]); + const [ shape, setShape ] = Dome.useState(setting_shape); + const [ dragging, setDragging ] = React.useState(); + // Preparation + const onClose = (id) => setShape(Grids.removeShapeItem(shape,id)); + const components = _.filter( lib.collection, (item) => isItemId('components',item.id) ); + const gridItems = components.map(makeGridItem(customize,onClose)); + const holding = dragging ? gridItems.find((elt) => elt.props.id === dragging) : undefined ; + // Make view + return ( + <React.Fragment> + <UseLibrary library={lib}> + {children} + </UseLibrary> + <Splitter settings={setting_split} unfold={customize} dir='RIGHT'> + <GridLayout + dnd={dnd} + padding={2} + className='labview-container' + items={gridItems} + shape={shape} + onReshape={setShape} + holding={holding} /> + <CustomizePanel + dnd={dnd} + settings={setting_panel} + shape={shape} + setShape={setShape} + setDragging={setDragging} + library={lib} /> + </Splitter> + </React.Fragment> + ); + +} + +// -------------------------------------------------------------------------- + +export default { LabView, View, Group, Component, Title } ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/frama-c/server.js b/Ivette/src/frama-c/server.js new file mode 100644 index 0000000000000000000000000000000000000000..60aabc6c8536123d40519fca2fb9033da5c9f5f2 --- /dev/null +++ b/Ivette/src/frama-c/server.js @@ -0,0 +1,623 @@ +// -------------------------------------------------------------------------- +// --- Frama-C Server +// -------------------------------------------------------------------------- + +/** + @module frama-c/server + @description + Manage the current Frama-C server/client interface +*/ + +import _ from 'lodash' ; +import React from 'react' ; +import Dome from 'dome' ; +import System from 'dome/system' ; +import { Buffer } from 'dome/text/buffers' ; +import Zmq from 'zeromq' ; + +// -------------------------------------------------------------------------- +// --- Events +// -------------------------------------------------------------------------- + +/** + @event + @summary Server Status Notification Event + @description + Event `'frama-c.server`. +*/ +export const SERVER = 'frama-c.server' ; + +// -------------------------------------------------------------------------- +// --- Server Utilities +// -------------------------------------------------------------------------- +/* +const SERVER_LOG = '-server-log' ; +const SERVER_NO_LOG = '-server-no-log' ; +const SERVER_OPT = '-server-zmq' ; +const SERVER_DEF = '-server-zmq=' ; +const SERVER_URL = '.frama-c.socket.io' ; + +const getZmqLog = (params) => params.find((opt) => ( + opt === SERVER_LOG || opt === SERVER_NO_LOG +)); + +const getZmqURL = (params) => { + let def = params.findIndex((opt) => opt.startsWith(SERVER_DEF)); + if (def) { + let quote = def[ SERVER_DEF.length ]; + return ( quote === "'" || quote === '"' ) + ? def.slice( SERVER_DEF.length + 1 , -1 ) + : def.slice( SERVER_DEF.length ); + } + let pos = params.findIndex((opt) => opt.startsWith(SERVER_OPT)); + if (pos) return params[pos+1]; + return undefined ; +}; +*/ +// -------------------------------------------------------------------------- +// --- Server Status +// -------------------------------------------------------------------------- + +/** + @typedef STATUS + @summary Server Status Codes. + @description +- `IDLE` Server paused +- `STARTED` Frama-C command launched +- `RUNNING` Server ready +- `KILLING` Server shutdown, waiting for exit +- `RESTART` Server shutdown, will reboot on exit +- `FAILED` Server halted on error + */ + +export const IDLE = 'IDLE' ; +export const STARTED = 'STARTED' ; // Command started +export const RUNNING = 'RUNNING' ; // Server connected +export const KILLING = 'KILLING' ; // Waiting for halt +export const RESTART = 'RESTART' ; // Restart when halt +export const FAILED = 'FAILED' ; // Error issued + +// -------------------------------------------------------------------------- +// --- Server Class +// -------------------------------------------------------------------------- + +/** + @summary Frama-C Server Interface. + @description + This class is responsible for running a Frama-C server + and communicate with it. + The server automatically locks the module when running + and listen to module KILL events. + + The server shall be property configured before being started. + It does _not_ use configuration from `module.config` on its own ; + you shall configure it by using `server.configure()`. + */ +export class Server { + + constructor() { + this.status = IDLE ; + this.console = new Buffer({ maxlines: 200 }); + this._reset(); + this.stop = this.stop.bind(this); + this.kill = this.kill.bind(this); + this.start = this.start.bind(this); + this.restart = this.restart.bind(this); + this.clearFailed = this.clearFailed.bind(this); + } + + // -------------------------------------------------------------------------- + + // CLIENT STATE: + // this.rqid // Request ID + // this.sent // Characters sent + // this.recv // Characters received + // this.started // Date of Server activity start + // this.process // Cumulated Server processing time + // this.pending // Pending promise callbacks + // this.queue_cmd // Queue of server commands to be sent + // this.queue_ids // Waiting request ids to be sent + // this.polling // Polling scheduled + + // SERVER STATE: + // this.config: server process config + // this.process: dome child process + // this.socket: ZMQ (REQ) socket + // this.busy: ZMQ socket is busy + // this.error: process error + // this.killer: killer timeout + + // SERVER CONFIG: + // See this.configure() + + // -------------------------------------------------------------------------- + // --- Server Status + // -------------------------------------------------------------------------- + + /** Return `FAILED` status message. */ + getError() { return this.error; } + + /** + @summary Current Server `STATUS`. + @return {STATUS} the current server status + @description + See [STATUS](module-frama-c_server.html#~STATUS) code definitions. + */ + getStatus() { return this.status; } + _status(s,err) { + if (s !== this.status || err) { + this.status = s; + this.error = err; + this.module.emit(SERVER); + } + } + + /** + @summary Frama-C Server is running and ready to handle requests. + @return {boolean} status is `RUNNING`. + */ + isRunning() { return this.status === RUNNING; } + + /** + @summary Server Statistics. + @return {object} stats (see above) + @description +The returned object has the following properties: +- `pending` : number of pending requests; +- `requests` : number of issued requests; +- `time` : ellapsed time of server activity, in milliseconds. +- `sent` : number of UTF-8 chars sent to server; +- `recv` : number of UTF-8 chars received from server; +- `rate` : number of requests per milliseconds. + */ + getStats() { + const pending = _.reduce( this.pending , (n,_) => n+1, 0 ); + const requests = this.rqid - pending ; + const process = this.process ; + const started = this.started ; + const sent = this.sent ; + const recv = this.recv ; + const time = process + (started ? Date.now() - started : 0 ); + const rate = process ? requests / process : 0 ; + return { + pending, requests, sent, recv, rate, time + }; + } + + // -------------------------------------------------------------------------- + // --- Server Control (Start) + // -------------------------------------------------------------------------- + + /** + @summary Start the Server. + @description + If the server is started or running, this is a no-op. + If the server is being shutdown, it will reboot. + Otherwise, the Frama-C Server is spawned. + + You can use `server.start` instead of `() => server.start()`. + */ + start() { + switch(this.status) { + case IDLE: + case FAILED: + this._status(STARTED); + this._launch() + .then(() => this._status(RUNNING)) + .catch((err) => this._status(FAILED,err)); + return; + case KILLING: + this._status(RESTART); + return; + case STARTED: + case RUNNING: + case RESTART: + default: + return; + } + } + + // -------------------------------------------------------------------------- + // --- Server Control (Stop) + // -------------------------------------------------------------------------- + + /** + @summary Stop the Server. + @description + If the server is starting, it is hard killed. + If the server is running, it is shutdown gracefully. + When the server is shutting down, restart is canceled. + Otherwise, this is a no-op. + + You can use `server.stop` instead of `() => server.stop()`. + */ + stop() { + switch(this.status) { + case STARTED: + this._kill(); + this._status(KILLING); + return; + case RUNNING: + this._shutdown(); + this._status(KILLING); + return; + case RESTART: + this._status(KILLING); + return; + case IDLE: + case FAILED: + case KILLING: + default: + return; + } + } + + // -------------------------------------------------------------------------- + // --- Server Control (Kill) + // -------------------------------------------------------------------------- + + /** + @summary Terminate the Server. + @description + If the server is starting or running or shutting down, + it is hard killed and restart is canceled. + Otherwize, this is no-op. + + You can use `server.kill` instead of `() => server.kill()`. + This function is automatically called when the `module` emits the `KILL` signal. + */ + kill() { + switch(this.status) { + case STARTED: + case RUNNING: + case KILLING: + case RESTART: + this._kill(); + this._status(KILLING); + return; + case IDLE: + case FAILED: + default: + return; + } + } + + // -------------------------------------------------------------------------- + // --- Server Control (Restart) + // -------------------------------------------------------------------------- + + /** + @summary Re-start the Server. + @description + If paused, simply start the Server. + When running, try to gracefully shutdown the Server, + and finally schedule a reboot on exit. + */ + restart() { + switch(this.status) { + case IDLE: + case FAILED: + this.start(); + return; + case RUNNING: + this._shutdown(); + // Fall Through + case KILLING: + this._status(RESTART); + return; + case STARTED: + case RESTART: + default: + return; + } + } + + // -------------------------------------------------------------------------- + // --- Server Control (Reset) + // -------------------------------------------------------------------------- + + /** + @summary Acknowledge `FAILED` status. + @description + Simply go back to `IDLE` status when `FAILED`. + Otherwised, do nothing. + */ + clearFailed() { + if (this.status === FAILED) + this._status(IDLE); + } + + // -------------------------------------------------------------------------- + // --- Server Configure + // -------------------------------------------------------------------------- + + /** + @summary Configure the Server. + @param {object} config - Server Configuration + @param {string} [config.command] - Server command (default: `frama-c`) + @param {Array.<string>} [config.params] - Server arguments (default: `-server-zmq .frama-c.socket.io`) + @param {string} [config.sockaddr] - Server socket name (default: `.frama-c.socket.io`) + @param {string} [config.logout] - Process stdout log file (default: `undefined`) + @param {string} [config.logerr] - Process stderr log file (default: `undefined`) + @param {Object} [config.env] - Process environment variables (default: `undefined`) + */ + configure( config ) + { + if (!config) + this.config = + { + command: 'frama-c', + params: ['-server-zmq', '.frama-c.socket.io'], + sockaddr: '.frama-c.socket.io' + } + else + this.config = config; + } + + // -------------------------------------------------------------------------- + // --- Low-level Launching + // -------------------------------------------------------------------------- + + async _launch() { + this._reset(); + if (!this.config) throw('Frama-C Server not configured'); + let { env, command, params, sockaddr, logout, logerr } = this.config; + sockaddr = System.join( this.module.session, sockaddr ); + logout = logout && System.join( this.module.session, logout ); + logerr = logerr && System.join( this.module.session, logerr ); + let options = { + cwd: this.module.session, + stdout: { path: logout, pipe: true }, + stderr: { path: logerr, pipe: true }, + env + }; + // Launch Process + const process = await System.spawn( command, params, options ); + const logging = this.console.append ; + const kill = this.kill ; + this.console.clear(); + this.module.lock(); + this.module.on(KILL,kill); + this.process = process ; + process.stdout.on('data', logging ); + process.stderr.on('data', logging ); + process.on('close', (status) => { + this.module.off(KILL,kill); + this.module.unlock(); + logging('Exit',status,'\n'); + this._close(status); + }); + // Connect to Server + this.socket = new Zmq.Request(); + this.busy = false ; + await this.socket.bind(addr).catch(kill); + } + + // -------------------------------------------------------------------------- + // --- Low-level Killing + // -------------------------------------------------------------------------- + + _reset() { + this.rqid = 0; + this.sent = 0; + this.recv = 0; + this.time = 0; + this.process = 0; + this.started = undefined; + this.queue_cmd = []; + this.queue_ids = []; + const pending = this.pending ; + this.pending = {}; + _.forEach( pending , ({ reject }) => reject('shutdown') ); + if (this.flushed) clearImmediate(this.flushed); + this.flushed = undefined; + if (this.polling) clearTimeout(this.polling); + this.polling = undefined; + } + + _kill() { + this._reset(); + if (this.killer) clearTimeout(this.killer); + if (this.process) this.process.kill(); + } + + _shutdown() { + this._reset(); + this.queue_cmd.push('SHUTDOWN'); + this._flush(); + if (!this.killer) { + const process = this.process ; + if (process) { + const timeout = (this.config && this.config.timeout) || 300 ; + this.killer = setTimeout( () => process.kill() , timeout ); + } + } + } + + _close(status) { + this._reset(); + if (this.killer) { + clearTimeout( this.killer ); + this.killer = undefined ; + } + if (this.socket) { + this.socket.close(); + this.socket = undefined ; + this.busy = false ; + } + if (this.process) { + this.process.kill(); + this.process = undefined ; + } + if (status) { + this._status(FAILED,'Exit Status ' + status); + } else { + this._status(IDLE); + } + } + + // -------------------------------------------------------------------------- + // --- Request Queue + // -------------------------------------------------------------------------- + + sendGET( rq, params ) { return this._sendRequest( 'GET' , rq , params ); } + sendSET( rq, params ) { return this._sendRequest( 'SET' , rq , params ); } + sendEXEC( rq, params ) { return this._sendRequest( 'EXEC' , rq , params ); } + + _sendRequest( kind, rq , params ) { + if (!this.isRunning()) return Promise.reject('Server not running'); + const rid = 'RQ.' + this.rqid++; + const data = JSON.stringify(params); + const promise = new Promise((resolve,reject) => { + this.pending[rid] = { resolve, reject }; + this.queue_cmd.push(kind,rid,rq,data); + this.queue_ids.push(rid); + }); + promise.kill = () => { + if (this.socket && this.pending[rid]) { + this.queue_cmd.push('KILL',rid); + this._flush(); + } + }; + this._flush(); + return promise; + } + + _resolve(id,result) { + let promise = this.pending[id]; + if (promise) { + delete this.pending[id]; + promise.resolve(result); + } + } + + _reject(id,error) { + let promise = this.pending[id]; + if (promise) { + delete this.pending[id]; + promise.reject(error); + } + } + + _cancel(ids) { + ids.forEach((rid) => this._reject(rid,'canceled')); + } + + _waiting() { + return _.find( this.resolve , () => true ) !== undefined ; + } + + // -------------------------------------------------------------------------- + // --- Server Command Queue + // -------------------------------------------------------------------------- + + _flush() { + if (!this.flushed) { + this.flushed = setImmediate(() => { + this.flushed = undefined; + this._send(); + }); + } + } + + _poll() { + if (!this.polling) { + let timeout = (this.config && this.config.polling) || 50 ; + this.polling = setTimeout(() => { + this.polling = false; + this._send(); + }, timeout); + } + } + + _send() { + // when busy, will be eventually re-triggered + if (!this.busy) { + const cmd = this.queue_cmd ; + if (!cmd.length && this._waiting()) cmd.push('POLL'); + if (!cmd.length) { + const ids = this.queue_ids ; + this.queue_cmd = []; + this.queue_ids = []; + const socket = this.socket ; + if (socket) { + if (!this.started) this.started = Date.now() ; + this.busy = true ; + this.sent = cmd.reduce( (s,p) => s + p.length , this.sent); + socket.send( cmd ) + .then(() => socket.receive().then((resp) => this._receive(resp))) + .catch(() => this._cancel(ids)) + .finally(() => this.busy = false); + } else + this._cancel(ids); + } else { + const started = this.started ; + if (started) { + const stopped = Date.now(); + this.process += stopped - started ; + this.started = undefined ; + } + } + } + } + + _receive(resp) { + try { + this.recv = resp.reduce( (s,p) => s + p.length , this.recv); + var rid,data,err,cmd; + const shift = () => resp.shift().toString(); + while( resp.length ) { + cmd = shift(); + switch( cmd ) { + case 'NONE': + break; + case 'DATA': + rid = shift(); + data = shift(); + this._resolve(rid,data); + break; + case 'KILLED': + rid = shift(); + this._reject(rid,'killed'); + break; + case 'ERROR': + rid = shift(); + err = shift(); + this._reject(rid,err); + break; + case 'REJECTED': + rid = shift(); + this._reject(rid,'rejected'); + break; + case 'WRONG': + err = shift(); + console.error('[Frama-C Server] ZMQ Protocol Error:',err); + break; + case 'NONE': + break; + default: + console.error('[Frama-C Server] Unknown Response:',cmd); + resp.length = 0; + break; + } + } + } finally { + if (this.queue_cmd.length) + this._flush(); + else + this._poll(); + } + } + +} + +// -------------------------------------------------------------------------- +// --- Exports +// -------------------------------------------------------------------------- + +export default { + Server, + IDLE,STARTED,RUNNING,KILLING,RESTART,FAILED +}; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/frama-c/states.js b/Ivette/src/frama-c/states.js new file mode 100644 index 0000000000000000000000000000000000000000..a602bb1430fcab581e7738fa5725802561edd0be --- /dev/null +++ b/Ivette/src/frama-c/states.js @@ -0,0 +1,114 @@ +// -------------------------------------------------------------------------- +// --- Frama-C States +// -------------------------------------------------------------------------- + +/** + @module frama-c/states + @description + Manage the current Frama-C project and projectified state values. +*/ + +import _ from 'lodash' ; +import React from 'react' ; +import Dome from 'dome' ; + +const NONE = [ undefined, () => undefined ]; // No-state + +/** + @event + @summary Current Project Updates + @description + Event `'frama-c.project'`. +*/ +export const PROJECT = 'frama-c.project' ; + +/** + @event + @summary State Notification Event (prefix) + @description + Event `'frama-c.state.<id>'` for project `<id>`. +*/ +export const STATE = 'frama-c.state.' ; + +// -------------------------------------------------------------------------- +// --- Current Project +// -------------------------------------------------------------------------- + +var currentProject = undefined ; + +/** + @summary Current Project (Custom React Hook). + @return {string} the current project identifier, or `undefined`. + */ +export function useProject() +{ + Dome.useUpdate(PROJECT); +} + +/** + @summary Update Current Project. + @param {string} project - the project identifier + @description + Make all states switching to their projectified value. + Emits `PROJECT`. + */ +export function setProject(project) +{ + currentProject = project ; + Dome.emit(PROJECT); +} + +/** + @summary Clear Project. + @param {Module} module - the Frama-C module + @param {string} [project] - the project identifier, defaults to current + @description + Remove all projectified values for the specified project + Emits `PROJECT`. + */ +export function clearProject(project) +{ + const theProject = project || currentProject ; + _.unset( globalStates , ['states',theProject] ); + Dome.emit(PROJECT); +} + +// -------------------------------------------------------------------------- +// --- Projectified State +// -------------------------------------------------------------------------- + +var globalStates = {} ; + +/** + @summary Projectified State (Custom React Hook). + @param {string} id - the state identifier (mandatory) + @param {string} [project] - the project identifier, defaults to current + @return {array} `[state,setState]` for the specified project + @description + Returns a getter and a setter for the specified state + in the specified or current project. + The initial value of states is always `undefined`. + + Each state is associated to a specific event `frama-c-state.<id>` which is + is used to notify updates. The hook also updates on `PROJECT` notifications. + */ +export function useState(id,project) +{ + const theEvent = STATE + id ; + Dome.useUpdate(PROJECT,theEvent); + const theProject = project || currentProject ; + if (!theProject) return NONE; + const thePath = ['states',theProject,id] ; + const theValue = _.get( globalStates, thePath ); + const setValue = (v) => { + Dome.emit(theEvent,v); + _.set( globalStates, thePath, v ); + }; + return [ theValue, setValue ]; +} + +// -------------------------------------------------------------------------- + +export default { useProject, setProject, clearProject, useState, PROJECT }; + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/main/index.js b/Ivette/src/main/index.js new file mode 100644 index 0000000000000000000000000000000000000000..2624543a9daad843d4d432821eee867a08b836ae --- /dev/null +++ b/Ivette/src/main/index.js @@ -0,0 +1,19 @@ +// -------------------------------------------------------------------------- +// --- Electron main-process entry-point for Dome. +// -------------------------------------------------------------------------- + +/* + Template of ./src/main/index.js + Imported from $(DOME)/template/main.js + + The call to Dome.start() will initialize the Dome application + and create the main window that will run the renderer process + from `src/renderer/index.js`. + + You may add your own code to be run in the Electron main-process + before or after the call to `Dome.start()`. +*/ + +import Dome from 'dome' ; +Dome.setName('Ivette'); +Dome.start(); diff --git a/Ivette/src/renderer/Application.js b/Ivette/src/renderer/Application.js new file mode 100644 index 0000000000000000000000000000000000000000..8129a62e076ad4affd2af6b508112668c9ada69e --- /dev/null +++ b/Ivette/src/renderer/Application.js @@ -0,0 +1,63 @@ +// -------------------------------------------------------------------------- +// --- Main React Component rendered by './index.js' +// -------------------------------------------------------------------------- + +import React from 'react' ; +import Dome from 'dome' ; +import { Catch } from 'dome/errors' ; +import { Vfill } from 'dome/layout/boxes' ; +import { Splitter } from 'dome/layout/splitters' ; +import Toolbar from 'dome/layout/toolbars' ; +import Sidebar from 'dome/layout/sidebars' ; + +import './style.css' ; +import 'dome/misc/exports' ; + +import { LabView, View, Group, Component } from 'frama-c/labviews' ; + +// -------------------------------------------------------------------------- +// --- Main View +// -------------------------------------------------------------------------- + +export default (function() { + + const [sidebar,flipSidebar] = Dome.useSwitch('frama-c.sidebar.unfold',false); + const [viewbar,flipViewbar] = Dome.useSwitch('frama-c.viewbar.unfold',false); + + return ( + <Vfill> + <Toolbar.ToolBar> + <Toolbar.Button + icon='SIDEBAR' title='Show/Hide side bar' + selected={sidebar} + onClick={flipSidebar} + /> + <Toolbar.Filler/> + <Toolbar.Button + icon='ITEMS.GRID' + title='Customize Main View' + selected={viewbar} + onClick={flipViewbar}/> + </Toolbar.ToolBar> + <Splitter dir='LEFT' settings='frame-c.sidebar.position' unfold={sidebar}> + <Sidebar.SideBar> + <div>(Empty)</div> + </Sidebar.SideBar> + <LabView + customize={viewbar} + settings='frama-c.labview' + > + <View id='default' label='Dashboard' defaultView /> + <Component id='dashboard' label='Dashboard'/> + <Group id='plugins' label='Plugins'> + <Component id='plugins.eva' label='Frama-C / EVA' /> + <Component id='plugins.wp' label='Frama-C / WP' /> + </Group> + </LabView> + </Splitter> + </Vfill> + ); + +}); + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/renderer/Console.js b/Ivette/src/renderer/Console.js new file mode 100644 index 0000000000000000000000000000000000000000..cd542dd70a1d7284a121cc9039f3516e609d266f --- /dev/null +++ b/Ivette/src/renderer/Console.js @@ -0,0 +1,31 @@ +// -------------------------------------------------------------------------- +// --- Console +// -------------------------------------------------------------------------- + +import React from 'react' ; +import Dome from 'dome' ; +import { Buffer } from 'dome/text/buffers' ; +import { Text } from 'dome/text/editors' ; +import 'codemirror/theme/ambiance.css' ; + +const buffer = new Buffer( { maxlines: 1024 } ); + +{ + Dome.on('refresh',() => buffer.setFocused(false)); + Dome.on('console',(msg) => { buffer.append(msg); buffer.scroll(); } ); + buffer.log('Welcome to Ivette !'); +} + +function Console(props) { + return ( + <Text buffer={buffer} + mode='text' + theme="ambiance" + readOnly="nocursor" /> + ); +} + +Console.log = (...args) => buffer.log(...args); +Console.clear = () => buffer.clear(); + +export default Console ; diff --git a/Ivette/src/renderer/Preferences.js b/Ivette/src/renderer/Preferences.js new file mode 100644 index 0000000000000000000000000000000000000000..542d1d7c97a42463aa3f0f6f528e1262b58a4e07 --- /dev/null +++ b/Ivette/src/renderer/Preferences.js @@ -0,0 +1,20 @@ +// -------------------------------------------------------------------------- +// --- Main React Component rendered by './index.js' +// -------------------------------------------------------------------------- + +/* + Template from $(DOME)/template/Settings.js + + This module shall export a React Component that + will be rendered (with empty props and children) + in the settings window of your application. + +*/ + +import React from 'react' ; + +export default (() => ( + <h1 className='dome-text-title' style={{margin: 24}}> + Settings (none) + </h1> +)); diff --git a/Ivette/src/renderer/index.js b/Ivette/src/renderer/index.js new file mode 100644 index 0000000000000000000000000000000000000000..1544ac9e11373febc48161e9672b71456c6819f6 --- /dev/null +++ b/Ivette/src/renderer/index.js @@ -0,0 +1,41 @@ +// -------------------------------------------------------------------------- +// --- Electron renderer-process entry-point for Dome. +// -------------------------------------------------------------------------- + +/* + Template of ./src/renderer/index.js + Imported from $(DOME)/template/renderer.js + + You can modify this template and add your own code before or + after rendering the main components. + + However, please note that React hot-reloading is fragile. + Component that are not imported by <Application/> or <Preferences/> + may suffer from well known limitations of hot-reloading and + may lead to state losses or complete application reloads. +*/ + +// Enable live-editing in React: +import 'react-hot-loader/patch' ; +import React from 'react' ; +import Dome from 'dome' ; + +// You can change the name of the main components, +// provided you define the makefile variable +// `DOME_CUSTOM_ENTRIES` to prevent files 'Application.js' and 'Preferences.js' +// from being generated by the template makefile. + +import Application from './Application' ; +import Preferences from './Preferences' ; + +// Define the application main components for each window: +Dome.setApplicationWindow(Application); +Dome.setPreferencesWindow(Preferences); + +// Mark the main application reloadable and enable live updates: +module.hot && Dome.isApplicationWindow() && + module.hot.accept('./Application',() => Dome.setApplicationWindow(Application)); +module.hot && Dome.isPreferencesWindow() && + module.hot.accept('./Preferences',() => Dome.setPreferencesWindow(Preferences)); + +// -------------------------------------------------------------------------- diff --git a/Ivette/src/renderer/style.css b/Ivette/src/renderer/style.css new file mode 100644 index 0000000000000000000000000000000000000000..b7459ca55318f240befe30cbd06e227daec4c366 --- /dev/null +++ b/Ivette/src/renderer/style.css @@ -0,0 +1,7 @@ +/* -------------------------------------------------------------------------- */ +/* --- Frama-C Styling --- */ +/* -------------------------------------------------------------------------- */ + +/* (Empty) */ + +/* -------------------------------------------------------------------------- */ diff --git a/Ivette/webpack.main.js b/Ivette/webpack.main.js new file mode 100644 index 0000000000000000000000000000000000000000..608d29372314dcb2e5cd7406dac737c35371daf6 --- /dev/null +++ b/Ivette/webpack.main.js @@ -0,0 +1,38 @@ +// -------------------------------------------------------------------------- +// --- Webpack extension for electron main-process +// -------------------------------------------------------------------------- + +/* + Template of ./webpack.main.js from $(DOME)/template/webpack.main.js + + This webpack definitions will be merged into electron-webpack + ones thanks to electron-webpack.json configuration file. + + You may extend it with your own additions. +*/ + +const path = require('path'); +const DOME = process.env.DOME || path.resolve(__dirname , 'dome'); +const ENV = process.env.DOME_ENV ; + +// Do not use electron-devtools-installer in production mode +function domeDevtools() { + switch(ENV) { + case 'dev': + return 'electron-devtools-installer'; + default: + return path.resolve( DOME , 'src/misc/devtools.js' ); + } +} + +module.exports = { + resolve: { + alias: { + 'dome$': path.resolve( DOME , 'src/main/dome.js' ), + 'dome/system$': path.resolve( DOME , 'src/misc/system.js' ), + 'dome/devtools': domeDevtools() + } + } +} ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/webpack.plugin.js b/Ivette/webpack.plugin.js new file mode 100644 index 0000000000000000000000000000000000000000..f60bdbf7ab8cda15ad9dcba2c747a5a3d82e57ed --- /dev/null +++ b/Ivette/webpack.plugin.js @@ -0,0 +1,41 @@ +// -------------------------------------------------------------------------- +// --- Webpack configuration for packing plugins +// -------------------------------------------------------------------------- + +/* + Template of ./webpack.plugin.js from $(DOME)/template/webpack.plugin.js + + This webpack definitions will be used to make plugin bundles. + + You may extend it with your own additions. +*/ + +const path = require('path'); +const DOME = process.env.DOME || path.resolve( __dirname , 'dome' ); +const PLUGIN = process.env.DOME_PLUGIN ; +const ENTRY = path.resolve( __dirname , 'src/plugins' , PLUGIN ); +const DIST = path.resolve( __dirname , 'dist/plugins' , PLUGIN ); + +module.exports = { + entry: ENTRY, + output: { + path: DIST, + filename: 'bundle.js', + libraryTarget: 'commonjs2' + }, + module: { + rules: [ + { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, + { test: /\.js$/, use: [ 'babel-loader' ], exclude: /(node_modules)/ } + ] + }, + externals: [ + 'lodash', + 'react', + /^dome\/.+$/, + /^@plugins\/.+$/, + /^@\/.+$/ + ] +}; + +// -------------------------------------------------------------------------- diff --git a/Ivette/webpack.renderer.js b/Ivette/webpack.renderer.js new file mode 100644 index 0000000000000000000000000000000000000000..523eaa554cde3df6800a34a768dc9eb3948abbdf --- /dev/null +++ b/Ivette/webpack.renderer.js @@ -0,0 +1,38 @@ +// -------------------------------------------------------------------------- +// --- Webpack extension for electron main-process +// -------------------------------------------------------------------------- + +/* + Template from $(DOME)/template/webpack.main.js + + This webpack definitions will be merged into electron-webpack + ones thanks to electron-webpack.json configuration file. + + You may extend it with your own additions. +*/ + +const path = require('path'); +const DOME = process.env.DOME || path.resolve( __dirname , 'dome' ); + +// -------------------------------------------------------------------------- + +module.exports = { + module: { + rules: [ + { test: /\.css$/, use: [ 'css-loader' ] } + ] + }, + resolve: { + alias: { + 'frama-c': path.resolve( __dirname , 'src/frama-c' ), + '@plugins': path.resolve( __dirname , 'src/plugins' ), + 'dome/misc': path.resolve( DOME , 'src/misc' ), + 'dome/system': path.resolve( DOME , 'src/misc/system.js' ), + 'dome$': path.resolve( DOME , 'src/renderer/dome.js' ), + 'dome': path.resolve( DOME , 'src/renderer' ), + 'react-dom': '@hot-loader/react-dom' + } + } +} ; + +// -------------------------------------------------------------------------- diff --git a/Ivette/yarn.lock b/Ivette/yarn.lock new file mode 100644 index 0000000000000000000000000000000000000000..1df871031514506d4b97c672d4df859da2fdc497 --- /dev/null +++ b/Ivette/yarn.lock @@ -0,0 +1,8215 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"7zip-bin@~5.0.3": + version "5.0.3" + resolved "https://registry.yarnpkg.com/7zip-bin/-/7zip-bin-5.0.3.tgz#bc5b5532ecafd923a61f2fb097e3b108c0106a3f" + integrity sha512-GLyWIFBbGvpKPGo55JyRZAo4lVbnBiD52cKlw/0Vt+wnmKvWJkpZvsjVoaIolyBXDeAQKSicRtqFNPem9w0WYA== + +"7zip@0.0.6": + version "0.0.6" + resolved "https://registry.yarnpkg.com/7zip/-/7zip-0.0.6.tgz#9cafb171af82329490353b4816f03347aa150a30" + integrity sha1-nK+xca+CMpSQNTtIFvAzR6oVCjA= + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" + integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== + dependencies: + "@babel/highlight" "^7.0.0" + +"@babel/core@^7", "@babel/core@^7.5.0": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.7.2.tgz#ea5b99693bcfc058116f42fa1dd54da412b29d91" + integrity sha512-eeD7VEZKfhK1KUXGiyPFettgF3m513f8FoBSWiQ1xTvl1RAopLs42Wp9+Ze911I6H0N9lNqJMDgoZT7gHsipeQ== + dependencies: + "@babel/code-frame" "^7.5.5" + "@babel/generator" "^7.7.2" + "@babel/helpers" "^7.7.0" + "@babel/parser" "^7.7.2" + "@babel/template" "^7.7.0" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.7.2" + convert-source-map "^1.7.0" + debug "^4.1.0" + json5 "^2.1.0" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.7.2": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.2.tgz#2f4852d04131a5e17ea4f6645488b5da66ebf3af" + integrity sha512-WthSArvAjYLz4TcbKOi88me+KmDJdKSlfwwN8CnUYn9jBkzhq0ZEPuBfkAWIvjJ3AdEV1Cf/+eSQTnp3IDJKlQ== + dependencies: + "@babel/types" "^7.7.2" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + +"@babel/generator@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.4.tgz#db651e2840ca9aa66f327dcec1dc5f5fa9611369" + integrity sha512-m5qo2WgdOJeyYngKImbkyQrnUN1mPceaG5BV+G0E3gWsa4l/jCSryWJdM2x8OuGAOyh+3d5pVYfZWCiNFtynxg== + dependencies: + "@babel/types" "^7.7.4" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.0.0", "@babel/helper-annotate-as-pure@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.0.tgz#efc54032d43891fe267679e63f6860aa7dbf4a5e" + integrity sha512-k50CQxMlYTYo+GGyUGFwpxKVtxVJi9yh61sXZji3zYHccK9RYliZGSTOgci85T+r+0VFN2nWbGM04PIqwfrpMg== + dependencies: + "@babel/types" "^7.7.0" + +"@babel/helper-annotate-as-pure@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.4.tgz#bb3faf1e74b74bd547e867e48f551fa6b098b6ce" + integrity sha512-2BQmQgECKzYKFPpiycoF9tlb5HA4lrVyAmLLVK177EcQAqjVLciUb2/R+n1boQ9y5ENV3uz2ZqiNw7QMBBw1Og== + dependencies: + "@babel/types" "^7.7.4" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.7.0.tgz#32dd9551d6ed3a5fc2edc50d6912852aa18274d9" + integrity sha512-Cd8r8zs4RKDwMG/92lpZcnn5WPQ3LAMQbCw42oqUh4s7vsSN5ANUZjMel0OOnxDLq57hoDDbai+ryygYfCTOsw== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.7.0" + "@babel/types" "^7.7.0" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.7.4.tgz#5f73f2b28580e224b5b9bd03146a4015d6217f5f" + integrity sha512-Biq/d/WtvfftWZ9Uf39hbPBYDUo986m5Bb4zhkeYDGUllF43D+nUe5M6Vuo6/8JDK/0YX/uBdeoQpyaNhNugZQ== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.7.4" + "@babel/types" "^7.7.4" + +"@babel/helper-builder-react-jsx@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.7.4.tgz#da188d247508b65375b2c30cf59de187be6b0c66" + integrity sha512-kvbfHJNN9dg4rkEM4xn1s8d1/h6TYNvajy9L1wx4qLn9HFg0IkTsQi4rfBe92nxrPUFcMsHoMV+8rU7MJb3fCA== + dependencies: + "@babel/types" "^7.7.4" + esutils "^2.0.0" + +"@babel/helper-call-delegate@^7.4.4": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.7.0.tgz#df8942452c2c1a217335ca7e393b9afc67f668dc" + integrity sha512-Su0Mdq7uSSWGZayGMMQ+z6lnL00mMCnGAbO/R0ZO9odIdB/WNU/VfQKqMQU0fdIsxQYbRjDM4BixIa93SQIpvw== + dependencies: + "@babel/helper-hoist-variables" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + +"@babel/helper-call-delegate@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.7.4.tgz#621b83e596722b50c0066f9dc37d3232e461b801" + integrity sha512-8JH9/B7J7tCYJ2PpWVpw9JhPuEVHztagNVuQAFBVFYluRMlpG7F1CgKEgGeL6KFqcsIa92ZYVj6DSc0XwmN1ZA== + dependencies: + "@babel/helper-hoist-variables" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" + +"@babel/helper-create-regexp-features-plugin@^7.7.0": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.2.tgz#6f20443778c8fce2af2ff4206284afc0ced65db6" + integrity sha512-pAil/ZixjTlrzNpjx+l/C/wJk002Wo7XbbZ8oujH/AoJ3Juv0iN/UTcPUHXKMFLqsfS0Hy6Aow8M31brUYBlQQ== + dependencies: + "@babel/helper-regex" "^7.4.4" + regexpu-core "^4.6.0" + +"@babel/helper-create-regexp-features-plugin@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.4.tgz#6d5762359fd34f4da1500e4cff9955b5299aaf59" + integrity sha512-Mt+jBKaxL0zfOIWrfQpnfYCN7/rS6GKx6CCCfuoqVVd+17R8zNDlzVYmIi9qyb2wOk002NsmSTDymkIygDUH7A== + dependencies: + "@babel/helper-regex" "^7.4.4" + regexpu-core "^4.6.0" + +"@babel/helper-define-map@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.7.0.tgz#60b0e9fd60def9de5054c38afde8c8ee409c7529" + integrity sha512-kPKWPb0dMpZi+ov1hJiwse9dWweZsz3V9rP4KdytnX1E7z3cTNmFGglwklzFPuqIcHLIY3bgKSs4vkwXXdflQA== + dependencies: + "@babel/helper-function-name" "^7.7.0" + "@babel/types" "^7.7.0" + lodash "^4.17.13" + +"@babel/helper-define-map@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.7.4.tgz#2841bf92eb8bd9c906851546fe6b9d45e162f176" + integrity sha512-v5LorqOa0nVQUvAUTUF3KPastvUt/HzByXNamKQ6RdJRTV7j8rLL+WB5C/MzzWAwOomxDhYFb1wLLxHqox86lg== + dependencies: + "@babel/helper-function-name" "^7.7.4" + "@babel/types" "^7.7.4" + lodash "^4.17.13" + +"@babel/helper-explode-assignable-expression@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.7.0.tgz#db2a6705555ae1f9f33b4b8212a546bc7f9dc3ef" + integrity sha512-CDs26w2shdD1urNUAji2RJXyBFCaR+iBEGnFz3l7maizMkQe3saVw9WtjG1tz8CwbjvlFnaSLVhgnu1SWaherg== + dependencies: + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + +"@babel/helper-explode-assignable-expression@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.7.4.tgz#fa700878e008d85dc51ba43e9fb835cddfe05c84" + integrity sha512-2/SicuFrNSXsZNBxe5UGdLr+HZg+raWBLE9vC98bdYOKX/U6PY0mdGlYUJdtTDPSU0Lw0PNbKKDpwYHJLn2jLg== + dependencies: + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" + +"@babel/helper-function-name@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.7.0.tgz#44a5ad151cfff8ed2599c91682dda2ec2c8430a3" + integrity sha512-tDsJgMUAP00Ugv8O2aGEua5I2apkaQO7lBGUq1ocwN3G23JE5Dcq0uh3GvFTChPa4b40AWiAsLvCZOA2rdnQ7Q== + dependencies: + "@babel/helper-get-function-arity" "^7.7.0" + "@babel/template" "^7.7.0" + "@babel/types" "^7.7.0" + +"@babel/helper-function-name@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz#ab6e041e7135d436d8f0a3eca15de5b67a341a2e" + integrity sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ== + dependencies: + "@babel/helper-get-function-arity" "^7.7.4" + "@babel/template" "^7.7.4" + "@babel/types" "^7.7.4" + +"@babel/helper-get-function-arity@^7.0.0", "@babel/helper-get-function-arity@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.0.tgz#c604886bc97287a1d1398092bc666bc3d7d7aa2d" + integrity sha512-tLdojOTz4vWcEnHWHCuPN5P85JLZWbm5Fx5ZsMEMPhF3Uoe3O7awrbM2nQ04bDOUToH/2tH/ezKEOR8zEYzqyw== + dependencies: + "@babel/types" "^7.7.0" + +"@babel/helper-get-function-arity@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz#cb46348d2f8808e632f0ab048172130e636005f0" + integrity sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA== + dependencies: + "@babel/types" "^7.7.4" + +"@babel/helper-hoist-variables@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.0.tgz#b4552e4cfe5577d7de7b183e193e84e4ec538c81" + integrity sha512-LUe/92NqsDAkJjjCEWkNe+/PcpnisvnqdlRe19FahVapa4jndeuJ+FBiTX1rcAKWKcJGE+C3Q3tuEuxkSmCEiQ== + dependencies: + "@babel/types" "^7.7.0" + +"@babel/helper-hoist-variables@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.4.tgz#612384e3d823fdfaaf9fce31550fe5d4db0f3d12" + integrity sha512-wQC4xyvc1Jo/FnLirL6CEgPgPCa8M74tOdjWpRhQYapz5JC7u3NYU1zCVoVAGCE3EaIP9T1A3iW0WLJ+reZlpQ== + dependencies: + "@babel/types" "^7.7.4" + +"@babel/helper-member-expression-to-functions@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.0.tgz#472b93003a57071f95a541ea6c2b098398bcad8a" + integrity sha512-QaCZLO2RtBcmvO/ekOLp8p7R5X2JriKRizeDpm5ChATAFWrrYDcDxPuCIBXKyBjY+i1vYSdcUTMIb8psfxHDPA== + dependencies: + "@babel/types" "^7.7.0" + +"@babel/helper-member-expression-to-functions@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz#356438e2569df7321a8326644d4b790d2122cb74" + integrity sha512-9KcA1X2E3OjXl/ykfMMInBK+uVdfIVakVe7W7Lg3wfXUNyS3Q1HWLFRwZIjhqiCGbslummPDnmb7vIekS0C1vw== + dependencies: + "@babel/types" "^7.7.4" + +"@babel/helper-module-imports@7.0.0-beta.35": + version "7.0.0-beta.35" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.35.tgz#308e350e731752cdb4d0f058df1d704925c64e0a" + integrity sha512-vaC1KyIZSuyWb3Lj277fX0pxivyHwuDU4xZsofqgYAbkDxNieMg2vuhzP5AgMweMY7fCQUMTi+BgPqTLjkxXFg== + dependencies: + "@babel/types" "7.0.0-beta.35" + lodash "^4.2.0" + +"@babel/helper-module-imports@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.7.0.tgz#99c095889466e5f7b6d66d98dffc58baaf42654d" + integrity sha512-Dv3hLKIC1jyfTkClvyEkYP2OlkzNvWs5+Q8WgPbxM5LMeorons7iPP91JM+DU7tRbhqA1ZeooPaMFvQrn23RHw== + dependencies: + "@babel/types" "^7.7.0" + +"@babel/helper-module-imports@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz#e5a92529f8888bf319a6376abfbd1cebc491ad91" + integrity sha512-dGcrX6K9l8258WFjyDLJwuVKxR4XZfU0/vTUgOQYWEnRD8mgr+p4d6fCUMq/ys0h4CCt/S5JhbvtyErjWouAUQ== + dependencies: + "@babel/types" "^7.7.4" + +"@babel/helper-module-transforms@^7.1.0", "@babel/helper-module-transforms@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.7.0.tgz#154a69f0c5b8fd4d39e49750ff7ac4faa3f36786" + integrity sha512-rXEefBuheUYQyX4WjV19tuknrJFwyKw0HgzRwbkyTbB+Dshlq7eqkWbyjzToLrMZk/5wKVKdWFluiAsVkHXvuQ== + dependencies: + "@babel/helper-module-imports" "^7.7.0" + "@babel/helper-simple-access" "^7.7.0" + "@babel/helper-split-export-declaration" "^7.7.0" + "@babel/template" "^7.7.0" + "@babel/types" "^7.7.0" + lodash "^4.17.13" + +"@babel/helper-module-transforms@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.7.4.tgz#8d7cdb1e1f8ea3d8c38b067345924ac4f8e0879a" + integrity sha512-ehGBu4mXrhs0FxAqN8tWkzF8GSIGAiEumu4ONZ/hD9M88uHcD+Yu2ttKfOCgwzoesJOJrtQh7trI5YPbRtMmnA== + dependencies: + "@babel/helper-module-imports" "^7.7.4" + "@babel/helper-simple-access" "^7.7.4" + "@babel/helper-split-export-declaration" "^7.7.4" + "@babel/template" "^7.7.4" + "@babel/types" "^7.7.4" + lodash "^4.17.13" + +"@babel/helper-module-transforms@^7.7.5": + version "7.7.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.7.5.tgz#d044da7ffd91ec967db25cd6748f704b6b244835" + integrity sha512-A7pSxyJf1gN5qXVcidwLWydjftUN878VkalhXX5iQDuGyiGK3sOrrKKHF4/A4fwHtnsotv/NipwAeLzY4KQPvw== + dependencies: + "@babel/helper-module-imports" "^7.7.4" + "@babel/helper-simple-access" "^7.7.4" + "@babel/helper-split-export-declaration" "^7.7.4" + "@babel/template" "^7.7.4" + "@babel/types" "^7.7.4" + lodash "^4.17.13" + +"@babel/helper-optimise-call-expression@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.0.tgz#4f66a216116a66164135dc618c5d8b7a959f9365" + integrity sha512-48TeqmbazjNU/65niiiJIJRc5JozB8acui1OS7bSd6PgxfuovWsvjfWSzlgx+gPFdVveNzUdpdIg5l56Pl5jqg== + dependencies: + "@babel/types" "^7.7.0" + +"@babel/helper-optimise-call-expression@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz#034af31370d2995242aa4df402c3b7794b2dcdf2" + integrity sha512-VB7gWZ2fDkSuqW6b1AKXkJWO5NyNI3bFL/kK79/30moK57blr6NbH8xcl2XcKCwOmJosftWunZqfO84IGq3ZZg== + dependencies: + "@babel/types" "^7.7.4" + +"@babel/helper-plugin-utils@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" + integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== + +"@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.5.5.tgz#0aa6824f7100a2e0e89c1527c23936c152cab351" + integrity sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw== + dependencies: + lodash "^4.17.13" + +"@babel/helper-remap-async-to-generator@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.0.tgz#4d69ec653e8bff5bce62f5d33fc1508f223c75a7" + integrity sha512-pHx7RN8X0UNHPB/fnuDnRXVZ316ZigkO8y8D835JlZ2SSdFKb6yH9MIYRU4fy/KPe5sPHDFOPvf8QLdbAGGiyw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.7.0" + "@babel/helper-wrap-function" "^7.7.0" + "@babel/template" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + +"@babel/helper-remap-async-to-generator@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.4.tgz#c68c2407350d9af0e061ed6726afb4fff16d0234" + integrity sha512-Sk4xmtVdM9sA/jCI80f+KS+Md+ZHIpjuqmYPk1M7F/upHou5e4ReYmExAiu6PVe65BhJPZA2CY9x9k4BqE5klw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.7.4" + "@babel/helper-wrap-function" "^7.7.4" + "@babel/template" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" + +"@babel/helper-replace-supers@^7.5.5", "@babel/helper-replace-supers@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.7.0.tgz#d5365c8667fe7cbd13b8ddddceb9bd7f2b387512" + integrity sha512-5ALYEul5V8xNdxEeWvRsBzLMxQksT7MaStpxjJf9KsnLxpAKBtfw5NeMKZJSYDa0lKdOcy0g+JT/f5mPSulUgg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.7.0" + "@babel/helper-optimise-call-expression" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + +"@babel/helper-replace-supers@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz#3c881a6a6a7571275a72d82e6107126ec9e2cdd2" + integrity sha512-pP0tfgg9hsZWo5ZboYGuBn/bbYT/hdLPVSS4NMmiRJdwWhP0IznPwN9AE1JwyGsjSPLC364I0Qh5p+EPkGPNpg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.7.4" + "@babel/helper-optimise-call-expression" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" + +"@babel/helper-simple-access@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.7.0.tgz#97a8b6c52105d76031b86237dc1852b44837243d" + integrity sha512-AJ7IZD7Eem3zZRuj5JtzFAptBw7pMlS3y8Qv09vaBWoFsle0d1kAn5Wq6Q9MyBXITPOKnxwkZKoAm4bopmv26g== + dependencies: + "@babel/template" "^7.7.0" + "@babel/types" "^7.7.0" + +"@babel/helper-simple-access@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.7.4.tgz#a169a0adb1b5f418cfc19f22586b2ebf58a9a294" + integrity sha512-zK7THeEXfan7UlWsG2A6CI/L9jVnI5+xxKZOdej39Y0YtDYKx9raHk5F2EtK9K8DHRTihYwg20ADt9S36GR78A== + dependencies: + "@babel/template" "^7.7.4" + "@babel/types" "^7.7.4" + +"@babel/helper-split-export-declaration@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.0.tgz#1365e74ea6c614deeb56ebffabd71006a0eb2300" + integrity sha512-HgYSI8rH08neWlAH3CcdkFg9qX9YsZysZI5GD8LjhQib/mM0jGOZOVkoUiiV2Hu978fRtjtsGsW6w0pKHUWtqA== + dependencies: + "@babel/types" "^7.7.0" + +"@babel/helper-split-export-declaration@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz#57292af60443c4a3622cf74040ddc28e68336fd8" + integrity sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug== + dependencies: + "@babel/types" "^7.7.4" + +"@babel/helper-wrap-function@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.7.0.tgz#15af3d3e98f8417a60554acbb6c14e75e0b33b74" + integrity sha512-sd4QjeMgQqzshSjecZjOp8uKfUtnpmCyQhKQrVJBBgeHAB/0FPi33h3AbVlVp07qQtMD4QgYSzaMI7VwncNK/w== + dependencies: + "@babel/helper-function-name" "^7.7.0" + "@babel/template" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + +"@babel/helper-wrap-function@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz#37ab7fed5150e22d9d7266e830072c0cdd8baace" + integrity sha512-VsfzZt6wmsocOaVU0OokwrIytHND55yvyT4BPB9AIIgwr8+x7617hetdJTsuGwygN5RC6mxA9EJztTjuwm2ofg== + dependencies: + "@babel/helper-function-name" "^7.7.4" + "@babel/template" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" + +"@babel/helpers@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.7.0.tgz#359bb5ac3b4726f7c1fde0ec75f64b3f4275d60b" + integrity sha512-VnNwL4YOhbejHb7x/b5F39Zdg5vIQpUUNzJwx0ww1EcVRt41bbGRZWhAURrfY32T5zTT3qwNOQFWpn+P0i0a2g== + dependencies: + "@babel/template" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + +"@babel/highlight@^7.0.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" + integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ== + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.4.4": + version "7.7.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.3.tgz#5fad457c2529de476a248f75b0f090b3060af043" + integrity sha512-bqv+iCo9i+uLVbI0ILzKkvMorqxouI+GbV13ivcARXn9NNEabi2IEz912IgNpT/60BNXac5dgcfjb94NjsF33A== + +"@babel/parser@^7.7.0", "@babel/parser@^7.7.2": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.2.tgz#ea8334dc77416bfd9473eb470fd00d8245b3943b" + integrity sha512-DDaR5e0g4ZTb9aP7cpSZLkACEBdoLGwJDWgHtBhrGX7Q1RjhdoMOfexICj5cqTAtpowjGQWfcvfnQG7G2kAB5w== + +"@babel/parser@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.4.tgz#75ab2d7110c2cf2fa949959afb05fa346d2231bb" + integrity sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g== + +"@babel/plugin-proposal-async-generator-functions@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.0.tgz#83ef2d6044496b4c15d8b4904e2219e6dccc6971" + integrity sha512-ot/EZVvf3mXtZq0Pd0+tSOfGWMizqmOohXmNZg6LNFjHOV+wOPv7BvVYh8oPR8LhpIP3ye8nNooKL50YRWxpYA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.7.0" + "@babel/plugin-syntax-async-generators" "^7.2.0" + +"@babel/plugin-proposal-async-generator-functions@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.4.tgz#0351c5ac0a9e927845fffd5b82af476947b7ce6d" + integrity sha512-1ypyZvGRXriY/QP668+s8sFr2mqinhkRDMPSQLNghCQE+GAkFtp+wkHVvg2+Hdki8gwP+NFzJBJ/N1BfzCCDEw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.7.4" + "@babel/plugin-syntax-async-generators" "^7.7.4" + +"@babel/plugin-proposal-dynamic-import@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.7.0.tgz#dc02a8bad8d653fb59daf085516fa416edd2aa7f" + integrity sha512-7poL3Xi+QFPC7sGAzEIbXUyYzGJwbc2+gSD0AkiC5k52kH2cqHdqxm5hNFfLW3cRSTcx9bN0Fl7/6zWcLLnKAQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-dynamic-import" "^7.2.0" + +"@babel/plugin-proposal-dynamic-import@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.7.4.tgz#dde64a7f127691758cbfed6cf70de0fa5879d52d" + integrity sha512-StH+nGAdO6qDB1l8sZ5UBV8AC3F2VW2I8Vfld73TMKyptMU9DY5YsJAS8U81+vEtxcH3Y/La0wG0btDrhpnhjQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-dynamic-import" "^7.7.4" + +"@babel/plugin-proposal-json-strings@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317" + integrity sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-json-strings" "^7.2.0" + +"@babel/plugin-proposal-json-strings@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.7.4.tgz#7700a6bfda771d8dc81973249eac416c6b4c697d" + integrity sha512-wQvt3akcBTfLU/wYoqm/ws7YOAQKu8EVJEvHip/mzkNtjaclQoCCIqKXFP5/eyfnfbQCDV3OLRIK3mIVyXuZlw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-json-strings" "^7.7.4" + +"@babel/plugin-proposal-object-rest-spread@^7.6.2": + version "7.6.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.6.2.tgz#8ffccc8f3a6545e9f78988b6bf4fe881b88e8096" + integrity sha512-LDBXlmADCsMZV1Y9OQwMc0MyGZ8Ta/zlD9N67BfQT8uYwkRswiu2hU6nJKrjrt/58aH/vqfQlR/9yId/7A2gWw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + +"@babel/plugin-proposal-object-rest-spread@^7.7.7": + version "7.7.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.7.7.tgz#9f27075004ab99be08c5c1bd653a2985813cb370" + integrity sha512-3qp9I8lelgzNedI3hrhkvhaEYree6+WHnyA/q4Dza9z7iEIs1eyhWyJnetk3jJ69RT0AT4G0UhEGwyGFJ7GUuQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.7.4" + +"@babel/plugin-proposal-optional-catch-binding@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz#135d81edb68a081e55e56ec48541ece8065c38f5" + integrity sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" + +"@babel/plugin-proposal-optional-catch-binding@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.7.4.tgz#ec21e8aeb09ec6711bc0a39ca49520abee1de379" + integrity sha512-DyM7U2bnsQerCQ+sejcTNZh8KQEUuC3ufzdnVnSiUv/qoGJp2Z3hanKL18KDhsBT5Wj6a7CMT5mdyCNJsEaA9w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.7.4" + +"@babel/plugin-proposal-unicode-property-regex@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.0.tgz#549fe1717a1bd0a2a7e63163841cb37e78179d5d" + integrity sha512-mk34H+hp7kRBWJOOAR0ZMGCydgKMD4iN9TpDRp3IIcbunltxEY89XSimc6WbtSLCDrwcdy/EEw7h5CFCzxTchw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-proposal-unicode-property-regex@^7.7.7": + version "7.7.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.7.tgz#433fa9dac64f953c12578b29633f456b68831c4e" + integrity sha512-80PbkKyORBUVm1fbTLrHpYdJxMThzM1UqFGh0ALEhO9TYbG86Ah9zQYAB/84axz2vcxefDLdZwWwZNlYARlu9w== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-async-generators@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f" + integrity sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-async-generators@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.7.4.tgz#331aaf310a10c80c44a66b238b6e49132bd3c889" + integrity sha512-Li4+EjSpBgxcsmeEF8IFcfV/+yJGxHXDirDkEoyFjumuwbmfCVHUt0HuowD/iGM7OhIRyXJH9YXxqiH6N815+g== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-dynamic-import@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz#69c159ffaf4998122161ad8ebc5e6d1f55df8612" + integrity sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-dynamic-import@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.7.4.tgz#29ca3b4415abfe4a5ec381e903862ad1a54c3aec" + integrity sha512-jHQW0vbRGvwQNgyVxwDh4yuXu4bH1f5/EICJLAhl1SblLs2CDhrsmCk+v5XLdE9wxtAFRyxx+P//Iw+a5L/tTg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-json-strings@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470" + integrity sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-json-strings@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz#86e63f7d2e22f9e27129ac4e83ea989a382e86cc" + integrity sha512-QpGupahTQW1mHRXddMG5srgpHWqRLwJnJZKXTigB9RPFCCGbDGCgBeM/iC82ICXp414WeYx/tD54w7M2qRqTMg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-jsx@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.7.4.tgz#dab2b56a36fb6c3c222a1fbc71f7bf97f327a9ec" + integrity sha512-wuy6fiMe9y7HeZBWXYCGt2RGxZOj0BImZ9EyXJVnVGBKO/Br592rbR3rtIQn0eQhAk9vqaKP5n8tVqEFBQMfLg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-object-rest-spread@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" + integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-object-rest-spread@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz#47cf220d19d6d0d7b154304701f468fc1cc6ff46" + integrity sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz#a94013d6eda8908dfe6a477e7f9eda85656ecf5c" + integrity sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.7.4.tgz#a3e38f59f4b6233867b4a92dcb0ee05b2c334aa6" + integrity sha512-4ZSuzWgFxqHRE31Glu+fEr/MirNZOMYmD/0BhBWyLyOOQz/gTAl7QmWm2hX1QxEIXsr2vkdlwxIzTyiYRC4xcQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-top-level-await@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.7.0.tgz#f5699549f50bbe8d12b1843a4e82f0a37bb65f4d" + integrity sha512-hi8FUNiFIY1fnUI2n1ViB1DR0R4QeK4iHcTlW6aJkrPoTdb8Rf1EMQ6GT3f67DDkYyWgew9DFoOZ6gOoEsdzTA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-top-level-await@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.7.4.tgz#bd7d8fa7b9fee793a36e4027fd6dd1aa32f946da" + integrity sha512-wdsOw0MvkL1UIgiQ/IFr3ETcfv1xb8RMM0H9wbiDyLaJFyiDg5oZvDLCXosIXmFeIlweML5iOBXAkqddkYNizg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-arrow-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" + integrity sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-arrow-functions@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.7.4.tgz#76309bd578addd8aee3b379d809c802305a98a12" + integrity sha512-zUXy3e8jBNPiffmqkHRNDdZM2r8DWhCB7HhcoyZjiK1TxYEluLHAvQuYnTT+ARqRpabWqy/NHkO6e3MsYB5YfA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-async-to-generator@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.0.tgz#e2b84f11952cf5913fe3438b7d2585042772f492" + integrity sha512-vLI2EFLVvRBL3d8roAMqtVY0Bm9C1QzLkdS57hiKrjUBSqsQYrBsMCeOg/0KK7B0eK9V71J5mWcha9yyoI2tZw== + dependencies: + "@babel/helper-module-imports" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.7.0" + +"@babel/plugin-transform-async-to-generator@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.4.tgz#694cbeae6d613a34ef0292713fa42fb45c4470ba" + integrity sha512-zpUTZphp5nHokuy8yLlyafxCJ0rSlFoSHypTUWgpdwoDXWQcseaect7cJ8Ppk6nunOM6+5rPMkod4OYKPR5MUg== + dependencies: + "@babel/helper-module-imports" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.7.4" + +"@babel/plugin-transform-block-scoped-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190" + integrity sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-block-scoped-functions@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.7.4.tgz#d0d9d5c269c78eaea76227ace214b8d01e4d837b" + integrity sha512-kqtQzwtKcpPclHYjLK//3lH8OFsCDuDJBaFhVwf8kqdnF6MN4l618UDlcA7TfRs3FayrHj+svYnSX8MC9zmUyQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-block-scoping@^7.6.3": + version "7.6.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.3.tgz#6e854e51fbbaa84351b15d4ddafe342f3a5d542a" + integrity sha512-7hvrg75dubcO3ZI2rjYTzUrEuh1E9IyDEhhB6qfcooxhDA33xx2MasuLVgdxzcP6R/lipAC6n9ub9maNW6RKdw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + lodash "^4.17.13" + +"@babel/plugin-transform-block-scoping@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.7.4.tgz#200aad0dcd6bb80372f94d9e628ea062c58bf224" + integrity sha512-2VBe9u0G+fDt9B5OV5DQH4KBf5DoiNkwFKOz0TCvBWvdAN2rOykCTkrL+jTLxfCAm76l9Qo5OqL7HBOx2dWggg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + lodash "^4.17.13" + +"@babel/plugin-transform-classes@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.0.tgz#b411ecc1b8822d24b81e5d184f24149136eddd4a" + integrity sha512-/b3cKIZwGeUesZheU9jNYcwrEA7f/Bo4IdPmvp7oHgvks2majB5BoT5byAql44fiNQYOPzhk2w8DbgfuafkMoA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.7.0" + "@babel/helper-define-map" "^7.7.0" + "@babel/helper-function-name" "^7.7.0" + "@babel/helper-optimise-call-expression" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.7.0" + "@babel/helper-split-export-declaration" "^7.7.0" + globals "^11.1.0" + +"@babel/plugin-transform-classes@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.4.tgz#c92c14be0a1399e15df72667067a8f510c9400ec" + integrity sha512-sK1mjWat7K+buWRuImEzjNf68qrKcrddtpQo3swi9j7dUcG6y6R6+Di039QN2bD1dykeswlagupEmpOatFHHUg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.7.4" + "@babel/helper-define-map" "^7.7.4" + "@babel/helper-function-name" "^7.7.4" + "@babel/helper-optimise-call-expression" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.7.4" + "@babel/helper-split-export-declaration" "^7.7.4" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da" + integrity sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-computed-properties@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.7.4.tgz#e856c1628d3238ffe12d668eb42559f79a81910d" + integrity sha512-bSNsOsZnlpLLyQew35rl4Fma3yKWqK3ImWMSC/Nc+6nGjC9s5NFWAer1YQ899/6s9HxO2zQC1WoFNfkOqRkqRQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-destructuring@^7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.6.0.tgz#44bbe08b57f4480094d57d9ffbcd96d309075ba6" + integrity sha512-2bGIS5P1v4+sWTCnKNDZDxbGvEqi0ijeqM/YqHtVGrvG2y0ySgnEEhXErvE9dA0bnIzY9bIzdFK0jFA46ASIIQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-destructuring@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.7.4.tgz#2b713729e5054a1135097b6a67da1b6fe8789267" + integrity sha512-4jFMXI1Cu2aXbcXXl8Lr6YubCn6Oc7k9lLsu8v61TZh+1jny2BWmdtvY9zSUlLdGUvcy9DMAWyZEOqjsbeg/wA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-dotall-regex@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.7.0.tgz#c5c9ecacab3a5e0c11db6981610f0c32fd698b3b" + integrity sha512-3QQlF7hSBnSuM1hQ0pS3pmAbWLax/uGNCbPBND9y+oJ4Y776jsyujG2k0Sn2Aj2a0QwVOiOFL5QVPA7spjvzSA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-dotall-regex@^7.7.7": + version "7.7.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.7.7.tgz#3e9713f1b69f339e87fa796b097d73ded16b937b" + integrity sha512-b4in+YlTeE/QmTgrllnb3bHA0HntYvjz8O3Mcbx75UBPJA2xhb5A8nle498VhxSXJHQefjtQxpnLPehDJ4TRlg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-duplicate-keys@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz#c5dbf5106bf84cdf691222c0974c12b1df931853" + integrity sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-duplicate-keys@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.7.4.tgz#3d21731a42e3f598a73835299dd0169c3b90ac91" + integrity sha512-g1y4/G6xGWMD85Tlft5XedGaZBCIVN+/P0bs6eabmcPP9egFleMAo65OOjlhcz1njpwagyY3t0nsQC9oTFegJA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-exponentiation-operator@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008" + integrity sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-exponentiation-operator@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.7.4.tgz#dd30c0191e3a1ba19bcc7e389bdfddc0729d5db9" + integrity sha512-MCqiLfCKm6KEA1dglf6Uqq1ElDIZwFuzz1WH5mTf8k2uQSxEJMbOIEh7IZv7uichr7PMfi5YVSrr1vz+ipp7AQ== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-for-of@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz#0267fc735e24c808ba173866c6c4d1440fc3c556" + integrity sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-for-of@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.7.4.tgz#248800e3a5e507b1f103d8b4ca998e77c63932bc" + integrity sha512-zZ1fD1B8keYtEcKF+M1TROfeHTKnijcVQm0yO/Yu1f7qoDoxEIc/+GX6Go430Bg84eM/xwPFp0+h4EbZg7epAA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-function-name@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.0.tgz#0fa786f1eef52e3b7d4fc02e54b2129de8a04c2a" + integrity sha512-P5HKu0d9+CzZxP5jcrWdpe7ZlFDe24bmqP6a6X8BHEBl/eizAsY8K6LX8LASZL0Jxdjm5eEfzp+FIrxCm/p8bA== + dependencies: + "@babel/helper-function-name" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-function-name@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.4.tgz#75a6d3303d50db638ff8b5385d12451c865025b1" + integrity sha512-E/x09TvjHNhsULs2IusN+aJNRV5zKwxu1cpirZyRPw+FyyIKEHPXTsadj48bVpc1R5Qq1B5ZkzumuFLytnbT6g== + dependencies: + "@babel/helper-function-name" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-literals@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1" + integrity sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-literals@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.7.4.tgz#27fe87d2b5017a2a5a34d1c41a6b9f6a6262643e" + integrity sha512-X2MSV7LfJFm4aZfxd0yLVFrEXAgPqYoDG53Br/tCKiKYfX0MjVjQeWPIhPHHsCqzwQANq+FLN786fF5rgLS+gw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-member-expression-literals@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz#fa10aa5c58a2cb6afcf2c9ffa8cb4d8b3d489a2d" + integrity sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-member-expression-literals@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.7.4.tgz#aee127f2f3339fc34ce5e3055d7ffbf7aa26f19a" + integrity sha512-9VMwMO7i69LHTesL0RdGy93JU6a+qOPuvB4F4d0kR0zyVjJRVJRaoaGjhtki6SzQUu8yen/vxPKN6CWnCUw6bA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-modules-amd@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz#ef00435d46da0a5961aa728a1d2ecff063e4fb91" + integrity sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg== + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-amd@^7.7.5": + version "7.7.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.5.tgz#39e0fb717224b59475b306402bb8eedab01e729c" + integrity sha512-CT57FG4A2ZUNU1v+HdvDSDrjNWBrtCmSH6YbbgN3Lrf0Di/q/lWRxZrE72p3+HCCz9UjfZOEBdphgC0nzOS6DQ== + dependencies: + "@babel/helper-module-transforms" "^7.7.5" + "@babel/helper-plugin-utils" "^7.0.0" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-commonjs@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.0.tgz#3e5ffb4fd8c947feede69cbe24c9554ab4113fe3" + integrity sha512-KEMyWNNWnjOom8vR/1+d+Ocz/mILZG/eyHHO06OuBQ2aNhxT62fr4y6fGOplRx+CxCSp3IFwesL8WdINfY/3kg== + dependencies: + "@babel/helper-module-transforms" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-simple-access" "^7.7.0" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-commonjs@^7.7.5": + version "7.7.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.5.tgz#1d27f5eb0bcf7543e774950e5b2fa782e637b345" + integrity sha512-9Cq4zTFExwFhQI6MT1aFxgqhIsMWQWDVwOgLzl7PTWJHsNaqFvklAU+Oz6AQLAS0dJKTwZSOCo20INwktxpi3Q== + dependencies: + "@babel/helper-module-transforms" "^7.7.5" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-simple-access" "^7.7.4" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-systemjs@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.7.0.tgz#9baf471213af9761c1617bb12fd278e629041417" + integrity sha512-ZAuFgYjJzDNv77AjXRqzQGlQl4HdUM6j296ee4fwKVZfhDR9LAGxfvXjBkb06gNETPnN0sLqRm9Gxg4wZH6dXg== + dependencies: + "@babel/helper-hoist-variables" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-systemjs@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.7.4.tgz#cd98152339d3e763dfe838b7d4273edaf520bb30" + integrity sha512-y2c96hmcsUi6LrMqvmNDPBBiGCiQu0aYqpHatVVu6kD4mFEXKjyNxd/drc18XXAf9dv7UXjrZwBVmTTGaGP8iw== + dependencies: + "@babel/helper-hoist-variables" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-umd@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.7.0.tgz#d62c7da16670908e1d8c68ca0b5d4c0097b69966" + integrity sha512-u7eBA03zmUswQ9LQ7Qw0/ieC1pcAkbp5OQatbWUzY1PaBccvuJXUkYzoN1g7cqp7dbTu6Dp9bXyalBvD04AANA== + dependencies: + "@babel/helper-module-transforms" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-modules-umd@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.7.4.tgz#1027c355a118de0aae9fee00ad7813c584d9061f" + integrity sha512-u2B8TIi0qZI4j8q4C51ktfO7E3cQ0qnaXFI1/OXITordD40tt17g/sXqgNNCcMTcBFKrUPcGDx+TBJuZxLx7tw== + dependencies: + "@babel/helper-module-transforms" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.7.0.tgz#358e6fd869b9a4d8f5cbc79e4ed4fc340e60dcaf" + integrity sha512-+SicSJoKouPctL+j1pqktRVCgy+xAch1hWWTMy13j0IflnyNjaoskj+DwRQFimHbLqO3sq2oN2CXMvXq3Bgapg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.7.0" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.7.4.tgz#fb3bcc4ee4198e7385805007373d6b6f42c98220" + integrity sha512-jBUkiqLKvUWpv9GLSuHUFYdmHg0ujC1JEYoZUfeOOfNydZXp1sXObgyPatpcwjWgsdBGsagWW0cdJpX/DO2jMw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.7.4" + +"@babel/plugin-transform-new-target@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz#18d120438b0cc9ee95a47f2c72bc9768fbed60a5" + integrity sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-new-target@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.7.4.tgz#4a0753d2d60639437be07b592a9e58ee00720167" + integrity sha512-CnPRiNtOG1vRodnsyGX37bHQleHE14B9dnnlgSeEs3ek3fHN1A1SScglTCg1sfbe7sRQ2BUcpgpTpWSfMKz3gg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-object-super@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz#c70021df834073c65eb613b8679cc4a381d1a9f9" + integrity sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.5.5" + +"@babel/plugin-transform-object-super@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.7.4.tgz#48488937a2d586c0148451bf51af9d7dda567262" + integrity sha512-ho+dAEhC2aRnff2JCA0SAK7V2R62zJd/7dmtoe7MHcso4C2mS+vZjn1Pb1pCVZvJs1mgsvv5+7sT+m3Bysb6eg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.7.4" + +"@babel/plugin-transform-parameters@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz#7556cf03f318bd2719fe4c922d2d808be5571e16" + integrity sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw== + dependencies: + "@babel/helper-call-delegate" "^7.4.4" + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-parameters@^7.7.7": + version "7.7.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.7.7.tgz#7a884b2460164dc5f194f668332736584c760007" + integrity sha512-OhGSrf9ZBrr1fw84oFXj5hgi8Nmg+E2w5L7NhnG0lPvpDtqd7dbyilM2/vR8CKbJ907RyxPh2kj6sBCSSfI9Ew== + dependencies: + "@babel/helper-call-delegate" "^7.7.4" + "@babel/helper-get-function-arity" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-property-literals@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz#03e33f653f5b25c4eb572c98b9485055b389e905" + integrity sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-property-literals@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.7.4.tgz#2388d6505ef89b266103f450f9167e6bd73f98c2" + integrity sha512-MatJhlC4iHsIskWYyawl53KuHrt+kALSADLQQ/HkhTjX954fkxIEh4q5slL4oRAnsm/eDoZ4q0CIZpcqBuxhJQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-react-display-name@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.7.4.tgz#9f2b80b14ebc97eef4a9b29b612c58ed9c0d10dd" + integrity sha512-sBbIvqYkthai0X0vkD2xsAwluBp+LtNHH+/V4a5ydifmTtb8KOVOlrMIk/MYmIc4uTYDnjZUHQildYNo36SRJw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-react-jsx-self@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.7.4.tgz#81b8fbfd14b2215e8f1c2c3adfba266127b0231c" + integrity sha512-PWYjSfqrO273mc1pKCRTIJXyqfc9vWYBax88yIhQb+bpw3XChVC7VWS4VwRVs63wFHKxizvGSd00XEr+YB9Q2A== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.7.4" + +"@babel/plugin-transform-react-jsx-source@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.7.4.tgz#8994b1bf6014b133f5a46d3b7d1ee5f5e3e72c10" + integrity sha512-5ZU9FnPhqtHsOXxutRtXZAzoEJwDaP32QcobbMP1/qt7NYcsCNK8XgzJcJfoEr/ZnzVvUNInNjIW22Z6I8p9mg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.7.4" + +"@babel/plugin-transform-react-jsx@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.7.4.tgz#d91205717fae4e2f84d020cd3057ec02a10f11da" + integrity sha512-LixU4BS95ZTEAZdPaIuyg/k8FiiqN9laQ0dMHB4MlpydHY53uQdWCUrwjLr5o6ilS6fAgZey4Q14XBjl5tL6xw== + dependencies: + "@babel/helper-builder-react-jsx" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.7.4" + +"@babel/plugin-transform-regenerator@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.0.tgz#f1b20b535e7716b622c99e989259d7dd942dd9cc" + integrity sha512-AXmvnC+0wuj/cFkkS/HFHIojxH3ffSXE+ttulrqWjZZRaUOonfJc60e1wSNT4rV8tIunvu/R3wCp71/tLAa9xg== + dependencies: + regenerator-transform "^0.14.0" + +"@babel/plugin-transform-regenerator@^7.7.5": + version "7.7.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.5.tgz#3a8757ee1a2780f390e89f246065ecf59c26fce9" + integrity sha512-/8I8tPvX2FkuEyWbjRCt4qTAgZK0DVy8QRguhA524UH48RfGJy94On2ri+dCuwOpcerPRl9O4ebQkRcVzIaGBw== + dependencies: + regenerator-transform "^0.14.0" + +"@babel/plugin-transform-reserved-words@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz#4792af87c998a49367597d07fedf02636d2e1634" + integrity sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-reserved-words@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.7.4.tgz#6a7cf123ad175bb5c69aec8f6f0770387ed3f1eb" + integrity sha512-OrPiUB5s5XvkCO1lS7D8ZtHcswIC57j62acAnJZKqGGnHP+TIc/ljQSrgdX/QyOTdEK5COAhuc820Hi1q2UgLQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-shorthand-properties@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" + integrity sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-shorthand-properties@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.7.4.tgz#74a0a9b2f6d67a684c6fbfd5f0458eb7ba99891e" + integrity sha512-q+suddWRfIcnyG5YiDP58sT65AJDZSUhXQDZE3r04AuqD6d/XLaQPPXSBzP2zGerkgBivqtQm9XKGLuHqBID6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-spread@^7.6.2": + version "7.6.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.6.2.tgz#fc77cf798b24b10c46e1b51b1b88c2bf661bb8dd" + integrity sha512-DpSvPFryKdK1x+EDJYCy28nmAaIMdxmhot62jAXF/o99iA33Zj2Lmcp3vDmz+MUh0LNYVPvfj5iC3feb3/+PFg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-spread@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.7.4.tgz#aa673b356fe6b7e70d69b6e33a17fef641008578" + integrity sha512-8OSs0FLe5/80cndziPlg4R0K6HcWSM0zyNhHhLsmw/Nc5MaA49cAsnoJ/t/YZf8qkG7fD+UjTRaApVDB526d7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-sticky-regex@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1" + integrity sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + +"@babel/plugin-transform-sticky-regex@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.7.4.tgz#ffb68c05090c30732076b1285dc1401b404a123c" + integrity sha512-Ls2NASyL6qtVe1H1hXts9yuEeONV2TJZmplLONkMPUG158CtmnrzW5Q5teibM5UVOFjG0D3IC5mzXR6pPpUY7A== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + +"@babel/plugin-transform-template-literals@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz#9d28fea7bbce637fb7612a0750989d8321d4bcb0" + integrity sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-template-literals@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.7.4.tgz#1eb6411736dd3fe87dbd20cc6668e5121c17d604" + integrity sha512-sA+KxLwF3QwGj5abMHkHgshp9+rRz+oY9uoRil4CyLtgEuE/88dpkeWgNk5qKVsJE9iSfly3nvHapdRiIS2wnQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-typeof-symbol@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2" + integrity sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-typeof-symbol@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.7.4.tgz#3174626214f2d6de322882e498a38e8371b2140e" + integrity sha512-KQPUQ/7mqe2m0B8VecdyaW5XcQYaePyl9R7IsKd+irzj6jvbhoGnRE+M0aNkyAzI07VfUQ9266L5xMARitV3wg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-unicode-regex@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.0.tgz#743d9bcc44080e3cc7d49259a066efa30f9187a3" + integrity sha512-RrThb0gdrNwFAqEAAx9OWgtx6ICK69x7i9tCnMdVrxQwSDp/Abu9DXFU5Hh16VP33Rmxh04+NGW28NsIkFvFKA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-unicode-regex@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.4.tgz#a3c0f65b117c4c81c5b6484f2a5e7b95346b83ae" + integrity sha512-N77UUIV+WCvE+5yHw+oks3m18/umd7y392Zv7mYTpFqHtkpcc+QUz+gLJNTWVlWROIWeLqY0f3OjZxV5TcXnRw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/preset-env@^7.5.3": + version "7.7.1" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.7.1.tgz#04a2ff53552c5885cf1083e291c8dd5490f744bb" + integrity sha512-/93SWhi3PxcVTDpSqC+Dp4YxUu3qZ4m7I76k0w73wYfn7bGVuRIO4QUz95aJksbS+AD1/mT1Ie7rbkT0wSplaA== + dependencies: + "@babel/helper-module-imports" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-async-generator-functions" "^7.7.0" + "@babel/plugin-proposal-dynamic-import" "^7.7.0" + "@babel/plugin-proposal-json-strings" "^7.2.0" + "@babel/plugin-proposal-object-rest-spread" "^7.6.2" + "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.7.0" + "@babel/plugin-syntax-async-generators" "^7.2.0" + "@babel/plugin-syntax-dynamic-import" "^7.2.0" + "@babel/plugin-syntax-json-strings" "^7.2.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" + "@babel/plugin-syntax-top-level-await" "^7.7.0" + "@babel/plugin-transform-arrow-functions" "^7.2.0" + "@babel/plugin-transform-async-to-generator" "^7.7.0" + "@babel/plugin-transform-block-scoped-functions" "^7.2.0" + "@babel/plugin-transform-block-scoping" "^7.6.3" + "@babel/plugin-transform-classes" "^7.7.0" + "@babel/plugin-transform-computed-properties" "^7.2.0" + "@babel/plugin-transform-destructuring" "^7.6.0" + "@babel/plugin-transform-dotall-regex" "^7.7.0" + "@babel/plugin-transform-duplicate-keys" "^7.5.0" + "@babel/plugin-transform-exponentiation-operator" "^7.2.0" + "@babel/plugin-transform-for-of" "^7.4.4" + "@babel/plugin-transform-function-name" "^7.7.0" + "@babel/plugin-transform-literals" "^7.2.0" + "@babel/plugin-transform-member-expression-literals" "^7.2.0" + "@babel/plugin-transform-modules-amd" "^7.5.0" + "@babel/plugin-transform-modules-commonjs" "^7.7.0" + "@babel/plugin-transform-modules-systemjs" "^7.7.0" + "@babel/plugin-transform-modules-umd" "^7.7.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.7.0" + "@babel/plugin-transform-new-target" "^7.4.4" + "@babel/plugin-transform-object-super" "^7.5.5" + "@babel/plugin-transform-parameters" "^7.4.4" + "@babel/plugin-transform-property-literals" "^7.2.0" + "@babel/plugin-transform-regenerator" "^7.7.0" + "@babel/plugin-transform-reserved-words" "^7.2.0" + "@babel/plugin-transform-shorthand-properties" "^7.2.0" + "@babel/plugin-transform-spread" "^7.6.2" + "@babel/plugin-transform-sticky-regex" "^7.2.0" + "@babel/plugin-transform-template-literals" "^7.4.4" + "@babel/plugin-transform-typeof-symbol" "^7.2.0" + "@babel/plugin-transform-unicode-regex" "^7.7.0" + "@babel/types" "^7.7.1" + browserslist "^4.6.0" + core-js-compat "^3.1.1" + invariant "^2.2.2" + js-levenshtein "^1.1.3" + semver "^5.5.0" + +"@babel/preset-env@^7.7.7": + version "7.7.7" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.7.7.tgz#c294167b91e53e7e36d820e943ece8d0c7fe46ac" + integrity sha512-pCu0hrSSDVI7kCVUOdcMNQEbOPJ52E+LrQ14sN8uL2ALfSqePZQlKrOy+tM4uhEdYlCHi4imr8Zz2cZe9oSdIg== + dependencies: + "@babel/helper-module-imports" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-async-generator-functions" "^7.7.4" + "@babel/plugin-proposal-dynamic-import" "^7.7.4" + "@babel/plugin-proposal-json-strings" "^7.7.4" + "@babel/plugin-proposal-object-rest-spread" "^7.7.7" + "@babel/plugin-proposal-optional-catch-binding" "^7.7.4" + "@babel/plugin-proposal-unicode-property-regex" "^7.7.7" + "@babel/plugin-syntax-async-generators" "^7.7.4" + "@babel/plugin-syntax-dynamic-import" "^7.7.4" + "@babel/plugin-syntax-json-strings" "^7.7.4" + "@babel/plugin-syntax-object-rest-spread" "^7.7.4" + "@babel/plugin-syntax-optional-catch-binding" "^7.7.4" + "@babel/plugin-syntax-top-level-await" "^7.7.4" + "@babel/plugin-transform-arrow-functions" "^7.7.4" + "@babel/plugin-transform-async-to-generator" "^7.7.4" + "@babel/plugin-transform-block-scoped-functions" "^7.7.4" + "@babel/plugin-transform-block-scoping" "^7.7.4" + "@babel/plugin-transform-classes" "^7.7.4" + "@babel/plugin-transform-computed-properties" "^7.7.4" + "@babel/plugin-transform-destructuring" "^7.7.4" + "@babel/plugin-transform-dotall-regex" "^7.7.7" + "@babel/plugin-transform-duplicate-keys" "^7.7.4" + "@babel/plugin-transform-exponentiation-operator" "^7.7.4" + "@babel/plugin-transform-for-of" "^7.7.4" + "@babel/plugin-transform-function-name" "^7.7.4" + "@babel/plugin-transform-literals" "^7.7.4" + "@babel/plugin-transform-member-expression-literals" "^7.7.4" + "@babel/plugin-transform-modules-amd" "^7.7.5" + "@babel/plugin-transform-modules-commonjs" "^7.7.5" + "@babel/plugin-transform-modules-systemjs" "^7.7.4" + "@babel/plugin-transform-modules-umd" "^7.7.4" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.7.4" + "@babel/plugin-transform-new-target" "^7.7.4" + "@babel/plugin-transform-object-super" "^7.7.4" + "@babel/plugin-transform-parameters" "^7.7.7" + "@babel/plugin-transform-property-literals" "^7.7.4" + "@babel/plugin-transform-regenerator" "^7.7.5" + "@babel/plugin-transform-reserved-words" "^7.7.4" + "@babel/plugin-transform-shorthand-properties" "^7.7.4" + "@babel/plugin-transform-spread" "^7.7.4" + "@babel/plugin-transform-sticky-regex" "^7.7.4" + "@babel/plugin-transform-template-literals" "^7.7.4" + "@babel/plugin-transform-typeof-symbol" "^7.7.4" + "@babel/plugin-transform-unicode-regex" "^7.7.4" + "@babel/types" "^7.7.4" + browserslist "^4.6.0" + core-js-compat "^3.6.0" + invariant "^2.2.2" + js-levenshtein "^1.1.3" + semver "^5.5.0" + +"@babel/preset-react@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.7.4.tgz#3fe2ea698d8fb536d8e7881a592c3c1ee8bf5707" + integrity sha512-j+vZtg0/8pQr1H8wKoaJyGL2IEk3rG/GIvua7Sec7meXVIvGycihlGMx5xcU00kqCJbwzHs18xTu3YfREOqQ+g== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.7.4" + "@babel/plugin-transform-react-jsx" "^7.7.4" + "@babel/plugin-transform-react-jsx-self" "^7.7.4" + "@babel/plugin-transform-react-jsx-source" "^7.7.4" + +"@babel/runtime@^7.6.3": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.2.tgz#111a78002a5c25fc8e3361bedc9529c696b85a6a" + integrity sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw== + dependencies: + regenerator-runtime "^0.13.2" + +"@babel/template@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.0.tgz#4fadc1b8e734d97f56de39c77de76f2562e597d0" + integrity sha512-OKcwSYOW1mhWbnTBgQY5lvg1Fxg+VyfQGjcBduZFljfc044J5iDlnDSfhQ867O17XHiSCxYHUxHg2b7ryitbUQ== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.7.0" + "@babel/types" "^7.7.0" + +"@babel/template@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.4.tgz#428a7d9eecffe27deac0a98e23bf8e3675d2a77b" + integrity sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.7.4" + "@babel/types" "^7.7.4" + +"@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.2.tgz#ef0a65e07a2f3c550967366b3d9b62a2dcbeae09" + integrity sha512-TM01cXib2+rgIZrGJOLaHV/iZUAxf4A0dt5auY6KNZ+cm6aschuJGqKJM3ROTt3raPUdIDk9siAufIFEleRwtw== + dependencies: + "@babel/code-frame" "^7.5.5" + "@babel/generator" "^7.7.2" + "@babel/helper-function-name" "^7.7.0" + "@babel/helper-split-export-declaration" "^7.7.0" + "@babel/parser" "^7.7.2" + "@babel/types" "^7.7.2" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + +"@babel/traverse@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.4.tgz#9c1e7c60fb679fe4fcfaa42500833333c2058558" + integrity sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw== + dependencies: + "@babel/code-frame" "^7.5.5" + "@babel/generator" "^7.7.4" + "@babel/helper-function-name" "^7.7.4" + "@babel/helper-split-export-declaration" "^7.7.4" + "@babel/parser" "^7.7.4" + "@babel/types" "^7.7.4" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + +"@babel/types@7.0.0-beta.35": + version "7.0.0-beta.35" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.35.tgz#cf933a9a9a38484ca724b335b88d83726d5ab960" + integrity sha512-y9XT11CozHDgjWcTdxmhSj13rJVXpa5ZXwjjOiTedjaM0ba5ItqdS02t31EhPl7HtOWxsZkYCCUNrSfrOisA6w== + dependencies: + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^2.0.0" + +"@babel/types@^7.7.0", "@babel/types@^7.7.1", "@babel/types@^7.7.2": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.2.tgz#550b82e5571dcd174af576e23f0adba7ffc683f7" + integrity sha512-YTf6PXoh3+eZgRCBzzP25Bugd2ngmpQVrk7kXX0i5N9BO7TFBtIgZYs7WtxtOGs8e6A4ZI7ECkbBCEHeXocvOA== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + +"@babel/types@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.4.tgz#516570d539e44ddf308c07569c258ff94fde9193" + integrity sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + +"@develar/schema-utils@~2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@develar/schema-utils/-/schema-utils-2.1.0.tgz#eceb1695bfbed6f6bb84666d5d3abe5e1fd54e17" + integrity sha512-qjCqB4ctMig9Gz5bd6lkdFr3bO6arOdQqptdBSpF1ZpCnjofieCciEzkoS9ujY9cMGyllYSCSmBJ3x9OKHXzoA== + dependencies: + ajv "^6.1.0" + ajv-keywords "^3.1.0" + +"@electron/get@^1.0.1": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@electron/get/-/get-1.6.0.tgz#3e1437fa0f436ce9d4e0c27a4c330835ae6d74ed" + integrity sha512-xuvAzbN9iBApfAMvW0hKUpxHR5wPVbG9RaoSTbpu/WaHISDu0MVfMWYhfeU0X730CpBV0G2RkLgwAs9WDan3GA== + dependencies: + debug "^4.1.1" + env-paths "^2.2.0" + fs-extra "^8.1.0" + got "^9.6.0" + sanitize-filename "^1.6.2" + sumchecker "^3.0.0" + optionalDependencies: + global-agent "^2.0.2" + global-tunnel-ng "^2.7.1" + +"@hot-loader/react-dom@^16.11.0": + version "16.11.0" + resolved "https://registry.yarnpkg.com/@hot-loader/react-dom/-/react-dom-16.11.0.tgz#c0b483923b289db5431516f56ee2a69448ebf9bd" + integrity sha512-cIOVB8YgT4EVCNiXK+gGuYl6adW/TKlW3N7GvgY5QgpL2NTWagF/oJxVscHSdR3O7NjJsoxdseB5spqwCHNIhA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.17.0" + +"@posthtml/esm@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@posthtml/esm/-/esm-1.0.0.tgz#09bcb28a02438dcee22ad1970ca1d85a000ae0cf" + integrity sha512-dEVG+ITnvqKGa4v040tP+n8LOKOqr94qjLva7bE5pnfm2KHJwsKz69J4KMxgWLznbpBJzy8vQfCayEk3vLZnZQ== + +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + +"@types/debug@^4.1.4": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd" + integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ== + +"@types/events@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" + integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== + +"@types/glob@^7.1.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" + integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== + dependencies: + "@types/events" "*" + "@types/minimatch" "*" + "@types/node" "*" + +"@types/minimatch@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" + integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== + +"@types/node@*", "@types/node@^12.0.12": + version "12.12.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.6.tgz#a47240c10d86a9a57bb0c633f0b2e0aea9ce9253" + integrity sha512-FjsYUPzEJdGXjwKqSpE0/9QEh6kzhTAeObA54rn6j3rR4C/mzpI9L0KNfoeASSPMMdxIsoJuCLDWcM/rVjIsSA== + +"@types/prop-types@*": + version "15.7.3" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" + integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== + +"@types/q@^1.5.1": + version "1.5.2" + resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" + integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== + +"@types/react@^16.9.17": + version "16.9.17" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.17.tgz#58f0cc0e9ec2425d1441dd7b623421a867aa253e" + integrity sha512-UP27In4fp4sWF5JgyV6pwVPAQM83Fj76JOcg02X5BZcpSu5Wx+fP9RMqc2v0ssBoQIFvD5JdKY41gjJJKmw6Bg== + dependencies: + "@types/prop-types" "*" + csstype "^2.2.0" + +"@types/webpack-env@^1.13.9": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.14.1.tgz#0d8a53f308f017c53a5ddc3d07f4d6fa76b790d7" + integrity sha512-0Ki9jAAhKDSuLDXOIMADg54Hu60SuBTEsWaJGGy5cV+SSUQ63J2a+RrYYGrErzz39fXzTibhKrAQJAb8M7PNcA== + +"@webassemblyjs/ast@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" + integrity sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ== + dependencies: + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/wast-parser" "1.8.5" + +"@webassemblyjs/floating-point-hex-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz#1ba926a2923613edce496fd5b02e8ce8a5f49721" + integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ== + +"@webassemblyjs/helper-api-error@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz#c49dad22f645227c5edb610bdb9697f1aab721f7" + integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA== + +"@webassemblyjs/helper-buffer@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz#fea93e429863dd5e4338555f42292385a653f204" + integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q== + +"@webassemblyjs/helper-code-frame@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz#9a740ff48e3faa3022b1dff54423df9aa293c25e" + integrity sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ== + dependencies: + "@webassemblyjs/wast-printer" "1.8.5" + +"@webassemblyjs/helper-fsm@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz#ba0b7d3b3f7e4733da6059c9332275d860702452" + integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow== + +"@webassemblyjs/helper-module-context@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz#def4b9927b0101dc8cbbd8d1edb5b7b9c82eb245" + integrity sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g== + dependencies: + "@webassemblyjs/ast" "1.8.5" + mamacro "^0.0.3" + +"@webassemblyjs/helper-wasm-bytecode@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz#537a750eddf5c1e932f3744206551c91c1b93e61" + integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ== + +"@webassemblyjs/helper-wasm-section@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz#74ca6a6bcbe19e50a3b6b462847e69503e6bfcbf" + integrity sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + +"@webassemblyjs/ieee754@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz#712329dbef240f36bf57bd2f7b8fb9bf4154421e" + integrity sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.8.5.tgz#044edeb34ea679f3e04cd4fd9824d5e35767ae10" + integrity sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.8.5.tgz#a8bf3b5d8ffe986c7c1e373ccbdc2a0915f0cedc" + integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw== + +"@webassemblyjs/wasm-edit@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz#962da12aa5acc1c131c81c4232991c82ce56e01a" + integrity sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/helper-wasm-section" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + "@webassemblyjs/wasm-opt" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + "@webassemblyjs/wast-printer" "1.8.5" + +"@webassemblyjs/wasm-gen@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz#54840766c2c1002eb64ed1abe720aded714f98bc" + integrity sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/ieee754" "1.8.5" + "@webassemblyjs/leb128" "1.8.5" + "@webassemblyjs/utf8" "1.8.5" + +"@webassemblyjs/wasm-opt@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz#b24d9f6ba50394af1349f510afa8ffcb8a63d264" + integrity sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + +"@webassemblyjs/wasm-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz#21576f0ec88b91427357b8536383668ef7c66b8d" + integrity sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-api-error" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/ieee754" "1.8.5" + "@webassemblyjs/leb128" "1.8.5" + "@webassemblyjs/utf8" "1.8.5" + +"@webassemblyjs/wast-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz#e10eecd542d0e7bd394f6827c49f3df6d4eefb8c" + integrity sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/floating-point-hex-parser" "1.8.5" + "@webassemblyjs/helper-api-error" "1.8.5" + "@webassemblyjs/helper-code-frame" "1.8.5" + "@webassemblyjs/helper-fsm" "1.8.5" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/wast-printer@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz#114bbc481fd10ca0e23b3560fa812748b0bae5bc" + integrity sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/wast-parser" "1.8.5" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn@^6.2.1: + version "6.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e" + integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA== + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" + integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== + +ajv@^6.1.0, ajv@^6.10.1, ajv@^6.10.2: + version "6.10.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" + integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= + +ansi-align@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" + integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw== + dependencies: + string-width "^3.0.0" + +ansi-colors@^3.0.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" + integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== + +ansi-html@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +app-builder-bin@3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-3.4.3.tgz#58a74193eb882f029be6b7f0cd3f0c6805927a6b" + integrity sha512-qMhayIwi3juerQEVJMQ76trObEbfQT0nhUdxZz9a26/3NLT3pE6awmQ8S1cEnrGugaaM5gYqR8OElcDezfmEsg== + +app-builder-lib@21.2.0, app-builder-lib@~21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-21.2.0.tgz#fa1d1604601431e2c3476857e9b9b61d33ad26cc" + integrity sha512-aOX/nv77/Bti6NymJDg7p9T067xD8m1ipIEJR7B4Mm1GsJWpMm9PZdXtCRiMNRjHtQS5KIljT0g17781y6qn5A== + dependencies: + "7zip-bin" "~5.0.3" + "@develar/schema-utils" "~2.1.0" + async-exit-hook "^2.0.1" + bluebird-lst "^1.0.9" + builder-util "21.2.0" + builder-util-runtime "8.3.0" + chromium-pickle-js "^0.2.0" + debug "^4.1.1" + ejs "^2.6.2" + electron-publish "21.2.0" + fs-extra "^8.1.0" + hosted-git-info "^2.7.1" + is-ci "^2.0.0" + isbinaryfile "^4.0.2" + js-yaml "^3.13.1" + lazy-val "^1.0.4" + minimatch "^3.0.4" + normalize-package-data "^2.5.0" + read-config-file "5.0.0" + sanitize-filename "^1.6.2" + semver "^6.3.0" + temp-file "^3.3.4" + +aproba@^1.0.3, aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-flatten@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +assert@^1.1.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== + dependencies: + object-assign "^4.1.1" + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +async-exit-hook@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/async-exit-hook/-/async-exit-hook-2.0.1.tgz#8bd8b024b0ec9b1c01cccb9af9db29bd717dfaf3" + integrity sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw== + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +async@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" + +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +autoprefixer@^6.3.1: + version "6.7.7" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014" + integrity sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ= + dependencies: + browserslist "^1.7.6" + caniuse-db "^1.0.30000634" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^5.2.16" + postcss-value-parser "^3.2.3" + +babel-loader@^8.0.6: + version "8.0.6" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.6.tgz#e33bdb6f362b03f4bb141a0c21ab87c501b70dfb" + integrity sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw== + dependencies: + find-cache-dir "^2.0.0" + loader-utils "^1.0.2" + mkdirp "^0.5.1" + pify "^4.0.1" + +babel-plugin-component@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-component/-/babel-plugin-component-1.1.1.tgz#9b023a23ff5c9aae0fd56c5a18b9cab8c4d45eea" + integrity sha512-WUw887kJf2GH80Ng/ZMctKZ511iamHNqPhd9uKo14yzisvV7Wt1EckIrb8oq/uCz3B3PpAW7Xfl7AkTLDYT6ag== + dependencies: + "@babel/helper-module-imports" "7.0.0-beta.35" + +babel-plugin-dynamic-import-node@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" + integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ== + dependencies: + object.assign "^4.1.0" + +babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +balanced-match@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + integrity sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg= + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base64-js@^1.0.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" + integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= + +big.js@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" + integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +bluebird-lst@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/bluebird-lst/-/bluebird-lst-1.0.9.tgz#a64a0e4365658b9ab5fe875eb9dfb694189bb41c" + integrity sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw== + dependencies: + bluebird "^3.5.5" + +bluebird@^3.5.4, bluebird@^3.5.5: + version "3.7.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.1.tgz#df70e302b471d7473489acf26a93d63b53f874de" + integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= + dependencies: + array-flatten "^2.1.0" + deep-equal "^1.0.1" + dns-equal "^1.0.0" + dns-txt "^2.0.2" + multicast-dns "^6.0.1" + multicast-dns-service-types "^1.1.0" + +boolbase@^1.0.0, boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + +boolean@^2.0.2, boolean@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/boolean/-/boolean-2.0.3.tgz#da4a5c5a85231d64dd4f6022a0fa5a66adc76653" + integrity sha512-iHzXeFCXWrpjYE7DToXGCBPGZf0eVISqzL+4sgrOSYEKXnb59WHPFvGTTyCj6zJ/MuuLAxEn8zPkrTHHzlt3IA== + +boxen@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-3.2.0.tgz#fbdff0de93636ab4450886b6ff45b92d098f45eb" + integrity sha512-cU4J/+NodM3IHdSL2yN8bqYqnmlBTidDR4RC7nJs61ZmtGz8VZzM3HLQX0zY5mrSmPtR3xWwsq2jOUQqFZN8+A== + dependencies: + ansi-align "^3.0.0" + camelcase "^5.3.1" + chalk "^2.4.2" + cli-boxes "^2.2.0" + string-width "^3.0.0" + term-size "^1.2.0" + type-fest "^0.3.0" + widest-line "^2.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6: + version "1.7.7" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" + integrity sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk= + dependencies: + caniuse-db "^1.0.30000639" + electron-to-chromium "^1.2.7" + +browserslist@^4.6.0, browserslist@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.7.2.tgz#1bb984531a476b5d389cedecb195b2cd69fb1348" + integrity sha512-uZavT/gZXJd2UTi9Ov7/Z340WOSQ3+m1iBVRUknf+okKxonL9P83S3ctiBDtuRmRu8PiCHjqyueqQ9HYlJhxiw== + dependencies: + caniuse-lite "^1.0.30001004" + electron-to-chromium "^1.3.295" + node-releases "^1.1.38" + +browserslist@^4.8.2: + version "4.8.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.2.tgz#b45720ad5fbc8713b7253c20766f701c9a694289" + integrity sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA== + dependencies: + caniuse-lite "^1.0.30001015" + electron-to-chromium "^1.3.322" + node-releases "^1.1.42" + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builder-util-runtime@8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.3.0.tgz#f5fac9139af6facf42a21fbe4d3aebed88fda33e" + integrity sha512-CSOdsYqf4RXIHh1HANPbrZHlZ9JQJXSuDDloblZPcWQVN62inyYoTQuSmY3KrgefME2Sv3Kn2MxHvbGQHRf8Iw== + dependencies: + debug "^4.1.1" + sax "^1.2.4" + +builder-util@21.2.0, builder-util@~21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-21.2.0.tgz#aba721190e4e841009d9fb4b88f1130ed616522f" + integrity sha512-Nd6CUb6YgDY8EXAXEIegx+1kzKqyFQ5ZM5BoYkeunAlwz/zDJoH1UCyULjoS5wQe5czNClFQy07zz2bzYD0Z4A== + dependencies: + "7zip-bin" "~5.0.3" + "@types/debug" "^4.1.4" + app-builder-bin "3.4.3" + bluebird-lst "^1.0.9" + builder-util-runtime "8.3.0" + chalk "^2.4.2" + debug "^4.1.1" + fs-extra "^8.1.0" + is-ci "^2.0.0" + js-yaml "^3.13.1" + source-map-support "^0.5.13" + stat-mode "^0.3.0" + temp-file "^3.3.4" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +cacache@^12.0.2: + version "12.0.3" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" + integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== + dependencies: + bluebird "^3.5.5" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.4" + graceful-fs "^4.1.15" + infer-owner "^1.0.3" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.3" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + +camel-case@3.0.x: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" + integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M= + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +caniuse-api@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" + integrity sha1-tTTnxzTE+B7F++isoq0kNUuWLGw= + dependencies: + browserslist "^1.3.6" + caniuse-db "^1.0.30000529" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: + version "1.0.30001008" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30001008.tgz#1691f28db0e08bf6abb5e472d8aaea392ec4a995" + integrity sha512-Fog+uREPKb/RDc0puoAqqBZB05I8wYff+TIMDkYw9Lweq7+hUEN5fNLpIaBX6AJxq4sndqPct8fYLrDUV6u4xw== + +caniuse-lite@^1.0.30001004: + version "1.0.30001008" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001008.tgz#b8841b1df78a9f5ed9702537ef592f1f8772c0d9" + integrity sha512-b8DJyb+VVXZGRgJUa30cbk8gKHZ3LOZTBLaUEEVr2P4xpmFigOCc62CO4uzquW641Ouq1Rm9N+rWLWdSYDaDIw== + +caniuse-lite@^1.0.30001015: + version "1.0.30001015" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001015.tgz#15a7ddf66aba786a71d99626bc8f2b91c6f0f5f0" + integrity sha512-/xL2AbW/XWHNu1gnIrO8UitBGoFthcsDgU9VLK1/dpsoxbaD5LscHozKze05R6WLsBvLhqv78dAPozMFQBYLbQ== + +catharsis@^0.8.11: + version "0.8.11" + resolved "https://registry.yarnpkg.com/catharsis/-/catharsis-0.8.11.tgz#d0eb3d2b82b7da7a3ce2efb1a7b00becc6643468" + integrity sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g== + dependencies: + lodash "^4.17.14" + +chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chokidar@^2.0.2, chokidar@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +chownr@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142" + integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw== + +chrome-trace-event@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" + integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== + dependencies: + tslib "^1.9.0" + +chromium-pickle-js@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz#04a106672c18b085ab774d983dfa3ea138f22205" + integrity sha1-BKEGZywYsIWrd02YPfo+oTjyIgU= + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +clap@^1.0.9: + version "1.2.3" + resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51" + integrity sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA== + dependencies: + chalk "^1.1.3" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +classnames@^2.2.5: + version "2.2.6" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" + integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== + +clean-css@4.2.x: + version "4.2.1" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17" + integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g== + dependencies: + source-map "~0.6.0" + +cli-boxes@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.0.tgz#538ecae8f9c6ca508e3c3c95b453fe93cb4c168d" + integrity sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w== + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +clone-response@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= + dependencies: + mimic-response "^1.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +clsx@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.0.4.tgz#0c0171f6d5cb2fe83848463c15fcc26b4df8c2ec" + integrity sha512-1mQ557MIZTrL/140j+JVdRM6e31/OA4vTYxXgqIIZlndyfjHpyawKZia1Im05Vp9BWmImkcNrNtFYQMyFcgJDg== + +coa@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" + integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== + dependencies: + "@types/q" "^1.5.1" + chalk "^2.4.1" + q "^1.1.2" + +coa@~1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.4.tgz#a9ef153660d6a86a8bdec0289a5c684d217432fd" + integrity sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0= + dependencies: + q "^1.1.2" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +codemirror@^5.49.2: + version "5.49.2" + resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.49.2.tgz#c84fdaf11b19803f828b0c67060c7bc6d154ccad" + integrity sha512-dwJ2HRPHm8w51WB5YTF9J7m6Z5dtkqbU9ntMZ1dqXyFB9IpjoUFDj80ahRVEoVanfIp6pfASJbOlbWdEf8FOzQ== + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.3.0, color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" + integrity sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE= + dependencies: + color-name "^1.0.0" + +color@^0.11.0: + version "0.11.4" + resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764" + integrity sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q= + dependencies: + clone "^1.0.2" + color-convert "^1.3.0" + color-string "^0.3.0" + +colormin@^1.0.5: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133" + integrity sha1-6i90IKcrlogaOKrlnsEkpvcpgTM= + dependencies: + color "^0.11.0" + css-color-names "0.0.4" + has "^1.0.1" + +colors@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM= + +commander@2.17.x: + version "2.17.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" + integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== + +commander@^2.19.0, commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@~2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" + integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +compressible@~2.0.16: + version "2.0.17" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1" + integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw== + dependencies: + mime-db ">= 1.40.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@1.6.2, concat-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +config-chain@^1.1.11: + version "1.1.12" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" + integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + +configstore@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-4.0.0.tgz#5933311e95d3687efb592c528b922d9262d227e7" + integrity sha512-CmquAXFBocrzaSM8mtGPMM/HiWmyIpr4CcJl/rgY2uCObZ/S7cKU0silxslqJejl+t/T9HS8E0PUNQD81JGUEQ== + dependencies: + dot-prop "^4.1.0" + graceful-fs "^4.1.2" + make-dir "^1.0.0" + unique-string "^1.0.0" + write-file-atomic "^2.0.0" + xdg-basedir "^3.0.0" + +connect-history-api-fallback@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" + integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== + +console-browserify@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-js-compat@^3.1.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.4.0.tgz#2a47c51d3dc026d290018cacd987495f68a47c75" + integrity sha512-pgQUcgT2+v9/yxHgMynYjNj7nmxLRXv3UC39rjCjDwpe63ev2rioQTju1PKLYUBbPCQQvZNWvQC8tBJd65q11g== + dependencies: + browserslist "^4.7.2" + semver "^6.3.0" + +core-js-compat@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.0.tgz#4eb6cb69d03d99159ed7c860cd5fcf7d23a62ea9" + integrity sha512-Z3eCNjGgoYluH89Jt4wVkfYsc/VdLrA2/woX5lm0isO/pCT+P+Y+o65bOuEnjDJLthdwTBxbCVzptTXtc18fJg== + dependencies: + browserslist "^4.8.2" + semver "7.0.0" + +core-js@^2.4.0: + version "2.6.10" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.10.tgz#8a5b8391f8cc7013da703411ce5b585706300d7f" + integrity sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA== + +core-js@^3.3.3: + version "3.4.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.4.0.tgz#29ea478601789c72f2978e9bb98f43546f89d3aa" + integrity sha512-lQxb4HScV71YugF/X28LtePZj9AB7WqOpcB+YztYxusvhrgZiQXPmCYfPC5LHsw/+ScEtDbXU3xbqH3CjBRmYA== + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +crocket@^0.9.11: + version "0.9.11" + resolved "https://registry.yarnpkg.com/crocket/-/crocket-0.9.11.tgz#288fca11ef0d3dd239b62c488265f30c8edfb0c5" + integrity sha1-KI/KEe8NPdI5tixIgmXzDI7fsMU= + dependencies: + xpipe "*" + +cross-spawn@6.0.5, cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-unzip@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/cross-unzip/-/cross-unzip-0.0.2.tgz#5183bc47a09559befcf98cc4657964999359372f" + integrity sha1-UYO8R6CVWb78+YzEZXlkmZNZNy8= + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +crypto-random-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= + +css-color-names@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= + +css-hot-loader@^1.4.4: + version "1.4.4" + resolved "https://registry.yarnpkg.com/css-hot-loader/-/css-hot-loader-1.4.4.tgz#ae784932cd8b7d092f7f15702af08b3ec9436052" + integrity sha512-J/qXHz+r7FOT92qMIJfxUk0LC9fecQNZVr0MswQ4FOpKLyOCBjofVMfc6R268bh/5ktkTShrweMr0wWqerC92g== + dependencies: + loader-utils "^1.1.0" + lodash "^4.17.5" + normalize-url "^1.9.1" + +css-loader@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.2.0.tgz#bb570d89c194f763627fcf1f80059c6832d009b2" + integrity sha512-QTF3Ud5H7DaZotgdcJjGMvyDj5F3Pn1j/sC6VBEOVp94cbwqyIBdcs/quzj4MC1BKQSrTpQznegH/5giYbhnCQ== + dependencies: + camelcase "^5.3.1" + cssesc "^3.0.0" + icss-utils "^4.1.1" + loader-utils "^1.2.3" + normalize-path "^3.0.0" + postcss "^7.0.17" + postcss-modules-extract-imports "^2.0.0" + postcss-modules-local-by-default "^3.0.2" + postcss-modules-scope "^2.1.0" + postcss-modules-values "^3.0.0" + postcss-value-parser "^4.0.0" + schema-utils "^2.0.0" + +css-loader@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.4.0.tgz#9fb263436783117a41d014e45e8eaeba54dd6670" + integrity sha512-JornYo4RAXl1Mzt0lOSVPmArzAMV3rGY2VuwtaDc732WTWjdwTaeS19nCGWMcSCf305Q396lhhDAJEWWM0SgPQ== + dependencies: + camelcase "^5.3.1" + cssesc "^3.0.0" + icss-utils "^4.1.1" + loader-utils "^1.2.3" + normalize-path "^3.0.0" + postcss "^7.0.23" + postcss-modules-extract-imports "^2.0.0" + postcss-modules-local-by-default "^3.0.2" + postcss-modules-scope "^2.1.1" + postcss-modules-values "^3.0.0" + postcss-value-parser "^4.0.2" + schema-utils "^2.6.0" + +css-select-base-adapter@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" + integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== + +css-select@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-select@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.0.2.tgz#ab4386cec9e1f668855564b17c3733b43b2a5ede" + integrity sha512-dSpYaDVoWaELjvZ3mS6IKZM/y2PMPa/XYoEfYNZePL4U/XgyxZNroHEHReDx/d+VgXh9VbCTtFqLkFbmeqeaRQ== + dependencies: + boolbase "^1.0.0" + css-what "^2.1.2" + domutils "^1.7.0" + nth-check "^1.0.2" + +css-tree@1.0.0-alpha.37: + version "1.0.0-alpha.37" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" + integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== + dependencies: + mdn-data "2.0.4" + source-map "^0.6.1" + +css-what@2.1, css-what@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" + integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssnano@^3.4.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38" + integrity sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg= + dependencies: + autoprefixer "^6.3.1" + decamelize "^1.1.2" + defined "^1.0.0" + has "^1.0.1" + object-assign "^4.0.1" + postcss "^5.0.14" + postcss-calc "^5.2.0" + postcss-colormin "^2.1.8" + postcss-convert-values "^2.3.4" + postcss-discard-comments "^2.0.4" + postcss-discard-duplicates "^2.0.1" + postcss-discard-empty "^2.0.1" + postcss-discard-overridden "^0.1.1" + postcss-discard-unused "^2.2.1" + postcss-filter-plugins "^2.0.0" + postcss-merge-idents "^2.1.5" + postcss-merge-longhand "^2.0.1" + postcss-merge-rules "^2.0.3" + postcss-minify-font-values "^1.0.2" + postcss-minify-gradients "^1.0.1" + postcss-minify-params "^1.0.4" + postcss-minify-selectors "^2.0.4" + postcss-normalize-charset "^1.1.0" + postcss-normalize-url "^3.0.7" + postcss-ordered-values "^2.1.0" + postcss-reduce-idents "^2.2.2" + postcss-reduce-initial "^1.0.0" + postcss-reduce-transforms "^1.0.3" + postcss-svgo "^2.1.1" + postcss-unique-selectors "^2.0.2" + postcss-value-parser "^3.2.3" + postcss-zindex "^2.0.1" + +csso@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/csso/-/csso-4.0.2.tgz#e5f81ab3a56b8eefb7f0092ce7279329f454de3d" + integrity sha512-kS7/oeNVXkHWxby5tHVxlhjizRCSv8QdU7hB2FpdAibDU8FjTAolhNjKNTiLzXtUrKT6HwClE81yXwEk1309wg== + dependencies: + css-tree "1.0.0-alpha.37" + +csso@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.2.tgz#ddd52c587033f49e94b71fc55569f252e8ff5f85" + integrity sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U= + dependencies: + clap "^1.0.9" + source-map "^0.5.3" + +csstype@^2.2.0, csstype@^2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.7.tgz#20b0024c20b6718f4eda3853a1f5a1cce7f5e4a5" + integrity sha512-9Mcn9sFbGBAdmimWb2gLVDtFJzeKtDGIr76TUqmjZrw9LFXBMSU70lcs+C0/7fyCd6iBDqmksUcCOUIkisPHsQ== + +cyclist@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" + integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.0.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0, debug@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +decamelize@^1.1.2, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + +deep-equal@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.0.tgz#3103cdf8ab6d32cf4a8df7865458f2b8d33f3745" + integrity sha512-ZbfWJq/wN1Z273o7mUSjILYqehAktR2NVoSrOukDkU9kg2v/Uv89yU4Cvz8seJeAmtN5oqiefKq8FPuXOboqLw== + dependencies: + is-arguments "^1.0.4" + is-date-object "^1.0.1" + is-regex "^1.0.4" + object-is "^1.0.1" + object-keys "^1.1.1" + regexp.prototype.flags "^1.2.0" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +default-gateway@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" + integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA== + dependencies: + execa "^1.0.0" + ip-regex "^2.1.0" + +defer-to-connect@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.0.tgz#b41bd7efa8508cef13f8456975f7a278c72833fd" + integrity sha512-WE2sZoctWm/v4smfCAdjYbrfS55JiMRdlY9ZubFhsYbteCK9+BvAx4YV7nPjYM6ZnX5BcoVKwfmyx9sIFTgQMQ== + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= + +del@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" + integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== + dependencies: + "@types/glob" "^7.1.1" + globby "^6.1.0" + is-path-cwd "^2.0.0" + is-path-in-cwd "^2.0.0" + p-map "^2.0.0" + pify "^4.0.1" + rimraf "^2.6.3" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-file@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + +detect-node@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" + integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dmg-builder@21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-21.2.0.tgz#a9c883557cacb9abdb66c7133b30fe921c1a3ba7" + integrity sha512-9cJEclnGy7EyKFCoHDYDf54pub/t92CQapyiUxU0w9Bj2vUvfoDagP1PMiX4XD5rPp96141h9A+QN0OB4VgvQg== + dependencies: + app-builder-lib "~21.2.0" + bluebird-lst "^1.0.9" + builder-util "~21.2.0" + fs-extra "^8.1.0" + iconv-lite "^0.5.0" + js-yaml "^3.13.1" + sanitize-filename "^1.6.2" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= + +dns-packet@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" + integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg== + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= + dependencies: + buffer-indexof "^1.0.0" + +dom-converter@^0.2: + version "0.2.0" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" + integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== + dependencies: + utila "~0.4" + +dom-helpers@^5.0.0: + version "5.1.3" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.1.3.tgz#7233248eb3a2d1f74aafca31e52c5299cc8ce821" + integrity sha512-nZD1OtwfWGRBWlpANxacBEZrEuLa16o1nh7YopFWeoF68Zt8GGEmzHu6Xv4F3XaFIC+YXtTLrzgqKxFgLEe4jw== + dependencies: + "@babel/runtime" "^7.6.3" + csstype "^2.6.7" + +dom-serializer@0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.1.tgz#13650c850daffea35d8b626a4cfc4d3a17643fdb" + integrity sha512-sK3ujri04WyjwQXVoK4PU3y8ula1stq10GJZpqHIUgoGZdsGzAGu65BnU3d08aTVSvO7mGPZUc0wTEDL+qGE0Q== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +dom-walk@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" + integrity sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg= + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +domelementtype@1, domelementtype@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d" + integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ== + +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== + dependencies: + domelementtype "1" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^1.5.1, domutils@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + +dot-prop@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ== + dependencies: + is-obj "^1.0.0" + +dotenv-expand@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" + integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== + +dotenv@^8.0.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" + integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +ejs@^2.6.2: + version "2.7.1" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.1.tgz#5b5ab57f718b79d4aca9254457afecd36fa80228" + integrity sha512-kS/gEPzZs3Y1rRsbGX4UOSjtP/CeJP0CxSNZHYxGfVM/VgLcv0ZqM7C45YyTj2DI2g7+P9Dd24C+IMIg6D0nYQ== + +electron-builder@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-21.2.0.tgz#b68ec4def713fc0b8602654ce842f972432f50c5" + integrity sha512-x8EXrqFbAb2L3N22YlGar3dGh8vwptbB3ovo3OF6K7NTpcsmM2zEoJv7GhFyX73rNzSG2HaWpXwGAtOp2JWiEw== + dependencies: + app-builder-lib "21.2.0" + bluebird-lst "^1.0.9" + builder-util "21.2.0" + builder-util-runtime "8.3.0" + chalk "^2.4.2" + dmg-builder "21.2.0" + fs-extra "^8.1.0" + is-ci "^2.0.0" + lazy-val "^1.0.4" + read-config-file "5.0.0" + sanitize-filename "^1.6.2" + update-notifier "^3.0.1" + yargs "^13.3.0" + +electron-devtools-installer@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/electron-devtools-installer/-/electron-devtools-installer-2.2.4.tgz#261a50337e37121d338b966f07922eb4939a8763" + integrity sha512-b5kcM3hmUqn64+RUcHjjr8ZMpHS2WJ5YO0pnG9+P/RTdx46of/JrEjuciHWux6pE+On6ynWhHJF53j/EDJN0PA== + dependencies: + "7zip" "0.0.6" + cross-unzip "0.0.2" + rimraf "^2.5.2" + semver "^5.3.0" + +electron-publish@21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-21.2.0.tgz#cc225cb46aa62e74b899f2f7299b396c9802387d" + integrity sha512-mWavuoWJe87iaeKd0I24dNWIaR+0yRzshjNVqGyK019H766fsPWl3caQJnVKFaEyrZRP397v4JZVG0e7s16AxA== + dependencies: + bluebird-lst "^1.0.9" + builder-util "~21.2.0" + builder-util-runtime "8.3.0" + chalk "^2.4.2" + fs-extra "^8.1.0" + lazy-val "^1.0.4" + mime "^2.4.4" + +electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.295: + version "1.3.306" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.306.tgz#e8265301d053d5f74e36cb876486830261fbe946" + integrity sha512-frDqXvrIROoYvikSKTIKbHbzO6M3/qC6kCIt/1FOa9kALe++c4VAJnwjSFvf1tYLEUsP2n9XZ4XSCyqc3l7A/A== + +electron-to-chromium@^1.3.322: + version "1.3.322" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz#a6f7e1c79025c2b05838e8e344f6e89eb83213a8" + integrity sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA== + +electron-webpack-js@~2.3.2: + version "2.3.4" + resolved "https://registry.yarnpkg.com/electron-webpack-js/-/electron-webpack-js-2.3.4.tgz#f1ffb076530559e48dd5e1b961e8e5be299a5b6c" + integrity sha512-lHP/hqNFkf7WXuo5ABfcpbm920cQdymNI2DnTHH1ZqizJMZE8dPCAn6VVZiY95Z8l5bN9qFz8idKCfuQMN5NCQ== + dependencies: + "@babel/core" "^7.5.0" + "@babel/plugin-syntax-dynamic-import" "^7.2.0" + "@babel/preset-env" "^7.5.3" + babel-loader "^8.0.6" + babel-plugin-component "^1.1.1" + +electron-webpack@^2.7.4: + version "2.7.4" + resolved "https://registry.yarnpkg.com/electron-webpack/-/electron-webpack-2.7.4.tgz#f1deed156375fbd846ee718bfc9ccf93a2e27207" + integrity sha512-0278nUbG4bANuvrWpLq/CYKJhGwR1gzhAI5IInasbAV8FVA3PyAvu/KMZCZLuVbTxGmWStPg2pdLf1a9alfLCQ== + dependencies: + "@types/webpack-env" "^1.13.9" + async-exit-hook "^2.0.1" + bluebird "^3.5.5" + chalk "^2.4.2" + crocket "^0.9.11" + css-hot-loader "^1.4.4" + css-loader "^3.0.0" + debug "^4.1.1" + dotenv "^8.0.0" + dotenv-expand "^5.1.0" + electron-devtools-installer "^2.2.4" + electron-webpack-js "~2.3.2" + file-loader "^4.0.0" + fs-extra "^8.1.0" + html-loader "^1.0.0-alpha.0" + html-webpack-plugin "^3.2.0" + lazy-val "^1.0.4" + mini-css-extract-plugin "^0.7.0" + node-loader "^0.6.0" + read-config-file "^4.0.1" + semver "^6.2.0" + source-map-support "^0.5.12" + style-loader "^0.23.1" + terser-webpack-plugin "^1.3.0" + url-loader "^2.0.1" + webpack-cli "^3.3.5" + webpack-dev-server "^3.7.2" + webpack-merge "^4.2.1" + yargs "^13.2.4" + +electron@^7: + version "7.1.1" + resolved "https://registry.yarnpkg.com/electron/-/electron-7.1.1.tgz#98be17d850e64689a09ab6dd1e437b36307f2fcf" + integrity sha512-NJPv4SuMJlRUtXBd/Ey9XKSLOZ4+hxsOrHHPXwrBQNNdeZesoSrTMgPymee/FwMRtrSt0Pz8NccEZUu/pxmbhQ== + dependencies: + "@electron/get" "^1.0.1" + "@types/node" "^12.0.12" + extract-zip "^1.0.3" + +elliptic@^6.0.0: + version "6.5.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.1.tgz#c380f5f909bf1b9b4428d028cd18d3b0efd6b52b" + integrity sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg== + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= + +encodeurl@^1.0.2, encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" + integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + tapable "^1.0.0" + +enhanced-resolve@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66" + integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.5.0" + tapable "^1.0.0" + +entities@^1.1.1, entities@~1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + +entities@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" + integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== + +env-paths@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43" + integrity sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA== + +errno@^0.1.3, errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== + dependencies: + prr "~1.0.1" + +es-abstract@^1.12.0, es-abstract@^1.5.1: + version "1.16.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.0.tgz#d3a26dc9c3283ac9750dca569586e976d9dcc06d" + integrity sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg== + dependencies: + es-to-primitive "^1.2.0" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.0" + is-callable "^1.1.4" + is-regex "^1.0.4" + object-inspect "^1.6.0" + object-keys "^1.1.1" + string.prototype.trimleft "^2.1.0" + string.prototype.trimright "^2.1.0" + +es-to-primitive@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" + integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es6-error@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" + integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +esprima@^2.6.0: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== + dependencies: + estraverse "^4.1.0" + +estraverse@^4.1.0, estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +esutils@^2.0.0, esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +eventemitter3@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" + integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== + +events@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" + integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA== + +eventsource@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" + integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== + dependencies: + original "^1.0.0" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= + dependencies: + homedir-polyfill "^1.0.1" + +express@^4.17.1: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extract-zip@^1.0.3: + version "1.6.7" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9" + integrity sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k= + dependencies: + concat-stream "1.6.2" + debug "2.6.9" + mkdirp "0.5.1" + yauzl "2.4.1" + +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +faye-websocket@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= + dependencies: + websocket-driver ">=0.5.1" + +faye-websocket@~0.11.1: + version "0.11.3" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e" + integrity sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA== + dependencies: + websocket-driver ">=0.5.1" + +fd-slicer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + integrity sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU= + dependencies: + pend "~1.2.0" + +figgy-pudding@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" + integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== + +file-loader@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-4.2.0.tgz#5fb124d2369d7075d70a9a5abecd12e60a95215e" + integrity sha512-+xZnaK5R8kBJrHK0/6HRlrKNamvVS5rjyuju+rnyxRGuwUJwpAMsVzUl5dz6rK8brkzjV6JpcFNjp6NqV0g1OQ== + dependencies: + loader-utils "^1.2.3" + schema-utils "^2.0.0" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +findup-sync@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" + integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg== + dependencies: + detect-file "^1.0.0" + is-glob "^4.0.0" + micromatch "^3.0.4" + resolve-dir "^1.0.1" + +flatten@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b" + integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== + +flush-write-stream@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" + +follow-redirects@^1.0.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.9.0.tgz#8d5bcdc65b7108fe1508649c79c12d732dcedb4f" + integrity sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A== + dependencies: + debug "^3.0.0" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-minipass@^1.2.5: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== + dependencies: + minipass "^2.6.0" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.7: + version "1.2.9" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" + integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== + dependencies: + nan "^2.12.1" + node-pre-gyp "^0.12.0" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-stream@^4.0.0, get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" + integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob@^7.0.3, glob@^7.1.3, glob@^7.1.4: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-agent@^2.0.2: + version "2.1.5" + resolved "https://registry.yarnpkg.com/global-agent/-/global-agent-2.1.5.tgz#0e9b8367f7068bb6fa360a8f920499e1d873762f" + integrity sha512-pYJjCxxNBzYxo6iNO62JZn8iCFVbvpiM0zE4w/G5hBNIvLjnvzIeCVQPMKc3aK8ju5L7Q8NNI/oBSosU0eeSYw== + dependencies: + boolean "^2.0.2" + core-js "^3.3.3" + es6-error "^4.1.1" + matcher "^2.0.0" + roarr "^2.14.2" + semver "^6.3.0" + serialize-error "^5.0.0" + +global-dirs@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" + integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= + dependencies: + ini "^1.3.4" + +global-modules@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +global-tunnel-ng@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz#d03b5102dfde3a69914f5ee7d86761ca35d57d8f" + integrity sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg== + dependencies: + encodeurl "^1.0.2" + lodash "^4.17.10" + npm-conf "^1.1.3" + tunnel "^0.0.6" + +global@^4.3.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" + integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== + dependencies: + min-document "^2.19.0" + process "^0.11.10" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globalthis@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.0.tgz#c5fb98213a9b4595f59cf3e7074f141b4169daae" + integrity sha512-vcCAZTJ3r5Qcu5l8/2oyVdoFwxKgfYnMTR2vwWeux/NAVZK3PwcMaWkdUIn4GJbmKuRK7xcvDsLuK+CKcXyodg== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + object-keys "^1.0.12" + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +got@^9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" + integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== + +handle-thing@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" + integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has-yarn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" + integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== + +has@^1.0.1, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +he@1.2.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hoist-non-react-statics@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b" + integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA== + dependencies: + react-is "^16.7.0" + +homedir-polyfill@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" + integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== + dependencies: + parse-passwd "^1.0.0" + +hosted-git-info@^2.1.4, hosted-git-info@^2.7.1: + version "2.8.5" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c" + integrity sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg== + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-comment-regex@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" + integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== + +html-entities@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" + integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= + +html-loader@^1.0.0-alpha.0: + version "1.0.0-alpha.0" + resolved "https://registry.yarnpkg.com/html-loader/-/html-loader-1.0.0-alpha.0.tgz#3f4ae7b490a587619be6d1eaa8ce16683580c642" + integrity sha512-KcuaIRWTU0kFjOJCs32a3JsGNCWkeOak0/F/uvJNp3x/N4McXdqHpcK64cYTozK7QLPKKtUqb9h7wR9K9rYRkg== + dependencies: + "@posthtml/esm" "^1.0.0" + htmlnano "^0.1.6" + loader-utils "^1.1.0" + posthtml "^0.11.2" + schema-utils "^0.4.3" + +html-minifier@^3.2.3: + version "3.5.21" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c" + integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA== + dependencies: + camel-case "3.0.x" + clean-css "4.2.x" + commander "2.17.x" + he "1.2.x" + param-case "2.1.x" + relateurl "0.2.x" + uglify-js "3.4.x" + +html-webpack-plugin@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz#b01abbd723acaaa7b37b6af4492ebda03d9dd37b" + integrity sha1-sBq71yOsqqeze2r0SS69oD2d03s= + dependencies: + html-minifier "^3.2.3" + loader-utils "^0.2.16" + lodash "^4.17.3" + pretty-error "^2.0.2" + tapable "^1.0.0" + toposort "^1.0.0" + util.promisify "1.0.0" + +htmlnano@^0.1.6: + version "0.1.10" + resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-0.1.10.tgz#a0a548eb4c76ae2cf2423ec7a25c881734d3dea6" + integrity sha512-eTEUzz8VdWYp+w/KUdb99kwao4reR64epUySyZkQeepcyzPQ2n2EPWzibf6QDxmkGy10Kr+CKxYqI3izSbmhJQ== + dependencies: + cssnano "^3.4.0" + object-assign "^4.0.1" + posthtml "^0.11.3" + posthtml-render "^1.1.4" + svgo "^1.0.5" + terser "^3.8.1" + +htmlparser2@^3.3.0, htmlparser2@^3.9.2: + version "3.10.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" + integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== + dependencies: + domelementtype "^1.3.1" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^3.1.1" + +http-cache-semantics@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz#495704773277eeef6e43f9ab2c2c7d259dda25c5" + integrity sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew== + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +"http-parser-js@>=0.4.0 <0.4.11": + version "0.4.10" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4" + integrity sha1-ksnBN0w1CF912zWexWzCV8u5P6Q= + +http-proxy-middleware@0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" + integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== + dependencies: + http-proxy "^1.17.0" + is-glob "^4.0.0" + lodash "^4.17.11" + micromatch "^3.1.10" + +http-proxy@^1.17.0: + version "1.18.0" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a" + integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +iconv-lite@0.4.24, iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.5.0.tgz#59cdde0a2a297cc2aeb0c6445a195ee89f127550" + integrity sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +icss-utils@^4.0.0, icss-utils@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" + integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== + dependencies: + postcss "^7.0.14" + +ieee754@^1.1.4: + version "1.1.13" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= + +ignore-walk@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" + integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== + dependencies: + minimatch "^3.0.4" + +immutable@^4.0.0-rc.12: + version "4.0.0-rc.12" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0-rc.12.tgz#ca59a7e4c19ae8d9bf74a97bdf0f6e2f2a5d0217" + integrity sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A== + +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" + integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= + +import-local@2.0.0, import-local@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= + +infer-owner@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +internal-ip@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" + integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg== + dependencies: + default-gateway "^4.2.0" + ipaddr.js "^1.9.0" + +interpret@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" + integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== + +invariant@^2.2.2: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + +ip@^1.1.0, ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +ipaddr.js@1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" + integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== + +ipaddr.js@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-absolute-url@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" + integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= + +is-absolute-url@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" + integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arguments@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3" + integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA== + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-installed-globally@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" + integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA= + dependencies: + global-dirs "^0.1.0" + is-path-inside "^1.0.0" + +is-npm@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-3.0.0.tgz#ec9147bfb629c43f494cf67936a961edec7e8053" + integrity sha512-wsigDr1Kkschp2opC4G3yA6r9EgVA6NjRpWzIi9axXqeIaAATPRJc4uLujXe3Nd9uO8KoDyA4MD6aZSeXTADhA== + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= + +is-path-cwd@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-in-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" + integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== + dependencies: + is-path-inside "^2.1.0" + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= + dependencies: + path-is-inside "^1.0.1" + +is-path-inside@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" + integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== + dependencies: + path-is-inside "^1.0.2" + +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= + dependencies: + has "^1.0.1" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-svg@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9" + integrity sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk= + dependencies: + html-comment-regex "^1.1.0" + +is-symbol@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" + integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== + dependencies: + has-symbols "^1.0.0" + +is-windows@^1.0.1, is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +is-yarn-global@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" + integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isbinaryfile@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.2.tgz#bfc45642da645681c610cca831022e30af426488" + integrity sha512-C3FSxJdNrEr2F4z6uFtNzECDM5hXk+46fxaa+cwBe5/XrWSmzdG8DDgyjfX6/NRdBB21q2JXuRAzPCUs+fclnQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +js-base64@^2.1.9: + version "2.5.1" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121" + integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw== + +js-levenshtein@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" + integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@~3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" + integrity sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A= + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +js2xmlparser@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js2xmlparser/-/js2xmlparser-4.0.0.tgz#ae14cc711b2892083eed6e219fbc993d858bc3a5" + integrity sha512-WuNgdZOXVmBk5kUPMcTcVUpbGRzLfNkv7+7APq7WiDihpXVKrgxo6wwRpRl9OQeEBgKCVk9mR7RbzrnNWC8oBw== + dependencies: + xmlcreate "^2.0.0" + +jsdoc@^3.6.3: + version "3.6.3" + resolved "https://registry.yarnpkg.com/jsdoc/-/jsdoc-3.6.3.tgz#dccea97d0e62d63d306b8b3ed1527173b5e2190d" + integrity sha512-Yf1ZKA3r9nvtMWHO1kEuMZTlHOF8uoQ0vyo5eH7SQy5YeIiHM+B0DgKnn+X6y6KDYZcF7G2SPkKF+JORCXWE/A== + dependencies: + "@babel/parser" "^7.4.4" + bluebird "^3.5.4" + catharsis "^0.8.11" + escape-string-regexp "^2.0.0" + js2xmlparser "^4.0.0" + klaw "^3.0.0" + markdown-it "^8.4.2" + markdown-it-anchor "^5.0.2" + marked "^0.7.0" + mkdirp "^0.5.1" + requizzle "^0.2.3" + strip-json-comments "^3.0.1" + taffydb "2.6.2" + underscore "~1.9.1" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= + +json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stringify-safe@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json3@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" + integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== + +json5@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.1.tgz#81b6cb04e9ba496f1c7005d07b4368a2638f90b6" + integrity sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ== + dependencies: + minimist "^1.2.0" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + +killable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" + integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + +klaw@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146" + integrity sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g== + dependencies: + graceful-fs "^4.1.9" + +latest-version@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" + integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== + dependencies: + package-json "^6.3.0" + +lazy-val@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.4.tgz#882636a7245c2cfe6e0a4e3ba6c5d68a137e5c65" + integrity sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q== + +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== + dependencies: + invert-kv "^2.0.0" + +linkify-it@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf" + integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw== + dependencies: + uc.micro "^1.0.1" + +loader-runner@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" + integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== + +loader-utils@1.2.3, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== + dependencies: + big.js "^5.2.2" + emojis-list "^2.0.0" + json5 "^1.0.1" + +loader-utils@^0.2.16: + version "0.2.17" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" + integrity sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g= + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + object-assign "^4.0.1" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.3, lodash@^4.17.5, lodash@^4.2.0: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +loglevel@^1.6.4: + version "1.6.6" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.6.tgz#0ee6300cc058db6b3551fa1c4bf73b83bb771312" + integrity sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ== + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lower-case@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" + integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= + +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== + dependencies: + pify "^3.0.0" + +make-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +mamacro@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" + integrity sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA== + +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +markdown-it-anchor@^5.0.2: + version "5.2.5" + resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-5.2.5.tgz#dbf13cfcdbffd16a510984f1263e1d479a47d27a" + integrity sha512-xLIjLQmtym3QpoY9llBgApknl7pxAcN3WDRc2d3rwpl+/YvDZHPmKscGs+L6E05xf2KrCXPBvosWt7MZukwSpQ== + +markdown-it@^8.4.2: + version "8.4.2" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54" + integrity sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ== + dependencies: + argparse "^1.0.7" + entities "~1.1.1" + linkify-it "^2.0.0" + mdurl "^1.0.1" + uc.micro "^1.0.5" + +marked@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/marked/-/marked-0.7.0.tgz#b64201f051d271b1edc10a04d1ae9b74bb8e5c0e" + integrity sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg== + +matcher@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/matcher/-/matcher-2.0.0.tgz#85fe38d97670dbd2a46590cf099401e2ffb4755c" + integrity sha512-nlmfSlgHBFx36j/Pl/KQPbIaqE8Zf0TqmSMjsuddHDg6PMSVgmyW9HpkLs0o0M1n2GIZ/S2BZBLIww/xjhiGng== + dependencies: + escape-string-regexp "^2.0.0" + +math-expression-evaluator@^1.2.14: + version "1.2.17" + resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac" + integrity sha1-3oGf282E3M2PrlnGrreWFbnSZqw= + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +mdn-data@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" + integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== + +mdurl@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + +memory-fs@^0.4.0, memory-fs@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +memory-fs@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" + integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.40.0: + version "1.40.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" + integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== + +"mime-db@>= 1.40.0 < 2": + version "1.42.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac" + integrity sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ== + +mime-types@~2.1.17, mime-types@~2.1.24: + version "2.1.24" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" + integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== + dependencies: + mime-db "1.40.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.4.4: + version "2.4.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" + integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== + +mimic-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-response@^1.0.0, mimic-response@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= + dependencies: + dom-walk "^0.1.0" + +mini-css-extract-plugin@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.7.0.tgz#5ba8290fbb4179a43dd27cca444ba150bee743a0" + integrity sha512-RQIw6+7utTYn8DBGsf/LpRgZCJMpZt+kuawJ/fju0KiOL6nAaTBNmCJwS7HtwSCXfS47gCkmtBFS7HdsquhdxQ== + dependencies: + loader-utils "^1.1.0" + normalize-url "1.9.1" + schema-utils "^1.0.0" + webpack-sources "^1.1.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.2.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== + dependencies: + minipass "^2.9.0" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + +nan@^2.12.1: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +needle@^2.2.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" + integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +neo-async@^2.5.0, neo-async@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" + integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +no-case@^2.2.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" + integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== + dependencies: + lower-case "^1.1.1" + +node-forge@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" + integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ== + +node-gyp-build@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.0.tgz#2c2b05f461f4178641a6ce2d7159f04094e9376d" + integrity sha512-4oiumOLhCDU9Rronz8PZ5S4IvT39H5+JEv/hps9V8s7RSLhsac0TCP78ulnHXOo8X1wdpPiTayGlM1jr4IbnaQ== + +node-libs-browser@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" + integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^3.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.1" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.11.0" + vm-browserify "^1.0.1" + +node-loader@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/node-loader/-/node-loader-0.6.0.tgz#c797ef51095ed5859902b157f6384f6361e05ae8" + integrity sha1-x5fvUQle1YWZArFX9jhPY2HgWug= + +node-pre-gyp@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" + integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +node-releases@^1.1.38: + version "1.1.39" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.39.tgz#c1011f30343aff5b633153b10ff691d278d08e8d" + integrity sha512-8MRC/ErwNCHOlAFycy9OPca46fQYUjbJRDcZTHVWIGXIjYLM73k70vv3WkYutVnM4cCo4hE0MqBVVZjP6vjISA== + dependencies: + semver "^6.3.0" + +node-releases@^1.1.42: + version "1.1.42" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.42.tgz#a999f6a62f8746981f6da90627a8d2fc090bbad7" + integrity sha512-OQ/ESmUqGawI2PRX+XIRao44qWYBBfN54ImQYdWVTQqUckuejOg76ysSqDBK8NG3zwySRVnX36JwDQ6x+9GxzA== + dependencies: + semver "^6.3.0" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +normalize-url@1.9.1, normalize-url@^1.4.0, normalize-url@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" + integrity sha1-LMDWazHqIwNkWENuNiDYWVTGbDw= + dependencies: + object-assign "^4.0.1" + prepend-http "^1.0.0" + query-string "^4.1.0" + sort-keys "^1.0.0" + +normalize-url@^4.1.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" + integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== + +npm-bundled@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" + integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== + +npm-conf@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" + integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw== + dependencies: + config-chain "^1.1.11" + pify "^3.0.0" + +npm-packlist@^1.1.6: + version "1.4.6" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.6.tgz#53ba3ed11f8523079f1457376dd379ee4ea42ff4" + integrity sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +nth-check@^1.0.2, nth-check@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" + integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== + +object-is@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6" + integrity sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY= + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +object.values@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.0.tgz#bf6810ef5da3e5325790eaaa2be213ea84624da9" + integrity sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.12.0" + function-bind "^1.1.1" + has "^1.0.3" + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +opn@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" + integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== + dependencies: + is-wsl "^1.1.0" + +original@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== + dependencies: + url-parse "^1.4.3" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-locale@^3.0.0, os-locale@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + +os-tmpdir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== + +p-limit@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" + integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-retry@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" + integrity sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w== + dependencies: + retry "^0.12.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-json@^6.3.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" + integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== + dependencies: + got "^9.6.0" + registry-auth-token "^4.0.0" + registry-url "^5.0.0" + semver "^6.2.0" + +pako@~1.0.5: + version "1.0.10" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732" + integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw== + +parallel-transform@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" + integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== + dependencies: + cyclist "^1.0.1" + inherits "^2.0.3" + readable-stream "^2.1.5" + +param-case@2.1.x: + version "2.1.1" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" + integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc= + dependencies: + no-case "^2.2.0" + +parse-asn1@^5.0.0: + version "5.1.5" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e" + integrity sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ== + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@^1.0.1, path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +pbkdf2@^3.0.3: + version "3.0.17" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" + integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +portfinder@^1.0.25: + version "1.0.25" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.25.tgz#254fd337ffba869f4b9d37edc298059cb4d35eca" + integrity sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg== + dependencies: + async "^2.6.2" + debug "^3.1.1" + mkdirp "^0.5.1" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +postcss-calc@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e" + integrity sha1-d7rnypKK2FcW4v2kLyYb98HWW14= + dependencies: + postcss "^5.0.2" + postcss-message-helpers "^2.0.0" + reduce-css-calc "^1.2.6" + +postcss-colormin@^2.1.8: + version "2.2.2" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b" + integrity sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks= + dependencies: + colormin "^1.0.5" + postcss "^5.0.13" + postcss-value-parser "^3.2.3" + +postcss-convert-values@^2.3.4: + version "2.6.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d" + integrity sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0= + dependencies: + postcss "^5.0.11" + postcss-value-parser "^3.1.2" + +postcss-discard-comments@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d" + integrity sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0= + dependencies: + postcss "^5.0.14" + +postcss-discard-duplicates@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz#b9abf27b88ac188158a5eb12abcae20263b91932" + integrity sha1-uavye4isGIFYpesSq8riAmO5GTI= + dependencies: + postcss "^5.0.4" + +postcss-discard-empty@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5" + integrity sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU= + dependencies: + postcss "^5.0.14" + +postcss-discard-overridden@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58" + integrity sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg= + dependencies: + postcss "^5.0.16" + +postcss-discard-unused@^2.2.1: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433" + integrity sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM= + dependencies: + postcss "^5.0.14" + uniqs "^2.0.0" + +postcss-filter-plugins@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz#82245fdf82337041645e477114d8e593aa18b8ec" + integrity sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ== + dependencies: + postcss "^5.0.4" + +postcss-merge-idents@^2.1.5: + version "2.1.7" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270" + integrity sha1-TFUwMTwI4dWzu/PSu8dH4njuonA= + dependencies: + has "^1.0.1" + postcss "^5.0.10" + postcss-value-parser "^3.1.1" + +postcss-merge-longhand@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658" + integrity sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg= + dependencies: + postcss "^5.0.4" + +postcss-merge-rules@^2.0.3: + version "2.1.2" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721" + integrity sha1-0d9d+qexrMO+VT8OnhDofGG19yE= + dependencies: + browserslist "^1.5.2" + caniuse-api "^1.5.2" + postcss "^5.0.4" + postcss-selector-parser "^2.2.2" + vendors "^1.0.0" + +postcss-message-helpers@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" + integrity sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4= + +postcss-minify-font-values@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69" + integrity sha1-S1jttWZB66fIR0qzUmyv17vey2k= + dependencies: + object-assign "^4.0.1" + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-minify-gradients@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1" + integrity sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE= + dependencies: + postcss "^5.0.12" + postcss-value-parser "^3.3.0" + +postcss-minify-params@^1.0.4: + version "1.2.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3" + integrity sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM= + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.2" + postcss-value-parser "^3.0.2" + uniqs "^2.0.0" + +postcss-minify-selectors@^2.0.4: + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf" + integrity sha1-ssapjAByz5G5MtGkllCBFDEXNb8= + dependencies: + alphanum-sort "^1.0.2" + has "^1.0.1" + postcss "^5.0.14" + postcss-selector-parser "^2.0.0" + +postcss-modules-extract-imports@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" + integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== + dependencies: + postcss "^7.0.5" + +postcss-modules-local-by-default@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz#e8a6561be914aaf3c052876377524ca90dbb7915" + integrity sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ== + dependencies: + icss-utils "^4.1.1" + postcss "^7.0.16" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.0.0" + +postcss-modules-scope@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz#ad3f5bf7856114f6fcab901b0502e2a2bc39d4eb" + integrity sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" + +postcss-modules-scope@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.1.tgz#33d4fc946602eb5e9355c4165d68a10727689dba" + integrity sha512-OXRUPecnHCg8b9xWvldG/jUpRIGPNRka0r4D4j0ESUU2/5IOnpsjfPPmDprM3Ih8CgZ8FXjWqaniK5v4rWt3oQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" + +postcss-modules-values@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" + integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg== + dependencies: + icss-utils "^4.0.0" + postcss "^7.0.6" + +postcss-normalize-charset@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1" + integrity sha1-757nEhLX/nWceO0WL2HtYrXLk/E= + dependencies: + postcss "^5.0.5" + +postcss-normalize-url@^3.0.7: + version "3.0.8" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222" + integrity sha1-EI90s/L82viRov+j6kWSJ5/HgiI= + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^1.4.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + +postcss-ordered-values@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d" + integrity sha1-7sbCpntsQSqNsgQud/6NpD+VwR0= + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.1" + +postcss-reduce-idents@^2.2.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3" + integrity sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM= + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-reduce-initial@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea" + integrity sha1-aPgGlfBF0IJjqHmtJA343WT2ROo= + dependencies: + postcss "^5.0.4" + +postcss-reduce-transforms@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1" + integrity sha1-/3b02CEkN7McKYpC0uFEQCV3GuE= + dependencies: + has "^1.0.1" + postcss "^5.0.8" + postcss-value-parser "^3.0.1" + +postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90" + integrity sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A= + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" + integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== + dependencies: + cssesc "^3.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-svgo@^2.1.1: + version "2.1.6" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d" + integrity sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0= + dependencies: + is-svg "^2.0.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + svgo "^0.7.0" + +postcss-unique-selectors@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d" + integrity sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0= + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + +postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz#482282c09a42706d1fc9a069b73f44ec08391dc9" + integrity sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ== + +postcss-zindex@^2.0.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22" + integrity sha1-0hCd3AVbka9n/EyzsCWUZjnSryI= + dependencies: + has "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.8, postcss@^5.2.16: + version "5.2.18" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5" + integrity sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg== + dependencies: + chalk "^1.1.3" + js-base64 "^2.1.9" + source-map "^0.5.6" + supports-color "^3.2.3" + +postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.21" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.21.tgz#06bb07824c19c2021c5d056d5b10c35b989f7e17" + integrity sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +postcss@^7.0.23: + version "7.0.23" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.23.tgz#9f9759fad661b15964f3cfc3140f66f1e05eadc1" + integrity sha512-hOlMf3ouRIFXD+j2VJecwssTwbvsPGJVMzupptg+85WA+i7MwyrydmQAgY3R+m0Bc0exunhbJmijy8u8+vufuQ== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +posthtml-parser@^0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.4.2.tgz#a132bbdf0cd4bc199d34f322f5c1599385d7c6c1" + integrity sha512-BUIorsYJTvS9UhXxPTzupIztOMVNPa/HtAm9KHni9z6qEfiJ1bpOBL5DfUOL9XAc3XkLIEzBzpph+Zbm4AdRAg== + dependencies: + htmlparser2 "^3.9.2" + +posthtml-render@^1.1.4, posthtml-render@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-1.1.5.tgz#387934e85438a3de77085fbc7d264efb00bd0e0f" + integrity sha512-yvt54j0zCBHQVEFAuR+yHld8CZrCa/E1Z/OcFNCV1IEWTLVxT8O7nYnM4IIw1CD4r8kaRd3lc42+0lgCKgm87w== + +posthtml@^0.11.2, posthtml@^0.11.3: + version "0.11.6" + resolved "https://registry.yarnpkg.com/posthtml/-/posthtml-0.11.6.tgz#e349d51af7929d0683b9d8c3abd8166beecc90a8" + integrity sha512-C2hrAPzmRdpuL3iH0TDdQ6XCc9M7Dcc3zEW5BLerY65G4tWWszwv6nG/ksi6ul5i2mx22ubdljgktXCtNkydkw== + dependencies: + posthtml-parser "^0.4.1" + posthtml-render "^1.1.5" + +prepend-http@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + +pretty-error@^2.0.2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3" + integrity sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM= + dependencies: + renderkid "^2.0.1" + utila "~0.4" + +private@^0.1.6: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= + +proxy-addr@~2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" + integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.0" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.2.4: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +q@^1.1.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + +query-string@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" + integrity sha1-u7aTucqRXCMlFbIosaArYJBD2+s= + dependencies: + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +querystringify@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" + integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +rc@^1.2.7, rc@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-dom@^16.12.0: + version "16.12.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.12.0.tgz#0da4b714b8d13c2038c9396b54a92baea633fe11" + integrity sha512-LMxFfAGrcS3kETtQaCkTKjMiifahaMySFDn71fZUNpPHZQEzmk/GiAeIT8JSOrHB23fnuCOMruL2a8NYlw+8Gw== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.18.0" + +react-draggable@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.2.0.tgz#40cc5209082ca7d613104bf6daf31372cc0e1114" + integrity sha512-5wFq//gEoeTYprnd4ze8GrFc+Rbnx+9RkOMR3vk4EbWxj02U6L6T3yrlKeiw4X5CtjD2ma2+b3WujghcXNRzkw== + dependencies: + classnames "^2.2.5" + prop-types "^15.6.0" + +react-hot-loader@^4.12.18: + version "4.12.18" + resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.12.18.tgz#a9029e34af2690d76208f9a35189d73c2dfea6a7" + integrity sha512-qYD0Qi9lIbg9jLyfmodfqvAQqCBsoPKxAhca8Nxvy2/2pO5Q9r2kM28jN0bbbSnhwK8dJ7FjsfVtXKOxMW+bqw== + dependencies: + fast-levenshtein "^2.0.6" + global "^4.3.0" + hoist-non-react-statics "^3.3.0" + loader-utils "^1.1.0" + prop-types "^15.6.1" + react-lifecycles-compat "^3.0.4" + shallowequal "^1.1.0" + source-map "^0.7.3" + +react-is@^16.7.0, react-is@^16.8.1: + version "16.11.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.11.0.tgz#b85dfecd48ad1ce469ff558a882ca8e8313928fa" + integrity sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw== + +react-lifecycles-compat@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-virtualized@^9.21.2: + version "9.21.2" + resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.21.2.tgz#02e6df65c1e020c8dbf574ec4ce971652afca84e" + integrity sha512-oX7I7KYiUM7lVXQzmhtF4Xg/4UA5duSA+/ZcAvdWlTLFCoFYq1SbauJT5gZK9cZS/wdYR6TPGpX/dqzvTqQeBA== + dependencies: + babel-runtime "^6.26.0" + clsx "^1.0.1" + dom-helpers "^5.0.0" + loose-envify "^1.3.0" + prop-types "^15.6.0" + react-lifecycles-compat "^3.0.4" + +react@^16.8: + version "16.11.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.11.0.tgz#d294545fe62299ccee83363599bf904e4a07fdbb" + integrity sha512-M5Y8yITaLmU0ynd0r1Yvfq98Rmll6q8AxaEe88c8e7LxO8fZ2cNgmFt0aGAS9wzf1Ao32NKXtCl+/tVVtkxq6g== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + +read-config-file@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/read-config-file/-/read-config-file-5.0.0.tgz#1487c983fae9c1b672d3acda5cac899a2d451f02" + integrity sha512-jIKUu+C84bfnKxyJ5j30CxCqgXWYjZLXuVE/NYlMEpeni+dhESgAeZOZd0JZbg1xTkMmnCdxksDoarkOyfEsOg== + dependencies: + dotenv "^8.0.0" + dotenv-expand "^5.1.0" + fs-extra "^8.1.0" + js-yaml "^3.13.1" + json5 "^2.1.0" + lazy-val "^1.0.4" + +read-config-file@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/read-config-file/-/read-config-file-4.0.1.tgz#ece5f6b1a5e6a46d0d93fdd0339f2f60ab892776" + integrity sha512-5caED3uo2IAZMPcbh/9hx/O29s2430RLxtnFDdzxpH/epEpawOrQnGBHueotIXUrGPPIgdNQN+S/CIp2WmiSfw== + dependencies: + ajv "^6.10.1" + ajv-keywords "^3.4.1" + dotenv "^8.0.0" + dotenv-expand "^5.1.0" + fs-extra "^8.1.0" + js-yaml "^3.13.1" + json5 "^2.1.0" + lazy-val "^1.0.4" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6, readable-stream@^3.1.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" + integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +reduce-css-calc@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" + integrity sha1-dHyRTgSWFKTJz7umKYca0dKSdxY= + dependencies: + balanced-match "^0.4.2" + math-expression-evaluator "^1.2.14" + reduce-function-call "^1.0.1" + +reduce-function-call@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.3.tgz#60350f7fb252c0a67eb10fd4694d16909971300f" + integrity sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ== + dependencies: + balanced-match "^1.0.0" + +regenerate-unicode-properties@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" + integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA== + dependencies: + regenerate "^1.4.0" + +regenerate@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + +regenerator-runtime@^0.13.2: + version "0.13.3" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" + integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== + +regenerator-transform@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb" + integrity sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ== + dependencies: + private "^0.1.6" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexp.prototype.flags@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz#6b30724e306a27833eeb171b66ac8890ba37e41c" + integrity sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA== + dependencies: + define-properties "^1.1.2" + +regexpu-core@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6" + integrity sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.1.0" + regjsgen "^0.5.0" + regjsparser "^0.6.0" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.1.0" + +registry-auth-token@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.0.0.tgz#30e55961eec77379da551ea5c4cf43cbf03522be" + integrity sha512-lpQkHxd9UL6tb3k/aHAVfnVtn+Bcs9ob5InuFLLEDqSqeq+AljB8GZW9xY0x7F+xYwEcjKe07nyoxzEYz6yvkw== + dependencies: + rc "^1.2.8" + safe-buffer "^5.0.1" + +registry-url@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" + integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== + dependencies: + rc "^1.2.8" + +regjsgen@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" + integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== + +regjsparser@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c" + integrity sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ== + dependencies: + jsesc "~0.5.0" + +relateurl@0.2.x: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +renderkid@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.3.tgz#380179c2ff5ae1365c522bf2fcfcff01c5b74149" + integrity sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA== + dependencies: + css-select "^1.1.0" + dom-converter "^0.2" + htmlparser2 "^3.3.0" + strip-ansi "^3.0.0" + utila "^0.4.0" + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +requizzle@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/requizzle/-/requizzle-0.2.3.tgz#4675c90aacafb2c036bd39ba2daa4a1cb777fded" + integrity sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ== + dependencies: + lodash "^4.17.14" + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= + dependencies: + resolve-from "^3.0.0" + +resolve-dir@^1.0.0, resolve-dir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^1.10.0, resolve@^1.3.2: + version "1.12.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" + integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== + dependencies: + path-parse "^1.0.6" + +responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= + dependencies: + lowercase-keys "^1.0.0" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + +rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +roarr@^2.14.2: + version "2.14.4" + resolved "https://registry.yarnpkg.com/roarr/-/roarr-2.14.4.tgz#2d9d26864ce95ce570b4b5c5e548aefd40bb2bf7" + integrity sha512-QMzRAQGZFPgnx4nNWp4Q+WHfiZh2HTSEjNaxFLrEIj3PmcQ1GHL5OjaaIyF9ybUDD2aZ9t3Awc/obrRPils9ng== + dependencies: + boolean "^2.0.3" + detect-node "^2.0.4" + globalthis "^1.0.0" + json-stringify-safe "^5.0.1" + semver-compare "^1.0.0" + sprintf-js "^1.1.2" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= + dependencies: + aproba "^1.1.1" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sanitize-filename@^1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/sanitize-filename/-/sanitize-filename-1.6.3.tgz#755ebd752045931977e30b2025d340d7c9090378" + integrity sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg== + dependencies: + truncate-utf8-bytes "^1.0.0" + +sax@^1.2.4, sax@~1.2.1, sax@~1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +scheduler@^0.17.0: + version "0.17.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.17.0.tgz#7c9c673e4ec781fac853927916d1c426b6f3ddfe" + integrity sha512-7rro8Io3tnCPuY4la/NuI5F2yfESpnfZyT6TtkXnSWVkcu0BCDJ+8gk5ozUaFaxpIyNuWAPXrH0yFcSi28fnDA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +scheduler@^0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.18.0.tgz#5901ad6659bc1d8f3fdaf36eb7a67b0d6746b1c4" + integrity sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +schema-utils@^0.4.3: + version "0.4.7" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" + integrity sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ== + dependencies: + ajv "^6.1.0" + ajv-keywords "^3.1.0" + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +schema-utils@^2.0.0, schema-utils@^2.4.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.5.0.tgz#8f254f618d402cc80257486213c8970edfd7c22f" + integrity sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ== + dependencies: + ajv "^6.10.2" + ajv-keywords "^3.4.1" + +schema-utils@^2.6.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.1.tgz#eb78f0b945c7bcfa2082b3565e8db3548011dc4f" + integrity sha512-0WXHDs1VDJyo+Zqs9TKLKyD/h7yDpHUhEFsM2CzkICFdoX1av+GBq/J2xRTFfsQO5kBfhZzANf2VcIm84jqDbg== + dependencies: + ajv "^6.10.2" + ajv-keywords "^3.4.1" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= + +selfsigned@^1.10.7: + version "1.10.7" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.7.tgz#da5819fd049d5574f28e88a9bcc6dbc6e6f3906b" + integrity sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA== + dependencies: + node-forge "0.9.0" + +semver-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" + integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= + +semver-diff@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" + integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY= + dependencies: + semver "^5.0.3" + +"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@^6.2.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serialize-error@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-5.0.0.tgz#a7ebbcdb03a5d71a6ed8461ffe0fc1a1afed62ac" + integrity sha512-/VtpuyzYf82mHYTtI4QKtwHa79vAdU5OQpNPAmE/0UDdlGT0ZxHwC+J6gXkw29wwoVI8fMPsfcVHOwXtUQYYQA== + dependencies: + type-fest "^0.8.0" + +serialize-javascript@^1.7.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.9.1.tgz#cfc200aef77b600c47da9bb8149c943e798c2fdb" + integrity sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A== + +serialize-javascript@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" + integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shallowequal@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" + integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +sockjs-client@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.4.0.tgz#c9f2568e19c8fd8173b4997ea3420e0bb306c7d5" + integrity sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g== + dependencies: + debug "^3.2.5" + eventsource "^1.0.7" + faye-websocket "~0.11.1" + inherits "^2.0.3" + json3 "^3.3.2" + url-parse "^1.4.3" + +sockjs@0.3.19: + version "0.3.19" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" + integrity sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw== + dependencies: + faye-websocket "^0.10.0" + uuid "^3.0.1" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= + dependencies: + is-plain-obj "^1.0.0" + +source-list-map@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.5.12, source-map-support@^0.5.13, source-map-support@^0.5.16, source-map-support@~0.5.10, source-map-support@~0.5.12: + version "0.5.16" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" + integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +spdx-correct@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.5" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" + integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.1.tgz#6f12ed1c5db7ea4f24ebb8b89ba58c87c08257f2" + integrity sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +ssri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" + integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== + dependencies: + figgy-pudding "^3.5.1" + +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + +stat-mode@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-0.3.0.tgz#69283b081f851582b328d2a4ace5f591ce52f54b" + integrity sha512-QjMLR0A3WwFY2aZdV0okfFEJB5TRjkggXZjxP3A1RsWsNHNu3YPv8btmtc6iCFZ0Rul3FE93OYogvhOUClU+ng== + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +stream-browserify@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" + integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string.prototype.trimleft@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" + integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + +string.prototype.trimright@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" + integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-json-comments@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" + integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +style-loader@^0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" + integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== + dependencies: + loader-utils "^1.1.0" + schema-utils "^1.0.0" + +sumchecker@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.0.tgz#da5457b4605184575c76540e5e99cc777cb8ce4c" + integrity sha512-yreseuC/z4iaodVoq07XULEOO9p4jnQazO7mbrnDSvWAU/y2cbyIKs+gWJptfcGu9R+1l27K8Rkj0bfvqnBpgQ== + dependencies: + debug "^4.1.0" + +supports-color@6.1.0, supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= + dependencies: + has-flag "^1.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +svgo@^0.7.0: + version "0.7.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" + integrity sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U= + dependencies: + coa "~1.0.1" + colors "~1.1.2" + csso "~2.3.1" + js-yaml "~3.7.0" + mkdirp "~0.5.1" + sax "~1.2.1" + whet.extend "~0.9.9" + +svgo@^1.0.5: + version "1.3.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" + integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== + dependencies: + chalk "^2.4.1" + coa "^2.0.2" + css-select "^2.0.0" + css-select-base-adapter "^0.1.1" + css-tree "1.0.0-alpha.37" + csso "^4.0.2" + js-yaml "^3.13.1" + mkdirp "~0.5.1" + object.values "^1.1.0" + sax "~1.2.4" + stable "^0.1.8" + unquote "~1.1.1" + util.promisify "~1.0.0" + +taffydb@2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/taffydb/-/taffydb-2.6.2.tgz#7cbcb64b5a141b6a2efc2c5d2c67b4e150b2a268" + integrity sha1-fLy2S1oUG2ou/CxdLGe04VCyomg= + +tapable@^1.0.0, tapable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +tar@^4: + version "4.4.13" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" + integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.8.6" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" + +temp-file@^3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/temp-file/-/temp-file-3.3.4.tgz#73af868cd7cb7400a44e4bb03e653b2280ce2878" + integrity sha512-qSZ5W5q54iyGnP8cNl49RE0jTJc5CrzNocux5APD5yIxcgonoMuMSbsZfaZy8rTGCYo0Xz6ySVv3adagZ8gffg== + dependencies: + async-exit-hook "^2.0.1" + fs-extra "^8.1.0" + +term-size@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" + integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk= + dependencies: + execa "^0.7.0" + +terser-webpack-plugin@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz#61b18e40eaee5be97e771cdbb10ed1280888c2b4" + integrity sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg== + dependencies: + cacache "^12.0.2" + find-cache-dir "^2.1.0" + is-wsl "^1.1.0" + schema-utils "^1.0.0" + serialize-javascript "^1.7.0" + source-map "^0.6.1" + terser "^4.1.2" + webpack-sources "^1.4.0" + worker-farm "^1.7.0" + +terser-webpack-plugin@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" + integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA== + dependencies: + cacache "^12.0.2" + find-cache-dir "^2.1.0" + is-wsl "^1.1.0" + schema-utils "^1.0.0" + serialize-javascript "^2.1.2" + source-map "^0.6.1" + terser "^4.1.2" + webpack-sources "^1.4.0" + worker-farm "^1.7.0" + +terser@^3.8.1: + version "3.17.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-3.17.0.tgz#f88ffbeda0deb5637f9d24b0da66f4e15ab10cb2" + integrity sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ== + dependencies: + commander "^2.19.0" + source-map "~0.6.1" + source-map-support "~0.5.10" + +terser@^4.1.2: + version "4.3.9" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.3.9.tgz#e4be37f80553d02645668727777687dad26bbca8" + integrity sha512-NFGMpHjlzmyOtPL+fDw3G7+6Ueh/sz4mkaUYa4lJCxOPTNzd0Uj0aZJOmsDYoSQyfuVoWDMSWTPU3huyOm2zdA== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +timers-browserify@^2.0.4: + version "2.0.11" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f" + integrity sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ== + dependencies: + setimmediate "^1.0.4" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +toposort@^1.0.0: + version "1.0.7" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029" + integrity sha1-LmhELZ9k7HILjMieZEOsbKqVACk= + +truncate-utf8-bytes@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b" + integrity sha1-QFkjkJWS1W94pYGENLC3hInKXys= + dependencies: + utf8-byte-length "^1.0.1" + +tslib@^1.9.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + +tunnel@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" + integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== + +type-fest@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1" + integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ== + +type-fest@^0.8.0: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +uc.micro@^1.0.1, uc.micro@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" + integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== + +uglify-js@3.4.x: + version "3.4.10" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f" + integrity sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw== + dependencies: + commander "~2.19.0" + source-map "~0.6.1" + +underscore@~1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" + integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== + +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277" + integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g== + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57" + integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw== + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= + +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + +unique-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo= + dependencies: + crypto-random-string "^1.0.0" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unquote@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== + +update-notifier@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-3.0.1.tgz#78ecb68b915e2fd1be9f767f6e298ce87b736250" + integrity sha512-grrmrB6Zb8DUiyDIaeRTBCkgISYUgETNe7NglEbVsrLWXeESnlCSP50WfRSj/GmzMPl6Uchj24S/p80nP/ZQrQ== + dependencies: + boxen "^3.0.0" + chalk "^2.0.1" + configstore "^4.0.0" + has-yarn "^2.1.0" + import-lazy "^2.1.0" + is-ci "^2.0.0" + is-installed-globally "^0.1.0" + is-npm "^3.0.0" + is-yarn-global "^0.3.0" + latest-version "^5.0.0" + semver-diff "^2.0.0" + xdg-basedir "^3.0.0" + +upper-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg= + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-loader@^2.0.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-2.2.0.tgz#af321aece1fd0d683adc8aaeb27829f29c75b46e" + integrity sha512-G8nk3np8ZAnwhHXas1JxJEwJyQdqFXAKJehfgZ/XrC48volFBRtO+FIKtF2u0Ma3bw+4vnDVjHPAQYlF9p2vsw== + dependencies: + loader-utils "^1.2.3" + mime "^2.4.4" + schema-utils "^2.4.1" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + dependencies: + prepend-http "^2.0.0" + +url-parse@^1.4.3: + version "1.4.7" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278" + integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +utf8-byte-length@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61" + integrity sha1-9F8VDExm7uloGGUFq5P8u4rWv2E= + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util.promisify@1.0.0, util.promisify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + +utila@^0.4.0, utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.0.1, uuid@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" + integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== + +v8-compile-cache@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" + integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +vendors@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.3.tgz#a6467781abd366217c050f8202e7e50cc9eef8c0" + integrity sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw== + +vm-browserify@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +watchpack@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" + integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== + dependencies: + chokidar "^2.0.2" + graceful-fs "^4.1.2" + neo-async "^2.5.0" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +webpack-cli@^3.3.5: + version "3.3.10" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.10.tgz#17b279267e9b4fb549023fae170da8e6e766da13" + integrity sha512-u1dgND9+MXaEt74sJR4PR7qkPxXUSQ0RXYq8x1L6Jg1MYVEmGPrH6Ah6C4arD4r0J1P5HKjRqpab36k0eIzPqg== + dependencies: + chalk "2.4.2" + cross-spawn "6.0.5" + enhanced-resolve "4.1.0" + findup-sync "3.0.0" + global-modules "2.0.0" + import-local "2.0.0" + interpret "1.2.0" + loader-utils "1.2.3" + supports-color "6.1.0" + v8-compile-cache "2.0.3" + yargs "13.2.4" + +webpack-dev-middleware@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz#0019c3db716e3fa5cecbf64f2ab88a74bab331f3" + integrity sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw== + dependencies: + memory-fs "^0.4.1" + mime "^2.4.4" + mkdirp "^0.5.1" + range-parser "^1.2.1" + webpack-log "^2.0.0" + +webpack-dev-server@^3.7.2: + version "3.9.0" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.9.0.tgz#27c3b5d0f6b6677c4304465ac817623c8b27b89c" + integrity sha512-E6uQ4kRrTX9URN9s/lIbqTAztwEPdvzVrcmHE8EQ9YnuT9J8Es5Wrd8n9BKg1a0oZ5EgEke/EQFgUsp18dSTBw== + dependencies: + ansi-html "0.0.7" + bonjour "^3.5.0" + chokidar "^2.1.8" + compression "^1.7.4" + connect-history-api-fallback "^1.6.0" + debug "^4.1.1" + del "^4.1.1" + express "^4.17.1" + html-entities "^1.2.1" + http-proxy-middleware "0.19.1" + import-local "^2.0.0" + internal-ip "^4.3.0" + ip "^1.1.5" + is-absolute-url "^3.0.3" + killable "^1.0.1" + loglevel "^1.6.4" + opn "^5.5.0" + p-retry "^3.0.1" + portfinder "^1.0.25" + schema-utils "^1.0.0" + selfsigned "^1.10.7" + semver "^6.3.0" + serve-index "^1.9.1" + sockjs "0.3.19" + sockjs-client "1.4.0" + spdy "^4.0.1" + strip-ansi "^3.0.1" + supports-color "^6.1.0" + url "^0.11.0" + webpack-dev-middleware "^3.7.2" + webpack-log "^2.0.0" + ws "^6.2.1" + yargs "12.0.5" + +webpack-log@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" + integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== + dependencies: + ansi-colors "^3.0.0" + uuid "^3.3.2" + +webpack-merge@^4.2.1: + version "4.2.2" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" + integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g== + dependencies: + lodash "^4.17.15" + +webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1: + version "1.4.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@^4.41.4: + version "4.41.4" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.4.tgz#4bec4125224bdf50efa8be6226c19047599cd034" + integrity sha512-Lc+2uB6NjpCWsHI3trkoISOI64h9QYIXenbEWj3bn3oyjfB1lEBXjWAfAyY2sM0rZn41oD5V91OLwKRwS6Wp8Q== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/wasm-edit" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + acorn "^6.2.1" + ajv "^6.10.2" + ajv-keywords "^3.4.1" + chrome-trace-event "^1.0.2" + enhanced-resolve "^4.1.0" + eslint-scope "^4.0.3" + json-parse-better-errors "^1.0.2" + loader-runner "^2.4.0" + loader-utils "^1.2.3" + memory-fs "^0.4.1" + micromatch "^3.1.10" + mkdirp "^0.5.1" + neo-async "^2.6.1" + node-libs-browser "^2.2.1" + schema-utils "^1.0.0" + tapable "^1.1.3" + terser-webpack-plugin "^1.4.3" + watchpack "^1.6.0" + webpack-sources "^1.4.1" + +websocket-driver@>=0.5.1: + version "0.7.3" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.3.tgz#a2d4e0d4f4f116f1e6297eba58b05d430100e9f9" + integrity sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg== + dependencies: + http-parser-js ">=0.4.0 <0.4.11" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== + +whet.extend@~0.9.9: + version "0.9.9" + resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" + integrity sha1-+HfVv2SMl+WqVC+twW1qJZucEaE= + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@^1.2.14, which@^1.2.9, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +widest-line@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc" + integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA== + dependencies: + string-width "^2.1.1" + +worker-farm@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" + integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== + dependencies: + errno "~0.1.7" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^2.0.0: + version "2.4.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" + integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + +ws@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" + integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== + dependencies: + async-limiter "~1.0.0" + +xdg-basedir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= + +xmlcreate@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/xmlcreate/-/xmlcreate-2.0.1.tgz#2ec38bd7b708d213fd1a90e2431c4af9c09f6a52" + integrity sha512-MjGsXhKG8YjTKrDCXseFo3ClbMGvUD4en29H2Cev1dv4P/chlpw6KdYmlCWDkhosBVKRDjM836+3e3pm1cBNJA== + +xpipe@*: + version "1.0.5" + resolved "https://registry.yarnpkg.com/xpipe/-/xpipe-1.0.5.tgz#8dd8bf45fc3f7f55f0e054b878f43a62614dafdf" + integrity sha1-jdi/Rfw/f1Xw4FS4ePQ6YmFNr98= + +xtend@^4.0.0, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yargs-parser@^11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" + integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^13.1.0, yargs-parser@^13.1.1: + version "13.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" + integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@12.0.5: + version "12.0.5" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" + integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== + dependencies: + cliui "^4.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^11.1.1" + +yargs@13.2.4: + version "13.2.4" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83" + integrity sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + os-locale "^3.1.0" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.0" + +yargs@^13.2.4, yargs@^13.3.0: + version "13.3.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" + integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.1" + +yauzl@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" + integrity sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU= + dependencies: + fd-slicer "~1.0.1" + +zeromq@^6.0.0-beta.5: + version "6.0.0-beta.5" + resolved "https://registry.yarnpkg.com/zeromq/-/zeromq-6.0.0-beta.5.tgz#098505fcb66beb78eeb0c541efe415d3e2090292" + integrity sha512-zsSbjfLjDxQq/Mp6NemNK/AVpm1NeafJRgz7nos1nV9MI/3w/P76pFdlqzxRTW4cuNqyFXJ4Q7g2tUhaZi4rcg== + dependencies: + node-gyp-build "^4.1.0"