[
  {
    "path": ".editorconfig",
    "content": "# Editor configuration, see http://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.md]\nmax_line_length = off\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"root\": true,\n  \"ignorePatterns\": [\"**/*\"],\n  \"plugins\": [\"@nrwl/nx\"],\n  \"overrides\": [\n    {\n      \"files\": [\"*.ts\", \"*.tsx\", \"*.js\", \"*.jsx\"],\n      \"rules\": {\n        \"@nrwl/nx/enforce-module-boundaries\": [\n          \"error\",\n          {\n            \"enforceBuildableLibDependency\": true,\n            \"allow\": [],\n            \"depConstraints\": [\n              {\n                \"sourceTag\": \"*\",\n                \"onlyDependOnLibsWithTags\": [\"*\"]\n              }\n            ]\n          }\n        ]\n      },\n      \"plugins\": [],\n      \"extends\": []\n    },\n    {\n      \"files\": [\"*.ts\", \"*.tsx\"],\n      \"extends\": [\"plugin:@nrwl/nx/typescript\"],\n      \"rules\": {},\n      \"plugins\": []\n    },\n    {\n      \"files\": [\"*.js\", \"*.jsx\"],\n      \"extends\": [\"plugin:@nrwl/nx/javascript\"],\n      \"rules\": {}\n    }\n  ]\n}\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. iOS]\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n**Smartphone (please complete the following information):**\n - Device: [e.g. iPhone6]\n - OS: [e.g. iOS8.1]\n - Browser [e.g. stock browser, safari]\n - Version [e.g. 22]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: Node.js CI\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v2\n        with:\n          fetch-depth: 0\n      - uses: nrwl/nx-set-shas@v2\n      - run: npm ci\n      - run: npx nx workspace-lint\n      - run: npx nx format:check\n      - run: npx nx run-many --target=lint --all\n      - run: npx nx run-many --target=test --all\n      - run: npx nx run dev-server:build\n      - run: npm run build:prod\n        env:\n          CI: true\n"
  },
  {
    "path": ".gitignore",
    "content": "# See http://help.github.com/ignore-files/ for more about ignoring files.\n\n# compiled output\n/dist\n/tmp\n/out-tsc\n\n# dependencies\n/node_modules\n\n# IDEs and editors\n/.idea\n.project\n.classpath\n.c9/\n*.launch\n.settings/\n*.sublime-workspace\n\n# IDE - VSCode\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n\n# misc\n/.angular/cache\n/.sass-cache\n/connect.lock\n/coverage\n/libpeerconnection.log\nnpm-debug.log\nyarn-error.log\ntestem.log\n/typings\n\n# System Files\n.DS_Store\nThumbs.db\n"
  },
  {
    "path": ".prettierignore",
    "content": "# Add files here to ignore them from prettier formatting\n\n/dist\n/coverage\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"singleQuote\": true\n}\n"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\n    \"angular.ng-template\",\n    \"nrwl.angular-console\",\n    \"esbenp.prettier-vscode\",\n    \"firsttris.vscode-jest-runner\",\n    \"dbaeumer.vscode-eslint\"\n  ]\n}\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at flemke.dev@gmail.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "## Contribution guidelines\n\nContributions are very welcome. Please stick to the [code of conduct](./CODE_OF_CONDUCT.md) and, if possible, follow the issue templates.\n\n\n### Commit message guidelines\n\nPlease use the following template for your commit messages.\n\n```\ntype(scope): message\n\nmessage-body\n\nBREAKING CHANGE\nCloses #4746\n```\n\nThe message body can be multiple lines without any empty lines in between. If there is a breaking change please add the `BREAKING CHANGE` note.\nIf there is a related issue to this commit, please add a line containing `Closes/Fixes/Related to #ISSUENUMBER`. The type may be\none of the following\n\n- feature (if new features are introduced)\n- fix (if a bug was fixed and no features are introduced)\n- package (for changes related to npm/travis configuration)\n- misc (anything that does not fit in the above)\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2022 Felix Lemke\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "NOTES.md",
    "content": "These are notes for the stream implementation of Nodeplotlib.\n\n## General\n\n- A plot window (**apps/web**) tries to connect to the server via a realtime api (e.g. websockets).\n- The server recognizes the count of connected apps.\n- If the user executes the `plot` function several times, it will only open a window if there is no\n  open connection to a **apps/web**.\n\n## Server lifecycle\n\n- The server starts with the execution of the `plot` function if there is no active server running.\n- The server stops if all **apps/web** are disconnected (and there were connections before).\n\n## The plot function\n\n- The plot function can either handle a `Plot` or an `Observable<Plot>`.\n  - It creates an `Observable<Plot>` by using Rxjs' `of` observable constructor.\n- The plot streams are saved in a Plots Set.\n- If there is an active **apps/web** that listens to the server, it subscribes to all Plots in the Set.\n- It does not submit a whole \"plots\" object, but rather submits all plots one by one. The reason is\n  realtime data, for which only the updated plot should be transmitted.\n- If all **apps/web** are disconnected, it should close the observable subscriptions of the plots and close\n  the server as mentioned in the **server lifecycle** section.\n\n## The stack function\n\n- Is the `stack` function really needed? Stack served the purpose that only one window opens which\n  could display several plots.\n\n## The clear function\n\n- The `clear` function is also probably not needed. Just close all windows and it should close the\n  subscriptions to the plots and streams.\n\n## Backlog\n\n- The user can remove plots from the frontend. If that happened it submits a message to the\n  backend so that the subscription can be cancelled and the plot stream can be removed from the plots set.\n\n## Frontend only\n\n- The user has the possibility to rearrange plots per drag and drop.\n- The user can resize the individual plot windows.\n\n## Development\n\nTo start the app for development purposes run\n\n```\nnpm run build web -- --watch\nnpm start dev-server\n```\n"
  },
  {
    "path": "README.md",
    "content": "# <img src=\"./img/nodeplotlib_64x64.png\" width=\"22px\" height=\"22px\"> NodePlotLib\n\n[![NodeJS CI](https://github.com/ngfelixl/nodeplotlib/workflows/Node.js%20CI/badge.svg)](https://github.com/ngfelixl/nodeplotlib/actions?query=workflow%3A%22Node.js+CI%22)\n[![npm](https://img.shields.io/npm/v/nodeplotlib?color=#00f800)](https://npmjs.com/package/nodeplotlib)\n[![npm](https://img.shields.io/npm/dt/nodeplotlib.svg)](https://npmjs.com/package/nodeplotlib)\n[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n\n[![Animation (View on Github)](https://raw.githubusercontent.com/ngfelixl/nodeplotlib/master/img/animation-next.gif)](https://raw.githubusercontent.com/ngfelixl/nodeplotlib/master/img/animation-next.gif)\n\nThis readme contains all the necessary information for the development.\n\n## [Go to the user docs](./libs/nodeplotlib/README.md)\n\n## Installation\n\n### Npmjs\n\n```sh\nnpm install nodeplotlib\n# or\nyarn add nodeplotlib\n```\n\n### Repository\n\nCreate a fork of this repository. Then clone it\n\n```\ngit clone https://github.com/{{USERNAME}}/nodeplotlib\ncd nodeplotlib\nnpm i\n```\n\n## Serving the app for development\n\nServing in development mode prevents the app to open a new browser window on changes.\nYou can open the app at the specified port, e.g. `http://localhost:4201`.\n\n```\nnpx nx run web:build -- --watch\n\nNODEPLOTLIB_PORT=4201 npx nx run dev-server:serve\n// or on Windows cmd\nset \"NODEPLOTLIB_PORT=4201\" && npx nx run dev-server:serve\n// or on Windows Powershell\n$env:NODEPLOTLIB_PORT = \"4201\" ; npx nx run dev-server:serve\n```\n\n## Build for production\n\nTo build for production three steps are necessary. Build the web app, build\nthe library, and finally copy the web app files to the libraries dist folder.\nAll steps are bundled in the following script:\n\n```\nnpm run build:prod\n```\n\nAll dist files are located in **/dist/libs/nodeplotlib**\n\n## Release Guide\n\nThis is a note for maintainers only. There are several steps to follow before you\ncan publish the new version to npm.\n\n1. Bump the version number using semver. Use \"rc\" for release candidates as the _preid_, e.g.\n   `1.0.0-rc1`. Update the version number in the root [package.json](./package.json)\n   and in the libs [package.json](./libs/nodeplotlib/package.json).\n2. If everything is committed and in place on \"master\" for non-release candidates,\n   or on \"release/...\" for release candidates. Create a tag with that version number,\n   e.g. `v1.0.0-rc1` or `v1.0.1`, and push it to the repository.\n3. Run `npm run build:prod`\n4. Navigate to **/dist/libs/nodeplotlib**\n5. Run `npm pack`\n6. Make sure to be logged in to npmjs. Then run\n   - `npm publish {{filename}}.tgz` or\n   - `npm publish {{filename}}.tgz --tag test` for release candidates.\n7. Create a release on Github for non-release cadidate versions.\n\n## Behind the scenes\n\nThe lib launches a webserver and opens new tabs for every plot located at\n`http://localhost:{{PORT}}`, where `PORT` is a free port determined by the express\nserver itself. At this address the Angular application will be served temporarily.\nThe server and the app set up a connection via socket.io. This way a realtime\ntransmission is possible.\n\n## Contributing\n\nContributions in all forms are welcome.\n\n## Contributors\n\n<a href=\"https://github.com/ngfelixl\"><img src=\"https://avatars2.githubusercontent.com/u/24190530\" title=\"ngfelixl\" width=\"100\" height=\"100\"></a>\n<a href=\"https://github.com/mitsos1os\"><img src=\"https://avatars3.githubusercontent.com/u/8208733\" title=\"mitsos1os\" width=\"100\" height=\"100\"></a>\n<a href=\"https://github.com/medved-nsk\"><img src=\"https://avatars1.githubusercontent.com/u/6310906\" title=\"medved-nsk\" width=\"100\" height=\"100\"></a>\n<a href=\"https://github.com/Moumouls\"><img src=\"https://avatars.githubusercontent.com/u/27959372\" title=\"Moumouls\" width=\"100\" height=\"100\"></a>\n<a href=\"https://github.com/grgr-dkrk\"><img src=\"https://avatars.githubusercontent.com/u/40130327\" title=\"guruguru-dekiruko\" width=\"100\" height=\"100\"></a>\n"
  },
  {
    "path": "angular.json",
    "content": "{\n  \"$schema\": \"./node_modules/nx/schemas/workspace-schema.json\",\n  \"version\": 2,\n  \"projects\": {\n    \"dev-server\": \"apps/dev-server\",\n    \"nodeplotlib\": \"libs/nodeplotlib\",\n    \"web\": \"apps/web\",\n    \"web-e2e\": \"apps/web-e2e\"\n  }\n}\n"
  },
  {
    "path": "apps/.gitkeep",
    "content": ""
  },
  {
    "path": "apps/dev-server/.eslintrc.json",
    "content": "{\n  \"extends\": [\"../../.eslintrc.json\"],\n  \"ignorePatterns\": [\"!**/*\"],\n  \"overrides\": [\n    {\n      \"files\": [\"*.ts\", \"*.tsx\", \"*.js\", \"*.jsx\"],\n      \"rules\": {}\n    },\n    {\n      \"files\": [\"*.ts\", \"*.tsx\"],\n      \"rules\": {}\n    },\n    {\n      \"files\": [\"*.js\", \"*.jsx\"],\n      \"rules\": {}\n    }\n  ]\n}\n"
  },
  {
    "path": "apps/dev-server/jest.config.ts",
    "content": "/* eslint-disable */\nexport default {\n  displayName: 'dev-server',\n  preset: '../../jest.preset.js',\n  globals: {\n    'ts-jest': {\n      tsconfig: '<rootDir>/tsconfig.spec.json',\n    },\n  },\n  testEnvironment: 'node',\n  transform: {\n    '^.+\\\\.[tj]s$': 'ts-jest',\n  },\n  moduleFileExtensions: ['ts', 'js', 'html'],\n  coverageDirectory: '../../coverage/apps/dev-server',\n};\n"
  },
  {
    "path": "apps/dev-server/project.json",
    "content": "{\n  \"$schema\": \"../../node_modules/nx/schemas/project-schema.json\",\n  \"sourceRoot\": \"apps/dev-server/src\",\n  \"projectType\": \"application\",\n  \"architect\": {\n    \"build\": {\n      \"executor\": \"@nrwl/node:webpack\",\n      \"outputs\": [\"{options.outputPath}\"],\n      \"options\": {\n        \"outputPath\": \"dist/apps/dev-server\",\n        \"main\": \"apps/dev-server/src/main.ts\",\n        \"tsConfig\": \"apps/dev-server/tsconfig.app.json\",\n        \"assets\": [\n          \"apps/dev-server/src/assets\",\n          {\n            \"glob\": \"**/*\",\n            \"input\": \"dist/apps/web\",\n            \"output\": \"web\"\n          }\n        ]\n      },\n      \"configurations\": {\n        \"production\": {\n          \"optimization\": true,\n          \"extractLicenses\": true,\n          \"inspect\": false,\n          \"fileReplacements\": [\n            {\n              \"replace\": \"apps/dev-server/src/environments/environment.ts\",\n              \"with\": \"apps/dev-server/src/environments/environment.prod.ts\"\n            }\n          ]\n        }\n      }\n    },\n    \"serve\": {\n      \"executor\": \"@nrwl/node:node\",\n      \"options\": {\n        \"buildTarget\": \"dev-server:build\"\n      }\n    },\n    \"lint\": {\n      \"executor\": \"@nrwl/linter:eslint\",\n      \"outputs\": [\"{options.outputFile}\"],\n      \"options\": {\n        \"lintFilePatterns\": [\"apps/dev-server/**/*.ts\"]\n      }\n    },\n    \"test\": {\n      \"executor\": \"@nrwl/jest:jest\",\n      \"outputs\": [\"coverage/apps/dev-server\"],\n      \"options\": {\n        \"jestConfig\": \"apps/dev-server/jest.config.ts\",\n        \"passWithNoTests\": true\n      }\n    }\n  },\n  \"implicitDependencies\": [\"web\"]\n}\n"
  },
  {
    "path": "apps/dev-server/src/assets/.gitkeep",
    "content": ""
  },
  {
    "path": "apps/dev-server/src/data/2d-histogram.ts",
    "content": "import { Layout, Plot } from '@npl/nodeplotlib';\n\nfunction normal() {\n  let x = 0,\n    y = 0,\n    rds;\n  do {\n    x = Math.random() * 2 - 1;\n    y = Math.random() * 2 - 1;\n    rds = x * x + y * y;\n  } while (rds == 0 || rds > 1);\n  const c = Math.sqrt((-2 * Math.log(rds)) / rds); // Box-Muller transform\n  return x * c; // throw away extra sample y * c\n}\n\nconst N = 2000;\nconst a = -1;\nconst b = 1.2;\n\nconst step = (b - a) / (N - 1);\nconst t = new Array(N),\n  x = new Array(N),\n  y = new Array(N);\n\nfor (let i = 0; i < N; i++) {\n  t[i] = a + step * i;\n  x[i] = Math.pow(t[i], 3) + 0.3 * normal();\n  y[i] = Math.pow(t[i], 6) + 0.3 * normal();\n}\n\nconst trace1: Plot = {\n  x: x,\n  y: y,\n  mode: 'markers',\n  name: 'points',\n  marker: {\n    color: 'rgb(102,0,0)',\n    size: 2,\n    opacity: 0.4,\n  },\n  type: 'scatter',\n};\nconst trace2: Plot = {\n  x: x,\n  y: y,\n  name: 'density',\n  ncontours: 20,\n  colorscale: 'Hot',\n  reversescale: true,\n  showscale: false,\n  type: 'histogram2dcontour',\n} as Plot;\nconst trace3: Plot = {\n  x: x,\n  name: 'x density',\n  marker: { color: 'rgb(102,0,0)' },\n  yaxis: 'y2',\n  type: 'histogram',\n};\nconst trace4: Plot = {\n  y: y,\n  name: 'y density',\n  marker: { color: 'rgb(102,0,0)' },\n  xaxis: 'x2',\n  type: 'histogram',\n};\nexport const data = [trace1, trace2, trace3, trace4];\nexport const layout: Layout = {\n  showlegend: false,\n  autosize: false,\n  width: 600,\n  height: 550,\n  margin: { t: 50 },\n  hovermode: 'closest',\n  bargap: 0,\n  xaxis: {\n    domain: [0, 0.85],\n    showgrid: false,\n    zeroline: false,\n  },\n  yaxis: {\n    domain: [0, 0.85],\n    showgrid: false,\n    zeroline: false,\n  },\n  xaxis2: {\n    domain: [0.85, 1],\n    showgrid: false,\n    zeroline: false,\n  },\n  yaxis2: {\n    domain: [0.85, 1],\n    showgrid: false,\n    zeroline: false,\n  },\n};\n"
  },
  {
    "path": "apps/dev-server/src/data/bar.ts",
    "content": "import { Plot } from '@npl/nodeplotlib';\n\nexport const data: Plot[] = [\n  {\n    type: 'bar',\n    x: [20, 14, 23],\n    y: ['giraffes', 'orangutans', 'monkeys'],\n    orientation: 'h',\n  },\n];\n"
  },
  {
    "path": "apps/dev-server/src/data/candlestick.ts",
    "content": "import { Plot } from '@npl/nodeplotlib';\n\nconst trace1 = {\n  x: [\n    '2017-01-04',\n    '2017-01-05',\n    '2017-01-06',\n    '2017-01-09',\n    '2017-01-10',\n    '2017-01-11',\n    '2017-01-12',\n    '2017-01-13',\n    '2017-01-17',\n    '2017-01-18',\n    '2017-01-19',\n    '2017-01-20',\n    '2017-01-23',\n    '2017-01-24',\n    '2017-01-25',\n    '2017-01-26',\n    '2017-01-27',\n    '2017-01-30',\n    '2017-01-31',\n    '2017-02-01',\n    '2017-02-02',\n    '2017-02-03',\n    '2017-02-06',\n    '2017-02-07',\n    '2017-02-08',\n    '2017-02-09',\n    '2017-02-10',\n    '2017-02-13',\n    '2017-02-14',\n    '2017-02-15',\n  ],\n  close: [\n    116.019997, 116.610001, 117.910004, 118.989998, 119.110001, 119.75, 119.25,\n    119.040001, 120, 119.989998, 119.779999, 120, 120.080002, 119.970001,\n    121.879997, 121.940002, 121.949997, 121.629997, 121.349998, 128.75,\n    128.529999, 129.080002, 130.289993, 131.529999, 132.039993, 132.419998,\n    132.119995, 133.289993, 135.020004, 135.509995,\n  ],\n  decreasing: { line: { color: '#7F7F7F' } },\n  high: [\n    116.510002, 116.860001, 118.160004, 119.43, 119.379997, 119.93, 119.300003,\n    119.620003, 120.239998, 120.5, 120.089996, 120.449997, 120.809998,\n    120.099998, 122.099998, 122.440002, 122.349998, 121.629997, 121.389999,\n    130.490005, 129.389999, 129.190002, 130.5, 132.089996, 132.220001,\n    132.449997, 132.940002, 133.820007, 135.089996, 136.270004,\n  ],\n  increasing: { line: { color: '#17BECF' } },\n  line: { color: 'rgba(31,119,180,1)' },\n  low: [\n    115.75, 115.809998, 116.470001, 117.940002, 118.300003, 118.599998,\n    118.209999, 118.809998, 118.220001, 119.709999, 119.370003, 119.730003,\n    119.769997, 119.5, 120.279999, 121.599998, 121.599998, 120.660004,\n    120.620003, 127.010002, 127.779999, 128.160004, 128.899994, 130.449997,\n    131.220001, 131.119995, 132.050003, 132.75, 133.25, 134.619995,\n  ],\n  open: [\n    115.849998, 115.919998, 116.779999, 117.949997, 118.769997, 118.739998,\n    118.900002, 119.110001, 118.339996, 120, 119.400002, 120.449997, 120,\n    119.550003, 120.419998, 121.669998, 122.139999, 120.93, 121.150002,\n    127.029999, 127.980003, 128.309998, 129.130005, 130.539993, 131.350006,\n    131.649994, 132.460007, 133.080002, 133.470001, 135.520004,\n  ],\n  type: 'candlestick',\n  xaxis: 'x',\n  yaxis: 'y',\n} as Plot;\n\nexport const data = [trace1];\n\nexport const layout = {\n  dragmode: 'zoom',\n  margin: {\n    r: 10,\n    t: 25,\n    b: 40,\n    l: 60,\n  },\n  showlegend: false,\n  xaxis: {\n    autorange: true,\n    domain: [0, 1],\n    range: ['2017-01-03 12:00', '2017-02-15 12:00'],\n    rangeslider: { range: ['2017-01-03 12:00', '2017-02-15 12:00'] },\n    title: 'Date',\n    type: 'date',\n  },\n  yaxis: {\n    autorange: true,\n    domain: [0, 1],\n    range: [114.609999778, 137.410004222],\n    type: 'linear',\n  },\n};\n"
  },
  {
    "path": "apps/dev-server/src/data/line-stream.ts",
    "content": "import { Plot } from '@npl/nodeplotlib';\nimport { interval, Observable, map } from 'rxjs';\n\nexport const stream$: Observable<Plot[]> = interval(100).pipe(\n  map((index) => {\n    const data: Plot = {\n      x: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n      y: Array(10)\n        .fill(0)\n        .map((_, i) => Math.sin(index + i)),\n      type: 'scatter',\n    };\n    return [data];\n  })\n);\n"
  },
  {
    "path": "apps/dev-server/src/data/sankey.ts",
    "content": "import { Plot } from '@npl/nodeplotlib';\n\nexport const data = [\n  {\n    type: 'sankey',\n    orientation: 'h',\n    node: {\n      pad: 15,\n      thickness: 30,\n      line: {\n        color: 'black',\n        width: 0.5,\n      },\n      label: ['A1', 'A2', 'B1', 'B2', 'C1', 'C2'],\n      color: ['blue', 'blue', 'blue', 'blue', 'blue', 'blue'],\n    },\n\n    link: {\n      source: [0, 1, 0, 2, 3, 3],\n      target: [2, 3, 3, 4, 4, 5],\n      value: [8, 4, 2, 8, 4, 2],\n    },\n  } as Plot,\n];\n\nexport const layout = {\n  title: 'Basic Sankey',\n  font: {\n    size: 10,\n  },\n};\n"
  },
  {
    "path": "apps/dev-server/src/data/scatter.ts",
    "content": "import { Plot } from '@npl/nodeplotlib';\n\nconst trace1: Plot = {\n  x: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n  y: [1, 2, 1, 2, 1, 2, 1, 2, 1, 2],\n  type: 'scatter',\n};\nexport const data = [trace1];\nexport const layout = {};\n"
  },
  {
    "path": "apps/dev-server/src/data/table.ts",
    "content": "import { Plot } from '@npl/nodeplotlib';\n\nconst values = [\n  ['Salaries', 'Office', 'Merchandise', 'Legal', '<b>TOTAL</b>'],\n  [1200000, 20000, 80000, 2000, 12120000],\n  [1300000, 20000, 70000, 2000, 130902000],\n  [1300000, 20000, 120000, 2000, 131222000],\n  [1400000, 20000, 90000, 2000, 14102000],\n];\n\nconst headerColor = 'grey';\nconst rowEvenColor = 'lightgrey';\nconst rowOddColor = 'white';\n\nexport const data = [\n  {\n    type: 'table',\n    header: {\n      values: [\n        ['<b>EXPENSES</b>'],\n        ['<b>Q1</b>'],\n        ['<b>Q2</b>'],\n        ['<b>Q3</b>'],\n        ['<b>Q4</b>'],\n      ],\n      align: 'center',\n      line: { width: 1, color: 'black' },\n      fill: { color: headerColor },\n      font: { family: 'Arial', size: 12, color: 'white' },\n    },\n    cells: {\n      values: values,\n      align: 'center',\n      line: { color: 'black', width: 1 },\n      fill: {\n        color: [\n          [rowOddColor, rowEvenColor, rowOddColor, rowEvenColor, rowOddColor],\n        ],\n      },\n      font: { family: 'Arial', size: 11, color: ['black'] },\n    },\n  } as Plot,\n];\n"
  },
  {
    "path": "apps/dev-server/src/environments/environment.prod.ts",
    "content": "export const environment = {\n  production: true,\n};\n"
  },
  {
    "path": "apps/dev-server/src/environments/environment.ts",
    "content": "export const environment = {\n  production: false,\n};\n"
  },
  {
    "path": "apps/dev-server/src/main.ts",
    "content": "/**\n * This is not a production server yet!\n * This is only a minimal backend to get started.\n */\n\nimport { plot } from '@npl/nodeplotlib';\nimport {\n  data as histogram,\n  layout as histogramLayout,\n} from './data/2d-histogram';\nimport { data as bar } from './data/bar';\nimport { stream$ } from './data/line-stream';\nimport { data as sankey, layout as sankeyLayout } from './data/sankey';\nimport { data as scatter, layout as scatterPlotLayout } from './data/scatter';\nimport { data as table } from './data/table';\n\nplot(stream$);\nplot(scatter, scatterPlotLayout);\nplot(bar);\nplot(sankey, sankeyLayout);\nplot(histogram, histogramLayout);\nplot(table);\n"
  },
  {
    "path": "apps/dev-server/tsconfig.app.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../dist/out-tsc\",\n    \"module\": \"commonjs\",\n    \"types\": [\"node\"],\n    \"emitDecoratorMetadata\": true,\n    \"target\": \"es2015\"\n  },\n  \"exclude\": [\"**/*.spec.ts\", \"**/*.test.ts\"],\n  \"include\": [\"**/*.ts\"]\n}\n"
  },
  {
    "path": "apps/dev-server/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.base.json\",\n  \"files\": [],\n  \"include\": [],\n  \"references\": [\n    {\n      \"path\": \"./tsconfig.app.json\"\n    },\n    {\n      \"path\": \"./tsconfig.spec.json\"\n    }\n  ]\n}\n"
  },
  {
    "path": "apps/dev-server/tsconfig.spec.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../dist/out-tsc\",\n    \"module\": \"commonjs\",\n    \"types\": [\"jest\", \"node\"]\n  },\n  \"include\": [\"**/*.spec.ts\", \"**/*.test.ts\", \"**/*.d.ts\"]\n}\n"
  },
  {
    "path": "apps/web/.browserslistrc",
    "content": "# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.\n# For additional information regarding the format and rule options, please see:\n# https://github.com/browserslist/browserslist#queries\n\n# For the full list of supported browsers by the Angular framework, please see:\n# https://angular.io/guide/browser-support\n\n# You can see what browsers were selected by your queries by running:\n#   npx browserslist\n\nlast 1 Chrome version\nlast 1 Firefox version\nlast 2 Edge major versions\nlast 2 Safari major versions\nlast 2 iOS major versions\nFirefox ESR\nnot IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.\n"
  },
  {
    "path": "apps/web/.eslintrc.json",
    "content": "{\n  \"extends\": [\"../../.eslintrc.json\"],\n  \"ignorePatterns\": [\"!**/*\"],\n  \"overrides\": [\n    {\n      \"files\": [\"*.ts\"],\n      \"extends\": [\n        \"plugin:@nrwl/nx/angular\",\n        \"plugin:@angular-eslint/template/process-inline-templates\"\n      ],\n      \"rules\": {\n        \"@angular-eslint/directive-selector\": [\n          \"error\",\n          {\n            \"type\": \"attribute\",\n            \"prefix\": \"npl\",\n            \"style\": \"camelCase\"\n          }\n        ],\n        \"@angular-eslint/component-selector\": [\n          \"error\",\n          {\n            \"type\": \"element\",\n            \"prefix\": \"npl\",\n            \"style\": \"kebab-case\"\n          }\n        ]\n      }\n    },\n    {\n      \"files\": [\"*.html\"],\n      \"extends\": [\"plugin:@nrwl/nx/angular-template\"],\n      \"rules\": {}\n    }\n  ]\n}\n"
  },
  {
    "path": "apps/web/jest.config.ts",
    "content": "/* eslint-disable */\nexport default {\n  displayName: 'web',\n  preset: '../../jest.preset.js',\n  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],\n  globals: {\n    'ts-jest': {\n      tsconfig: '<rootDir>/tsconfig.spec.json',\n      stringifyContentPathRegex: '\\\\.(html|svg)$',\n    },\n  },\n  coverageDirectory: '../../coverage/apps/web',\n  transform: {\n    '^.+\\\\.(ts|mjs|js|html)$': 'jest-preset-angular',\n  },\n  transformIgnorePatterns: ['node_modules/(?!.*\\\\.mjs$)'],\n  snapshotSerializers: [\n    'jest-preset-angular/build/serializers/no-ng-attributes',\n    'jest-preset-angular/build/serializers/ng-snapshot',\n    'jest-preset-angular/build/serializers/html-comment',\n  ],\n};\n"
  },
  {
    "path": "apps/web/project.json",
    "content": "{\n  \"$schema\": \"../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"application\",\n  \"sourceRoot\": \"apps/web/src\",\n  \"prefix\": \"npl\",\n  \"targets\": {\n    \"build\": {\n      \"executor\": \"@angular-devkit/build-angular:browser\",\n      \"outputs\": [\"{options.outputPath}\"],\n      \"options\": {\n        \"outputPath\": \"dist/apps/web\",\n        \"index\": \"apps/web/src/index.html\",\n        \"main\": \"apps/web/src/main.ts\",\n        \"polyfills\": \"apps/web/src/polyfills.ts\",\n        \"tsConfig\": \"apps/web/tsconfig.app.json\",\n        \"assets\": [\"apps/web/src/favicon.ico\", \"apps/web/src/assets\"],\n        \"styles\": [\"apps/web/src/custom-theme.scss\", \"apps/web/src/styles.css\"],\n        \"scripts\": []\n      },\n      \"configurations\": {\n        \"production\": {\n          \"budgets\": [\n            {\n              \"type\": \"initial\",\n              \"maximumWarning\": \"500kb\",\n              \"maximumError\": \"1mb\"\n            },\n            {\n              \"type\": \"anyComponentStyle\",\n              \"maximumWarning\": \"2kb\",\n              \"maximumError\": \"4kb\"\n            }\n          ],\n          \"fileReplacements\": [\n            {\n              \"replace\": \"apps/web/src/environments/environment.ts\",\n              \"with\": \"apps/web/src/environments/environment.prod.ts\"\n            }\n          ],\n          \"outputHashing\": \"none\"\n        },\n        \"development\": {\n          \"buildOptimizer\": false,\n          \"optimization\": false,\n          \"vendorChunk\": true,\n          \"extractLicenses\": false,\n          \"sourceMap\": true,\n          \"namedChunks\": true\n        }\n      },\n      \"defaultConfiguration\": \"production\"\n    },\n    \"serve\": {\n      \"executor\": \"@angular-devkit/build-angular:dev-server\",\n      \"configurations\": {\n        \"production\": {\n          \"browserTarget\": \"web:build:production\"\n        },\n        \"development\": {\n          \"browserTarget\": \"web:build:development\"\n        }\n      },\n      \"defaultConfiguration\": \"development\"\n    },\n    \"extract-i18n\": {\n      \"executor\": \"@angular-devkit/build-angular:extract-i18n\",\n      \"options\": {\n        \"browserTarget\": \"web:build\"\n      }\n    },\n    \"lint\": {\n      \"executor\": \"@nrwl/linter:eslint\",\n      \"options\": {\n        \"lintFilePatterns\": [\"apps/web/src/**/*.ts\", \"apps/web/src/**/*.html\"]\n      }\n    },\n    \"test\": {\n      \"executor\": \"@nrwl/jest:jest\",\n      \"outputs\": [\"coverage/apps/web\"],\n      \"options\": {\n        \"jestConfig\": \"apps/web/jest.config.ts\",\n        \"passWithNoTests\": true\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "apps/web/src/app/app-routing.module.ts",
    "content": "import { NgModule } from '@angular/core';\nimport {\n  ActivatedRouteSnapshot,\n  BaseRouteReuseStrategy,\n  DetachedRouteHandle,\n  Route,\n  RouteReuseStrategy,\n  RouterModule,\n} from '@angular/router';\nimport { PlotsComponent } from './components/plots/plots.component';\nimport { TutorialComponent } from './components/tutorial/tutorial.component';\n\nconst routes: Route[] = [\n  { path: 'plots', component: PlotsComponent },\n  { path: 'tutorial', component: TutorialComponent },\n  { path: '**', redirectTo: 'plots' },\n];\n\n@NgModule({\n  imports: [RouterModule.forRoot(routes)],\n  exports: [RouterModule],\n})\nexport class AppRoutingModule {}\n\nexport class AppRoutesReuseStrategy implements RouteReuseStrategy {\n  private cache: { [key: string]: DetachedRouteHandle } = {};\n\n  shouldDetach(route: ActivatedRouteSnapshot): boolean {\n    return true;\n  }\n\n  store(route: ActivatedRouteSnapshot, handler: DetachedRouteHandle): void {\n    if (handler) {\n      this.cache[this.getUrl(route)] = handler;\n    }\n  }\n\n  shouldAttach(route: ActivatedRouteSnapshot): boolean {\n    return !!this.cache[this.getUrl(route)];\n  }\n\n  shouldReuseRoute(\n    future: ActivatedRouteSnapshot,\n    current: ActivatedRouteSnapshot\n  ): boolean {\n    return future.routeConfig === current.routeConfig;\n  }\n\n  retrieve(route: ActivatedRouteSnapshot) {\n    if (!route.routeConfig || route.routeConfig.loadChildren) {\n      return null;\n    }\n    return this.cache[this.getUrl(route)];\n  }\n\n  private getUrl(route: ActivatedRouteSnapshot): string {\n    return route.routeConfig?.path ?? '';\n  }\n}\n"
  },
  {
    "path": "apps/web/src/app/app.module.ts",
    "content": "import { HttpClientModule } from '@angular/common/http';\nimport { NgModule } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatToolbarModule } from '@angular/material/toolbar';\nimport { BrowserModule } from '@angular/platform-browser';\nimport { BrowserAnimationsModule } from '@angular/platform-browser/animations';\nimport { AppRoutesReuseStrategy, AppRoutingModule } from './app-routing.module';\nimport { AppComponent } from './components/app/app.component';\nimport { TutorialComponent } from './components/tutorial/tutorial.component';\nimport { MatSidenavModule } from '@angular/material/sidenav';\nimport { MatListModule } from '@angular/material/list';\nimport { PlotComponent } from './components/plot/plot.component';\nimport { PlotsComponent } from './components/plots/plots.component';\nimport { DragDropModule } from '@angular/cdk/drag-drop';\nimport { MatCardModule } from '@angular/material/card';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatTooltipModule } from '@angular/material/tooltip';\nimport { RouteReuseStrategy } from '@angular/router';\n\n@NgModule({\n  declarations: [\n    AppComponent,\n    TutorialComponent,\n    PlotComponent,\n    PlotsComponent,\n  ],\n  imports: [\n    AppRoutingModule,\n    BrowserAnimationsModule,\n    BrowserModule,\n    MatButtonModule,\n    MatToolbarModule,\n    HttpClientModule,\n    MatSidenavModule,\n    MatListModule,\n    DragDropModule,\n    MatCardModule,\n    MatIconModule,\n    MatTooltipModule,\n  ],\n  providers: [\n    { provide: RouteReuseStrategy, useClass: AppRoutesReuseStrategy },\n  ],\n  bootstrap: [AppComponent],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "apps/web/src/app/components/app/app.component.css",
    "content": ":host {\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  display: flex;\n  flex-direction: column;\n  justify-content: stretch;\n  align-items: stretch;\n}\n\nmain {\n  flex: 1 1 0;\n  display: flex;\n  flex-direction: column;\n  align-items: stretch;\n  justify-content: stretch;\n}\n\nmat-toolbar {\n  flex: 0 0 auto;\n  justify-content: space-between;\n}\n\n.info-icons {\n  display: flex;\n  gap: 8px;\n}\n\n.info-icons img {\n  width: 24px;\n  height: 24px;\n}\n\n.green {\n  color: #00ff2a;\n}\n"
  },
  {
    "path": "apps/web/src/app/components/app/app.component.html",
    "content": "<mat-toolbar color=\"primary\" class=\"mat-elevation-z4\">\n  <span class=\"brand\" routerLink=\"/\">\n    <button mat-button>\n      <img\n        src=\"./assets/nodeplotlib_64x64_transparent.png\"\n        alt=\"NodePlotLib Brand Icon\"\n        height=\"32px\"\n        width=\"32px\"\n      />\n      <span>\n        <span class=\"green\">N</span>ode<span class=\"green\">P</span>lot<span\n          class=\"green\"\n          >L</span\n        >ib\n      </span>\n    </button>\n  </span>\n  <span class=\"info-icons\">\n    <button mat-icon-button routerLink=\"tutorial\" matTooltip=\"Tutorial\">\n      <mat-icon>tips_and_updates</mat-icon>\n    </button>\n    <a href=\"https://plotly.com/javascript/\" target=\"_blank\" rel=\"noreferrer\"\n      ><button mat-icon-button matTooltip=\"Plotly.js Documentation\">\n        <img src=\"/assets/plotly.svg\" alt=\"Plotly.js Icon\" /></button\n    ></a>\n    <a\n      href=\"https://github.com/ngfelixl/nodeplotlib\"\n      target=\"_blank\"\n      rel=\"noreferrer\"\n      ><button mat-icon-button>\n        <img src=\"/assets/github-light-32px.png\" alt=\"Github Icon\" /></button\n    ></a>\n  </span>\n</mat-toolbar>\n<main>\n  <router-outlet></router-outlet>\n</main>\n"
  },
  {
    "path": "apps/web/src/app/components/app/app.component.spec.ts",
    "content": "import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { SocketService } from '../../services/socket.service';\nimport { AppComponent } from './app.component';\n\ndescribe('AppComponent', () => {\n  let fixture: ComponentFixture<AppComponent>;\n\n  beforeEach(() => {\n    TestBed.configureTestingModule({\n      declarations: [AppComponent],\n      imports: [],\n      providers: [{ provide: SocketService, useValue: {} }],\n      schemas: [CUSTOM_ELEMENTS_SCHEMA],\n    }).compileComponents();\n\n    fixture = TestBed.createComponent(AppComponent);\n  });\n\n  it('should create', () => {\n    expect(fixture).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "apps/web/src/app/components/app/app.component.ts",
    "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\nimport { SocketService } from '../../services/socket.service';\n\n@Component({\n  selector: 'npl-root',\n  templateUrl: './app.component.html',\n  styleUrls: ['./app.component.css'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AppComponent {\n  constructor(private socketService: SocketService) {}\n}\n"
  },
  {
    "path": "apps/web/src/app/components/plot/plot.component.css",
    "content": ""
  },
  {
    "path": "apps/web/src/app/components/plot/plot.component.html",
    "content": "<div #plotContainer></div>\n"
  },
  {
    "path": "apps/web/src/app/components/plot/plot.component.ts",
    "content": "import {\n  AfterViewInit,\n  ChangeDetectionStrategy,\n  Component,\n  ElementRef,\n  Input,\n  OnChanges,\n  SimpleChanges,\n  ViewChild,\n} from '@angular/core';\nimport { PlotData } from '@npl/nodeplotlib';\n\n// eslint-disable-next-line\ndeclare const Plotly: any;\n\n@Component({\n  selector: 'npl-plot',\n  templateUrl: './plot.component.html',\n  styleUrls: ['./plot.component.css'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class PlotComponent implements AfterViewInit, OnChanges {\n  @Input() plotData!: PlotData;\n  @ViewChild('plotContainer', { static: false }) plotContainer!: ElementRef;\n\n  ngAfterViewInit() {\n    Plotly.newPlot(\n      this.plotContainer.nativeElement,\n      this.plotData.data,\n      { ...(this.plotData.layout ?? {}), autosize: true },\n      { ...(this.plotData.config ?? {}), responsive: true }\n    );\n  }\n\n  ngOnChanges(simpleChanges: SimpleChanges) {\n    if (simpleChanges.plotData) {\n      Plotly.react(\n        this.plotContainer.nativeElement,\n        this.plotData.data,\n        { ...(this.plotData.layout ?? {}), autosize: true },\n        { ...(this.plotData.config ?? {}), responsive: true }\n      );\n    }\n  }\n}\n"
  },
  {
    "path": "apps/web/src/app/components/plots/plots.component.css",
    "content": ":host {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(500px, 1fr));\n  grid-gap: 8px;\n  margin: 12px;\n  grid-template-rows: auto;\n}\n"
  },
  {
    "path": "apps/web/src/app/components/plots/plots.component.html",
    "content": "<mat-card *ngFor=\"let plot of plots$ | async; trackBy: trackById\">\n  <npl-plot [plotData]=\"plot\"></npl-plot>\n</mat-card>\n"
  },
  {
    "path": "apps/web/src/app/components/plots/plots.component.spec.ts",
    "content": "import { Component, CUSTOM_ELEMENTS_SCHEMA, Input } from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport { By } from '@angular/platform-browser';\nimport { PlotData } from '@npl/nodeplotlib';\nimport { Subject } from 'rxjs';\nimport { PlotsService } from '../../services/plots.service';\nimport { PlotsComponent } from './plots.component';\n\nconst PLOTS: PlotData[] = [\n  {\n    id: 1,\n    data: [{ x: [1, 2, 3], y: [2, 3, 4] }],\n    layout: {\n      title: 'Test Plot 1',\n    },\n  },\n  {\n    id: 2,\n    data: [{ x: [1, 2, 3], y: [2, 3, 4] }],\n    layout: {\n      title: 'Test Plot 2',\n    },\n  },\n];\n\n@Component({\n  selector: 'npl-plot',\n  template: '',\n})\nexport class PlotComponent {\n  @Input() plotData!: PlotData;\n}\n\ndescribe('PlotsComponent', () => {\n  let component: PlotsComponent;\n  let fixture: ComponentFixture<PlotsComponent>;\n  let plotsServiceMock: PlotsService;\n  let plots$: Subject<PlotData[]>;\n\n  beforeEach(async () => {\n    plots$ = new Subject();\n    plotsServiceMock = {\n      plots$,\n    } as unknown as PlotsService;\n\n    await TestBed.configureTestingModule({\n      declarations: [PlotsComponent, PlotComponent],\n      providers: [{ provide: PlotsService, useValue: plotsServiceMock }],\n      schemas: [CUSTOM_ELEMENTS_SCHEMA],\n    }).compileComponents();\n  });\n\n  beforeEach(() => {\n    fixture = TestBed.createComponent(PlotsComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  it('should create', () => {\n    expect(component).toBeTruthy();\n  });\n\n  it('should render a empty list if there are no emitted values', () => {\n    const plots = fixture.debugElement.queryAll(By.directive(PlotComponent));\n\n    expect(plots.length).toBe(0);\n  });\n\n  it('should render a plot if there is one element', () => {\n    plots$.next([PLOTS[0]]);\n\n    fixture.detectChanges();\n\n    const plots = fixture.debugElement.queryAll(By.directive(PlotComponent));\n    expect(plots.length).toBe(1);\n  });\n\n  it('should render several plots', () => {\n    plots$.next(PLOTS);\n\n    fixture.detectChanges();\n\n    const plots = fixture.debugElement.queryAll(By.directive(PlotComponent));\n    expect(plots.length).toBe(2);\n  });\n});\n"
  },
  {
    "path": "apps/web/src/app/components/plots/plots.component.ts",
    "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\nimport { PlotData } from '@npl/nodeplotlib';\nimport { PlotsService } from '../../services/plots.service';\n\n@Component({\n  selector: 'npl-plots',\n  templateUrl: './plots.component.html',\n  styleUrls: ['./plots.component.css'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class PlotsComponent {\n  plots$ = this.plotsService.plots$;\n\n  constructor(private plotsService: PlotsService) {}\n\n  trackById(_: number, plot: PlotData) {\n    return plot.id;\n  }\n}\n"
  },
  {
    "path": "apps/web/src/app/components/tutorial/tutorial.component.css",
    "content": ":host {\n  display: block;\n  margin: 18px;\n}\n"
  },
  {
    "path": "apps/web/src/app/components/tutorial/tutorial.component.html",
    "content": "<h1>Tutorials</h1>\n\nThe tutorials sections will be tackled once the application is done. It will\ncontain the following topics:\n\n<ul>\n  <li>Basic plot commands</li>\n  <li>The Plot and the Layout interfaces</li>\n  <li>How to plot streams in realtime</li>\n</ul>\n"
  },
  {
    "path": "apps/web/src/app/components/tutorial/tutorial.component.ts",
    "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\n@Component({\n  selector: 'npl-tutorial',\n  templateUrl: './tutorial.component.html',\n  styleUrls: ['./tutorial.component.css'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class TutorialComponent {}\n"
  },
  {
    "path": "apps/web/src/app/services/plots.service.ts",
    "content": "import { Injectable } from '@angular/core';\nimport { PlotData } from '@npl/nodeplotlib';\nimport { BehaviorSubject } from 'rxjs';\nimport { map } from 'rxjs/operators';\nimport { SocketService } from './socket.service';\n\n@Injectable({ providedIn: 'root' })\nexport class PlotsService {\n  private plotDataMap$ = new BehaviorSubject<Map<number, PlotData>>(new Map());\n  plots$ = this.plotDataMap$.pipe(\n    map((plotDataMap) => Array.from(plotDataMap.values()))\n  );\n\n  constructor(private socketService: SocketService) {\n    this.socketService.listen<PlotData>('plotdata', (data) => {\n      const plots = this.plotDataMap$.value;\n      plots.set(data.id, data);\n      this.plotDataMap$.next(plots);\n    });\n    this.socketService.emit('readplots');\n  }\n}\n"
  },
  {
    "path": "apps/web/src/app/services/socket.service.ts",
    "content": "import { Injectable, OnDestroy } from '@angular/core';\nimport { io, Socket } from 'socket.io-client';\nimport { environment } from '../../environments/environment';\n\n@Injectable({ providedIn: 'root' })\nexport class SocketService implements OnDestroy {\n  private socket: Socket;\n\n  constructor() {\n    this.socket = io(environment.socketIoEndpoint, { transports: ['polling'] });\n\n    this.socket.on('connect', () => {\n      console.log('[Nodeplotlib] connected');\n    });\n\n    this.socket.on('disconnect', () => {\n      console.log('[Nodeplotlib] disconnected');\n    });\n  }\n\n  listen<T>(eventName: string, cb: (data: T) => void) {\n    return this.socket.on(eventName, cb);\n  }\n\n  emit<T>(eventName: string, data?: T) {\n    this.socket.emit(eventName, data);\n  }\n\n  ngOnDestroy() {\n    this.socket?.disconnect();\n  }\n}\n"
  },
  {
    "path": "apps/web/src/assets/.gitkeep",
    "content": ""
  },
  {
    "path": "apps/web/src/custom-theme.scss",
    "content": "// Custom Theming for Angular Material\n// For more information: https://material.angular.io/guide/theming\n@use '@angular/material' as mat;\n// Plus imports for other components in your app.\n\n// Include the common styles for Angular Material. We include this here so that you only\n// have to load a single css file for Angular Material in your app.\n// Be sure that you only ever include this mixin once!\n@include mat.core();\n\n// Define the palettes for your theme using the Material Design palettes available in palette.scss\n// (imported above). For each palette, you can optionally specify a default, lighter, and darker\n// hue. Available color palettes: https://material.io/design/color/\n$web-primary: mat.define-palette(mat.$blue-grey-palette, 900);\n$web-accent: mat.define-palette(mat.$light-green-palette, A200, A100, A400);\n\n// The warn palette is optional (defaults to red).\n$web-warn: mat.define-palette(mat.$red-palette);\n\n// Create the theme object. A theme consists of configurations for individual\n// theming systems such as \"color\" or \"typography\".\n$web-theme: mat.define-light-theme(\n  (\n    color: (\n      primary: $web-primary,\n      accent: $web-accent,\n      warn: $web-warn,\n    ),\n  )\n);\n\n// Include theme styles for core and each component used in your app.\n// Alternatively, you can import and @include the theme mixins for each component\n// that you are using.\n@include mat.all-component-themes($web-theme);\n"
  },
  {
    "path": "apps/web/src/environments/environment.prod.ts",
    "content": "export const environment = {\n  production: true,\n  socketIoEndpoint: '',\n};\n"
  },
  {
    "path": "apps/web/src/environments/environment.ts",
    "content": "// This file can be replaced during build by using the `fileReplacements` array.\n// `ng build` replaces `environment.ts` with `environment.prod.ts`.\n// The list of file replacements can be found in `angular.json`.\n\nexport const environment = {\n  production: false,\n  socketIoEndpoint: '',\n};\n\n/*\n * For easier debugging in development mode, you can import the following file\n * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.\n *\n * This import should be commented out in production mode because it will have a negative impact\n * on performance if an error is thrown.\n */\n// import 'zone.js/plugins/zone-error';  // Included with Angular CLI.\n"
  },
  {
    "path": "apps/web/src/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <base href=\"/\" />\n    <title>Nodeplotlib</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" />\n    <link\n      href=\"https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap\"\n      rel=\"stylesheet\"\n    />\n    <link\n      href=\"https://fonts.googleapis.com/icon?family=Material+Icons\"\n      rel=\"stylesheet\"\n    />\n  </head>\n  <body class=\"mat-typography\">\n    <npl-root></npl-root>\n    <script\n      type=\"text/javascript\"\n      src=\"https://cdn.plot.ly/plotly-1.58.4.min.js\"\n      defer\n    ></script>\n  </body>\n</html>\n"
  },
  {
    "path": "apps/web/src/main.ts",
    "content": "import { enableProdMode } from '@angular/core';\nimport { platformBrowserDynamic } from '@angular/platform-browser-dynamic';\n\nimport { AppModule } from './app/app.module';\nimport { environment } from './environments/environment';\n\nif (environment.production) {\n  enableProdMode();\n}\n\nplatformBrowserDynamic()\n  .bootstrapModule(AppModule)\n  .catch((err) => console.error(err));\n"
  },
  {
    "path": "apps/web/src/polyfills.ts",
    "content": "/**\n * This file includes polyfills needed by Angular and is loaded before the app.\n * You can add your own extra polyfills to this file.\n *\n * This file is divided into 2 sections:\n *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.\n *   2. Application imports. Files imported after ZoneJS that should be loaded before your main\n *      file.\n *\n * The current setup is for so-called \"evergreen\" browsers; the last versions of browsers that\n * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),\n * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.\n *\n * Learn more in https://angular.io/guide/browser-support\n */\n\n/***************************************************************************************************\n * BROWSER POLYFILLS\n */\n\n/**\n * By default, zone.js will patch all possible macroTask and DomEvents\n * user can disable parts of macroTask/DomEvents patch by setting following flags\n * because those flags need to be set before `zone.js` being loaded, and webpack\n * will put import in the top of bundle, so user need to create a separate file\n * in this directory (for example: zone-flags.ts), and put the following flags\n * into that file, and then add the following code before importing zone.js.\n * import './zone-flags';\n *\n * The flags allowed in zone-flags.ts are listed here.\n *\n * The following flags will work for all browsers.\n *\n * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame\n * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick\n * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames\n *\n *  in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js\n *  with the following flag, it will bypass `zone.js` patch for IE/Edge\n *\n *  (window as any).__Zone_enable_cross_context_check = true;\n *\n */\n\n/***************************************************************************************************\n * Zone JS is required by default for Angular itself.\n */\nimport 'zone.js'; // Included with Angular CLI.\n\n/***************************************************************************************************\n * APPLICATION IMPORTS\n */\n"
  },
  {
    "path": "apps/web/src/styles.css",
    "content": "/* You can add global styles to this file, and also import other style files */\n\nhtml,\nbody {\n  height: 100%;\n}\nbody {\n  margin: 0;\n  font-family: Roboto, 'Helvetica Neue', sans-serif;\n}\n\n.brand .mat-button-wrapper {\n  display: flex;\n  align-items: center;\n  gap: 12px;\n  font-size: 1.2em;\n}\n"
  },
  {
    "path": "apps/web/src/test-setup.ts",
    "content": "import 'jest-preset-angular/setup-jest';\n\nimport { getTestBed } from '@angular/core/testing';\nimport {\n  BrowserDynamicTestingModule,\n  platformBrowserDynamicTesting,\n} from '@angular/platform-browser-dynamic/testing';\n\ngetTestBed().resetTestEnvironment();\ngetTestBed().initTestEnvironment(\n  BrowserDynamicTestingModule,\n  platformBrowserDynamicTesting(),\n  { teardown: { destroyAfterEach: false } }\n);\n"
  },
  {
    "path": "apps/web/tsconfig.app.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../dist/out-tsc\",\n    \"types\": []\n  },\n  \"files\": [\"src/main.ts\", \"src/polyfills.ts\"],\n  \"include\": [\"src/**/*.d.ts\"]\n}\n"
  },
  {
    "path": "apps/web/tsconfig.editor.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"**/*.ts\"],\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\"]\n  }\n}\n"
  },
  {
    "path": "apps/web/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.base.json\",\n  \"files\": [],\n  \"include\": [],\n  \"references\": [\n    {\n      \"path\": \"./tsconfig.app.json\"\n    },\n    {\n      \"path\": \"./tsconfig.spec.json\"\n    },\n    {\n      \"path\": \"./tsconfig.editor.json\"\n    }\n  ],\n  \"compilerOptions\": {\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"noImplicitReturns\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"target\": \"es2020\"\n  },\n  \"angularCompilerOptions\": {\n    \"strictInjectionParameters\": true,\n    \"strictInputAccessModifiers\": true,\n    \"strictTemplates\": true\n  }\n}\n"
  },
  {
    "path": "apps/web/tsconfig.spec.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../dist/out-tsc\",\n    \"module\": \"commonjs\",\n    \"types\": [\"jest\", \"node\"]\n  },\n  \"files\": [\"src/test-setup.ts\"],\n  \"include\": [\"**/*.spec.ts\", \"**/*.test.ts\", \"**/*.d.ts\"]\n}\n"
  },
  {
    "path": "apps/web-e2e/.eslintrc.json",
    "content": "{\n  \"extends\": [\"plugin:cypress/recommended\", \"../../.eslintrc.json\"],\n  \"ignorePatterns\": [\"!**/*\"],\n  \"overrides\": [\n    {\n      \"files\": [\"*.ts\", \"*.tsx\", \"*.js\", \"*.jsx\"],\n      \"rules\": {}\n    },\n    {\n      \"files\": [\"src/plugins/index.js\"],\n      \"rules\": {\n        \"@typescript-eslint/no-var-requires\": \"off\",\n        \"no-undef\": \"off\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "apps/web-e2e/cypress.json",
    "content": "{\n  \"fileServerFolder\": \".\",\n  \"fixturesFolder\": \"./src/fixtures\",\n  \"integrationFolder\": \"./src/integration\",\n  \"modifyObstructiveCode\": false,\n  \"supportFile\": \"./src/support/index.ts\",\n  \"pluginsFile\": false,\n  \"video\": true,\n  \"videosFolder\": \"../../dist/cypress/apps/web-e2e/videos\",\n  \"screenshotsFolder\": \"../../dist/cypress/apps/web-e2e/screenshots\",\n  \"chromeWebSecurity\": false\n}\n"
  },
  {
    "path": "apps/web-e2e/project.json",
    "content": "{\n  \"$schema\": \"../../node_modules/nx/schemas/project-schema.json\",\n  \"sourceRoot\": \"apps/web-e2e/src\",\n  \"projectType\": \"application\",\n  \"architect\": {\n    \"e2e\": {\n      \"executor\": \"@nrwl/cypress:cypress\",\n      \"options\": {\n        \"cypressConfig\": \"apps/web-e2e/cypress.json\",\n        \"devServerTarget\": \"web:serve:development\",\n        \"tsConfig\": \"apps/web-e2e/tsconfig.json\"\n      },\n      \"configurations\": {\n        \"production\": {\n          \"devServerTarget\": \"web:serve:production\"\n        }\n      }\n    },\n    \"lint\": {\n      \"executor\": \"@nrwl/linter:eslint\",\n      \"outputs\": [\"{options.outputFile}\"],\n      \"options\": {\n        \"lintFilePatterns\": [\"apps/web-e2e/**/*.{js,ts}\"]\n      }\n    }\n  },\n  \"tags\": [],\n  \"implicitDependencies\": [\"web\"]\n}\n"
  },
  {
    "path": "apps/web-e2e/src/fixtures/example.json",
    "content": "{\n  \"name\": \"Using fixtures to represent data\",\n  \"email\": \"hello@cypress.io\"\n}\n"
  },
  {
    "path": "apps/web-e2e/src/integration/app.spec.ts",
    "content": "import { getGreeting } from '../support/app.po';\n\ndescribe('web', () => {\n  beforeEach(() => cy.visit('/'));\n\n  it('should display welcome message', () => {\n    // Custom command example, see `../support/commands.ts` file\n    cy.login('my-email@something.com', 'myPassword');\n\n    // Function helper example, see `../support/app.po.ts` file\n    getGreeting().contains('Welcome to web!');\n  });\n});\n"
  },
  {
    "path": "apps/web-e2e/src/support/app.po.ts",
    "content": "export const getGreeting = () => cy.get('h1');\n"
  },
  {
    "path": "apps/web-e2e/src/support/commands.ts",
    "content": "// ***********************************************\n// This example commands.js shows you how to\n// create various custom commands and overwrite\n// existing commands.\n//\n// For more comprehensive examples of custom\n// commands please read more here:\n// https://on.cypress.io/custom-commands\n// ***********************************************\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\ndeclare namespace Cypress {\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  interface Chainable<Subject> {\n    login(email: string, password: string): void;\n  }\n}\n//\n// -- This is a parent command --\nCypress.Commands.add('login', (email, password) => {\n  console.log('Custom command example: Login', email, password);\n});\n//\n// -- This is a child command --\n// Cypress.Commands.add(\"drag\", { prevSubject: 'element'}, (subject, options) => { ... })\n//\n//\n// -- This is a dual command --\n// Cypress.Commands.add(\"dismiss\", { prevSubject: 'optional'}, (subject, options) => { ... })\n//\n//\n// -- This will overwrite an existing command --\n// Cypress.Commands.overwrite(\"visit\", (originalFn, url, options) => { ... })\n"
  },
  {
    "path": "apps/web-e2e/src/support/index.ts",
    "content": "// ***********************************************************\n// This example support/index.js is processed and\n// loaded automatically before your test files.\n//\n// This is a great place to put global configuration and\n// behavior that modifies Cypress.\n//\n// You can change the location of this file or turn off\n// automatically serving support files with the\n// 'supportFile' configuration option.\n//\n// You can read more here:\n// https://on.cypress.io/configuration\n// ***********************************************************\n\n// Import commands.js using ES2015 syntax:\nimport './commands';\n"
  },
  {
    "path": "apps/web-e2e/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"sourceMap\": false,\n    \"outDir\": \"../../dist/out-tsc\",\n    \"allowJs\": true,\n    \"types\": [\"cypress\", \"node\"],\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"noImplicitReturns\": true,\n    \"noFallthroughCasesInSwitch\": true\n  },\n  \"include\": [\"src/**/*.ts\", \"src/**/*.js\"],\n  \"angularCompilerOptions\": {\n    \"strictInjectionParameters\": true,\n    \"strictInputAccessModifiers\": true,\n    \"strictTemplates\": true\n  }\n}\n"
  },
  {
    "path": "decorate-angular-cli.js",
    "content": "/**\n * This file decorates the Angular CLI with the Nx CLI to enable features such as computation caching\n * and faster execution of tasks.\n *\n * It does this by:\n *\n * - Patching the Angular CLI to warn you in case you accidentally use the undecorated ng command.\n * - Symlinking the ng to nx command, so all commands run through the Nx CLI\n * - Updating the package.json postinstall script to give you control over this script\n *\n * The Nx CLI decorates the Angular CLI, so the Nx CLI is fully compatible with it.\n * Every command you run should work the same when using the Nx CLI, except faster.\n *\n * Because of symlinking you can still type `ng build/test/lint` in the terminal. The ng command, in this case,\n * will point to nx, which will perform optimizations before invoking ng. So the Angular CLI is always invoked.\n * The Nx CLI simply does some optimizations before invoking the Angular CLI.\n *\n * To opt out of this patch:\n * - Replace occurrences of nx with ng in your package.json\n * - Remove the script from your postinstall script in your package.json\n * - Delete and reinstall your node_modules\n */\n\nconst fs = require('fs');\nconst os = require('os');\nconst cp = require('child_process');\nconst isWindows = os.platform() === 'win32';\nlet output;\ntry {\n  output = require('@nrwl/workspace').output;\n} catch (e) {\n  console.warn(\n    'Angular CLI could not be decorated to enable computation caching. Please ensure @nrwl/workspace is installed.'\n  );\n  process.exit(0);\n}\n\n/**\n * Symlink of ng to nx, so you can keep using `ng build/test/lint` and still\n * invoke the Nx CLI and get the benefits of computation caching.\n */\nfunction symlinkNgCLItoNxCLI() {\n  try {\n    const ngPath = './node_modules/.bin/ng';\n    const nxPath = './node_modules/.bin/nx';\n    if (isWindows) {\n      /**\n       * This is the most reliable way to create symlink-like behavior on Windows.\n       * Such that it works in all shells and works with npx.\n       */\n      ['', '.cmd', '.ps1'].forEach((ext) => {\n        if (fs.existsSync(nxPath + ext))\n          fs.writeFileSync(ngPath + ext, fs.readFileSync(nxPath + ext));\n      });\n    } else {\n      // If unix-based, symlink\n      cp.execSync(`ln -sf ./nx ${ngPath}`);\n    }\n  } catch (e) {\n    output.error({\n      title:\n        'Unable to create a symlink from the Angular CLI to the Nx CLI:' +\n        e.message,\n    });\n    throw e;\n  }\n}\n\ntry {\n  symlinkNgCLItoNxCLI();\n  require('nx/src/adapter/decorate-cli').decorateCli();\n  output.log({\n    title: 'Angular CLI has been decorated to enable computation caching.',\n  });\n} catch (e) {\n  output.error({\n    title: 'Decoration of the Angular CLI did not complete successfully',\n  });\n}\n"
  },
  {
    "path": "jest.config.ts",
    "content": "import { getJestProjects } from '@nrwl/jest';\n\nexport default {\n  projects: getJestProjects(),\n};\n"
  },
  {
    "path": "jest.preset.js",
    "content": "const nxPreset = require('@nrwl/jest/preset').default;\n\nmodule.exports = { ...nxPreset };\n"
  },
  {
    "path": "libs/nodeplotlib/.babelrc",
    "content": "{\n  \"presets\": [[\"@nrwl/web/babel\", { \"useBuiltIns\": \"usage\" }]]\n}\n"
  },
  {
    "path": "libs/nodeplotlib/.eslintrc.json",
    "content": "{\n  \"extends\": [\"../../.eslintrc.json\"],\n  \"ignorePatterns\": [\"!**/*\"],\n  \"overrides\": [\n    {\n      \"files\": [\"*.ts\", \"*.tsx\", \"*.js\", \"*.jsx\"],\n      \"rules\": {}\n    },\n    {\n      \"files\": [\"*.ts\", \"*.tsx\"],\n      \"rules\": {}\n    },\n    {\n      \"files\": [\"*.js\", \"*.jsx\"],\n      \"rules\": {}\n    }\n  ]\n}\n"
  },
  {
    "path": "libs/nodeplotlib/README.md",
    "content": "# <img src=\"https://raw.githubusercontent.com/ngfelixl/nodeplotlib/master/img/nodeplotlib_64x64.png\" width=\"28px\" height=\"28px\"> NodePlotLib\n\n[![NodeJS CI](https://github.com/ngfelixl/nodeplotlib/workflows/Node.js%20CI/badge.svg)](https://github.com/ngfelixl/nodeplotlib/actions?query=workflow%3A%22Node.js+CI%22)\n[![npm](https://img.shields.io/npm/v/nodeplotlib?color=#00f800)](https://npmjs.com/package/nodeplotlib)\n[![npm](https://img.shields.io/npm/dt/nodeplotlib.svg)](https://npmjs.com/package/nodeplotlib)\n[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n\n[![Animation (View on Github)](https://raw.githubusercontent.com/ngfelixl/nodeplotlib/master/img/animation-next.gif)](https://raw.githubusercontent.com/ngfelixl/nodeplotlib/master/img/animation-next.gif)\n\nLibrary to create plots directly in TypeScript or JavaScript in NodeJS on top of [plotly.js](https://plot.ly/javascript/)\nwithout any front-end preparations. Inspired by matplotlib.\n\n## Installation\n\n```sh\nnpm install nodeplotlib\n# or\nyarn add nodeplotlib\n```\n\n## Usage\n\n### Creating a simple plot\n\nUse with TypeScript/JavaScript:\n\n```typescript\nimport { plot, Plot } from 'nodeplotlib';\n\nconst data: Plot[] = [\n  {\n    x: [1, 3, 4, 5],\n    y: [3, 12, 1, 4],\n    type: 'scatter',\n  },\n];\n\nplot(data);\n```\n\n### Creating a stream that plots data in realtime\n\nNodePlotLib makes use of the popular [RxJS](https://rxjs.dev) library,\nwhich provides functionality for streams, stream creator functions (e.g. from interval or from event),\nand tons of operators to modify your stream.\n\nIn this example we create a stream based on an interval which triggers every 100ms. Then we modify\nthe output of the interval (which is just a counter) to be an actual `Plot` using RxJS' `map` operator.\nThe output will be a `sin` function.\n\n```typescript\nimport { plot, Plot } from 'nodeplotlib';\nimport { interval, map } from 'rxjs';\n\nconst stream$: Observable<Plot[]> = interval(100).pipe(\n  map(createSinusPlotFromNumber)\n);\n\nfunction createSinusPlotFromNumber(num: number): Plot[] {\n  const data: Plot[] = [\n    {\n      x: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n      y: Array(10)\n        .fill(0)\n        .map((_, i) => Math.sin(num + i)),\n      type: 'scatter',\n    },\n  ];\n  return data;\n}\n```\n\nAs you can see, providing a function for a dynamic plot seems to be a good idea.\nThe functions content looks almost the same as the \"non-stream\" version. Simple as\nthat, you can just put the created Observable as an argument in the plot function:\n\n```typescript\nplot(stream$);\n```\n\n### API overview\n\nThere are three exports. The `plot` function and types for the Plot and for the Layout.\n\n```typescript\nimport { plot, Plot, Layout, Config } from 'nodeplotlib';\n```\n\nThe `plot` function has the following structure\n\n```typescript\nfunction plot(\n  data: Plot[] | Observable<Plot[]>,\n  layout?: Layout,\n  config?: Config\n): void;\n```\n\nIt does not return a Subscription for the Observables because you just need to close\nthe listening browser window to unsubscribe from all Obserables.\n\n## Examples\n\nIn this section there are some examples to getting started. See the full plotly\n[cheatsheet](https://images.plot.ly/plotly-documentation/images/plotly_js_cheat_sheet.pdf?_ga=2.2676214.711017137.1550402185-1513144731.1549064935).\n\n#### Line Plots\n\n```typescript\nconst trace1: Plot = { x: [1, 2], y: [1, 2], type: 'scatter' };\nconst trace2: Plot = { x: [3, 4], y: [9, 16], type: 'scatter' };\nplot([trace1, trace2]);\n```\n\n#### Bar Charts\n\n```typescript\nconst trace: Plot = { x: [1, 2], y: [1, 2], type: 'bar' };\nplot([trace]);\n```\n\n#### 3D Line Plots\n\n```typescript\nconst trace: Plot = {\n  x: [9, 8, 5, 1],\n  y: [1, 2, 4, 8],\n  z: [11, 8, 15, 3],\n  type: 'scatter3d',\n};\nplot([trace]);\n```\n\n#### 3D Surface Plots\n\n```typescript\nconst trace: Plot = {\n  colorscale: 'Viridis',\n  z: [\n    [3, 5, 7, 9],\n    [21, 13, 8, 5],\n  ],\n};\nplot([trace]);\n```\n\n#### Radial Plots\n\nIn order to style the plot, one is able to pass in the `layout` parameter, which internally\nis typeof `Partial<Layout>` from plotly's `Layout`. See the full layout documentation\n[here](https://plot.ly/javascript/#layout-options).\n\nWith this parameter one is able to define styles like _title_, _axis labels_,\n_subplots_ and many more.\n\n```typescript\nconst data: Plot[] = [\n  {\n    type: 'scatterpolar',\n    r: [1.5, 10, 39, 31, 15, 1.5],\n    theta: ['A', 'B', 'C', 'D', 'E', 'A'],\n    fill: 'toself',\n    name: 'Group B',\n  },\n];\n\nconst layout: Layout = {\n  polar: {\n    radialaxis: {\n      visible: true,\n      range: [0, 50],\n    },\n  },\n};\n\nplot(data, layout);\n```\n\n## Plot types\n\n| Simple charts   | Advanced charts  | 3D Plots |\n| --------------- | ---------------- | -------- |\n| Scatter         | 2d density plots | Scatter  |\n| Line            | Histograms       | Surface  |\n| Bar             | Box-plots        | Lines    |\n| Pie charts      | Contour plots    |          |\n| Sankey diagrams | Heatmaps         |          |\n| Tables          | Radar charts     |          |\n\n## Contributing\n\nContributions in all forms are welcome.\n\n## Developers guide\n\nYou can find the developers guide in the repositories root\n[README.md](https://github.com/ngfelixl/nodeplotlib).\n\n## Contributors\n\n<a href=\"https://github.com/ngfelixl\"><img src=\"https://avatars2.githubusercontent.com/u/24190530\" title=\"ngfelixl\" width=\"100\" height=\"100\"></a>\n<a href=\"https://github.com/mitsos1os\"><img src=\"https://avatars3.githubusercontent.com/u/8208733\" title=\"mitsos1os\" width=\"100\" height=\"100\"></a>\n<a href=\"https://github.com/medved-nsk\"><img src=\"https://avatars1.githubusercontent.com/u/6310906\" title=\"medved-nsk\" width=\"100\" height=\"100\"></a>\n<a href=\"https://github.com/Moumouls\"><img src=\"https://avatars.githubusercontent.com/u/27959372\" title=\"Moumouls\" width=\"100\" height=\"100\"></a>\n<a href=\"https://github.com/grgr-dkrk\"><img src=\"https://avatars.githubusercontent.com/u/40130327\" title=\"guruguru-dekiruko\" width=\"100\" height=\"100\"></a>\n<a href=\"https://github.com/nathanbabcock\"><img src=\"https://avatars.githubusercontent.com/u/9583103\" title=\"nathanbabcock\" width=\"100\" height=\"100\"></a>\n"
  },
  {
    "path": "libs/nodeplotlib/jest.config.ts",
    "content": "/* eslint-disable */\nexport default {\n  displayName: 'nodeplotlib',\n  preset: '../../jest.preset.js',\n  globals: {\n    'ts-jest': {\n      tsconfig: '<rootDir>/tsconfig.spec.json',\n    },\n  },\n  testEnvironment: 'node',\n  transform: {\n    '^.+\\\\.[tj]sx?$': 'ts-jest',\n  },\n  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],\n  coverageDirectory: '../../coverage/libs/nodeplotlib',\n};\n"
  },
  {
    "path": "libs/nodeplotlib/package.json",
    "content": "{\n  \"name\": \"nodeplotlib\",\n  \"version\": \"1.1.3\",\n  \"description\": \"NodeJS frontend-less plotting lib using plotly.js inspired by matplotlib\",\n  \"author\": \"Felix Lemke <flemke.dev@gmail.com> (https://felixlemke.dev)\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/ngfelixl/nodeplotlib.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/ngfelixl/nodeplotlib/issues\"\n  },\n  \"homepage\": \"https://github.com/ngfelixl/nodeplotlib#readme\",\n  \"keywords\": [\n    \"plot\",\n    \"nodejs\",\n    \"plotlyjs\",\n    \"science\",\n    \"easy-to-use\",\n    \"statistics\",\n    \"browser\",\n    \"localhost\"\n  ],\n  \"dependencies\": {\n    \"@types/plotly.js\": \"^1.54.17\",\n    \"@nestjs/platform-express\": \"^9.0.0\",\n    \"@nestjs/platform-socket.io\": \"^9.0.0\"\n  },\n  \"peerDependencies\": {}\n}\n"
  },
  {
    "path": "libs/nodeplotlib/project.json",
    "content": "{\n  \"$schema\": \"../../node_modules/nx/schemas/project-schema.json\",\n  \"root\": \"libs/nodeplotlib\",\n  \"sourceRoot\": \"libs/nodeplotlib/src\",\n  \"projectType\": \"library\",\n  \"architect\": {\n    \"build\": {\n      \"builder\": \"@nrwl/js:tsc\",\n      \"outputs\": [\"{options.outputPath}\"],\n      \"options\": {\n        \"main\": \"libs/nodeplotlib/src/index.ts\",\n        \"outputPath\": \"dist/libs/nodeplotlib\",\n        \"tsConfig\": \"libs/nodeplotlib/tsconfig.lib.json\",\n        \"generatePackageJson\": true,\n        \"extractLicenses\": true\n      }\n    },\n    \"lint\": {\n      \"builder\": \"@nrwl/linter:eslint\",\n      \"outputs\": [\"{options.outputFile}\"],\n      \"options\": {\n        \"lintFilePatterns\": [\"libs/nodeplotlib/**/*.ts\"]\n      }\n    },\n    \"test\": {\n      \"builder\": \"@nrwl/jest:jest\",\n      \"outputs\": [\"coverage/libs/nodeplotlib\"],\n      \"options\": {\n        \"jestConfig\": \"libs/nodeplotlib/jest.config.ts\",\n        \"passWithNoTests\": true\n      }\n    }\n  },\n  \"tags\": []\n}\n"
  },
  {
    "path": "libs/nodeplotlib/src/index.ts",
    "content": "// Exports required for the actual nodeplotlib\nexport { Plot, Layout, Config } from './lib/interfaces/plot';\nexport { plot } from './lib/nodeplotlib';\n\n// Exports required for the web app\nexport { PlotData } from './lib/interfaces/plot';\n"
  },
  {
    "path": "libs/nodeplotlib/src/lib/interfaces/index.ts",
    "content": "export { Layout, Plot, PlotData, PlotDataStream } from './plot';\n"
  },
  {
    "path": "libs/nodeplotlib/src/lib/interfaces/plot.ts",
    "content": "import {\n  Layout as PlotlyLayout,\n  PlotData as PlotlyPlotData,\n  Config as PlotlyConfig,\n} from 'plotly.js';\nimport { Observable } from 'rxjs';\n\nexport type Plot = Partial<PlotlyPlotData>;\nexport type Layout = Partial<PlotlyLayout>;\nexport type Config = Partial<PlotlyConfig>;\n\nexport interface PlotDataStream {\n  id: number;\n  data: Observable<Plot[]>;\n  layout: Observable<Layout | undefined>;\n  config: Config | undefined;\n}\n\nexport interface PlotData {\n  id: number;\n  data: Plot[];\n  layout?: Layout;\n  config?: Config;\n}\n"
  },
  {
    "path": "libs/nodeplotlib/src/lib/nodeplotlib.ts",
    "content": "import { INestApplication } from '@nestjs/common';\nimport { NestFactory } from '@nestjs/core';\nimport { Layout, Plot, PlotDataStream } from './interfaces';\nimport { BehaviorSubject, Observable, of, Subscription } from 'rxjs';\nimport { PlotsService } from './server/plots/plots.service';\nimport { ServerModule } from './server/server.module';\nimport { BridgeService } from './server/services/bridge.service';\nimport { getPort } from './utils/get-port';\nimport { Config } from './interfaces/plot';\nlet app: INestApplication | null = null;\nlet plotsService: PlotsService;\nlet bridgeService: BridgeService;\n\n// This variable is used to determine if the nestjs app is running\n// or starting. Because it is \"async\" and the plot function is not,\n// we need to make sure that we do not bootstrap the app twice in the\n// same macro-task.\nlet appRuns = false;\nlet shutdownSubscription: Subscription;\nconst plotsBuffer$ = new BehaviorSubject<Omit<PlotDataStream, 'id'>[]>([]);\nconst port = getPort();\n\n/**\n * Plots the given data with the given layout. This function\n * starts a server if one is not already running.\n * @param data\n * @param layout\n * @param cb\n */\nexport function plot(\n  data: Plot[] | Observable<Plot[]>,\n  layout?: Layout,\n  config?: Config\n) {\n  bootstrap(port);\n  const bufferedPlots = plotsBuffer$.value;\n\n  const streamData$: Observable<Plot[]> =\n    data instanceof Observable ? data : of(data);\n  plotsBuffer$.next([\n    ...bufferedPlots,\n    { data: streamData$, layout: of(layout), config },\n  ]);\n}\n\nasync function bootstrap(port: number) {\n  if (appRuns) {\n    console.log('[Nodeplotlib] App is already up and running');\n    return;\n  }\n  appRuns = true;\n  app = await NestFactory.create(ServerModule);\n  plotsService = app.get(PlotsService);\n  bridgeService = app.get(BridgeService);\n  await app.listen(port);\n\n  const actualPort = app.getHttpServer().address().port;\n  bridgeService.setPort(actualPort);\n  plotsService.setBuffer(plotsBuffer$);\n  console.log(\n    '[Nodeplotlib] Server running at',\n    `http://localhost:${actualPort}`\n  );\n\n  shutdownSubscription = bridgeService.shutdown$.subscribe(shutdown);\n}\n\nasync function shutdown() {\n  console.log('[Nodeplotlib] Server shutting down');\n  shutdownSubscription?.unsubscribe();\n  appRuns = false;\n\n  if (app) {\n    await app.close();\n  }\n}\n"
  },
  {
    "path": "libs/nodeplotlib/src/lib/server/plots/plots.gateway.ts",
    "content": "import {\n  OnGatewayConnection,\n  OnGatewayDisconnect,\n  SubscribeMessage,\n  WebSocketGateway,\n} from '@nestjs/websockets';\nimport { PlotData } from '../../interfaces';\nimport { combineLatest, merge, Observable } from 'rxjs';\nimport { map, share, switchMap } from 'rxjs/operators';\nimport { BridgeService } from '../services/bridge.service';\nimport { PlotsService } from './plots.service';\n\n@WebSocketGateway({ transports: ['polling'] })\nexport class PlotsGateway implements OnGatewayConnection, OnGatewayDisconnect {\n  private clientMap = new Map<WebSocket, number>();\n  private plotDataStream$: Observable<PlotData>;\n\n  constructor(\n    private bridgeService: BridgeService,\n    private plotsService: PlotsService\n  ) {\n    this.plotDataStream$ = this.plotsService.plotIds$.pipe(\n      switchMap((plotIds) =>\n        merge(\n          ...Array.from(plotIds).map((id) => {\n            const plotDataStream = this.plotsService.plotEntities.get(id);\n            if (!plotDataStream) {\n              return new Observable<PlotData>();\n            }\n            return combineLatest([\n              plotDataStream.data,\n              plotDataStream.layout,\n            ]).pipe(\n              map(([data, layout]) => ({\n                id,\n                data,\n                layout,\n                config: plotDataStream.config,\n              }))\n            );\n          })\n        )\n      ),\n      share()\n    );\n  }\n\n  @SubscribeMessage('readplots')\n  handleEvent() {\n    return this.plotDataStream$.pipe(\n      map((plotData) => ({\n        event: 'plotdata',\n        data: plotData,\n      }))\n    );\n  }\n\n  handleConnection(client: WebSocket) {\n    console.log('[Nodeplotlib] client connected');\n    this.clientMap.set(client, Date.now());\n  }\n\n  handleDisconnect(client: WebSocket) {\n    console.log('[Nodeplotlib] client disconnected');\n    this.clientMap.delete(client);\n\n    if (this.clientMap.size === 0) {\n      this.bridgeService.shutdown$.next(null);\n    }\n  }\n}\n"
  },
  {
    "path": "libs/nodeplotlib/src/lib/server/plots/plots.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { PlotDataStream } from '../../interfaces';\nimport { BehaviorSubject, Observable, Subscription } from 'rxjs';\nimport { filter } from 'rxjs/operators';\n\n@Injectable()\nexport class PlotsService {\n  plotEntities = new Map<number, PlotDataStream>();\n  plotIds$ = new BehaviorSubject<Set<number>>(new Set());\n  private currentPlotId = 0;\n  private bufferSubscription?: Subscription;\n\n  setBuffer(buffer$: Observable<Omit<PlotDataStream, 'id'>[]>) {\n    this.bufferSubscription?.unsubscribe();\n    this.bufferSubscription = buffer$\n      .pipe(filter((buffer) => buffer.length > 0))\n      .subscribe((buffer) => this.readBuffer(buffer));\n  }\n\n  addPlot(plotData: Omit<PlotDataStream, 'id'>) {\n    const plot: PlotDataStream = {\n      id: this.currentPlotId++,\n      data: plotData.data,\n      layout: plotData.layout,\n      config: plotData.config,\n    };\n\n    this.plotEntities.set(plot.id, plot);\n    const plotIds = this.plotIds$.value;\n    plotIds.add(plot.id);\n    this.plotIds$.next(plotIds);\n  }\n\n  /**\n   * Function gets executed on the main process and makes the service read\n   * the buffered plot data.\n   * @param buffer\n   */\n  readBuffer(buffer: Omit<PlotDataStream, 'id'>[]) {\n    for (const plot of buffer) {\n      this.addPlot(plot);\n    }\n  }\n}\n"
  },
  {
    "path": "libs/nodeplotlib/src/lib/server/server.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { ServeStaticModule } from '@nestjs/serve-static';\nimport { join } from 'path';\nimport { PlotsGateway } from './plots/plots.gateway';\nimport { PlotsService } from './plots/plots.service';\nimport { BridgeService } from './services/bridge.service';\n\n@Module({\n  imports: [\n    ServeStaticModule.forRoot({\n      rootPath: join(__dirname, 'web'),\n    }),\n  ],\n  providers: [PlotsGateway, PlotsService, BridgeService],\n})\nexport class ServerModule {}\n"
  },
  {
    "path": "libs/nodeplotlib/src/lib/server/services/bridge-service.spec.ts",
    "content": "import { BridgeService } from './bridge.service';\nimport { openWindow } from '../../utils/open-window';\njest.mock('../../utils/open-window');\n\ndescribe('BridgeService', () => {\n  it('should emit a shutdown$ event if the shutdown function is called', (done) => {\n    const bridgeService = new BridgeService();\n    bridgeService.shutdown$.subscribe(() => {\n      done();\n    });\n    bridgeService.shutdown();\n  });\n\n  it('call the openWindow function with the url if a port is set', () => {\n    const bridgeService = new BridgeService();\n    bridgeService.setPort(1234);\n    expect(openWindow).toHaveBeenCalledWith(`http://localhost:1234`);\n  });\n});\n"
  },
  {
    "path": "libs/nodeplotlib/src/lib/server/services/bridge.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\nimport { Subject } from 'rxjs';\nimport { openWindow } from '../../utils/open-window';\n\n/**\n * The BridgeService is used to build a bridge between the\n * NestJS server and the outside of the NestJS server.\n * The two purposes are to get the port of the express server\n * inside of the NestJS server and to provide a shutdown$\n * steam so that the NestJS server can trigger a full shutdown.\n *\n * @see nodeplotlib.ts\n */\n@Injectable()\nexport class BridgeService {\n  shutdown$ = new Subject();\n  port$ = new Subject<number>();\n\n  constructor() {\n    this.port$.subscribe((port) => {\n      openWindow(`http://localhost:${port}`);\n    });\n  }\n\n  setPort(port: number) {\n    this.port$.next(port);\n  }\n\n  shutdown() {\n    this.shutdown$.next(null);\n  }\n}\n"
  },
  {
    "path": "libs/nodeplotlib/src/lib/utils/get-port.spec.ts",
    "content": "import { getPort } from './get-port';\n\ndescribe('getPort', () => {\n  it('should return 0 if NODEPLOTLIB_PORT is undefined', () => {\n    process.env.NODEPLOTLIB_PORT = undefined;\n    expect(getPort()).toBe(0);\n  });\n\n  it('should return 0 if NODEPLOTLIB_PORT is null', () => {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    process.env.NODEPLOTLIB_PORT = null as any;\n    expect(getPort()).toBe(0);\n  });\n\n  it('should return 0 if NODEPLOTLIB_PORT is empty string', () => {\n    process.env.NODEPLOTLIB_PORT = '';\n    expect(getPort()).toBe(0);\n  });\n\n  it('should return 0 if NODEPLOTLIB_PORT is 0', () => {\n    process.env.NODEPLOTLIB_PORT = '0';\n    expect(getPort()).toBe(0);\n  });\n\n  it('should return the number if NODEPLOTLIB_PORT is a number and not 0', () => {\n    process.env.NODEPLOTLIB_PORT = '123';\n    expect(getPort()).toBe(123);\n  });\n});\n"
  },
  {
    "path": "libs/nodeplotlib/src/lib/utils/get-port.ts",
    "content": "export function getPort(): number {\n  const portAsString = process.env.NODEPLOTLIB_PORT;\n  const port = Number(portAsString);\n  if (isNaN(port)) {\n    return 0;\n  }\n  return port;\n}\n"
  },
  {
    "path": "libs/nodeplotlib/src/lib/utils/open-window.spec.ts",
    "content": "import { openWindow } from './open-window';\nimport { exec } from 'child_process';\nimport { type } from 'os';\njest.mock('child_process');\njest.mock('os');\n\ndescribe('openWindow', () => {\n  let execMock: jest.MockedFunction<typeof exec>;\n  let typeMock: jest.MockedFunction<typeof type>;\n\n  beforeEach(() => {\n    execMock = exec as jest.MockedFunction<typeof exec>;\n    typeMock = type as jest.MockedFunction<typeof type>;\n  });\n\n  afterEach(() => {\n    delete process.env.NODEPLOTLIB_PORT;\n  });\n\n  it('should not call the exec function if NODEPLOTLIB_PORT is set', () => {\n    process.env.NODEPLOTLIB_PORT = '123';\n    openWindow('location');\n    expect(execMock).not.toBeCalled();\n  });\n\n  it('should not call the exec function if NODEPLOTLIB_PORT is set to \"\"', () => {\n    process.env.NODEPLOTLIB_PORT = '';\n    openWindow('location');\n    expect(execMock).not.toBeCalled();\n  });\n\n  it('should call the exec function for linux correctly', () => {\n    typeMock.mockImplementation(() => 'Linux');\n    openWindow('location');\n    expect(execMock).toBeCalledWith('xdg-open location');\n  });\n\n  it('should call the exec function for windows correctly', () => {\n    typeMock.mockImplementation(() => 'Windows_NT');\n    openWindow('location');\n    expect(execMock).toBeCalledWith('start location');\n  });\n\n  it('should call the exec function for mac correctly', () => {\n    typeMock.mockImplementation(() => 'Darwin');\n    openWindow('location');\n    expect(execMock).toBeCalledWith('open location');\n  });\n});\n"
  },
  {
    "path": "libs/nodeplotlib/src/lib/utils/open-window.ts",
    "content": "import { exec } from 'child_process';\nimport { type } from 'os';\n\nexport function openWindow(location: string) {\n  if (process.env.NODEPLOTLIB_PORT) {\n    return;\n  }\n\n  switch (type()) {\n    case 'Linux':\n      exec(`xdg-open ${location}`);\n      break;\n    case 'Darwin':\n      exec(`open ${location}`);\n      break;\n    case 'Windows_NT':\n      exec(`start ${location}`);\n      break;\n  }\n}\n"
  },
  {
    "path": "libs/nodeplotlib/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.base.json\",\n  \"files\": [],\n  \"include\": [],\n  \"references\": [\n    {\n      \"path\": \"./tsconfig.lib.json\"\n    },\n    {\n      \"path\": \"./tsconfig.spec.json\"\n    }\n  ],\n  \"compilerOptions\": {\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"noImplicitReturns\": true,\n    \"noFallthroughCasesInSwitch\": true\n  }\n}\n"
  },
  {
    "path": "libs/nodeplotlib/tsconfig.lib.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"outDir\": \"../../dist/out-tsc\",\n    \"declaration\": true,\n    \"types\": [\"node\"]\n  },\n  \"exclude\": [\"**/*.spec.ts\", \"**/*.test.ts\", \"jest.config.ts\"],\n  \"include\": [\"**/*.ts\"]\n}\n"
  },
  {
    "path": "libs/nodeplotlib/tsconfig.spec.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../../dist/out-tsc\",\n    \"module\": \"commonjs\",\n    \"types\": [\"jest\", \"node\"]\n  },\n  \"include\": [\n    \"**/*.test.ts\",\n    \"**/*.spec.ts\",\n    \"**/*.test.tsx\",\n    \"**/*.spec.tsx\",\n    \"**/*.test.js\",\n    \"**/*.spec.js\",\n    \"**/*.test.jsx\",\n    \"**/*.spec.jsx\",\n    \"**/*.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "nx.json",
    "content": "{\n  \"$schema\": \"./node_modules/nx/schemas/nx-schema.json\",\n  \"npmScope\": \"npl\",\n  \"affected\": {\n    \"defaultBase\": \"main\"\n  },\n  \"implicitDependencies\": {\n    \"package.json\": {\n      \"dependencies\": \"*\",\n      \"devDependencies\": \"*\"\n    },\n    \".eslintrc.json\": \"*\"\n  },\n  \"tasksRunnerOptions\": {\n    \"default\": {\n      \"runner\": \"nx/tasks-runners/default\",\n      \"options\": {\n        \"cacheableOperations\": [\"build\", \"lint\", \"test\", \"e2e\"]\n      }\n    }\n  },\n  \"targetDefaults\": {\n    \"build\": {\n      \"dependsOn\": [\"^build\"]\n    }\n  },\n  \"generators\": {\n    \"@nrwl/angular:application\": {\n      \"style\": \"css\",\n      \"linter\": \"eslint\",\n      \"unitTestRunner\": \"jest\",\n      \"e2eTestRunner\": \"cypress\"\n    },\n    \"@nrwl/angular:library\": {\n      \"linter\": \"eslint\",\n      \"unitTestRunner\": \"jest\"\n    },\n    \"@nrwl/angular:component\": {\n      \"style\": \"css\"\n    }\n  },\n  \"defaultProject\": \"web\"\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"nodeplotlib\",\n  \"version\": \"1.1.3\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"ng\": \"nx\",\n    \"postinstall\": \"node ./decorate-angular-cli.js && ngcc --properties es2020 browser module main\",\n    \"format:write\": \"nx format:write\",\n    \"build\": \"nx build\",\n    \"build:prod\": \"nx run web:build && nx run nodeplotlib:build && ts-node ./tools/util/copy-files.ts\",\n    \"demo\": \"node ./tools/demo/candlestick.js\"\n  },\n  \"private\": true,\n  \"dependencies\": {\n    \"@angular/animations\": \"14.1.1\",\n    \"@angular/cdk\": \"14.1.1\",\n    \"@angular/common\": \"14.1.1\",\n    \"@angular/compiler\": \"14.1.1\",\n    \"@angular/core\": \"14.1.1\",\n    \"@angular/forms\": \"14.1.1\",\n    \"@angular/material\": \"14.1.1\",\n    \"@angular/platform-browser\": \"14.1.1\",\n    \"@angular/platform-browser-dynamic\": \"14.1.1\",\n    \"@angular/router\": \"14.1.1\",\n    \"@nestjs/common\": \"9.0.8\",\n    \"@nestjs/core\": \"9.0.8\",\n    \"@nestjs/microservices\": \"9.0.8\",\n    \"@nestjs/platform-express\": \"9.0.8\",\n    \"@nestjs/platform-socket.io\": \"9.0.8\",\n    \"@nestjs/serve-static\": \"3.0.0\",\n    \"@nestjs/websockets\": \"9.0.8\",\n    \"@ngrx/effects\": \"~14.0.1\",\n    \"@ngrx/entity\": \"~14.0.1\",\n    \"@ngrx/store\": \"~14.0.1\",\n    \"@nrwl/angular\": \"14.5.4\",\n    \"@types/plotly.js\": \"^1.54.17\",\n    \"express\": \"^4.17.1\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rxjs\": \"^7.4.0\",\n    \"socket.io-client\": \"^4.4.0\",\n    \"tslib\": \"^2.0.0\",\n    \"zone.js\": \"~0.11.4\"\n  },\n  \"devDependencies\": {\n    \"@angular-devkit/build-angular\": \"14.1.1\",\n    \"@angular-eslint/eslint-plugin\": \"~14.0.0\",\n    \"@angular-eslint/eslint-plugin-template\": \"~14.0.0\",\n    \"@angular-eslint/template-parser\": \"~14.0.0\",\n    \"@angular/cli\": \"~14.1.0\",\n    \"@angular/compiler-cli\": \"14.1.1\",\n    \"@angular/language-service\": \"14.1.1\",\n    \"@nestjs/schematics\": \"9.0.1\",\n    \"@nestjs/testing\": \"9.0.8\",\n    \"@ngrx/eslint-plugin\": \"^14.0.1\",\n    \"@nrwl/cli\": \"14.5.4\",\n    \"@nrwl/cypress\": \"14.5.4\",\n    \"@nrwl/eslint-plugin-nx\": \"14.5.4\",\n    \"@nrwl/jest\": \"14.5.4\",\n    \"@nrwl/linter\": \"14.5.4\",\n    \"@nrwl/nest\": \"14.5.4\",\n    \"@nrwl/node\": \"14.5.4\",\n    \"@nrwl/workspace\": \"14.5.4\",\n    \"@types/express\": \"^4.17.13\",\n    \"@types/jest\": \"27.4.1\",\n    \"@types/node\": \"16.11.7\",\n    \"@types/request\": \"^2.48.7\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.29.0\",\n    \"@typescript-eslint/parser\": \"^5.29.0\",\n    \"copy-webpack-plugin\": \"^6.3.2\",\n    \"cypress\": \"^9.1.0\",\n    \"eslint\": \"~8.15.0\",\n    \"eslint-config-prettier\": \"8.1.0\",\n    \"eslint-plugin-cypress\": \"^2.10.3\",\n    \"fs-extra\": \"^10.0.0\",\n    \"jest\": \"27.5.1\",\n    \"jest-preset-angular\": \"~11.1.2\",\n    \"nx\": \"14.5.4\",\n    \"plotly.js-dist\": \"^2.5.1\",\n    \"prettier\": \"^2.6.2\",\n    \"request\": \"^2.88.2\",\n    \"ts-jest\": \"27.1.4\",\n    \"ts-node\": \"~10.8.0\",\n    \"typescript\": \"~4.7.2\"\n  }\n}\n"
  },
  {
    "path": "tools/demo/README.md",
    "content": "# Demo plots\n\nThese plots are meant to run with the compiled version of nodeplotlib. You can run them\nwith the following commands:\n\n```\nnode ./tools/demo/scatter.js\nnode ./tools/demo/candlestick.js\nnpx ts-node ./tools/demo/scatter.ts\n```\n\nFor further demos you can have a look at the **dev-server** app. In the _/data_ folder\nyou'll find demos for several plot types.\n"
  },
  {
    "path": "tools/demo/candlestick.js",
    "content": "const npl = require('../../dist/libs/nodeplotlib');\n\nconst trace1 = {\n  x: [\n    '2017-01-04',\n    '2017-01-05',\n    '2017-01-06',\n    '2017-01-09',\n    '2017-01-10',\n    '2017-01-11',\n    '2017-01-12',\n    '2017-01-13',\n    '2017-01-17',\n    '2017-01-18',\n    '2017-01-19',\n    '2017-01-20',\n    '2017-01-23',\n    '2017-01-24',\n    '2017-01-25',\n    '2017-01-26',\n    '2017-01-27',\n    '2017-01-30',\n    '2017-01-31',\n    '2017-02-01',\n    '2017-02-02',\n    '2017-02-03',\n    '2017-02-06',\n    '2017-02-07',\n    '2017-02-08',\n    '2017-02-09',\n    '2017-02-10',\n    '2017-02-13',\n    '2017-02-14',\n    '2017-02-15',\n  ],\n  close: [\n    116.019997, 116.610001, 117.910004, 118.989998, 119.110001, 119.75, 119.25,\n    119.040001, 120, 119.989998, 119.779999, 120, 120.080002, 119.970001,\n    121.879997, 121.940002, 121.949997, 121.629997, 121.349998, 128.75,\n    128.529999, 129.080002, 130.289993, 131.529999, 132.039993, 132.419998,\n    132.119995, 133.289993, 135.020004, 135.509995,\n  ],\n  decreasing: { line: { color: '#7F7F7F' } },\n  high: [\n    116.510002, 116.860001, 118.160004, 119.43, 119.379997, 119.93, 119.300003,\n    119.620003, 120.239998, 120.5, 120.089996, 120.449997, 120.809998,\n    120.099998, 122.099998, 122.440002, 122.349998, 121.629997, 121.389999,\n    130.490005, 129.389999, 129.190002, 130.5, 132.089996, 132.220001,\n    132.449997, 132.940002, 133.820007, 135.089996, 136.270004,\n  ],\n  increasing: { line: { color: '#17BECF' } },\n  line: { color: 'rgba(31,119,180,1)' },\n  low: [\n    115.75, 115.809998, 116.470001, 117.940002, 118.300003, 118.599998,\n    118.209999, 118.809998, 118.220001, 119.709999, 119.370003, 119.730003,\n    119.769997, 119.5, 120.279999, 121.599998, 121.599998, 120.660004,\n    120.620003, 127.010002, 127.779999, 128.160004, 128.899994, 130.449997,\n    131.220001, 131.119995, 132.050003, 132.75, 133.25, 134.619995,\n  ],\n  open: [\n    115.849998, 115.919998, 116.779999, 117.949997, 118.769997, 118.739998,\n    118.900002, 119.110001, 118.339996, 120, 119.400002, 120.449997, 120,\n    119.550003, 120.419998, 121.669998, 122.139999, 120.93, 121.150002,\n    127.029999, 127.980003, 128.309998, 129.130005, 130.539993, 131.350006,\n    131.649994, 132.460007, 133.080002, 133.470001, 135.520004,\n  ],\n  type: 'candlestick',\n  xaxis: 'x',\n  yaxis: 'y',\n};\n\nconst data = [trace1];\n\nconst layout = {\n  dragmode: 'zoom',\n  margin: {\n    r: 10,\n    t: 25,\n    b: 40,\n    l: 60,\n  },\n  showlegend: false,\n  xaxis: {\n    autorange: true,\n    domain: [0, 1],\n    range: ['2017-01-03 12:00', '2017-02-15 12:00'],\n    rangeslider: { range: ['2017-01-03 12:00', '2017-02-15 12:00'] },\n    title: 'Date',\n    type: 'date',\n  },\n  yaxis: {\n    autorange: true,\n    domain: [0, 1],\n    range: [114.609999778, 137.410004222],\n    type: 'linear',\n  },\n};\n\nnpl.plot(data, layout);\n"
  },
  {
    "path": "tools/demo/scatter.js",
    "content": "import npl from '../../dist/libs/nodeplotlib';\nnpl.plot([{ x: [0], y: [1], type: 'scatter' }]);\n"
  },
  {
    "path": "tools/demo/scatter.ts",
    "content": "import npl from '../../dist/libs/nodeplotlib';\n\nnpl.plot([{ x: [0, 1], y: [1, 1], type: 'scatter' }]);\n"
  },
  {
    "path": "tools/demo/stream.ts",
    "content": "import { plot, Plot } from '../../dist/libs/nodeplotlib';\nimport { interval, map, Observable } from 'rxjs';\n\nconst stream$: Observable<Plot[]> = interval(100).pipe(\n  map(createSinusPlotFromNumber)\n);\n\nfunction createSinusPlotFromNumber(num: number): Plot[] {\n  const data: Plot[] = [\n    {\n      x: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],\n      y: Array(10)\n        .fill(0)\n        .map((_, i) => Math.sin(num + i)),\n      type: 'scatter',\n    },\n  ];\n  return data;\n}\n\nplot(stream$);\n"
  },
  {
    "path": "tools/generators/.gitkeep",
    "content": ""
  },
  {
    "path": "tools/tsconfig.tools.json",
    "content": "{\n  \"extends\": \"../tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"../dist/out-tsc/tools\",\n    \"rootDir\": \".\",\n    \"module\": \"commonjs\",\n    \"target\": \"es5\",\n    \"types\": [\"node\"],\n    \"importHelpers\": false\n  },\n  \"include\": [\"**/*.ts\"]\n}\n"
  },
  {
    "path": "tools/util/copy-files.ts",
    "content": "import { copySync } from 'fs-extra';\n\ncopySync('dist/apps/web', 'dist/libs/nodeplotlib/src/lib/server/web');\ncopySync('libs/nodeplotlib/README.md', 'dist/libs/nodeplotlib/README.md');\ncopySync('LICENSE', 'dist/libs/nodeplotlib/LICENSE');\n"
  },
  {
    "path": "tsconfig.base.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    \"rootDir\": \".\",\n    \"sourceMap\": true,\n    \"declaration\": false,\n    \"moduleResolution\": \"node\",\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"importHelpers\": true,\n    \"target\": \"es2015\",\n    \"module\": \"esnext\",\n    \"lib\": [\"es2017\", \"dom\"],\n    \"skipLibCheck\": true,\n    \"skipDefaultLibCheck\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@npl/nodeplotlib\": [\"libs/nodeplotlib/src/index.ts\"]\n    }\n  },\n  \"exclude\": [\"node_modules\", \"tmp\"]\n}\n"
  }
]