{"id":17134720,"url":"https://github.com/robojones/z1","last_synced_at":"2025-10-24T17:15:01.338Z","repository":{"id":42128983,"uuid":"80294894","full_name":"robojones/z1","owner":"robojones","description":"Node.js cluster manager","archived":false,"fork":false,"pushed_at":"2023-01-07T17:56:36.000Z","size":1510,"stargazers_count":9,"open_issues_count":1,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-24T13:03:48.280Z","etag":null,"topics":["app","cli","cluster","manager","nodejs","process","workers"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/z1","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/robojones.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-28T16:23:17.000Z","updated_at":"2023-11-03T17:12:43.000Z","dependencies_parsed_at":"2023-02-07T19:31:26.052Z","dependency_job_id":null,"html_url":"https://github.com/robojones/z1","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"purl":"pkg:github/robojones/z1","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robojones%2Fz1","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robojones%2Fz1/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robojones%2Fz1/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robojones%2Fz1/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/robojones","download_url":"https://codeload.github.com/robojones/z1/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robojones%2Fz1/sbom","scorecard":{"id":781085,"data":{"date":"2025-08-11","repo":{"name":"github.com/robojones/z1","commit":"7bde2b210e29df337eaa9716ce6b9d070199af9e"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/11 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 22 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"15 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-qrpm-p2h7-hrv2","Warn: Project is vulnerable to: GHSA-mwcw-c2x4-8c55","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-76p7-773f-r4q5","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T04:56:19.600Z","repository_id":42128983,"created_at":"2025-08-23T04:56:19.601Z","updated_at":"2025-08-23T04:56:19.601Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280833154,"owners_count":26399003,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-24T02:00:06.418Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["app","cli","cluster","manager","nodejs","process","workers"],"created_at":"2024-10-14T19:45:34.312Z","updated_at":"2025-10-24T17:15:01.309Z","avatar_url":"https://github.com/robojones.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# z1\n\n[![CircleCI](https://circleci.com/gh/robojones/z1.svg?style=svg)](https://circleci.com/gh/robojones/z1)\n\n__z1__ is a Node.js cluster management program. It works on Linux Debian, Ubuntu, and other Debian based distributions.\n\nWhen using Node.js on a __web server__, one will somehow come to the point where he wants to start __multiple\nprocesses__ for one app. The main goal of z1 is to __simplify__ the creation and management of Node.js processes.\n\n![Terminal example](https://raw.githubusercontent.com/robojones/z1/master/screenshots/terminal.gif)\n\n_This animation shows how simple it is to start a Node.js application with z1._\n\n## Table of contents\n\n- [Features](#features)\n- [Setup](#setup)\n    - [Installation](#installation)\n    - [Automatically resurrect z1](#automatically-resurrect-z1)\n    - [Prepare package.json](#prepare-packagejson)\n    - [Development](#development)\n- [CLI](#cli)\n    - [Environment variables](#environment-variables)\n    - [Start](#start)\n    - [Restart](#restart)\n    - [List](#list)\n    - [Info](#info)\n    - [Stop](#stop)\n    - [Exit](#exit)\n    - [Resurrect](#resurrect)\n    - [Install and Uninstall](#install-and-uninstall)\n    - [Passing arguments to workers](#passing-arguments-to-workers)\n- [API](#api)\n    - [z1.start](#z1startdir-args-opt-env-immediate)\n    - [z1.restart](#z1restartapp-opt-immediate)\n    - [z1.stop](#z1stopapp-opt-immediate)\n    - [z1.info](#z1infoapp)\n    - [z1.list](#z1list)\n    - [z1.exit](#z1exit)\n    - [z1.resurrect](#z1resurrectimmediate)\n    - [z1.ready](#z1ready)\n\n## Changes\n\n- v4.0.0\n    - use [revents](https://npmjs.com/package/revents) for data transmission between the CLI and the daemon.\n    - `Ctrl + C` can now be used to abort the starting process of apps.\n    - remove upgrade command.\n- v3.17.0\n    - add [WORKERS](#environment-variables) environment variable\n- v3.16.0\n    - add colors to cli\n- v3.15.0\n    - display the app's logs during command execution\n- v3.14.0\n    - add JSDoc to API\n\n## Setup\n\n### Installation\n\nVia [NPM](https://npmjs.com)\n\n```\nsudo npm install z1 -g\n```\n\n__Note:__\nYou might want to run `z1 resurrect` automatically after rebooting your system. It will start the z1 daemon and all the\napps that were running before.\n(see: [install command](#install-and-uninstall))\n\n### Prepare package.json\n\nBefore you can start your Node.js app, you need to add a few things to your\n`package.json` file.\n\n1. __name__ - The name of your app.\n2. __main__ - The entry point of your app (The file that you would normally run with (`node \u003cfile\u003e`).\n3. __ports__ _(optional)_ - An array of port numbers that your app uses.\n4. __workers__ _(optional)_ - A number specifying how many processes should be created for your app. The default value\n   is the number of CPU-cores in your system.\n5. __output__ _(optional)_ - A directory for the log and error files. (Default: `~/.z1/\u003cyourAppname\u003e`)\n6. __devPorts__ _(optional)_ - Ports for [development](#development)\n7. __devWorkers__ _(optional)_ - Workers for [development](#development)\n\n__Important:__\nz1 needs to know when your Node.js program (e.g. a web server) is successfully started. If you app uses ports, z1 will\nautomatically know when it listens to all the specified ports. It will then assume, that you app is completely started.\n__If you app does not use any ports, you must require z1 in your program and call the [z1.ready()](#z1ready) method.__\n\nExample package.json file:\n\n```json\n{\n  \"name\": \"homepage\",\n  \"main\": \"index.js\",\n  \"ports\": [8080],\n  \"workers\": 2\n}\n```\n\n### Development\n\nIf you are running z1 locally, you can set `NODE_ENV=development`. This will cause z1 to use the `devPorts`\nand `devWorkers` (if specified) instead of the `ports` and `workers` properties from the `package.json`. The __default\ntimeout__ for stop and restart will be set to __0ms__.\n\n## CLI\n\n### Environment variables\n\nYou can set different environment variables for each app. The [start](#start) command automatically applies the\nenvironment variables of the current shell to the app.\n\n```\nEXAMPLE=hello z1 start path/to/your/app\n```\n\nThere are some environment variables that automatically z1 sets for each process:\n\n- __PORT__ - The first port you specified.\n- __PORTS__ - All ports that your app uses (separated by commas).\n- __APPNAME__ - The name of your app.\n- __PWD__ - The directory of your app.\n- __WORKERS__ - The number of workers started for the app.\n\nThese variables __can't be overwritten__.\n\n### Start\n\nAfter you [prepared the package.json](#prepare-packagejson) file of your app, you can now start it. First go to the\ndirectory where the `package.json` of your project is located. Type the following command into your terminal:\n\n```\nz1 start\n```\n\nThis command works regardless of how many workers you have specified in the `package.json` file. If your app was\nsuccessfully startet, the output should look like this:\n\n![Start command output](https://raw.githubusercontent.com/robojones/z1/master/screenshots/start.png)\n\n_As you may have noticed, each log is displayed twice. This happens because two workers are started for the app and the\nlogs of all workers are being displayed._\n\n__Options__\n\nIf you want to start your app with different settings than the ones specified in the `package.json`, you can add them to\nto the `z1 start` command.\n\n```\n--name anotherName\n--ports 80,2020,8080\n--workers 4\n--output path/to/logs/\n```\n\n### Restart\n\nYou can restart your app to apply updates for your app or changes to the `package.json`. The restart process will be __\ngapless__ and no requests will be refused. Just type the following command:\n\n```\nz1 restart homepage\n```\n\nThe first argument for the `z1 restart` command is the name that was specified in the `package.json` when you started\nthe app. If you are running this command inside the directory of the Node.js application, z1 will automatically detect\nthe name.\n\nOutput of the example from above:\n\n![Restart command output](https://raw.githubusercontent.com/robojones/z1/master/screenshots/restart.png)\n\n__Options__\n\n```\n--timeout 10000\n```\n\n`--timeout` is a number specifying the maximal time (in ms) that the old workers can __continue to run__ after they are\nkilled. The timeout allows old processes to __finish their active requests__ while not accepting new ones. If all\nrequests are finished, or the timeout is exceeded, the old processes get killed. The default value is 30000 (30s). If\nyou set it to \"Infinity\" the old processes might run forever.\n\n### List\n\n```\nz1 list\n```\n\nDisplays a list of all running apps.\n\nThe output could look like this:\n\n![List command output](https://raw.githubusercontent.com/robojones/z1/master/screenshots/list.png)\n\n### Info\n\n```\nz1 info homepage\n```\n\nShows more detailed information than z1 list.\n\nExample output:\n\n![Info command output](https://raw.githubusercontent.com/robojones/z1/master/screenshots/info.png)\n\n- __pending__ - processes are currently starting.\n- __available__ - workers are listening to all the ports specified in the `package.json`\n- __killed__ - workers are not listening for new connections. They will finish their outstanding requests before they\n  exit.\n- __revive count__ - shows you how often the workers of your app crashed since the last restart.\n\n__Options:__\n\n- `--name` - output the appname\n- `--dir` - output the directory of the app\n- `--ports` - output the ports that the app uses\n- `--pending` - output the number of pending workers\n- `--available` - output the number of available workers\n- `--killed` - output the number of killed workers\n- `--revive-count` - output how often the app has been revived\n\n### Stop\n\nTo stop an app just type:\n\n```\nz1 stop homepage\n```\n\nExample output:\n\n![Stop command output](https://raw.githubusercontent.com/robojones/z1/master/screenshots/stop.png)\n\n__Options__\n\n```\n--timeout 10000\n```\n\n`--timeout` is a number specifying the maximal time that the workers are allowed to run after they are killed (in ms).\nThe default value is 30,000ms. If you set it to \"infinity\" the old processes might run forever.\n\n### Exit\n\n```\nz1 exit\n```\n\nThis will kill the z1 daemon process and therefore all apps and workers.\n\n### Resurrect\n\nAfter you typed [exit](#exit), you can use the following to start all the apps that were running before:\n\n```\nz1 resurrect\n```\n\nNote: If you are starting a new app before `z1 resurrect`, the old apps will not be restored.\n\n### Install and Uninstall\n\nThis command allows you to add and remove additional features.\n\n1. __zsh__ - shell completion for zsh\n2. __bash__ - shell completion for bash _(coming soon)_\n3. __cron__ - cron job that resurrects z1 after a reboot\n\n```\nsudo z1 install zsh\n```\n\n### Passing arguments to workers\n\nYou can start your app with custom arguments.\n\n```\nz1 start --name 'custom app' --ports 80 -- hello\n```\n\nThis would start an app with the name 'custom app' that is listening on port 80. Everything behind the `--` will be\npassed to the workers. In your code you can get the \"hello\" as argv.\n\n```javascript\nprocess.argv[2] === 'hello' // true\n```\n\n## API\n\nBesides the CLI, you can also __require__ z1 to control your apps with a Node.js program.\n\n```javascript\nconst z1 = require('z1')\n```\n\n### z1.start(dir, args, opt, env, immediate)\n\n__Arguments__\n\n- __dir__ `\u003cString\u003e` - Path to the directory where the `package.json` of the app is located (Default: current directory)\n- __args__ `\u003cArray\u003e` _(optional)_ - Arguments for the workers\n- __opt__ `\u003cObject\u003e` _(optional)_ - Options that overwrite the ones from the [package.json](#prepare-packagejson)\n- __env__ `\u003cObject\u003e` _(optional)_ - Key-value-pairs to be added to `process.env` in the workers.\n- __immediate__ `\u003cBoolean\u003e` _(optional)_ (Default: `false`)\n\n__Returns__ a `\u003cPromise\u003e` that gets resolved when the app is started. If you set __immediate__ to `true`, the promise\ngets resolved immediately after your command was transmitted to the daemon.\n\nBy default It resolves to an object with the following data:\n\n```javascript\n{\n  app: String,\n  dir: String,\n  started: Number\n}\n```\n\n- __app__ - The name of the app specified in the `package.json`. You will need this in order to restart/stop the app.\n- __dir__ - Absolute path to the directory where the `package.json` is located\n- __started__ - Number of workers started for this app\n\n### z1.restart(app, opt, immediate)\n\n__Arguments__\n\n- __app__ `\u003cString\u003e` - The name specified in the `package.json` of the app you want to restart.\n- __opt__ `\u003cObject\u003e` - _(optional)_\n    - __timeout__ `\u003cNumber\u003e` - Maximum time until the old workers get killed (default: 30000ms).\n    - __signal__ `\u003cString\u003e` - Kill signal for the old workers\n- __immediate__ `\u003cBoolean\u003e` _(optional)_ (Default: `false`)\n\n__Returns__ a `\u003cPromise\u003e` that gets resolved when the new workers are available and the old ones are killed. It resolves\nto an object with the following data:\n\n```javascript\n{\n  app: String,\n  dir: String,\n  started: Number,\n  killed: Number\n}\n```\n\n- __app__ - the app name\n- __dir__ - directory of the app\n- __started__ - Number of started workers\n- __killed__ - Number of killed workers\n\n### z1.stop(app, opt, immediate)\n\n__Arguments__\n\n- __app__ `\u003cString\u003e` The name specified in the `package.json` of the app you want to restart.\n- __opt__ `\u003cObject\u003e` _(optional)_\n    - __timeout__ `\u003cNumber\u003e` Maximum time until the old workers get killed (default: 30000ms).\n    - __signal__ `\u003cString\u003e` Kill signal\n- __immediate__ `\u003cBoolean\u003e` _(optional)_ (Default: `false`)\n\n__Returns__ a `\u003cPromise\u003e` that gets resolved when the old workers are killed. It resolves to an object with the\nfollowing data:\n\n```javascript\n{\n  app: String,\n  killed: Number\n}\n```\n\n- __app__ - the app name\n- __killed__ - Number of killed workers\n\n### z1.info(app)\n\n__Arguments__\n\n- __app__ `\u003cString\u003e` The name of your app.\n\n__Returns__ a `\u003cPromise\u003e` that gets resolved to an object that contains information about the app.\n\nExample:\n\n```javascript\n{\n  name: 'homepage',\n  reviveCount: 0,\n  ports: [80],\n  pending: 0,\n  available: 2,\n  killed: 0\n}\n```\n\n### z1.list()\n\n__Returns__ a `\u003cPromise\u003e` that resolves to an object containing data about all running workers.\n\nYou can access the data for an app by using the name as key:\n\n```javascript\nz1.list().then(data =\u003e {\n  console.log(data.stats)\n})\n```\n\nThe output would be:\n\n```javascript\n{\n  homepage: {\n    dir: '/home/user/apps/homepage',\n    ports: [80],\n    pending: 0,\n    available: 2,\n    killed: 0\n  }\n}\n```\n\n### z1.exit()\n\n__Returns__ a `\u003cPromise\u003e` that resolves to an empty object. It gets resolves after the z1 daemon has exited.\n\n### z1.resurrect(immediate)\n\n- __immediate__ `\u003cBoolean\u003e` _(optional)_ (Default: `false`)\n\n__Returns__ a `\u003cPromise\u003e` that resolves to an object.\n\nExample:\n\n```javascript\n{\n  started: 2 // two workers started\n}\n```\n\nIt will be rejected if `z1.resurrect()` or `z1.start()` was called before.\n\nResurrect will start all apps that were running before the daemon was killed.\n\n### z1.ready()\n\n__Returns__ a `\u003cPromise\u003e` that resolves when the ready signal has been transmitted.\n\nThis function __must__ be called if an app does not use any port. It will tell the z1 daemon that your app has been\nstarted successfully.\n\nExample:\n\n```javascript\nconst z1 = require('z1')\n\n// ...your program...\n\nz1.ready()\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobojones%2Fz1","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frobojones%2Fz1","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobojones%2Fz1/lists"}