diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ca7d3e3d8eb2ba2ad07f1a74314414a41174f334..5bdad66c816a37bfd80fd18bfc1729c3389442a4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -236,6 +236,20 @@ deploy prod test: - /^dev-.*$/ when: manual +deploy prod util: + stage: release + before_script: + - mkdir -p /etc/deploy + - echo ${CI_K8S_PROD_CONFIG} | base64 -d > ${KUBECONFIG} + script: + - helm dependency update ops/helm/nomad + - helm upgrade --install nomad-util-v1 ops/helm/nomad -f ops/helm/nomad/deployments/prod-util-values.yaml --set image.tag=$CI_COMMIT_REF_NAME,roll=true --wait + - docker pull $TEST_IMAGE + - docker run -t -e NOMAD_KEYCLOAK_REALM_NAME=fairdi_nomad_prod $TEST_IMAGE python -m nomad.cli client -n https://nomad-lab.eu/prod/v1/util/api -u test -w $CI_NOMAD_TEST_PASSWORD integrationtests --skip-publish --skip-doi + except: + - /^dev-.*$/ + when: manual + release latest image: stage: release script: diff --git a/dependencies/parsers/atomistic b/dependencies/parsers/atomistic index 7a57120d6b4845f471577af75ad3e205ee503ea5..5f18ce5289026a01856ea1741c62b09fd0c0ea8a 160000 --- a/dependencies/parsers/atomistic +++ b/dependencies/parsers/atomistic @@ -1 +1 @@ -Subproject commit 7a57120d6b4845f471577af75ad3e205ee503ea5 +Subproject commit 5f18ce5289026a01856ea1741c62b09fd0c0ea8a diff --git a/dependencies/parsers/electronic b/dependencies/parsers/electronic index eee9bd051c3c52e3560cdb8092f79488dee05009..0161e491222515f06d79a690cbdd56f109ac0ed0 160000 --- a/dependencies/parsers/electronic +++ b/dependencies/parsers/electronic @@ -1 +1 @@ -Subproject commit eee9bd051c3c52e3560cdb8092f79488dee05009 +Subproject commit 0161e491222515f06d79a690cbdd56f109ac0ed0 diff --git a/dependencies/parsers/workflow b/dependencies/parsers/workflow index 4050431cce67d80793e548e7f79e44de7e95ecb8..557e880015153eabe05fd0c13e3efce73e6c5e97 160000 --- a/dependencies/parsers/workflow +++ b/dependencies/parsers/workflow @@ -1 +1 @@ -Subproject commit 4050431cce67d80793e548e7f79e44de7e95ecb8 +Subproject commit 557e880015153eabe05fd0c13e3efce73e6c5e97 diff --git a/gui/materia b/gui/materia index 8089b06fc35d23e0ef5a39e9c6943ef7f876defe..b2016c324335605c7bc8a73966f3c39db68c87ff 160000 --- a/gui/materia +++ b/gui/materia @@ -1 +1 @@ -Subproject commit 8089b06fc35d23e0ef5a39e9c6943ef7f876defe +Subproject commit b2016c324335605c7bc8a73966f3c39db68c87ff diff --git a/gui/package.json b/gui/package.json index 1f5282998e562b62ddf2d51cf4f419c1f9147e75..585415aa7737faba041e5d29df51f38a39f6b380 100644 --- a/gui/package.json +++ b/gui/package.json @@ -1,6 +1,6 @@ { "name": "nomad-fair-gui", - "version": "1.0.7", + "version": "1.0.8", "commit": "e98694e", "private": true, "workspaces": [ diff --git a/gui/public/env.js b/gui/public/env.js index e522694959bb1c8c8be0bbc2dcb788489ecbdf16..bc042beec2b5a3190fce5229f29332a1e5bc9881 100644 --- a/gui/public/env.js +++ b/gui/public/env.js @@ -11,7 +11,7 @@ window.nomadEnv = { 'encyclopediaBase': 'https://nomad-lab.eu/prod/rae/encyclopedia/#', 'debug': false, 'version': { - 'label': '1.0.7', + 'label': '1.0.8', 'isBeta': false, 'isTest': true, 'usesBetaData': true, diff --git a/gui/src/components/aitoolkit/CoursePage.js b/gui/src/components/aitoolkit/CoursePage.js new file mode 100644 index 0000000000000000000000000000000000000000..4c1300f1e5d2dd064b67cd48259098a273d88926 --- /dev/null +++ b/gui/src/components/aitoolkit/CoursePage.js @@ -0,0 +1,454 @@ +/* + * Copyright The NOMAD Authors. + * + * This file is part of NOMAD. See https://nomad-lab.eu for further info. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react' +import { + Button, + Grid, + Typography, + Divider, + IconButton, + makeStyles, + AccordionActions + +} from '@material-ui/core' +import { Link } from 'react-router-dom' +import { StringParam, useQueryParam } from 'use-query-params' +import TutorialsIcon from '../../images/AIT_ico_bp_tutorial.svg' +import ArrowIcon from '../../images/AIT_ico_bd_link_go_to.svg' +import FigureAI from '../../images/AIT_illu_AIT.svg' +import tutorials from '../../courseAI.json' +import { aitoolkitEnabled } from '../../config' +import MuiAccordion from '@material-ui/core/Accordion' +import MuiAccordionSummary from '@material-ui/core/AccordionSummary' +import MuiAccordionDetails from '@material-ui/core/AccordionDetails' +import { styled } from '@material-ui/core/styles' +import ArrowForwardIosSharpIcon from '@material-ui/icons/ArrowForwardIosSharp' +import ExpandMoreIcon from '@material-ui/icons/ExpandMore' +import Markdown from '../Markdown' +import AccessIcon from '../../images/AIT_ico_bd_link_external_big.svg' +import WatchIcon from '../../images/AIT_ico_bd_youtube.svg' +import PdfIcon from '../../images/AIT_ico_bd_link_pdf.svg' +import DoiIcon from '../../images/AIT_ico_bd_link_doi.svg' + +export const useStyles = makeStyles(theme => ({ + root: { + margin: theme.spacing(3), + width: '100%', + marginLeft: 'auto', + marginRight: 'auto', + maxWidth: '1052px', + marginBottom: '150px' + }, + sectionIcon: { + marginTop: theme.spacing(3) + }, + sectionTitle: { + marginBottom: theme.spacing(1), + marginLeft: theme.spacing(2), + marginTop: '105px' + }, + title: { + color: '#2A3C67', + fontSize: '35px', + marginLeft: '-10px', + fontWeight: theme.typography.fontWeightMedium, + marginTop: '-70px' + }, + deck: { + color: '#2A3C67', + fontSize: '22px', + marginTop: '20px', + lineHeight: '30px', + marginLeft: '-10px', + width: '518px' + }, + icon: { + height: '371px', + marginTop: '-20px', + marginLeft: '100px' + }, + filter: { + fontWeight: theme.typography.fontWeightMedium, + color: '#2A3C67', + fontSize: '20px', + marginTop: '60px', + marginLeft: '0px' + }, + autocomplete: { + height: 'auto', + color: '#2A3C67', + border: '3px solid #00DFE0', + borderRadius: '10px 10px 10px 10px', + marginTop: '10px', + marginLeft: '0px', + width: '240px' + }, + tutorialsList: { + marginTop: '50px' + }, + textLevel: { + textAlign: 'left', + color: '#2A3C67', + fontSize: '22px', + height: '22px', + marginTop: '-16px' + }, + titleSecondary: { + fontWeight: 'bold', + color: '#00DFE0', + fontSize: '35px', + marginLeft: '-10px' + }, + bottomButton: { + color: '#F3F2F5', + backgroundColor: '#F3F2F5', + borderRadius: '30px', + width: '242px', + height: '70px', + textAlign: 'center', + align: 'center', + marginTop: '40px', + textTransform: 'none', + fontSize: '12pt', + lineHeight: '20px' + }, + bottomButtonText: { + color: '#2A3C67', + fontWeight: theme.typography.fontWeightMedium + }, + bottomIcon: { + marginTop: '80px', + marginLeft: '120px' + }, + tutorialTitleGrid: { + marginRight: '40px' + }, + tutorialTitleText: { + fontWeight: theme.typography.fontWeightMedium, + fontSize: '28px', + color: '#2A3C67', + lineHeight: '30px' + }, + fieldText: { + color: '#2A3C67' + }, + linkAuthors: { + color: '#2A3C67', + cursor: 'pointer', + lineHeight: '20px', + fontSize: '16px' + }, + tutorialDescriptionGrid: { + marginLeft: '50px' + }, + tutorialDescriptionText: { + color: '#2A3C67', + fontSize: '18px' + }, + keywordsGrid: { + marginLeft: '80px' + }, + linkKeywords: { + border: '1.5px solid #00DFE0', + lineHeight: '35px', + color: '#2A3C67', + cursor: 'pointer', + fontStyle: 'normal', + fontSize: '16px' + }, + tutorialActions: { + marginLeft: '50px' + }, + tutorialResources: { + marginTop: '-17px', + marginLeft: '-6px' + } +})) + +const Accordion = styled((props) => ( + <MuiAccordion {...props} /> +))(({ theme }) => ({ + backgroundColor: theme.palette.background.default, + borderBottom: '13px solid #7FEFEF' +})) + +const AccordionSummary = styled((props) => ( + <MuiAccordionSummary + expandIcon={<ArrowForwardIosSharpIcon sx={{ fontSize: '0.9rem' }} />} + {...props} + /> +))(({ theme }) => ({ + flexDirection: 'row-reverse', + '& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': { + transform: 'rotate(90deg)' + }, + '& .MuiAccordionSummary-content': { + marginLeft: theme.spacing(1), + marginTop: '20px', + marginBottom: '20px' + } +})) + +const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({ + padding: theme.spacing(2) +})) + +export default function TutorialsPage() { + const styles = useStyles() + + const tutorials_list = tutorials.tutorials + + tutorials_list.forEach(tutorial => { + tutorial.key = tutorial.title.replace(/\W/gm, '_').toLowerCase() + }) + + function AccordionsList() { + const [expanded, setExpanded] = useQueryParam('expanded', StringParam) + return ( + tutorials_list.map(tutorial => ( + <div key={tutorial.title} > + <Accordion + key={tutorial.key} + expanded={expanded === tutorial.key} + onChange={() => setExpanded(expanded === tutorial.key ? null : tutorial.key)} + elevation={0} + > + <AccordionSummary expandIcon={<ExpandMoreIcon />}> + <Grid container spacing={1} > + <Grid item xs={7} className={styles.tutorialTitleGrid} > + <Typography className={styles.tutorialTitleText}> + {tutorial.title} + </Typography> + </Grid> + <Grid item xs={4}> + <Typography className={styles.fieldText}> + {<b>Lecturer: </b> } + {tutorial.lecturer + + } + </Typography> + </Grid> + </Grid> + </AccordionSummary> + <AccordionDetails > + <Grid container spacing={4}> + <Grid item xs={6} className={styles.tutorialDescriptionGrid}> + <Markdown className={styles.tutorialDescriptionText}> + {tutorial.description} + </Markdown> + </Grid> + <Grid item xs={4} className={styles.keywordsGrid}> + + {tutorial.notebook_name_1 && <><Typography className={styles.fieldText}> + <b>Notebook authors:</b> + </Typography><Typography> + {tutorial.authors_notebook_1 + .map(name => { + const label = name.split(',').reverse().join(' ') + return label + }).reduce((prev, curr) => [prev, ' | ', curr])} + </Typography> + <Button + href={tutorial.link_notebook_1} + target="tutorial" + startIcon={<img alt='Access icon' src={AccessIcon}></img>} + > + <Typography className={styles.fieldText} > + <b>Access notebook</b> + </Typography> + </Button> + </>} + {tutorial.notebook_name_2 && <><Typography className={styles.fieldText}> + <b>Notebook authors:</b> + </Typography><Typography> + {tutorial.authors_notebook_2 + .map(name => { + const label = name.split(',').reverse().join(' ') + return label + }).reduce((prev, curr) => [prev, ' | ', curr])} + </Typography> + <Button + href={tutorial.link_notebook_2} + target="tutorial" + startIcon={<img alt='Access icon' src={AccessIcon}></img>} + > + <Typography className={styles.fieldText} > + <b>Access notebook</b> + </Typography> + </Button> + </>} + </Grid> + </Grid> + </AccordionDetails> + <AccordionActions> + <Grid container spacing={4}> + <Grid item xs={7} className={styles.tutorialActions}> + <Grid container spacing={0}> + <Grid item xs={5}> + <Button + href={tutorial.link_video_1} + target="tutorial" + startIcon={<img alt='Watch icon' src={WatchIcon}></img>} + > + <Typography className={styles.fieldText} > + <b>Watch video 1</b> + </Typography> + </Button> + </Grid> + <Grid item xs={5} > + <div> + { tutorial.link_video_2 && <Button + width='10px' + color='#2A3C67' + href={tutorial.link_video_2} + target="tutorial" + startIcon={<img alt='Watch icon' src={WatchIcon}></img>} + > + <Typography className={styles.fieldText} > + <b>Watch video 2</b> + </Typography> + </Button>} + </div> + </Grid> + </Grid> + </Grid> + {tutorial.link_paper && + <Grid item xs={4} className={styles.tutorialResources}> + <Grid item xs={12}> + <Typography className={styles.fieldText}> + <b>Additional Resources</b>: + </Typography> + </Grid> + <Grid container spacing={0}> + <Grid item xs={2} > + <div> + {tutorial.link_paper && <Button + color='#2A3C67' + href={tutorial.link_paper} + target="tutorial" + startIcon={<img alt='DOI icon' src={DoiIcon}></img>}> + </Button>} + </div> + </Grid> + <Grid item xs={2}> + <div> + {tutorial.link_paper && <Button + color='#2A3C67' + href={tutorial.link_paper} + target="tutorial" + startIcon={<img alt='PDF icon' src={PdfIcon}/>}> + </Button>} + </div> + </Grid> + </Grid> + </Grid> + } + </Grid> + </AccordionActions> + <Divider /> + </Accordion> + </div> + ))) + } + + return <Grid container spacing={1} className={styles.root}> + <Grid container spacing={0} className={styles.Heading}> + <Grid item xs={6} className={styles.sectionTitle}> + <Grid container spacing={0}> + <Grid item xs={4} style={{marginTop: '-100px', marginLeft: '-20px'}}> + <IconButton + {...(aitoolkitEnabled ? ({to: 'aitoolkit', component: Link}) : ({href: 'https://nomad-lab.eu/AIToolkit', component: 'a'}))} + > + <img alt='AI toolkit logo' src={FigureAI} style={{width: '120px'}}/> + </IconButton> + </Grid> + <Grid item xs={8}> + <Typography className={styles.title}> + AI lectures + </Typography> + </Grid> + </Grid> + <Typography className={styles.deck}> + We present a virtual course in artificial intelligence, by proposing a path through some of the tutorial notebooks from the AI-toolkit. Each topic is presented via a video lecture and accompanied by one or more notebooks that allow for putting your hand on the explained methods. </Typography> + </Grid> + <Grid item xs={4} className={styles.sectionIcon}> + <img alt='Tutorials icon' src={TutorialsIcon} className={styles.icon}/> + </Grid> + </Grid> + + <Grid container spacing={1} className={styles.tutorialsList}> + <Grid item xs={12}> + <Divider + style={{ + backgroundColor: '#7FEFEF', + height: '13px', + borderRadius: '4px', + marginBottom: '-8px' + }} + /> + </Grid> + <Grid item xs={12}> + <AccordionsList/> + </Grid> + + </Grid> + <Grid item xs={6} className={styles.sectionTitle}> + <Typography className={styles.titleSecondary}> + Next intermediate level + </Typography> + <Typography className={styles.deck}> + If you are still curious about applications of artificial intelligence to materials science, you can find + more lectures and more notebooks in our tutorials section. + </Typography> + <Grid container spacing={1}> + <Grid item xs={4}> + <IconButton + component={Link} + {...(aitoolkitEnabled ? ({to: 'aitoolkit', component: Link}) : ({href: 'https://nomad-lab.eu/AIToolkit', component: 'a'}))} + style={{marginRight: '0px', marginTop: '20px'}} + > + <img alt='AI toolkit logo' src={FigureAI} style={{width: '120px'}}/> + </IconButton> + </Grid> + <Grid item xs={8}> + <Button + width='10px' + color='#2A3C67' + component={Link} + to="tutorials" + className={styles.bottomButton} + endIcon={<img alt='Arrow icon' src={ArrowIcon}/>} + > + <Typography className={styles.bottomButtonText}> + More AI tutorials + </Typography> + </Button> + </Grid> + </Grid> + </Grid> + <Grid item xs={4} className={styles.sectionIcon}> + <IconButton + component={Link} + to="tutorials" + className={styles.bottomIcon} + > + <img alt='Tutorials icon' src={TutorialsIcon} style={{width: '300px'}}/> + </IconButton> + </Grid> + </Grid> +} diff --git a/gui/src/components/nav/Routes.js b/gui/src/components/nav/Routes.js index a8b230301718ce2d6aadf41cf5be23d1080ff940..9d3ead48a533ac23e563bc5329d24abe622a806f 100644 --- a/gui/src/components/nav/Routes.js +++ b/gui/src/components/nav/Routes.js @@ -26,6 +26,7 @@ import About from '../About' import AIToolkitPage from '../aitoolkit/AIToolkitPage' import TutorialsPage from '../aitoolkit/TutorialsPage' import ReproducePage from '../aitoolkit/ReproducePage' +import CoursePage from '../aitoolkit/CoursePage' import { MetainfoPage, help as metainfoHelp } from '../archive/MetainfoBrowser' import EntryPage, { help as entryHelp } from '../entry/EntryPage' import UploadPage from '../uploads/UploadPage' @@ -296,6 +297,11 @@ export const routes = [ path: 'reproduce', title: 'Artificial Intelligence Toolkit', component: ReproducePage + }, + { + path: 'course', + title: 'Artificial Intelligence Toolkit', + component: CoursePage } ] }, diff --git a/gui/src/courseAI.json b/gui/src/courseAI.json new file mode 100644 index 0000000000000000000000000000000000000000..b5f88b7e3736bcedbd43a465d04fd083bbf0bfec --- /dev/null +++ b/gui/src/courseAI.json @@ -0,0 +1,136 @@ + { + "tutorials": [ + { + "lecturer": "Luca Ghiringhelli", + "title": "Introduction to artificial intelligence and machine-learning methods", + "description": "This introductory lecture covers a general overview of artificial intelligence methods, including machine-learning and data-mining methods. There is no hands-on notebook specifically associated to this lectures, but the concepts introduced therein can be useful to link together the various techniques presented in the next lectures.", + "link_video_1": "https://www.youtube.com/watch?v=z_Q0yXGHPDE", + "link_video_2": "https://www.youtube.com/watch?v=7m0vfdK716I", + "notebook_1": "true", + "authors_notebook_1": [ + "Ahmetcik, Emre", + "Ziletti, Angelo", + "Ouyang, Runhai", + "Sbail\u00f2, Luigi", + "Scheffler, Matthias", + "Ghiringhelli, Luca M."] + }, + { + "lecturer": "Santiago Rigamonti", + "title": "Regularized regression and kernel methods", + "description": "In this tutorial, we will explore the application of kernel ridge regression to the prediction of materials properties.", + "link_video_1": "https://www.youtube.com/watch?v=QHfcpuYfDtI", + "link_video_2": "https://www.youtube.com/watch?v=A6c_QJmMAqE", + "notebook_name_1": "krr4mat.ipynb", + "link_notebook_1": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/krr4mat.ipynb", + "authors_notebook_1": [ + "Langer, Marcel" + ] + }, + { + "lecturer": "Daniel Speckhard", + "title": "Decision trees and random forests", + "description": "In this tutorial, we will introduce decision trees. We go through a toy model introducing the SKLearn API. We then discuss step by step the different theoretical aspects of trees. We then move to training a regression tree and classification tree on different datasets related to materials science. We end the tutorial by covering random forests and bagging classfiers.", + "link_video_1": "https://www.youtube.com/watch?v=lUdCB6cqpvo", + "link_video_2": "https://www.youtube.com/watch?v=rwxE35URuF8", + "authors_notebook_1": [ + "Speckhard, Daniel", + "Leitherer, Andreas", + "Ghiringhelli, Luca M." + ], + "notebook_name_1": "decision_tree.ipynb", + "link_notebook_1": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/decision_tree.ipynb" + }, + { + "lecturer": "Angelo Ziletti", + "title": "Artificial neural networks and deep learning", + "link_video_1": "https://www.youtube.com/watch?v=-_-2ESB4Ag0", + "link_video_2": "https://www.youtube.com/watch?v=qRqIU3kYF80", + "description": "In these tutorials, we introduce the basic of deep learning, via tranditional multilayer perceptrons and modern convolutional neural networks.", + "notebook_name_1": "nn_regression.ipynb", + "link_notebook_1": "https://nomad-lab.eu/prod/analytics/public/user-redirect/notebooks/tutorials/nn_regression.ipynb", + "authors_notebook_1": [ + "Leitherer, Andreas", + "Sbail\u00f2, Luigi", + "Ghiringhelli, Luca M." + ], + "notebook_name_2": "convolutional_nn.ipynb", + "link_notebook_2": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/convolutional_nn.ipynb", + "authors_notebook_2": [ + "Ziletti, Angelo", + "Leitherer, Andreas", + "Ghiringhelli, Luca M." + ] + }, + { + "lecturer": "Luigi Sbail\u00f2", + "title": "Unsupervised learning", + "link_video_1": "https://www.youtube.com/watch?v=Ozu-QCBB2bg", + "link_video_2": "https://www.youtube.com/watch?v=hnB5B7Iu6Ds", + "description": "In this tutorial, we introduce to the most popular clustering algorithms. We focus on partitioning, hierarchical and density-based clustering algorithms. The methods are tested on synthetic datasets of increasing complexity.", + "notebook_name_1": "clustering_tutorial.ipynb", + "link_notebook_1": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/clustering_tutorial.ipynb", + "authors_notebook_1": [ + "Sbail\u00f2, Luigi", + "Ghiringhelli, Luca M." + ], + "notebook_name_2": "exploratory_analysis.ipynb", + "link_notebook_2": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/exploratory_analysis.ipynb", + "authors_notebook_2": [ + "Sbail\u00f2, Luigi", + "Ghiringhelli, Luca M." + ] + }, + { + "lecturer": "Luca Ghiringhelli", + "title": "Compressed sensing meets symbolic regression: SISSO", + "description": "In this tutorial, we will show how to find descriptive parameters to predict materials properties using symbolic regrression combined with compressed sensing tools. The relative stability of the zincblende (ZB) versus rocksalt (RS) structure of binary materials is predicted and compared against a model trained with kernel ridge regression.", + "link_video_1": "https://www.youtube.com/watch?v=YJZm4xot4bM", + "link_video_2": "https://www.youtube.com/watch?v=KjPCMdWikBg", + "notebook_name_1": "compressed_sensing.ipynb", + "authors_notebook_1": [ + "Ahmetcik, Emre", + "Ziletti, Angelo", + "Ouyang, Runhai", + "Sbail\u00f2, Luigi", + "Scheffler, Matthias", + "Ghiringhelli, Luca M." + ], + "link_notebook_1": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/compressed_sensing.ipynb" + }, + { + "lecturer": "Matthias Scheffler", + "title": "Subgroup discovery, rare-phenomena challenge, and domain of applicability", + "link_video_1": "https://www.youtube.com/watch?v=cizNEJypwao", + "link_video_2": "https://www.youtube.com/watch?v=uKEzs6koTcs", + "description": "In these tutorials, we introduce the subgroup discovery (SGD) method, which identifies rules (Boolean statements involving selected features among the given candidates) describing exceptional subsets of data. SGD is an exploratory analysis tools and allows for identifying local structure in the data, while most ML tools focus on global models. A notable application of SGD is to locate the domain of applicability of ML models, i.e., identifying the property of data that are expected to yield significantly lower errors than the overall dataset. A notebook on this specific application is also linked.", + "authors_notebook_1":[ + "Foppa, Lucas", + "Ghiringhelli, Luca M." + ], + + "notebook_name_1": "sgd_alloys_oxygen_reduction_evolution.ipynb", + "link_notebook_1": "https://nomad-lab.eu/prod/analytics/public/user-redirect/notebooks/tutorials/sgd_alloys_oxygen_reduction_evolution.ipynb", + "notebook_name_2": "domain_of_applicability.ipynb", + "link_notebook_2": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/domain_of_applicability.ipynb", + "authors_notebook_2": [ + "Arif, Mohammad-Yasin", + "Sbail\u00f2, Luigi", + "Ghiringhelli, Luca M." + ] + }, + { + "lecturer": "Lucas Foppa", + "title": "Fusion of experimental and computational data by AI", + "description": "In this tutorial, we provide an example of AI techniques combined to experiments, in such a way that the AI is trained on an initial set of data and the predictions of the trained model is used to guide the experiment in a similar but distinct class of materials.", + "link_video_1": "https://www.youtube.com/watch?v=8wbITgsDNqE", + "authors_notebook_1": [ + "Foppa, Lucas", + "Ghiringhelli, Luca M.", + "Scheffler, Matthias" + ], + "notebook_name_1": "sgd_propylene_oxidation_hte.ipynb", + "link_notebook_1": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/sgd_propylene_oxidation_hte.ipynb" + } + ] + } diff --git a/gui/src/images/nomad.svg b/gui/src/images/nomad.svg new file mode 100644 index 0000000000000000000000000000000000000000..1f38c509048ea8b6872171b3f270a1b3a593d921 --- /dev/null +++ b/gui/src/images/nomad.svg @@ -0,0 +1,300 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ + <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/"> +]> +<svg version="1.1" + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" + x="0px" y="0px" width="425px" height="227px" viewBox="-36.073 -17.643 425 227" enable-background="new -36.073 -17.643 425 227" + xml:space="preserve"> +<defs> +</defs> +<polygon fill="#17A5F7" points="109.873,49.391 98.234,37.752 93.973,53.652 105.613,65.293 "/> +<polygon fill="#17A5F7" points="89.711,69.549 78.072,57.91 73.811,73.811 85.451,85.451 "/> +<polygon fill="#17A5F7" points="137.412,56.77 125.773,45.131 121.512,61.031 133.152,72.67 "/> +<polygon fill="#17A5F7" points="117.25,76.928 105.611,65.289 101.35,81.189 112.99,92.828 "/> +<polygon fill="#17A5F7" points="164.951,64.146 153.313,52.508 149.051,68.408 160.691,80.049 "/> +<polygon fill="#17A5F7" points="144.789,84.305 133.15,72.666 128.889,88.566 140.529,100.207 "/> +<polygon fill="#17A5F7" points="192.491,71.525 180.852,59.887 176.59,75.787 188.231,87.426 "/> +<polygon fill="#17A5F7" points="172.328,91.684 160.689,80.045 156.428,95.945 168.068,107.584 "/> +<polygon fill="#17A5F7" points="220.03,78.902 208.392,67.264 204.13,83.164 215.771,94.805 "/> +<polygon fill="#17A5F7" points="199.868,99.061 188.229,87.422 183.968,103.322 195.608,114.963 "/> +<polygon fill="#17A5F7" points="247.569,86.281 235.931,74.643 231.669,90.543 243.31,102.182 "/> +<polygon fill="#17A5F7" points="227.407,106.439 215.769,94.801 211.507,110.701 223.147,122.341 "/> +<polygon fill="#17A5F7" points="97.09,97.09 85.451,85.451 81.189,101.352 92.83,112.99 "/> +<polygon fill="#17A5F7" points="124.629,104.467 112.99,92.828 108.729,108.729 120.369,120.37 "/> +<polygon fill="#17A5F7" points="152.168,111.846 140.529,100.207 136.268,116.108 147.908,127.747 "/> +<polygon fill="#17A5F7" points="179.707,119.224 168.068,107.584 163.807,123.485 175.447,135.126 "/> +<polygon fill="#17A5F7" points="207.247,126.603 195.608,114.963 191.347,130.864 202.987,142.503 "/> +<polygon fill="#17A5F7" points="226.837,136.11 221.017,130.292 218.886,138.241 224.706,144.062 "/> +<polygon fill="#17A5F7" points="254.382,143.499 248.562,137.679 246.431,145.63 252.251,151.448 "/> +<polygon fill="#17A5F7" points="342.405,90.396 336.585,84.576 334.454,92.527 340.274,98.346 "/> +<polygon fill="#17A5F7" points="300.106,27.936 294.288,22.115 292.157,30.066 297.978,35.885 "/> +<polygon fill="#17A5F7" points="275.108,93.658 263.47,82.02 259.208,97.92 270.849,109.561 "/> +<polygon fill="#17A5F7" points="254.946,113.816 243.308,102.178 239.046,118.079 250.687,129.72 "/> +<polygon fill="#17A5F7" points="302.647,101.037 291.009,89.398 286.747,105.299 298.388,116.938 "/> +<polygon fill="#17A5F7" points="282.485,121.196 270.847,109.557 266.585,125.458 278.226,137.097 "/> +<polygon fill="#17A5F7" points="169.785,18.58 163.965,12.762 161.834,20.711 167.654,26.531 "/> +<polygon fill="#17A5F7" points="122.084,31.359 116.266,25.541 114.135,33.49 119.955,39.311 "/> +<polygon fill="#17A5F7" points="138.271,12.266 135.361,9.355 134.295,13.33 137.205,16.24 "/> +<polygon fill="#17A5F7" points="90.57,25.047 87.66,22.137 86.596,26.111 89.506,29.021 "/> +<polygon fill="#17A5F7" points="63.031,17.67 60.121,14.76 59.055,18.734 61.965,21.645 "/> +<polygon fill="#17A5F7" points="7.951,2.91 5.041,0 3.977,3.975 6.887,6.885 "/> +<polygon fill="#17A5F7" points="15.328,30.449 12.418,27.539 11.354,31.514 14.264,34.424 "/> +<polygon fill="#17A5F7" points="30.086,85.525 27.176,82.615 26.111,86.59 29.021,89.5 "/> +<polygon fill="#17A5F7" points="37.465,113.064 34.555,110.154 33.49,114.129 36.4,117.04 "/> +<polygon fill="#17A5F7" points="65.006,120.448 62.096,117.538 61.029,121.513 63.939,124.423 "/> +<polygon fill="#17A5F7" points="92.545,127.669 89.635,124.759 88.57,128.733 91.48,131.644 "/> +<polygon fill="#17A5F7" points="120.086,135.208 117.176,132.298 116.109,136.272 119.02,139.183 "/> +<polygon fill="#17A5F7" points="202.704,157.345 199.794,154.435 198.729,158.409 201.64,161.319 "/> +<polygon fill="#17A5F7" points="241.052,14.242 238.142,11.332 237.077,15.307 239.987,18.217 "/> +<polygon fill="#17A5F7" points="268.593,21.623 265.683,18.713 264.618,22.688 267.528,25.598 "/> +<polygon fill="#17A5F7" points="331.052,63.922 328.142,61.012 327.077,64.986 329.987,67.896 "/> +<polygon fill="#17A5F7" points="318.269,111.621 315.358,108.711 314.294,112.686 317.204,115.597 "/> +<polygon fill="#17A5F7" points="46.842,36.762 41.023,30.943 38.893,38.893 44.713,44.713 "/> +<polygon fill="#17A5F7" points="74.383,43.986 68.564,38.168 66.434,46.117 72.254,51.938 "/> +<polygon fill="#17A5F7" points="34.061,58.9 28.242,53.08 26.111,61.031 31.932,66.85 "/> +<polygon fill="#17A5F7" points="54.221,64.299 48.402,58.48 46.271,66.43 52.092,72.25 "/> +<polygon fill="#17A5F7" points="151.6,141.521 145.779,135.7 143.648,143.651 149.469,149.47 "/> +<polygon fill="#17A5F7" points="61.6,91.84 55.781,86.021 53.65,93.971 59.471,99.791 "/> +<polygon fill="#17A5F7" points="157.572,36.607 145.934,24.969 141.672,40.869 153.313,52.51 "/> +<polygon fill="#17A5F7" points="197.325,25.959 191.505,20.139 189.374,28.09 195.194,33.908 "/> +<polygon fill="#17A5F7" points="185.112,43.986 173.473,32.348 169.211,48.248 180.852,59.887 "/> +<polygon fill="#17A5F7" points="224.864,33.336 219.044,27.518 216.913,35.467 222.733,41.287 "/> +<polygon fill="#17A5F7" points="212.651,51.363 201.013,39.725 196.751,55.625 208.392,67.266 "/> +<polygon fill="#17A5F7" points="260.353,38.584 248.714,26.945 244.452,42.846 256.093,54.484 "/> +<polygon fill="#17A5F7" points="240.19,58.742 228.552,47.104 224.29,63.004 235.931,74.643 "/> +<polygon fill="#17A5F7" points="287.892,45.961 276.253,34.322 271.991,50.223 283.632,61.863 "/> +<polygon fill="#17A5F7" points="267.729,66.119 256.091,54.48 251.829,70.381 263.47,82.021 "/> +<polygon fill="#17A5F7" points="315.431,53.34 303.792,41.701 299.53,57.602 311.171,69.24 "/> +<polygon fill="#17A5F7" points="295.269,73.498 283.63,61.859 279.368,77.76 291.009,89.398 "/> +<polygon fill="#17A5F7" points="322.808,80.875 311.169,69.236 306.907,85.137 318.548,96.777 "/> +<polygon fill="#00C8C9" points="137.412,56.77 153.313,52.508 149.051,68.408 133.15,72.668 "/> +<polygon fill="#00C8C9" points="117.25,76.928 133.15,72.666 128.889,88.566 112.988,92.826 "/> +<polygon fill="#00C8C9" points="164.951,64.146 180.852,59.887 176.59,75.787 160.689,80.045 "/> +<polygon fill="#00C8C9" points="144.789,84.305 160.689,80.045 156.428,95.945 140.527,100.203 "/> +<polygon fill="#00C8C9" points="192.491,71.525 208.392,67.264 204.13,83.164 188.229,87.424 "/> +<polygon fill="#00C8C9" points="172.328,91.684 188.229,87.422 183.968,103.322 168.066,107.582 "/> +<polygon fill="#00C8C9" points="220.03,78.902 235.931,74.643 231.669,90.543 215.769,94.801 "/> +<polygon fill="#00C8C9" points="247.569,86.281 263.47,82.02 259.208,97.92 243.308,102.18 "/> +<polygon fill="#00C8C9" points="240.19,58.742 256.091,54.48 251.829,70.381 235.929,74.641 "/> +<polygon fill="#527DE3" points="117.252,76.93 105.611,65.289 121.512,61.031 133.152,72.67 "/> +<polygon fill="#527DE3" points="97.09,97.088 85.449,85.447 101.35,81.189 112.99,92.828 "/> +<polygon fill="#527DE3" points="144.791,84.309 133.15,72.668 149.051,68.408 160.691,80.049 "/> +<polygon fill="#527DE3" points="124.629,104.467 112.988,92.826 128.889,88.566 140.529,100.207 "/> +<polygon fill="#527DE3" points="172.33,91.686 160.689,80.045 176.59,75.787 188.231,87.426 "/> +<polygon fill="#527DE3" points="199.87,99.064 188.229,87.424 204.13,83.164 215.771,94.805 "/> +<polygon fill="#527DE3" points="227.409,106.441 215.769,94.801 231.669,90.543 243.31,102.182 "/> +<polygon fill="#527DE3" points="254.948,113.82 243.308,102.18 259.208,97.92 270.849,109.561 "/> +<polygon fill="#527DE3" points="220.03,78.902 208.39,67.262 224.29,63.004 235.931,74.643 "/> +<polygon fill="#527DE3" points="247.569,86.281 235.929,74.641 251.829,70.381 263.47,82.021 "/> +<polygon fill="#527DE3" points="275.108,93.658 263.468,82.018 279.368,77.76 291.009,89.398 "/> +<polygon fill="#00DFE0" points="82.334,42.014 98.234,37.752 93.973,53.652 78.072,57.912 "/> +<polygon fill="#00DFE0" points="62.172,62.172 78.072,57.91 73.811,73.811 57.91,78.07 "/> +<polygon fill="#00DFE0" points="109.873,49.391 125.773,45.131 121.512,61.031 105.611,65.289 "/> +<polygon fill="#00DFE0" points="89.711,69.549 105.611,65.289 101.35,81.189 85.449,85.447 "/> +<polygon fill="#00DFE0" points="199.868,99.061 215.769,94.801 211.507,110.701 195.606,114.959 "/> +<polygon fill="#00DFE0" points="69.551,89.711 85.451,85.451 81.189,101.352 65.289,105.609 "/> +<polygon fill="#00DFE0" points="97.09,97.09 112.99,92.828 108.729,108.729 92.828,112.988 "/> +<polygon fill="#00DFE0" points="124.629,104.467 140.529,100.207 136.268,116.108 120.367,120.366 "/> +<polygon fill="#00DFE0" points="152.168,111.846 168.068,107.584 163.807,123.485 147.906,127.745 "/> +<polygon fill="#00DFE0" points="179.707,119.224 195.608,114.963 191.347,130.864 175.445,135.122 "/> +<polygon fill="#00DFE0" points="213.067,132.421 221.017,130.292 218.886,138.241 210.937,140.37 "/> +<polygon fill="#00DFE0" points="240.612,139.81 248.562,137.679 246.431,145.63 238.481,147.759 "/> +<polygon fill="#00DFE0" points="328.636,86.707 336.585,84.576 334.454,92.527 326.505,94.656 "/> +<polygon fill="#00DFE0" points="286.337,24.246 294.288,22.115 292.157,30.066 284.206,32.195 "/> +<polygon fill="#00DFE0" points="227.407,106.439 243.308,102.178 239.046,118.079 223.146,122.339 "/> +<polygon fill="#00DFE0" points="275.108,93.658 291.009,89.398 286.747,105.299 270.847,109.557 "/> +<polygon fill="#00DFE0" points="254.946,113.816 270.847,109.557 266.585,125.458 250.685,129.716 "/> +<polygon fill="#00DFE0" points="156.016,14.891 163.965,12.762 161.834,20.711 153.885,22.84 "/> +<polygon fill="#00DFE0" points="108.314,27.67 116.266,25.541 114.135,33.49 106.184,35.619 "/> +<polygon fill="#00DFE0" points="131.387,10.42 135.361,9.355 134.295,13.33 130.32,14.395 "/> +<polygon fill="#00DFE0" points="83.686,23.201 87.66,22.137 86.596,26.111 82.619,27.176 "/> +<polygon fill="#00DFE0" points="56.146,15.824 60.121,14.76 59.055,18.734 55.08,19.799 "/> +<polygon fill="#00DFE0" points="1.066,1.064 5.041,0 3.977,3.975 0,5.039 "/> +<polygon fill="#00DFE0" points="8.443,28.604 12.418,27.539 11.354,31.514 7.377,32.578 "/> +<polygon fill="#00DFE0" points="23.201,83.68 27.176,82.615 26.111,86.59 22.135,87.654 "/> +<polygon fill="#00DFE0" points="30.58,111.219 34.555,110.154 33.49,114.129 29.514,115.194 "/> +<polygon fill="#00DFE0" points="58.121,118.603 62.096,117.538 61.029,121.513 57.055,122.577 "/> +<polygon fill="#00DFE0" points="85.66,125.823 89.635,124.759 88.57,128.733 84.594,129.798 "/> +<polygon fill="#00DFE0" points="113.201,133.362 117.176,132.298 116.109,136.272 112.135,137.337 "/> +<polygon fill="#00DFE0" points="195.819,155.499 199.794,154.435 198.729,158.409 194.753,159.474 "/> +<polygon fill="#00DFE0" points="234.167,12.396 238.142,11.332 237.077,15.307 233.101,16.371 "/> +<polygon fill="#00DFE0" points="261.708,19.777 265.683,18.713 264.618,22.688 260.642,23.752 "/> +<polygon fill="#00DFE0" points="324.167,62.076 328.142,61.012 327.077,64.986 323.101,66.051 "/> +<polygon fill="#00DFE0" points="311.384,109.775 315.358,108.711 314.294,112.686 310.317,113.75 "/> +<polygon fill="#00DFE0" points="33.072,33.072 41.023,30.943 38.893,38.893 30.941,41.021 "/> +<polygon fill="#00DFE0" points="60.613,40.297 68.564,38.168 66.434,46.117 58.482,48.246 "/> +<polygon fill="#00DFE0" points="20.291,55.211 28.242,53.08 26.111,61.031 18.16,63.16 "/> +<polygon fill="#00DFE0" points="40.451,60.609 48.402,58.48 46.271,66.43 38.32,68.559 "/> +<polygon fill="#00DFE0" points="137.83,137.831 145.779,135.7 143.648,143.651 135.699,145.78 "/> +<polygon fill="#00DFE0" points="47.83,88.15 55.781,86.021 53.65,93.971 45.699,96.1 "/> +<polygon fill="#00DFE0" points="130.033,29.23 145.934,24.969 141.672,40.869 125.771,45.129 "/> +<polygon fill="#00DFE0" points="183.556,22.27 191.505,20.139 189.374,28.09 181.424,30.219 "/> +<polygon fill="#00DFE0" points="157.572,36.607 173.473,32.348 169.211,48.248 153.311,52.506 "/> +<polygon fill="#00DFE0" points="211.095,29.646 219.044,27.518 216.913,35.467 208.964,37.596 "/> +<polygon fill="#00DFE0" points="185.112,43.986 201.013,39.725 196.751,55.625 180.85,59.885 "/> +<polygon fill="#00DFE0" points="232.813,31.205 248.714,26.945 244.452,42.846 228.552,47.104 "/> +<polygon fill="#00DFE0" points="212.651,51.363 228.552,47.104 224.29,63.004 208.39,67.262 "/> +<polygon fill="#00DFE0" points="260.353,38.584 276.253,34.322 271.991,50.223 256.091,54.482 "/> +<polygon fill="#00DFE0" points="287.892,45.961 303.792,41.701 299.53,57.602 283.63,61.859 "/> +<polygon fill="#00DFE0" points="267.729,66.119 283.63,61.859 279.368,77.76 263.468,82.018 "/> +<polygon fill="#00DFE0" points="295.269,73.498 311.169,69.236 306.907,85.137 291.007,89.396 "/> +<polygon fill="#4472DB" points="89.713,69.553 78.072,57.912 93.973,53.652 105.613,65.293 "/> +<polygon fill="#4472DB" points="69.551,89.711 57.91,78.07 73.811,73.811 85.451,85.451 "/> +<polygon fill="#4472DB" points="152.168,111.844 140.527,100.203 156.428,95.945 168.068,107.584 "/> +<polygon fill="#4472DB" points="179.707,119.224 168.066,107.582 183.968,103.322 195.608,114.963 "/> +<polygon fill="#4472DB" points="207.247,126.601 195.606,114.959 211.507,110.701 223.147,122.341 "/> +<polygon fill="#4472DB" points="76.93,117.251 65.289,105.609 81.189,101.352 92.83,112.99 "/> +<polygon fill="#4472DB" points="104.469,124.63 92.828,112.988 108.729,108.729 120.369,120.37 "/> +<polygon fill="#4472DB" points="132.008,132.007 120.367,120.366 136.268,116.108 147.908,127.747 "/> +<polygon fill="#4472DB" points="159.547,139.386 147.906,127.745 163.807,123.485 175.447,135.126 "/> +<polygon fill="#4472DB" points="187.087,146.763 175.445,135.122 191.347,130.864 202.987,142.503 "/> +<polygon fill="#4472DB" points="216.757,146.19 210.937,140.37 218.886,138.241 224.706,144.062 "/> +<polygon fill="#4472DB" points="244.302,153.579 238.481,147.759 246.431,145.63 252.251,151.448 "/> +<polygon fill="#4472DB" points="332.325,100.477 326.505,94.656 334.454,92.527 340.274,98.346 "/> +<polygon fill="#4472DB" points="290.026,38.016 284.206,32.195 292.157,30.066 297.978,35.885 "/> +<polygon fill="#4472DB" points="234.786,133.979 223.146,122.339 239.046,118.079 250.687,129.72 "/> +<polygon fill="#4472DB" points="282.487,121.198 270.847,109.557 286.747,105.299 298.388,116.938 "/> +<polygon fill="#4472DB" points="262.325,141.356 250.685,129.716 266.585,125.458 278.226,137.097 "/> +<polygon fill="#4472DB" points="159.705,28.66 153.885,22.84 161.834,20.711 167.654,26.531 "/> +<polygon fill="#4472DB" points="112.004,41.439 106.184,35.619 114.135,33.49 119.955,39.311 "/> +<polygon fill="#4472DB" points="133.23,17.305 130.32,14.395 134.295,13.33 137.205,16.24 "/> +<polygon fill="#4472DB" points="85.529,30.086 82.619,27.176 86.596,26.111 89.506,29.021 "/> +<polygon fill="#4472DB" points="57.99,22.709 55.08,19.799 59.055,18.734 61.965,21.645 "/> +<polygon fill="#4472DB" points="2.91,7.949 0,5.039 3.977,3.975 6.887,6.885 "/> +<polygon fill="#4472DB" points="10.287,35.488 7.377,32.578 11.354,31.514 14.264,34.424 "/> +<polygon fill="#4472DB" points="25.045,90.564 22.135,87.654 26.111,86.59 29.021,89.5 "/> +<polygon fill="#4472DB" points="32.424,118.104 29.514,115.194 33.49,114.129 36.4,117.04 "/> +<polygon fill="#4472DB" points="59.965,125.487 57.055,122.577 61.029,121.513 63.939,124.423 "/> +<polygon fill="#4472DB" points="87.504,132.708 84.594,129.798 88.57,128.733 91.48,131.644 "/> +<polygon fill="#4472DB" points="115.045,140.247 112.135,137.337 116.109,136.272 119.02,139.183 "/> +<polygon fill="#4472DB" points="197.663,162.384 194.753,159.474 198.729,158.409 201.64,161.319 "/> +<polygon fill="#4472DB" points="236.011,19.281 233.101,16.371 237.077,15.307 239.987,18.217 "/> +<polygon fill="#4472DB" points="263.552,26.662 260.642,23.752 264.618,22.688 267.528,25.598 "/> +<polygon fill="#4472DB" points="326.011,68.961 323.101,66.051 327.077,64.986 329.987,67.896 "/> +<polygon fill="#4472DB" points="313.228,116.661 310.317,113.75 314.294,112.686 317.204,115.597 "/> +<polygon fill="#4472DB" points="36.762,46.842 30.941,41.021 38.893,38.893 44.713,44.713 "/> +<polygon fill="#4472DB" points="64.303,54.066 58.482,48.246 66.434,46.117 72.254,51.938 "/> +<polygon fill="#4472DB" points="23.98,68.98 18.16,63.16 26.111,61.031 31.932,66.85 "/> +<polygon fill="#4472DB" points="44.141,74.379 38.32,68.559 46.271,66.43 52.092,72.25 "/> +<polygon fill="#4472DB" points="141.52,151.601 135.699,145.78 143.648,143.651 149.469,149.47 "/> +<polygon fill="#4472DB" points="51.52,101.92 45.699,96.1 53.65,93.971 59.471,99.791 "/> +<polygon fill="#4472DB" points="137.412,56.77 125.771,45.129 141.672,40.869 153.313,52.51 "/> +<polygon fill="#4472DB" points="187.245,36.039 181.424,30.219 189.374,28.09 195.194,33.908 "/> +<polygon fill="#4472DB" points="164.951,64.146 153.311,52.506 169.211,48.248 180.852,59.887 "/> +<polygon fill="#4472DB" points="214.784,43.416 208.964,37.596 216.913,35.467 222.733,41.287 "/> +<polygon fill="#4472DB" points="192.491,71.525 180.85,59.885 196.751,55.625 208.392,67.266 "/> +<polygon fill="#4472DB" points="240.192,58.744 228.552,47.104 244.452,42.846 256.093,54.484 "/> +<polygon fill="#4472DB" points="267.731,66.123 256.091,54.482 271.991,50.223 283.632,61.863 "/> +<polygon fill="#4472DB" points="295.271,73.5 283.63,61.859 299.53,57.602 311.171,69.24 "/> +<polygon fill="#4472DB" points="302.647,101.037 291.007,89.396 306.907,85.137 318.548,96.777 "/> +<path fill="#4472DB" d="M1.465,191.705V174.12h1.055l9.918,11.02v-11.02h3.166v17.585h-1.161l-9.813-10.903v10.903H1.465z"/> +<path fill="#4472DB" d="M20.244,189.179c-1.513-1.684-2.269-3.773-2.269-6.266c0-2.502,0.756-4.592,2.269-6.272 + c1.512-1.681,3.394-2.521,5.645-2.521s4.132,0.84,5.645,2.521c1.512,1.681,2.268,3.771,2.268,6.272c0,2.501-0.756,4.592-2.268,6.272 + c-1.513,1.68-3.394,2.52-5.645,2.52S21.756,190.863,20.244,189.179z M25.9,188.423c1.399,0,2.539-0.527,3.418-1.582 + c0.879-1.057,1.319-2.365,1.319-3.928c0-1.563-0.44-2.873-1.319-3.928c-0.879-1.055-2.026-1.583-3.439-1.583 + c-1.4,0-2.54,0.528-3.419,1.583s-1.319,2.364-1.319,3.928c0,1.563,0.439,2.871,1.319,3.928 + C23.339,187.896,24.486,188.423,25.9,188.423z"/> +<path fill="#4472DB" d="M37.049,174.12l4.495,12.883l4.579-12.883h3.376l-6.32,17.585h-3.165l-6.341-17.585H37.049z"/> +<path fill="#4472DB" d="M51.544,191.705v-17.574l11.627-0.011v3.282h-8.462v3.752h6.341v3.271h-6.341v3.998h8.441v3.282H51.544z"/> +<path fill="#4472DB" d="M69.879,174.12v14.303h8.441v3.282H66.714V174.12H69.879z"/> +<path fill="#4472DB" d="M88.853,191.705V174.12h1.055l6.859,8.675l6.869-8.675h1.055v17.585h-3.166l-0.011-10.199l-4.748,5.861 + l-4.749-5.861v10.199H88.853z"/> +<path fill="#4472DB" d="M107.011,191.705l6.331-17.585h3.166l6.32,17.572l-3.366,0.013l-0.949-2.696h-7.175l-0.95,2.696H107.011z + M115.009,178.81l-2.405,6.682h4.748L115.009,178.81z"/> +<path fill="#4472DB" d="M134.864,174.12v3.282h-5.275v14.303h-3.166v-14.303h-5.275v-3.282H134.864z"/> +<path fill="#4472DB" d="M137.283,191.705v-17.574l11.627-0.011v3.282h-8.462v3.752h6.341v3.271h-6.341v3.998h8.441v3.282H137.283z" + /> +<path fill="#4472DB" d="M161.732,184.038l3.946,7.667h-3.629l-3.788-7.269h-2.891v7.269h-3.165V174.12h6.9 + c3.693,0,5.54,1.688,5.54,5.064C164.645,181.725,163.674,183.342,161.732,184.038z M155.37,181.154h4.432 + c1.273-0.023,1.928-0.668,1.962-1.936c-0.035-1.156-0.679-1.757-1.931-1.805h-4.463V181.154z"/> +<path fill="#4472DB" d="M168.19,174.108h3.155v17.597h-3.155V174.108z"/> +<path fill="#4472DB" d="M173.795,191.705l6.331-17.585h3.166l6.32,17.572l-3.366,0.013l-0.949-2.696h-7.176l-0.95,2.696H173.795z + M181.793,178.81l-2.405,6.682h4.749L181.793,178.81z"/> +<path fill="#4472DB" d="M194.956,174.12v14.303h8.441v3.282h-11.605V174.12H194.956z"/> +<path fill="#4472DB" d="M214.464,174.705c0.809,0.392,1.564,0.979,2.268,1.76l-2.11,2.345c-0.703-0.938-1.688-1.407-2.954-1.407 + c-1.266,0-2.074,0.332-2.427,0.997c-0.352,0.664-0.352,1.23,0,1.7c0.353,0.469,1.161,0.82,2.427,1.055 + c1.336,0.156,2.55,0.645,3.641,1.466c1.09,0.819,1.636,2.129,1.636,3.927c0,1.407-0.583,2.618-1.747,3.634 + c-1.164,1.017-2.52,1.524-4.067,1.524c-1.471,0-2.697-0.234-3.683-0.703c-0.984-0.469-1.828-1.095-2.532-1.876l2.11-2.345 + c0.703,0.938,1.899,1.485,3.588,1.642c1.406,0,2.283-0.332,2.632-0.996c0.349-0.665,0.349-1.329,0-1.993 + c-0.349-0.665-1.226-1.075-2.632-1.231c-1.266-0.156-2.427-0.587-3.482-1.289c-1.055-0.704-1.583-1.916-1.583-3.635 + c0-1.556,0.601-2.805,1.799-3.746c1.199-0.941,2.434-1.412,3.699-1.412C212.515,174.12,213.654,174.315,214.464,174.705z"/> +<path fill="#4472DB" d="M227.696,191.705v-17.597h6.1c4.924,0,7.385,2.935,7.385,8.805c0,5.86-2.461,8.792-7.385,8.792H227.696z + M233.796,188.199c2.806-0.007,4.213-1.771,4.221-5.286c-0.008-3.519-1.415-5.276-4.221-5.276h-2.934v10.563H233.796z"/> +<path fill="#4472DB" d="M244.362,174.108h3.155v17.597h-3.155V174.108z"/> +<path fill="#4472DB" d="M259.909,174.705c0.809,0.392,1.564,0.979,2.27,1.76l-2.11,2.345c-0.705-0.938-1.688-1.407-2.956-1.407 + c-1.265,0-2.074,0.332-2.426,0.997c-0.352,0.664-0.352,1.23,0,1.7c0.352,0.469,1.161,0.82,2.426,1.055 + c1.338,0.156,2.551,0.645,3.641,1.466c1.091,0.819,1.636,2.129,1.636,3.927c0,1.407-0.582,2.618-1.746,3.634 + c-1.164,1.017-2.521,1.524-4.067,1.524c-1.471,0-2.698-0.234-3.682-0.703c-0.986-0.469-1.83-1.095-2.532-1.876l2.109-2.345 + c0.703,0.938,1.899,1.485,3.587,1.642c1.407,0,2.285-0.332,2.633-0.996c0.349-0.665,0.349-1.329,0-1.993 + c-0.348-0.665-1.226-1.075-2.633-1.231c-1.266-0.156-2.427-0.587-3.481-1.289c-1.056-0.704-1.583-1.916-1.583-3.635 + c0-1.556,0.601-2.805,1.8-3.746s2.432-1.412,3.697-1.412C257.961,174.12,259.101,174.315,259.909,174.705z"/> +<path fill="#4472DB" d="M266.71,189.179c-1.516-1.676-2.274-3.777-2.274-6.302c0.007-2.47,0.767-4.546,2.279-6.23 + s3.387-2.526,5.624-2.526c2.258,0,4.196,0.78,5.813,2.345l-2.11,2.566c-1.076-0.938-2.311-1.407-3.703-1.407 + c-1.421,0.009-2.565,0.502-3.435,1.479s-1.304,2.228-1.304,3.751c0.008,1.634,0.447,2.931,1.32,3.894 + c0.871,0.961,2.019,1.441,3.439,1.441c1.42,0,2.647-0.466,3.682-1.396l2.11,2.567c-1.611,1.563-3.549,2.345-5.813,2.345 + C270.102,191.697,268.226,190.855,266.71,189.179z"/> +<path fill="#4472DB" d="M281.622,189.179c-1.512-1.684-2.268-3.773-2.268-6.266c0-2.502,0.756-4.592,2.268-6.272 + c1.513-1.681,3.395-2.521,5.646-2.521s4.133,0.84,5.645,2.521c1.513,1.681,2.269,3.771,2.269,6.272c0,2.501-0.756,4.592-2.269,6.272 + c-1.512,1.68-3.394,2.52-5.645,2.52S283.135,190.863,281.622,189.179z M287.278,188.423c1.399,0,2.539-0.527,3.419-1.582 + c0.878-1.057,1.318-2.365,1.318-3.928c0-1.563-0.44-2.873-1.318-3.928c-0.88-1.055-2.026-1.583-3.44-1.583 + c-1.399,0-2.539,0.528-3.418,1.583c-0.88,1.055-1.319,2.364-1.319,3.928c0,1.563,0.439,2.871,1.319,3.928 + C284.718,187.896,285.864,188.423,287.278,188.423z"/> +<path fill="#4472DB" d="M298.535,174.12l4.495,12.883l4.579-12.883h3.377l-6.32,17.585H301.5l-6.342-17.585H298.535z"/> +<path fill="#4472DB" d="M313.139,191.705v-17.574l11.627-0.011v3.282h-8.463v3.752h6.342v3.271h-6.342v3.998h8.441v3.282H313.139z" + /> +<path fill="#4472DB" d="M337.913,184.038l3.945,7.667h-3.63l-3.788-7.269h-2.891v7.269h-3.165V174.12h6.9 + c3.693,0,5.54,1.688,5.54,5.064C340.825,181.725,339.854,183.342,337.913,184.038z M331.55,181.154h4.432 + c1.273-0.023,1.928-0.668,1.963-1.936c-0.035-1.156-0.68-1.757-1.931-1.805h-4.464V181.154z"/> +<path fill="#4472DB" d="M342.036,174.12h3.714l3.671,5.744l3.757-5.744h3.63l-5.804,8.793v8.792h-3.165v-8.792L342.036,174.12z"/> +<polygon fill="#4472DB" points="98.127,101.262 90.656,101.262 94.012,102.851 101.336,102.851 101.336,79.317 98.127,75.787 "/> +<polygon fill="#4472DB" points="124.025,60.173 124.025,101.262 121.286,101.262 124.042,102.851 126.727,102.851 126.727,62.999 + "/> +<polygon fill="#4472DB" points="116.555,84.642 96.879,62.999 93.146,60.173 116.555,85.922 "/> +<polygon fill="#FFFFFF" points="124.025,60.173 116.555,60.173 116.555,84.642 116.555,85.922 93.146,60.173 90.656,60.173 + 90.656,101.262 98.127,101.262 98.127,75.787 101.336,79.317 121.286,101.262 124.025,101.262 "/> +<path fill="none" d="M142.09,74.569c-2.035,2.417-3.051,5.416-3.051,8.997c0,3.58,1.016,6.58,3.051,8.996 + c0.207,0.246,0.425,0.471,0.645,0.692c1.544,0.914,3.319,1.375,5.33,1.375c3.238,0,5.875-1.209,7.91-3.625 + c2.035-2.418,3.053-5.416,3.053-8.997s-1.018-6.579-3.053-8.997c-0.207-0.246-0.425-0.471-0.645-0.692 + c-1.543-0.914-3.318-1.375-5.33-1.375C146.762,70.943,144.125,72.152,142.09,74.569z"/> +<path fill="#4472DB" d="M163.086,69.198c-1.014-1.115-2.108-2.049-3.265-2.841c0.438,0.401,0.866,0.826,1.281,1.281 + c3.5,3.85,5.25,8.639,5.25,14.368s-1.75,10.519-5.25,14.368s-7.854,5.773-13.061,5.773c-3.695,0-6.951-0.991-9.786-2.933 + c3.262,2.993,7.184,4.491,11.771,4.491c5.207,0,9.561-1.924,13.061-5.773s5.25-8.639,5.25-14.367 + C168.336,77.837,166.586,73.048,163.086,69.198z"/> +<path fill="#4472DB" d="M142.09,92.563c-2.035-2.416-3.051-5.416-3.051-8.996c0-3.581,1.016-6.58,3.051-8.997 + s4.672-3.626,7.91-3.626c2.011,0,3.786,0.461,5.33,1.375c-1.941-1.949-4.375-2.933-7.314-2.933c-3.238,0-5.875,1.209-7.91,3.625 + c-2.035,2.418-3.051,5.416-3.051,8.997s1.016,6.579,3.051,8.997c0.784,0.931,1.662,1.678,2.629,2.25 + C142.515,93.033,142.297,92.809,142.09,92.563z"/> +<path fill="#FFFFFF" d="M161.102,96.375c3.5-3.85,5.25-8.639,5.25-14.368s-1.75-10.519-5.25-14.368 + c-0.415-0.456-0.843-0.88-1.281-1.281c-3.264-2.992-7.189-4.492-11.78-4.492c-5.209,0-9.563,1.925-13.063,5.773 + c-3.5,3.85-5.248,8.639-5.248,14.368c0,5.712,1.748,10.497,5.248,14.354c1.017,1.121,2.115,2.06,3.276,2.854 + c2.835,1.942,6.091,2.933,9.786,2.933C153.249,102.148,157.602,100.225,161.102,96.375z M140.106,91.004 + c-2.035-2.418-3.051-5.416-3.051-8.997s1.016-6.579,3.051-8.997c2.035-2.416,4.672-3.625,7.91-3.625 + c2.938,0,5.373,0.984,7.314,2.933c0.22,0.221,0.438,0.446,0.645,0.692c2.035,2.418,3.053,5.416,3.053,8.997 + s-1.018,6.579-3.053,8.997c-2.035,2.416-4.672,3.625-7.91,3.625c-2.011,0-3.786-0.461-5.33-1.375 + C141.768,92.682,140.89,91.935,140.106,91.004z"/> +<polygon fill="#4472DB" points="179.49,101.262 172.02,101.262 174.044,102.851 181.515,102.851 181.515,79.904 179.49,77.43 "/> +<polygon fill="#4472DB" points="190.696,91.127 192.721,92.717 201.906,81.489 201.902,77.43 "/> +<path fill="#4472DB" d="M209.399,60.145c0,0.028,0,41.117,0,41.117h-7.471l2.023,1.589h7.471V61.762L209.399,60.145z"/> +<polygon fill="#4472DB" points="191.291,79.699 176.968,61.762 174.51,60.173 190.696,80.443 "/> +<path fill="#FFFFFF" d="M209.399,60.173c-0.008,0-2.49,0-2.49,0l-15.618,19.526l-0.595,0.744L174.51,60.173h-2.49v41.089h7.471 + V77.43l2.024,2.474l9.182,11.223l0.362-0.442l10.844-13.255l0.004,4.059l0.022,19.772h7.471V60.173z"/> +<polygon fill="none" points="237.677,86.745 233.432,74.755 229.072,86.745 "/> +<polygon fill="#4472DB" points="223.482,94.962 221.241,101.262 213.272,101.262 215.296,102.851 223.265,102.851 225.506,96.552 + 240.981,96.552 240.416,94.962 "/> +<polygon fill="#4472DB" points="252.624,102.851 237.708,61.762 235.685,60.173 250.6,101.234 242.79,101.261 244.681,102.851 "/> +<polygon fill="#4472DB" points="233.432,74.755 232.148,71.13 226.471,86.745 229.072,86.745 "/> +<path fill="#FFFFFF" d="M235.685,60.173h-7.471l-14.941,41.089h7.969l2.241-6.299h16.934l0.565,1.59l1.615,4.541 + c0.002,0.007,0.061,0.168,0.061,0.168l0.133,0l7.81-0.027L235.685,60.173z M232.148,71.13l1.283,3.625l4.245,11.989h-8.604h-2.602 + L232.148,71.13z"/> +<path fill="none" d="M263.963,69.98v23.092h4.899c6.624-0.018,9.944-4.136,9.961-12.354c-0.008-4.358-0.956-7.548-2.823-9.596 + c-1.401-0.757-3.104-1.142-5.114-1.142H263.963z"/> +<path fill="#4472DB" d="M263.963,69.98h6.923c2.011,0,3.713,0.385,5.114,1.142c-1.653-1.813-4.026-2.731-7.138-2.731h-6.923v24.681 + h2.023V69.98z"/> +<path fill="#4472DB" d="M281.001,64.315c3.521,3.394,5.293,8.853,5.293,16.402c0,13.697-5.812,20.544-17.432,20.544h-14.394 + l2.023,1.589h14.394c11.621,0,17.432-6.847,17.432-20.543C288.317,73.433,285.868,67.447,281.001,64.315z"/> +<path fill="#FFFFFF" d="M286.294,80.717c0-7.549-1.771-13.008-5.293-16.402c-2.875-2.772-6.914-4.17-12.139-4.17h-14.394v41.117 + h14.394C280.482,101.262,286.294,94.415,286.294,80.717z M261.939,68.391h6.923c3.111,0,5.484,0.918,7.138,2.731 + c1.867,2.047,2.815,5.238,2.823,9.596c-0.017,8.219-3.337,12.336-9.961,12.354h-4.899h-2.023V68.391z"/> +</svg> diff --git a/gui/src/setupTests.js b/gui/src/setupTests.js index 03ed708b22ae79f9acc96ffb2b352f83b7ddb08c..0dd4457ebe36487a18eb375aebc1da4c45f4d85b 100644 --- a/gui/src/setupTests.js +++ b/gui/src/setupTests.js @@ -11,7 +11,7 @@ global.nomadEnv = { 'appBase': 'http://nomad-lab.eu/prod/rae/beta', 'debug': false, 'version': { - 'label': '1.0.7', + 'label': '1.0.8', 'isBeta': false, 'isTest': true, 'usesBetaData': true, diff --git a/gui/yarn.lock b/gui/yarn.lock index e5fc8cd173fb9f641a6772c161f31a87681ce44b..0c1e3aa0a863bafc30101ae354dd5dfde35c7e8c 100644 --- a/gui/yarn.lock +++ b/gui/yarn.lock @@ -1695,6 +1695,11 @@ dependencies: type-detect "4.0.8" +"@socket.io/component-emitter@~3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" + integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== + "@svgr/babel-plugin-add-jsx-attribute@^4.2.0": version "4.2.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz" @@ -1883,16 +1888,52 @@ dependencies: "@babel/types" "^7.3.0" +"@types/component-emitter@^1.2.10": + version "1.2.11" + resolved "https://registry.yarnpkg.com/@types/component-emitter/-/component-emitter-1.2.11.tgz#50d47d42b347253817a39709fef03ce66a108506" + integrity sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ== + "@types/cookie@^0.3.1": version "0.3.3" resolved "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz" integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow== +"@types/cookie@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" + integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== + +"@types/cors@^2.8.12": + version "2.8.12" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" + integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== + +"@types/eslint-scope@^3.7.3": + version "3.7.3" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224" + integrity sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + "@types/eslint-visitor-keys@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz" integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== +"@types/eslint@*": + version "8.4.2" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.2.tgz#48f2ac58ab9c631cb68845c3d956b28f79fad575" + integrity sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^0.0.51": + version "0.0.51" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" + integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== + "@types/glob@^7.1.1": version "7.2.0" resolved "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz" @@ -1936,6 +1977,11 @@ dependencies: "@types/istanbul-lib-report" "*" +"@types/json-schema@*", "@types/json-schema@^7.0.8": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6", "@types/json-schema@^7.0.7": version "7.0.9" resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz" @@ -1956,6 +2002,11 @@ resolved "https://registry.npmjs.org/@types/node/-/node-16.11.10.tgz" integrity sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA== +"@types/node@>=10.0.0": + version "17.0.31" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.31.tgz#a5bb84ecfa27eec5e1c802c6bbf8139bdb163a5d" + integrity sha512-AR0x5HbXGqkEx9CadRH3EBYx/VkiUgZIhP4wvPn/+5KIsgpNoyFaRlVe0Zlx9gRtg8fA06a9tskE2MSN7TcG4Q== + "@types/object-assign@^4.0.30": version "4.0.30" resolved "https://registry.npmjs.org/@types/object-assign/-/object-assign-4.0.30.tgz" @@ -2234,6 +2285,14 @@ "@typescript-eslint/types" "4.33.0" eslint-visitor-keys "^2.0.0" +"@webassemblyjs/ast@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" + integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ast@1.8.5": version "1.8.5" resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz" @@ -2243,45 +2302,36 @@ "@webassemblyjs/helper-wasm-bytecode" "1.8.5" "@webassemblyjs/wast-parser" "1.8.5" -"@webassemblyjs/ast@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz" - integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== - dependencies: - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" +"@webassemblyjs/floating-point-hex-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" + integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== "@webassemblyjs/floating-point-hex-parser@1.8.5": version "1.8.5" resolved "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz" integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ== -"@webassemblyjs/floating-point-hex-parser@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz" - integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== +"@webassemblyjs/helper-api-error@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" + integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== "@webassemblyjs/helper-api-error@1.8.5": version "1.8.5" resolved "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz" integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA== -"@webassemblyjs/helper-api-error@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz" - integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== +"@webassemblyjs/helper-buffer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" + integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== "@webassemblyjs/helper-buffer@1.8.5": version "1.8.5" resolved "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz" integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q== -"@webassemblyjs/helper-buffer@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz" - integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA== - "@webassemblyjs/helper-code-frame@1.8.5": version "1.8.5" resolved "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz" @@ -2289,23 +2339,11 @@ dependencies: "@webassemblyjs/wast-printer" "1.8.5" -"@webassemblyjs/helper-code-frame@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz" - integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA== - dependencies: - "@webassemblyjs/wast-printer" "1.9.0" - "@webassemblyjs/helper-fsm@1.8.5": version "1.8.5" resolved "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz" integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow== -"@webassemblyjs/helper-fsm@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz" - integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw== - "@webassemblyjs/helper-module-context@1.8.5": version "1.8.5" resolved "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz" @@ -2314,22 +2352,34 @@ "@webassemblyjs/ast" "1.8.5" mamacro "^0.0.3" -"@webassemblyjs/helper-module-context@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz" - integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g== +"@webassemblyjs/helper-numbers@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" + integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== dependencies: - "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/floating-point-hex-parser" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" + integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== "@webassemblyjs/helper-wasm-bytecode@1.8.5": version "1.8.5" resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz" integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ== -"@webassemblyjs/helper-wasm-bytecode@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz" - integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== +"@webassemblyjs/helper-wasm-section@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" + integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" "@webassemblyjs/helper-wasm-section@1.8.5": version "1.8.5" @@ -2341,15 +2391,12 @@ "@webassemblyjs/helper-wasm-bytecode" "1.8.5" "@webassemblyjs/wasm-gen" "1.8.5" -"@webassemblyjs/helper-wasm-section@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz" - integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw== +"@webassemblyjs/ieee754@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" + integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" + "@xtuc/ieee754" "^1.2.0" "@webassemblyjs/ieee754@1.8.5": version "1.8.5" @@ -2358,12 +2405,12 @@ dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/ieee754@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz" - integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg== +"@webassemblyjs/leb128@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" + integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== dependencies: - "@xtuc/ieee754" "^1.2.0" + "@xtuc/long" "4.2.2" "@webassemblyjs/leb128@1.8.5": version "1.8.5" @@ -2372,22 +2419,29 @@ dependencies: "@xtuc/long" "4.2.2" -"@webassemblyjs/leb128@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz" - integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw== - dependencies: - "@xtuc/long" "4.2.2" +"@webassemblyjs/utf8@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" + integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== "@webassemblyjs/utf8@1.8.5": version "1.8.5" resolved "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz" integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw== -"@webassemblyjs/utf8@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz" - integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== +"@webassemblyjs/wasm-edit@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" + integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/helper-wasm-section" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-opt" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/wast-printer" "1.11.1" "@webassemblyjs/wasm-edit@1.8.5": version "1.8.5" @@ -2403,19 +2457,16 @@ "@webassemblyjs/wasm-parser" "1.8.5" "@webassemblyjs/wast-printer" "1.8.5" -"@webassemblyjs/wasm-edit@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz" - integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw== +"@webassemblyjs/wasm-gen@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" + integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/helper-wasm-section" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-opt" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - "@webassemblyjs/wast-printer" "1.9.0" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" "@webassemblyjs/wasm-gen@1.8.5": version "1.8.5" @@ -2428,16 +2479,15 @@ "@webassemblyjs/leb128" "1.8.5" "@webassemblyjs/utf8" "1.8.5" -"@webassemblyjs/wasm-gen@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz" - integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA== +"@webassemblyjs/wasm-opt@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" + integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" "@webassemblyjs/wasm-opt@1.8.5": version "1.8.5" @@ -2449,15 +2499,17 @@ "@webassemblyjs/wasm-gen" "1.8.5" "@webassemblyjs/wasm-parser" "1.8.5" -"@webassemblyjs/wasm-opt@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz" - integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A== +"@webassemblyjs/wasm-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" + integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" "@webassemblyjs/wasm-parser@1.8.5": version "1.8.5" @@ -2471,18 +2523,6 @@ "@webassemblyjs/leb128" "1.8.5" "@webassemblyjs/utf8" "1.8.5" -"@webassemblyjs/wasm-parser@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz" - integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - "@webassemblyjs/wast-parser@1.8.5": version "1.8.5" resolved "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz" @@ -2495,16 +2535,12 @@ "@webassemblyjs/helper-fsm" "1.8.5" "@xtuc/long" "4.2.2" -"@webassemblyjs/wast-parser@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz" - integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw== +"@webassemblyjs/wast-printer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" + integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/floating-point-hex-parser" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-code-frame" "1.9.0" - "@webassemblyjs/helper-fsm" "1.9.0" + "@webassemblyjs/ast" "1.11.1" "@xtuc/long" "4.2.2" "@webassemblyjs/wast-printer@1.8.5": @@ -2516,15 +2552,6 @@ "@webassemblyjs/wast-parser" "1.8.5" "@xtuc/long" "4.2.2" -"@webassemblyjs/wast-printer@1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz" - integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" - "@xtuc/long" "4.2.2" - "@welldone-software/why-did-you-render@^6.2.1": version "6.2.3" resolved "https://registry.npmjs.org/@welldone-software/why-did-you-render/-/why-did-you-render-6.2.3.tgz" @@ -2576,6 +2603,11 @@ acorn-globals@^6.0.0: acorn "^7.1.1" acorn-walk "^7.1.1" +acorn-import-assertions@^1.7.6: + version "1.8.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" + integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== + acorn-jsx@^5.2.0, acorn-jsx@^5.3.1: version "5.3.2" resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" @@ -2596,7 +2628,7 @@ acorn@^5.5.3: resolved "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz" integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== -acorn@^6.0.1, acorn@^6.0.4, acorn@^6.2.1, acorn@^6.4.1: +acorn@^6.0.1, acorn@^6.0.4, acorn@^6.2.1: version "6.4.2" resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz" integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== @@ -2611,6 +2643,11 @@ acorn@^8.2.4: resolved "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz" integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== +acorn@^8.4.1, acorn@^8.5.0: + version "8.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== + address@1.1.2, address@^1.0.1: version "1.1.2" resolved "https://registry.npmjs.org/address/-/address-1.1.2.tgz" @@ -2627,11 +2664,6 @@ adjust-sourcemap-loader@2.0.0: object-path "0.11.4" regex-parser "2.2.10" -after@0.8.2: - version "0.8.2" - resolved "https://registry.npmjs.org/after/-/after-0.8.2.tgz" - integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= - agent-base@6: version "6.0.2" resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" @@ -2667,7 +2699,7 @@ ajv@6.5.3: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4: +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2994,11 +3026,6 @@ array.prototype.flatmap@^1.2.5: define-properties "^1.1.3" es-abstract "^1.19.0" -arraybuffer.slice@~0.0.7: - version "0.0.7" - resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz" - integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== - arrify@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz" @@ -3365,11 +3392,6 @@ bach@^1.0.0: async-settle "^1.0.0" now-and-later "^2.0.0" -backo2@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz" - integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= - bail@^1.0.0: version "1.0.5" resolved "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz" @@ -3390,11 +3412,6 @@ base16@^1.0.0: resolved "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz" integrity sha1-4pf2DX7BAUp6lxo568ipjAtoHnA= -base64-arraybuffer@0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz" - integrity sha1-mBjHngWbE1X5fgQooBfIOOkLqBI= - base64-js@1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz" @@ -3405,9 +3422,9 @@ base64-js@^1.0.2: resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -base64id@2.0.0: +base64id@2.0.0, base64id@~2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== base@^0.11.1: @@ -3469,11 +3486,6 @@ bit-twiddle@^1.0.0: resolved "https://registry.npmjs.org/bit-twiddle/-/bit-twiddle-1.0.2.tgz" integrity sha1-DGwfq+KyPRcXPZpht7cJPrnhdp4= -blob@0.0.5: - version "0.0.5" - resolved "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz" - integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== - bluebird@^3.5.5: version "3.7.2" resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz" @@ -3583,35 +3595,35 @@ browser-resolve@^1.11.3: dependencies: resolve "1.1.7" -browser-sync-client@^2.27.7: - version "2.27.7" - resolved "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.27.7.tgz" - integrity sha512-wKg9UP9a4sCIkBBAXUdbkdWFJzfSAQizGh+nC19W9y9zOo9s5jqeYRFUUbs7x5WKhjtspT+xetVp9AtBJ6BmWg== +browser-sync-client@^2.27.9: + version "2.27.9" + resolved "https://registry.yarnpkg.com/browser-sync-client/-/browser-sync-client-2.27.9.tgz#3a4bff71d1d657dff6106ac234a6bf24c724a9d3" + integrity sha512-FHW8kydp7FXo6jnX3gXJCpHAHtWNLK0nx839nnK+boMfMI1n4KZd0+DmTxHBsHsF3OHud4V4jwoN8U5HExMIdQ== dependencies: etag "1.8.1" fresh "0.5.2" mitt "^1.1.3" rxjs "^5.5.6" -browser-sync-ui@^2.27.7: - version "2.27.7" - resolved "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-2.27.7.tgz" - integrity sha512-Bt4OQpx9p18OIzk0KKyu7jqlvmjacasUlk8ARY3uuIyiFWSBiRgr2i6XY8dEMF14DtbooaEBOpHEu9VCYvMcCw== +browser-sync-ui@^2.27.9: + version "2.27.9" + resolved "https://registry.yarnpkg.com/browser-sync-ui/-/browser-sync-ui-2.27.9.tgz#53253383a6d8cbc921c85f290fa330fdb449d76b" + integrity sha512-rsduR2bRIwFvM8CX6iY/Nu5aWub0WB9zfSYg9Le/RV5N5DEyxJYey0VxdfWCnzDOoelassTDzYQo+r0iJno3qw== dependencies: async-each-series "0.1.1" connect-history-api-fallback "^1" immutable "^3" server-destroy "1.0.1" - socket.io-client "^2.4.0" + socket.io-client "^4.4.1" stream-throttle "^0.1.3" -browser-sync@^2.27.7: - version "2.27.7" - resolved "https://registry.npmjs.org/browser-sync/-/browser-sync-2.27.7.tgz" - integrity sha512-9ElnnA/u+s2Jd+IgY+2SImB+sAEIteHsMG0NR96m7Ph/wztpvJCUpyC2on1KqmG9iAp941j+5jfmd34tEguGbg== +browser-sync@^2.27.9: + version "2.27.9" + resolved "https://registry.yarnpkg.com/browser-sync/-/browser-sync-2.27.9.tgz#e0555cb44bd5ede00685e70e108b393d2966874a" + integrity sha512-3zBtggcaZIeU9so4ja9yxk7/CZu9B3DOL6zkxFpzHCHsQmkGBPVXg61jItbeoa+WXgNLnr1sYES/2yQwyEZ2+w== dependencies: - browser-sync-client "^2.27.7" - browser-sync-ui "^2.27.7" + browser-sync-client "^2.27.9" + browser-sync-ui "^2.27.9" bs-recipes "1.3.4" bs-snippet-injector "^2.0.1" chokidar "^3.5.1" @@ -3637,9 +3649,9 @@ browser-sync@^2.27.7: serve-index "1.9.1" serve-static "1.13.2" server-destroy "1.0.1" - socket.io "2.4.0" + socket.io "^4.4.1" ua-parser-js "1.0.2" - yargs "^15.4.1" + yargs "^17.3.1" browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.2.0" @@ -3723,6 +3735,17 @@ browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.17.5, browserslist@^4 node-releases "^2.0.1" picocolors "^1.0.0" +browserslist@^4.14.5: + version "4.20.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.3.tgz#eb7572f49ec430e054f56d52ff0ebe9be915f8bf" + integrity sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg== + dependencies: + caniuse-lite "^1.0.30001332" + electron-to-chromium "^1.4.118" + escalade "^3.1.1" + node-releases "^2.0.3" + picocolors "^1.0.0" + bs-recipes@1.3.4: version "1.3.4" resolved "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz" @@ -3955,6 +3978,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001035, can resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001283.tgz" integrity sha512-9RoKo841j1GQFSJz/nCXOj0sD7tHBtlowjYlrqIUS812x9/emfBLBt6IyMz1zIaYc/eRL8Cs6HPUVi2Hzq4sIg== +caniuse-lite@^1.0.30001332: + version "1.0.30001339" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001339.tgz#f9aece4ea8156071613b27791547ba0b33f176cf" + integrity sha512-Es8PiVqCe+uXdms0Gu5xP5PF2bxLR7OBp3wUzUnuO7OHzhOfCyg3hdiGWVPVxhiuniOzng+hTc1u3fEQ0TlkSQ== + capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz" @@ -4213,15 +4241,6 @@ cliui@^5.0.0: strip-ansi "^5.2.0" wrap-ansi "^5.1.0" -cliui@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz" - integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^6.2.0" - cliui@^7.0.2: version "7.0.4" resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" @@ -4398,26 +4417,11 @@ complex.js@^2.0.11: resolved "https://registry.npmjs.org/complex.js/-/complex.js-2.0.15.tgz" integrity sha512-gDBvQU8IG139ZBQTSo2qvDFP+lANMGluM779csXOr6ny1NUtA3wkUnCFjlDNH/moAVfXtvClYt6G0zarFbtz5w== -component-bind@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz" - integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= - -component-emitter@1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz" - integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= - component-emitter@^1.2.1, component-emitter@^1.3.0, component-emitter@~1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== -component-inherit@0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz" - integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= - compose-function@3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/compose-function/-/compose-function-3.0.3.tgz" @@ -4657,6 +4661,14 @@ core-util-is@~1.0.0: resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== +cors@~2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + cosmiconfig@^5.0.0, cosmiconfig@^5.2.1: version "5.2.1" resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz" @@ -5354,19 +5366,12 @@ debug@^4.3.3: dependencies: ms "2.1.2" -debug@~3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - -debug@~4.1.0: - version "4.1.1" - resolved "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== +debug@~4.3.1, debug@~4.3.2: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: - ms "^2.1.1" + ms "2.1.2" decamelize@^1.1.1, decamelize@^1.2.0: version "1.2.0" @@ -5798,6 +5803,11 @@ electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.896: resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.3.tgz" integrity sha512-hfpppjYhqIZB8jrNb0rNceQRkSnBN7QJl3W26O1jUv3F3BkQknqy1YTqVXkFnIcFtBc3Qnv5M7r5Lez2iOLgZA== +electron-to-chromium@^1.4.118: + version "1.4.137" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz#186180a45617283f1c012284458510cd99d6787f" + integrity sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA== + elliptic@^6.5.3: version "6.5.4" resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" @@ -5857,47 +5867,39 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" -engine.io-client@~3.5.0: - version "3.5.2" - resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.2.tgz" - integrity sha512-QEqIp+gJ/kMHeUun7f5Vv3bteRHppHH/FMBQX/esFj/fuYfjyUKWGMo3VCvIP/V8bE9KcjHmRZrhIz2Z9oNsDA== - dependencies: - component-emitter "~1.3.0" - component-inherit "0.0.3" - debug "~3.1.0" - engine.io-parser "~2.2.0" - has-cors "1.1.0" - indexof "0.0.1" - parseqs "0.0.6" - parseuri "0.0.6" - ws "~7.4.2" - xmlhttprequest-ssl "~1.6.2" - yeast "0.1.2" - -engine.io-parser@~2.2.0: - version "2.2.1" - resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz" - integrity sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg== +engine.io-client@~6.2.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.2.2.tgz#c6c5243167f5943dcd9c4abee1bfc634aa2cbdd0" + integrity sha512-8ZQmx0LQGRTYkHuogVZuGSpDqYZtCM/nv8zQ68VZ+JkOpazJ7ICdsSpaO6iXwvaU30oFg5QJOJWj8zWqhbKjkQ== dependencies: - after "0.8.2" - arraybuffer.slice "~0.0.7" - base64-arraybuffer "0.1.4" - blob "0.0.5" - has-binary2 "~1.0.2" + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + engine.io-parser "~5.0.3" + ws "~8.2.3" + xmlhttprequest-ssl "~2.0.0" -engine.io@~3.5.0: - version "3.5.0" - resolved "https://registry.npmjs.org/engine.io/-/engine.io-3.5.0.tgz" - integrity sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA== +engine.io-parser@~5.0.3: + version "5.0.4" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.4.tgz#0b13f704fa9271b3ec4f33112410d8f3f41d0fc0" + integrity sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg== + +engine.io@~6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.2.0.tgz#003bec48f6815926f2b1b17873e576acd54f41d0" + integrity sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg== dependencies: + "@types/cookie" "^0.4.1" + "@types/cors" "^2.8.12" + "@types/node" ">=10.0.0" accepts "~1.3.4" base64id "2.0.0" cookie "~0.4.1" - debug "~4.1.0" - engine.io-parser "~2.2.0" - ws "~7.4.2" + cors "~2.8.5" + debug "~4.3.1" + engine.io-parser "~5.0.3" + ws "~8.2.3" -enhanced-resolve@^4.1.0, enhanced-resolve@^4.1.1, enhanced-resolve@^4.5.0: +enhanced-resolve@^4.1.0, enhanced-resolve@^4.1.1: version "4.5.0" resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz" integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== @@ -5906,6 +5908,14 @@ enhanced-resolve@^4.1.0, enhanced-resolve@^4.1.1, enhanced-resolve@^4.5.0: memory-fs "^0.5.0" tapable "^1.0.0" +enhanced-resolve@^5.9.2: + version "5.9.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz#44a342c012cbc473254af5cc6ae20ebd0aae5d88" + integrity sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + enquirer@^2.3.5: version "2.3.6" resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz" @@ -5963,6 +5973,11 @@ es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.19.1: string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.1" +es-module-lexer@^0.9.0: + version "0.9.3" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" + integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== + es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" @@ -6248,6 +6263,14 @@ eslint-plugin-testing-library@^3.10.1: dependencies: "@typescript-eslint/experimental-utils" "^3.10.1" +eslint-scope@5.1.1, eslint-scope@^5.0.0, eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz" @@ -6256,14 +6279,6 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-scope@^5.0.0, eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - eslint-utils@^1.3.1, eslint-utils@^1.4.2, eslint-utils@^1.4.3: version "1.4.3" resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz" @@ -6455,7 +6470,7 @@ eventemitter3@^4.0.0: resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -events@^3.0.0: +events@^3.0.0, events@^3.2.0: version "3.3.0" resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -6920,7 +6935,7 @@ find-cache-dir@^3.2.0: make-dir "^3.0.2" pkg-dir "^4.1.0" -find-up@4.1.0, find-up@^4.0.0, find-up@^4.1.0: +find-up@4.1.0, find-up@^4.0.0: version "4.1.0" resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== @@ -7376,6 +7391,11 @@ glob-to-regexp@^0.3.0: resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz" integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + glob-watcher@^5.0.3: version "5.0.5" resolved "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz" @@ -7504,6 +7524,11 @@ graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2 resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== +graceful-fs@^4.2.9: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + growly@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz" @@ -7610,18 +7635,6 @@ has-bigints@^1.0.1: resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz" integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== -has-binary2@~1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz" - integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw== - dependencies: - isarray "2.0.1" - -has-cors@1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz" - integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" @@ -8073,11 +8086,6 @@ indexes-of@^1.0.1: resolved "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz" integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= -indexof@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz" - integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= - infer-owner@^1.0.3, infer-owner@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz" @@ -8675,11 +8683,6 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= -isarray@2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz" - integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= - isexe@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" @@ -9203,6 +9206,15 @@ jest-worker@^25.1.0: merge-stream "^2.0.0" supports-color "^7.0.0" +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + jest@24.9.0: version "24.9.0" resolved "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz" @@ -9761,6 +9773,11 @@ loader-runner@^2.4.0: resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz" integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + loader-utils@1.2.3: version "1.2.3" resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz" @@ -10213,6 +10230,11 @@ mime-db@1.51.0, "mime-db@>= 1.43.0 < 2": resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz" integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + mime-db@~1.33.0: version "1.33.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz" @@ -10232,6 +10254,13 @@ mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: dependencies: mime-db "1.51.0" +mime-types@^2.1.27: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mime@1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz" @@ -10478,7 +10507,7 @@ negotiator@0.6.2: resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -neo-async@^2.5.0, neo-async@^2.6.1: +neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2: version "2.6.2" resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== @@ -10591,8 +10620,13 @@ node-releases@^2.0.1: resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz" integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== +node-releases@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.4.tgz#f38252370c43854dc48aa431c766c6c398f40476" + integrity sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ== + "nomad-fair-gui@file:.": - version "1.0.4" + version "1.0.8" dependencies: "@date-io/date-fns" "1.x" "@fontsource/material-icons" "^4.2.1" @@ -10621,7 +10655,7 @@ node-releases@^2.0.1: mathjs "^7.1.0" muuri "^0.9.5" muuri-react "^3.1.6" - nomad-fair-gui "file:../../../.cache/yarn/v6/npm-nomad-fair-gui-1.0.4-242748d1-d2ee-4abb-b990-62653a75e0a2-1646650639665/node_modules/nomad-fair-gui" + nomad-fair-gui "file:../../../../Library/Caches/Yarn/v6/npm-nomad-fair-gui-1.0.8-27db3b4d-61a1-4f19-827a-50b28cd081d0-1652177602070/node_modules/nomad-fair-gui" object-hash "^2.0.3" pace "^0.0.4" pace-js "^1.0.2" @@ -10751,7 +10785,7 @@ object-assign@^3.0.0: resolved "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz" integrity sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I= -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -11257,16 +11291,6 @@ parse5@6.0.1: resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== -parseqs@0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz" - integrity sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w== - -parseuri@0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz" - integrity sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow== - parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" @@ -13779,6 +13803,15 @@ schema-utils@^2.5.0, schema-utils@^2.6.0, schema-utils@^2.6.1, schema-utils@^2.6 ajv "^6.12.4" ajv-keywords "^3.5.2" +schema-utils@^3.1.0, schema-utils@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + section-iterator@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/section-iterator/-/section-iterator-2.0.0.tgz" @@ -13880,6 +13913,13 @@ serialize-javascript@^4.0.0: dependencies: randombytes "^2.1.0" +serialize-javascript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + serialize-query-params@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/serialize-query-params/-/serialize-query-params-0.3.0.tgz" @@ -14145,57 +14185,49 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -socket.io-adapter@~1.1.0: - version "1.1.2" - resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz" - integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g== - -socket.io-client@2.4.0, socket.io-client@^2.4.0: +socket.io-adapter@~2.4.0: version "2.4.0" - resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.4.0.tgz" - integrity sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ== + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz#b50a4a9ecdd00c34d4c8c808224daa1a786152a6" + integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg== + +socket.io-client@^4.4.1: + version "4.5.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.5.0.tgz#3858b6183bab31c5c4eaf3efd0fa50840ebb4504" + integrity sha512-HW61c1G7OrYGxaI79WRn17+b03iBCdvhBj4iqyXHBoL5M8w2MSO/vChsjA93knG4GYEai1/vbXWJna9dzxXtSg== dependencies: - backo2 "1.0.2" - component-bind "1.0.0" - component-emitter "~1.3.0" - debug "~3.1.0" - engine.io-client "~3.5.0" - has-binary2 "~1.0.2" - indexof "0.0.1" - parseqs "0.0.6" - parseuri "0.0.6" - socket.io-parser "~3.3.0" - to-array "0.1.4" - -socket.io-parser@~3.3.0: - version "3.3.2" - resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.2.tgz" - integrity sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg== + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.2" + engine.io-client "~6.2.1" + socket.io-parser "~4.2.0" + +socket.io-parser@~4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.0.4.tgz#9ea21b0d61508d18196ef04a2c6b9ab630f4c2b0" + integrity sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g== dependencies: + "@types/component-emitter" "^1.2.10" component-emitter "~1.3.0" - debug "~3.1.0" - isarray "2.0.1" + debug "~4.3.1" -socket.io-parser@~3.4.0: - version "3.4.1" - resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz" - integrity sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A== +socket.io-parser@~4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.0.tgz#3f01e5bc525d94aa52a97ed5cbc12e229bbc4d6b" + integrity sha512-tLfmEwcEwnlQTxFB7jibL/q2+q8dlVQzj4JdRLJ/W/G1+Fu9VSxCx1Lo+n1HvXxKnM//dUuD0xgiA7tQf57Vng== dependencies: - component-emitter "1.2.1" - debug "~4.1.0" - isarray "2.0.1" + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" -socket.io@2.4.0: - version "2.4.0" - resolved "https://registry.npmjs.org/socket.io/-/socket.io-2.4.0.tgz" - integrity sha512-9UPJ1UTvKayuQfVv2IQ3k7tCQC/fboDyIK62i99dAQIyHKaBsNdTpwHLgKJ6guRWxRtC9H+138UwpaGuQO9uWQ== +socket.io@^4.4.1: + version "4.5.0" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.5.0.tgz#78ae2e84784c29267086a416620c18ef95b37186" + integrity sha512-slTYqU2jCgMjXwresG8grhUi/cC6GjzmcfqArzaH3BN/9I/42eZk9yamNvZJdBfTubkjEdKAKs12NEztId+bUA== dependencies: - debug "~4.1.0" - engine.io "~3.5.0" - has-binary2 "~1.0.2" - socket.io-adapter "~1.1.0" - socket.io-client "2.4.0" - socket.io-parser "~3.4.0" + accepts "~1.3.4" + base64id "~2.0.0" + debug "~4.3.2" + engine.io "~6.2.0" + socket.io-adapter "~2.4.0" + socket.io-parser "~4.0.4" sockjs-client@1.4.0: version "1.4.0" @@ -14240,7 +14272,7 @@ source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.6, source-map-support@~0.5.12: +source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -14268,6 +14300,13 @@ source-map@^0.7.3: resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== +source-map@~0.8.0-beta.0: + version "0.8.0-beta.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.8.0-beta.0.tgz#d4c1bb42c3f7ee925f005927ba10709e0d1d1f11" + integrity sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA== + dependencies: + whatwg-url "^7.0.0" + sparkles@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz" @@ -14737,6 +14776,13 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + sver-compat@^1.5.0: version "1.5.0" resolved "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz" @@ -14829,6 +14875,11 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + term-size@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz" @@ -14866,6 +14917,17 @@ terser-webpack-plugin@^1.4.3: webpack-sources "^1.4.0" worker-farm "^1.7.0" +terser-webpack-plugin@^5.1.3: + version "5.3.1" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz#0320dcc270ad5372c1e8993fabbd927929773e54" + integrity sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g== + dependencies: + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + terser "^5.7.2" + terser@^4.1.2, terser@^4.4.3, terser@^4.6.3: version "4.8.0" resolved "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz" @@ -14875,6 +14937,16 @@ terser@^4.1.2, terser@^4.4.3, terser@^4.6.3: source-map "~0.6.1" source-map-support "~0.5.12" +terser@^5.7.2: + version "5.13.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.13.1.tgz#66332cdc5a01b04a224c9fad449fc1a18eaa1799" + integrity sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA== + dependencies: + acorn "^8.5.0" + commander "^2.20.0" + source-map "~0.8.0-beta.0" + source-map-support "~0.5.20" + test-exclude@^5.2.3: version "5.2.3" resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz" @@ -14907,15 +14979,15 @@ tfunk@^4.0.0: chalk "^1.1.3" dlv "^1.1.3" -three@<=0.124.0: - version "0.124.0" - resolved "https://registry.npmjs.org/three/-/three-0.124.0.tgz" - integrity sha512-ROXp1Ly7YyF+jC910DQyAWj++Qlw2lQv0qwYLNQwdDbjk4bsOXAfGO92wYTMPNei1GMJUmCxSxc3MjGBTS09Rg== +three.meshline@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/three.meshline/-/three.meshline-1.4.0.tgz#2a483cbd99cd5f74cf6ee5c253a9a4b4a8169178" + integrity sha512-A8IsiMrWP8zmHisGDAJ76ZD7t/dOF/oCe/FUKNE6Bu01ZYEx8N6IlU/1Plb2aOZtAuWM2A8s8qS3hvY0OFuvOw== -threejs-meshline@^2.0.12: - version "2.0.12" - resolved "https://registry.npmjs.org/threejs-meshline/-/threejs-meshline-2.0.12.tgz" - integrity sha512-2U3SyGWAotT/TJCO9NhBDiaAPUq8X+bgh7hK7fDlwoBg9yOPvjaVzIf8b0A60k7poNhEg225qWaX7WeYlUjC7g== +three@^0.135.0: + version "0.135.0" + resolved "https://registry.yarnpkg.com/three/-/three-0.135.0.tgz#cff4ec8edd3c51ce9bc7e88d13e8eafed4d0ddfc" + integrity sha512-kuEpuuxRzLv0MDsXai9huCxOSQPZ4vje6y0gn80SRmQvgz6/+rI0NAvCRAw56zYaWKMGMfqKWsxF9Qa2Z9xymQ== throat@^4.0.0: version "4.1.0" @@ -15015,11 +15087,6 @@ to-absolute-glob@^2.0.0: is-absolute "^1.0.0" is-negated-glob "^1.0.0" -to-array@0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz" - integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= - to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz" @@ -15717,7 +15784,7 @@ value-or-function@^3.0.0: resolved "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz" integrity sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM= -vary@~1.1.2: +vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= @@ -15834,9 +15901,9 @@ vm-browserify@^1.0.1: resolved "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== -voronoi-diagram@^1.0.1: +voronoi-diagram@1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/voronoi-diagram/-/voronoi-diagram-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/voronoi-diagram/-/voronoi-diagram-1.0.1.tgz#4741e1e8e3184d2cdf49222adf377f062c50edfb" integrity sha1-R0Hh6OMYTSzfSSIq3zd/BixQ7fs= dependencies: circumcenter "^1.0.0" @@ -15887,7 +15954,7 @@ watchpack-chokidar2@^2.0.1: dependencies: chokidar "^2.1.8" -watchpack@^1.6.0, watchpack@^1.7.4: +watchpack@^1.6.0: version "1.7.5" resolved "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz" integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== @@ -15898,6 +15965,14 @@ watchpack@^1.6.0, watchpack@^1.7.4: chokidar "^3.4.1" watchpack-chokidar2 "^2.0.1" +watchpack@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25" + integrity sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + wbuf@^1.1.0, wbuf@^1.7.3: version "1.7.3" resolved "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz" @@ -16018,6 +16093,11 @@ webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack- source-list-map "^2.0.0" source-map "~0.6.1" +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + webpack@4.42.0: version "4.42.0" resolved "https://registry.npmjs.org/webpack/-/webpack-4.42.0.tgz" @@ -16047,34 +16127,35 @@ webpack@4.42.0: watchpack "^1.6.0" webpack-sources "^1.4.1" -webpack@^4.46.0: - version "4.46.0" - resolved "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz" - integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/wasm-edit" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - acorn "^6.4.1" - ajv "^6.10.2" - ajv-keywords "^3.4.1" +webpack@^5.72.0: + version "5.72.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.72.0.tgz#f8bc40d9c6bb489a4b7a8a685101d6022b8b6e28" + integrity sha512-qmSmbspI0Qo5ld49htys8GY9XhS9CGqFoHTsOVAnjBdg0Zn79y135R+k4IR4rKK6+eKaabMhJwiVB7xw0SJu5w== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^0.0.51" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/wasm-edit" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + acorn "^8.4.1" + acorn-import-assertions "^1.7.6" + browserslist "^4.14.5" chrome-trace-event "^1.0.2" - enhanced-resolve "^4.5.0" - eslint-scope "^4.0.3" + enhanced-resolve "^5.9.2" + es-module-lexer "^0.9.0" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.9" 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.3" - 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.7.4" - webpack-sources "^1.4.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.1.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.1.3" + watchpack "^2.3.1" + webpack-sources "^3.2.3" websocket-driver@>=0.5.1: version "0.7.4" @@ -16347,15 +16428,6 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" @@ -16405,10 +16477,10 @@ ws@^7.4.6: resolved "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz" integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== -ws@~7.4.2: - version "7.4.6" - resolved "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz" - integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@~8.2.3: + version "8.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" + integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== x-is-string@^0.1.0: version "0.1.0" @@ -16425,10 +16497,10 @@ xmlchars@^2.1.1, xmlchars@^2.2.0: resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xmlhttprequest-ssl@~1.6.2: - version "1.6.3" - resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz" - integrity sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q== +xmlhttprequest-ssl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67" + integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== xregexp@^4.3.0: version "4.4.1" @@ -16493,19 +16565,16 @@ yargs-parser@^13.1.2: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^18.1.2: - version "18.1.3" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs-parser@^20.2.2, yargs-parser@^20.2.7: version "20.2.9" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +yargs-parser@^21.0.0: + version "21.0.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" + integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== + yargs-parser@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz" @@ -16561,23 +16630,6 @@ yargs@^13.3.0, yargs@^13.3.2: y18n "^4.0.0" yargs-parser "^13.1.2" -yargs@^15.4.1: - version "15.4.1" - resolved "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz" - integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== - dependencies: - cliui "^6.0.0" - decamelize "^1.2.0" - find-up "^4.1.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 "^4.2.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^18.1.2" - yargs@^16.2.0: version "16.2.0" resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" @@ -16591,6 +16643,19 @@ yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@^17.3.1: + version "17.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.4.1.tgz#ebe23284207bb75cee7c408c33e722bfb27b5284" + integrity sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.0.0" + yargs@^7.1.0: version "7.1.2" resolved "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz" @@ -16610,11 +16675,6 @@ yargs@^7.1.0: y18n "^3.2.1" yargs-parser "^5.0.1" -yeast@0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz" - integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= - yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" diff --git a/nomad/app/v1/routers/entries.py b/nomad/app/v1/routers/entries.py index a3bf7bdac4a32ddcd0078e7dafc4862bd4ad786b..e17b9ecebf0cc554d37ec17defe61a87ac2134ba 100644 --- a/nomad/app/v1/routers/entries.py +++ b/nomad/app/v1/routers/entries.py @@ -17,6 +17,10 @@ # from datetime import datetime +import functools +from itertools import zip_longest +import multiprocessing +import operator from typing import Optional, Set, Union, Dict, Iterator, Any, List from fastapi import ( @@ -38,7 +42,6 @@ from nomad.datamodel import EditableUserMetadata from nomad.files import StreamedFile, create_zipstream from nomad.utils import strip from nomad.archive import RequiredReader, RequiredValidationError, ArchiveQueryError -from nomad.archive import ArchiveQueryError from nomad.search import AuthenticationRequiredError, SearchError, update_metadata as es_update_metadata from nomad.search import search, QueryValidationError from nomad.metainfo.elasticsearch_extension import entry_type @@ -69,7 +72,7 @@ archive_required_documentation = strip(''' The `required` part allows you to specify what parts of the requested archives should be returned. The NOMAD Archive is a hierarchical data format and you can *require* certain branches (i.e. *sections*) in the hierarchy. -By specifing certain sections with specific contents or all contents (via +By specifying certain sections with specific contents or all contents (via the directive `"*"`), you can determine what sections and what quantities should be returned. The default is the whole archive, i.e., `"*"`. @@ -441,13 +444,20 @@ def _do_exaustive_search(owner: Owner, query: Query, include: List[str], user: U break -class _Uploads(): +class _Uploads: ''' A helper class that caches subsequent access to upload files the same upload. ''' + def __init__(self): self._upload_files = None + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + def get_upload_files(self, upload_id: str) -> files.UploadFiles: if self._upload_files is not None and self._upload_files.upload_id != upload_id: self._upload_files.close() @@ -492,13 +502,9 @@ def _answer_entries_rawdir_request( required=MetadataRequired(include=['entry_id', 'upload_id', 'mainfile']), user_id=user.user_id if user is not None else None) - uploads = _Uploads() - try: - response_data = [ - _create_entry_rawdir(entry_metadata, uploads) - for entry_metadata in search_response.data] - finally: - uploads.close() + with _Uploads() as uploads: + response_data = [_create_entry_rawdir( + entry_metadata, uploads) for entry_metadata in search_response.data] return EntriesRawDirResponse( owner=search_response.owner, @@ -670,68 +676,107 @@ def _read_archive(entry_metadata, uploads, required_reader: RequiredReader): return { 'entry_id': entry_id, 'parser_name': entry_metadata['parser_name'], - 'archive': required_reader.read(archive, entry_id) - } + 'archive': required_reader.read(archive, entry_id)} except ArchiveQueryError as e: - raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e)) + raise HTTPException(status.HTTP_400_BAD_REQUEST, detail=str(e)) def _validate_required(required: ArchiveRequired) -> RequiredReader: try: return RequiredReader(required) except RequiredValidationError as e: - raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=[dict( - msg=e.msg, loc=['required'] + e.loc)]) + raise HTTPException( + status.HTTP_422_UNPROCESSABLE_ENTITY, + detail=[dict(msg=e.msg, loc=['required'] + e.loc)]) + + +def _read_entry_from_archive(entry, uploads, required_reader: RequiredReader): + entry_id, upload_id = entry['entry_id'], entry['upload_id'] + + # all other exceptions are handled by the caller `_read_entries_from_archive` + try: + upload_files = uploads.get_upload_files(upload_id) + + with upload_files.read_archive(entry_id, True) as archive: + return { + 'entry_id': entry_id, + 'upload_id': upload_id, + 'parser_name': entry['parser_name'], + 'archive': required_reader.read(archive, entry_id)} + except ArchiveQueryError as e: + raise HTTPException(status.HTTP_400_BAD_REQUEST, detail=str(e)) + except KeyError as e: + logger.error('missing archive', exc_info=e, entry_id=entry_id) + + return None + + +def _read_entries_from_archive(entries, required): + ''' + Takes pickleable arguments so that it can be offloaded to worker processes. + + It is important to ensure the return values are also pickleable. + ''' + with _Uploads() as uploads: + required_reader = _validate_required(required) + + responses = [_read_entry_from_archive( + entry, uploads, required_reader) for entry in entries if entry is not None] + + return list(filter(None, responses)) def _answer_entries_archive_request( owner: Owner, query: Query, pagination: MetadataPagination, required: ArchiveRequired, user: User): - if owner == Owner.all_: - raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=strip(''' - The owner=all is not allowed for this operation as it will search for entries - that you might now be allowed to access. - ''')) + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, detail=strip( + '''The owner=all is not allowed for this operation as it will search for entries + that you might now be allowed to access.''')) if required is None: required = '*' - required_reader = _validate_required(required) - search_response = perform_search( owner=owner, query=query, pagination=pagination, required=MetadataRequired(include=['entry_id', 'upload_id', 'parser_name']), user_id=user.user_id if user is not None else None) - uploads = _Uploads() - response_data = {} - for entry_metadata in search_response.data: - entry_id, upload_id = entry_metadata['entry_id'], entry_metadata['upload_id'] + # fewer than 8 entries per process is not useful + # more than config.max_process_number processes is too much for the server + number: int = min( + len(search_response.data) // config.archive.min_entires_per_process, + config.archive.max_process_number) - archive_data = None + if number <= 1: + request_data: list = _read_entries_from_archive(search_response.data, required) + else: + entries_per_process = len(search_response.data) // number + 1 - try: - archive_data = _read_archive(entry_metadata, uploads, required_reader)['archive'] - except KeyError as e: - logger.error('missing archive', exc_info=e, entry_id=entry_id) - continue - - response_data[entry_id] = { - 'entry_id': entry_id, - 'upload_id': upload_id, - 'parser_name': entry_metadata['parser_name'], - 'archive': archive_data} + # use process pool + pool: multiprocessing.pool.Pool = multiprocessing.pool.Pool(processes=number) - uploads.close() + try: + responses = pool.map( + functools.partial(_read_entries_from_archive, required=required), + zip_longest(*[iter(search_response.data)] * entries_per_process)) + finally: + # gracefully shutdown the pool + pool.close() + pool.join() + + # collect results from each process + # https://stackoverflow.com/a/45323085 + request_data = functools.reduce(operator.iconcat, responses, []) return EntriesArchiveResponse( owner=search_response.owner, query=search_response.query, pagination=search_response.pagination, required=required, - data=list(response_data.values())) + data=request_data) _entries_archive_docstring = strip(''' @@ -805,7 +850,6 @@ def _answer_entries_archive_download_request( 'The limit of maximum number of entries in a single download (%d) has been ' 'exeeded (%d).' % (config.max_entry_download, response.pagination.total))) - uploads = _Uploads() manifest = [] search_includes = ['entry_id', 'upload_id', 'parser_name'] @@ -833,12 +877,10 @@ def _answer_entries_archive_download_request( manifest_content = json.dumps(manifest, indent=2).encode() yield StreamedFile(path='manifest.json', f=io.BytesIO(manifest_content), size=len(manifest_content)) - try: + with _Uploads() as uploads: # create the streaming response with zip file contents content = create_zipstream(streamed_files(), compress=files_params.compress) return StreamingResponse(content, media_type='application/zip') - finally: - uploads.close() _entries_archive_download_docstring = strip(''' @@ -936,11 +978,9 @@ async def get_entry_rawdir( status_code=status.HTTP_404_NOT_FOUND, detail='The entry with the given id does not exist or is not visible to you.') - uploads = _Uploads() - try: - return EntryRawDirResponse(entry_id=entry_id, data=_create_entry_rawdir(response.data[0], uploads)) - finally: - uploads.close() + with _Uploads() as uploads: + return EntryRawDirResponse( + entry_id=entry_id, data=_create_entry_rawdir(response.data[0], uploads)) @router.get( @@ -1044,13 +1084,12 @@ def answer_entry_archive_request(query: Dict[str, Any], required: ArchiveRequire entry_metadata = response.data[0] entry_id = entry_metadata['entry_id'] - uploads = _Uploads() - try: + with _Uploads() as uploads: try: archive_data = _read_archive(entry_metadata, uploads, required_reader)['archive'] except KeyError: raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, + status.HTTP_404_NOT_FOUND, detail='The entry does exist, but it has no archive.') return { @@ -1060,10 +1099,7 @@ def answer_entry_archive_request(query: Dict[str, Any], required: ArchiveRequire 'entry_id': entry_id, 'upload_id': entry_metadata['upload_id'], 'parser_name': entry_metadata['parser_name'], - 'archive': archive_data - }} - finally: - uploads.close() + 'archive': archive_data}} @router.get( diff --git a/nomad/archive/__init__.py b/nomad/archive/__init__.py index 7b4ef387d72ce84976e25da1b43c91ee1f8d276e..b7cb22460a1b884de38386c697ac56bf4e5a4d08 100644 --- a/nomad/archive/__init__.py +++ b/nomad/archive/__init__.py @@ -35,7 +35,7 @@ section annotations/categories. from .storage import ( write_archive, read_archive, ArchiveError, ArchiveReader, ArchiveWriter, - ArchiveObject, ArchiveList, ArchiveItem) + ArchiveDict, ArchiveList, ArchiveItem) from .query import query_archive, filter_archive, ArchiveQueryError from .partial import ( read_partial_archive_from_mongo, read_partial_archives_from_mongo, diff --git a/nomad/archive/query.py b/nomad/archive/query.py index 6aae0eda3693205b4d420d5d200bb66dd8bba982..54dbb180a05ef3aca99055b6c4ec47e170808708 100644 --- a/nomad/archive/query.py +++ b/nomad/archive/query.py @@ -16,13 +16,70 @@ # limitations under the License. # -from typing import Any, Tuple, Dict, Callable, Union, List -from io import BytesIO +import functools import re +from typing import Any, Dict, Callable, Union, Tuple +from io import BytesIO from nomad import utils -from .storage import ArchiveReader, ArchiveList, ArchiveObject +from .storage import ArchiveReader, ArchiveList, ArchiveDict, _to_son + +_query_archive_key_pattern = re.compile(r'^([\s\w\-]+)(\[([-?0-9]*)(:([-?0-9]*))?])?$') + + +@functools.lru_cache(maxsize=1024) +def _fix_index(index, length): + if index is None: + return index + + return max(-length, index) if index < 0 else min(length, index) + + +@functools.lru_cache(maxsize=1024) +def _extract_key_and_index(match) -> Tuple[str, Union[Tuple[int, int], int]]: + key = match.group(1) + + # noinspection PyTypeChecker + index: Union[Tuple[int, int], int] = None + + # check if we have indices + if match.group(2) is not None: + group = match.group(3) + first_index = None if group == '' else int(group) + + if match.group(4) is None: + index = first_index # one item + else: + group = match.group(5) + last_index = None if group == '' else int(group) + index = (0 if first_index is None else first_index, last_index) + + return key, index + + +# @cached(thread_safe=False, max_size=1024) +def _extract_child(archive_item, prop, index) -> Union[dict, list]: + archive_child = archive_item[prop] + is_list = isinstance(archive_child, (ArchiveList, list)) + + if index is None and is_list: + index = (0, None) + elif index is not None and not is_list: + raise ArchiveQueryError(f'cannot use list key on none list {prop}') + + if index is not None: + length = len(archive_child) + if isinstance(index, tuple): + index = (_fix_index(index[0], length), _fix_index(index[1], length)) + if index[0] == index[1]: + archive_child = [archive_child[index[0]]] + else: + archive_child = archive_child[index[0]: index[1]] + else: + archive_child = [archive_child[_fix_index(index, length)]] + + return archive_child class ArchiveQueryError(Exception): @@ -33,9 +90,6 @@ class ArchiveQueryError(Exception): pass -__query_archive_key_pattern = re.compile(r'^([\s\w\-]+)(\[([-?0-9]*)(:([-?0-9]*))?\])?$') - - def query_archive( f_or_archive_reader: Union[str, ArchiveReader, BytesIO], query_dict: dict, **kwargs) -> Dict: @@ -72,43 +126,25 @@ def query_archive( * exclude (in combination with wildcard keys), replaces the value with null ''' - def _to_son(data): - if isinstance(data, (ArchiveList, List)): - data = [_to_son(item) for item in data] - - elif isinstance(data, ArchiveObject): - data = data.to_dict() - - return data - - def _load_data(query_dict: Dict[str, Any], archive_item: ArchiveObject) -> Dict: - query_dict_with_fixed_ids = { - utils.adjust_uuid_size(key): value for key, value in query_dict.items()} - return filter_archive(query_dict_with_fixed_ids, archive_item, transform=_to_son) - if isinstance(f_or_archive_reader, ArchiveReader): return _load_data(query_dict, f_or_archive_reader) - elif isinstance(f_or_archive_reader, (BytesIO, str)): with ArchiveReader(f_or_archive_reader, **kwargs) as archive: return _load_data(query_dict, archive) else: - raise TypeError('%s is neither a file-like nor ArchiveReader' % f_or_archive_reader) + raise TypeError(f'{f_or_archive_reader} is neither a file-like nor ArchiveReader') -def filter_archive( - required: Union[str, Dict[str, Any]], archive_item: Union[Dict, ArchiveObject, str], - transform: Callable, result_root: Dict = None, resolve_inplace: bool = False) -> Dict: +def _load_data(query_dict: Dict[str, Any], archive_item: ArchiveDict) -> Dict: + query_dict_with_fixed_ids = {utils.adjust_uuid_size( + key): value for key, value in query_dict.items()} + return filter_archive(query_dict_with_fixed_ids, archive_item, transform=_to_son) - def _fix_index(index, length): - if index is None: - return index - if index < 0: - return max(-(length), index) - else: - return min(length, index) +def filter_archive( + required: Union[str, Dict[str, Any]], archive_item: Union[Dict, ArchiveDict, str], + transform: Callable, result_root: Dict = None, resolve_inplace: bool = False) -> Dict: if archive_item is None: return None @@ -119,51 +155,31 @@ def filter_archive( if required == 'resolve': # TODO this requires to reflect on the definition to determine what are references! pass - elif required in ['*', 'include']: pass - else: raise ArchiveQueryError(f'unknown directive {required}') return transform(archive_item) - elif not isinstance(required, dict): + if not isinstance(required, dict): raise ArchiveQueryError('a value in required is neither dict not string directive') if isinstance(archive_item, str): # The archive item is a reference, the required is still a dict, the references # needs to be resolved # TODO - raise ArchiveQueryError(f'resolving references in non partial archives is not yet implemented') + raise ArchiveQueryError( + f'resolving references in non partial archives is not yet implemented') result: Dict[str, Any] = {} for key, val in required.items(): key = key.strip() # process array indices - match = __query_archive_key_pattern.match(key) - index: Union[Tuple[int, int], int] = None + match = _query_archive_key_pattern.match(key) if match: - key = match.group(1) - - # check if we have indices - if match.group(2) is not None: - first_index, last_index = None, None - group = match.group(3) - first_index = None if group == '' else int(group) - - if match.group(4) is not None: - group = match.group(5) - last_index = None if group == '' else int(group) - index = (0 if first_index is None else first_index, last_index) - - else: - index = first_index # one item - - else: - index = None - + key, index = _extract_key_and_index(match) elif key == '*': # TODO raise ArchiveQueryError('key wildcards not yet implemented') @@ -171,32 +187,11 @@ def filter_archive( raise ArchiveQueryError('invalid key format: %s' % key) try: - archive_child = archive_item[key] - is_list = isinstance(archive_child, (ArchiveList, list)) - - if index is None and is_list: - index = (0, None) - - elif index is not None and not is_list: - raise ArchiveQueryError('cannot use list key on none list %s' % key) - - if index is None: - pass - else: - length = len(archive_child) - if isinstance(index, tuple): - index = (_fix_index(index[0], length), _fix_index(index[1], length)) - if index[0] == index[1]: - archive_child = [archive_child[index[0]]] - else: - archive_child = archive_child[index[0]: index[1]] - else: - archive_child = [archive_child[_fix_index(index, length)]] + archive_child = _extract_child(archive_item, key, index) if isinstance(archive_child, (ArchiveList, list)): - result[key] = [ - filter_archive(val, item, transform=transform) - for item in archive_child] + result[key] = [filter_archive( + val, item, transform=transform) for item in archive_child] else: result[key] = filter_archive(val, archive_child, transform=transform) diff --git a/nomad/archive/required.py b/nomad/archive/required.py index fe1b2e7d63915c046bcc8c02992c108dc3a4bdba..6d6dbbfac1fce0ddbe27499c7363aeb6673120d1 100644 --- a/nomad/archive/required.py +++ b/nomad/archive/required.py @@ -16,14 +16,14 @@ # limitations under the License. # -from typing import cast, Union, Dict, Tuple, List, Any, Callable -import re +import functools +from typing import cast, Union, Dict, Tuple, Any from nomad import utils from nomad.metainfo import Definition, Section, Quantity, SubSection, Reference, QuantityReference - -from .storage import ArchiveReader, ArchiveList, ArchiveObject, ArchiveError -from .query import ArchiveQueryError # TODO +from .storage import ArchiveReader, ArchiveList, ArchiveError +from .query import ArchiveQueryError, _to_son, _query_archive_key_pattern, _extract_key_and_index, \ + _extract_child class RequiredValidationError(Exception): @@ -33,6 +33,29 @@ class RequiredValidationError(Exception): self.loc = loc +@functools.lru_cache(maxsize=1024) +def _parse_required_key(key: str) -> Tuple[str, Union[Tuple[int, int], int]]: + key = key.strip() + match = _query_archive_key_pattern.match(key) + + if not match: + raise Exception(f'invalid key format: {key}') + + return _extract_key_and_index(match) + + +def _setdefault(target: Union[dict, list], key, value_type: type): + if isinstance(target, list): + if target[key] is None: + target[key] = value_type() + return target[key] + + if key not in target: + target[key] = value_type() + + return target[key] + + class RequiredReader: ''' Clients can read only the required parts of an archive. They specify the required @@ -54,7 +77,7 @@ class RequiredReader: } } - The structure has to adheres to metainfo definitions of an archive's sub-sections and + The structure has to adhere to metainfo definitions of an archive's subsections and quantities. At each point in the specification, children can be replaced with certain directives. @@ -70,38 +93,23 @@ class RequiredReader: - required: The requirement specification as a python dictionary or directive string. ''' - __query_archive_key_pattern = re.compile(r'^([\s\w\-]+)(\[([-?0-9]*)(:([-?0-9]*))?\])?$') - - def __init__(self, required: Union[dict, str], root_section_def: Section = None, resolve_inplace: bool = False): + def __init__( + self, required: Union[dict, str], root_section_def: Section = None, + resolve_inplace: bool = False): if root_section_def is None: from nomad import datamodel self.root_section_def = datamodel.EntryArchive.m_def else: self.root_section_def = root_section_def - self.__result_root: dict = None - self.__archive_root: dict = None # it is actually an ArchvieReader, but we use it as dict + # noinspection PyTypeChecker + self._result_root: dict = None + # noinspection PyTypeChecker + self._archive_root: dict = None # it is actually an ArchiveReader, but we use it as dict self.resolve_inplace = resolve_inplace self.required = self.validate(required, is_root=True) - def __to_son(self, data): - if isinstance(data, (ArchiveList, List)): - data = [self.__to_son(item) for item in data] - - elif isinstance(data, ArchiveObject): - data = data.to_dict() - - return data - - def __fix_index(self, index, length): - if index is None: - return index - if index < 0: - return max(-(length), index) - else: - return min(length, index) - def validate( self, required: Union[str, dict], definition: Definition = None, loc: list = None, is_root=False) -> dict: @@ -109,11 +117,11 @@ class RequiredReader: Validates the required specification of this instance. It will replace all string directives with dicts. Those will have keys `_def` and `_directive`. It will add a key `_def` to all dicts. The `_def` will be the respective metainfo - definition. If will also add key `_ref`. It will be None or contain a + definition. It will also add key `_ref`. It will be None or contain a Reference instance, if the definition is a reference target. This method will raise an exception (:class:`RequiredValidationError`) to denote - any mismatches between the required specification and the metainfo. Also to denote + any mismatches between the required specification and the metainfo, also, to denote misused directives, bad structure, etc. raises: @@ -124,8 +132,7 @@ class RequiredReader: if isinstance(resolve_inplace, bool): self.resolve_inplace = resolve_inplace elif resolve_inplace is not None: - raise RequiredValidationError( - 'resolve-inplace is not a bool', ['resolve-inplace']) + raise RequiredValidationError('resolve-inplace is not a bool', ['resolve-inplace']) if definition is None: definition = self.root_section_def @@ -164,7 +171,7 @@ class RequiredReader: loc.append(key) try: - prop, index = self.__parse_required_key(key) + prop, index = _parse_required_key(key) except Exception: raise RequiredValidationError(f'invalid key format {key}', loc) if prop == '*': @@ -173,8 +180,7 @@ class RequiredReader: try: prop_def = cast(Section, definition).all_properties[prop] except KeyError: - raise RequiredValidationError( - f'{definition.name} has not property {prop}', loc) + raise RequiredValidationError(f'{definition.name} has not property {prop}', loc) result[key] = self.validate(value, prop_def, loc) result[key].update(_prop=prop, _index=index) loc.pop() @@ -186,64 +192,34 @@ class RequiredReader: Reads the archive of the given entry id from the given archive reader and applies the instance's requirement specification. ''' - assert self.__result_root is None and self.__archive_root is None, \ + assert self._result_root is None and self._archive_root is None, \ 'instance cannot be used concurrently for multiple reads at the same time' - self.__archive_root = archive_reader[utils.adjust_uuid_size(entry_id)] + self._archive_root = archive_reader[utils.adjust_uuid_size(entry_id)] result: dict = {} - self.__result_root = result - result.update(**cast(dict, self.__apply_required(self.required, self.__archive_root))) + self._result_root = result + result.update(**cast(dict, self._apply_required(self.required, self._archive_root))) - self.__archive_root = None - self.__result_root = None + self._archive_root = None + self._result_root = None return result - def __parse_required_key(self, key: str) -> Tuple[str, Union[Tuple[int, int], int]]: - key = key.strip() - match = RequiredReader.__query_archive_key_pattern.match(key) - index: Union[Tuple[int, int], int] = None - if match: - key = match.group(1) - - # check if we have indices - if match.group(2) is not None: - first_index, last_index = None, None - group = match.group(3) - first_index = None if group == '' else int(group) - - if match.group(4) is not None: - group = match.group(5) - last_index = None if group == '' else int(group) - index = (0 if first_index is None else first_index, last_index) - - else: - index = first_index # one item - - else: - index = None - - else: - raise Exception('invalid key format: %s' % key) - - return key, index - - def __resolve_refs(self, archive: dict, definition: Definition) -> dict: + def _resolve_refs(self, archive: dict, definition: Definition) -> dict: ''' Resolves all references in archive. ''' if isinstance(definition, Quantity): # it's a quantity ref, the archive is already resolved - return self.__to_son(archive[definition.name]) + return _to_son(archive[definition.name]) # it's a section ref section_def = cast(Section, definition) - archive = self.__to_son(archive) + archive = _to_son(archive) result = {} - for prop in archive: - value = archive[prop] + for prop, value in archive.items(): prop_def = section_def.all_properties[prop] - handle_item: Callable[[Any], Any] = None if isinstance(prop_def, SubSection): - handle_item = lambda value: self.__resolve_refs(value, prop_def.sub_section.m_resolved()) + def handle_item(v): + return self._resolve_refs(v, prop_def.sub_section.m_resolved()) elif isinstance(prop_def.type, Reference): if isinstance(prop_def.type, QuantityReference): target_def = prop_def.type.target_quantity_def.m_resolved() @@ -252,18 +228,19 @@ class RequiredReader: required = dict( _directive='include-resolved', _def=target_def, _ref=prop_def.type) - handle_item = lambda value: self.__resolve_ref(required, value) - else: - handle_item = lambda value: value - if isinstance(value, (list, ArchiveList)): - result[prop] = [handle_item(item) for item in value] + def handle_item(v): + return self._resolve_ref(required, v) else: - result[prop] = handle_item(value) + result[prop] = value.to_list() if isinstance(value, ArchiveList) else value + continue + + result[prop] = [handle_item(item) for item in value] if isinstance( + value, (list, ArchiveList)) else handle_item(value) return result - def __resolve_ref(self, required: dict, path: str) -> Union[dict, str]: + def _resolve_ref(self, required: dict, path: str) -> Union[dict, str]: # The archive item is a reference, the required is still a dict, the references # This is a simplified version of the metainfo implementation (m_resolve). # It implements the same semantics, but does not apply checks. @@ -274,44 +251,28 @@ class RequiredReader: # TODO support custom reference resolution, e.g. user_id based return path - resolved = self.__archive_root + resolved = self._archive_root path_stack = path.strip('/').split('/') - path_stack.reverse() try: - while len(path_stack) > 0: - prop = path_stack.pop() - resolved = resolved[prop] - if len(path_stack) > 0 and path_stack[-1].isdigit(): - resolved = resolved[int(path_stack.pop())] - + for prop in path_stack: + resolved = resolved[int(prop) if prop.isdigit() else prop] except Exception: raise ArchiveError('could not resolve reference') # apply required to resolved archive_item if isinstance(required['_def'], Quantity): - resolved_result = self.__to_son(resolved) + resolved_result = _to_son(resolved) else: - resolved_result = self.__apply_required(required, resolved) + resolved_result = self._apply_required(required, resolved) # return or add to root depending on self.resolve_inplace if self.resolve_inplace: return resolved_result - def _setdefault(target: Union[dict, list], prop, value_type: type): - if isinstance(target, list): - if target[prop] is None: - target[prop] = value_type() - return target[prop] - - if prop not in target: - target[prop] = value_type() - - return target[prop] - - path_stack = path.strip('/').split('/') path_stack.reverse() - target_container: Union[dict, list] = self.__result_root + target_container: Union[dict, list] = self._result_root + # noinspection PyTypeChecker prop_or_index: Union[str, int] = None while len(path_stack) > 0: if prop_or_index is not None: @@ -319,17 +280,16 @@ class RequiredReader: prop_or_index = path_stack.pop() if len(path_stack) > 0 and path_stack[-1].isdigit(): - target_list = _setdefault(target_container, prop_or_index, list) - index = int(path_stack.pop()) - for _ in range(len(target_list), index + 1): - target_list.append(None) - target_container = target_list - prop_or_index = index + target_container = _setdefault(target_container, prop_or_index, list) + prop_or_index = int(path_stack.pop()) + size_diff: int = prop_or_index - len(target_container) + 1 + if size_diff > 0: + target_container.extend([None] * size_diff) # type: ignore target_container[prop_or_index] = resolved_result # type: ignore return path - def __apply_required(self, required: dict, archive_item: Union[dict, str]) -> Union[Dict, str]: + def _apply_required(self, required: dict, archive_item: Union[dict, str]) -> Union[Dict, str]: if archive_item is None: return None @@ -337,17 +297,17 @@ class RequiredReader: if directive is not None: if directive == 'include-resolved': if isinstance(archive_item, str): - return self.__resolve_ref(required, archive_item) - return self.__resolve_refs(archive_item, required['_def']) + return self._resolve_ref(required, archive_item) - elif directive in ['*', 'include']: - return self.__to_son(archive_item) + return self._resolve_refs(archive_item, required['_def']) - else: - raise ArchiveQueryError(f'unknown directive {required}') + if directive in ['*', 'include']: + return _to_son(archive_item) + + raise ArchiveQueryError(f'unknown directive {required}') if isinstance(archive_item, str): - return self.__resolve_ref(required, archive_item) + return self._resolve_ref(required, archive_item) result: dict = {} for key, val in required.items(): @@ -357,35 +317,12 @@ class RequiredReader: prop, index = val['_prop'], val['_index'] try: - archive_child = archive_item[prop] - is_list = isinstance(archive_child, (ArchiveList, list)) - - if index is None and is_list: - index = (0, None) - - elif index is not None and not is_list: - raise ArchiveQueryError('cannot use list key on none list %s' % prop) - - if index is None: - pass - else: - length = len(archive_child) - if isinstance(index, tuple): - index = (self.__fix_index(index[0], length), self.__fix_index(index[1], length)) - if index[0] == index[1]: - archive_child = [archive_child[index[0]]] - else: - archive_child = archive_child[index[0]: index[1]] - else: - archive_child = [archive_child[self.__fix_index(index, length)]] + archive_child = _extract_child(archive_item, prop, index) if isinstance(archive_child, (ArchiveList, list)): - result[prop] = [ - self.__apply_required(val, item) - for item in archive_child] + result[prop] = [self._apply_required(val, item) for item in archive_child] else: - result[prop] = self.__apply_required(val, archive_child) - + result[prop] = self._apply_required(val, archive_child) except (KeyError, IndexError): continue diff --git a/nomad/archive/storage.py b/nomad/archive/storage.py index 4cc6db9a4e227f674ff26cbd02020d7ef45c716c..bf8ed1805f220d4cc59bffb49d0d63dcc1fdbb3b 100644 --- a/nomad/archive/storage.py +++ b/nomad/archive/storage.py @@ -19,26 +19,59 @@ from typing import Iterable, Any, Tuple, Dict, BinaryIO, Union, List, cast from io import BytesIO, BufferedReader from collections.abc import Mapping, Sequence + +from memoization import cached import msgpack from msgpack.fallback import Packer, StringIO import struct import json -import math from nomad import utils - +from nomad.config import archive __packer = msgpack.Packer(autoreset=True, use_bin_type=True) +_toc_uuid_size = utils.default_hash_len + 1 +_toc_item_size = _toc_uuid_size + 25 # packed(uuid + [10-byte-pos, 10-byte-pos]) +_entries_per_block = archive.block_size // _toc_item_size +_bytes_per_block = _entries_per_block * _toc_item_size + -def packb(o, **kwargs): +def packb(o): return __packer.pack(o) -def unpackb(o, **kwargs): +def unpackb(o): return msgpack.unpackb(o, raw=False) +def _encode(start: int, end: int) -> bytes: + return start.to_bytes(5, byteorder='little', signed=False) + end.to_bytes( + 5, byteorder='little', signed=False) + + +def _decode(position: bytes) -> Tuple[int, int]: + return int.from_bytes(position[:5], byteorder='little', signed=False), int.from_bytes( + position[5:], byteorder='little', signed=False) + + +def _unpack_entry(data: bytes) -> Tuple[Any, Tuple[Any, Any]]: + entry_uuid = unpackb(data[: _toc_uuid_size]) + positions_encoded = unpackb(data[_toc_uuid_size:]) + return entry_uuid, (_decode(positions_encoded[0]), _decode(positions_encoded[1])) + + +def _to_son(data): + if isinstance(data, ArchiveList): + data = data.to_list() + + elif isinstance(data, ArchiveDict): + data = data.to_dict() + + # no need to convert build-in types + return data + + class ArchiveError(Exception): ''' An error that indicates a broken archive. ''' pass @@ -51,77 +84,78 @@ class TOCPacker(Packer): Uses a combination of the pure python msgpack fallback packer and the "real" c-based packing. ''' + def __init__(self, toc_depth: int, *args, **kwargs): self.toc_depth = toc_depth + # noinspection PyTypeChecker self.toc: Dict[str, Any] = None self._depth = 0 # Because we cannot change msgpacks interface of _pack, this _stack is used to - # tranfer the result of _pack calls in terms of the TOC. + # transfer the result of _pack calls in terms of the TOC. self._stack: List[Any] = [] super().__init__(*args, **kwargs) - def pack(self, obj, *args, **kwargs): - assert isinstance(obj, dict), 'TOC packer can only pack dicts, %s' % obj.__class__ - self._depth = 0 - self._buffer = StringIO() - result = super().pack(obj, *args, **kwargs) - self.toc = self._stack.pop() - assert len(self._stack) == 0 - return result - def _pos(self): return self._buffer.getbuffer().nbytes - def _pack(self, obj, *args, **kwargs): - if isinstance(obj, dict): - toc_result = {} - start = self._pos() - if self._depth >= self.toc_depth: - pack_result = self._buffer.write(packb(obj)) - else: - self._depth += 1 - pack_result = super()._pack(obj, *args, **kwargs) - self._depth -= 1 - - toc = {} - for key, value in reversed(list(obj.items())): - if isinstance(value, (list, tuple)): - # this makes some assumptions about the non emptyness and uniformness - # of array items - if len(value) > 0 and isinstance(value[0], dict): - toc[key] = self._stack.pop() - - elif isinstance(value, (dict, list, tuple)): - toc[key] = self._stack.pop() - - toc_result['toc'] = {key: value for key, value in reversed(list(toc.items()))} - - end = self._pos() - toc_result['pos'] = [start, end] - - self._stack.append(toc_result) - - elif isinstance(obj, list): - toc_result = [] - pack_result = super()._pack(obj, *args, **kwargs) + def _pack_list(self, obj, *args, **kwargs): + pack_result = super()._pack(obj, *args, **kwargs) - # same assumption and condition as above - if len(obj) > 0 and isinstance(obj[0], dict): - for _ in obj: - toc_result.append(self._stack.pop()) + toc_result = [] + # same assumption and condition as above + if len(obj) > 0 and isinstance(obj[0], dict): + for _ in obj: + toc_result.append(self._stack.pop()) - self._stack.append(list(reversed(toc_result))) + self._stack.append(list(reversed(toc_result))) - else: + return pack_result + + def _pack_dict(self, obj, *args, **kwargs): + toc_result = {} + start = self._pos() + if self._depth >= self.toc_depth: pack_result = self._buffer.write(packb(obj)) + else: + self._depth += 1 + pack_result = super()._pack(obj, *args, **kwargs) + self._depth -= 1 + + toc = {} + for key, value in reversed(list(obj.items())): + if isinstance(value, dict) or (isinstance(value, (list, tuple)) and len( + value) > 0 and isinstance(value[0], dict)): + # assumes non emptiness and uniformity of array items + toc[key] = self._stack.pop() + + toc_result['toc'] = {key: value for key, value in reversed(list(toc.items()))} + + end = self._pos() + toc_result['pos'] = [start, end] + + self._stack.append(toc_result) return pack_result + def _pack(self, obj, *args, **kwargs): + if isinstance(obj, dict): + return self._pack_dict(obj, *args, **kwargs) + + if isinstance(obj, list): + return self._pack_list(obj, *args, **kwargs) -_toc_uuid_size = utils.default_hash_len + 1 -_toc_item_size = _toc_uuid_size + 25 # packed(uuid + [10-byte-pos, 10-byte-pos]) + return self._buffer.write(packb(obj)) + + def pack(self, obj): + assert isinstance(obj, dict), f'TOC packer can only pack dicts, {obj.__class__}' + self._depth = 0 + self._buffer = StringIO() + result = super().pack(obj) + self.toc = self._stack.pop() + assert len(self._stack) == 0 + return result class ArchiveWriter: @@ -130,8 +164,10 @@ class ArchiveWriter: self.n_entries = n_entries self._pos = 0 + # noinspection PyTypeChecker self._toc_position: Tuple[int, int] = None self._toc: Dict[str, Tuple[Tuple[int, int], Tuple[int, int]]] = {} + # noinspection PyTypeChecker self._f: BinaryIO = None self._toc_packer = TOCPacker(toc_depth=entry_toc_depth) @@ -146,24 +182,19 @@ class ArchiveWriter: # write empty placeholder header self._write_map_header(3) - self.write(packb('toc_pos')) - self.write(packb(ArchiveWriter._encode_position(0, 0))) + self._writeb('toc_pos') + self._writeb(_encode(0, 0)) - self.write(packb('toc')) + self._writeb('toc') toc_start, _ = self._write_map_header(self.n_entries) - _, toc_end = self.write(b'0' * _toc_item_size * self.n_entries) + _, toc_end = self._write(b'0' * _toc_item_size * self.n_entries) self._toc_position = toc_start, toc_end - self.write(packb('data')) + self._writeb('data') self._write_map_header(self.n_entries) return self - def write(self, b: bytes) -> Tuple[int, int]: - start = self._pos - self._pos += self._f.write(b) - return start, self._pos - def __exit__(self, exc_type, exc_val, exc_tb): if exc_val is not None: raise exc_val @@ -174,28 +205,36 @@ class ArchiveWriter: assert len(self._toc) == self.n_entries toc_items = sorted(self._toc.items(), key=lambda item: item[0]) - toc = { - uuid: [ - ArchiveWriter._encode_position(*positions[0]), - ArchiveWriter._encode_position(*positions[1])] - for uuid, positions in toc_items} + toc = {uuid: [_encode(*positions[0]), _encode( + *positions[1])] for uuid, positions in toc_items} self._write_map_header(3) - self.write(packb('toc_pos')) - self.write( - packb(ArchiveWriter._encode_position(*self._toc_position), use_bin_type=True)) + self._writeb('toc_pos') + self._writeb(_encode(*self._toc_position)) - self.write(packb('toc')) - toc_position = self.write(packb(toc, use_bin_type=True)) - assert toc_position == self._toc_position, '%s - %s' % (toc_position, self._toc_position) + self._writeb('toc') + toc_position = self._writeb(toc) + assert toc_position == self._toc_position, f'{toc_position} - {self._toc_position}' if isinstance(self.file_or_path, str): self._f.close() - @staticmethod - def _encode_position(start: int, end: int) -> bytes: - return start.to_bytes(5, byteorder='little', signed=False) + \ - end.to_bytes(5, byteorder='little', signed=False) + def _write_map_header(self, n): + if n <= 0x0f: + return self._write(struct.pack('B', 0x80 + n)) + if n <= 0xffff: + return self._write(struct.pack(">BH", 0xde, n)) + if n <= 0xffffffff: + return self._write(struct.pack(">BI", 0xdf, n)) + raise ValueError("Dict is too large") + + def _write(self, b: bytes) -> Tuple[int, int]: + start = self._pos + self._pos += self._f.write(b) + return start, self._pos + + def _writeb(self, obj): + return self._write(packb(obj)) def add(self, uuid: str, data: Any) -> None: uuid = utils.adjust_uuid_size(uuid) @@ -204,198 +243,196 @@ class ArchiveWriter: packed = self._toc_packer.pack(data) toc = self._toc_packer.toc - self.write(packb(uuid)) + self._writeb(uuid) self._write_map_header(2) - self.write(packb('toc')) - toc_pos = self.write(packb(toc, use_bin_type=True)) - self.write(packb('data')) - data_pos = self.write(packed) + self._writeb('toc') + toc_pos = self._writeb(toc) + self._writeb('data') + data_pos = self._write(packed) self._toc[uuid] = (toc_pos, data_pos) - def _write_map_header(self, n): - if n <= 0x0f: - return self.write(struct.pack('B', 0x80 + n)) - if n <= 0xffff: - return self.write(struct.pack(">BH", 0xde, n)) - if n <= 0xffffffff: - return self.write(struct.pack(">BI", 0xdf, n)) - raise ValueError("Dict is too large") - class ArchiveItem: - def __init__(self, toc_entry: list, f: BytesIO, offset: int = 0): - self.toc_entry = toc_entry + def __init__(self, f: BytesIO, offset: int = 0): self._f = f self._offset = offset + def _direct_read(self, size: int, offset: int): + self._f.seek(offset) + return self._f.read(size) + def _read(self, position: Tuple[int, int]): start, end = position - self._f.seek(start + self._offset) - return unpackb(self._f.read(end - start)) + raw_data = self._direct_read(end - start, start + self._offset) + return unpackb(raw_data) - def _getchild(self, child_toc_entry): + @cached(thread_safe=False, max_size=512) + def _child(self, child_toc_entry): if isinstance(child_toc_entry, dict): if 'toc' in child_toc_entry: - return ArchiveObject(child_toc_entry, self._f, self._offset) - else: - return self._read(child_toc_entry['pos']) + return ArchiveDict(child_toc_entry, self._f, self._offset) - elif isinstance(child_toc_entry, list): + return self._read(child_toc_entry['pos']) + + if isinstance(child_toc_entry, list): return ArchiveList(child_toc_entry, self._f, self._offset) - else: - assert False, 'unreachable' + assert False, 'unreachable' class ArchiveList(ArchiveItem, Sequence): + def __init__(self, toc_entry: list, *args, **kwargs): + super().__init__(*args, **kwargs) + self._toc_entry = toc_entry + self._full_list = None def __getitem__(self, index): - child_toc_entry = self.toc_entry[index] - return self._getchild(child_toc_entry) + if self._full_list is None: + child_entry = self._toc_entry[index] + return self._child(child_entry) + + return self._full_list[index] def __len__(self): - return self.toc_entry.__len__() + return self._toc_entry.__len__() + + def to_list(self): + if self._full_list is None: + self._full_list = [_to_son(self._child(child_entry)) for child_entry in self._toc_entry] + return self._full_list -class ArchiveObject(ArchiveItem, Mapping): - def __init__(self, *args, **kwargs): +class ArchiveDict(ArchiveItem, Mapping): + def __init__(self, toc_entry: dict, *args, **kwargs): super().__init__(*args, **kwargs) - self._data = None + self._toc_entry = toc_entry def __getitem__(self, key): - if self._data is None: - try: - child_toc_entry = self.toc_entry['toc'][key] - except KeyError: - return self.to_dict().__getitem__(key) - return self._getchild(child_toc_entry) - else: - return self._data.__getitem__(key) + try: + child_toc_entry = self._toc_entry['toc'][key] + return self._child(child_toc_entry) + except KeyError: + return self.to_dict().__getitem__(key) def __iter__(self): - if self._data is None: - return self.toc_entry['toc'].__iter__() - else: - return self._data.__iter__() + return self._toc_entry['toc'].__iter__() def __len__(self): - if self._data is None: - return self.toc_entry['toc'].__len__() - else: - return self._data.__len__() + return self._toc_entry['toc'].__len__() + @cached(thread_safe=False) def to_dict(self): - return self._read(self.toc_entry['pos']) + # todo: potential bug here, what if children are ArchiveList or ArchiveDict? + return self._read(self._toc_entry['pos']) -class ArchiveReader(ArchiveObject): +class ArchiveReader(ArchiveDict): def __init__(self, file_or_path: Union[str, BytesIO], use_blocked_toc=True): - self.file_or_path = file_or_path + self._file_or_path = file_or_path - f: BytesIO = None - if isinstance(self.file_or_path, str): - f = cast(BytesIO, open(self.file_or_path, 'rb')) - elif isinstance(self.file_or_path, BytesIO): - f = self.file_or_path - elif isinstance(self.file_or_path, BufferedReader): - f = self.file_or_path + if isinstance(self._file_or_path, str): + f: BytesIO = cast( + BytesIO, open(self._file_or_path, 'rb', buffering=archive.read_buffer_size)) + elif isinstance(self._file_or_path, (BytesIO, BufferedReader)): + f = cast(BytesIO, self._file_or_path) else: raise ValueError('not a file or path') + # noinspection PyTypeChecker super().__init__(None, f) - self._toc_entry = None - # this number is determined by the msgpack encoding of the file beginning: # { 'toc_pos': <...> # ^11 - self._f.seek(11) - self.toc_position = ArchiveReader._decode_position(self._f.read(10)) - - self.use_blocked_toc = use_blocked_toc - if use_blocked_toc: - self._f.seek(11) - self._toc: Dict[str, Any] = {} - toc_start = self.toc_position[0] - self._f.seek(toc_start) - b = self._f.read(1)[0] - if b & 0b11110000 == 0b10000000: - self._n_toc = b & 0b00001111 - self._toc_offset = toc_start + 1 - elif b == 0xde: - self._n_toc, = struct.unpack_from(">H", self._f.read(2)) - self._toc_offset = toc_start + 3 - elif b == 0xdf: - self._n_toc, = struct.unpack_from(">I", self._f.read(4)) - self._toc_offset = toc_start + 5 - else: - raise ArchiveError('Archive top-level TOC is not a msgpack map (dictionary).') - + self._toc_position = _decode(self._direct_read(10, 11)) + + self._use_blocked_toc = use_blocked_toc + + if not self._use_blocked_toc: + self._toc_entry = self._read(self._toc_position) + return + + toc_start = self._toc_position[0] + b = self._direct_read(1, toc_start)[0] + if b & 0b11110000 == 0b10000000: + self._toc_number = b & 0b00001111 + self._toc_offset = toc_start + 1 + elif b == 0xde: + self._toc_number, = struct.unpack_from(">H", self._direct_read(2, toc_start + 1)) + self._toc_offset = toc_start + 3 + elif b == 0xdf: + self._toc_number, = struct.unpack_from(">I", self._direct_read(4, toc_start + 1)) + self._toc_offset = toc_start + 5 else: - self.toc_entry = self._read(self.toc_position) + raise ArchiveError('Archive top-level TOC is not a msgpack map (dictionary).') + + self._toc: Dict[str, Any] = {} + self._toc_block_info = [None] * (self._toc_number // _entries_per_block + 1) def __enter__(self): return self - fs_block_size = 4096 - toc_block_size_entries = math.ceil(4096 / _toc_item_size) - toc_block_size_bytes = math.ceil(4096 / 54) * _toc_item_size + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() def _load_toc_block(self, i_entry: int): - i_block = math.floor(i_entry / ArchiveReader.toc_block_size_entries) + i_block = i_entry // _entries_per_block + + if self._toc_block_info[i_block]: + return self._toc_block_info[i_block] + + i_offset = i_block * _bytes_per_block + self._toc_offset + block_data = self._direct_read(_bytes_per_block, i_offset) - self._f.seek(i_block * ArchiveReader.toc_block_size_bytes + self._toc_offset) - block_data = self._f.read(ArchiveReader.toc_block_size_bytes) first, last = None, None - toc_block_size_entries = min( - ArchiveReader.toc_block_size_entries, - self._n_toc - i_block * ArchiveReader.toc_block_size_entries) - - for i in range(0, toc_block_size_entries): - offset = i * _toc_item_size - entry_uuid = unpackb(block_data[offset:offset + _toc_uuid_size]) - positions_encoded = unpackb(block_data[offset + _toc_uuid_size:offset + _toc_item_size]) - positions = ( - ArchiveReader._decode_position(positions_encoded[0]), - ArchiveReader._decode_position(positions_encoded[1])) + + entries_current_block = min( + _entries_per_block, self._toc_number - i_block * _entries_per_block) + + offset: int = 0 + for i in range(entries_current_block): + entry_uuid, positions = _unpack_entry(block_data[offset:offset + _toc_item_size]) self._toc[entry_uuid] = positions + offset += _toc_item_size if i == 0: first = entry_uuid - if i + 1 == toc_block_size_entries: + if i + 1 == entries_current_block: last = entry_uuid - return first, last + self._toc_block_info[i_block] = (first, last) + + return self._toc_block_info[i_block] def __getitem__(self, key): key = utils.adjust_uuid_size(key) - if self.use_blocked_toc and self.toc_entry is None: - if self._n_toc == 0: + if self._use_blocked_toc and self._toc_entry is None: + if self._toc_number == 0: raise KeyError(key) positions = self._toc.get(key) # TODO use hash algorithm instead of binary search if positions is None: r_start = 0 - r_end = self._n_toc - i_block = None + r_end = self._toc_number + i_entry = None while r_start <= r_end: - new_i_block = r_start + math.floor((r_end - r_start) / 2) - if i_block == new_i_block: + m_entry = r_start + (r_end - r_start) // 2 + if i_entry == m_entry: break - else: - i_block = new_i_block - first, last = self._load_toc_block(i_block) + i_entry = m_entry + + first, last = self._load_toc_block(i_entry) if key < first: - r_end = i_block - 1 + r_end = i_entry - 1 elif key > last: - r_start = i_block + 1 + r_start = i_entry + 1 else: break @@ -404,48 +441,38 @@ class ArchiveReader(ArchiveObject): raise KeyError(key) toc_position, data_position = positions - else: - positions_encoded = self.toc_entry[key] - toc_position = ArchiveReader._decode_position(positions_encoded[0]) - data_position = ArchiveReader._decode_position(positions_encoded[1]) + positions = self._toc_entry[key] + toc_position = _decode(positions[0]) + data_position = _decode(positions[1]) - toc = self._read(toc_position) - return ArchiveObject(toc, self._f, data_position[0]) + return ArchiveDict(self._read(toc_position), self._f, data_position[0]) def __iter__(self): - if self.toc_entry is None: + if self._toc_entry is None: # is not necessarily read when using blocked toc - self.toc_entry = self._read(self.toc_position) + self._toc_entry = self._read(self._toc_position) - return self.toc_entry.__iter__() + return self._toc_entry.__iter__() def __len__(self): - if self.toc_entry is None: + if self._toc_entry is None: # is not necessarily read when using blocked toc - self.toc_entry = self._read(self.toc_position) + self._toc_entry = self._read(self._toc_position) - return self.toc_entry.__len__() + return self._toc_entry.__len__() def close(self): - if isinstance(self.file_or_path, str): + if isinstance(self._file_or_path, str): self._f.close() - def __exit__(self, exc_type, exc_val, exc_tb): - self.close() - - @staticmethod - def _decode_position(position: bytes) -> Tuple[int, int]: - return int.from_bytes(position[0:5], byteorder='little', signed=False), \ - int.from_bytes(position[5:], byteorder='little', signed=False) - def is_closed(self): return self._f.closed def write_archive( - path_or_file: Union[str, BytesIO], n_entries: int, data: Iterable[Tuple[str, Any]], - entry_toc_depth: int = 2) -> None: + path_or_file: Union[str, BytesIO], n_entries: int, + data: Iterable[Tuple[str, Any]], entry_toc_depth: int = 2) -> None: ''' Writes a msgpack-based archive file. The file contents will be a valid msgpack-object. The data will contain extra table-of-contents (TOC) objects that map some keys to @@ -495,7 +522,7 @@ def write_archive( TOCs are regular msgpack encoded integers. Arguments: - file_or_path: A file path or file-like to the archive file that should be written. + path_or_file: A file path or file-like to the archive file that should be written. n_entries: The number of entries that will be added to the file. data: The file contents as an iterator of entry id, data tuples. entry_toc_depth: The depth of the table of contents in each entry. Only objects will @@ -506,7 +533,7 @@ def write_archive( writer.add(uuid, entry) -def read_archive(file_or_path: str, **kwargs) -> ArchiveReader: +def read_archive(file_or_path: Union[str, BytesIO], **kwargs) -> ArchiveReader: ''' Allows to read a msgpack-based archive. @@ -525,7 +552,6 @@ def read_archive(file_or_path: str, **kwargs) -> ArchiveReader: if __name__ == '__main__': - def benchmark(): from time import time import sys @@ -551,7 +577,9 @@ if __name__ == '__main__': start = time() for _ in range(0, 23): read_archive(buffer, use_blocked_toc=use_blocked_toc)[example_uuid]['run']['system'] - print('archive.py: access single entry system (23), blocked %d: ' % use_blocked_toc, (time() - start) / 23) + print( + f'archive.py: access single entry system (23), blocked {use_blocked_toc:d}: ', + (time() - start) / 23) # read every n-ed entry from archive buffer = BytesIO(buffer.getbuffer()) @@ -562,7 +590,9 @@ if __name__ == '__main__': for i, entry in enumerate(example_archive): if i % access_every == 0: data[entry[0]]['run']['system'] - print('archive.py: access every %d-ed entry single entry system (23), blocked %d: ' % (access_every, use_blocked_toc), (time() - start) / 23) + print( + f'archive.py: access every {access_every:d}-ed entry single entry system (23), ' + f'blocked {use_blocked_toc:d}: ', (time() - start) / 23) # just msgpack start = time() diff --git a/nomad/config.py b/nomad/config.py index f11340314debf658b4e06ff6f62fd87c50c5bb0d..a4f4cbb0077ffe1efe8ae77224ce521ce19e5099 100644 --- a/nomad/config.py +++ b/nomad/config.py @@ -311,7 +311,7 @@ datacite = NomadConfig( ) meta = NomadConfig( - version='1.0.7', + version='1.0.8', commit=gitinfo.commit, deployment='devel', label=None, @@ -381,6 +381,13 @@ bundle_import = NomadConfig( ) ) +archive = NomadConfig( + block_size=256 * 1024, + read_buffer_size=256 * 1024, # GPFS needs at least 256K to achieve decent performance + max_process_number=20, # maximum number of processes can be assigned to process archive query + min_entires_per_process=20 # minimum number of entries per process +) + auxfile_cutoff = 100 parser_matching_size = 150 * 80 # 150 lines of 80 ASCII characters per line console_log_level = logging.WARNING diff --git a/nomad/datamodel/metainfo/simulation/calculation.py b/nomad/datamodel/metainfo/simulation/calculation.py index 0198b734ec5240abe1959467e32b7dfcccbe98a3..bd4219902cca57eb275e4b33c109e1f0c2220a6e 100644 --- a/nomad/datamodel/metainfo/simulation/calculation.py +++ b/nomad/datamodel/metainfo/simulation/calculation.py @@ -126,6 +126,7 @@ class AtomicValues(MSection): m_def = Section(validate=False) + # TODO rename this to spin_channel spin = Quantity( type=np.dtype(np.int32), shape=[], @@ -210,6 +211,7 @@ class EnergyEntry(Atomic): cell. ''') + # TODO rename this to value_atomic values_per_atom = Quantity( type=np.dtype(np.float64), shape=['n_atoms'], @@ -409,6 +411,38 @@ class Energy(MSection): ''', repeats=True) + enthalpy = Quantity( + type=np.dtype(np.float64), + shape=[], + unit='joule', + description=''' + Value of the calculated enthalpy per cell i.e. energy_total + pressure * volume. + ''') + + entropy = Quantity( + type=np.dtype(np.float64), + shape=[], + unit='joule / kelvin', + description=''' + Value of the entropy. + ''') + + chemical_potential = Quantity( + type=np.dtype(np.float64), + shape=[], + unit='joule', + description=''' + Value of the chemical potential. + ''') + + internal = Quantity( + type=np.dtype(np.float64), + shape=[], + unit='joule', + description=''' + Value of the internal energy. + ''') + # TODO remove this should be be entropy.correction correction_entropy = SubSection( sub_section=EnergyEntry.m_def, @@ -529,38 +563,6 @@ class Forces(MSection): corresponding to the minus gradient of energy_T0. ''') - enthalpy = Quantity( - type=np.dtype(np.float64), - shape=[], - unit='joule', - description=''' - Value of the calculated enthalpy per cell i.e. energy_total + pressure * volume. - ''') - - entropy = Quantity( - type=np.dtype(np.float64), - shape=[], - unit='joule / kelvin', - description=''' - Value of the entropy. - ''') - - chemical_potential = Quantity( - type=np.dtype(np.float64), - shape=[], - unit='joule', - description=''' - Value of the chemical potential. - ''') - - internal = Quantity( - type=np.dtype(np.float64), - shape=[], - unit='joule', - description=''' - Value of the internal energy. - ''') - contributions = SubSection( sub_section=ForcesEntry.m_def, description=''' @@ -646,6 +648,20 @@ class ChargesValue(AtomicValues): Value of the charge projected on atom and orbital. ''') + n_electrons = Quantity( + type=np.dtype(np.float64), + shape=[], + description=''' + Value of the number of electrons projected on atom and orbital. + ''') + + spin_z = Quantity( + type=np.dtype(np.float64), + shape=[], + description=''' + Value of the azimuthal spin projected on atom and orbital. + ''') + class Charges(Atomic): ''' @@ -670,6 +686,15 @@ class Charges(Atomic): Value of the atomic charges calculated through analysis_method. ''') + n_electrons = Quantity( + type=np.dtype(np.float64), + shape=['n_atoms'], + description=''' + Value of the number of electrons on the atoms. + ''') + + # TODO should this be on a separate section magnetic_moments or charges should be + # renamed population spins = Quantity( type=np.dtype(np.float64), shape=['n_atoms'], @@ -1428,7 +1453,7 @@ class ExcitedStates(MSection): ''') -class VibrationsValues(MSection): +class VibrationalFrequenciesValues(MSection): ''' Section describing a vibrational spectrum. ''' @@ -1472,7 +1497,7 @@ class VibrationsValues(MSection): ''') -class Vibrations(MSection): +class VibrationalFrequencies(MSection): ''' Section containing results related to vibrational frequencies. ''' @@ -1491,12 +1516,14 @@ class Vibrations(MSection): shape=['n_frequencies'], unit='1 / meter', description=''' - Values of vibration Frequenices (cm-1) + Values of vibrational frequencies (m-1) ''') - raman = SubSection(sub_section=VibrationsValues.m_def, repeats=False) + # TODO add normal modes + + raman = SubSection(sub_section=VibrationalFrequenciesValues.m_def, repeats=False) - infrared = SubSection(sub_section=VibrationsValues.m_def, repeats=False) + infrared = SubSection(sub_section=VibrationalFrequenciesValues.m_def, repeats=False) class BaseCalculation(MSection): @@ -1649,7 +1676,7 @@ class BaseCalculation(MSection): excited_states = SubSection(sub_section=ExcitedStates.m_def, repeats=True) - vibrational_frequencies = SubSection(sub_section=Vibrations.m_def, repeats=True) + vibrational_frequencies = SubSection(sub_section=VibrationalFrequencies.m_def, repeats=True) potential = SubSection(sub_section=Potential.m_def, repeats=True) diff --git a/nomad/datamodel/metainfo/simulation/system.py b/nomad/datamodel/metainfo/simulation/system.py index b42f30d8193309a7f93b28ced703e4ab5e9e03ba..4cae537bde7b95c477824c04c09a6c973e901366 100644 --- a/nomad/datamodel/metainfo/simulation/system.py +++ b/nomad/datamodel/metainfo/simulation/system.py @@ -27,6 +27,70 @@ from ..common import FastAccess m_package = Package() +class AtomsGroup(MSection): + ''' + Describes a group of atoms which may constitute a sub system as in the case of a + molecule. + ''' + + m_def = Section(validate=False) + + label = Quantity( + type=str, + shape=[], + description=''' + Label of the group. + ''') + + type = Quantity( + type=str, + shape=[], + description=''' + Type of the group. + ''') + + index = Quantity( + type=int, + shape=[], + description=''' + Index of the group with respect to its parent group. + ''') + + composition_formula = Quantity( + type=str, + shape=[], + description=''' + The overall composition of the group with respect to its subgroups. + The syntax for a groups composed of X and Y with x and y components of each, + respectively, is X(x)Y(y). + ''') + + n_atoms = Quantity( + type=int, + shape=[], + description=''' + The total number of atoms in the group. + ''') + + atom_indices = Quantity( + type=np.dtype(np.int32), + shape=['n_atoms'], + description=''' + Indices of the atoms in the group with respect to the system. + ''') + + is_molecule = Quantity( + type=bool, + shape=[], + description=''' + Denotes if the atoms in this group represent a molecule. That is, all atoms + in the group are connected via bonds, and no other atoms contain bonds + with these atoms. + ''') + + atoms_group = SubSection(sub_section=SectionProxy('AtomsGroup'), repeats=True) + + class Atoms(MSection): ''' Describes the atomic structure of the physical system. This includes the atom @@ -484,6 +548,8 @@ class System(MSection): atoms = SubSection(sub_section=Atoms.m_def, categories=[FastAccess]) + atoms_group = SubSection(sub_section=AtomsGroup.m_def, repeats=True) + chemical_composition = Quantity( type=str, shape=[], diff --git a/nomad/datamodel/metainfo/workflow.py b/nomad/datamodel/metainfo/workflow.py index 2a5edb943d6e6a5e620405344097668f4e83d834..308f34c8dcb235ba9550610452b994200b226734 100644 --- a/nomad/datamodel/metainfo/workflow.py +++ b/nomad/datamodel/metainfo/workflow.py @@ -1331,6 +1331,230 @@ class MolecularDynamics(MSection): Indicates if calculation contains thermodynamic data. ''') + radial_distribution_functions = SubSection(sub_section=SectionProxy('RadialDistributionFunction'), repeats=True) + + mean_squared_displacements = SubSection(sub_section=SectionProxy('MeanSquaredDisplacement'), repeats=True) + + +class EnsemblePropertyValues(MSection): + ''' + Generic section containing information regarding the values of an ensemble property. + ''' + + m_def = Section(validate=False) + + label = Quantity( + type=str, + shape=[], + description=''' + Describes the atoms or molecule types involved in determining the property. + ''') + + +class EnsembleProperty(MSection): + ''' + Generic section containing information about a calculation of any static observable + from a trajectory (i.e., from an ensemble average). + ''' + + m_def = Section(validate=False) + + type = Quantity( + type=MEnum('Molecular', 'Atomic'), + shape=[], + description=''' + Describes if the observable is calculated at the molecular or atomic level. + ''') + + n_smooth = Quantity( + type=int, + shape=[], + description=''' + Number of bins over which the running average was computed for + the observable `values'. + ''') + + error_type = Quantity( + type=str, + shape=[], + description=''' + Describes the type of error reported for this observable. + ''') + + n_variables = Quantity( + type=int, + shape=[], + description=''' + Number of variables along which the property is determined. + ''') + + variables_name = Quantity( + type=np.dtype(str), + shape=['n_variables'], + description=''' + Name/description of the independent variables along which the observable is defined. + ''') + + +class RadialDistributionFunctionValues(EnsemblePropertyValues): + ''' + Section containing information regarding the values of + radial distribution functions (rdfs). + ''' + + m_def = Section(validate=False) + + n_bins = Quantity( + type=int, + shape=[], + description=''' + Number of bins. + ''') + + bins = Quantity( + type=np.dtype(np.float64), + shape=['n_bins'], + unit='m', + description=''' + Distances along which the rdf was calculated. + ''') + + value = Quantity( + type=np.dtype(np.float64), + shape=['n_bins'], + description=''' + Values of the property. + ''') + + +class RadialDistributionFunction(EnsembleProperty): + ''' + Section containing information about the calculation of + radial distribution functions (rdfs). + ''' + + m_def = Section(validate=False) + + radial_distribution_function_values = SubSection(sub_section=RadialDistributionFunctionValues.m_def, repeats=True) + + +class CorrelationFunctionValues(MSection): + ''' + Generic section containing information regarding the values of a correlation function. + ''' + + m_def = Section(validate=False) + + label = Quantity( + type=str, + shape=[], + description=''' + Describes the atoms or molecule types involved in determining the property. + ''') + + n_times = Quantity( + type=int, + shape=[], + description=''' + Number of times windows for the calculation of the correlation function. + ''') + + +class CorrelationFunction(MSection): + ''' + Generic section containing information about a calculation of any time correlation + function from a trajectory. + ''' + + m_def = Section(validate=False) + + type = Quantity( + type=MEnum('Molecular', 'Atomic'), + shape=[], + description=''' + Describes if the correlation function is calculated at the molecular or atomic level. + ''') + + direction = Quantity( + type=MEnum('x', 'y', 'z', 'xy', 'yz', 'xz', 'xyz'), + shape=[], + description=''' + Describes the direction in which the correlation function was calculated. + ''') + + error_type = Quantity( + type=str, + shape=[], + description=''' + Describes the type of error reported for this correlation function. + ''') + + +class DiffusionConstantValues(MSection): + ''' + Section containing information regarding the diffusion constants. + ''' + + m_def = Section(validate=False) + + value = Quantity( + type=np.dtype(np.float64), + shape=[], + unit='m^2/s', + description=''' + Values of the diffusion constants. + ''') + + error_type = Quantity( + type=str, + shape=[], + description=''' + Describes the type of error reported for this observable. + ''') + + errors = Quantity( + type=np.dtype(np.float64), + shape=['*'], + description=''' + Error associated with the determination of the diffusion constant. + ''') + + +class MeanSquaredDisplacementValues(CorrelationFunctionValues): + ''' + Section containing information regarding the values of a mean squared displacements (msds). + ''' + + m_def = Section(validate=False) + + times = Quantity( + type=np.dtype(np.float64), + shape=['n_times'], + unit='s', + description=''' + Time windows used for the calculation of the msds. + ''') + + value = Quantity( + type=np.dtype(np.float64), + shape=['n_times'], + unit='m^2', + description=''' + Msd values. + ''') + + diffusion_constant = SubSection(sub_section=DiffusionConstantValues.m_def, repeats=False) + + +class MeanSquaredDisplacement(CorrelationFunction): + ''' + Section containing information about a calculation of any mean squared displacements (msds). + ''' + + m_def = Section(validate=False) + + mean_squared_displacement_values = SubSection(sub_section=MeanSquaredDisplacementValues.m_def, repeats=True) + class SinglePoint(MSection): ''' diff --git a/nomad/files.py b/nomad/files.py index a0084b06bef503901c53e67147dbd23c32aa4e2d..5d82a9cb9c42b4d553f44b7c810f3a9f20722e92 100644 --- a/nomad/files.py +++ b/nomad/files.py @@ -618,7 +618,7 @@ class UploadFiles(DirectoryObject, metaclass=ABCMeta): mime_type = 'application/octet-stream' return mime_type - def read_archive(self, entry_id: str) -> ArchiveReader: + def read_archive(self, entry_id: str, use_blocked_toc: bool = True) -> ArchiveReader: ''' Returns an :class:`nomad.archive.ArchiveReader` that contains the given entry_id. @@ -763,9 +763,9 @@ class StagingUploadFiles(UploadFiles): return self.archive_file_object(entry_id).size - def read_archive(self, entry_id: str) -> ArchiveReader: + def read_archive(self, entry_id: str, use_blocked_toc: bool = True) -> ArchiveReader: try: - return read_archive(self.archive_file_object(entry_id).os_path) + return read_archive(self.archive_file_object(entry_id).os_path, use_blocked_toc=use_blocked_toc) except FileNotFoundError: raise KeyError(entry_id) @@ -1201,7 +1201,7 @@ class PublicUploadFiles(UploadFiles): self.access # Invoke to initialize return self._archive_msg_file_object - def _open_msg_file(self) -> ArchiveReader: + def _open_msg_file(self, use_blocked_toc: bool = True) -> ArchiveReader: if self._archive_msg_file is not None: if not self._archive_msg_file.is_closed(): return self._archive_msg_file @@ -1211,7 +1211,7 @@ class PublicUploadFiles(UploadFiles): if not msg_file_object.exists(): raise FileNotFoundError() - archive = read_archive(msg_file_object.os_path) + archive = read_archive(msg_file_object.os_path, use_blocked_toc=use_blocked_toc) assert archive is not None self._archive_msg_file = archive @@ -1374,9 +1374,9 @@ class PublicUploadFiles(UploadFiles): raise KeyError(file_path) - def read_archive(self, entry_id: str) -> Any: + def read_archive(self, entry_id: str, use_blocked_toc: bool = True) -> Any: try: - archive = self._open_msg_file() + archive = self._open_msg_file(use_blocked_toc) if entry_id in archive: return archive except FileNotFoundError: diff --git a/nomad/normalizing/workflow.py b/nomad/normalizing/workflow.py index 7caa048e483c7b72443288a04ba6ac25db9da56d..8054310342af98bfcb9e90a1621ac5a07d1af6ef 100644 --- a/nomad/normalizing/workflow.py +++ b/nomad/normalizing/workflow.py @@ -247,6 +247,8 @@ class GeometryOptimizationNormalizer(TaskNormalizer): except (IndexError, AttributeError): invalid = True break + if energy is None: + continue energies.append(energy.magnitude) if invalid: self.logger.warning("energy not reported for an scc that is part of a geometry optimization") diff --git a/nomad/parsing/parsers.py b/nomad/parsing/parsers.py index b9a8076b1f3ec0607270b21f6e72086aec4ae836..0405151642593aa40f6f3312aea07e7ad201ba1f 100644 --- a/nomad/parsing/parsers.py +++ b/nomad/parsing/parsers.py @@ -265,6 +265,12 @@ parsers = [ name='parsers/molcas', code_name='MOLCAS', code_homepage='http://www.molcas.org/', domain='dft', mainfile_contents_re=r'M O L C A S' ), + MatchingParserInterface( + 'electronicparsers.MopacParser', + name='parsers/mopac', code_name='MOPAC', domain='dft', + mainfile_contents_re=r'\s*\*\*\s*MOPAC\s*([0-9a-zA-Z]*)\s*\*\*\s*', + mainfile_mime_re=r'text/.*', + ), MatchingParserInterface( 'electronicparsers.NWChemParser', name='parsers/nwchem', code_name='NWChem', code_homepage='http://www.nwchem-sw.org/', @@ -281,6 +287,13 @@ parsers = [ name='parsers/onetep', code_name='ONETEP', code_homepage='https://www.onetep.org/', domain='dft', mainfile_contents_re=r'####### # # ####### ####### ####### ######' ), + MatchingParserInterface( + 'electronicparsers.OpenmxParser', + name='parsers/openmx', code_name='OpenMX', code_homepage='http://www.openmx-square.org/', + mainfile_mime_re=r'(text/.*)', + mainfile_name_re=r'.*\.out$', + mainfile_contents_re=(r'^\*{59}\s+\*{59}\s+This calculation was performed by OpenMX'), + ), MatchingParserInterface( 'electronicparsers.OrcaParser', name='parsers/orca', code_name='ORCA', code_homepage='https://orcaforum.kofo.mpg.de/', @@ -364,6 +377,11 @@ parsers = [ name='parsers/asap', code_name='ASAP', domain='dft', mainfile_name_re=r'.*.traj$', mainfile_mime_re=r'application/octet-stream' ), + MatchingParserInterface( + 'atomisticparsers.BOPfoxParser', + name='parsers/bopfox', code_name='BOPfox', + mainfile_contents_re=r'\s+\-+\s+BOPfox' + ), MatchingParserInterface( 'atomisticparsers.DFTBPlusParser', name='parsers/dftbplus', code_name='DFTB+', domain='dft', @@ -404,12 +422,6 @@ parsers = [ name='parsers/lib-atoms', code_name='libAtoms', code_homepage='https://libatoms.github.io/', mainfile_contents_re=(r'\s*<GAP_params\s'), ), - MatchingParserInterface( - 'atomisticparsers.MopacParser', - name='parsers/mopac', code_name='MOPAC', domain='dft', - mainfile_contents_re=r'\s*\*\*\s*MOPAC\s*([0-9a-zA-Z]*)\s*\*\*\s*', - mainfile_mime_re=r'text/.*', - ), MatchingParserInterface( 'atomisticparsers.NAMDParser', name='parsers/namd', code_name='Namd', domain='dft', @@ -427,6 +439,17 @@ parsers = [ name='parsers/tinker', code_name='TINKER', domain='dft', mainfile_contents_re=r'TINKER --- Software Tools for Molecular Design' ), + MatchingParserInterface( + 'atomisticparsers.XTBParser', + name='parsers/xtb', code_name='XTB', + code_homepage='https://www.chemie.uni-bonn.de/pctc/mulliken-center/software/xtb/xtb', + mainfile_contents_re=( + r'\s*-----------------------------------------------------------\s*' + r'\s*\| ===================== \|\s*' + r'\s*\| x T B \|\s*' + r'\s*\| ===================== \|\s*' + ) + ), MatchingParserInterface( 'workflowparsers.AFLOWParser', name='parsers/aflow', code_name='AFlow', code_homepage='http://www.aflowlib.org/', @@ -474,9 +497,9 @@ parsers = [ mainfile_contents_re=(r'^LOBSTER\s*v[\d\.]+.*'), ), MatchingParserInterface( - 'workflowparsers.MPParser', - name='parsers/mp', code_name='MaterialsProject', - code_homepage='https://materialsproject.org', + 'workflowparsers.AtomateParser', + name='parsers/atomate', code_name='Atomate', + code_homepage='https://atomate.org', mainfile_mime_re=r'(application/json)|(text/.*)', mainfile_name_re=r'.*mp.+materials\.json', mainfile_contents_re=(r'"pymatgen_version":') diff --git a/ops/helm/nomad/Chart.yaml b/ops/helm/nomad/Chart.yaml index d9cc2e12e65b51b43e0f77e06b9429e713e4a448..8e5795431ff8a33b425fd6a9e972e519862c2da8 100644 --- a/ops/helm/nomad/Chart.yaml +++ b/ops/helm/nomad/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v1 -appVersion: "1.0.7" +appVersion: "1.0.8" description: A Helm chart for Kubernetes that only runs nomad services and uses externally hosted databases. name: nomad -version: "1.0.7" +version: "1.0.8" diff --git a/ops/helm/nomad/deployments/prod-staging-values.yaml b/ops/helm/nomad/deployments/prod-staging-values.yaml index 4831d21a33da004177ba2fa31fd71321b9eda346..8d3371673543d1e02bce889020abbfffcf8ac2dd 100644 --- a/ops/helm/nomad/deployments/prod-staging-values.yaml +++ b/ops/helm/nomad/deployments/prod-staging-values.yaml @@ -1,8 +1,8 @@ version: - label: "1.0.7" + label: "1.0.8" isBeta: true usesBetaData: false - officialUrl: "https://nomad-lab.eu/prod/rae/gui" + officialUrl: "https://nomad-lab.eu/prod/v1/gui" image: tag: "latest" diff --git a/ops/helm/nomad/deployments/prod-test-values.yaml b/ops/helm/nomad/deployments/prod-test-values.yaml index c82fe644a7430f770daf1df34dcba27b3970ddd1..dca786303d3c23b47847eaeb2ca6fbd3b9ce455b 100644 --- a/ops/helm/nomad/deployments/prod-test-values.yaml +++ b/ops/helm/nomad/deployments/prod-test-values.yaml @@ -1,8 +1,8 @@ version: - label: "1.0.7" - isBeta: true + label: "1.0.8" + isBeta: false usesBetaData: true - officialUrl: "https://nomad-lab.eu/prod/rae/gui" + officialUrl: "https://nomad-lab.eu/prod/v1/gui" image: tag: "latest" diff --git a/ops/helm/nomad/deployments/prod-util-values.yaml b/ops/helm/nomad/deployments/prod-util-values.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b1e60a8d2d65d74e3ae45ba800e6bc8caf290808 --- /dev/null +++ b/ops/helm/nomad/deployments/prod-util-values.yaml @@ -0,0 +1,79 @@ +version: + label: "1.0.8" + isBeta: false + usesBetaData: false + officialUrl: "https://nomad-lab.eu/prod/v1/gui" + +image: + tag: "latest" + pullPolicy: "Always" + +proxy: + nodePort: 30016 + nodeIP: '130.183.207.81' + external: + host: "nomad-lab.eu" + path: "/prod/v1/util" + +gui: + debug: true + matomoEnabled: false + matomoSiteId: 2 + encyclopediaBase: 'https://nomad-lab.eu/prod/rae/encyclopedia/#' + aitoolkitEnabled: false + +app: + replicas: 1 + worker: 1 + threads: 4 + workerClass: "gthread" + nomadNodeType: "public" + +worker: + replicas: 1 + routing: "worker" + processes: 12 + nomadNodeType: "prod-worker" + +elastic: + host: elasticsearch.elasticsearch-7.svc.cluster.local + port: 9200 + +mongo: + host: rs0/mongodb-0.mongo.mongodb.svc.cluster.local,mongodb-1.mongo.mongodb.svc.cluster.local,mongodb-2.mongo.mongodb.svc.cluster.local + +logstash: + host: logstash.elk.svc.cluster.local + +dbname: nomad_prod_v1 + +uploadurl: 'https://nomad-lab.eu/prod/v1/util/api/uploads' + +client: + passwordSecret: 'nomad-keycloak-password' + +keycloak: + serverUrl: "https://nomad-lab.eu/fairdi/keycloak/auth/" + serverExternalUrl: "https://nomad-lab.eu/fairdi/keycloak/auth/" + passwordSecret: 'nomad-keycloak-password' + realmName: 'fairdi_nomad_prod' + clientId: 'nomad_public' + admin_user_id: '82efac55-6187-408c-8027-b98580c0e1c5' + +volumes: + prefixSize: 1 + public: /nomad/fairdi/prod/fs/public + staging: /scratch/fairdi/prod/fs/staging + tmp: /nomad/fairdi/prod/fs/tmp + nomad: /nomad + archiveVersionSuffix: v1 + +mail: + enabled: false + host: 'mailrelay.mpcdf.mpg.de' + port: 25 + from: 'support@nomad-lab.eu' + +datacite: + secret: 'nomad-datacite' + enabled: false diff --git a/ops/helm/nomad/deployments/prod-v1-values.yaml b/ops/helm/nomad/deployments/prod-v1-values.yaml index 6ec2c50eca88496d658c3158adac95124da7431f..5317b88834a6df008f56f89c22c8c0e64447989e 100644 --- a/ops/helm/nomad/deployments/prod-v1-values.yaml +++ b/ops/helm/nomad/deployments/prod-v1-values.yaml @@ -1,8 +1,8 @@ version: - label: "1.0.7" - isBeta: true + label: "1.0.8" + isBeta: false usesBetaData: false - officialUrl: "https://nomad-lab.eu/prod/rae/gui" + officialUrl: "https://nomad-lab.eu/prod/v1/gui" image: tag: "latest" diff --git a/ops/helm/nomad/values.yaml b/ops/helm/nomad/values.yaml index fdf9e90383c96706b3dc5497c7d98d758f344172..82af036bace82d8076c628ebd4180705afae460e 100644 --- a/ops/helm/nomad/values.yaml +++ b/ops/helm/nomad/values.yaml @@ -1,6 +1,6 @@ ## Default values for nomad@FAIRDI version: - label: "1.0.7" + label: "1.0.8" isTest: false isBeta: false usesBetaData: false diff --git a/requirements.txt b/requirements.txt index ad6f31a120cd5eb9892bb1694b43c72edf75a43f..460e80e7b9c725e299ad093209320c6928b8643a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,6 +23,7 @@ elasticsearch-dsl==7.4.0 pydantic==1.8.2 jmespath==0.10.0 httpx==0.22.0 +memoization==0.4.0 # [parsing] netCDF4==1.5.4 diff --git a/run.sh b/run.sh index 97b5580678acd147f6c72d31a118e4b21cad24b8..cd34360f15d4eb1875ab5d78b30b993691e2776f 100644 --- a/run.sh +++ b/run.sh @@ -3,4 +3,4 @@ python -m nomad.cli admin ops gui-config params=() [ -e gunicorn.conf ] && params+=(--config gunicorn.conf) [ -e gunicorn.log.conf ] && params+=(--log-config gunicorn.log.conf) -python -m gunicorn.app.wsgiapp "${params[@]}" --timeout 120 --worker-class=uvicorn.workers.UvicornWorker -b 0.0.0.0:8000 nomad.app.main:app +python -m gunicorn.app.wsgiapp "${params[@]}" --timeout 120 --keep-alive 5 --worker-class=uvicorn.workers.UvicornWorker -b 0.0.0.0:8000 nomad.app.main:app diff --git a/tests/data/parsers/mp/mp-1/elasticity.json b/tests/data/parsers/atomate/mp-1/elasticity.json similarity index 100% rename from tests/data/parsers/mp/mp-1/elasticity.json rename to tests/data/parsers/atomate/mp-1/elasticity.json diff --git a/tests/data/parsers/mp/mp-1/eos.json b/tests/data/parsers/atomate/mp-1/eos.json similarity index 100% rename from tests/data/parsers/mp/mp-1/eos.json rename to tests/data/parsers/atomate/mp-1/eos.json diff --git a/tests/data/parsers/mp/mp-1/magnetism.json b/tests/data/parsers/atomate/mp-1/magnetism.json similarity index 100% rename from tests/data/parsers/mp/mp-1/magnetism.json rename to tests/data/parsers/atomate/mp-1/magnetism.json diff --git a/tests/data/parsers/mp/mp-1/materials.json b/tests/data/parsers/atomate/mp-1/materials.json similarity index 100% rename from tests/data/parsers/mp/mp-1/materials.json rename to tests/data/parsers/atomate/mp-1/materials.json diff --git a/tests/data/parsers/mp/mp-1/surface_properties.json b/tests/data/parsers/atomate/mp-1/surface_properties.json similarity index 100% rename from tests/data/parsers/mp/mp-1/surface_properties.json rename to tests/data/parsers/atomate/mp-1/surface_properties.json diff --git a/tests/data/parsers/mp/mp-1/tasks.json b/tests/data/parsers/atomate/mp-1/tasks.json similarity index 100% rename from tests/data/parsers/mp/mp-1/tasks.json rename to tests/data/parsers/atomate/mp-1/tasks.json diff --git a/tests/data/parsers/mp/mp-1/thermo.json b/tests/data/parsers/atomate/mp-1/thermo.json similarity index 100% rename from tests/data/parsers/mp/mp-1/thermo.json rename to tests/data/parsers/atomate/mp-1/thermo.json diff --git a/tests/parsing/test_parsing.py b/tests/parsing/test_parsing.py index 0b6e64b08125f746e3604fe8afafa414d213d995..13e3e6d341c8b3d871d04fa3fc9491a8f112a44b 100644 --- a/tests/parsing/test_parsing.py +++ b/tests/parsing/test_parsing.py @@ -72,7 +72,7 @@ parser_examples = [ ('parsers/eels', 'tests/data/parsers/eels.json'), ('parsers/lobster', 'tests/data/parsers/lobster/NaCl/lobsterout'), ('parsers/aflow', 'tests/data/parsers/aflow/Ag1Co1O2_ICSD_246157/aflowlib.json'), - ('parsers/mp', 'tests/data/parsers/mp/mp-1/materials.json'), + ('parsers/atomate', 'tests/data/parsers/atomate/mp-1/materials.json'), ('parsers/asr', 'tests/data/parsers/asr/archive_ccdc26c4f32546c5a00ad03a093b73dc.json'), ('parsers/psi4', 'tests/data/parsers/psi4/adc1/output.ref'), ('parsers/yambo', 'tests/data/parsers/yambo/hBN/r-10b_1Ry_HF_and_locXC_gw0_em1d_ppa'), diff --git a/tests/test_archive.py b/tests/test_archive.py index 77acecc9bd796edc5237951982bcdb61626606fb..4088457ec96c267f91c6368fd7c32bc03671b2cc 100644 --- a/tests/test_archive.py +++ b/tests/test_archive.py @@ -26,7 +26,7 @@ import json from nomad import utils, config from nomad.metainfo import MSection, Quantity, Reference, SubSection, QuantityReference from nomad.datamodel import EntryArchive -from nomad.archive.storage import TOCPacker +from nomad.archive.storage import TOCPacker, _decode, _entries_per_block from nomad.archive import ( write_archive, read_archive, ArchiveReader, ArchiveQueryError, query_archive, write_partial_archive_to_mongo, read_partial_archive_from_mongo, read_partial_archives_from_mongo, @@ -147,12 +147,10 @@ def test_write_archive_single(example_uuid, example_entry): toc_packer.pack(example_entry) assert archive['data'][example_uuid]['toc'] == toc_packer.toc - toc = _unpack(packed_archive, ArchiveReader._decode_position(archive['toc_pos'])) + toc = _unpack(packed_archive, _decode(archive['toc_pos'])) assert example_uuid in toc - assert _unpack( - packed_archive, ArchiveReader._decode_position(toc[example_uuid][0])) == toc_packer.toc - assert _unpack( - packed_archive, ArchiveReader._decode_position(toc[example_uuid][1])) == example_entry + assert _unpack(packed_archive, _decode(toc[example_uuid][0])) == toc_packer.toc + assert _unpack(packed_archive, _decode(toc[example_uuid][1])) == example_entry def test_write_archive_multi(example_uuid, example_entry): @@ -203,7 +201,7 @@ def test_read_archive_single(example_uuid, example_entry, use_blocked_toc): @pytest.mark.parametrize('use_blocked_toc', [False, True]) def test_read_archive_multi(example_uuid, example_entry, use_blocked_toc): - archive_size = ArchiveReader.toc_block_size_entries * 2 + 23 + archive_size = _entries_per_block * 2 + 23 f = BytesIO() write_archive( f, archive_size, @@ -215,10 +213,10 @@ def test_read_archive_multi(example_uuid, example_entry, use_blocked_toc): if use_blocked_toc: reader._load_toc_block(0) assert reader._toc.get(create_example_uuid(0)) is not None - assert len(reader._toc) == ArchiveReader.toc_block_size_entries + assert len(reader._toc) == _entries_per_block reader._load_toc_block(archive_size - 1) assert reader._toc.get(create_example_uuid(archive_size - 1)) is not None - assert len(reader._toc) > ArchiveReader.toc_block_size_entries + assert len(reader._toc) > _entries_per_block for i in range(0, archive_size): reader.get(create_example_uuid(i)) is not None diff --git a/tests/test_client.py b/tests/test_client.py index 684c0090a510a6b92090ec4b8a737363f3e7c440..fe4cae8ab0824feb984497e32235622153a05300 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -94,32 +94,6 @@ def async_api_v1(monkeysession): return test_client -def test_async_query(): - required = { - 'workflow': { - 'calculation_result_ref': { - 'energy': '*', - 'system_ref': { - 'chemical_composition_reduced': '*' - } - } - } - } - - query = { - 'results.method.simulation.program_name': 'VASP', - 'results.material.elements': ['Ti', 'O'] - } - - async_query = ArchiveQuery(query=query, required=required, page_size=100, results_max=10000) - - num_entry = async_query.fetch(1000) - num_entry -= len(async_query.download(100)) - num_entry -= len(async_query.download(100)) - - assert num_entry == sum([count for _, count in async_query.upload_list()]) - - def test_async_query_basic(async_api_v1, published_wo_user_metadata): async_query = ArchiveQuery()