├── frontend ├── .gitignore ├── package.json ├── index.js ├── src │ └── render.js ├── index.html └── package-lock.json ├── .gitattributes ├── readme.md └── backend └── app.py /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "python-electron-boilerplate-frontend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "electron": "^11.1.1", 14 | "jquery": "^3.5.1", 15 | "time-stamp": "^2.2.0", 16 | "zeromq": "^6.0.0-beta.6" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/index.js: -------------------------------------------------------------------------------- 1 | const { app, BrowserWindow, ipcMain } = require('electron'); 2 | const { join } = require('path'); 3 | 4 | let mainWindow; 5 | 6 | const createWindow = () => { 7 | mainWindow = new BrowserWindow({ 8 | webPreferences: { 9 | nodeIntegration: true, 10 | contextIsolation: false 11 | }, 12 | show: true, 13 | devTools: true 14 | }) 15 | mainWindow.setMenuBarVisibility(false); 16 | mainWindow.loadFile(join(__dirname + '/index.html')); 17 | } 18 | 19 | app.once("ready", createWindow); -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # python-electron-boilerplate 2 | python-electron-boilerplate is a boilerplate framework allowing you to create a multi-process application using Python as a backend and Node.JS and Electron on the frontend. ZeroMQ sockets are used to create communication channels. This is very barebones and merely displays the functionality that ZMQ can offer to communicate between processes. 3 | ![Boilerplate](https://i.imgur.com/T7CyAk4.png) 4 | 5 | ## Running 6 | Run app.py in the backend, and then start electron in the frontend directory. 7 | 8 | ## Contributing 9 | Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. 10 | 11 | ## License 12 | [MIT](https://choosealicense.com/licenses/mit/) 13 | -------------------------------------------------------------------------------- /frontend/src/render.js: -------------------------------------------------------------------------------- 1 | const ZMQ = require('zeromq'); 2 | const $ = require('jquery'); 3 | const ts = require('time-stamp'); 4 | const { stringify } = JSON; 5 | 6 | const mainSock = new ZMQ.Push; 7 | const dataSock = new ZMQ.Request; 8 | const statusSock = new ZMQ.Pull; 9 | 10 | mainSock.connect("tcp://127.0.0.1:7777"); 11 | dataSock.connect("tcp://127.0.0.1:7778"); 12 | statusSock.connect("tcp://127.0.0.1:7779"); 13 | 14 | $('#sendData').on("click", async() => { 15 | const sendData = $('#send-data').val(); 16 | await mainSock.send(stringify({ type: "data", data: sendData })); 17 | }) 18 | 19 | $('#sendReceiveData').on("click", async() => { 20 | const sendData = $('#send-receive-data').val(); 21 | await dataSock.send(stringify({ type: "data", data: sendData })); 22 | const [dataResponse] = await dataSock.receive(); 23 | $('#received-data').val(dataResponse.toString()); 24 | }) 25 | 26 | const checkStatus = async() => { 27 | for await(const [msg] of statusSock){ 28 | $('#status-data').prepend(logTime(), " ", msg.toString(), "\n") 29 | } 30 | } 31 | 32 | checkStatus() 33 | 34 | const logTime = () => { 35 | return ts("HH:mm:ss"); 36 | } -------------------------------------------------------------------------------- /backend/app.py: -------------------------------------------------------------------------------- 1 | import zmq 2 | import signal 3 | from time import sleep 4 | from queue import Queue 5 | from random import choice 6 | from threading import Thread 7 | from json import loads, dumps 8 | 9 | statusQueue = Queue() 10 | 11 | statusMessages = [ 12 | {"type": "general", "message": "testing"}, 13 | {"type": "taskStatus", "message": "task 1 started"}, 14 | {"type": "taskStatus", "message": "task 2 stopped"} 15 | ] 16 | 17 | def mainSocket(): 18 | context = zmq.Context() 19 | socket = context.socket(zmq.PULL) 20 | socket.bind("tcp://*:7777") 21 | 22 | while True: 23 | message = loads(socket.recv()) 24 | print(message) 25 | 26 | def dataSocket(): 27 | context = zmq.Context() 28 | socket = context.socket(zmq.REP) 29 | socket.bind("tcp://*:7778") 30 | 31 | while True: 32 | message = loads(socket.recv()) 33 | print(message) 34 | socket.send(dumps({"dataReceived": message}).encode()) 35 | 36 | def statusSocket(): 37 | context = zmq.Context() 38 | socket = context.socket(zmq.PUSH) 39 | socket.bind("tcp://*:7779") 40 | 41 | while True: 42 | status = statusQueue.get() 43 | socket.send_json(status) 44 | 45 | if __name__ == "__main__": 46 | 47 | signal.signal(signal.SIGINT, signal.SIG_DFL) 48 | 49 | Thread(target = mainSocket).start() 50 | Thread(target = dataSocket).start() 51 | Thread(target = statusSocket).start() 52 | 53 | while True: 54 | statusQueue.put(choice(statusMessages)) 55 | sleep(5) -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Python Electron Boilerplate 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |

Python Electron Boilerplate

17 |
18 |
19 |
20 |
21 |

Send Data

22 |

This utilizes a ZMQ Push Socket in the frontend and a ZMQ Pull socket in the backend.

23 | 24 | 25 |
26 |
27 |
28 |
29 |
30 |
31 |

Send/Receive Data

32 |

This utilizes a ZMQ Request Socket in the frontend and a ZMQ Reply socket in the backend.

33 | 34 | 35 | 36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |

Status Data

45 |

This utilizes a Queue and ZMQ Push Socket in the backend and a ZMQ Pull socket in the frontend.

46 | 47 |
48 |
49 |
50 |
51 |
52 | 53 | -------------------------------------------------------------------------------- /frontend/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "python-electron-boilerplate-frontend", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@electron/get": { 8 | "version": "1.12.2", 9 | "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.12.2.tgz", 10 | "integrity": "sha512-vAuHUbfvBQpYTJ5wB7uVIDq5c/Ry0fiTBMs7lnEYAo/qXXppIVcWdfBr57u6eRnKdVso7KSiH6p/LbQAG6Izrg==", 11 | "requires": { 12 | "debug": "^4.1.1", 13 | "env-paths": "^2.2.0", 14 | "fs-extra": "^8.1.0", 15 | "global-agent": "^2.0.2", 16 | "global-tunnel-ng": "^2.7.1", 17 | "got": "^9.6.0", 18 | "progress": "^2.0.3", 19 | "sanitize-filename": "^1.6.2", 20 | "sumchecker": "^3.0.1" 21 | } 22 | }, 23 | "@sindresorhus/is": { 24 | "version": "0.14.0", 25 | "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", 26 | "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" 27 | }, 28 | "@szmarczak/http-timer": { 29 | "version": "1.1.2", 30 | "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", 31 | "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", 32 | "requires": { 33 | "defer-to-connect": "^1.0.1" 34 | } 35 | }, 36 | "@types/node": { 37 | "version": "12.19.11", 38 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.11.tgz", 39 | "integrity": "sha512-bwVfNTFZOrGXyiQ6t4B9sZerMSShWNsGRw8tC5DY1qImUNczS9SjT4G6PnzjCnxsu5Ubj6xjL2lgwddkxtQl5w==" 40 | }, 41 | "boolean": { 42 | "version": "3.0.2", 43 | "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.2.tgz", 44 | "integrity": "sha512-RwywHlpCRc3/Wh81MiCKun4ydaIFyW5Ea6JbL6sRCVx5q5irDw7pMXBUFYF/jArQ6YrG36q0kpovc9P/Kd3I4g==", 45 | "optional": true 46 | }, 47 | "buffer-crc32": { 48 | "version": "0.2.13", 49 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", 50 | "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" 51 | }, 52 | "buffer-from": { 53 | "version": "1.1.1", 54 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 55 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" 56 | }, 57 | "cacheable-request": { 58 | "version": "6.1.0", 59 | "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", 60 | "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", 61 | "requires": { 62 | "clone-response": "^1.0.2", 63 | "get-stream": "^5.1.0", 64 | "http-cache-semantics": "^4.0.0", 65 | "keyv": "^3.0.0", 66 | "lowercase-keys": "^2.0.0", 67 | "normalize-url": "^4.1.0", 68 | "responselike": "^1.0.2" 69 | }, 70 | "dependencies": { 71 | "get-stream": { 72 | "version": "5.2.0", 73 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", 74 | "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", 75 | "requires": { 76 | "pump": "^3.0.0" 77 | } 78 | }, 79 | "lowercase-keys": { 80 | "version": "2.0.0", 81 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", 82 | "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" 83 | } 84 | } 85 | }, 86 | "clone-response": { 87 | "version": "1.0.2", 88 | "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", 89 | "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", 90 | "requires": { 91 | "mimic-response": "^1.0.0" 92 | } 93 | }, 94 | "concat-stream": { 95 | "version": "1.6.2", 96 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", 97 | "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", 98 | "requires": { 99 | "buffer-from": "^1.0.0", 100 | "inherits": "^2.0.3", 101 | "readable-stream": "^2.2.2", 102 | "typedarray": "^0.0.6" 103 | } 104 | }, 105 | "config-chain": { 106 | "version": "1.1.12", 107 | "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", 108 | "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", 109 | "optional": true, 110 | "requires": { 111 | "ini": "^1.3.4", 112 | "proto-list": "~1.2.1" 113 | } 114 | }, 115 | "core-js": { 116 | "version": "3.8.1", 117 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.1.tgz", 118 | "integrity": "sha512-9Id2xHY1W7m8hCl8NkhQn5CufmF/WuR30BTRewvCXc1aZd3kMECwNZ69ndLbekKfakw9Rf2Xyc+QR6E7Gg+obg==", 119 | "optional": true 120 | }, 121 | "core-util-is": { 122 | "version": "1.0.2", 123 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 124 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 125 | }, 126 | "debug": { 127 | "version": "4.3.1", 128 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", 129 | "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", 130 | "requires": { 131 | "ms": "2.1.2" 132 | } 133 | }, 134 | "decompress-response": { 135 | "version": "3.3.0", 136 | "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", 137 | "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", 138 | "requires": { 139 | "mimic-response": "^1.0.0" 140 | } 141 | }, 142 | "defer-to-connect": { 143 | "version": "1.1.3", 144 | "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", 145 | "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" 146 | }, 147 | "define-properties": { 148 | "version": "1.1.3", 149 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 150 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 151 | "optional": true, 152 | "requires": { 153 | "object-keys": "^1.0.12" 154 | } 155 | }, 156 | "detect-node": { 157 | "version": "2.0.4", 158 | "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", 159 | "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", 160 | "optional": true 161 | }, 162 | "duplexer3": { 163 | "version": "0.1.4", 164 | "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", 165 | "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" 166 | }, 167 | "electron": { 168 | "version": "11.1.1", 169 | "resolved": "https://registry.npmjs.org/electron/-/electron-11.1.1.tgz", 170 | "integrity": "sha512-tlbex3xosJgfileN6BAQRotevPRXB/wQIq48QeQ08tUJJrXwE72c8smsM/hbHx5eDgnbfJ2G3a60PmRjHU2NhA==", 171 | "requires": { 172 | "@electron/get": "^1.0.1", 173 | "@types/node": "^12.0.12", 174 | "extract-zip": "^1.0.3" 175 | } 176 | }, 177 | "encodeurl": { 178 | "version": "1.0.2", 179 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 180 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", 181 | "optional": true 182 | }, 183 | "end-of-stream": { 184 | "version": "1.4.4", 185 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 186 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 187 | "requires": { 188 | "once": "^1.4.0" 189 | } 190 | }, 191 | "env-paths": { 192 | "version": "2.2.0", 193 | "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", 194 | "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==" 195 | }, 196 | "es6-error": { 197 | "version": "4.1.1", 198 | "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", 199 | "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", 200 | "optional": true 201 | }, 202 | "escape-string-regexp": { 203 | "version": "4.0.0", 204 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 205 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 206 | "optional": true 207 | }, 208 | "extract-zip": { 209 | "version": "1.7.0", 210 | "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", 211 | "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", 212 | "requires": { 213 | "concat-stream": "^1.6.2", 214 | "debug": "^2.6.9", 215 | "mkdirp": "^0.5.4", 216 | "yauzl": "^2.10.0" 217 | }, 218 | "dependencies": { 219 | "debug": { 220 | "version": "2.6.9", 221 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 222 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 223 | "requires": { 224 | "ms": "2.0.0" 225 | } 226 | }, 227 | "ms": { 228 | "version": "2.0.0", 229 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 230 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 231 | } 232 | } 233 | }, 234 | "fd-slicer": { 235 | "version": "1.1.0", 236 | "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", 237 | "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", 238 | "requires": { 239 | "pend": "~1.2.0" 240 | } 241 | }, 242 | "fs-extra": { 243 | "version": "8.1.0", 244 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", 245 | "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", 246 | "requires": { 247 | "graceful-fs": "^4.2.0", 248 | "jsonfile": "^4.0.0", 249 | "universalify": "^0.1.0" 250 | } 251 | }, 252 | "get-stream": { 253 | "version": "4.1.0", 254 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", 255 | "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", 256 | "requires": { 257 | "pump": "^3.0.0" 258 | } 259 | }, 260 | "global-agent": { 261 | "version": "2.1.12", 262 | "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.12.tgz", 263 | "integrity": "sha512-caAljRMS/qcDo69X9BfkgrihGUgGx44Fb4QQToNQjsiWh+YlQ66uqYVAdA8Olqit+5Ng0nkz09je3ZzANMZcjg==", 264 | "optional": true, 265 | "requires": { 266 | "boolean": "^3.0.1", 267 | "core-js": "^3.6.5", 268 | "es6-error": "^4.1.1", 269 | "matcher": "^3.0.0", 270 | "roarr": "^2.15.3", 271 | "semver": "^7.3.2", 272 | "serialize-error": "^7.0.1" 273 | } 274 | }, 275 | "global-tunnel-ng": { 276 | "version": "2.7.1", 277 | "resolved": "https://registry.npmjs.org/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz", 278 | "integrity": "sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==", 279 | "optional": true, 280 | "requires": { 281 | "encodeurl": "^1.0.2", 282 | "lodash": "^4.17.10", 283 | "npm-conf": "^1.1.3", 284 | "tunnel": "^0.0.6" 285 | } 286 | }, 287 | "globalthis": { 288 | "version": "1.0.1", 289 | "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.1.tgz", 290 | "integrity": "sha512-mJPRTc/P39NH/iNG4mXa9aIhNymaQikTrnspeCa2ZuJ+mH2QN/rXwtX3XwKrHqWgUQFbNZKtHM105aHzJalElw==", 291 | "optional": true, 292 | "requires": { 293 | "define-properties": "^1.1.3" 294 | } 295 | }, 296 | "got": { 297 | "version": "9.6.0", 298 | "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", 299 | "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", 300 | "requires": { 301 | "@sindresorhus/is": "^0.14.0", 302 | "@szmarczak/http-timer": "^1.1.2", 303 | "cacheable-request": "^6.0.0", 304 | "decompress-response": "^3.3.0", 305 | "duplexer3": "^0.1.4", 306 | "get-stream": "^4.1.0", 307 | "lowercase-keys": "^1.0.1", 308 | "mimic-response": "^1.0.1", 309 | "p-cancelable": "^1.0.0", 310 | "to-readable-stream": "^1.0.0", 311 | "url-parse-lax": "^3.0.0" 312 | } 313 | }, 314 | "graceful-fs": { 315 | "version": "4.2.4", 316 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", 317 | "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" 318 | }, 319 | "http-cache-semantics": { 320 | "version": "4.1.0", 321 | "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", 322 | "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" 323 | }, 324 | "inherits": { 325 | "version": "2.0.4", 326 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 327 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 328 | }, 329 | "ini": { 330 | "version": "1.3.8", 331 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 332 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", 333 | "optional": true 334 | }, 335 | "isarray": { 336 | "version": "1.0.0", 337 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 338 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 339 | }, 340 | "jquery": { 341 | "version": "3.5.1", 342 | "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz", 343 | "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==" 344 | }, 345 | "json-buffer": { 346 | "version": "3.0.0", 347 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", 348 | "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" 349 | }, 350 | "json-stringify-safe": { 351 | "version": "5.0.1", 352 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 353 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", 354 | "optional": true 355 | }, 356 | "jsonfile": { 357 | "version": "4.0.0", 358 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", 359 | "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", 360 | "requires": { 361 | "graceful-fs": "^4.1.6" 362 | } 363 | }, 364 | "keyv": { 365 | "version": "3.1.0", 366 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", 367 | "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", 368 | "requires": { 369 | "json-buffer": "3.0.0" 370 | } 371 | }, 372 | "lodash": { 373 | "version": "4.17.20", 374 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", 375 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", 376 | "optional": true 377 | }, 378 | "lowercase-keys": { 379 | "version": "1.0.1", 380 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", 381 | "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" 382 | }, 383 | "lru-cache": { 384 | "version": "6.0.0", 385 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 386 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 387 | "optional": true, 388 | "requires": { 389 | "yallist": "^4.0.0" 390 | } 391 | }, 392 | "matcher": { 393 | "version": "3.0.0", 394 | "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", 395 | "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", 396 | "optional": true, 397 | "requires": { 398 | "escape-string-regexp": "^4.0.0" 399 | } 400 | }, 401 | "mimic-response": { 402 | "version": "1.0.1", 403 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", 404 | "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" 405 | }, 406 | "minimist": { 407 | "version": "1.2.5", 408 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 409 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" 410 | }, 411 | "mkdirp": { 412 | "version": "0.5.5", 413 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 414 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 415 | "requires": { 416 | "minimist": "^1.2.5" 417 | } 418 | }, 419 | "ms": { 420 | "version": "2.1.2", 421 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 422 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 423 | }, 424 | "node-gyp-build": { 425 | "version": "4.2.3", 426 | "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", 427 | "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==" 428 | }, 429 | "normalize-url": { 430 | "version": "4.5.0", 431 | "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", 432 | "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==" 433 | }, 434 | "npm-conf": { 435 | "version": "1.1.3", 436 | "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", 437 | "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", 438 | "optional": true, 439 | "requires": { 440 | "config-chain": "^1.1.11", 441 | "pify": "^3.0.0" 442 | } 443 | }, 444 | "object-keys": { 445 | "version": "1.1.1", 446 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 447 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 448 | "optional": true 449 | }, 450 | "once": { 451 | "version": "1.4.0", 452 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 453 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 454 | "requires": { 455 | "wrappy": "1" 456 | } 457 | }, 458 | "p-cancelable": { 459 | "version": "1.1.0", 460 | "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", 461 | "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" 462 | }, 463 | "pend": { 464 | "version": "1.2.0", 465 | "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", 466 | "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" 467 | }, 468 | "pify": { 469 | "version": "3.0.0", 470 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", 471 | "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", 472 | "optional": true 473 | }, 474 | "prepend-http": { 475 | "version": "2.0.0", 476 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", 477 | "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" 478 | }, 479 | "process-nextick-args": { 480 | "version": "2.0.1", 481 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 482 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 483 | }, 484 | "progress": { 485 | "version": "2.0.3", 486 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 487 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" 488 | }, 489 | "proto-list": { 490 | "version": "1.2.4", 491 | "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", 492 | "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", 493 | "optional": true 494 | }, 495 | "pump": { 496 | "version": "3.0.0", 497 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 498 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 499 | "requires": { 500 | "end-of-stream": "^1.1.0", 501 | "once": "^1.3.1" 502 | } 503 | }, 504 | "readable-stream": { 505 | "version": "2.3.7", 506 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 507 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 508 | "requires": { 509 | "core-util-is": "~1.0.0", 510 | "inherits": "~2.0.3", 511 | "isarray": "~1.0.0", 512 | "process-nextick-args": "~2.0.0", 513 | "safe-buffer": "~5.1.1", 514 | "string_decoder": "~1.1.1", 515 | "util-deprecate": "~1.0.1" 516 | } 517 | }, 518 | "responselike": { 519 | "version": "1.0.2", 520 | "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", 521 | "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", 522 | "requires": { 523 | "lowercase-keys": "^1.0.0" 524 | } 525 | }, 526 | "roarr": { 527 | "version": "2.15.4", 528 | "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", 529 | "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", 530 | "optional": true, 531 | "requires": { 532 | "boolean": "^3.0.1", 533 | "detect-node": "^2.0.4", 534 | "globalthis": "^1.0.1", 535 | "json-stringify-safe": "^5.0.1", 536 | "semver-compare": "^1.0.0", 537 | "sprintf-js": "^1.1.2" 538 | } 539 | }, 540 | "safe-buffer": { 541 | "version": "5.1.2", 542 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 543 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 544 | }, 545 | "sanitize-filename": { 546 | "version": "1.6.3", 547 | "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", 548 | "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", 549 | "requires": { 550 | "truncate-utf8-bytes": "^1.0.0" 551 | } 552 | }, 553 | "semver": { 554 | "version": "7.3.4", 555 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", 556 | "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", 557 | "optional": true, 558 | "requires": { 559 | "lru-cache": "^6.0.0" 560 | } 561 | }, 562 | "semver-compare": { 563 | "version": "1.0.0", 564 | "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", 565 | "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", 566 | "optional": true 567 | }, 568 | "serialize-error": { 569 | "version": "7.0.1", 570 | "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", 571 | "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", 572 | "optional": true, 573 | "requires": { 574 | "type-fest": "^0.13.1" 575 | } 576 | }, 577 | "sprintf-js": { 578 | "version": "1.1.2", 579 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", 580 | "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", 581 | "optional": true 582 | }, 583 | "string_decoder": { 584 | "version": "1.1.1", 585 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 586 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 587 | "requires": { 588 | "safe-buffer": "~5.1.0" 589 | } 590 | }, 591 | "sumchecker": { 592 | "version": "3.0.1", 593 | "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", 594 | "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", 595 | "requires": { 596 | "debug": "^4.1.0" 597 | } 598 | }, 599 | "time-stamp": { 600 | "version": "2.2.0", 601 | "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-2.2.0.tgz", 602 | "integrity": "sha512-zxke8goJQpBeEgD82CXABeMh0LSJcj7CXEd0OHOg45HgcofF7pxNwZm9+RknpxpDhwN4gFpySkApKfFYfRQnUA==" 603 | }, 604 | "to-readable-stream": { 605 | "version": "1.0.0", 606 | "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", 607 | "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" 608 | }, 609 | "truncate-utf8-bytes": { 610 | "version": "1.0.2", 611 | "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", 612 | "integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=", 613 | "requires": { 614 | "utf8-byte-length": "^1.0.1" 615 | } 616 | }, 617 | "tunnel": { 618 | "version": "0.0.6", 619 | "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", 620 | "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", 621 | "optional": true 622 | }, 623 | "type-fest": { 624 | "version": "0.13.1", 625 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", 626 | "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", 627 | "optional": true 628 | }, 629 | "typedarray": { 630 | "version": "0.0.6", 631 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 632 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" 633 | }, 634 | "universalify": { 635 | "version": "0.1.2", 636 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 637 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" 638 | }, 639 | "url-parse-lax": { 640 | "version": "3.0.0", 641 | "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", 642 | "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", 643 | "requires": { 644 | "prepend-http": "^2.0.0" 645 | } 646 | }, 647 | "utf8-byte-length": { 648 | "version": "1.0.4", 649 | "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", 650 | "integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E=" 651 | }, 652 | "util-deprecate": { 653 | "version": "1.0.2", 654 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 655 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 656 | }, 657 | "wrappy": { 658 | "version": "1.0.2", 659 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 660 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 661 | }, 662 | "yallist": { 663 | "version": "4.0.0", 664 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 665 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 666 | "optional": true 667 | }, 668 | "yauzl": { 669 | "version": "2.10.0", 670 | "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", 671 | "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", 672 | "requires": { 673 | "buffer-crc32": "~0.2.3", 674 | "fd-slicer": "~1.1.0" 675 | } 676 | }, 677 | "zeromq": { 678 | "version": "6.0.0-beta.6", 679 | "resolved": "https://registry.npmjs.org/zeromq/-/zeromq-6.0.0-beta.6.tgz", 680 | "integrity": "sha512-wLf6M7pBHijl+BRltUL2VoDpgbQcOZetiX8UzycHL8CcYFxYnRrpoG5fi3UX3+Umavz1lk4/dGaQez8qiDgr/Q==", 681 | "requires": { 682 | "node-gyp-build": "^4.1.0" 683 | } 684 | } 685 | } 686 | } 687 | --------------------------------------------------------------------------------